Skip to content

Commit 120af74

Browse files
committed
feat: archon servers routes + labrinth billing routes
1 parent 6b0e96c commit 120af74

File tree

11 files changed

+474
-1
lines changed

11 files changed

+474
-1
lines changed

packages/api-client/src/core/abstract-client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ export abstract class AbstractModrinthClient {
2323
*/
2424
private _moduleNamespaces: Map<string, Record<string, AbstractModule>> = new Map()
2525

26-
// TODO: When adding kyros/archon add readonly fields for those too.
2726
public readonly labrinth!: InferredClientModules['labrinth']
27+
public readonly archon!: InferredClientModules['archon']
2828

2929
constructor(config: ClientConfig) {
3030
this.config = {

packages/api-client/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export { type BackoffStrategy, type RetryConfig, RetryFeature } from './features
1313
export { type VerboseLoggingConfig, VerboseLoggingFeature } from './features/verbose-logging'
1414
export type { InferredClientModules } from './modules'
1515
export * from './modules/types'
16+
export type { Archon } from './modules/archon/servers/types'
17+
export type { Labrinth } from './modules/labrinth/billing/types'
1618
export { GenericModrinthClient } from './platform/generic'
1719
export type { NuxtClientConfig } from './platform/nuxt'
1820
export { NuxtCircuitBreakerStorage, NuxtModrinthClient } from './platform/nuxt'
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './servers/v0'
2+
export * from './servers/types'
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
export namespace Archon {
2+
export namespace Servers {
3+
export namespace v0 {
4+
export type ServerGetResponse = {
5+
servers: Server[]
6+
pagination: Pagination
7+
}
8+
9+
export type Pagination = {
10+
current_page: number
11+
page_size: number
12+
total_pages: number
13+
total_items: number
14+
}
15+
16+
export type Status = 'installing' | 'broken' | 'available' | 'suspended'
17+
18+
export type SuspensionReason =
19+
| 'moderated'
20+
| 'paymentfailed'
21+
| 'cancelled'
22+
| 'upgrading'
23+
| 'other'
24+
25+
export type Loader =
26+
| 'Forge'
27+
| 'NeoForge'
28+
| 'Fabric'
29+
| 'Quilt'
30+
| 'Purpur'
31+
| 'Spigot'
32+
| 'Vanilla'
33+
| 'Paper'
34+
35+
export type Game = 'Minecraft'
36+
37+
export type UpstreamKind = 'modpack' | 'none'
38+
39+
export type Server = {
40+
server_id: string
41+
name: string
42+
owner_id: string
43+
net: Net
44+
game: Game
45+
backup_quota: number
46+
used_backup_quota: number
47+
status: Status
48+
suspension_reason: SuspensionReason | null
49+
loader: Loader | null
50+
loader_version: string | null
51+
mc_version: string | null
52+
upstream: Upstream | null
53+
sftp_username: string
54+
sftp_password: string
55+
sftp_host: string
56+
datacenter: string
57+
notices: Notice[]
58+
node: NodeInfo | null
59+
flows: Flows
60+
is_medal: boolean
61+
62+
medal_expires?: string
63+
}
64+
65+
export type Net = {
66+
ip: string
67+
port: number
68+
domain: string
69+
}
70+
71+
export type Upstream = {
72+
kind: UpstreamKind
73+
version_id: string
74+
project_id: string
75+
}
76+
77+
export type Notice = {
78+
id: number
79+
dismissable: boolean
80+
title: string
81+
message: string
82+
level: string
83+
announced: string
84+
}
85+
86+
export type NodeInfo = {
87+
token: string
88+
instance: string
89+
}
90+
91+
export type Flows = {
92+
intro: boolean
93+
}
94+
95+
export type GetServersOptions = {
96+
limit?: number
97+
offset?: number
98+
}
99+
}
100+
}
101+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { AbstractModule } from '../../../core/abstract-module'
2+
import type { Archon } from './types'
3+
4+
export class ArchonServersV0Module extends AbstractModule {
5+
public getModuleID(): string {
6+
return 'archon_servers_v0'
7+
}
8+
9+
/**
10+
* Get list of servers for the authenticated user
11+
* GET /modrinth/v0/servers
12+
*/
13+
public async list(
14+
options?: Archon.Servers.v0.GetServersOptions,
15+
): Promise<Archon.Servers.v0.ServerGetResponse> {
16+
const params = new URLSearchParams()
17+
if (options?.limit) params.set('limit', options.limit.toString())
18+
if (options?.offset) params.set('offset', options.offset.toString())
19+
20+
const query = params.toString() ? `?${params.toString()}` : ''
21+
22+
return this.client.request<Archon.Servers.v0.ServerGetResponse>(`/modrinth/v0/servers${query}`, {
23+
api: 'archon',
24+
method: 'GET',
25+
})
26+
}
27+
}

packages/api-client/src/modules/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { AbstractModrinthClient } from '../core/abstract-client'
22
import type { AbstractModule } from '../core/abstract-module'
3+
import { ArchonServersV0Module } from './archon/servers/v0'
4+
import { LabrinthBillingInternalModule } from './labrinth/billing/internal'
35
import { LabrinthProjectsV2Module } from './labrinth/projects/v2'
46
import { LabrinthProjectsV3Module } from './labrinth/projects/v3'
57

@@ -15,6 +17,8 @@ type ModuleConstructor = new (client: AbstractModrinthClient) => AbstractModule
1517
* TODO: Better way? Probably not
1618
*/
1719
export const MODULE_REGISTRY = {
20+
archon_servers_v0: ArchonServersV0Module,
21+
labrinth_billing_internal: LabrinthBillingInternalModule,
1822
labrinth_projects_v2: LabrinthProjectsV2Module,
1923
labrinth_projects_v3: LabrinthProjectsV3Module,
2024
} as const satisfies Record<string, ModuleConstructor>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './internal'
2+
export * from './types'
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import { AbstractModule } from '../../../core/abstract-module'
2+
import type { Labrinth } from './types'
3+
4+
export class LabrinthBillingInternalModule extends AbstractModule {
5+
public getModuleID(): string {
6+
return 'labrinth_billing_internal'
7+
}
8+
9+
/**
10+
* Get user's subscriptions
11+
* GET /_internal/billing/subscriptions
12+
*/
13+
public async getSubscriptions(
14+
userId?: string,
15+
): Promise<Labrinth.Billing.Internal.UserSubscription[]> {
16+
const params = userId ? `?user_id=${userId}` : ''
17+
18+
return this.client.request<Labrinth.Billing.Internal.UserSubscription[]>(
19+
`/billing/subscriptions${params}`,
20+
{
21+
api: 'labrinth',
22+
version: 'internal',
23+
method: 'GET',
24+
},
25+
)
26+
}
27+
28+
/**
29+
* Get available products for purchase
30+
* GET /_internal/billing/products
31+
*/
32+
public async getProducts(): Promise<Labrinth.Billing.Internal.Product[]> {
33+
return this.client.request<Labrinth.Billing.Internal.Product[]>('/billing/products', {
34+
api: 'labrinth',
35+
version: 'internal',
36+
method: 'GET',
37+
})
38+
}
39+
40+
/**
41+
* Get Stripe customer information
42+
* GET /_internal/billing/customer
43+
*/
44+
public async getCustomer(): Promise<unknown> {
45+
return this.client.request<unknown>('/billing/customer', {
46+
api: 'labrinth',
47+
version: 'internal',
48+
method: 'GET',
49+
})
50+
}
51+
52+
/**
53+
* Edit a subscription (change product, interval, cancel, etc.)
54+
* PATCH /_internal/billing/subscription/{id}
55+
*/
56+
public async editSubscription(
57+
id: string,
58+
edit: Labrinth.Billing.Internal.EditSubscriptionRequest,
59+
dry?: boolean,
60+
): Promise<Labrinth.Billing.Internal.EditSubscriptionResponse | void> {
61+
const params = dry ? '?dry=true' : ''
62+
63+
return this.client.request<Labrinth.Billing.Internal.EditSubscriptionResponse | void>(
64+
`/billing/subscription/${id}${params}`,
65+
{
66+
api: 'labrinth',
67+
version: 'internal',
68+
method: 'PATCH',
69+
body: edit,
70+
},
71+
)
72+
}
73+
74+
/**
75+
* Get user's payment methods
76+
* GET /_internal/billing/payment_methods
77+
*/
78+
public async getPaymentMethods(): Promise<unknown[]> {
79+
return this.client.request<unknown[]>('/billing/payment_methods', {
80+
api: 'labrinth',
81+
version: 'internal',
82+
method: 'GET',
83+
})
84+
}
85+
86+
/**
87+
* Initiate flow to add a new payment method
88+
* POST /_internal/billing/payment_method
89+
*/
90+
public async addPaymentMethodFlow(): Promise<Labrinth.Billing.Internal.AddPaymentMethodFlowResponse> {
91+
return this.client.request<Labrinth.Billing.Internal.AddPaymentMethodFlowResponse>(
92+
'/billing/payment_method',
93+
{
94+
api: 'labrinth',
95+
version: 'internal',
96+
method: 'POST',
97+
},
98+
)
99+
}
100+
101+
/**
102+
* Edit a payment method (set as primary)
103+
* PATCH /_internal/billing/payment_method/{id}
104+
*/
105+
public async editPaymentMethod(
106+
id: string,
107+
body: Labrinth.Billing.Internal.EditPaymentMethodRequest,
108+
): Promise<void> {
109+
return this.client.request<void>(`/billing/payment_method/${id}`, {
110+
api: 'labrinth',
111+
version: 'internal',
112+
method: 'PATCH',
113+
body,
114+
})
115+
}
116+
117+
/**
118+
* Remove a payment method
119+
* DELETE /_internal/billing/payment_method/{id}
120+
*/
121+
public async removePaymentMethod(id: string): Promise<void> {
122+
return this.client.request<void>(`/billing/payment_method/${id}`, {
123+
api: 'labrinth',
124+
version: 'internal',
125+
method: 'DELETE',
126+
})
127+
}
128+
129+
/**
130+
* Get payment history (charges)
131+
* GET /_internal/billing/payments
132+
*/
133+
public async getPayments(userId?: string): Promise<Labrinth.Billing.Internal.Charge[]> {
134+
const params = userId ? `?user_id=${userId}` : ''
135+
136+
return this.client.request<Labrinth.Billing.Internal.Charge[]>(`/billing/payments${params}`, {
137+
api: 'labrinth',
138+
version: 'internal',
139+
method: 'GET',
140+
})
141+
}
142+
143+
/**
144+
* Initiate a payment
145+
* POST /_internal/billing/payment
146+
*/
147+
public async initiatePayment(
148+
request: Labrinth.Billing.Internal.InitiatePaymentRequest,
149+
): Promise<Labrinth.Billing.Internal.InitiatePaymentResponse> {
150+
return this.client.request<Labrinth.Billing.Internal.InitiatePaymentResponse>('/billing/payment', {
151+
api: 'labrinth',
152+
version: 'internal',
153+
method: 'POST',
154+
body: request,
155+
})
156+
}
157+
158+
/**
159+
* Refund a charge (Admin only)
160+
* POST /_internal/billing/charge/{id}/refund
161+
*/
162+
public async refundCharge(
163+
id: string,
164+
refund: Labrinth.Billing.Internal.RefundChargeRequest,
165+
): Promise<void> {
166+
return this.client.request<void>(`/billing/charge/${id}/refund`, {
167+
api: 'labrinth',
168+
version: 'internal',
169+
method: 'POST',
170+
body: refund,
171+
})
172+
}
173+
174+
/**
175+
* Credit subscriptions (Admin only)
176+
* POST /_internal/billing/credit
177+
*/
178+
public async credit(request: Labrinth.Billing.Internal.CreditRequest): Promise<void> {
179+
return this.client.request<void>('/billing/credit', {
180+
api: 'labrinth',
181+
version: 'internal',
182+
method: 'POST',
183+
body: request,
184+
})
185+
}
186+
}

0 commit comments

Comments
 (0)