@blimu/client 0.7.0 → 1.1.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 +26 -79
- package/dist/client.d.mts +15 -59
- package/dist/client.d.ts +15 -59
- package/dist/client.js +1085 -109
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +1112 -4
- package/dist/client.mjs.map +1 -0
- package/dist/index.d.mts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +1227 -130
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1317 -18
- package/dist/index.mjs.map +1 -0
- package/dist/{schema-jwKwV_Bm.d.mts → schema-B4iFbKly.d.mts} +4 -15
- package/dist/{schema-jwKwV_Bm.d.ts → schema-B4iFbKly.d.ts} +4 -15
- package/dist/schema.d.mts +2 -1
- package/dist/schema.d.ts +2 -1
- package/dist/schema.js +1 -0
- package/dist/schema.js.map +1 -0
- package/dist/schema.mjs +1 -1
- package/dist/schema.mjs.map +1 -0
- package/dist/schema.zod-CyY7RTSY.d.mts +48 -0
- package/dist/schema.zod-CyY7RTSY.d.ts +48 -0
- package/dist/schema.zod.d.mts +2 -0
- package/dist/schema.zod.d.ts +2 -0
- package/dist/schema.zod.js +77 -0
- package/dist/schema.zod.js.map +1 -0
- package/dist/schema.zod.mjs +47 -0
- package/dist/schema.zod.mjs.map +1 -0
- package/dist/services/auth.d.mts +3 -25
- package/dist/services/auth.d.ts +3 -25
- package/dist/services/auth.js +7 -9
- package/dist/services/auth.js.map +1 -0
- package/dist/services/auth.mjs +59 -5
- package/dist/services/auth.mjs.map +1 -0
- package/dist/services/entitlements.d.mts +3 -11
- package/dist/services/entitlements.d.ts +3 -11
- package/dist/services/entitlements.js +8 -6
- package/dist/services/entitlements.js.map +1 -0
- package/dist/services/entitlements.mjs +28 -5
- package/dist/services/entitlements.mjs.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/utils.d.mts +2 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +1078 -3
- package/dist/utils.js.map +1 -0
- package/dist/utils.mjs +1092 -5
- package/dist/utils.mjs.map +1 -0
- package/package.json +18 -40
- package/dist/chunk-7SBLH5KM.mjs +0 -6
- package/dist/chunk-ATZGLDGF.mjs +0 -143
- package/dist/chunk-ENXZU3RF.mjs +0 -30
- package/dist/chunk-LZ27JJ4R.mjs +0 -25
- package/dist/chunk-YGEJFE6U.mjs +0 -65
package/dist/index.mjs
CHANGED
|
@@ -1,20 +1,1280 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// ../../node_modules/@blimu/fetch/dist/index.js
|
|
8
|
+
var __defProp2 = Object.defineProperty;
|
|
9
|
+
var __name = (target, value) => __defProp2(target, "name", { value, configurable: true });
|
|
10
|
+
var FetchError = class _FetchError extends Error {
|
|
11
|
+
static {
|
|
12
|
+
__name(this, "FetchError");
|
|
13
|
+
}
|
|
14
|
+
status;
|
|
15
|
+
data;
|
|
16
|
+
headers;
|
|
17
|
+
constructor(message, status, data, headers) {
|
|
18
|
+
super(message), this.status = status, this.data = data, this.headers = headers;
|
|
19
|
+
this.name = "FetchError";
|
|
20
|
+
if (Error.captureStackTrace) {
|
|
21
|
+
Error.captureStackTrace(this, _FetchError);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var ClientError = class extends FetchError {
|
|
26
|
+
static {
|
|
27
|
+
__name(this, "ClientError");
|
|
28
|
+
}
|
|
29
|
+
constructor(message, status, data, headers) {
|
|
30
|
+
super(message, status, data, headers);
|
|
31
|
+
this.name = "ClientError";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var ServerError = class extends FetchError {
|
|
35
|
+
static {
|
|
36
|
+
__name(this, "ServerError");
|
|
37
|
+
}
|
|
38
|
+
constructor(message, status, data, headers) {
|
|
39
|
+
super(message, status, data, headers);
|
|
40
|
+
this.name = "ServerError";
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var BadRequestError = class extends ClientError {
|
|
44
|
+
static {
|
|
45
|
+
__name(this, "BadRequestError");
|
|
46
|
+
}
|
|
47
|
+
constructor(message = "Bad Request", data, headers) {
|
|
48
|
+
super(message, 400, data, headers);
|
|
49
|
+
this.name = "BadRequestError";
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var UnauthorizedError = class extends ClientError {
|
|
53
|
+
static {
|
|
54
|
+
__name(this, "UnauthorizedError");
|
|
55
|
+
}
|
|
56
|
+
constructor(message = "Unauthorized", data, headers) {
|
|
57
|
+
super(message, 401, data, headers);
|
|
58
|
+
this.name = "UnauthorizedError";
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var ForbiddenError = class extends ClientError {
|
|
62
|
+
static {
|
|
63
|
+
__name(this, "ForbiddenError");
|
|
64
|
+
}
|
|
65
|
+
constructor(message = "Forbidden", data, headers) {
|
|
66
|
+
super(message, 403, data, headers);
|
|
67
|
+
this.name = "ForbiddenError";
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
var NotFoundError = class extends ClientError {
|
|
71
|
+
static {
|
|
72
|
+
__name(this, "NotFoundError");
|
|
73
|
+
}
|
|
74
|
+
constructor(message = "Not Found", data, headers) {
|
|
75
|
+
super(message, 404, data, headers);
|
|
76
|
+
this.name = "NotFoundError";
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
var MethodNotAllowedError = class extends ClientError {
|
|
80
|
+
static {
|
|
81
|
+
__name(this, "MethodNotAllowedError");
|
|
82
|
+
}
|
|
83
|
+
constructor(message = "Method Not Allowed", data, headers) {
|
|
84
|
+
super(message, 405, data, headers);
|
|
85
|
+
this.name = "MethodNotAllowedError";
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
var ConflictError = class extends ClientError {
|
|
89
|
+
static {
|
|
90
|
+
__name(this, "ConflictError");
|
|
91
|
+
}
|
|
92
|
+
constructor(message = "Conflict", data, headers) {
|
|
93
|
+
super(message, 409, data, headers);
|
|
94
|
+
this.name = "ConflictError";
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
var UnprocessableEntityError = class extends ClientError {
|
|
98
|
+
static {
|
|
99
|
+
__name(this, "UnprocessableEntityError");
|
|
100
|
+
}
|
|
101
|
+
constructor(message = "Unprocessable Entity", data, headers) {
|
|
102
|
+
super(message, 422, data, headers);
|
|
103
|
+
this.name = "UnprocessableEntityError";
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var TooManyRequestsError = class extends ClientError {
|
|
107
|
+
static {
|
|
108
|
+
__name(this, "TooManyRequestsError");
|
|
109
|
+
}
|
|
110
|
+
constructor(message = "Too Many Requests", data, headers) {
|
|
111
|
+
super(message, 429, data, headers);
|
|
112
|
+
this.name = "TooManyRequestsError";
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
var InternalServerError = class extends ServerError {
|
|
116
|
+
static {
|
|
117
|
+
__name(this, "InternalServerError");
|
|
118
|
+
}
|
|
119
|
+
constructor(message = "Internal Server Error", data, headers) {
|
|
120
|
+
super(message, 500, data, headers);
|
|
121
|
+
this.name = "InternalServerError";
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
var BadGatewayError = class extends ServerError {
|
|
125
|
+
static {
|
|
126
|
+
__name(this, "BadGatewayError");
|
|
127
|
+
}
|
|
128
|
+
constructor(message = "Bad Gateway", data, headers) {
|
|
129
|
+
super(message, 502, data, headers);
|
|
130
|
+
this.name = "BadGatewayError";
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
var ServiceUnavailableError = class extends ServerError {
|
|
134
|
+
static {
|
|
135
|
+
__name(this, "ServiceUnavailableError");
|
|
136
|
+
}
|
|
137
|
+
constructor(message = "Service Unavailable", data, headers) {
|
|
138
|
+
super(message, 503, data, headers);
|
|
139
|
+
this.name = "ServiceUnavailableError";
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
var GatewayTimeoutError = class extends ServerError {
|
|
143
|
+
static {
|
|
144
|
+
__name(this, "GatewayTimeoutError");
|
|
145
|
+
}
|
|
146
|
+
constructor(message = "Gateway Timeout", data, headers) {
|
|
147
|
+
super(message, 504, data, headers);
|
|
148
|
+
this.name = "GatewayTimeoutError";
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
function createFetchError(status, message, data, headers) {
|
|
152
|
+
const defaultMessage = message || `HTTP ${status}`;
|
|
153
|
+
switch (status) {
|
|
154
|
+
case 400:
|
|
155
|
+
return new BadRequestError(defaultMessage, data, headers);
|
|
156
|
+
case 401:
|
|
157
|
+
return new UnauthorizedError(defaultMessage, data, headers);
|
|
158
|
+
case 403:
|
|
159
|
+
return new ForbiddenError(defaultMessage, data, headers);
|
|
160
|
+
case 404:
|
|
161
|
+
return new NotFoundError(defaultMessage, data, headers);
|
|
162
|
+
case 405:
|
|
163
|
+
return new MethodNotAllowedError(defaultMessage, data, headers);
|
|
164
|
+
case 409:
|
|
165
|
+
return new ConflictError(defaultMessage, data, headers);
|
|
166
|
+
case 422:
|
|
167
|
+
return new UnprocessableEntityError(defaultMessage, data, headers);
|
|
168
|
+
case 429:
|
|
169
|
+
return new TooManyRequestsError(defaultMessage, data, headers);
|
|
170
|
+
// Generic 4xx
|
|
171
|
+
case 402:
|
|
172
|
+
case 406:
|
|
173
|
+
case 407:
|
|
174
|
+
case 408:
|
|
175
|
+
case 410:
|
|
176
|
+
case 411:
|
|
177
|
+
case 412:
|
|
178
|
+
case 413:
|
|
179
|
+
case 414:
|
|
180
|
+
case 415:
|
|
181
|
+
case 416:
|
|
182
|
+
case 417:
|
|
183
|
+
case 418:
|
|
184
|
+
case 421:
|
|
185
|
+
case 423:
|
|
186
|
+
case 424:
|
|
187
|
+
case 425:
|
|
188
|
+
case 426:
|
|
189
|
+
case 428:
|
|
190
|
+
case 431:
|
|
191
|
+
case 451:
|
|
192
|
+
return new ClientError(defaultMessage, status, data, headers);
|
|
193
|
+
// 5xx Server Errors
|
|
194
|
+
case 500:
|
|
195
|
+
return new InternalServerError(defaultMessage, data, headers);
|
|
196
|
+
case 502:
|
|
197
|
+
return new BadGatewayError(defaultMessage, data, headers);
|
|
198
|
+
case 503:
|
|
199
|
+
return new ServiceUnavailableError(defaultMessage, data, headers);
|
|
200
|
+
case 504:
|
|
201
|
+
return new GatewayTimeoutError(defaultMessage, data, headers);
|
|
202
|
+
// Generic 5xx
|
|
203
|
+
case 501:
|
|
204
|
+
case 505:
|
|
205
|
+
case 506:
|
|
206
|
+
case 507:
|
|
207
|
+
case 508:
|
|
208
|
+
case 510:
|
|
209
|
+
case 511:
|
|
210
|
+
return new ServerError(defaultMessage, status, data, headers);
|
|
211
|
+
default:
|
|
212
|
+
return new FetchError(defaultMessage, status, data, headers);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
__name(createFetchError, "createFetchError");
|
|
216
|
+
var HookRegistry = class {
|
|
217
|
+
static {
|
|
218
|
+
__name(this, "HookRegistry");
|
|
219
|
+
}
|
|
220
|
+
hooks = /* @__PURE__ */ new Map();
|
|
221
|
+
constructor(config) {
|
|
222
|
+
if (config) {
|
|
223
|
+
this.registerFromConfig(config);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Register hooks from a configuration object
|
|
228
|
+
*/
|
|
229
|
+
registerFromConfig(config) {
|
|
230
|
+
for (const [stage, hooks] of Object.entries(config)) {
|
|
231
|
+
if (hooks && Array.isArray(hooks)) {
|
|
232
|
+
for (const hook of hooks) {
|
|
233
|
+
this.register(stage, hook);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Register a hook for a specific stage
|
|
240
|
+
*/
|
|
241
|
+
register(stage, hook) {
|
|
242
|
+
if (!this.hooks.has(stage)) {
|
|
243
|
+
this.hooks.set(stage, []);
|
|
244
|
+
}
|
|
245
|
+
this.hooks.get(stage).push(hook);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Remove a specific hook from a stage
|
|
249
|
+
*/
|
|
250
|
+
remove(stage, hook) {
|
|
251
|
+
const hooks = this.hooks.get(stage);
|
|
252
|
+
if (!hooks) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
const index = hooks.indexOf(hook);
|
|
256
|
+
if (index === -1) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
hooks.splice(index, 1);
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Clear all hooks for a specific stage, or all hooks if no stage is provided
|
|
264
|
+
*/
|
|
265
|
+
clear(stage) {
|
|
266
|
+
if (stage) {
|
|
267
|
+
this.hooks.delete(stage);
|
|
268
|
+
} else {
|
|
269
|
+
this.hooks.clear();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Get all hooks for a specific stage
|
|
274
|
+
*/
|
|
275
|
+
get(stage) {
|
|
276
|
+
return this.hooks.get(stage) || [];
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Execute all hooks for a specific stage in registration order
|
|
280
|
+
*/
|
|
281
|
+
async execute(stage, context) {
|
|
282
|
+
const hooks = this.get(stage);
|
|
283
|
+
for (const hook of hooks) {
|
|
284
|
+
await hook(context);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Check if any hooks are registered for a stage
|
|
289
|
+
*/
|
|
290
|
+
has(stage) {
|
|
291
|
+
return this.hooks.has(stage) && this.hooks.get(stage).length > 0;
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
var exponentialStrategy = /* @__PURE__ */ __name((attempt, baseBackoffMs) => {
|
|
295
|
+
return baseBackoffMs * Math.pow(2, attempt);
|
|
296
|
+
}, "exponentialStrategy");
|
|
297
|
+
var linearStrategy = /* @__PURE__ */ __name((attempt, baseBackoffMs) => {
|
|
298
|
+
return baseBackoffMs * (attempt + 1);
|
|
299
|
+
}, "linearStrategy");
|
|
300
|
+
function getRetryStrategy(strategy) {
|
|
301
|
+
if (typeof strategy === "function") {
|
|
302
|
+
return strategy;
|
|
303
|
+
}
|
|
304
|
+
switch (strategy) {
|
|
305
|
+
case "exponential":
|
|
306
|
+
return exponentialStrategy;
|
|
307
|
+
case "linear":
|
|
308
|
+
return linearStrategy;
|
|
309
|
+
default:
|
|
310
|
+
return exponentialStrategy;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
__name(getRetryStrategy, "getRetryStrategy");
|
|
314
|
+
function calculateRetryDelay(attempt, strategy, baseBackoffMs) {
|
|
315
|
+
const strategyFn = getRetryStrategy(strategy);
|
|
316
|
+
return strategyFn(attempt, baseBackoffMs);
|
|
317
|
+
}
|
|
318
|
+
__name(calculateRetryDelay, "calculateRetryDelay");
|
|
319
|
+
async function* parseSSEStream(response) {
|
|
320
|
+
if (!response.body) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
const reader = response.body.getReader();
|
|
324
|
+
const decoder = new TextDecoder();
|
|
325
|
+
let buffer = "";
|
|
326
|
+
try {
|
|
327
|
+
while (true) {
|
|
328
|
+
const { done, value } = await reader.read();
|
|
329
|
+
if (done) break;
|
|
330
|
+
buffer += decoder.decode(value, {
|
|
331
|
+
stream: true
|
|
332
|
+
});
|
|
333
|
+
const lines = buffer.split("\n");
|
|
334
|
+
buffer = lines.pop() || "";
|
|
335
|
+
let currentEvent = {};
|
|
336
|
+
for (const line of lines) {
|
|
337
|
+
if (line.trim() === "") {
|
|
338
|
+
if (currentEvent.data !== void 0) {
|
|
339
|
+
yield currentEvent.data;
|
|
340
|
+
}
|
|
341
|
+
currentEvent = {};
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
const colonIndex = line.indexOf(":");
|
|
345
|
+
if (colonIndex === -1) continue;
|
|
346
|
+
const field = line.substring(0, colonIndex).trim();
|
|
347
|
+
const value2 = line.substring(colonIndex + 1).trim();
|
|
348
|
+
if (field === "data") {
|
|
349
|
+
currentEvent.data = currentEvent.data ? currentEvent.data + "\n" + value2 : value2;
|
|
350
|
+
} else if (field === "event") {
|
|
351
|
+
currentEvent.type = value2;
|
|
352
|
+
} else if (field === "id") {
|
|
353
|
+
currentEvent.id = value2;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (buffer.trim()) {
|
|
358
|
+
const lines = buffer.split("\n");
|
|
359
|
+
let currentEvent = {};
|
|
360
|
+
for (const line of lines) {
|
|
361
|
+
if (line.trim() === "" && currentEvent.data !== void 0) {
|
|
362
|
+
yield currentEvent.data;
|
|
363
|
+
currentEvent = {};
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
const colonIndex = line.indexOf(":");
|
|
367
|
+
if (colonIndex !== -1) {
|
|
368
|
+
const field = line.substring(0, colonIndex).trim();
|
|
369
|
+
const value = line.substring(colonIndex + 1).trim();
|
|
370
|
+
if (field === "data") {
|
|
371
|
+
currentEvent.data = currentEvent.data ? currentEvent.data + "\n" + value : value;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (currentEvent.data !== void 0) {
|
|
376
|
+
yield currentEvent.data;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
} finally {
|
|
380
|
+
reader.releaseLock();
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
__name(parseSSEStream, "parseSSEStream");
|
|
384
|
+
async function* parseNDJSONStream(response) {
|
|
385
|
+
if (!response.body) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
const reader = response.body.getReader();
|
|
389
|
+
const decoder = new TextDecoder();
|
|
390
|
+
let buffer = "";
|
|
391
|
+
try {
|
|
392
|
+
while (true) {
|
|
393
|
+
const { done, value } = await reader.read();
|
|
394
|
+
if (done) break;
|
|
395
|
+
buffer += decoder.decode(value, {
|
|
396
|
+
stream: true
|
|
397
|
+
});
|
|
398
|
+
const lines = buffer.split("\n");
|
|
399
|
+
buffer = lines.pop() || "";
|
|
400
|
+
for (const line of lines) {
|
|
401
|
+
const trimmed = line.trim();
|
|
402
|
+
if (trimmed === "") continue;
|
|
403
|
+
try {
|
|
404
|
+
const parsed = JSON.parse(trimmed);
|
|
405
|
+
yield parsed;
|
|
406
|
+
} catch (error) {
|
|
407
|
+
console.warn("Skipping invalid JSON line:", trimmed);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (buffer.trim()) {
|
|
412
|
+
try {
|
|
413
|
+
const parsed = JSON.parse(buffer.trim());
|
|
414
|
+
yield parsed;
|
|
415
|
+
} catch (error) {
|
|
416
|
+
console.warn("Skipping invalid JSON in buffer:", buffer.trim());
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
} finally {
|
|
420
|
+
reader.releaseLock();
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
__name(parseNDJSONStream, "parseNDJSONStream");
|
|
424
|
+
async function* parseChunkedStream(response) {
|
|
425
|
+
if (!response.body) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
const reader = response.body.getReader();
|
|
429
|
+
const decoder = new TextDecoder();
|
|
430
|
+
try {
|
|
431
|
+
while (true) {
|
|
432
|
+
const { done, value } = await reader.read();
|
|
433
|
+
if (done) break;
|
|
434
|
+
const chunk = decoder.decode(value, {
|
|
435
|
+
stream: true
|
|
436
|
+
});
|
|
437
|
+
yield chunk;
|
|
438
|
+
}
|
|
439
|
+
} finally {
|
|
440
|
+
reader.releaseLock();
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
__name(parseChunkedStream, "parseChunkedStream");
|
|
444
|
+
function isBrowser() {
|
|
445
|
+
return typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined" && typeof globalThis.window.document !== "undefined";
|
|
446
|
+
}
|
|
447
|
+
__name(isBrowser, "isBrowser");
|
|
448
|
+
function isNode() {
|
|
449
|
+
return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
|
|
450
|
+
}
|
|
451
|
+
__name(isNode, "isNode");
|
|
452
|
+
function encodeBase64(str) {
|
|
453
|
+
if (isBrowser()) {
|
|
454
|
+
if (typeof btoa !== "undefined") {
|
|
455
|
+
return btoa(str);
|
|
456
|
+
}
|
|
457
|
+
throw new Error("btoa is not available. This should not happen in a browser environment.");
|
|
458
|
+
} else {
|
|
459
|
+
if (typeof Buffer !== "undefined") {
|
|
460
|
+
return Buffer.from(str, "utf-8").toString("base64");
|
|
461
|
+
}
|
|
462
|
+
throw new Error("Buffer is not available. Please ensure you're running in Node.js or provide a polyfill.");
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
__name(encodeBase64, "encodeBase64");
|
|
466
|
+
function isFetchAvailable() {
|
|
467
|
+
return typeof fetch !== "undefined";
|
|
468
|
+
}
|
|
469
|
+
__name(isFetchAvailable, "isFetchAvailable");
|
|
470
|
+
function isAbortControllerAvailable() {
|
|
471
|
+
return typeof AbortController !== "undefined";
|
|
472
|
+
}
|
|
473
|
+
__name(isAbortControllerAvailable, "isAbortControllerAvailable");
|
|
474
|
+
function getFetchErrorMessage() {
|
|
475
|
+
if (isBrowser()) {
|
|
476
|
+
return "fetch is not available in this browser. Please use a modern browser or provide a polyfill.";
|
|
477
|
+
} else {
|
|
478
|
+
return "fetch is not available. Node.js 22+ includes native fetch. For older versions, please provide a custom fetch implementation (e.g., from 'undici' or 'node-fetch').";
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
__name(getFetchErrorMessage, "getFetchErrorMessage");
|
|
482
|
+
function serializeQueryParams(query) {
|
|
483
|
+
const params = new URLSearchParams();
|
|
484
|
+
for (const [key, value] of Object.entries(query)) {
|
|
485
|
+
if (value === void 0 || value === null) {
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
if (Array.isArray(value)) {
|
|
489
|
+
for (const item of value) {
|
|
490
|
+
if (item !== void 0 && item !== null) {
|
|
491
|
+
params.append(key, String(item));
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
} else {
|
|
495
|
+
params.set(key, String(value));
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return params;
|
|
499
|
+
}
|
|
500
|
+
__name(serializeQueryParams, "serializeQueryParams");
|
|
501
|
+
function buildUrl(baseUrl, path, query) {
|
|
502
|
+
let normalizedPath = path || "";
|
|
503
|
+
if (normalizedPath.length > 1 && normalizedPath.endsWith("/")) {
|
|
504
|
+
normalizedPath = normalizedPath.slice(0, -1);
|
|
505
|
+
}
|
|
506
|
+
let normalizedBaseUrl = baseUrl || "";
|
|
507
|
+
if (normalizedBaseUrl) {
|
|
508
|
+
try {
|
|
509
|
+
const baseUrlObj = new URL(normalizedBaseUrl);
|
|
510
|
+
if (baseUrlObj.pathname && baseUrlObj.pathname !== "/" && !normalizedBaseUrl.endsWith("/")) {
|
|
511
|
+
normalizedBaseUrl = normalizedBaseUrl + "/";
|
|
512
|
+
}
|
|
513
|
+
} catch {
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
if (normalizedPath.startsWith("/")) {
|
|
517
|
+
normalizedPath = normalizedPath.slice(1);
|
|
518
|
+
}
|
|
519
|
+
const url = new URL(normalizedPath, normalizedBaseUrl);
|
|
520
|
+
if (query) {
|
|
521
|
+
const params = serializeQueryParams(query);
|
|
522
|
+
const keys = Array.from(new Set(params.keys()));
|
|
523
|
+
for (const key of keys) {
|
|
524
|
+
url.searchParams.delete(key);
|
|
525
|
+
for (const value of params.getAll(key)) {
|
|
526
|
+
url.searchParams.append(key, value);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return url;
|
|
531
|
+
}
|
|
532
|
+
__name(buildUrl, "buildUrl");
|
|
533
|
+
function getContentType(body) {
|
|
534
|
+
if (body === null || body === void 0) {
|
|
535
|
+
return void 0;
|
|
536
|
+
}
|
|
537
|
+
if (body instanceof FormData) {
|
|
538
|
+
return void 0;
|
|
539
|
+
}
|
|
540
|
+
if (body instanceof URLSearchParams) {
|
|
541
|
+
return "application/x-www-form-urlencoded";
|
|
542
|
+
}
|
|
543
|
+
if (typeof body === "string") {
|
|
544
|
+
try {
|
|
545
|
+
JSON.parse(body);
|
|
546
|
+
return "application/json";
|
|
547
|
+
} catch {
|
|
548
|
+
return "text/plain";
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
if (typeof body === "object") {
|
|
552
|
+
return "application/json";
|
|
553
|
+
}
|
|
554
|
+
return void 0;
|
|
555
|
+
}
|
|
556
|
+
__name(getContentType, "getContentType");
|
|
557
|
+
function serializeBody(body, contentType) {
|
|
558
|
+
if (body === null || body === void 0) {
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
if (typeof body === "string" || body instanceof FormData || body instanceof URLSearchParams || body instanceof Blob || body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {
|
|
562
|
+
return body;
|
|
563
|
+
}
|
|
564
|
+
if (contentType === "application/x-www-form-urlencoded" && typeof body === "object" && body !== null && !Array.isArray(body)) {
|
|
565
|
+
const params = new URLSearchParams();
|
|
566
|
+
for (const [key, value] of Object.entries(body)) {
|
|
567
|
+
if (value !== null && value !== void 0) {
|
|
568
|
+
if (Array.isArray(value)) {
|
|
569
|
+
for (const item of value) {
|
|
570
|
+
params.append(key, String(item));
|
|
571
|
+
}
|
|
572
|
+
} else {
|
|
573
|
+
params.append(key, String(value));
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return params;
|
|
578
|
+
}
|
|
579
|
+
if (typeof body === "object") {
|
|
580
|
+
return JSON.stringify(body);
|
|
581
|
+
}
|
|
582
|
+
return String(body);
|
|
583
|
+
}
|
|
584
|
+
__name(serializeBody, "serializeBody");
|
|
585
|
+
async function parseResponse(response) {
|
|
586
|
+
const contentType = response.headers.get("content-type") || "";
|
|
587
|
+
if (contentType.includes("application/json")) {
|
|
588
|
+
return await response.json();
|
|
589
|
+
} else if (contentType.startsWith("text/")) {
|
|
590
|
+
return await response.text();
|
|
591
|
+
} else {
|
|
592
|
+
return await response.arrayBuffer();
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
__name(parseResponse, "parseResponse");
|
|
596
|
+
function isSuccessResponse(response) {
|
|
597
|
+
return response.ok;
|
|
598
|
+
}
|
|
599
|
+
__name(isSuccessResponse, "isSuccessResponse");
|
|
600
|
+
var FetchClient = class {
|
|
601
|
+
static {
|
|
602
|
+
__name(this, "FetchClient");
|
|
603
|
+
}
|
|
604
|
+
hookRegistry;
|
|
605
|
+
cfg;
|
|
606
|
+
constructor(config = {}) {
|
|
607
|
+
this.cfg = config;
|
|
608
|
+
if (!this.cfg.baseURL) {
|
|
609
|
+
this.cfg.baseURL = "";
|
|
610
|
+
}
|
|
611
|
+
this.hookRegistry = new HookRegistry(this.cfg.hooks);
|
|
612
|
+
if (!isFetchAvailable() && !this.cfg.fetch) {
|
|
613
|
+
throw new Error(getFetchErrorMessage());
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Add an authentication strategy
|
|
618
|
+
*/
|
|
619
|
+
addAuthStrategy(strategy) {
|
|
620
|
+
if (!this.cfg.auth) {
|
|
621
|
+
this.cfg.auth = {
|
|
622
|
+
strategies: []
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
this.cfg.auth.strategies.push(strategy);
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Remove all authentication strategies
|
|
629
|
+
*/
|
|
630
|
+
clearAuthStrategies() {
|
|
631
|
+
if (this.cfg.auth) {
|
|
632
|
+
this.cfg.auth.strategies = [];
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Register a hook for a specific lifecycle stage
|
|
637
|
+
*/
|
|
638
|
+
useHook(stage, hook) {
|
|
639
|
+
this.hookRegistry.register(stage, hook);
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Remove a hook
|
|
643
|
+
*/
|
|
644
|
+
removeHook(stage, hook) {
|
|
645
|
+
return this.hookRegistry.remove(stage, hook);
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Clear hooks for a stage or all hooks
|
|
649
|
+
*/
|
|
650
|
+
clearHooks(stage) {
|
|
651
|
+
this.hookRegistry.clear(stage);
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Make an HTTP request
|
|
655
|
+
*/
|
|
656
|
+
async request(init) {
|
|
657
|
+
let url = buildUrl(this.cfg.baseURL || "", init.path, init.query);
|
|
658
|
+
const headers = new Headers(this.cfg.headers || {});
|
|
659
|
+
if (init.headers) {
|
|
660
|
+
if (init.headers instanceof Headers) {
|
|
661
|
+
init.headers.forEach((value, key) => {
|
|
662
|
+
headers.set(key, value);
|
|
663
|
+
});
|
|
664
|
+
} else {
|
|
665
|
+
Object.entries(init.headers).forEach(([key, value]) => {
|
|
666
|
+
headers.set(key, String(value));
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
await this.applyAuthentication(headers, url);
|
|
671
|
+
let bodyContentType;
|
|
672
|
+
if (init.body !== void 0) {
|
|
673
|
+
bodyContentType = headers.get("Content-Type") || void 0;
|
|
674
|
+
if (!bodyContentType) {
|
|
675
|
+
bodyContentType = getContentType(init.body);
|
|
676
|
+
if (bodyContentType) {
|
|
677
|
+
headers.set("Content-Type", bodyContentType);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
const retries = this.cfg.retry?.retries ?? 0;
|
|
682
|
+
const baseBackoff = this.cfg.retry?.backoffMs ?? 300;
|
|
683
|
+
const retryOn = this.cfg.retry?.retryOn ?? [
|
|
684
|
+
429,
|
|
685
|
+
500,
|
|
686
|
+
502,
|
|
687
|
+
503,
|
|
688
|
+
504
|
|
689
|
+
];
|
|
690
|
+
const retryStrategy = this.cfg.retry?.strategy ?? "exponential";
|
|
691
|
+
let lastError;
|
|
692
|
+
for (let attempt = 0; attempt <= retries + 1; attempt++) {
|
|
693
|
+
try {
|
|
694
|
+
let attemptUrl = buildUrl(this.cfg.baseURL || "", init.path, init.query);
|
|
695
|
+
const attemptHeaders = new Headers(headers);
|
|
696
|
+
await this.applyAuthentication(attemptHeaders, attemptUrl);
|
|
697
|
+
return await this.doRequest(attemptUrl, init, attemptHeaders, attempt, bodyContentType);
|
|
698
|
+
} catch (err) {
|
|
699
|
+
lastError = err;
|
|
700
|
+
const shouldRetry = this.shouldRetry(err, attempt, retries, retryOn);
|
|
701
|
+
if (shouldRetry) {
|
|
702
|
+
if (this.hookRegistry.has("beforeRetry")) {
|
|
703
|
+
await this.hookRegistry.execute("beforeRetry", {
|
|
704
|
+
url: url.toString(),
|
|
705
|
+
init: {
|
|
706
|
+
...init,
|
|
707
|
+
headers
|
|
708
|
+
},
|
|
709
|
+
attempt,
|
|
710
|
+
error: err,
|
|
711
|
+
retryCount: attempt
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
const delay = calculateRetryDelay(attempt, retryStrategy, baseBackoff);
|
|
715
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
716
|
+
if (this.hookRegistry.has("afterRetry")) {
|
|
717
|
+
await this.hookRegistry.execute("afterRetry", {
|
|
718
|
+
url: url.toString(),
|
|
719
|
+
init: {
|
|
720
|
+
...init,
|
|
721
|
+
headers
|
|
722
|
+
},
|
|
723
|
+
attempt,
|
|
724
|
+
error: err,
|
|
725
|
+
retryCount: attempt,
|
|
726
|
+
success: false
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
continue;
|
|
730
|
+
}
|
|
731
|
+
throw err;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
throw lastError;
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Make a streaming HTTP request
|
|
738
|
+
*/
|
|
739
|
+
async *requestStream(init) {
|
|
740
|
+
let url = buildUrl(this.cfg.baseURL || "", init.path, init.query);
|
|
741
|
+
const headers = new Headers(this.cfg.headers || {});
|
|
742
|
+
if (init.headers) {
|
|
743
|
+
if (init.headers instanceof Headers) {
|
|
744
|
+
init.headers.forEach((value, key) => {
|
|
745
|
+
headers.set(key, value);
|
|
746
|
+
});
|
|
747
|
+
} else {
|
|
748
|
+
Object.entries(init.headers).forEach(([key, value]) => {
|
|
749
|
+
headers.set(key, String(value));
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
await this.applyAuthentication(headers, url);
|
|
754
|
+
let bodyContentType = headers.get("Content-Type") || void 0;
|
|
755
|
+
if (init.contentType && !bodyContentType) {
|
|
756
|
+
bodyContentType = init.contentType;
|
|
757
|
+
headers.set("Content-Type", bodyContentType);
|
|
758
|
+
}
|
|
759
|
+
const fetchInit = {
|
|
760
|
+
...init,
|
|
761
|
+
headers,
|
|
762
|
+
body: serializeBody(init.body, bodyContentType)
|
|
763
|
+
};
|
|
764
|
+
if (this.cfg.credentials !== void 0) {
|
|
765
|
+
fetchInit.credentials = this.cfg.credentials;
|
|
766
|
+
}
|
|
767
|
+
if (this.hookRegistry.has("beforeRequest")) {
|
|
768
|
+
await this.hookRegistry.execute("beforeRequest", {
|
|
769
|
+
url: url.toString(),
|
|
770
|
+
init: fetchInit,
|
|
771
|
+
attempt: 0
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
let controller;
|
|
775
|
+
let timeoutId;
|
|
776
|
+
const existingSignal = fetchInit.signal;
|
|
777
|
+
if (this.cfg.timeoutMs && typeof AbortController !== "undefined") {
|
|
778
|
+
controller = new AbortController();
|
|
779
|
+
if (existingSignal) {
|
|
780
|
+
if (existingSignal.aborted) {
|
|
781
|
+
controller.abort();
|
|
782
|
+
} else {
|
|
783
|
+
existingSignal.addEventListener("abort", () => {
|
|
784
|
+
controller?.abort();
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
fetchInit.signal = controller.signal;
|
|
789
|
+
timeoutId = setTimeout(() => {
|
|
790
|
+
controller?.abort();
|
|
791
|
+
if (this.hookRegistry.has("onTimeout")) {
|
|
792
|
+
this.hookRegistry.execute("onTimeout", {
|
|
793
|
+
url: url.toString(),
|
|
794
|
+
init: fetchInit,
|
|
795
|
+
attempt: 0,
|
|
796
|
+
timeoutMs: this.cfg.timeoutMs
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
}, this.cfg.timeoutMs);
|
|
800
|
+
}
|
|
801
|
+
try {
|
|
802
|
+
const fetchFn = this.cfg.fetch || fetch;
|
|
803
|
+
const res = await fetchFn(url.toString(), fetchInit);
|
|
804
|
+
if (this.hookRegistry.has("afterRequest")) {
|
|
805
|
+
await this.hookRegistry.execute("afterRequest", {
|
|
806
|
+
url: url.toString(),
|
|
807
|
+
init: fetchInit,
|
|
808
|
+
attempt: 0,
|
|
809
|
+
response: res
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
if (!res.ok) {
|
|
813
|
+
const parsed = await parseResponse(res);
|
|
814
|
+
const error = createFetchError(res.status, parsed?.message || `HTTP ${res.status}`, parsed, res.headers);
|
|
815
|
+
if (this.hookRegistry.has("onError")) {
|
|
816
|
+
await this.hookRegistry.execute("onError", {
|
|
817
|
+
url: url.toString(),
|
|
818
|
+
init: fetchInit,
|
|
819
|
+
attempt: 0,
|
|
820
|
+
error
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
throw error;
|
|
824
|
+
}
|
|
825
|
+
if (this.hookRegistry.has("onStreamStart")) {
|
|
826
|
+
await this.hookRegistry.execute("onStreamStart", {
|
|
827
|
+
url: url.toString(),
|
|
828
|
+
init: fetchInit,
|
|
829
|
+
attempt: 0,
|
|
830
|
+
response: res
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
const streamingFormat = init.streamingFormat || "chunked";
|
|
834
|
+
if (streamingFormat === "sse") {
|
|
835
|
+
for await (const chunk of parseSSEStream(res)) {
|
|
836
|
+
let transformedChunk = chunk;
|
|
837
|
+
if (this.hookRegistry.has("onStreamChunk")) {
|
|
838
|
+
await this.hookRegistry.execute("onStreamChunk", {
|
|
839
|
+
url: url.toString(),
|
|
840
|
+
init: fetchInit,
|
|
841
|
+
attempt: 0,
|
|
842
|
+
chunk
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
yield transformedChunk;
|
|
846
|
+
}
|
|
847
|
+
} else if (streamingFormat === "ndjson") {
|
|
848
|
+
for await (const chunk of parseNDJSONStream(res)) {
|
|
849
|
+
let transformedChunk = chunk;
|
|
850
|
+
if (this.hookRegistry.has("onStreamChunk")) {
|
|
851
|
+
await this.hookRegistry.execute("onStreamChunk", {
|
|
852
|
+
url: url.toString(),
|
|
853
|
+
init: fetchInit,
|
|
854
|
+
attempt: 0,
|
|
855
|
+
chunk
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
yield transformedChunk;
|
|
859
|
+
}
|
|
860
|
+
} else {
|
|
861
|
+
for await (const chunk of parseChunkedStream(res)) {
|
|
862
|
+
let transformedChunk = chunk;
|
|
863
|
+
if (this.hookRegistry.has("onStreamChunk")) {
|
|
864
|
+
await this.hookRegistry.execute("onStreamChunk", {
|
|
865
|
+
url: url.toString(),
|
|
866
|
+
init: fetchInit,
|
|
867
|
+
attempt: 0,
|
|
868
|
+
chunk
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
yield transformedChunk;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
if (this.hookRegistry.has("onStreamEnd")) {
|
|
875
|
+
await this.hookRegistry.execute("onStreamEnd", {
|
|
876
|
+
url: url.toString(),
|
|
877
|
+
init: fetchInit,
|
|
878
|
+
attempt: 0,
|
|
879
|
+
response: res
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
} catch (err) {
|
|
883
|
+
if (this.hookRegistry.has("onError")) {
|
|
884
|
+
await this.hookRegistry.execute("onError", {
|
|
885
|
+
url: url.toString(),
|
|
886
|
+
init: fetchInit,
|
|
887
|
+
attempt: 0,
|
|
888
|
+
error: err
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
throw err;
|
|
892
|
+
} finally {
|
|
893
|
+
if (timeoutId) {
|
|
894
|
+
clearTimeout(timeoutId);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Internal method to execute a single request attempt
|
|
900
|
+
*/
|
|
901
|
+
async doRequest(url, init, baseHeaders, attempt, contentType) {
|
|
902
|
+
const requestHeaders = baseHeaders;
|
|
903
|
+
const fetchInit = {
|
|
904
|
+
...init,
|
|
905
|
+
headers: requestHeaders,
|
|
906
|
+
body: serializeBody(init.body, contentType)
|
|
907
|
+
};
|
|
908
|
+
if (this.cfg.credentials !== void 0) {
|
|
909
|
+
fetchInit.credentials = this.cfg.credentials;
|
|
910
|
+
}
|
|
911
|
+
if (this.hookRegistry.has("beforeRequest")) {
|
|
912
|
+
await this.hookRegistry.execute("beforeRequest", {
|
|
913
|
+
url: url.toString(),
|
|
914
|
+
init: fetchInit,
|
|
915
|
+
attempt
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
let controller;
|
|
919
|
+
let timeoutId;
|
|
920
|
+
const existingSignal = fetchInit.signal;
|
|
921
|
+
if (this.cfg.timeoutMs && typeof AbortController !== "undefined") {
|
|
922
|
+
controller = new AbortController();
|
|
923
|
+
if (existingSignal) {
|
|
924
|
+
if (existingSignal.aborted) {
|
|
925
|
+
controller.abort();
|
|
926
|
+
} else {
|
|
927
|
+
existingSignal.addEventListener("abort", () => {
|
|
928
|
+
controller?.abort();
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
fetchInit.signal = controller.signal;
|
|
933
|
+
timeoutId = setTimeout(() => {
|
|
934
|
+
controller?.abort();
|
|
935
|
+
if (this.hookRegistry.has("onTimeout")) {
|
|
936
|
+
this.hookRegistry.execute("onTimeout", {
|
|
937
|
+
url: url.toString(),
|
|
938
|
+
init: fetchInit,
|
|
939
|
+
attempt,
|
|
940
|
+
timeoutMs: this.cfg.timeoutMs
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
}, this.cfg.timeoutMs);
|
|
944
|
+
}
|
|
945
|
+
try {
|
|
946
|
+
const fetchFn = this.cfg.fetch || fetch;
|
|
947
|
+
const res = await fetchFn(url.toString(), fetchInit);
|
|
948
|
+
if (this.hookRegistry.has("afterRequest")) {
|
|
949
|
+
await this.hookRegistry.execute("afterRequest", {
|
|
950
|
+
url: url.toString(),
|
|
951
|
+
init: fetchInit,
|
|
952
|
+
attempt,
|
|
953
|
+
response: res
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
const parsed = await parseResponse(res);
|
|
957
|
+
if (this.hookRegistry.has("afterResponse")) {
|
|
958
|
+
await this.hookRegistry.execute("afterResponse", {
|
|
959
|
+
url: url.toString(),
|
|
960
|
+
init: fetchInit,
|
|
961
|
+
attempt,
|
|
962
|
+
response: res,
|
|
963
|
+
data: parsed
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
if (!isSuccessResponse(res)) {
|
|
967
|
+
const error = createFetchError(res.status, parsed?.message || `HTTP ${res.status}`, parsed, res.headers);
|
|
968
|
+
if (this.hookRegistry.has("onError")) {
|
|
969
|
+
await this.hookRegistry.execute("onError", {
|
|
970
|
+
url: url.toString(),
|
|
971
|
+
init: fetchInit,
|
|
972
|
+
attempt,
|
|
973
|
+
error
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
throw error;
|
|
977
|
+
}
|
|
978
|
+
return parsed;
|
|
979
|
+
} catch (err) {
|
|
980
|
+
if (this.hookRegistry.has("onError")) {
|
|
981
|
+
await this.hookRegistry.execute("onError", {
|
|
982
|
+
url: url.toString(),
|
|
983
|
+
init: fetchInit,
|
|
984
|
+
attempt,
|
|
985
|
+
error: err
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
if (err instanceof DOMException) {
|
|
989
|
+
throw err;
|
|
990
|
+
}
|
|
991
|
+
if (err instanceof FetchError) {
|
|
992
|
+
throw err;
|
|
993
|
+
}
|
|
994
|
+
const status = err?.status;
|
|
995
|
+
const statusCode = typeof status === "number" ? status : 0;
|
|
996
|
+
if (typeof err === "string") {
|
|
997
|
+
throw createFetchError(statusCode, err);
|
|
998
|
+
}
|
|
999
|
+
throw createFetchError(statusCode, err?.message || "Network error");
|
|
1000
|
+
} finally {
|
|
1001
|
+
if (timeoutId) {
|
|
1002
|
+
clearTimeout(timeoutId);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Apply authentication strategies
|
|
1008
|
+
*/
|
|
1009
|
+
async applyAuthentication(headers, url) {
|
|
1010
|
+
if (!this.cfg.auth?.strategies) {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
for (const strategy of this.cfg.auth.strategies) {
|
|
1014
|
+
await this.applyAuthStrategy(strategy, headers, url);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Apply a single authentication strategy
|
|
1019
|
+
*/
|
|
1020
|
+
async applyAuthStrategy(strategy, headers, url) {
|
|
1021
|
+
switch (strategy.type) {
|
|
1022
|
+
case "bearer": {
|
|
1023
|
+
const token = typeof strategy.token === "function" ? await strategy.token() : strategy.token;
|
|
1024
|
+
if (token != null) {
|
|
1025
|
+
const headerName = strategy.headerName || "Authorization";
|
|
1026
|
+
headers.set(headerName, `Bearer ${String(token)}`);
|
|
1027
|
+
}
|
|
1028
|
+
break;
|
|
1029
|
+
}
|
|
1030
|
+
case "basic": {
|
|
1031
|
+
const encoded = encodeBase64(`${strategy.username}:${strategy.password}`);
|
|
1032
|
+
headers.set("Authorization", `Basic ${encoded}`);
|
|
1033
|
+
break;
|
|
1034
|
+
}
|
|
1035
|
+
case "apiKey": {
|
|
1036
|
+
const key = typeof strategy.key === "function" ? await strategy.key() : strategy.key;
|
|
1037
|
+
if (key != null) {
|
|
1038
|
+
switch (strategy.location) {
|
|
1039
|
+
case "header":
|
|
1040
|
+
headers.set(strategy.name, String(key));
|
|
1041
|
+
break;
|
|
1042
|
+
case "query":
|
|
1043
|
+
url.searchParams.set(strategy.name, String(key));
|
|
1044
|
+
break;
|
|
1045
|
+
case "cookie":
|
|
1046
|
+
headers.set("Cookie", `${strategy.name}=${String(key)}`);
|
|
1047
|
+
break;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
break;
|
|
1051
|
+
}
|
|
1052
|
+
case "custom":
|
|
1053
|
+
await strategy.apply(headers, url);
|
|
1054
|
+
break;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Determine if an error should be retried
|
|
1059
|
+
*/
|
|
1060
|
+
shouldRetry(error, attempt, maxRetries, retryOn) {
|
|
1061
|
+
if (attempt >= maxRetries) {
|
|
1062
|
+
return false;
|
|
1063
|
+
}
|
|
1064
|
+
if (this.cfg.retry?.retryOnError) {
|
|
1065
|
+
return this.cfg.retry.retryOnError(error);
|
|
1066
|
+
}
|
|
1067
|
+
if (error instanceof FetchError) {
|
|
1068
|
+
return retryOn.includes(error.status);
|
|
1069
|
+
}
|
|
1070
|
+
return true;
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
|
|
1074
|
+
// src/client.ts
|
|
1075
|
+
var CoreClient = class extends FetchClient {
|
|
1076
|
+
constructor(cfg = {}) {
|
|
1077
|
+
const authStrategies = [];
|
|
1078
|
+
const { auth: _existingAuth, bearer, ...restCfg } = cfg;
|
|
1079
|
+
if (cfg.bearer) {
|
|
1080
|
+
const bearerValue = cfg.bearer;
|
|
1081
|
+
if (typeof bearerValue === "string") {
|
|
1082
|
+
authStrategies.push({
|
|
1083
|
+
type: "bearer",
|
|
1084
|
+
token: () => bearerValue
|
|
1085
|
+
});
|
|
1086
|
+
} else if (typeof bearerValue === "function") {
|
|
1087
|
+
authStrategies.push({
|
|
1088
|
+
type: "bearer",
|
|
1089
|
+
token: bearerValue
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
const finalAuthStrategies = [
|
|
1094
|
+
..._existingAuth?.strategies || [],
|
|
1095
|
+
...authStrategies
|
|
1096
|
+
];
|
|
1097
|
+
const fetchConfig = {
|
|
1098
|
+
...restCfg,
|
|
1099
|
+
baseURL: cfg.baseURL ?? "https://api.blimu.dev",
|
|
1100
|
+
// Explicitly set auth after restCfg to ensure it's not overwritten
|
|
1101
|
+
// (restCfg might have an auth property that we want to replace)
|
|
1102
|
+
...finalAuthStrategies.length > 0 ? {
|
|
1103
|
+
auth: {
|
|
1104
|
+
strategies: finalAuthStrategies
|
|
1105
|
+
}
|
|
1106
|
+
} : {}
|
|
1107
|
+
// Hooks are passed through directly from FetchClientConfig (no mapping needed)
|
|
1108
|
+
};
|
|
1109
|
+
super(fetchConfig);
|
|
1110
|
+
}
|
|
1111
|
+
async request(init) {
|
|
1112
|
+
return await super.request(init);
|
|
1113
|
+
}
|
|
1114
|
+
async *requestStream(init) {
|
|
1115
|
+
yield* super.requestStream(init);
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
|
|
1119
|
+
// src/services/auth.ts
|
|
1120
|
+
var AuthService = class {
|
|
1121
|
+
constructor(core) {
|
|
1122
|
+
this.core = core;
|
|
1123
|
+
}
|
|
1124
|
+
/**
|
|
1125
|
+
* POST /v1/auth/logout*
|
|
1126
|
+
* @summary Logout and invalidate session*/
|
|
1127
|
+
logout(init) {
|
|
1128
|
+
return this.core.request({
|
|
1129
|
+
method: "POST",
|
|
1130
|
+
path: `/v1/auth/logout`,
|
|
1131
|
+
...init || {}
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* @summary Get query keys for logout
|
|
1136
|
+
* @returns ['v1/auth/logout']
|
|
1137
|
+
*/
|
|
1138
|
+
logout__queryKeys() {
|
|
1139
|
+
return ["v1/auth/logout"];
|
|
1140
|
+
}
|
|
1141
|
+
/**
|
|
1142
|
+
* POST /v1/auth/refresh*
|
|
1143
|
+
* @summary Refresh session token*/
|
|
1144
|
+
refresh(query, init) {
|
|
1145
|
+
return this.core.request({
|
|
1146
|
+
method: "POST",
|
|
1147
|
+
path: `/v1/auth/refresh`,
|
|
1148
|
+
query,
|
|
1149
|
+
...init || {}
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
/**
|
|
1153
|
+
* @summary Get query keys for refresh
|
|
1154
|
+
* @returns ['v1/auth/refresh', query]
|
|
1155
|
+
*/
|
|
1156
|
+
refresh__queryKeys(query) {
|
|
1157
|
+
return ["v1/auth/refresh", query];
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* GET /v1/auth/session*
|
|
1161
|
+
* @summary Get current session*/
|
|
1162
|
+
getSession(init) {
|
|
1163
|
+
return this.core.request({
|
|
1164
|
+
method: "GET",
|
|
1165
|
+
path: `/v1/auth/session`,
|
|
1166
|
+
...init || {}
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* @summary Get query keys for getSession
|
|
1171
|
+
* @returns ['v1/auth/session']
|
|
1172
|
+
*/
|
|
1173
|
+
getSession__queryKeys() {
|
|
1174
|
+
return ["v1/auth/session"];
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
|
|
1178
|
+
// src/services/entitlements.ts
|
|
1179
|
+
var EntitlementsService = class {
|
|
1180
|
+
constructor(core) {
|
|
1181
|
+
this.core = core;
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* GET /v1/client/entitlements/list-for-tenant/{tenantResourceId}*
|
|
1185
|
+
* @summary List entitlements for a tenant and all its sub-resources*
|
|
1186
|
+
* @description Returns entitlements for a tenant resource and all its descendant resources for the authenticated user. This endpoint scopes queries to a single tenant, preventing cross-tenant data access. Only evaluates roles and plans (excludes limits). Results are cached per resource for performance. The tenant resource type is automatically determined from the environment definition (resource marked as `is_tenant: true`).*/
|
|
1187
|
+
listForTenant(tenantResourceId, init) {
|
|
1188
|
+
return this.core.request({
|
|
1189
|
+
method: "GET",
|
|
1190
|
+
path: `/v1/client/entitlements/list-for-tenant/${encodeURIComponent(tenantResourceId)}`,
|
|
1191
|
+
...init || {}
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
/**
|
|
1195
|
+
* @summary Get query keys for listForTenant
|
|
1196
|
+
* @returns ['v1/client/entitlements/list-for-tenant', tenantResourceId]
|
|
1197
|
+
*/
|
|
1198
|
+
listForTenant__queryKeys(tenantResourceId) {
|
|
1199
|
+
return [
|
|
1200
|
+
"v1/client/entitlements/list-for-tenant",
|
|
1201
|
+
tenantResourceId
|
|
1202
|
+
];
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
|
|
1206
|
+
// src/utils.ts
|
|
1207
|
+
async function* paginate(fetchPage, initialQuery = {}, pageSize = 100) {
|
|
1208
|
+
let offset = Number(initialQuery.offset ?? 0);
|
|
1209
|
+
const limit = Number(initialQuery.limit ?? pageSize);
|
|
1210
|
+
const baseQuery = { ...initialQuery };
|
|
1211
|
+
while (true) {
|
|
1212
|
+
const page = await fetchPage({ ...baseQuery, limit, offset });
|
|
1213
|
+
const items = page.data ?? [];
|
|
1214
|
+
for (const item of items) {
|
|
1215
|
+
yield item;
|
|
1216
|
+
}
|
|
1217
|
+
if (!page.hasMore || items.length < limit) break;
|
|
1218
|
+
offset += limit;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
async function listAll(fetchPage, query = {}, pageSize = 100) {
|
|
1222
|
+
const out = [];
|
|
1223
|
+
for await (const item of paginate(fetchPage, query, pageSize))
|
|
1224
|
+
out.push(item);
|
|
1225
|
+
return out;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// src/schema.ts
|
|
1229
|
+
var schema_exports = {};
|
|
1230
|
+
|
|
1231
|
+
// src/schema.zod.ts
|
|
1232
|
+
var schema_zod_exports = {};
|
|
1233
|
+
__export(schema_zod_exports, {
|
|
1234
|
+
AuthRefreshQuerySchema: () => AuthRefreshQuerySchema,
|
|
1235
|
+
EntitlementTypeSchema: () => EntitlementTypeSchema,
|
|
1236
|
+
EntitlementsListResultSchema: () => EntitlementsListResultSchema,
|
|
1237
|
+
RefreshResponseSchema: () => RefreshResponseSchema,
|
|
1238
|
+
ResourceTypeSchema: () => ResourceTypeSchema,
|
|
1239
|
+
SessionResponseSchema: () => SessionResponseSchema
|
|
1240
|
+
});
|
|
1241
|
+
import { z } from "zod";
|
|
1242
|
+
var EntitlementTypeSchema = z.string();
|
|
1243
|
+
var ResourceTypeSchema = z.string();
|
|
1244
|
+
var EntitlementsListResultSchema = z.object({
|
|
1245
|
+
results: z.array(
|
|
1246
|
+
z.object({
|
|
1247
|
+
entitlements: z.array(
|
|
1248
|
+
z.object({
|
|
1249
|
+
allowed: z.boolean(),
|
|
1250
|
+
allowedByPlan: z.boolean(),
|
|
1251
|
+
allowedByRole: z.boolean(),
|
|
1252
|
+
allowedPlans: z.array(z.string()).optional(),
|
|
1253
|
+
allowedRoles: z.array(z.string()),
|
|
1254
|
+
currentPlan: z.string().optional(),
|
|
1255
|
+
currentRole: z.string().optional(),
|
|
1256
|
+
entitlement: EntitlementTypeSchema
|
|
1257
|
+
})
|
|
1258
|
+
),
|
|
1259
|
+
resourceId: z.string(),
|
|
1260
|
+
resourceType: ResourceTypeSchema
|
|
1261
|
+
})
|
|
1262
|
+
)
|
|
1263
|
+
});
|
|
1264
|
+
var RefreshResponseSchema = z.object({ sessionToken: z.string() });
|
|
1265
|
+
var SessionResponseSchema = z.object({
|
|
1266
|
+
isAuthenticated: z.boolean(),
|
|
1267
|
+
user: z.object({
|
|
1268
|
+
email: z.string(),
|
|
1269
|
+
emailVerified: z.boolean(),
|
|
1270
|
+
firstName: z.string().nullable(),
|
|
1271
|
+
id: z.string(),
|
|
1272
|
+
lastName: z.string().nullable()
|
|
1273
|
+
}).nullable()
|
|
1274
|
+
});
|
|
1275
|
+
var AuthRefreshQuerySchema = z.object({
|
|
1276
|
+
__lh_jwt: z.string().optional()
|
|
1277
|
+
});
|
|
18
1278
|
|
|
19
1279
|
// src/index.ts
|
|
20
1280
|
var Blimu = class {
|
|
@@ -29,11 +1289,50 @@ var Blimu = class {
|
|
|
29
1289
|
var BlimuError = FetchError;
|
|
30
1290
|
export {
|
|
31
1291
|
AuthService,
|
|
1292
|
+
BadGatewayError,
|
|
1293
|
+
BadRequestError,
|
|
32
1294
|
Blimu,
|
|
33
1295
|
BlimuError,
|
|
1296
|
+
ClientError,
|
|
1297
|
+
ConflictError,
|
|
1298
|
+
CoreClient,
|
|
34
1299
|
EntitlementsService,
|
|
1300
|
+
FetchClient,
|
|
35
1301
|
FetchError,
|
|
1302
|
+
ForbiddenError,
|
|
1303
|
+
GatewayTimeoutError,
|
|
1304
|
+
HookRegistry,
|
|
1305
|
+
InternalServerError,
|
|
1306
|
+
MethodNotAllowedError,
|
|
1307
|
+
NotFoundError,
|
|
36
1308
|
schema_exports as Schema,
|
|
1309
|
+
ServerError,
|
|
1310
|
+
ServiceUnavailableError,
|
|
1311
|
+
TooManyRequestsError,
|
|
1312
|
+
UnauthorizedError,
|
|
1313
|
+
UnprocessableEntityError,
|
|
1314
|
+
schema_zod_exports as ZodSchema,
|
|
1315
|
+
buildUrl,
|
|
1316
|
+
calculateRetryDelay,
|
|
1317
|
+
createFetchError,
|
|
1318
|
+
encodeBase64,
|
|
1319
|
+
exponentialStrategy,
|
|
1320
|
+
getContentType,
|
|
1321
|
+
getFetchErrorMessage,
|
|
1322
|
+
getRetryStrategy,
|
|
1323
|
+
isAbortControllerAvailable,
|
|
1324
|
+
isBrowser,
|
|
1325
|
+
isFetchAvailable,
|
|
1326
|
+
isNode,
|
|
1327
|
+
isSuccessResponse,
|
|
1328
|
+
linearStrategy,
|
|
37
1329
|
listAll,
|
|
38
|
-
paginate
|
|
1330
|
+
paginate,
|
|
1331
|
+
parseChunkedStream,
|
|
1332
|
+
parseNDJSONStream,
|
|
1333
|
+
parseResponse,
|
|
1334
|
+
parseSSEStream,
|
|
1335
|
+
serializeBody,
|
|
1336
|
+
serializeQueryParams
|
|
39
1337
|
};
|
|
1338
|
+
//# sourceMappingURL=index.mjs.map
|