@4players/payment 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,530 @@
1
+ import createClient from 'openapi-fetch';
2
+
3
+ // src/client.ts
4
+
5
+ // src/errors.ts
6
+ var PaymentError = class _PaymentError extends Error {
7
+ constructor(message, statusCode, details) {
8
+ super(message);
9
+ this.statusCode = statusCode;
10
+ this.details = details;
11
+ this.name = "PaymentError";
12
+ if (typeof Error.captureStackTrace === "function") {
13
+ Error.captureStackTrace(this, _PaymentError);
14
+ }
15
+ }
16
+ };
17
+ var PaymentApiError = class extends PaymentError {
18
+ /**
19
+ * Application-level error code from the response envelope.
20
+ * A value of `0` means no specific error code was returned (legacy null-data case).
21
+ */
22
+ code;
23
+ /**
24
+ * The HTTP status code of the response.
25
+ * Note: This may be `200` even when there is an application error.
26
+ */
27
+ httpStatus;
28
+ constructor(message, code, httpStatus) {
29
+ super(message, httpStatus);
30
+ this.name = "PaymentApiError";
31
+ this.code = code;
32
+ this.httpStatus = httpStatus;
33
+ }
34
+ };
35
+ var PaymentAuthError = class extends PaymentError {
36
+ constructor(message = "Authentication required. Please provide a valid session ID.") {
37
+ super(message, 401);
38
+ this.name = "PaymentAuthError";
39
+ }
40
+ };
41
+ var PaymentNotFoundError = class extends PaymentError {
42
+ constructor(resource, id) {
43
+ super(`${resource} with ID ${id} not found`, 404);
44
+ this.name = "PaymentNotFoundError";
45
+ }
46
+ };
47
+ var PaymentValidationError = class extends PaymentError {
48
+ constructor(message, details) {
49
+ super(message, 422, details);
50
+ this.name = "PaymentValidationError";
51
+ }
52
+ };
53
+ var PaymentRateLimitError = class extends PaymentError {
54
+ constructor(retryAfter) {
55
+ super(
56
+ retryAfter ? `Rate limit exceeded. Retry after ${retryAfter} seconds.` : "Rate limit exceeded. Please try again later.",
57
+ 429,
58
+ { retryAfter }
59
+ );
60
+ this.name = "PaymentRateLimitError";
61
+ }
62
+ };
63
+
64
+ // src/client.ts
65
+ var DEFAULT_BASE_URL = "https://secure.4players.de/public/api/v1";
66
+ var PaymentClient = class {
67
+ client;
68
+ /**
69
+ * Create a new Payment client instance.
70
+ *
71
+ * @param config - Client configuration
72
+ * @throws {PaymentAuthError} If no session ID is provided
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * const client = new PaymentClient({
77
+ * sessionId: 'your-fusion-sid'
78
+ * });
79
+ * ```
80
+ */
81
+ constructor(config) {
82
+ if (!config.sessionId) {
83
+ throw new PaymentAuthError("Session ID is required");
84
+ }
85
+ this.client = createClient({
86
+ baseUrl: config.baseUrl || DEFAULT_BASE_URL,
87
+ headers: {
88
+ "fusion-sid": config.sessionId,
89
+ "Content-Type": "application/json",
90
+ Accept: "application/json"
91
+ },
92
+ fetch: config.fetch
93
+ });
94
+ this.client.use(this.createEnvelopeMiddleware());
95
+ }
96
+ /**
97
+ * Creates middleware that unwraps the Payment API response envelope.
98
+ *
99
+ * The Payment API wraps ALL responses in `{ data, error }`.
100
+ * This middleware:
101
+ * 1. Checks `error.code` — if non-zero, throws `PaymentApiError`
102
+ * 2. Checks `data` — if null, throws `PaymentApiError` (legacy error pattern)
103
+ * 3. Returns a new Response containing only the unwrapped `data`
104
+ */
105
+ createEnvelopeMiddleware() {
106
+ return {
107
+ async onResponse({ response }) {
108
+ const contentType = response.headers.get("content-type");
109
+ if (!contentType?.includes("application/json")) {
110
+ return response;
111
+ }
112
+ const text = await response.clone().text();
113
+ let body;
114
+ try {
115
+ body = JSON.parse(text);
116
+ } catch {
117
+ return response;
118
+ }
119
+ if (body !== null && typeof body === "object" && "error" in body && "data" in body) {
120
+ const envelope = body;
121
+ if (envelope.error && envelope.error.code !== 0) {
122
+ throw new PaymentApiError(
123
+ envelope.error.message,
124
+ envelope.error.code,
125
+ response.status
126
+ );
127
+ }
128
+ if (envelope.data === null || envelope.data === void 0) {
129
+ throw new PaymentApiError(
130
+ envelope.error?.message || "Response data is null",
131
+ envelope.error?.code || 0,
132
+ response.status
133
+ );
134
+ }
135
+ return new Response(JSON.stringify(envelope.data), {
136
+ status: response.status,
137
+ statusText: response.statusText,
138
+ headers: response.headers
139
+ });
140
+ }
141
+ return response;
142
+ }
143
+ };
144
+ }
145
+ handleError(operation, error) {
146
+ if (error && typeof error === "object") {
147
+ const errorObj = error;
148
+ if (errorObj.status === 401 || errorObj.status === 403) {
149
+ throw new PaymentAuthError();
150
+ }
151
+ if (errorObj.status === 404) {
152
+ throw new PaymentNotFoundError(operation, "unknown");
153
+ }
154
+ if (errorObj.status === 429) {
155
+ throw new PaymentRateLimitError();
156
+ }
157
+ }
158
+ throw new PaymentError(
159
+ `Failed to ${operation}: ${JSON.stringify(error)}`,
160
+ void 0,
161
+ error
162
+ );
163
+ }
164
+ // ==================== Projects ====================
165
+ /**
166
+ * Get all projects the user has access to.
167
+ *
168
+ * @returns Array of payment projects
169
+ */
170
+ async getPaymentProjects() {
171
+ const { data, error } = await this.client.GET("/apps");
172
+ if (error) this.handleError("get payment projects", error);
173
+ return data;
174
+ }
175
+ /**
176
+ * Get the details of a specific app including the payment project.
177
+ *
178
+ * @param appId - The ID of the app to retrieve
179
+ * @returns Payment project details
180
+ */
181
+ async getPaymentProjectForApp(appId) {
182
+ const { data, error } = await this.client.GET("/apps/{app_id}", {
183
+ params: { path: { app_id: appId } }
184
+ });
185
+ if (error) this.handleError("get payment project for app", error);
186
+ return data;
187
+ }
188
+ /**
189
+ * Get a specific project by ID.
190
+ *
191
+ * @param projectId - The unique identifier of the project
192
+ * @returns Project details
193
+ */
194
+ async getProject(projectId) {
195
+ const { data, error } = await this.client.GET("/projects/{projectId}", {
196
+ params: { path: { projectId } }
197
+ });
198
+ if (error) this.handleError("get project", error);
199
+ return data;
200
+ }
201
+ /**
202
+ * Update a project's name, description, or peer limit.
203
+ *
204
+ * @param projectId - The unique identifier of the project
205
+ * @param body - Updated project fields
206
+ * @returns Success response
207
+ */
208
+ async editProject(projectId, body) {
209
+ const { data, error } = await this.client.PUT("/projects/{projectId}", {
210
+ params: { path: { projectId } },
211
+ body
212
+ });
213
+ if (error) this.handleError("edit project", error);
214
+ return data;
215
+ }
216
+ // ==================== Peers / Metrics ====================
217
+ /**
218
+ * Get peak peers over time for a project.
219
+ *
220
+ * @param projectId - The unique identifier of the project
221
+ * @param query - Query parameters (start timestamp is required)
222
+ * @returns Peers over time data
223
+ */
224
+ async getPeersOverTime(projectId, query) {
225
+ const { data, error } = await this.client.GET("/projects/{projectId}/peers-over-time", {
226
+ params: { path: { projectId }, query }
227
+ });
228
+ if (error) this.handleError("get peers over time", error);
229
+ return data;
230
+ }
231
+ // ==================== Billing ====================
232
+ /**
233
+ * Get all billing accounts for the current user.
234
+ *
235
+ * @returns Array of billing accounts
236
+ */
237
+ async getBillingAccounts() {
238
+ const { data, error } = await this.client.GET("/billing");
239
+ if (error) this.handleError("get billing accounts", error);
240
+ return data;
241
+ }
242
+ /**
243
+ * Get a specific billing account.
244
+ *
245
+ * @param billingAccountId - The unique identifier of the billing account
246
+ * @returns Billing account details
247
+ */
248
+ async getBillingAccount(billingAccountId) {
249
+ const { data, error } = await this.client.GET("/billing/{billingAccountId}", {
250
+ params: { path: { billingAccountId } }
251
+ });
252
+ if (error) this.handleError("get billing account", error);
253
+ return data;
254
+ }
255
+ /**
256
+ * Get invoices for a specific billing account.
257
+ *
258
+ * @param billingAccountId - The unique identifier of the billing account
259
+ * @returns Array of invoices
260
+ */
261
+ async getBillingAccountInvoices(billingAccountId) {
262
+ const { data, error } = await this.client.GET("/billing/{billingAccountId}/invoices", {
263
+ params: { path: { billingAccountId } }
264
+ });
265
+ if (error) this.handleError("get billing account invoices", error);
266
+ return data;
267
+ }
268
+ /**
269
+ * Create a Stripe setup session for a new billing account.
270
+ *
271
+ * @param body - Setup session creation payload
272
+ * @returns Setup session with redirect URL
273
+ */
274
+ async createSetupSession(body) {
275
+ const { data, error } = await this.client.POST("/billing/create-setup-session", {
276
+ body
277
+ });
278
+ if (error) this.handleError("create setup session", error);
279
+ return data;
280
+ }
281
+ /**
282
+ * Create a Stripe billing portal session.
283
+ *
284
+ * @param billingAccountId - The unique identifier of the billing account
285
+ * @param body - Portal session creation payload
286
+ * @returns Portal session with redirect URL
287
+ */
288
+ async createBillingPortalSession(billingAccountId, body) {
289
+ const { data, error } = await this.client.POST("/billing/{billingAccountId}/create-billing-portal-session", {
290
+ params: { path: { billingAccountId } },
291
+ body
292
+ });
293
+ if (error) this.handleError("create billing portal session", error);
294
+ return data;
295
+ }
296
+ /**
297
+ * Get billing options for a project.
298
+ *
299
+ * @param projectId - The unique identifier of the project
300
+ * @returns Billing options including current state and change options
301
+ */
302
+ async getBillingOptions(projectId) {
303
+ const { data, error } = await this.client.GET("/projects/{projectId}/get-billing-options", {
304
+ params: { path: { projectId } }
305
+ });
306
+ if (error) this.handleError("get billing options", error);
307
+ return data;
308
+ }
309
+ /**
310
+ * Set a billing account on a project.
311
+ *
312
+ * @param projectId - The unique identifier of the project
313
+ * @param body - Billing account and state to set
314
+ * @returns Success response
315
+ */
316
+ async setBillingAccount(projectId, body) {
317
+ const { data, error } = await this.client.POST("/projects/{projectId}/set-billing-account", {
318
+ params: { path: { projectId } },
319
+ body
320
+ });
321
+ if (error) this.handleError("set billing account", error);
322
+ return data;
323
+ }
324
+ /**
325
+ * Cancel billing for a project.
326
+ *
327
+ * @param projectId - The unique identifier of the project
328
+ * @returns Success response
329
+ */
330
+ async cancelBilling(projectId) {
331
+ const { data, error } = await this.client.POST("/projects/{projectId}/cancel-billing", {
332
+ params: { path: { projectId } }
333
+ });
334
+ if (error) this.handleError("cancel billing", error);
335
+ return data;
336
+ }
337
+ // ==================== Invoices ====================
338
+ /**
339
+ * Get all invoices for the current user, optionally filtered by ID.
340
+ *
341
+ * @param query - Optional query parameters for filtering by invoice IDs
342
+ * @returns Array of invoices
343
+ */
344
+ async getInvoices(query) {
345
+ const { data, error } = await this.client.GET("/invoices", {
346
+ params: { query }
347
+ });
348
+ if (error) this.handleError("get invoices", error);
349
+ return data;
350
+ }
351
+ /**
352
+ * Get a preview of the current month's invoice for a project.
353
+ *
354
+ * @param projectId - The unique identifier of the project
355
+ * @returns Invoice preview
356
+ */
357
+ async getInvoicePreview(projectId) {
358
+ const { data, error } = await this.client.GET("/projects/{projectId}/preview-invoice", {
359
+ params: { path: { projectId } }
360
+ });
361
+ if (error) this.handleError("get invoice preview", error);
362
+ return data;
363
+ }
364
+ // ==================== Access Keys ====================
365
+ /**
366
+ * Get a specific access key.
367
+ *
368
+ * @param accessKeyId - The unique identifier of the access key
369
+ * @returns Access key details
370
+ */
371
+ async getAccessKey(accessKeyId) {
372
+ const { data, error } = await this.client.GET("/odin-access-keys/{accessKeyId}", {
373
+ params: { path: { accessKeyId } }
374
+ });
375
+ if (error) this.handleError("get access key", error);
376
+ return data;
377
+ }
378
+ /**
379
+ * Create a new access key for a project.
380
+ *
381
+ * @param body - Access key creation payload
382
+ * @returns Created access key (includes the key value only in this response)
383
+ */
384
+ async createAccessKey(body) {
385
+ const { data, error } = await this.client.POST("/odin-access-keys/", {
386
+ body
387
+ });
388
+ if (error) this.handleError("create access key", error);
389
+ return data;
390
+ }
391
+ /**
392
+ * Update an existing access key's name or description.
393
+ *
394
+ * @param accessKeyId - The unique identifier of the access key
395
+ * @param body - Updated access key fields
396
+ * @returns Success response
397
+ */
398
+ async editAccessKey(accessKeyId, body) {
399
+ const { data, error } = await this.client.PUT("/odin-access-keys/{accessKeyId}", {
400
+ params: { path: { accessKeyId } },
401
+ body
402
+ });
403
+ if (error) this.handleError("edit access key", error);
404
+ return data;
405
+ }
406
+ /**
407
+ * Delete an access key. This operation is irreversible.
408
+ *
409
+ * @param accessKeyId - The unique identifier of the access key
410
+ * @returns Success response
411
+ */
412
+ async deleteAccessKey(accessKeyId) {
413
+ const { data, error } = await this.client.DELETE("/odin-access-keys/{accessKeyId}", {
414
+ params: { path: { accessKeyId } }
415
+ });
416
+ if (error) this.handleError("delete access key", error);
417
+ return data;
418
+ }
419
+ // ==================== Project Members ====================
420
+ /**
421
+ * Add a user to a project with a specified role.
422
+ *
423
+ * @param projectId - The unique identifier of the project
424
+ * @param body - User email and role
425
+ * @returns The created user role
426
+ */
427
+ async addProjectMember(projectId, body) {
428
+ const { data, error } = await this.client.POST("/projects/{projectId}/add-user-permission", {
429
+ params: { path: { projectId } },
430
+ body
431
+ });
432
+ if (error) this.handleError("add project member", error);
433
+ return data;
434
+ }
435
+ /**
436
+ * Revoke a user's permission from a project.
437
+ *
438
+ * @param projectId - The unique identifier of the project
439
+ * @param body - The permission ID to revoke
440
+ * @returns Success response
441
+ */
442
+ async deleteProjectMember(projectId, body) {
443
+ const { data, error } = await this.client.POST("/projects/{projectId}/revoke-user-permission", {
444
+ params: { path: { projectId } },
445
+ body
446
+ });
447
+ if (error) this.handleError("delete project member", error);
448
+ return data;
449
+ }
450
+ /**
451
+ * Change a project member's role.
452
+ *
453
+ * @param projectId - The unique identifier of the project
454
+ * @param body - The permission ID and new role
455
+ * @returns Success response
456
+ */
457
+ async changeMemberRole(projectId, body) {
458
+ const { data, error } = await this.client.POST("/projects/{projectId}/change-user-role", {
459
+ params: { path: { projectId } },
460
+ body
461
+ });
462
+ if (error) this.handleError("change member role", error);
463
+ return data;
464
+ }
465
+ // ==================== Tokens & Secrets ====================
466
+ /**
467
+ * Create an ODIN access token for a project.
468
+ *
469
+ * @param projectId - The unique identifier of the project
470
+ * @param body - Token creation payload
471
+ * @returns The created token
472
+ */
473
+ async createAccessToken(projectId, body) {
474
+ const { data, error } = await this.client.POST("/projects/{projectId}/create-token", {
475
+ params: { path: { projectId } },
476
+ body
477
+ });
478
+ if (error) this.handleError("create access token", error);
479
+ return data;
480
+ }
481
+ /**
482
+ * Revoke the secret for a project.
483
+ *
484
+ * @param projectId - The unique identifier of the project
485
+ * @returns Updated project with new secret
486
+ */
487
+ async revokeSecret(projectId) {
488
+ const { data, error } = await this.client.POST("/projects/{projectId}/revoke-secret", {
489
+ params: { path: { projectId } }
490
+ });
491
+ if (error) this.handleError("revoke secret", error);
492
+ return data;
493
+ }
494
+ // ==================== Resource Package Pricing ====================
495
+ /**
496
+ * Get the price for a single resource package in a specific region.
497
+ *
498
+ * @param projectId - The unique identifier of the project
499
+ * @param body - Resource package, region, and quantity
500
+ * @returns Price information
501
+ */
502
+ async getResourcePackagePrice(projectId, body) {
503
+ const { data, error } = await this.client.POST("/projects/{projectId}/resource-package-price", {
504
+ params: { path: { projectId } },
505
+ body
506
+ });
507
+ if (error) this.handleError("get resource package price", error);
508
+ return data;
509
+ }
510
+ /**
511
+ * Get prices for multiple resource packages in a specific region.
512
+ *
513
+ * @param projectId - The unique identifier of the project
514
+ * @param body - Resource package IDs, region, and quantity
515
+ * @returns Array of price information
516
+ */
517
+ async getResourcePackagePrices(projectId, body) {
518
+ const { data, error } = await this.client.POST("/projects/{projectId}/resource-package-prices", {
519
+ params: { path: { projectId } },
520
+ body
521
+ });
522
+ if (error) this.handleError("get resource package prices", error);
523
+ return data;
524
+ }
525
+ };
526
+ var client_default = PaymentClient;
527
+
528
+ export { PaymentApiError, PaymentAuthError, PaymentClient, PaymentError, PaymentNotFoundError, PaymentRateLimitError, PaymentValidationError, client_default as default };
529
+ //# sourceMappingURL=index.js.map
530
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Payment SDK Error Classes\n *\n * Provides structured error handling for Payment API operations.\n */\n\n// V8-specific stack trace capture (available in Node.js, Chrome, etc.)\ndeclare const Error: ErrorConstructor & {\n captureStackTrace?(targetObject: object, constructorOpt?: Function): void;\n};\n\n/**\n * Base error class for all Payment SDK errors.\n */\nexport class PaymentError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly details?: unknown\n ) {\n super(message);\n this.name = \"PaymentError\";\n // Maintains proper stack trace for where error was thrown (V8 engines)\n if (typeof Error.captureStackTrace === \"function\") {\n Error.captureStackTrace(this, PaymentError);\n }\n }\n}\n\n/**\n * Error thrown when the Payment API returns an application-level error\n * in its response envelope.\n *\n * The Payment API wraps all responses in an envelope:\n * ```json\n * { \"data\": T | null, \"error\": { \"code\": number, \"message\": string } }\n * ```\n *\n * A `PaymentApiError` is thrown when:\n * - `error.code !== 0` (application-level error, even if HTTP status is 200)\n * - `data` is `null` (legacy error pattern from before HTTP status codes were used)\n */\nexport class PaymentApiError extends PaymentError {\n /**\n * Application-level error code from the response envelope.\n * A value of `0` means no specific error code was returned (legacy null-data case).\n */\n public readonly code: number;\n\n /**\n * The HTTP status code of the response.\n * Note: This may be `200` even when there is an application error.\n */\n public readonly httpStatus: number;\n\n constructor(message: string, code: number, httpStatus: number) {\n super(message, httpStatus);\n this.name = \"PaymentApiError\";\n this.code = code;\n this.httpStatus = httpStatus;\n }\n}\n\n/**\n * Error thrown when authentication fails or is required.\n */\nexport class PaymentAuthError extends PaymentError {\n constructor(message = \"Authentication required. Please provide a valid session ID.\") {\n super(message, 401);\n this.name = \"PaymentAuthError\";\n }\n}\n\n/**\n * Error thrown when a requested resource is not found.\n */\nexport class PaymentNotFoundError extends PaymentError {\n constructor(resource: string, id: string) {\n super(`${resource} with ID ${id} not found`, 404);\n this.name = \"PaymentNotFoundError\";\n }\n}\n\n/**\n * Error thrown when request validation fails.\n */\nexport class PaymentValidationError extends PaymentError {\n constructor(message: string, details?: unknown) {\n super(message, 422, details);\n this.name = \"PaymentValidationError\";\n }\n}\n\n/**\n * Error thrown when the API rate limit is exceeded.\n */\nexport class PaymentRateLimitError extends PaymentError {\n constructor(retryAfter?: number) {\n super(\n retryAfter\n ? `Rate limit exceeded. Retry after ${retryAfter} seconds.`\n : \"Rate limit exceeded. Please try again later.\",\n 429,\n { retryAfter }\n );\n this.name = \"PaymentRateLimitError\";\n }\n}\n","/**\n * 4Players Payment API Client\n *\n * A type-safe client for the 4Players Payment API.\n * Works in browsers, Node.js, Deno, Bun, and edge runtimes.\n *\n * @example\n * ```typescript\n * import { PaymentClient } from '@4players/payment';\n *\n * const client = new PaymentClient({ sessionId: 'your-session-id' });\n *\n * const projects = await client.getPaymentProjects();\n * ```\n */\n\nimport createClient, { type Middleware } from \"openapi-fetch\";\nimport type { paths, components, operations } from \"./types.js\";\nimport {\n PaymentError,\n PaymentApiError,\n PaymentAuthError,\n PaymentNotFoundError,\n PaymentRateLimitError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://secure.4players.de/public/api/v1\";\n\n/**\n * Configuration options for the Payment client.\n */\nexport interface PaymentClientConfig {\n /** Fusion session ID for authentication (sent as fusion-sid header) */\n sessionId: string;\n /** Base URL for the Payment API (default: https://secure.4players.de/public/api/v1) */\n baseUrl?: string;\n /** Custom fetch implementation (useful for testing or special environments) */\n fetch?: typeof fetch;\n}\n\n// ==================== Entity types from components.schemas ====================\n\nexport type PaymentProject = components[\"schemas\"][\"PaymentProject\"];\nexport type BillingAccount = components[\"schemas\"][\"BillingAccount\"];\nexport type OdinAccessKey = components[\"schemas\"][\"OdinAccessKey\"];\nexport type OdinUserPermissions = components[\"schemas\"][\"OdinUserPermissions\"];\nexport type OdinUserRole = components[\"schemas\"][\"OdinUserRole\"];\nexport type OdinPeersOverTime = components[\"schemas\"][\"OdinPeersOverTime\"];\nexport type Subscription = components[\"schemas\"][\"Subscription\"];\nexport type Invoice = components[\"schemas\"][\"Invoice\"];\nexport type InvoicePosition = components[\"schemas\"][\"InvoicePosition\"];\nexport type Invoices = components[\"schemas\"][\"Invoices\"];\nexport type SubscriptionPosition = components[\"schemas\"][\"SubscriptionPosition\"];\nexport type TariffParams = components[\"schemas\"][\"TariffParams\"];\nexport type SetupSession = components[\"schemas\"][\"SetupSession\"];\nexport type PortalSession = components[\"schemas\"][\"PortalSession\"];\nexport type TokenPayload = components[\"schemas\"][\"TokenPayload\"];\nexport type BillingOptions = components[\"schemas\"][\"BillingOptions\"];\nexport type BillingChangeOptions = components[\"schemas\"][\"BillingChangeOptions\"];\nexport type BillingStateHistory = components[\"schemas\"][\"BillingStateHistory\"];\nexport type ResourcePackagePrice = components[\"schemas\"][\"ResourcePackagePrice\"];\nexport type SuccessResponse = components[\"schemas\"][\"SuccessResponse\"];\n\n// Enum types\nexport type BillingState = components[\"schemas\"][\"BillingState\"];\nexport type PermissionRole = components[\"schemas\"][\"PermissionRole\"];\nexport type UserStatus = components[\"schemas\"][\"UserStatus\"];\nexport type InvoiceStatus = components[\"schemas\"][\"InvoiceStatus\"];\n\n// ==================== Request/Payload types ====================\n\nexport type AddUserToProjectPayload = components[\"schemas\"][\"AddUserToProjectPayload\"];\nexport type ChangeUserRolePayload = components[\"schemas\"][\"ChangeUserRolePayload\"];\nexport type CreateAccessKeyPayload = components[\"schemas\"][\"CreateAccessKeyPayload\"];\nexport type CreateBillingPortalSessionPayload = components[\"schemas\"][\"CreateBillingPortalSessionPayload\"];\nexport type CreateSetupSessionPayload = components[\"schemas\"][\"CreateSetupSessionPayload\"];\nexport type CreateTokenPayload = components[\"schemas\"][\"CreateTokenPayload\"];\nexport type EditAccessKeyPayload = components[\"schemas\"][\"EditAccessKeyPayload\"];\nexport type EditProjectPayload = components[\"schemas\"][\"EditProjectPayload\"];\nexport type ResourcePackagePricePayload = components[\"schemas\"][\"ResourcePackagePricePayload\"];\nexport type ResourcePackagePricesPayload = components[\"schemas\"][\"ResourcePackagePricesPayload\"];\nexport type RevokeUserPayload = components[\"schemas\"][\"RevokeUserPayload\"];\nexport type SetBillingAccountPayload = components[\"schemas\"][\"SetBillingAccountPayload\"];\n\n// ==================== Query parameter types ====================\n\nexport type GetPeersOverTimeQuery = operations[\"getPeersOverTime\"][\"parameters\"][\"query\"];\nexport type GetInvoicesQuery = operations[\"getInvoices\"][\"parameters\"][\"query\"];\n\n// ==================== Response types ====================\n\nexport type GetPaymentProjectsResponse = operations[\"getPaymentProjects\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type GetPaymentProjectForAppResponse = operations[\"getPaymentProjectForApp\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type GetPeersOverTimeResponse = operations[\"getPeersOverTime\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type GetBillingAccountsResponse = operations[\"getBillingAccounts\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type GetBillingAccountResponse = operations[\"getBillingAccount\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type GetBillingAccountInvoicesResponse = operations[\"getBillingAccountInvoices\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type GetProjectResponse = operations[\"getProject\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type GetAccessKeyResponse = operations[\"getAccessKey\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type GetInvoicesResponse = operations[\"getInvoices\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type GetBillingOptionsResponse = operations[\"getBillingOptions\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type GetInvoicePreviewResponse = operations[\"getInvoicePreview\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type CreateAccessKeyResponse = operations[\"createAccessKey\"][\"responses\"][\"201\"][\"content\"][\"application/json\"];\nexport type CreateSetupSessionResponse = operations[\"createSetupSession\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type CreateBillingPortalSessionResponse = operations[\"createBillingPortalSession\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\nexport type CreateAccessTokenResponse = operations[\"createAccessToken\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\n/**\n * Response envelope used by the Payment API.\n */\ninterface PaymentEnvelope<T = unknown> {\n data: T | null;\n error: {\n code: number;\n message: string;\n };\n}\n\n/**\n * 4Players Payment API Client\n *\n * Provides a type-safe interface to the 4Players Payment REST API for managing\n * projects, billing, invoices, access keys, and user permissions.\n */\nexport class PaymentClient {\n private client: ReturnType<typeof createClient<paths>>;\n\n /**\n * Create a new Payment client instance.\n *\n * @param config - Client configuration\n * @throws {PaymentAuthError} If no session ID is provided\n *\n * @example\n * ```typescript\n * const client = new PaymentClient({\n * sessionId: 'your-fusion-sid'\n * });\n * ```\n */\n constructor(config: PaymentClientConfig) {\n if (!config.sessionId) {\n throw new PaymentAuthError(\"Session ID is required\");\n }\n\n this.client = createClient<paths>({\n baseUrl: config.baseUrl || DEFAULT_BASE_URL,\n headers: {\n \"fusion-sid\": config.sessionId,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n fetch: config.fetch,\n });\n\n // Register the envelope-unwrapping middleware\n this.client.use(this.createEnvelopeMiddleware());\n }\n\n /**\n * Creates middleware that unwraps the Payment API response envelope.\n *\n * The Payment API wraps ALL responses in `{ data, error }`.\n * This middleware:\n * 1. Checks `error.code` — if non-zero, throws `PaymentApiError`\n * 2. Checks `data` — if null, throws `PaymentApiError` (legacy error pattern)\n * 3. Returns a new Response containing only the unwrapped `data`\n */\n private createEnvelopeMiddleware(): Middleware {\n return {\n async onResponse({ response }) {\n const contentType = response.headers.get(\"content-type\");\n if (!contentType?.includes(\"application/json\")) {\n return response;\n }\n\n const text = await response.clone().text();\n let body: unknown;\n try {\n body = JSON.parse(text);\n } catch {\n return response;\n }\n\n if (\n body !== null &&\n typeof body === \"object\" &&\n \"error\" in body &&\n \"data\" in body\n ) {\n const envelope = body as PaymentEnvelope;\n\n // Application-level error (can happen even with HTTP 200!)\n if (envelope.error && envelope.error.code !== 0) {\n throw new PaymentApiError(\n envelope.error.message,\n envelope.error.code,\n response.status\n );\n }\n\n // Legacy error pattern: data is null with HTTP 200\n if (envelope.data === null || envelope.data === undefined) {\n throw new PaymentApiError(\n envelope.error?.message || \"Response data is null\",\n envelope.error?.code || 0,\n response.status\n );\n }\n\n // Return unwrapped data so openapi-fetch sees the schema-matching body\n return new Response(JSON.stringify(envelope.data), {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n }\n\n // Not an envelope — return as-is\n return response;\n },\n };\n }\n\n private handleError(operation: string, error: unknown): never {\n if (error && typeof error === \"object\") {\n const errorObj = error as Record<string, unknown>;\n\n if (errorObj.status === 401 || errorObj.status === 403) {\n throw new PaymentAuthError();\n }\n if (errorObj.status === 404) {\n throw new PaymentNotFoundError(operation, \"unknown\");\n }\n if (errorObj.status === 429) {\n throw new PaymentRateLimitError();\n }\n }\n\n throw new PaymentError(\n `Failed to ${operation}: ${JSON.stringify(error)}`,\n undefined,\n error\n );\n }\n\n // ==================== Projects ====================\n\n /**\n * Get all projects the user has access to.\n *\n * @returns Array of payment projects\n */\n async getPaymentProjects(): Promise<GetPaymentProjectsResponse> {\n const { data, error } = await this.client.GET(\"/apps\");\n if (error) this.handleError(\"get payment projects\", error);\n return data!;\n }\n\n /**\n * Get the details of a specific app including the payment project.\n *\n * @param appId - The ID of the app to retrieve\n * @returns Payment project details\n */\n async getPaymentProjectForApp(appId: string): Promise<GetPaymentProjectForAppResponse> {\n const { data, error } = await this.client.GET(\"/apps/{app_id}\", {\n params: { path: { app_id: appId } },\n });\n if (error) this.handleError(\"get payment project for app\", error);\n return data!;\n }\n\n /**\n * Get a specific project by ID.\n *\n * @param projectId - The unique identifier of the project\n * @returns Project details\n */\n async getProject(projectId: string): Promise<GetProjectResponse> {\n const { data, error } = await this.client.GET(\"/projects/{projectId}\", {\n params: { path: { projectId } },\n });\n if (error) this.handleError(\"get project\", error);\n return data!;\n }\n\n /**\n * Update a project's name, description, or peer limit.\n *\n * @param projectId - The unique identifier of the project\n * @param body - Updated project fields\n * @returns Success response\n */\n async editProject(projectId: string, body: EditProjectPayload): Promise<SuccessResponse> {\n const { data, error } = await this.client.PUT(\"/projects/{projectId}\", {\n params: { path: { projectId } },\n body,\n });\n if (error) this.handleError(\"edit project\", error);\n return data!;\n }\n\n // ==================== Peers / Metrics ====================\n\n /**\n * Get peak peers over time for a project.\n *\n * @param projectId - The unique identifier of the project\n * @param query - Query parameters (start timestamp is required)\n * @returns Peers over time data\n */\n async getPeersOverTime(projectId: string, query: GetPeersOverTimeQuery): Promise<GetPeersOverTimeResponse> {\n const { data, error } = await this.client.GET(\"/projects/{projectId}/peers-over-time\", {\n params: { path: { projectId }, query },\n });\n if (error) this.handleError(\"get peers over time\", error);\n return data!;\n }\n\n // ==================== Billing ====================\n\n /**\n * Get all billing accounts for the current user.\n *\n * @returns Array of billing accounts\n */\n async getBillingAccounts(): Promise<GetBillingAccountsResponse> {\n const { data, error } = await this.client.GET(\"/billing\");\n if (error) this.handleError(\"get billing accounts\", error);\n return data!;\n }\n\n /**\n * Get a specific billing account.\n *\n * @param billingAccountId - The unique identifier of the billing account\n * @returns Billing account details\n */\n async getBillingAccount(billingAccountId: string): Promise<GetBillingAccountResponse> {\n const { data, error } = await this.client.GET(\"/billing/{billingAccountId}\", {\n params: { path: { billingAccountId } },\n });\n if (error) this.handleError(\"get billing account\", error);\n return data!;\n }\n\n /**\n * Get invoices for a specific billing account.\n *\n * @param billingAccountId - The unique identifier of the billing account\n * @returns Array of invoices\n */\n async getBillingAccountInvoices(billingAccountId: string): Promise<GetBillingAccountInvoicesResponse> {\n const { data, error } = await this.client.GET(\"/billing/{billingAccountId}/invoices\", {\n params: { path: { billingAccountId } },\n });\n if (error) this.handleError(\"get billing account invoices\", error);\n return data!;\n }\n\n /**\n * Create a Stripe setup session for a new billing account.\n *\n * @param body - Setup session creation payload\n * @returns Setup session with redirect URL\n */\n async createSetupSession(body: CreateSetupSessionPayload): Promise<CreateSetupSessionResponse> {\n const { data, error } = await this.client.POST(\"/billing/create-setup-session\", {\n body,\n });\n if (error) this.handleError(\"create setup session\", error);\n return data!;\n }\n\n /**\n * Create a Stripe billing portal session.\n *\n * @param billingAccountId - The unique identifier of the billing account\n * @param body - Portal session creation payload\n * @returns Portal session with redirect URL\n */\n async createBillingPortalSession(billingAccountId: string, body: CreateBillingPortalSessionPayload): Promise<CreateBillingPortalSessionResponse> {\n const { data, error } = await this.client.POST(\"/billing/{billingAccountId}/create-billing-portal-session\", {\n params: { path: { billingAccountId } },\n body,\n });\n if (error) this.handleError(\"create billing portal session\", error);\n return data!;\n }\n\n /**\n * Get billing options for a project.\n *\n * @param projectId - The unique identifier of the project\n * @returns Billing options including current state and change options\n */\n async getBillingOptions(projectId: string): Promise<GetBillingOptionsResponse> {\n const { data, error } = await this.client.GET(\"/projects/{projectId}/get-billing-options\", {\n params: { path: { projectId } },\n });\n if (error) this.handleError(\"get billing options\", error);\n return data!;\n }\n\n /**\n * Set a billing account on a project.\n *\n * @param projectId - The unique identifier of the project\n * @param body - Billing account and state to set\n * @returns Success response\n */\n async setBillingAccount(projectId: string, body: SetBillingAccountPayload): Promise<SuccessResponse> {\n const { data, error } = await this.client.POST(\"/projects/{projectId}/set-billing-account\", {\n params: { path: { projectId } },\n body,\n });\n if (error) this.handleError(\"set billing account\", error);\n return data!;\n }\n\n /**\n * Cancel billing for a project.\n *\n * @param projectId - The unique identifier of the project\n * @returns Success response\n */\n async cancelBilling(projectId: string): Promise<SuccessResponse> {\n const { data, error } = await this.client.POST(\"/projects/{projectId}/cancel-billing\", {\n params: { path: { projectId } },\n });\n if (error) this.handleError(\"cancel billing\", error);\n return data!;\n }\n\n // ==================== Invoices ====================\n\n /**\n * Get all invoices for the current user, optionally filtered by ID.\n *\n * @param query - Optional query parameters for filtering by invoice IDs\n * @returns Array of invoices\n */\n async getInvoices(query?: GetInvoicesQuery): Promise<GetInvoicesResponse> {\n const { data, error } = await this.client.GET(\"/invoices\", {\n params: { query },\n });\n if (error) this.handleError(\"get invoices\", error);\n return data!;\n }\n\n /**\n * Get a preview of the current month's invoice for a project.\n *\n * @param projectId - The unique identifier of the project\n * @returns Invoice preview\n */\n async getInvoicePreview(projectId: string): Promise<GetInvoicePreviewResponse> {\n const { data, error } = await this.client.GET(\"/projects/{projectId}/preview-invoice\", {\n params: { path: { projectId } },\n });\n if (error) this.handleError(\"get invoice preview\", error);\n return data!;\n }\n\n // ==================== Access Keys ====================\n\n /**\n * Get a specific access key.\n *\n * @param accessKeyId - The unique identifier of the access key\n * @returns Access key details\n */\n async getAccessKey(accessKeyId: string): Promise<GetAccessKeyResponse> {\n const { data, error } = await this.client.GET(\"/odin-access-keys/{accessKeyId}\", {\n params: { path: { accessKeyId } },\n });\n if (error) this.handleError(\"get access key\", error);\n return data!;\n }\n\n /**\n * Create a new access key for a project.\n *\n * @param body - Access key creation payload\n * @returns Created access key (includes the key value only in this response)\n */\n async createAccessKey(body: CreateAccessKeyPayload): Promise<CreateAccessKeyResponse> {\n const { data, error } = await this.client.POST(\"/odin-access-keys/\", {\n body,\n });\n if (error) this.handleError(\"create access key\", error);\n return data!;\n }\n\n /**\n * Update an existing access key's name or description.\n *\n * @param accessKeyId - The unique identifier of the access key\n * @param body - Updated access key fields\n * @returns Success response\n */\n async editAccessKey(accessKeyId: string, body: EditAccessKeyPayload): Promise<SuccessResponse> {\n const { data, error } = await this.client.PUT(\"/odin-access-keys/{accessKeyId}\", {\n params: { path: { accessKeyId } },\n body,\n });\n if (error) this.handleError(\"edit access key\", error);\n return data!;\n }\n\n /**\n * Delete an access key. This operation is irreversible.\n *\n * @param accessKeyId - The unique identifier of the access key\n * @returns Success response\n */\n async deleteAccessKey(accessKeyId: string): Promise<SuccessResponse> {\n const { data, error } = await this.client.DELETE(\"/odin-access-keys/{accessKeyId}\", {\n params: { path: { accessKeyId } },\n });\n if (error) this.handleError(\"delete access key\", error);\n return data!;\n }\n\n // ==================== Project Members ====================\n\n /**\n * Add a user to a project with a specified role.\n *\n * @param projectId - The unique identifier of the project\n * @param body - User email and role\n * @returns The created user role\n */\n async addProjectMember(projectId: string, body: AddUserToProjectPayload): Promise<OdinUserRole> {\n const { data, error } = await this.client.POST(\"/projects/{projectId}/add-user-permission\", {\n params: { path: { projectId } },\n body,\n });\n if (error) this.handleError(\"add project member\", error);\n return data!;\n }\n\n /**\n * Revoke a user's permission from a project.\n *\n * @param projectId - The unique identifier of the project\n * @param body - The permission ID to revoke\n * @returns Success response\n */\n async deleteProjectMember(projectId: string, body: RevokeUserPayload): Promise<SuccessResponse> {\n const { data, error } = await this.client.POST(\"/projects/{projectId}/revoke-user-permission\", {\n params: { path: { projectId } },\n body,\n });\n if (error) this.handleError(\"delete project member\", error);\n return data!;\n }\n\n /**\n * Change a project member's role.\n *\n * @param projectId - The unique identifier of the project\n * @param body - The permission ID and new role\n * @returns Success response\n */\n async changeMemberRole(projectId: string, body: ChangeUserRolePayload): Promise<SuccessResponse> {\n const { data, error } = await this.client.POST(\"/projects/{projectId}/change-user-role\", {\n params: { path: { projectId } },\n body,\n });\n if (error) this.handleError(\"change member role\", error);\n return data!;\n }\n\n // ==================== Tokens & Secrets ====================\n\n /**\n * Create an ODIN access token for a project.\n *\n * @param projectId - The unique identifier of the project\n * @param body - Token creation payload\n * @returns The created token\n */\n async createAccessToken(projectId: string, body: CreateTokenPayload): Promise<CreateAccessTokenResponse> {\n const { data, error } = await this.client.POST(\"/projects/{projectId}/create-token\", {\n params: { path: { projectId } },\n body,\n });\n if (error) this.handleError(\"create access token\", error);\n return data!;\n }\n\n /**\n * Revoke the secret for a project.\n *\n * @param projectId - The unique identifier of the project\n * @returns Updated project with new secret\n */\n async revokeSecret(projectId: string): Promise<PaymentProject> {\n const { data, error } = await this.client.POST(\"/projects/{projectId}/revoke-secret\", {\n params: { path: { projectId } },\n });\n if (error) this.handleError(\"revoke secret\", error);\n return data!;\n }\n\n // ==================== Resource Package Pricing ====================\n\n /**\n * Get the price for a single resource package in a specific region.\n *\n * @param projectId - The unique identifier of the project\n * @param body - Resource package, region, and quantity\n * @returns Price information\n */\n async getResourcePackagePrice(projectId: string, body: ResourcePackagePricePayload): Promise<ResourcePackagePrice> {\n const { data, error } = await this.client.POST(\"/projects/{projectId}/resource-package-price\", {\n params: { path: { projectId } },\n body,\n });\n if (error) this.handleError(\"get resource package price\", error);\n return data!;\n }\n\n /**\n * Get prices for multiple resource packages in a specific region.\n *\n * @param projectId - The unique identifier of the project\n * @param body - Resource package IDs, region, and quantity\n * @returns Array of price information\n */\n async getResourcePackagePrices(projectId: string, body: ResourcePackagePricesPayload): Promise<ResourcePackagePrice[]> {\n const { data, error } = await this.client.POST(\"/projects/{projectId}/resource-package-prices\", {\n params: { path: { projectId } },\n body,\n });\n if (error) this.handleError(\"get resource package prices\", error);\n return data!;\n }\n}\n\nexport default PaymentClient;\n"]}