pgbeam 0.1.0 → 0.2.1
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/README.md +56 -0
- package/dist/index.cjs +568 -0
- package/dist/{index.d.ts → index.d.cts} +785 -236
- package/dist/index.d.mts +4262 -0
- package/dist/{index.js → index.mjs} +190 -89
- package/dist/operations.cjs +328 -0
- package/dist/{operations.d.ts → operations.d.cts} +582 -250
- package/dist/operations.d.mts +3692 -0
- package/dist/{operations.js → operations.mjs} +70 -73
- package/package.json +31 -28
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# pgbeam
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for the [PgBeam](https://pgbeam.com) API — globally distributed
|
|
4
|
+
PostgreSQL proxy platform with connection pooling and query caching.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install pgbeam
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { PgBeamClient } from "pgbeam";
|
|
16
|
+
|
|
17
|
+
const client = new PgBeamClient({
|
|
18
|
+
token: "your-api-token",
|
|
19
|
+
baseUrl: "https://api.pgbeam.com",
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Tag-based access
|
|
23
|
+
const projects = await client.api.projects.listProjects({
|
|
24
|
+
queryParams: { org_id: "org_123" },
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Route-based access
|
|
28
|
+
const project = await client.api.request("GET /v1/projects/{project_id}", {
|
|
29
|
+
pathParams: { project_id: "proj_123" },
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Error handling
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { PgBeamClient, ApiError } from "pgbeam";
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
await client.api.projects.getProject({
|
|
40
|
+
pathParams: { project_id: "proj_123" },
|
|
41
|
+
});
|
|
42
|
+
} catch (err) {
|
|
43
|
+
if (err instanceof ApiError) {
|
|
44
|
+
console.error(err.status, err.message);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Operations map
|
|
50
|
+
|
|
51
|
+
The `pgbeam/operations` export provides route and tag metadata for building
|
|
52
|
+
tooling on top of the SDK:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { operationsByTag, operationsByPath } from "pgbeam/operations";
|
|
56
|
+
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
|
|
3
|
+
var _extends = require('@swc/helpers/_/_extends');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generated by scripts/generate-maps.ts — do not edit manually.
|
|
7
|
+
* Run: pnpm --filter pgbeam generate
|
|
8
|
+
*/ const operationsByTag = {
|
|
9
|
+
account: {
|
|
10
|
+
exportAccountData: {
|
|
11
|
+
method: "GET",
|
|
12
|
+
path: "/v1/account/export"
|
|
13
|
+
},
|
|
14
|
+
getOnboardingProgress: {
|
|
15
|
+
method: "GET",
|
|
16
|
+
path: "/v1/organizations/{org_id}/onboarding"
|
|
17
|
+
},
|
|
18
|
+
updateOnboardingProgress: {
|
|
19
|
+
method: "PATCH",
|
|
20
|
+
path: "/v1/organizations/{org_id}/onboarding"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
analytics: {
|
|
24
|
+
getOrganizationActivity: {
|
|
25
|
+
method: "GET",
|
|
26
|
+
path: "/v1/organizations/{org_id}/activity"
|
|
27
|
+
},
|
|
28
|
+
listPlans: {
|
|
29
|
+
method: "GET",
|
|
30
|
+
path: "/v1/plans"
|
|
31
|
+
},
|
|
32
|
+
getOrganizationPlan: {
|
|
33
|
+
method: "GET",
|
|
34
|
+
path: "/v1/organizations/{org_id}/plan"
|
|
35
|
+
},
|
|
36
|
+
updateSpendLimit: {
|
|
37
|
+
method: "PUT",
|
|
38
|
+
path: "/v1/organizations/{org_id}/spend-limit"
|
|
39
|
+
},
|
|
40
|
+
submitCancellationFeedback: {
|
|
41
|
+
method: "POST",
|
|
42
|
+
path: "/v1/organizations/{org_id}/cancellation-feedback"
|
|
43
|
+
},
|
|
44
|
+
getProjectInsights: {
|
|
45
|
+
method: "GET",
|
|
46
|
+
path: "/v1/projects/{project_id}/insights"
|
|
47
|
+
},
|
|
48
|
+
getOrganizationUsage: {
|
|
49
|
+
method: "GET",
|
|
50
|
+
path: "/v1/organizations/{org_id}/usage"
|
|
51
|
+
},
|
|
52
|
+
getProjectUsage: {
|
|
53
|
+
method: "GET",
|
|
54
|
+
path: "/v1/projects/{project_id}/usage"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
projects: {
|
|
58
|
+
listCacheRules: {
|
|
59
|
+
method: "GET",
|
|
60
|
+
path: "/v1/projects/{project_id}/databases/{database_id}/cache-rules"
|
|
61
|
+
},
|
|
62
|
+
updateCacheRule: {
|
|
63
|
+
method: "PUT",
|
|
64
|
+
path: "/v1/projects/{project_id}/databases/{database_id}/cache-rules/{query_hash}"
|
|
65
|
+
},
|
|
66
|
+
listCustomDomains: {
|
|
67
|
+
method: "GET",
|
|
68
|
+
path: "/v1/projects/{project_id}/domains"
|
|
69
|
+
},
|
|
70
|
+
createCustomDomain: {
|
|
71
|
+
method: "POST",
|
|
72
|
+
path: "/v1/projects/{project_id}/domains"
|
|
73
|
+
},
|
|
74
|
+
deleteCustomDomain: {
|
|
75
|
+
method: "DELETE",
|
|
76
|
+
path: "/v1/projects/{project_id}/domains/{domain_id}"
|
|
77
|
+
},
|
|
78
|
+
verifyCustomDomain: {
|
|
79
|
+
method: "POST",
|
|
80
|
+
path: "/v1/projects/{project_id}/domains/{domain_id}/verify"
|
|
81
|
+
},
|
|
82
|
+
listProjects: {
|
|
83
|
+
method: "GET",
|
|
84
|
+
path: "/v1/projects"
|
|
85
|
+
},
|
|
86
|
+
createProject: {
|
|
87
|
+
method: "POST",
|
|
88
|
+
path: "/v1/projects"
|
|
89
|
+
},
|
|
90
|
+
getProject: {
|
|
91
|
+
method: "GET",
|
|
92
|
+
path: "/v1/projects/{project_id}"
|
|
93
|
+
},
|
|
94
|
+
updateProject: {
|
|
95
|
+
method: "PATCH",
|
|
96
|
+
path: "/v1/projects/{project_id}"
|
|
97
|
+
},
|
|
98
|
+
deleteProject: {
|
|
99
|
+
method: "DELETE",
|
|
100
|
+
path: "/v1/projects/{project_id}"
|
|
101
|
+
},
|
|
102
|
+
getProjectMetrics: {
|
|
103
|
+
method: "GET",
|
|
104
|
+
path: "/v1/projects/{project_id}/metrics"
|
|
105
|
+
},
|
|
106
|
+
listReplicas: {
|
|
107
|
+
method: "GET",
|
|
108
|
+
path: "/v1/databases/{database_id}/replicas"
|
|
109
|
+
},
|
|
110
|
+
createReplica: {
|
|
111
|
+
method: "POST",
|
|
112
|
+
path: "/v1/databases/{database_id}/replicas"
|
|
113
|
+
},
|
|
114
|
+
deleteReplica: {
|
|
115
|
+
method: "DELETE",
|
|
116
|
+
path: "/v1/databases/{database_id}/replicas/{replica_id}"
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
databases: {
|
|
120
|
+
listDatabases: {
|
|
121
|
+
method: "GET",
|
|
122
|
+
path: "/v1/projects/{project_id}/databases"
|
|
123
|
+
},
|
|
124
|
+
createDatabase: {
|
|
125
|
+
method: "POST",
|
|
126
|
+
path: "/v1/projects/{project_id}/databases"
|
|
127
|
+
},
|
|
128
|
+
getDatabase: {
|
|
129
|
+
method: "GET",
|
|
130
|
+
path: "/v1/projects/{project_id}/databases/{database_id}"
|
|
131
|
+
},
|
|
132
|
+
updateDatabase: {
|
|
133
|
+
method: "PATCH",
|
|
134
|
+
path: "/v1/projects/{project_id}/databases/{database_id}"
|
|
135
|
+
},
|
|
136
|
+
deleteDatabase: {
|
|
137
|
+
method: "DELETE",
|
|
138
|
+
path: "/v1/projects/{project_id}/databases/{database_id}"
|
|
139
|
+
},
|
|
140
|
+
testDatabaseConnection: {
|
|
141
|
+
method: "POST",
|
|
142
|
+
path: "/v1/projects/{project_id}/databases/{database_id}/test-connection"
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
platform: {
|
|
146
|
+
getHealth: {
|
|
147
|
+
method: "GET",
|
|
148
|
+
path: "/v1/health"
|
|
149
|
+
},
|
|
150
|
+
listRegions: {
|
|
151
|
+
method: "GET",
|
|
152
|
+
path: "/v1/regions"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const operationsByPath = {
|
|
157
|
+
"GET /v1/account/export": {
|
|
158
|
+
method: "GET",
|
|
159
|
+
path: "/v1/account/export",
|
|
160
|
+
operationId: "exportAccountData"
|
|
161
|
+
},
|
|
162
|
+
"GET /v1/organizations/{org_id}/activity": {
|
|
163
|
+
method: "GET",
|
|
164
|
+
path: "/v1/organizations/{org_id}/activity",
|
|
165
|
+
operationId: "getOrganizationActivity"
|
|
166
|
+
},
|
|
167
|
+
"GET /v1/plans": {
|
|
168
|
+
method: "GET",
|
|
169
|
+
path: "/v1/plans",
|
|
170
|
+
operationId: "listPlans"
|
|
171
|
+
},
|
|
172
|
+
"GET /v1/organizations/{org_id}/plan": {
|
|
173
|
+
method: "GET",
|
|
174
|
+
path: "/v1/organizations/{org_id}/plan",
|
|
175
|
+
operationId: "getOrganizationPlan"
|
|
176
|
+
},
|
|
177
|
+
"PUT /v1/organizations/{org_id}/spend-limit": {
|
|
178
|
+
method: "PUT",
|
|
179
|
+
path: "/v1/organizations/{org_id}/spend-limit",
|
|
180
|
+
operationId: "updateSpendLimit"
|
|
181
|
+
},
|
|
182
|
+
"POST /v1/organizations/{org_id}/cancellation-feedback": {
|
|
183
|
+
method: "POST",
|
|
184
|
+
path: "/v1/organizations/{org_id}/cancellation-feedback",
|
|
185
|
+
operationId: "submitCancellationFeedback"
|
|
186
|
+
},
|
|
187
|
+
"GET /v1/projects/{project_id}/databases/{database_id}/cache-rules": {
|
|
188
|
+
method: "GET",
|
|
189
|
+
path: "/v1/projects/{project_id}/databases/{database_id}/cache-rules",
|
|
190
|
+
operationId: "listCacheRules"
|
|
191
|
+
},
|
|
192
|
+
"PUT /v1/projects/{project_id}/databases/{database_id}/cache-rules/{query_hash}": {
|
|
193
|
+
method: "PUT",
|
|
194
|
+
path: "/v1/projects/{project_id}/databases/{database_id}/cache-rules/{query_hash}",
|
|
195
|
+
operationId: "updateCacheRule"
|
|
196
|
+
},
|
|
197
|
+
"GET /v1/projects/{project_id}/databases": {
|
|
198
|
+
method: "GET",
|
|
199
|
+
path: "/v1/projects/{project_id}/databases",
|
|
200
|
+
operationId: "listDatabases"
|
|
201
|
+
},
|
|
202
|
+
"POST /v1/projects/{project_id}/databases": {
|
|
203
|
+
method: "POST",
|
|
204
|
+
path: "/v1/projects/{project_id}/databases",
|
|
205
|
+
operationId: "createDatabase"
|
|
206
|
+
},
|
|
207
|
+
"GET /v1/projects/{project_id}/databases/{database_id}": {
|
|
208
|
+
method: "GET",
|
|
209
|
+
path: "/v1/projects/{project_id}/databases/{database_id}",
|
|
210
|
+
operationId: "getDatabase"
|
|
211
|
+
},
|
|
212
|
+
"PATCH /v1/projects/{project_id}/databases/{database_id}": {
|
|
213
|
+
method: "PATCH",
|
|
214
|
+
path: "/v1/projects/{project_id}/databases/{database_id}",
|
|
215
|
+
operationId: "updateDatabase"
|
|
216
|
+
},
|
|
217
|
+
"DELETE /v1/projects/{project_id}/databases/{database_id}": {
|
|
218
|
+
method: "DELETE",
|
|
219
|
+
path: "/v1/projects/{project_id}/databases/{database_id}",
|
|
220
|
+
operationId: "deleteDatabase"
|
|
221
|
+
},
|
|
222
|
+
"POST /v1/projects/{project_id}/databases/{database_id}/test-connection": {
|
|
223
|
+
method: "POST",
|
|
224
|
+
path: "/v1/projects/{project_id}/databases/{database_id}/test-connection",
|
|
225
|
+
operationId: "testDatabaseConnection"
|
|
226
|
+
},
|
|
227
|
+
"GET /v1/projects/{project_id}/domains": {
|
|
228
|
+
method: "GET",
|
|
229
|
+
path: "/v1/projects/{project_id}/domains",
|
|
230
|
+
operationId: "listCustomDomains"
|
|
231
|
+
},
|
|
232
|
+
"POST /v1/projects/{project_id}/domains": {
|
|
233
|
+
method: "POST",
|
|
234
|
+
path: "/v1/projects/{project_id}/domains",
|
|
235
|
+
operationId: "createCustomDomain"
|
|
236
|
+
},
|
|
237
|
+
"DELETE /v1/projects/{project_id}/domains/{domain_id}": {
|
|
238
|
+
method: "DELETE",
|
|
239
|
+
path: "/v1/projects/{project_id}/domains/{domain_id}",
|
|
240
|
+
operationId: "deleteCustomDomain"
|
|
241
|
+
},
|
|
242
|
+
"POST /v1/projects/{project_id}/domains/{domain_id}/verify": {
|
|
243
|
+
method: "POST",
|
|
244
|
+
path: "/v1/projects/{project_id}/domains/{domain_id}/verify",
|
|
245
|
+
operationId: "verifyCustomDomain"
|
|
246
|
+
},
|
|
247
|
+
"GET /v1/health": {
|
|
248
|
+
method: "GET",
|
|
249
|
+
path: "/v1/health",
|
|
250
|
+
operationId: "getHealth"
|
|
251
|
+
},
|
|
252
|
+
"GET /v1/projects/{project_id}/insights": {
|
|
253
|
+
method: "GET",
|
|
254
|
+
path: "/v1/projects/{project_id}/insights",
|
|
255
|
+
operationId: "getProjectInsights"
|
|
256
|
+
},
|
|
257
|
+
"GET /v1/organizations/{org_id}/onboarding": {
|
|
258
|
+
method: "GET",
|
|
259
|
+
path: "/v1/organizations/{org_id}/onboarding",
|
|
260
|
+
operationId: "getOnboardingProgress"
|
|
261
|
+
},
|
|
262
|
+
"PATCH /v1/organizations/{org_id}/onboarding": {
|
|
263
|
+
method: "PATCH",
|
|
264
|
+
path: "/v1/organizations/{org_id}/onboarding",
|
|
265
|
+
operationId: "updateOnboardingProgress"
|
|
266
|
+
},
|
|
267
|
+
"GET /v1/projects": {
|
|
268
|
+
method: "GET",
|
|
269
|
+
path: "/v1/projects",
|
|
270
|
+
operationId: "listProjects"
|
|
271
|
+
},
|
|
272
|
+
"POST /v1/projects": {
|
|
273
|
+
method: "POST",
|
|
274
|
+
path: "/v1/projects",
|
|
275
|
+
operationId: "createProject"
|
|
276
|
+
},
|
|
277
|
+
"GET /v1/projects/{project_id}": {
|
|
278
|
+
method: "GET",
|
|
279
|
+
path: "/v1/projects/{project_id}",
|
|
280
|
+
operationId: "getProject"
|
|
281
|
+
},
|
|
282
|
+
"PATCH /v1/projects/{project_id}": {
|
|
283
|
+
method: "PATCH",
|
|
284
|
+
path: "/v1/projects/{project_id}",
|
|
285
|
+
operationId: "updateProject"
|
|
286
|
+
},
|
|
287
|
+
"DELETE /v1/projects/{project_id}": {
|
|
288
|
+
method: "DELETE",
|
|
289
|
+
path: "/v1/projects/{project_id}",
|
|
290
|
+
operationId: "deleteProject"
|
|
291
|
+
},
|
|
292
|
+
"GET /v1/projects/{project_id}/metrics": {
|
|
293
|
+
method: "GET",
|
|
294
|
+
path: "/v1/projects/{project_id}/metrics",
|
|
295
|
+
operationId: "getProjectMetrics"
|
|
296
|
+
},
|
|
297
|
+
"GET /v1/regions": {
|
|
298
|
+
method: "GET",
|
|
299
|
+
path: "/v1/regions",
|
|
300
|
+
operationId: "listRegions"
|
|
301
|
+
},
|
|
302
|
+
"GET /v1/databases/{database_id}/replicas": {
|
|
303
|
+
method: "GET",
|
|
304
|
+
path: "/v1/databases/{database_id}/replicas",
|
|
305
|
+
operationId: "listReplicas"
|
|
306
|
+
},
|
|
307
|
+
"POST /v1/databases/{database_id}/replicas": {
|
|
308
|
+
method: "POST",
|
|
309
|
+
path: "/v1/databases/{database_id}/replicas",
|
|
310
|
+
operationId: "createReplica"
|
|
311
|
+
},
|
|
312
|
+
"DELETE /v1/databases/{database_id}/replicas/{replica_id}": {
|
|
313
|
+
method: "DELETE",
|
|
314
|
+
path: "/v1/databases/{database_id}/replicas/{replica_id}",
|
|
315
|
+
operationId: "deleteReplica"
|
|
316
|
+
},
|
|
317
|
+
"GET /v1/organizations/{org_id}/usage": {
|
|
318
|
+
method: "GET",
|
|
319
|
+
path: "/v1/organizations/{org_id}/usage",
|
|
320
|
+
operationId: "getOrganizationUsage"
|
|
321
|
+
},
|
|
322
|
+
"GET /v1/projects/{project_id}/usage": {
|
|
323
|
+
method: "GET",
|
|
324
|
+
path: "/v1/projects/{project_id}/usage",
|
|
325
|
+
operationId: "getProjectUsage"
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
class ApiError extends Error {
|
|
330
|
+
constructor(status, statusText, body){
|
|
331
|
+
var _extractMessage;
|
|
332
|
+
const message = typeof body === "object" && body !== null ? (_extractMessage = extractMessage(body)) != null ? _extractMessage : statusText : statusText;
|
|
333
|
+
super(message);
|
|
334
|
+
this.name = "ApiError";
|
|
335
|
+
this.status = status;
|
|
336
|
+
this.statusText = statusText;
|
|
337
|
+
this.body = body;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/** Extract a human-readable message from an API error body. */ function extractMessage(body) {
|
|
341
|
+
if (typeof body !== "object" || body === null) return undefined;
|
|
342
|
+
const obj = body;
|
|
343
|
+
// API returns { error: { code, message } }
|
|
344
|
+
if (typeof obj.error === "object" && obj.error !== null) {
|
|
345
|
+
const inner = obj.error;
|
|
346
|
+
if (typeof inner.message === "string") return inner.message;
|
|
347
|
+
}
|
|
348
|
+
if (typeof obj.message === "string") return obj.message;
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
const RETRYABLE_STATUS_CODES = new Set([
|
|
352
|
+
408,
|
|
353
|
+
429,
|
|
354
|
+
502,
|
|
355
|
+
503,
|
|
356
|
+
504
|
|
357
|
+
]);
|
|
358
|
+
const DEFAULT_RETRY = {
|
|
359
|
+
maxRetries: 5,
|
|
360
|
+
initialDelayMs: 500,
|
|
361
|
+
maxDelayMs: 30000,
|
|
362
|
+
idempotencyKeys: true
|
|
363
|
+
};
|
|
364
|
+
function resolveRetry(config) {
|
|
365
|
+
if (!config) return _extends._({}, DEFAULT_RETRY, {
|
|
366
|
+
maxRetries: 0
|
|
367
|
+
});
|
|
368
|
+
return _extends._({}, DEFAULT_RETRY, config);
|
|
369
|
+
}
|
|
370
|
+
/** Parse Retry-After header as milliseconds. Returns undefined if unparseable. */ function parseRetryAfter(response) {
|
|
371
|
+
const header = response.headers.get("Retry-After");
|
|
372
|
+
if (!header) return undefined;
|
|
373
|
+
// Integer seconds
|
|
374
|
+
const seconds = Number(header);
|
|
375
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
376
|
+
return seconds * 1000;
|
|
377
|
+
}
|
|
378
|
+
// HTTP-date
|
|
379
|
+
const date = Date.parse(header);
|
|
380
|
+
if (Number.isFinite(date)) {
|
|
381
|
+
const ms = date - Date.now();
|
|
382
|
+
return ms > 0 ? ms : 0;
|
|
383
|
+
}
|
|
384
|
+
return undefined;
|
|
385
|
+
}
|
|
386
|
+
/** Compute exponential backoff with jitter. */ function backoff(attempt, initialDelayMs, maxDelayMs) {
|
|
387
|
+
const delay = Math.min(initialDelayMs * 2 ** attempt, maxDelayMs);
|
|
388
|
+
return delay * (0.5 + Math.random());
|
|
389
|
+
}
|
|
390
|
+
/** Generate a UUID v4 using crypto.randomUUID if available, otherwise fallback. */ function generateUUID() {
|
|
391
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
392
|
+
return crypto.randomUUID();
|
|
393
|
+
}
|
|
394
|
+
// Fallback for environments without crypto.randomUUID
|
|
395
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c)=>{
|
|
396
|
+
const r = Math.random() * 16 | 0;
|
|
397
|
+
const v = c === "x" ? r : r & 0x3 | 0x8;
|
|
398
|
+
return v.toString(16);
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
function isMutatingMethod(method) {
|
|
402
|
+
const upper = method.toUpperCase();
|
|
403
|
+
return upper === "POST" || upper === "PATCH";
|
|
404
|
+
}
|
|
405
|
+
async function fetcher(options) {
|
|
406
|
+
var _options_fetchImpl;
|
|
407
|
+
let url = options.path;
|
|
408
|
+
if (options.pathParams) {
|
|
409
|
+
for (const [key, value] of Object.entries(options.pathParams)){
|
|
410
|
+
url = url.replace(`{${key}}`, encodeURIComponent(value));
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
const fullUrl = new URL(url, options.baseUrl);
|
|
414
|
+
if (options.queryParams) {
|
|
415
|
+
for (const [key, value] of Object.entries(options.queryParams)){
|
|
416
|
+
if (value !== undefined && value !== null) {
|
|
417
|
+
fullUrl.searchParams.set(key, String(value));
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
const headers = {};
|
|
422
|
+
if (options.token) {
|
|
423
|
+
headers.Authorization = `Bearer ${options.token}`;
|
|
424
|
+
}
|
|
425
|
+
if (options.body !== undefined) {
|
|
426
|
+
headers["Content-Type"] = "application/json";
|
|
427
|
+
}
|
|
428
|
+
const fetchFn = (_options_fetchImpl = options.fetchImpl) != null ? _options_fetchImpl : globalThis.fetch;
|
|
429
|
+
const retry = resolveRetry(options.retry);
|
|
430
|
+
const urlStr = fullUrl.toString();
|
|
431
|
+
const fetchBody = options.body !== undefined ? JSON.stringify(options.body) : undefined;
|
|
432
|
+
// Generate idempotency key once, reused across all retry attempts.
|
|
433
|
+
const idempotencyKey = retry.maxRetries > 0 && retry.idempotencyKeys && isMutatingMethod(options.method) ? generateUUID() : undefined;
|
|
434
|
+
for(let attempt = 0; attempt <= retry.maxRetries; attempt++){
|
|
435
|
+
const reqHeaders = _extends._({}, headers);
|
|
436
|
+
// Attach idempotency key on all attempts for mutating requests.
|
|
437
|
+
if (idempotencyKey) {
|
|
438
|
+
reqHeaders["Idempotency-Key"] = idempotencyKey;
|
|
439
|
+
}
|
|
440
|
+
try {
|
|
441
|
+
var _parseRetryAfter;
|
|
442
|
+
const response = await fetchFn(urlStr, {
|
|
443
|
+
method: options.method,
|
|
444
|
+
headers: reqHeaders,
|
|
445
|
+
body: fetchBody
|
|
446
|
+
});
|
|
447
|
+
if (options.onResponse) {
|
|
448
|
+
await options.onResponse(response);
|
|
449
|
+
}
|
|
450
|
+
if (response.ok) {
|
|
451
|
+
return parseResponseBody(response);
|
|
452
|
+
}
|
|
453
|
+
// Non-retryable error or last attempt — throw immediately.
|
|
454
|
+
if (!RETRYABLE_STATUS_CODES.has(response.status) || attempt === retry.maxRetries) {
|
|
455
|
+
const errorBody = await response.json().catch(()=>null);
|
|
456
|
+
throw new ApiError(response.status, response.statusText, errorBody);
|
|
457
|
+
}
|
|
458
|
+
// Retryable error — wait and retry.
|
|
459
|
+
const delay = (_parseRetryAfter = parseRetryAfter(response)) != null ? _parseRetryAfter : backoff(attempt, retry.initialDelayMs, retry.maxDelayMs);
|
|
460
|
+
await sleep(delay);
|
|
461
|
+
} catch (err) {
|
|
462
|
+
// If it's already an ApiError, rethrow (we threw it above).
|
|
463
|
+
if (err instanceof ApiError) throw err;
|
|
464
|
+
// Network error — retry if we have attempts left.
|
|
465
|
+
if (attempt === retry.maxRetries) throw err;
|
|
466
|
+
const delay = backoff(attempt, retry.initialDelayMs, retry.maxDelayMs);
|
|
467
|
+
await sleep(delay);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
// Unreachable — the loop either returns or throws.
|
|
471
|
+
throw new Error("fetcher: exhausted all retry attempts");
|
|
472
|
+
}
|
|
473
|
+
async function parseResponseBody(response) {
|
|
474
|
+
if (response.status === 204) return undefined;
|
|
475
|
+
const contentType = response.headers.get("content-type");
|
|
476
|
+
if (contentType == null ? void 0 : contentType.includes("application/json")) {
|
|
477
|
+
return response.json();
|
|
478
|
+
}
|
|
479
|
+
// Fallback: try JSON, return undefined if body is empty/non-JSON
|
|
480
|
+
const text = await response.text();
|
|
481
|
+
if (!text) return undefined;
|
|
482
|
+
try {
|
|
483
|
+
return JSON.parse(text);
|
|
484
|
+
} catch (unused) {
|
|
485
|
+
return undefined;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
function sleep(ms) {
|
|
489
|
+
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
class PgBeamClient {
|
|
493
|
+
async _resolveToken() {
|
|
494
|
+
if (typeof this._tokenOrFn === "function") {
|
|
495
|
+
return this._tokenOrFn();
|
|
496
|
+
}
|
|
497
|
+
return this._tokenOrFn;
|
|
498
|
+
}
|
|
499
|
+
_call(method, path) {
|
|
500
|
+
return async (params = {})=>{
|
|
501
|
+
const token = await this._resolveToken();
|
|
502
|
+
return fetcher({
|
|
503
|
+
method,
|
|
504
|
+
path,
|
|
505
|
+
pathParams: params.pathParams,
|
|
506
|
+
queryParams: params.queryParams,
|
|
507
|
+
body: params.body,
|
|
508
|
+
baseUrl: this._baseUrl,
|
|
509
|
+
token,
|
|
510
|
+
fetchImpl: this._fetchImpl,
|
|
511
|
+
onResponse: this._onResponse,
|
|
512
|
+
retry: this._retry
|
|
513
|
+
});
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
/** Access API operations via tag-based namespaces or `.request()`. */ get api() {
|
|
517
|
+
if (this._api) return this._api;
|
|
518
|
+
const request = async (route, params)=>{
|
|
519
|
+
const meta = operationsByPath[route];
|
|
520
|
+
if (!meta) throw new Error(`Unknown route: ${String(route)}`);
|
|
521
|
+
const token = await this._resolveToken();
|
|
522
|
+
return fetcher({
|
|
523
|
+
method: meta.method,
|
|
524
|
+
path: meta.path,
|
|
525
|
+
pathParams: params == null ? void 0 : params.pathParams,
|
|
526
|
+
queryParams: params == null ? void 0 : params.queryParams,
|
|
527
|
+
body: params == null ? void 0 : params.body,
|
|
528
|
+
baseUrl: this._baseUrl,
|
|
529
|
+
token,
|
|
530
|
+
fetchImpl: this._fetchImpl,
|
|
531
|
+
onResponse: this._onResponse,
|
|
532
|
+
retry: this._retry
|
|
533
|
+
});
|
|
534
|
+
};
|
|
535
|
+
this._api = new Proxy({}, {
|
|
536
|
+
get: (_, prop)=>{
|
|
537
|
+
if (prop === "request") return request;
|
|
538
|
+
const tagOps = operationsByTag[prop];
|
|
539
|
+
if (!tagOps) return undefined;
|
|
540
|
+
return new Proxy({}, {
|
|
541
|
+
get: (_, method)=>{
|
|
542
|
+
const ops = tagOps;
|
|
543
|
+
const opMeta = ops[method];
|
|
544
|
+
if (!opMeta) return undefined;
|
|
545
|
+
return this._call(opMeta.method, opMeta.path);
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
return this._api;
|
|
551
|
+
}
|
|
552
|
+
constructor(options){
|
|
553
|
+
var _options_retry;
|
|
554
|
+
this._baseUrl = options.baseUrl;
|
|
555
|
+
this._tokenOrFn = options.token;
|
|
556
|
+
this._fetchImpl = options.fetch;
|
|
557
|
+
this._onResponse = options.onResponse;
|
|
558
|
+
this._retry = options.retry === false ? {
|
|
559
|
+
maxRetries: 0
|
|
560
|
+
} : (_options_retry = options.retry) != null ? _options_retry : {
|
|
561
|
+
maxRetries: 5
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
exports.ApiError = ApiError;
|
|
567
|
+
exports.PgBeamClient = PgBeamClient;
|
|
568
|
+
exports.extractMessage = extractMessage;
|