@relyio/sdk 0.2.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +201 -0
  3. package/README.md +314 -0
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/chunk-2QUK2ZGD.js +738 -0
  6. package/dist/chunk-7W4MJXQ4.cjs +4429 -0
  7. package/dist/chunk-FJK7ZWKK.cjs +776 -0
  8. package/dist/chunk-HT6NFRM2.cjs +196 -0
  9. package/dist/chunk-I3ESNANB.js +177 -0
  10. package/dist/chunk-IY5LSKXU.js +3 -0
  11. package/dist/chunk-MWMSFIWN.cjs +17 -0
  12. package/dist/chunk-PPA2WWOH.cjs +4 -0
  13. package/dist/chunk-RJBIJ2ZK.js +4375 -0
  14. package/dist/chunk-XQ4QHWZE.js +13 -0
  15. package/dist/client/index.cjs +17 -0
  16. package/dist/client/index.d.cts +3 -0
  17. package/dist/client/index.d.ts +3 -0
  18. package/dist/client/index.js +4 -0
  19. package/dist/define-schema-DHvUCKwj.d.cts +2101 -0
  20. package/dist/define-schema-DHvUCKwj.d.ts +2101 -0
  21. package/dist/index-B-KiFHbx.d.ts +2708 -0
  22. package/dist/index-BsUqCAu8.d.cts +7855 -0
  23. package/dist/index-BsUqCAu8.d.ts +7855 -0
  24. package/dist/index-DGWaawHt.d.cts +2708 -0
  25. package/dist/index.cjs +499 -0
  26. package/dist/index.d.cts +523 -0
  27. package/dist/index.d.ts +523 -0
  28. package/dist/index.js +148 -0
  29. package/dist/react/index.cjs +4 -0
  30. package/dist/react/index.d.cts +2 -0
  31. package/dist/react/index.d.ts +2 -0
  32. package/dist/react/index.js +3 -0
  33. package/dist/schema/index.cjs +157 -0
  34. package/dist/schema/index.d.cts +223 -0
  35. package/dist/schema/index.d.ts +223 -0
  36. package/dist/schema/index.js +4 -0
  37. package/dist/types/index.cjs +6 -0
  38. package/dist/types/index.d.cts +1 -0
  39. package/dist/types/index.d.ts +1 -0
  40. package/dist/types/index.js +3 -0
  41. package/dist/utils/index.cjs +81 -0
  42. package/dist/utils/index.d.cts +87 -0
  43. package/dist/utils/index.d.ts +87 -0
  44. package/dist/utils/index.js +4 -0
  45. package/package.json +159 -0
@@ -0,0 +1,4375 @@
1
+ import { __name, __publicField } from './chunk-XQ4QHWZE.js';
2
+
3
+ /* RelyIO SDK - Built with ❤️ by the RelyIO Team */
4
+
5
+ // src/errors/sdk-error.ts
6
+ var _SDKError = class _SDKError extends Error {
7
+ constructor(message, statusCode, cause, context) {
8
+ super(message);
9
+ /** HTTP status code if applicable */
10
+ __publicField(this, "statusCode");
11
+ /** Original error that caused this error */
12
+ __publicField(this, "cause");
13
+ /** Additional context about the error */
14
+ __publicField(this, "context");
15
+ /** Timestamp when the error occurred */
16
+ __publicField(this, "timestamp");
17
+ this.name = this.constructor.name;
18
+ this.statusCode = statusCode;
19
+ this.cause = cause;
20
+ this.context = context;
21
+ this.timestamp = Date.now();
22
+ Object.setPrototypeOf(this, new.target.prototype);
23
+ }
24
+ /**
25
+ * Convert error to JSON for logging and debugging
26
+ */
27
+ toJSON() {
28
+ return {
29
+ name: this.name,
30
+ message: this.message,
31
+ code: this.code,
32
+ statusCode: this.statusCode,
33
+ retryable: this.retryable,
34
+ context: this.context,
35
+ timestamp: this.timestamp,
36
+ stack: this.stack
37
+ };
38
+ }
39
+ /**
40
+ * Get a user-friendly error message
41
+ */
42
+ getUserMessage() {
43
+ return this.message;
44
+ }
45
+ /**
46
+ * Get detailed error information for debugging
47
+ */
48
+ getDebugInfo() {
49
+ return `${this.name}: ${this.message} (${this.code})`;
50
+ }
51
+ /**
52
+ * Check if this error is of a specific type
53
+ */
54
+ isType(errorType) {
55
+ return this.code === errorType;
56
+ }
57
+ /**
58
+ * Create a new error with additional context
59
+ */
60
+ withContext(context) {
61
+ const Constructor = this.constructor;
62
+ return new Constructor(this.message, this.statusCode, this.cause, {
63
+ ...this.context,
64
+ ...context
65
+ });
66
+ }
67
+ };
68
+ __name(_SDKError, "SDKError");
69
+ var SDKError = _SDKError;
70
+
71
+ // src/errors/auth-errors.ts
72
+ var _AuthenticationError = class _AuthenticationError extends SDKError {
73
+ constructor(message = "Authentication failed", statusCode = 401, cause, context) {
74
+ super(message, statusCode, cause, context);
75
+ __publicField(this, "code", "AUTHENTICATION_ERROR");
76
+ __publicField(this, "retryable", false);
77
+ }
78
+ getUserMessage() {
79
+ return "Authentication failed. Please check your API key and try again.";
80
+ }
81
+ };
82
+ __name(_AuthenticationError, "AuthenticationError");
83
+ var AuthenticationError = _AuthenticationError;
84
+ var _AuthorizationError = class _AuthorizationError extends SDKError {
85
+ constructor(message = "Authorization failed", statusCode = 403, cause, context) {
86
+ super(message, statusCode, cause, context);
87
+ __publicField(this, "code", "AUTHORIZATION_ERROR");
88
+ __publicField(this, "retryable", false);
89
+ }
90
+ getUserMessage() {
91
+ return "You do not have permission to access this resource.";
92
+ }
93
+ };
94
+ __name(_AuthorizationError, "AuthorizationError");
95
+ var AuthorizationError = _AuthorizationError;
96
+ var _InvalidApiKeyError = class _InvalidApiKeyError extends SDKError {
97
+ constructor(message = "Invalid API key", cause, context) {
98
+ super(message, 401, cause, context);
99
+ __publicField(this, "code", "INVALID_API_KEY");
100
+ __publicField(this, "retryable", false);
101
+ }
102
+ getUserMessage() {
103
+ return "Invalid API key. Please check your API key and try again.";
104
+ }
105
+ };
106
+ __name(_InvalidApiKeyError, "InvalidApiKeyError");
107
+ var InvalidApiKeyError = _InvalidApiKeyError;
108
+
109
+ // src/errors/contract-errors.ts
110
+ var _MissingApiKeyError = class _MissingApiKeyError extends SDKError {
111
+ constructor(message = "No API key was sent", context) {
112
+ super(message, 401, void 0, context);
113
+ __publicField(this, "code", "MISSING_API_KEY");
114
+ __publicField(this, "retryable", false);
115
+ }
116
+ getUserMessage() {
117
+ return "No API key was sent. Set `apiKey` when creating the client.";
118
+ }
119
+ };
120
+ __name(_MissingApiKeyError, "MissingApiKeyError");
121
+ var MissingApiKeyError = _MissingApiKeyError;
122
+ var _ReadOnlyKeyError = class _ReadOnlyKeyError extends SDKError {
123
+ constructor(message = "This API key is read-only", context) {
124
+ super(message, 403, void 0, context);
125
+ __publicField(this, "code", "READ_ONLY_KEY");
126
+ __publicField(this, "retryable", false);
127
+ }
128
+ getUserMessage() {
129
+ return "This API key is read-only. Use a key with write access for this operation.";
130
+ }
131
+ };
132
+ __name(_ReadOnlyKeyError, "ReadOnlyKeyError");
133
+ var ReadOnlyKeyError = _ReadOnlyKeyError;
134
+ var _PlanFeatureUnavailableError = class _PlanFeatureUnavailableError extends SDKError {
135
+ constructor(message = "This feature is not available on the current plan", feature, context) {
136
+ super(message, 403, void 0, context);
137
+ __publicField(this, "code", "PLAN_FEATURE_UNAVAILABLE");
138
+ __publicField(this, "retryable", false);
139
+ /** The entitlement key the service named, when it named one. */
140
+ __publicField(this, "feature");
141
+ this.feature = feature;
142
+ }
143
+ getUserMessage() {
144
+ return this.feature === void 0 ? "This feature is not available on the current plan." : `The current plan does not include "${this.feature}".`;
145
+ }
146
+ };
147
+ __name(_PlanFeatureUnavailableError, "PlanFeatureUnavailableError");
148
+ var PlanFeatureUnavailableError = _PlanFeatureUnavailableError;
149
+ var _UsageQuotaExceededError = class _UsageQuotaExceededError extends SDKError {
150
+ constructor(message = "Usage quota exceeded", meter, limit, context) {
151
+ super(message, 403, void 0, context);
152
+ __publicField(this, "code", "USAGE_QUOTA_EXCEEDED");
153
+ __publicField(this, "retryable", false);
154
+ /** The meter the service named. Always present on a refusal from the contract. */
155
+ __publicField(this, "meter");
156
+ /** The threshold, where the deciding seam carried one — often it does not. */
157
+ __publicField(this, "limit");
158
+ this.meter = meter;
159
+ this.limit = limit;
160
+ }
161
+ getUserMessage() {
162
+ return this.meter === void 0 ? "A usage quota for this account has been exceeded." : `The "${this.meter}" quota for this account has been exceeded.`;
163
+ }
164
+ };
165
+ __name(_UsageQuotaExceededError, "UsageQuotaExceededError");
166
+ var UsageQuotaExceededError = _UsageQuotaExceededError;
167
+ var _RateLimitError = class _RateLimitError extends SDKError {
168
+ constructor(message = "Rate limit exceeded", limit, resetAt, context) {
169
+ super(message, 429, void 0, context);
170
+ __publicField(this, "code", "RATE_LIMIT_EXCEEDED");
171
+ __publicField(this, "retryable", true);
172
+ __publicField(this, "limit");
173
+ __publicField(this, "resetAt");
174
+ this.limit = limit;
175
+ this.resetAt = resetAt;
176
+ }
177
+ getUserMessage() {
178
+ return this.resetAt === void 0 ? "Too many requests. Please retry shortly." : `Too many requests. The window resets at ${this.resetAt}.`;
179
+ }
180
+ };
181
+ __name(_RateLimitError, "RateLimitError");
182
+ var RateLimitError = _RateLimitError;
183
+ var _MethodNotAllowedError = class _MethodNotAllowedError extends SDKError {
184
+ constructor(message = "Method not allowed", context) {
185
+ super(message, 405, void 0, context);
186
+ __publicField(this, "code", "METHOD_NOT_ALLOWED");
187
+ __publicField(this, "retryable", false);
188
+ }
189
+ getUserMessage() {
190
+ return "That operation is not available on this resource.";
191
+ }
192
+ };
193
+ __name(_MethodNotAllowedError, "MethodNotAllowedError");
194
+ var MethodNotAllowedError = _MethodNotAllowedError;
195
+ var _PayloadTooLargeError = class _PayloadTooLargeError extends SDKError {
196
+ constructor(message = "Payload too large", limitBytes, context) {
197
+ super(message, 413, void 0, context);
198
+ __publicField(this, "code", "PAYLOAD_TOO_LARGE");
199
+ __publicField(this, "retryable", false);
200
+ __publicField(this, "limitBytes");
201
+ this.limitBytes = limitBytes;
202
+ }
203
+ getUserMessage() {
204
+ return this.limitBytes === void 0 ? "The request body is larger than this endpoint accepts." : `The request body is larger than the ${this.limitBytes}-byte limit.`;
205
+ }
206
+ };
207
+ __name(_PayloadTooLargeError, "PayloadTooLargeError");
208
+ var PayloadTooLargeError = _PayloadTooLargeError;
209
+ var _TransactionRolledBackError = class _TransactionRolledBackError extends SDKError {
210
+ constructor(message = "Transaction rolled back", failedIndex, context) {
211
+ super(message, 409, void 0, context);
212
+ __publicField(this, "code", "TRANSACTION_ROLLED_BACK");
213
+ __publicField(this, "retryable", false);
214
+ __publicField(this, "failedIndex");
215
+ this.failedIndex = failedIndex;
216
+ }
217
+ getUserMessage() {
218
+ return this.failedIndex === void 0 ? "The batch was rolled back; nothing was written." : `The batch was rolled back at operation ${this.failedIndex}; nothing was written.`;
219
+ }
220
+ };
221
+ __name(_TransactionRolledBackError, "TransactionRolledBackError");
222
+ var TransactionRolledBackError = _TransactionRolledBackError;
223
+ var _ServiceIndeterminateError = class _ServiceIndeterminateError extends SDKError {
224
+ constructor(message = "The service could not decide this request", missing, context) {
225
+ super(message, 503, void 0, context);
226
+ __publicField(this, "code", "SERVICE_INDETERMINATE");
227
+ __publicField(this, "retryable", true);
228
+ __publicField(this, "missing");
229
+ this.missing = missing;
230
+ }
231
+ getUserMessage() {
232
+ return "The service is temporarily unable to answer. Please retry.";
233
+ }
234
+ };
235
+ __name(_ServiceIndeterminateError, "ServiceIndeterminateError");
236
+ var ServiceIndeterminateError = _ServiceIndeterminateError;
237
+ var _ServerError = class _ServerError extends SDKError {
238
+ constructor(message = "The service failed to handle the request", statusCode = 500, context) {
239
+ super(message, statusCode, void 0, context);
240
+ __publicField(this, "code", "INTERNAL_ERROR");
241
+ __publicField(this, "retryable", true);
242
+ }
243
+ getUserMessage() {
244
+ return "Something went wrong on the RelyIO side. Please retry.";
245
+ }
246
+ };
247
+ __name(_ServerError, "ServerError");
248
+ var ServerError = _ServerError;
249
+ var _UnknownContractError = class _UnknownContractError extends SDKError {
250
+ constructor(code, message, statusCode, context) {
251
+ super(message, statusCode, void 0, context);
252
+ __publicField(this, "code");
253
+ __publicField(this, "retryable", false);
254
+ this.code = code;
255
+ }
256
+ getUserMessage() {
257
+ return `The service refused this request with "${this.code}".`;
258
+ }
259
+ };
260
+ __name(_UnknownContractError, "UnknownContractError");
261
+ var UnknownContractError = _UnknownContractError;
262
+
263
+ // src/errors/content-errors.ts
264
+ var _ResourceNotFoundError = class _ResourceNotFoundError extends SDKError {
265
+ constructor(message = "Resource not found", statusCode = 404, cause, context) {
266
+ super(message, statusCode, cause, context);
267
+ __publicField(this, "code", "RESOURCE_NOT_FOUND");
268
+ __publicField(this, "retryable", false);
269
+ }
270
+ getUserMessage() {
271
+ const resourceType = this.context?.resourceType;
272
+ const resourceId = this.context?.resourceId;
273
+ if (resourceType != null && resourceId != null) {
274
+ return `${resourceType} with ID "${resourceId}" was not found.`;
275
+ }
276
+ return "The requested resource was not found.";
277
+ }
278
+ };
279
+ __name(_ResourceNotFoundError, "ResourceNotFoundError");
280
+ var ResourceNotFoundError = _ResourceNotFoundError;
281
+ var _ResourceConflictError = class _ResourceConflictError extends SDKError {
282
+ constructor(message = "Resource conflict", statusCode = 409, cause, context) {
283
+ super(message, statusCode, cause, context);
284
+ __publicField(this, "code", "RESOURCE_CONFLICT");
285
+ __publicField(this, "retryable", false);
286
+ }
287
+ getUserMessage() {
288
+ return "The resource could not be created or updated due to a conflict.";
289
+ }
290
+ };
291
+ __name(_ResourceConflictError, "ResourceConflictError");
292
+ var ResourceConflictError = _ResourceConflictError;
293
+ var _ResourceExpiredError = class _ResourceExpiredError extends SDKError {
294
+ constructor(message = "Resource has expired", statusCode = 410, cause, context) {
295
+ super(message, statusCode, cause, context);
296
+ __publicField(this, "code", "RESOURCE_EXPIRED");
297
+ __publicField(this, "retryable", false);
298
+ }
299
+ getUserMessage() {
300
+ return "The resource is no longer available.";
301
+ }
302
+ };
303
+ __name(_ResourceExpiredError, "ResourceExpiredError");
304
+ var ResourceExpiredError = _ResourceExpiredError;
305
+ function isResourceNotFound(error) {
306
+ return error instanceof ResourceNotFoundError;
307
+ }
308
+ __name(isResourceNotFound, "isResourceNotFound");
309
+
310
+ // src/errors/network-errors.ts
311
+ var _NetworkError = class _NetworkError extends SDKError {
312
+ constructor(message = "Network request failed", statusCode, cause, context) {
313
+ super(message, statusCode, cause, context);
314
+ __publicField(this, "code", "NETWORK_ERROR");
315
+ __publicField(this, "retryable", true);
316
+ }
317
+ getUserMessage() {
318
+ return "Network connection failed. Please check your internet connection and try again.";
319
+ }
320
+ };
321
+ __name(_NetworkError, "NetworkError");
322
+ var NetworkError = _NetworkError;
323
+ var _TimeoutError = class _TimeoutError extends SDKError {
324
+ constructor(message = "Request timed out", timeout, statusCode, cause) {
325
+ super(message, statusCode, cause, { timeout });
326
+ __publicField(this, "code", "TIMEOUT_ERROR");
327
+ __publicField(this, "retryable", true);
328
+ }
329
+ getUserMessage() {
330
+ const timeout = this.context?.timeout;
331
+ return `Request timed out${timeout != null ? ` after ${timeout}ms` : ""}. Please try again.`;
332
+ }
333
+ };
334
+ __name(_TimeoutError, "TimeoutError");
335
+ var TimeoutError = _TimeoutError;
336
+ var _ConnectionError = class _ConnectionError extends SDKError {
337
+ constructor(message = "Connection failed", statusCode, cause, context) {
338
+ super(message, statusCode, cause, context);
339
+ __publicField(this, "code", "CONNECTION_ERROR");
340
+ __publicField(this, "retryable", true);
341
+ }
342
+ getUserMessage() {
343
+ return "Failed to connect to RelyIO servers. Please check your connection and try again.";
344
+ }
345
+ };
346
+ __name(_ConnectionError, "ConnectionError");
347
+ var ConnectionError = _ConnectionError;
348
+
349
+ // src/errors/validation-errors.ts
350
+ var _BaseValidationError = class _BaseValidationError extends SDKError {
351
+ constructor(message = "Validation failed", violations = [], statusCode = 400, cause) {
352
+ super(message, statusCode, cause, { violations });
353
+ __publicField(this, "retryable", false);
354
+ __publicField(this, "violations");
355
+ this.violations = violations;
356
+ }
357
+ getUserMessage() {
358
+ if (this.violations.length === 0) {
359
+ return "Validation failed. Please check your input and try again.";
360
+ }
361
+ if (this.violations.length === 1) {
362
+ const violation = this.violations[0];
363
+ return `Validation failed: ${violation?.message ?? "Unknown error"}`;
364
+ }
365
+ return `Validation failed with ${this.violations.length} errors. Please check your input and try again.`;
366
+ }
367
+ /**
368
+ * Get violations for a specific field
369
+ */
370
+ getViolationsForField(fieldName) {
371
+ return this.violations.filter((v) => v.field === fieldName);
372
+ }
373
+ /**
374
+ * Check if a specific field has validation errors
375
+ */
376
+ hasFieldError(fieldName) {
377
+ return this.violations.some((v) => v.field === fieldName);
378
+ }
379
+ /**
380
+ * Get all validation messages as a formatted string
381
+ */
382
+ getFormattedMessages() {
383
+ return this.violations.map((v) => `${v.field}: ${v.message}`).join("\n");
384
+ }
385
+ };
386
+ __name(_BaseValidationError, "BaseValidationError");
387
+ var BaseValidationError = _BaseValidationError;
388
+ var _ValidationError = class _ValidationError extends BaseValidationError {
389
+ constructor() {
390
+ super(...arguments);
391
+ __publicField(this, "code", "VALIDATION_ERROR");
392
+ }
393
+ };
394
+ __name(_ValidationError, "ValidationError");
395
+ var ValidationError = _ValidationError;
396
+ var _InvalidPayloadError = class _InvalidPayloadError extends BaseValidationError {
397
+ constructor(message = "Invalid payload", violations = [], cause) {
398
+ super(message, violations, 400, cause);
399
+ __publicField(this, "code", "INVALID_PAYLOAD");
400
+ }
401
+ getUserMessage() {
402
+ return "The request payload is invalid. Please check your data and try again.";
403
+ }
404
+ };
405
+ __name(_InvalidPayloadError, "InvalidPayloadError");
406
+ var InvalidPayloadError = _InvalidPayloadError;
407
+ var _SchemaValidationError = class _SchemaValidationError extends BaseValidationError {
408
+ constructor(message = "Schema validation failed", violations = [], cause) {
409
+ super(message, violations, 400, cause);
410
+ __publicField(this, "code", "SCHEMA_VALIDATION_ERROR");
411
+ }
412
+ getUserMessage() {
413
+ return "The data does not match the expected schema. Please check your content structure.";
414
+ }
415
+ };
416
+ __name(_SchemaValidationError, "SchemaValidationError");
417
+ var SchemaValidationError = _SchemaValidationError;
418
+ var _RequiredFieldError = class _RequiredFieldError extends BaseValidationError {
419
+ constructor(fieldName, message, cause) {
420
+ const violation = {
421
+ field: fieldName,
422
+ message: message ?? `Field "${fieldName}" is required`,
423
+ code: "REQUIRED"
424
+ };
425
+ super(`Required field "${fieldName}" is missing`, [violation], 400, cause);
426
+ __publicField(this, "code", "REQUIRED_FIELD_ERROR");
427
+ }
428
+ getUserMessage() {
429
+ const violation = this.violations[0];
430
+ const fieldName = violation?.field;
431
+ return `The field "${fieldName}" is required and cannot be empty.`;
432
+ }
433
+ };
434
+ __name(_RequiredFieldError, "RequiredFieldError");
435
+ var RequiredFieldError = _RequiredFieldError;
436
+ var _InvalidFieldTypeError = class _InvalidFieldTypeError extends BaseValidationError {
437
+ constructor(fieldName, expectedType, actualType, value, cause) {
438
+ const violation = {
439
+ field: fieldName,
440
+ message: `Expected ${expectedType}, got ${actualType}`,
441
+ code: "INVALID_TYPE",
442
+ value
443
+ };
444
+ super(
445
+ `Invalid type for field "${fieldName}": expected ${expectedType}, got ${actualType}`,
446
+ [violation],
447
+ 400,
448
+ cause
449
+ );
450
+ __publicField(this, "code", "INVALID_FIELD_TYPE");
451
+ }
452
+ getUserMessage() {
453
+ const violation = this.violations[0];
454
+ return `The field "${violation?.field}" has an invalid type. ${violation?.message}.`;
455
+ }
456
+ };
457
+ __name(_InvalidFieldTypeError, "InvalidFieldTypeError");
458
+ var InvalidFieldTypeError = _InvalidFieldTypeError;
459
+
460
+ // ../../platform/api-contract/dist/client/index.js
461
+ var _a;
462
+ var ContractBodyError = (_a = class extends Error {
463
+ constructor(message, body) {
464
+ super(message);
465
+ __publicField(this, "body");
466
+ this.name = "ContractBodyError";
467
+ this.body = body;
468
+ }
469
+ }, __name(_a, "ContractBodyError"), _a);
470
+ function describe(body) {
471
+ try {
472
+ return JSON.stringify(body)?.slice(0, 200) ?? String(body);
473
+ } catch {
474
+ return String(body);
475
+ }
476
+ }
477
+ __name(describe, "describe");
478
+ function readPayload(body) {
479
+ if (typeof body !== "object" || body === null || !("data" in body)) {
480
+ throw new ContractBodyError(
481
+ `expected a contract success body carrying \`data\`, got ${describe(body)}`,
482
+ body
483
+ );
484
+ }
485
+ return body.data;
486
+ }
487
+ __name(readPayload, "readPayload");
488
+ function readError(body) {
489
+ if (typeof body !== "object" || body === null || !("error" in body)) return void 0;
490
+ const error = body.error;
491
+ if (typeof error !== "object" || error === null || !("code" in error)) return void 0;
492
+ const code = error.code;
493
+ if (typeof code !== "string") return void 0;
494
+ const messages = error.messages;
495
+ return {
496
+ code,
497
+ messages: Array.isArray(messages) ? messages.filter((m) => typeof m === "string") : [],
498
+ ..."details" in error ? { details: error.details } : {}
499
+ };
500
+ }
501
+ __name(readError, "readError");
502
+
503
+ // src/errors/error-mapper.ts
504
+ var _ErrorMapper = class _ErrorMapper {
505
+ /** Map a non-2xx response to an SDK error. */
506
+ static mapHttpError(response, requestContext) {
507
+ const { status, statusText, body } = response;
508
+ const refusal = readError(body);
509
+ const context = { ...requestContext, response: body };
510
+ if (refusal === void 0) {
511
+ return new NetworkError(`HTTP ${status}: ${statusText}`.trim(), status, void 0, context);
512
+ }
513
+ return this.fromContractCode(refusal, status, context);
514
+ }
515
+ static fromContractCode(refusal, status, context) {
516
+ const message = refusal.messages[0] ?? `RelyIO refused with ${refusal.code}`;
517
+ switch (refusal.code) {
518
+ case "MISSING_API_KEY": {
519
+ return new MissingApiKeyError(message, context);
520
+ }
521
+ case "INVALID_API_KEY": {
522
+ return new InvalidApiKeyError(message, void 0, context);
523
+ }
524
+ case "ACCESS_DENIED": {
525
+ return new AuthorizationError(message, 403, void 0, context);
526
+ }
527
+ case "READ_ONLY_KEY": {
528
+ return new ReadOnlyKeyError(message, context);
529
+ }
530
+ case "PLAN_FEATURE_UNAVAILABLE": {
531
+ return new PlanFeatureUnavailableError(message, detailString(refusal, "feature"), context);
532
+ }
533
+ case "USAGE_QUOTA_EXCEEDED": {
534
+ return new UsageQuotaExceededError(
535
+ message,
536
+ detailString(refusal, "meter"),
537
+ detailNumber(refusal, "limit"),
538
+ context
539
+ );
540
+ }
541
+ case "RATE_LIMIT_EXCEEDED": {
542
+ return new RateLimitError(
543
+ message,
544
+ detailNumber(refusal, "limit"),
545
+ detailString(refusal, "resetAt"),
546
+ context
547
+ );
548
+ }
549
+ case "REQUEST_INVALID": {
550
+ return new InvalidPayloadError(message, violationsOf(refusal));
551
+ }
552
+ case "CONTENT_INVALID": {
553
+ return new ValidationError(message, violationsOf(refusal), 400);
554
+ }
555
+ case "METHOD_NOT_ALLOWED": {
556
+ return new MethodNotAllowedError(message, context);
557
+ }
558
+ case "RESOURCE_NOT_FOUND": {
559
+ return new ResourceNotFoundError(message, 404, void 0, {
560
+ ...context,
561
+ resourceType: detailString(refusal, "kind"),
562
+ resourceId: detailString(refusal, "id")
563
+ });
564
+ }
565
+ case "RESOURCE_CONFLICT": {
566
+ return new ResourceConflictError(message, 409, void 0, {
567
+ ...context,
568
+ expectedVersion: detailNumber(refusal, "expectedVersion"),
569
+ actualVersion: detailNumber(refusal, "actualVersion")
570
+ });
571
+ }
572
+ case "RESOURCE_EXPIRED": {
573
+ return new ResourceExpiredError(message, 410, void 0, context);
574
+ }
575
+ case "REQUEST_TIMEOUT": {
576
+ return new TimeoutError(message, void 0, void 0, void 0);
577
+ }
578
+ case "PAYLOAD_TOO_LARGE": {
579
+ return new PayloadTooLargeError(message, detailNumber(refusal, "limitBytes"), context);
580
+ }
581
+ case "TRANSACTION_ROLLED_BACK": {
582
+ return new TransactionRolledBackError(
583
+ message,
584
+ detailNumber(refusal, "failedIndex"),
585
+ context
586
+ );
587
+ }
588
+ case "SERVICE_INDETERMINATE": {
589
+ return new ServiceIndeterminateError(message, detailString(refusal, "missing"), context);
590
+ }
591
+ case "INTERNAL_ERROR": {
592
+ return new ServerError(message, status, context);
593
+ }
594
+ default: {
595
+ return new UnknownContractError(refusal.code, message, status, context);
596
+ }
597
+ }
598
+ }
599
+ /**
600
+ * Map generic JavaScript errors to SDK errors
601
+ */
602
+ static mapGenericError(error, _context) {
603
+ if (error instanceof SDKError) {
604
+ return error;
605
+ }
606
+ if (error.name === "TypeError" && error.message.includes("fetch")) {
607
+ return new NetworkError("Network request failed", void 0, error, _context);
608
+ }
609
+ if (error.name === "AbortError" || error.message.includes("timeout")) {
610
+ return new TimeoutError("Request timed out", void 0, void 0, error);
611
+ }
612
+ if (error.message.includes("Network Error") || error.message.includes("ECONNREFUSED")) {
613
+ return new ConnectionError("Connection failed", void 0, error, _context);
614
+ }
615
+ return new NetworkError(
616
+ error.message ?? "An unknown error occurred",
617
+ void 0,
618
+ error,
619
+ _context
620
+ );
621
+ }
622
+ /**
623
+ * Check if an error is retryable
624
+ */
625
+ static isRetryable(error) {
626
+ if (error instanceof SDKError) {
627
+ return error.retryable;
628
+ }
629
+ return error.name === "TypeError" && error.message.includes("fetch") || error.message.includes("timeout") || error.message.includes("Network Error") || error.message.includes("ECONNREFUSED");
630
+ }
631
+ /**
632
+ * Extract retry delay from error
633
+ */
634
+ static getRetryDelay(_error) {
635
+ return 0;
636
+ }
637
+ };
638
+ __name(_ErrorMapper, "ErrorMapper");
639
+ var ErrorMapper = _ErrorMapper;
640
+ function knownCode(refusal) {
641
+ return typeof refusal.code === "string" ? refusal.code : void 0;
642
+ }
643
+ __name(knownCode, "knownCode");
644
+ function detailBag(refusal) {
645
+ if (knownCode(refusal) === void 0) return void 0;
646
+ const details = refusal.details;
647
+ if (typeof details !== "object" || details === null) return void 0;
648
+ return details;
649
+ }
650
+ __name(detailBag, "detailBag");
651
+ function detailString(refusal, key) {
652
+ const value = detailBag(refusal)?.[key];
653
+ return typeof value === "string" ? value : void 0;
654
+ }
655
+ __name(detailString, "detailString");
656
+ function detailNumber(refusal, key) {
657
+ const value = detailBag(refusal)?.[key];
658
+ return typeof value === "number" ? value : void 0;
659
+ }
660
+ __name(detailNumber, "detailNumber");
661
+ function violationsOf(refusal) {
662
+ const issues = detailBag(refusal)?.issues;
663
+ if (!Array.isArray(issues)) return [];
664
+ return issues.filter((issue) => typeof issue === "object" && issue !== null).map((issue) => ({
665
+ field: issue.path,
666
+ message: issue.message,
667
+ code: issue.code,
668
+ path: issue.path === "" ? void 0 : issue.path.split(".")
669
+ }));
670
+ }
671
+ __name(violationsOf, "violationsOf");
672
+
673
+ // src/http/api-routes.ts
674
+ function fillPath(template, params) {
675
+ const missing = [];
676
+ const filled = template.replace(/\{(\w+)\}/g, (_match, name) => {
677
+ const value = params[name];
678
+ if (value === void 0) {
679
+ missing.push(name);
680
+ return "";
681
+ }
682
+ return encodeURIComponent(value);
683
+ });
684
+ if (missing.length > 0) {
685
+ throw new Error(`${template} needs path parameter(s) ${missing.join(", ")}`);
686
+ }
687
+ const extra = Object.keys(params).filter((name) => !template.includes(`{${name}}`));
688
+ if (extra.length > 0) {
689
+ throw new Error(`${template} declares no path parameter(s) ${extra.join(", ")}`);
690
+ }
691
+ return filled;
692
+ }
693
+ __name(fillPath, "fillPath");
694
+
695
+ // src/http/http-client.ts
696
+ var _HttpClient = class _HttpClient {
697
+ constructor(config) {
698
+ __publicField(this, "baseUrl");
699
+ __publicField(this, "defaultHeaders");
700
+ __publicField(this, "timeout");
701
+ __publicField(this, "retryConfig");
702
+ __publicField(this, "debug");
703
+ __publicField(this, "logger");
704
+ __publicField(this, "config");
705
+ this.config = config;
706
+ this.baseUrl = config.baseUrl;
707
+ this.timeout = config.timeout;
708
+ this.debug = config.debug.enabled ?? false;
709
+ this.logger = config.debug.logger;
710
+ this.defaultHeaders = {
711
+ "Content-Type": "application/json",
712
+ "X-API-Key": config.apiKey,
713
+ ...config.headers
714
+ };
715
+ if (config.dataset != null) {
716
+ this.defaultHeaders["X-RelyIO-Dataset"] = config.dataset;
717
+ }
718
+ if (typeof window === "undefined") {
719
+ const globalWithVersion = globalThis;
720
+ this.defaultHeaders["User-Agent"] = `RelyIO-SDK/${globalWithVersion.__VERSION__ ?? "0.0.0"}`;
721
+ }
722
+ this.retryConfig = {
723
+ maxAttempts: config.retryAttempts,
724
+ baseDelay: 1e3,
725
+ maxDelay: 1e4,
726
+ backoffFactor: 2,
727
+ jitter: true,
728
+ retryCondition: /* @__PURE__ */ __name((error, attempt) => {
729
+ return ErrorMapper.isRetryable(error) && attempt < config.retryAttempts;
730
+ }, "retryCondition")
731
+ };
732
+ this.log("debug", "HttpClient initialized", {
733
+ baseUrl: this.baseUrl,
734
+ timeout: this.timeout,
735
+ retryAttempts: config.retryAttempts,
736
+ environment: typeof window === "undefined" ? "node" : "browser"
737
+ });
738
+ }
739
+ /**
740
+ * Call a route the committed document declares, and get back the body that
741
+ * document says it serves.
742
+ */
743
+ async send(path, method, options) {
744
+ const pathParams = options.path === void 0 ? {} : { ...options.path };
745
+ return this.request({
746
+ method: method.toUpperCase(),
747
+ url: fillPath(path, pathParams),
748
+ params: options.query,
749
+ body: options.body,
750
+ headers: options.headers,
751
+ signal: options.signal,
752
+ timeout: options.timeout
753
+ });
754
+ }
755
+ /**
756
+ * Call a route and return its payload — `send` plus the one unwrap, which is
757
+ * what all but a handful of call sites want.
758
+ */
759
+ async fetchPayload(path, method, options) {
760
+ const response = await this.send(path, method, options);
761
+ return readPayload(response.body);
762
+ }
763
+ /**
764
+ * Make an HTTP request with retry logic
765
+ */
766
+ async request(config) {
767
+ const mergedConfig = this.mergeRequestConfig(config);
768
+ this.log("debug", "Making request", {
769
+ method: mergedConfig.method,
770
+ url: mergedConfig.url
771
+ // Show the final URL with query params
772
+ });
773
+ let lastError;
774
+ let attempt = 0;
775
+ while (attempt < this.retryConfig.maxAttempts) {
776
+ attempt++;
777
+ try {
778
+ if (config.method === "DELETE" && mergedConfig.headers) {
779
+ delete mergedConfig.headers["Content-Type"];
780
+ }
781
+ const response = await this.makeRequest(mergedConfig.url, mergedConfig);
782
+ this.log("debug", "Request successful", {
783
+ status: response.status,
784
+ attempt,
785
+ url: mergedConfig.url
786
+ });
787
+ return response;
788
+ } catch (error) {
789
+ lastError = error;
790
+ this.log("warn", "Request failed", {
791
+ error: error instanceof Error ? error.message : "Unknown error",
792
+ attempt,
793
+ url: mergedConfig.url
794
+ });
795
+ if (attempt < this.retryConfig.maxAttempts && this.retryConfig.retryCondition?.(lastError, attempt) === true) {
796
+ const delay = this.calculateRetryDelay(attempt);
797
+ this.log("debug", "Retrying request", { attempt, delay });
798
+ await this.sleep(delay);
799
+ continue;
800
+ }
801
+ break;
802
+ }
803
+ }
804
+ const sdkError = ErrorMapper.mapGenericError(lastError, {
805
+ url: mergedConfig.url,
806
+ method: mergedConfig.method,
807
+ attempt
808
+ });
809
+ this.log("error", "Request failed after all retries", {
810
+ error: sdkError.toJSON(),
811
+ url: mergedConfig.url
812
+ });
813
+ throw sdkError;
814
+ }
815
+ /**
816
+ * Make a GET request
817
+ */
818
+ async get(url, params) {
819
+ return this.request({
820
+ method: "GET",
821
+ url,
822
+ params
823
+ });
824
+ }
825
+ /**
826
+ * Make a POST request
827
+ */
828
+ async post(url, data, params) {
829
+ return this.request({
830
+ method: "POST",
831
+ url,
832
+ body: data,
833
+ params
834
+ });
835
+ }
836
+ /**
837
+ * Make a PUT request
838
+ */
839
+ async put(url, data, params) {
840
+ return this.request({
841
+ method: "PUT",
842
+ url,
843
+ body: data,
844
+ params
845
+ });
846
+ }
847
+ /**
848
+ * Make a DELETE request
849
+ */
850
+ async delete(url, params) {
851
+ return this.request({
852
+ method: "DELETE",
853
+ url,
854
+ params
855
+ });
856
+ }
857
+ /**
858
+ * Make a PATCH request
859
+ */
860
+ async patch(url, data, params) {
861
+ return this.request({
862
+ method: "PATCH",
863
+ url,
864
+ body: data,
865
+ params
866
+ });
867
+ }
868
+ /**
869
+ * Set default headers for all requests
870
+ */
871
+ setDefaultHeaders(headers) {
872
+ this.defaultHeaders = { ...this.defaultHeaders, ...headers };
873
+ }
874
+ /**
875
+ * Set authentication token
876
+ */
877
+ setAuthToken(token) {
878
+ this.defaultHeaders.Authorization = `Bearer ${token}`;
879
+ }
880
+ /**
881
+ * Get current default headers
882
+ */
883
+ getDefaultHeaders() {
884
+ return { ...this.defaultHeaders };
885
+ }
886
+ /**
887
+ * Update base URL
888
+ */
889
+ setBaseUrl(baseUrl) {
890
+ this.baseUrl = baseUrl;
891
+ }
892
+ /**
893
+ * Get current base URL
894
+ */
895
+ getBaseUrl() {
896
+ return this.baseUrl;
897
+ }
898
+ async makeRequest(url, config) {
899
+ const controller = new AbortController();
900
+ const timeoutId = setTimeout(() => controller.abort(), config.timeout ?? this.timeout);
901
+ try {
902
+ const filteredHeaders = this.filterHeadersForBrowser(config.headers ?? {});
903
+ const requestInit = {
904
+ method: config.method,
905
+ headers: filteredHeaders,
906
+ body: this.prepareRequestBody(config),
907
+ signal: config.signal ?? controller.signal,
908
+ // Include credentials for CORS requests if in browser and configured
909
+ ...typeof window !== "undefined" && this.config.browser.includeCredentials != null && { credentials: "include" }
910
+ };
911
+ const response = await fetch(url, requestInit);
912
+ clearTimeout(timeoutId);
913
+ const responseBody = await this.parseResponse(response);
914
+ if (!response.ok) {
915
+ const error = ErrorMapper.mapHttpError(
916
+ {
917
+ status: response.status,
918
+ statusText: response.statusText,
919
+ body: responseBody,
920
+ headers: this.headersToObject(response.headers)
921
+ },
922
+ {
923
+ url: config.url,
924
+ method: config.method
925
+ }
926
+ );
927
+ throw error;
928
+ }
929
+ return {
930
+ body: responseBody,
931
+ status: response.status,
932
+ statusText: response.statusText,
933
+ headers: this.headersToObject(response.headers),
934
+ config
935
+ };
936
+ } catch (error) {
937
+ clearTimeout(timeoutId);
938
+ if (error instanceof SDKError) {
939
+ throw error;
940
+ }
941
+ if (error instanceof DOMException && error.name === "AbortError") {
942
+ throw new TimeoutError(
943
+ `Request timed out after ${config.timeout ?? this.timeout}ms`,
944
+ config.timeout ?? this.timeout
945
+ );
946
+ }
947
+ if (error instanceof TypeError && error.message.includes("CORS")) {
948
+ const corsError = new NetworkError(
949
+ "CORS policy error: The request was blocked by CORS policy. This usually means the server is not configured to allow requests from this origin. Please check the server CORS configuration.",
950
+ void 0,
951
+ error,
952
+ {
953
+ url: config.url,
954
+ method: config.method,
955
+ corsError: true,
956
+ suggestion: "Check if the API server allows requests from your domain and has proper CORS headers configured."
957
+ }
958
+ );
959
+ if (typeof window !== "undefined" && this.config.browser.onCorsError) {
960
+ try {
961
+ this.config.browser.onCorsError(corsError, {
962
+ url: config.url,
963
+ method: config.method,
964
+ originalError: error
965
+ });
966
+ } catch (handlerError) {
967
+ this.log("warn", "Custom CORS error handler threw an error", handlerError);
968
+ }
969
+ }
970
+ throw corsError;
971
+ }
972
+ throw error;
973
+ }
974
+ }
975
+ /**
976
+ * Filter headers that browsers don't allow to be set manually
977
+ */
978
+ filterHeadersForBrowser(headers) {
979
+ if (typeof window !== "undefined") {
980
+ const filteredHeaders = { ...headers };
981
+ const forbiddenHeaders = ["user-agent", "referer", "origin", "host", "connection", "upgrade"];
982
+ forbiddenHeaders.forEach((header) => {
983
+ delete filteredHeaders[header];
984
+ delete filteredHeaders[header.toLowerCase()];
985
+ delete filteredHeaders[header.toUpperCase()];
986
+ });
987
+ return filteredHeaders;
988
+ }
989
+ return headers;
990
+ }
991
+ /**
992
+ * Prepare request body based on content type and environment
993
+ */
994
+ prepareRequestBody(config) {
995
+ if (config.body == null) return void 0;
996
+ if (config.body instanceof FormData || config.body instanceof Blob || typeof config.body === "string") {
997
+ return config.body;
998
+ }
999
+ return JSON.stringify(config.body);
1000
+ }
1001
+ async parseResponse(response) {
1002
+ if (response.status === 204 || response.status === 205) {
1003
+ return void 0;
1004
+ }
1005
+ const contentType = response.headers.get("content-type");
1006
+ if (contentType == null) {
1007
+ return await response.text();
1008
+ }
1009
+ if (contentType.includes("application/json")) {
1010
+ return await response.json();
1011
+ }
1012
+ if (contentType.includes("text/")) {
1013
+ return await response.text();
1014
+ }
1015
+ try {
1016
+ return await response.json();
1017
+ } catch {
1018
+ return await response.text();
1019
+ }
1020
+ }
1021
+ resolveUrl(url) {
1022
+ if (url.startsWith("http://") || url.startsWith("https://")) {
1023
+ return url;
1024
+ }
1025
+ return `${this.baseUrl}${url.startsWith("/") ? "" : "/"}${url}`;
1026
+ }
1027
+ mergeRequestConfig(config) {
1028
+ const url = this.resolveUrl(config.url);
1029
+ const queryString = config.params != null ? this.buildQueryString(config.params) : "";
1030
+ const finalUrl = queryString.length > 0 ? `${url}?${queryString}` : url;
1031
+ return {
1032
+ ...config,
1033
+ url: finalUrl,
1034
+ headers: {
1035
+ ...this.defaultHeaders,
1036
+ ...config.headers
1037
+ },
1038
+ timeout: config.timeout ?? this.timeout
1039
+ };
1040
+ }
1041
+ buildQueryString(params) {
1042
+ const searchParams = new URLSearchParams();
1043
+ for (const [key, value] of Object.entries(params)) {
1044
+ if (value !== void 0 && value !== null) {
1045
+ if (Array.isArray(value)) {
1046
+ value.forEach((v) => searchParams.append(key, String(v)));
1047
+ } else {
1048
+ searchParams.append(key, String(value));
1049
+ }
1050
+ }
1051
+ }
1052
+ return searchParams.toString();
1053
+ }
1054
+ headersToObject(headers) {
1055
+ const obj = {};
1056
+ headers.forEach((value, key) => {
1057
+ obj[key] = value;
1058
+ });
1059
+ return obj;
1060
+ }
1061
+ calculateRetryDelay(attempt) {
1062
+ const exponentialDelay = this.retryConfig.baseDelay * Math.pow(this.retryConfig.backoffFactor, attempt - 1);
1063
+ const delay = Math.min(exponentialDelay, this.retryConfig.maxDelay);
1064
+ if (this.retryConfig.jitter) {
1065
+ return delay * (0.5 + Math.random() * 0.5);
1066
+ }
1067
+ return delay;
1068
+ }
1069
+ sleep(ms) {
1070
+ return new Promise((resolve) => setTimeout(resolve, ms));
1071
+ }
1072
+ log(level, message, data) {
1073
+ if (!this.debug) return;
1074
+ if (this.logger != null) {
1075
+ this.logger(level, message, data);
1076
+ } else {
1077
+ console.log(`[RelyIO SDK ${level.toUpperCase()}] ${message}`, data ?? "");
1078
+ }
1079
+ }
1080
+ };
1081
+ __name(_HttpClient, "HttpClient");
1082
+ var HttpClient = _HttpClient;
1083
+
1084
+ // src/content/query-builder.ts
1085
+ var _ContentQueryBuilder = class _ContentQueryBuilder {
1086
+ constructor(httpClient, contentType, defaultLocale) {
1087
+ this.httpClient = httpClient;
1088
+ this.contentType = contentType;
1089
+ this.defaultLocale = defaultLocale;
1090
+ __publicField(this, "queryOptions", {});
1091
+ __publicField(this, "localeValue");
1092
+ __publicField(this, "localesArray");
1093
+ __publicField(this, "fetchAllLocales", false);
1094
+ __publicField(this, "fieldsProjection");
1095
+ __publicField(this, "childrenOptions");
1096
+ __publicField(this, "pageNumber");
1097
+ __publicField(this, "pageSizeValue");
1098
+ }
1099
+ /**
1100
+ * Add where conditions to the query
1101
+ */
1102
+ where(conditions) {
1103
+ this.queryOptions.where = {
1104
+ ...this.queryOptions.where,
1105
+ ...conditions
1106
+ };
1107
+ return this;
1108
+ }
1109
+ /**
1110
+ * Select specific fields to return
1111
+ */
1112
+ select(fields) {
1113
+ this.queryOptions.select = fields;
1114
+ return this;
1115
+ }
1116
+ /**
1117
+ * Include related content in the response
1118
+ */
1119
+ include(relations) {
1120
+ this.queryOptions.include = [...this.queryOptions.include ?? [], ...relations];
1121
+ return this;
1122
+ }
1123
+ sort(fieldOrOptions, direction) {
1124
+ if (typeof fieldOrOptions === "string") {
1125
+ this.queryOptions.sort = {
1126
+ ...this.queryOptions.sort,
1127
+ [fieldOrOptions]: direction ?? "asc"
1128
+ };
1129
+ } else {
1130
+ this.queryOptions.sort = {
1131
+ ...this.queryOptions.sort,
1132
+ ...fieldOrOptions
1133
+ };
1134
+ }
1135
+ return this;
1136
+ }
1137
+ /**
1138
+ * Sort by a specific field in ascending order
1139
+ */
1140
+ sortAsc(field) {
1141
+ return this.sort(field, "asc");
1142
+ }
1143
+ /**
1144
+ * Sort by a specific field in descending order
1145
+ */
1146
+ sortDesc(field) {
1147
+ return this.sort(field, "desc");
1148
+ }
1149
+ /**
1150
+ * Limit the number of results
1151
+ */
1152
+ limit(count) {
1153
+ this.queryOptions.limit = count;
1154
+ return this;
1155
+ }
1156
+ /**
1157
+ * Set offset for pagination
1158
+ */
1159
+ offset(count) {
1160
+ this.queryOptions.offset = count;
1161
+ return this;
1162
+ }
1163
+ /**
1164
+ * Set cursor for cursor-based pagination
1165
+ */
1166
+ cursor(cursor) {
1167
+ this.queryOptions.cursor = cursor;
1168
+ return this;
1169
+ }
1170
+ /**
1171
+ * Set locale for localized content
1172
+ * @param locale - Locale code (e.g., 'en-US', 'de-DE', 'fr-FR')
1173
+ *
1174
+ * @example
1175
+ * ```typescript
1176
+ * // Fetch in Spanish
1177
+ * .locale('es-ES')
1178
+ * ```
1179
+ */
1180
+ locale(locale) {
1181
+ this.localeValue = locale;
1182
+ this.localesArray = void 0;
1183
+ this.fetchAllLocales = false;
1184
+ return this;
1185
+ }
1186
+ /**
1187
+ * Fetch content in multiple specific locales
1188
+ * Returns primary locale at top level, others in _metadata.localizations
1189
+ *
1190
+ * @param localeCodes - Array of locale codes to fetch
1191
+ *
1192
+ * @example
1193
+ * ```typescript
1194
+ * const product = await client.content('product')
1195
+ * .findById('prod_123')
1196
+ * .locales(['en-US', 'es-ES', 'de-DE'])
1197
+ * .execute()
1198
+ *
1199
+ * // Access: product.title (first locale)
1200
+ * // Access: product._metadata.localizations['es-ES'].title
1201
+ * ```
1202
+ */
1203
+ locales(localeCodes) {
1204
+ this.localesArray = localeCodes;
1205
+ this.localeValue = void 0;
1206
+ this.fetchAllLocales = false;
1207
+ return this;
1208
+ }
1209
+ /**
1210
+ * Fetch content in all available locales
1211
+ * Returns default locale at top level, others in _metadata.localizations
1212
+ *
1213
+ * @example
1214
+ * ```typescript
1215
+ * const product = await client.content('product')
1216
+ * .findById('prod_123')
1217
+ * .allLocales()
1218
+ * .execute()
1219
+ *
1220
+ * // Access: product.title (default locale)
1221
+ * // Access: product._metadata.localizations['es-ES'].title
1222
+ * // Access: product._metadata.availableLocales
1223
+ * ```
1224
+ */
1225
+ allLocales() {
1226
+ this.fetchAllLocales = true;
1227
+ this.localeValue = void 0;
1228
+ this.localesArray = void 0;
1229
+ return this;
1230
+ }
1231
+ /**
1232
+ * Select specific fields to return (projection)
1233
+ * @param fieldNames - Array of field names to include
1234
+ *
1235
+ * @example
1236
+ * ```typescript
1237
+ * .fields(['id', 'title', 'price', 'brand.name'])
1238
+ * ```
1239
+ */
1240
+ fields(fieldNames) {
1241
+ this.fieldsProjection = fieldNames;
1242
+ return this;
1243
+ }
1244
+ /**
1245
+ * Include children in results (for hierarchical content)
1246
+ * @param options - Children options or boolean to enable with defaults
1247
+ *
1248
+ * @example
1249
+ * ```typescript
1250
+ * // Include all children
1251
+ * .children(true)
1252
+ *
1253
+ * // Include with options
1254
+ * .children({ contentTypes: ['variant'], limit: 10 })
1255
+ * ```
1256
+ */
1257
+ children(options) {
1258
+ if (typeof options === "boolean") {
1259
+ this.childrenOptions = options ? {} : void 0;
1260
+ } else {
1261
+ this.childrenOptions = options;
1262
+ }
1263
+ return this;
1264
+ }
1265
+ /**
1266
+ * Set page number for page-based pagination
1267
+ * @param pageNum - Page number (1-based)
1268
+ */
1269
+ page(pageNum) {
1270
+ this.pageNumber = pageNum;
1271
+ return this;
1272
+ }
1273
+ /**
1274
+ * Set page size for page-based pagination
1275
+ * @param size - Items per page
1276
+ */
1277
+ pageSize(size) {
1278
+ this.pageSizeValue = size;
1279
+ return this;
1280
+ }
1281
+ /**
1282
+ * Execute the query and return all matching results
1283
+ */
1284
+ async execute() {
1285
+ return readPayload(await this.executeWithMeta());
1286
+ }
1287
+ /**
1288
+ * Execute the query and return the whole body — the items under `data`, the
1289
+ * cursor facts under `page`.
1290
+ */
1291
+ async executeWithMeta() {
1292
+ const response = await this.httpClient.send(
1293
+ "/v1/{contentType}",
1294
+ "get",
1295
+ { path: { contentType: this.contentType }, query: this.buildQueryParams() }
1296
+ );
1297
+ return response.body;
1298
+ }
1299
+ /**
1300
+ * Execute the query and return a single result (first match)
1301
+ */
1302
+ async first() {
1303
+ const originalLimit = this.queryOptions.limit;
1304
+ this.limit(1);
1305
+ try {
1306
+ const results = await this.execute();
1307
+ return results.length > 0 ? results[0] ?? null : null;
1308
+ } finally {
1309
+ if (originalLimit !== void 0) {
1310
+ this.queryOptions.limit = originalLimit;
1311
+ } else {
1312
+ delete this.queryOptions.limit;
1313
+ }
1314
+ }
1315
+ }
1316
+ /**
1317
+ * Get paginated results
1318
+ */
1319
+ async paginate(limit = 20) {
1320
+ return this.limit(limit).executeWithMeta();
1321
+ }
1322
+ /**
1323
+ * Create an async iterator for streaming results
1324
+ */
1325
+ async *[Symbol.asyncIterator]() {
1326
+ const limit = this.queryOptions.limit ?? 100;
1327
+ let cursor;
1328
+ let hasMore = true;
1329
+ while (hasMore) {
1330
+ if (cursor != null && cursor !== "") {
1331
+ this.cursor(cursor);
1332
+ }
1333
+ const result = await this.limit(limit).executeWithMeta();
1334
+ for (const item of readPayload(result)) {
1335
+ yield item;
1336
+ }
1337
+ hasMore = result.page.hasMore;
1338
+ cursor = result.page.nextCursor ?? void 0;
1339
+ }
1340
+ }
1341
+ /**
1342
+ * Execute the query and return all results as an array (for large datasets)
1343
+ */
1344
+ async all() {
1345
+ const allItems = [];
1346
+ for await (const item of this) {
1347
+ allItems.push(item);
1348
+ }
1349
+ return allItems;
1350
+ }
1351
+ /**
1352
+ * Clone the query builder
1353
+ */
1354
+ clone() {
1355
+ const cloned = new _ContentQueryBuilder(this.httpClient, this.contentType, this.defaultLocale);
1356
+ cloned.queryOptions = JSON.parse(JSON.stringify(this.queryOptions));
1357
+ cloned.localeValue = this.localeValue;
1358
+ cloned.localesArray = this.localesArray ? [...this.localesArray] : void 0;
1359
+ cloned.fetchAllLocales = this.fetchAllLocales;
1360
+ cloned.fieldsProjection = this.fieldsProjection ? [...this.fieldsProjection] : void 0;
1361
+ cloned.pageNumber = this.pageNumber;
1362
+ cloned.pageSizeValue = this.pageSizeValue;
1363
+ return cloned;
1364
+ }
1365
+ /**
1366
+ * Get the current query options
1367
+ */
1368
+ getQueryOptions() {
1369
+ return { ...this.queryOptions };
1370
+ }
1371
+ /**
1372
+ * Execute the query and return the whole body.
1373
+ *
1374
+ * Identical to {@link executeWithMeta} now that the list serves one shape;
1375
+ * kept as the name callers already import.
1376
+ */
1377
+ async executeWithMetaExtended() {
1378
+ return this.executeWithMeta();
1379
+ }
1380
+ /**
1381
+ * `count()` and `exists()` are gone, and their absence is the honest answer
1382
+ * rather than an omission (`INV-RD-CAPABILITY-IS-HONEST`).
1383
+ *
1384
+ * `count()` sent `withCount` and read `pagination.total`; API2 moved the
1385
+ * customer list onto the **cursor** dialect, whose page facts are
1386
+ * `{ nextCursor, hasMore }` and nothing else, so no total reaches this
1387
+ * surface at all. Keeping the method would have meant either a request that
1388
+ * always throws or a number assembled from a page the caller happened to
1389
+ * fetch — a count of what was returned, presented as a count of what matched
1390
+ * (rule 6). The plan's §3.3 listed `count` among six methods a type would
1391
+ * repair; what the type actually shows is that the capability is no longer
1392
+ * there. A caller that wants "is there at least one" fetches one and looks at
1393
+ * `data.length`; a caller that wants a true total uses `POST /v1/search`,
1394
+ * which is the offset dialect precisely because a facet-bearing result wants
1395
+ * one (Decision 5).
1396
+ */
1397
+ /**
1398
+ * Build query parameters for the HTTP request
1399
+ */
1400
+ buildQueryParams() {
1401
+ const params = {};
1402
+ if (this.queryOptions.where && Object.keys(this.queryOptions.where).length > 0) {
1403
+ params.filters = JSON.stringify(this.queryOptions.where);
1404
+ }
1405
+ if (this.queryOptions.select) {
1406
+ params.fields = this.queryOptions.select.join(",");
1407
+ }
1408
+ if (this.fieldsProjection) {
1409
+ params.fields = this.fieldsProjection.join(",");
1410
+ }
1411
+ if (this.queryOptions.include) {
1412
+ params.include = this.queryOptions.include.join(",");
1413
+ }
1414
+ if (this.queryOptions.sort) {
1415
+ const sortArray = Object.entries(this.queryOptions.sort).map(
1416
+ ([field, direction]) => `${field}:${direction}`
1417
+ );
1418
+ params.sort = sortArray.join(",");
1419
+ }
1420
+ if (this.queryOptions.limit !== void 0) {
1421
+ params.limit = this.queryOptions.limit;
1422
+ }
1423
+ if (this.queryOptions.offset !== void 0) {
1424
+ params.offset = this.queryOptions.offset;
1425
+ }
1426
+ if (this.queryOptions.cursor !== void 0) {
1427
+ params.cursor = this.queryOptions.cursor;
1428
+ }
1429
+ if (this.localeValue != null && this.localeValue !== "") {
1430
+ params.locale = this.localeValue;
1431
+ } else if (this.fetchAllLocales) {
1432
+ params.locale = "*";
1433
+ } else if (this.localesArray && this.localesArray.length > 0) {
1434
+ params.locales = this.localesArray.join(",");
1435
+ } else if (this.defaultLocale != null && this.defaultLocale !== "") {
1436
+ params.locale = this.defaultLocale;
1437
+ }
1438
+ if (this.pageNumber !== void 0) {
1439
+ params.page = this.pageNumber;
1440
+ }
1441
+ if (this.pageSizeValue !== void 0) {
1442
+ params.pageSize = this.pageSizeValue;
1443
+ }
1444
+ if (this.childrenOptions) {
1445
+ if (this.childrenOptions.contentTypes) {
1446
+ params.children = this.childrenOptions.contentTypes.join(",");
1447
+ } else {
1448
+ params.children = "true";
1449
+ }
1450
+ if (this.childrenOptions.limit !== void 0) {
1451
+ params.childrenLimit = this.childrenOptions.limit;
1452
+ }
1453
+ }
1454
+ return params;
1455
+ }
1456
+ };
1457
+ __name(_ContentQueryBuilder, "ContentQueryBuilder");
1458
+ var ContentQueryBuilder = _ContentQueryBuilder;
1459
+ var _ContentByIdBuilder = class _ContentByIdBuilder {
1460
+ constructor(httpClient, contentType, id, defaultLocale) {
1461
+ this.httpClient = httpClient;
1462
+ this.contentType = contentType;
1463
+ this.id = id;
1464
+ this.defaultLocale = defaultLocale;
1465
+ __publicField(this, "includeRelations");
1466
+ __publicField(this, "localeValue");
1467
+ __publicField(this, "localesArray");
1468
+ __publicField(this, "fetchAllLocales", false);
1469
+ __publicField(this, "childrenOptions");
1470
+ }
1471
+ /**
1472
+ * Include related content in the response
1473
+ */
1474
+ include(relations) {
1475
+ this.includeRelations = relations;
1476
+ return this;
1477
+ }
1478
+ /**
1479
+ * Set locale for localized content
1480
+ * @param locale - Locale code (e.g., 'en-US', 'de-DE', 'fr-FR')
1481
+ */
1482
+ locale(locale) {
1483
+ this.localeValue = locale;
1484
+ this.localesArray = void 0;
1485
+ this.fetchAllLocales = false;
1486
+ return this;
1487
+ }
1488
+ /**
1489
+ * Fetch content in multiple specific locales
1490
+ * Returns primary locale at top level, others in _metadata.localizations
1491
+ *
1492
+ * @param localeCodes - Array of locale codes to fetch
1493
+ */
1494
+ locales(localeCodes) {
1495
+ this.localesArray = localeCodes;
1496
+ this.localeValue = void 0;
1497
+ this.fetchAllLocales = false;
1498
+ return this;
1499
+ }
1500
+ /**
1501
+ * Fetch content in all available locales
1502
+ * Returns default locale at top level, others in _metadata.localizations
1503
+ */
1504
+ allLocales() {
1505
+ this.fetchAllLocales = true;
1506
+ this.localeValue = void 0;
1507
+ this.localesArray = void 0;
1508
+ return this;
1509
+ }
1510
+ /**
1511
+ * Include children in results (for hierarchical content)
1512
+ * @param options - Children options or boolean to enable with defaults
1513
+ */
1514
+ children(options) {
1515
+ if (typeof options === "boolean") {
1516
+ this.childrenOptions = options ? {} : void 0;
1517
+ } else {
1518
+ this.childrenOptions = options;
1519
+ }
1520
+ return this;
1521
+ }
1522
+ /**
1523
+ * Execute the query and return the content item
1524
+ */
1525
+ async execute() {
1526
+ const params = {};
1527
+ if (this.includeRelations != null) {
1528
+ params.include = this.includeRelations.join(",");
1529
+ }
1530
+ if (this.localeValue != null && this.localeValue !== "") {
1531
+ params.locale = this.localeValue;
1532
+ } else if (this.fetchAllLocales) {
1533
+ params.locale = "*";
1534
+ } else if (this.localesArray && this.localesArray.length > 0) {
1535
+ params.locales = this.localesArray.join(",");
1536
+ } else if (this.defaultLocale != null && this.defaultLocale !== "") {
1537
+ params.locale = this.defaultLocale;
1538
+ }
1539
+ if (this.childrenOptions != null) {
1540
+ if (this.childrenOptions.contentTypes) {
1541
+ params.children = this.childrenOptions.contentTypes.join(",");
1542
+ } else {
1543
+ params.children = "true";
1544
+ }
1545
+ if (this.childrenOptions.limit !== void 0) {
1546
+ params.childrenLimit = this.childrenOptions.limit;
1547
+ }
1548
+ }
1549
+ try {
1550
+ return await this.httpClient.fetchPayload(
1551
+ "/v1/{contentType}/{id}",
1552
+ "get",
1553
+ { path: { contentType: this.contentType, id: this.id }, query: params }
1554
+ );
1555
+ } catch (error) {
1556
+ if (isResourceNotFound(error)) return null;
1557
+ throw error;
1558
+ }
1559
+ }
1560
+ };
1561
+ __name(_ContentByIdBuilder, "ContentByIdBuilder");
1562
+ var ContentByIdBuilder = _ContentByIdBuilder;
1563
+
1564
+ // ../../platform/api-contract/dist/index.js
1565
+ var HEADER_ENTITY_TAG = { name: "X-Entity-Tag" };
1566
+ var HEADER_IF_MATCH = {
1567
+ name: "If-Match"};
1568
+ var HEADER_IDEMPOTENCY_KEY = {
1569
+ name: "Idempotency-Key"};
1570
+
1571
+ // src/http/write-options.ts
1572
+ function writeHeaders(options) {
1573
+ if (options === void 0) return void 0;
1574
+ const headers = {};
1575
+ if ("ifMatch" in options && options.ifMatch !== void 0) {
1576
+ headers[HEADER_IF_MATCH.name] = options.ifMatch;
1577
+ }
1578
+ if (options.idempotencyKey !== void 0) {
1579
+ headers[HEADER_IDEMPOTENCY_KEY.name] = options.idempotencyKey;
1580
+ }
1581
+ return Object.keys(headers).length > 0 ? headers : void 0;
1582
+ }
1583
+ __name(writeHeaders, "writeHeaders");
1584
+ function entityTagOf(response) {
1585
+ const wanted = HEADER_ENTITY_TAG.name.toLowerCase();
1586
+ for (const [name, value] of Object.entries(response.headers)) {
1587
+ if (name.toLowerCase() === wanted) return value;
1588
+ }
1589
+ return void 0;
1590
+ }
1591
+ __name(entityTagOf, "entityTagOf");
1592
+
1593
+ // src/content/content-client.ts
1594
+ var _ContentClient = class _ContentClient {
1595
+ constructor(httpClient, contentType, defaultLocale) {
1596
+ this.httpClient = httpClient;
1597
+ this.contentType = contentType;
1598
+ this.defaultLocale = defaultLocale;
1599
+ }
1600
+ /**
1601
+ * Create a new query builder for this content type
1602
+ */
1603
+ query() {
1604
+ return new ContentQueryBuilder(this.httpClient, this.contentType, this.defaultLocale);
1605
+ }
1606
+ /**
1607
+ * Find content by ID with fluent options
1608
+ */
1609
+ findById(id) {
1610
+ return new ContentByIdBuilder(this.httpClient, this.contentType, id, this.defaultLocale);
1611
+ }
1612
+ /**
1613
+ * Fetch all content items
1614
+ * @param locale - Optional locale for localized content
1615
+ */
1616
+ async fetchAll(locale) {
1617
+ const builder = this.query();
1618
+ if (locale != null && locale !== "") {
1619
+ builder.locale(locale);
1620
+ }
1621
+ return builder.execute();
1622
+ }
1623
+ /**
1624
+ * Fetch content with query options
1625
+ */
1626
+ async fetch(options) {
1627
+ const builder = this.query();
1628
+ if (options?.where) {
1629
+ builder.where(options.where);
1630
+ }
1631
+ if (options?.limit != null) {
1632
+ builder.limit(options.limit);
1633
+ }
1634
+ if (options?.offset != null) {
1635
+ builder.offset(options.offset);
1636
+ }
1637
+ if (options?.sort) {
1638
+ builder.sort(options.sort);
1639
+ }
1640
+ if (options?.include) {
1641
+ builder.include(options.include);
1642
+ }
1643
+ if (options?.locale != null && options.locale !== "") {
1644
+ builder.locale(options.locale);
1645
+ }
1646
+ if (options?.fields != null) {
1647
+ builder.fields(options.fields);
1648
+ }
1649
+ if (options?.children != null) {
1650
+ builder.children(options.children);
1651
+ }
1652
+ return builder.execute();
1653
+ }
1654
+ /**
1655
+ * Fetch a single content item by ID
1656
+ * @param id - Entry ID or slug
1657
+ * @param options - Fetch options (include, locale)
1658
+ */
1659
+ async fetchOne(id, options) {
1660
+ const builder = this.findById(id);
1661
+ if (options?.include != null) {
1662
+ builder.include(options.include);
1663
+ }
1664
+ if (options?.locale != null && options.locale !== "") {
1665
+ builder.locale(options.locale);
1666
+ }
1667
+ return builder.execute();
1668
+ }
1669
+ /**
1670
+ * Fetch one entry **and the entity tag that read served**.
1671
+ *
1672
+ * This is the read half of a conditional write. `X-Entity-Tag` is minted from
1673
+ * `(entryUid, locale, localeVersion)` and is exactly what `If-Match` takes,
1674
+ * so a caller reads here, edits, and hands the same string back to `update`
1675
+ * — with nothing to assemble in between
1676
+ * (`INV-API-CONDITIONAL-WRITE-IS-REACHABLE`).
1677
+ *
1678
+ * `entityTag` is `undefined` when the response came from the cache: a cached
1679
+ * body cannot know the current version, and an absent tag beats a stale one
1680
+ * that would refuse the next write.
1681
+ */
1682
+ async fetchOneWithTag(id, options) {
1683
+ const query = {};
1684
+ if (options?.include != null) query.include = options.include.join(",");
1685
+ const locale = options?.locale ?? this.defaultLocale;
1686
+ if (locale != null && locale !== "") query.locale = locale;
1687
+ const response = await this.httpClient.send(
1688
+ "/v1/{contentType}/{id}",
1689
+ "get",
1690
+ { path: { contentType: this.contentType, id }, query }
1691
+ );
1692
+ return { entry: readPayload(response.body), entityTag: entityTagOf(response) };
1693
+ }
1694
+ /**
1695
+ * Fetch the first content item matching the conditions
1696
+ * @param where - Filter conditions
1697
+ * @param locale - Optional locale
1698
+ */
1699
+ async fetchFirst(where, locale) {
1700
+ const builder = this.query();
1701
+ if (where != null) {
1702
+ builder.where(where);
1703
+ }
1704
+ if (locale != null && locale !== "") {
1705
+ builder.locale(locale);
1706
+ }
1707
+ return builder.first();
1708
+ }
1709
+ /**
1710
+ * Create a new content item
1711
+ * @param data - Content data
1712
+ * @param options - Create options (slug, locale, parentId, sortOrder)
1713
+ */
1714
+ async create(data, options) {
1715
+ const { idempotencyKey, ...body } = options ?? {};
1716
+ return this.httpClient.fetchPayload(
1717
+ "/v1/{contentType}",
1718
+ "post",
1719
+ {
1720
+ path: { contentType: this.contentType },
1721
+ body: { content: data, ...body },
1722
+ headers: writeHeaders({ idempotencyKey })
1723
+ }
1724
+ );
1725
+ }
1726
+ /**
1727
+ * Update a content item by ID (partial update)
1728
+ * @param id - Entry ID
1729
+ * @param data - Fields to update
1730
+ * @param options - Update options (slug, locale, parentId, sortOrder)
1731
+ */
1732
+ async update(id, data, options) {
1733
+ const { idempotencyKey, ifMatch, ...body } = options ?? {};
1734
+ return this.httpClient.fetchPayload(
1735
+ "/v1/{contentType}/{id}",
1736
+ "patch",
1737
+ {
1738
+ path: { contentType: this.contentType, id },
1739
+ body: { content: data, ...body },
1740
+ headers: writeHeaders({ idempotencyKey, ifMatch })
1741
+ }
1742
+ );
1743
+ }
1744
+ /**
1745
+ * Delete a content item by ID
1746
+ */
1747
+ async delete(id, options) {
1748
+ await this.httpClient.send("/v1/{contentType}/{id}", "delete", {
1749
+ path: { contentType: this.contentType, id },
1750
+ headers: writeHeaders(options)
1751
+ });
1752
+ }
1753
+ /**
1754
+ * Check if content exists by ID
1755
+ */
1756
+ async exists(id) {
1757
+ try {
1758
+ const item = await this.fetchOne(id);
1759
+ return item !== null;
1760
+ } catch (error) {
1761
+ if (error instanceof ResourceNotFoundError) {
1762
+ return false;
1763
+ }
1764
+ throw error;
1765
+ }
1766
+ }
1767
+ /**
1768
+ * Get version history for one locale of an entry.
1769
+ *
1770
+ * Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
1771
+ * schema default, no fallback is applied, and a locale with no history returns an empty array
1772
+ * rather than another locale's rows. Every row names the locale it belongs to.
1773
+ */
1774
+ async versions(id, options) {
1775
+ return this.httpClient.fetchPayload("/v1/{contentType}/{id}/versions", "get", {
1776
+ path: { contentType: this.contentType, id },
1777
+ query: {
1778
+ limit: options?.limit ?? 10,
1779
+ ...options?.locale === void 0 ? {} : { locale: options.locale }
1780
+ }
1781
+ });
1782
+ }
1783
+ /**
1784
+ * Get a specific version of an entry.
1785
+ *
1786
+ * `locale` defaults to the schema default. Version numbers are per locale, so version 2 is
1787
+ * different content in each one.
1788
+ */
1789
+ async version(id, versionNumber, options) {
1790
+ return this.httpClient.fetchPayload("/v1/{contentType}/{id}/versions/{versionNumber}", "get", {
1791
+ path: {
1792
+ contentType: this.contentType,
1793
+ id,
1794
+ versionNumber: String(versionNumber)
1795
+ },
1796
+ query: options?.locale === void 0 ? void 0 : { locale: options.locale }
1797
+ });
1798
+ }
1799
+ /**
1800
+ * Revert one locale of an entry to a previous version.
1801
+ *
1802
+ * `locale` is **required**, and that is not a convention: versions are numbered per locale, so
1803
+ * `versionNumber` alone is ambiguous, and defaulting it would silently revert the wrong
1804
+ * translation. Only that locale's fields change — shared fields and every other locale are left
1805
+ * untouched.
1806
+ *
1807
+ * The restore is validated as strictly as a publish, so it cannot publish invalid content, and it
1808
+ * records a new version of its own rather than rewinding the counter — so the revert is auditable
1809
+ * and itself reversible.
1810
+ */
1811
+ async restore(id, versionNumber, locale, options) {
1812
+ return this.httpClient.fetchPayload("/v1/{contentType}/{id}/versions/{versionNumber}/restore", "post", {
1813
+ path: {
1814
+ contentType: this.contentType,
1815
+ id,
1816
+ versionNumber: String(versionNumber)
1817
+ },
1818
+ body: { locale },
1819
+ headers: writeHeaders(options)
1820
+ });
1821
+ }
1822
+ /**
1823
+ * Get children of a hierarchical entry
1824
+ * @param id - Parent entry ID
1825
+ * @param options - Fetch options
1826
+ */
1827
+ async children(id, options) {
1828
+ const params = {};
1829
+ if (options?.depth != null) {
1830
+ params.depth = options.depth;
1831
+ }
1832
+ if (options?.include != null) {
1833
+ params.include = options.include.join(",");
1834
+ }
1835
+ if (options?.locale != null && options.locale !== "") {
1836
+ params.locale = options.locale;
1837
+ }
1838
+ return this.httpClient.fetchPayload(
1839
+ "/v1/{contentType}/{id}/children",
1840
+ "get",
1841
+ { path: { contentType: this.contentType, id }, query: params }
1842
+ );
1843
+ }
1844
+ /**
1845
+ * Get the content type name
1846
+ */
1847
+ getContentType() {
1848
+ return this.contentType;
1849
+ }
1850
+ /**
1851
+ * Create a new ContentClient for a different content type
1852
+ */
1853
+ ofType(contentType) {
1854
+ return new _ContentClient(this.httpClient, contentType, this.defaultLocale);
1855
+ }
1856
+ /**
1857
+ * Create a new ContentClient with a different default locale
1858
+ */
1859
+ withLocale(locale) {
1860
+ return new _ContentClient(this.httpClient, this.contentType, locale);
1861
+ }
1862
+ /**
1863
+ * Get the current default locale
1864
+ */
1865
+ getDefaultLocale() {
1866
+ return this.defaultLocale;
1867
+ }
1868
+ };
1869
+ __name(_ContentClient, "ContentClient");
1870
+ var ContentClient = _ContentClient;
1871
+
1872
+ // src/errors/file-errors.ts
1873
+ var _FileUploadError = class _FileUploadError extends SDKError {
1874
+ constructor(code, message, options = {}) {
1875
+ super(message, options.statusCode, options.cause, { fileErrorCode: code });
1876
+ __publicField(this, "code");
1877
+ __publicField(this, "retryable");
1878
+ this.code = code;
1879
+ this.retryable = options.retriable ?? false;
1880
+ }
1881
+ getUserMessage() {
1882
+ return this.message;
1883
+ }
1884
+ };
1885
+ __name(_FileUploadError, "FileUploadError");
1886
+ var FileUploadError = _FileUploadError;
1887
+ var _FileValidationError = class _FileValidationError extends BaseValidationError {
1888
+ constructor(message, violations = [], cause) {
1889
+ super(message, violations, 400, cause);
1890
+ __publicField(this, "code", "FILE_VALIDATION_ERROR");
1891
+ }
1892
+ getUserMessage() {
1893
+ if (this.violations.length === 1) return this.violations[0]?.message ?? this.message;
1894
+ return this.message;
1895
+ }
1896
+ };
1897
+ __name(_FileValidationError, "FileValidationError");
1898
+ var FileValidationError = _FileValidationError;
1899
+ function validateFile(file, constraints = {}) {
1900
+ const violations = [];
1901
+ const { allowedMimeTypes, maxSizeBytes } = constraints;
1902
+ if (allowedMimeTypes && allowedMimeTypes.length > 0 && file.type != null && file.type !== "" && !allowedMimeTypes.includes(file.type)) {
1903
+ violations.push({
1904
+ field: "file",
1905
+ code: "UNSUPPORTED_MIME",
1906
+ message: `Unsupported file type "${file.type}". Allowed: ${allowedMimeTypes.join(", ")}`,
1907
+ value: file.type
1908
+ });
1909
+ }
1910
+ if (typeof maxSizeBytes === "number" && maxSizeBytes > 0 && typeof file.size === "number" && file.size > maxSizeBytes) {
1911
+ violations.push({
1912
+ field: "file",
1913
+ code: "UPLOAD_TOO_LARGE",
1914
+ message: `File is too large (${file.size} bytes); max is ${maxSizeBytes} bytes`,
1915
+ value: file.size
1916
+ });
1917
+ }
1918
+ return violations;
1919
+ }
1920
+ __name(validateFile, "validateFile");
1921
+
1922
+ // src/content/asset-client.ts
1923
+ function hasText(value) {
1924
+ return value != null && value !== "";
1925
+ }
1926
+ __name(hasText, "hasText");
1927
+ async function computeSha256Hex(blob) {
1928
+ try {
1929
+ const subtle = globalThis.crypto?.subtle;
1930
+ if (subtle === void 0 || typeof blob.arrayBuffer !== "function") return void 0;
1931
+ const digest = await subtle.digest("SHA-256", await blob.arrayBuffer());
1932
+ const bytes = new Uint8Array(digest);
1933
+ let hex = "";
1934
+ for (const byte of bytes) hex += byte.toString(16).padStart(2, "0");
1935
+ return hex;
1936
+ } catch {
1937
+ return void 0;
1938
+ }
1939
+ }
1940
+ __name(computeSha256Hex, "computeSha256Hex");
1941
+ var _AssetFileBuilder = class _AssetFileBuilder {
1942
+ constructor(httpClient, assetType, entryUid, defaultLocale) {
1943
+ this.httpClient = httpClient;
1944
+ this.assetType = assetType;
1945
+ this.entryUid = entryUid;
1946
+ this.defaultLocale = defaultLocale;
1947
+ }
1948
+ /**
1949
+ * The path parameters every `/file/*` route on this builder takes.
1950
+ *
1951
+ * The path *template* is the document's; only these two values are the
1952
+ * builder's, so a route that gains or loses a segment is a compile error here
1953
+ * rather than a hand-built string that silently misses.
1954
+ */
1955
+ get target() {
1956
+ return { contentType: this.assetType, id: this.entryUid };
1957
+ }
1958
+ withLocale(locale) {
1959
+ return locale ?? this.defaultLocale;
1960
+ }
1961
+ /**
1962
+ * Issue a single upload target — an R2 presigned PUT (image/file) or a
1963
+ * Cloudflare Stream direct-creator URL (video). Resumable multipart is plan 17.
1964
+ */
1965
+ async presign(input) {
1966
+ const locale = this.withLocale(input.locale);
1967
+ return this.httpClient.fetchPayload("/v1/{contentType}/{id}/file/presign", "post", {
1968
+ path: this.target,
1969
+ body: {
1970
+ fileName: input.fileName,
1971
+ ...hasText(input.contentType) ? { contentType: input.contentType } : {},
1972
+ ...input.size != null ? { size: input.size } : {},
1973
+ ...hasText(locale) ? { locale } : {},
1974
+ ...hasText(input.hash) ? { hash: input.hash } : {}
1975
+ }
1976
+ });
1977
+ }
1978
+ /**
1979
+ * Acknowledge a completed client upload (kicks off the fast-path intake for
1980
+ * R2; a no-op for Stream, whose readiness is webhook-driven).
1981
+ */
1982
+ async confirm(input = {}) {
1983
+ const locale = this.withLocale(input.locale);
1984
+ return this.httpClient.fetchPayload("/v1/{contentType}/{id}/file/confirm", "post", {
1985
+ path: this.target,
1986
+ body: {
1987
+ ...hasText(locale) ? { locale } : {},
1988
+ ...hasText(input.hash) ? { hash: input.hash } : {}
1989
+ }
1990
+ });
1991
+ }
1992
+ // ──────────────────────────────────────────────────────────────────────────
1993
+ // MULTIPART (resumable large-file uploads) — same 5-call protocol the
1994
+ // Studio Uppy path uses. No Uppy dependency in the SDK.
1995
+ // ──────────────────────────────────────────────────────────────────────────
1996
+ /** Open an R2 multipart session for a large file (standalone of `presign`). */
1997
+ async createMultipart(input) {
1998
+ const locale = this.withLocale(input.locale);
1999
+ return this.httpClient.fetchPayload("/v1/{contentType}/{id}/file/multipart/create", "post", {
2000
+ path: this.target,
2001
+ body: {
2002
+ fileName: input.fileName,
2003
+ ...hasText(input.contentType) ? { contentType: input.contentType } : {},
2004
+ ...input.size != null ? { size: input.size } : {},
2005
+ ...hasText(locale) ? { locale } : {},
2006
+ ...hasText(input.hash) ? { hash: input.hash } : {}
2007
+ }
2008
+ });
2009
+ }
2010
+ /** Presign a single part PUT (1-based `partNumber`). */
2011
+ async signPart(target) {
2012
+ return this.httpClient.fetchPayload("/v1/{contentType}/{id}/file/multipart/sign-part", "post", {
2013
+ path: this.target,
2014
+ body: {
2015
+ uploadId: target.uploadId,
2016
+ objectKey: target.objectKey,
2017
+ partNumber: target.partNumber,
2018
+ ...hasText(target.locale) ? { locale: target.locale } : {}
2019
+ }
2020
+ });
2021
+ }
2022
+ /** List parts already uploaded (cross-session resume). */
2023
+ async listParts(target) {
2024
+ const payload = await this.httpClient.fetchPayload("/v1/{contentType}/{id}/file/multipart/list-parts", "post", {
2025
+ path: this.target,
2026
+ body: {
2027
+ uploadId: target.uploadId,
2028
+ objectKey: target.objectKey,
2029
+ ...hasText(target.locale) ? { locale: target.locale } : {}
2030
+ }
2031
+ });
2032
+ return payload.parts;
2033
+ }
2034
+ /** Finalize a multipart session. */
2035
+ async completeMultipart(target) {
2036
+ return this.httpClient.fetchPayload("/v1/{contentType}/{id}/file/multipart/complete", "post", {
2037
+ path: this.target,
2038
+ body: {
2039
+ uploadId: target.uploadId,
2040
+ objectKey: target.objectKey,
2041
+ parts: target.parts.map((p) => ({ partNumber: p.partNumber, etag: p.etag })),
2042
+ ...hasText(target.locale) ? { locale: target.locale } : {}
2043
+ }
2044
+ });
2045
+ }
2046
+ /** Abort a multipart session, freeing staged parts. */
2047
+ async abortMultipart(target) {
2048
+ return this.httpClient.fetchPayload("/v1/{contentType}/{id}/file/multipart/abort", "post", {
2049
+ path: this.target,
2050
+ body: {
2051
+ uploadId: target.uploadId,
2052
+ objectKey: target.objectKey,
2053
+ ...hasText(target.locale) ? { locale: target.locale } : {}
2054
+ }
2055
+ });
2056
+ }
2057
+ /**
2058
+ * Resolve a single gateway delivery URL for the requested locale/variant/purpose.
2059
+ * Throws if the binding is not `ready`.
2060
+ */
2061
+ async url(input = {}) {
2062
+ const params = {};
2063
+ const locale = this.withLocale(input.locale);
2064
+ if (hasText(locale)) params.locale = locale;
2065
+ if (hasText(input.variantId)) params.variantId = input.variantId;
2066
+ if (input.purpose !== void 0) params.purpose = input.purpose;
2067
+ return this.httpClient.fetchPayload(
2068
+ "/v1/{contentType}/{id}/file/url",
2069
+ "get",
2070
+ { path: this.target, query: params }
2071
+ );
2072
+ }
2073
+ /**
2074
+ * Update the binding's delivery visibility (token-based; no byte relocation —
2075
+ * a downgrade purges the gateway cache). Returns the refreshed asset entry.
2076
+ */
2077
+ async updateVisibility(visibility, options = {}) {
2078
+ const locale = this.withLocale(options.locale);
2079
+ return this.httpClient.fetchPayload("/v1/{contentType}/{id}/file", "patch", {
2080
+ path: this.target,
2081
+ body: { visibility, ...hasText(locale) ? { locale } : {} }
2082
+ });
2083
+ }
2084
+ /**
2085
+ * Set the binding's normalized (0..1, origin top-left) smart-crop focal point
2086
+ * (plan 18) so `cover`/`crop` variants frame the subject. Per locale for
2087
+ * file-localized asset types; token-based (no byte change). Returns the
2088
+ * refreshed asset entry.
2089
+ */
2090
+ async setFocalPoint(focalPoint, options = {}) {
2091
+ const locale = this.withLocale(options.locale);
2092
+ return this.httpClient.fetchPayload("/v1/{contentType}/{id}/file", "patch", {
2093
+ path: this.target,
2094
+ body: { focalPoint, ...hasText(locale) ? { locale } : {} }
2095
+ });
2096
+ }
2097
+ /**
2098
+ * Remove the file binding, clean up the underlying bytes, and purge the
2099
+ * gateway cache. The asset entry itself is preserved.
2100
+ */
2101
+ async delete(options = {}) {
2102
+ const params = {};
2103
+ const locale = this.withLocale(options.locale);
2104
+ if (hasText(locale)) params.locale = locale;
2105
+ await this.httpClient.send("/v1/{contentType}/{id}/file", "delete", {
2106
+ path: this.target,
2107
+ query: params
2108
+ });
2109
+ }
2110
+ /**
2111
+ * Poll the asset entry until its file binding reaches `ready` (resolves with
2112
+ * the ready entry) or `failed` (throws). Times out after `timeoutMs`.
2113
+ */
2114
+ async waitUntilReady(options = {}) {
2115
+ const timeoutMs = options.timeoutMs ?? 6e4;
2116
+ const pollIntervalMs = options.pollIntervalMs ?? 1500;
2117
+ const locale = this.withLocale(options.locale);
2118
+ const deadline = Date.now() + timeoutMs;
2119
+ for (; ; ) {
2120
+ const builder = new ContentByIdBuilder(
2121
+ this.httpClient,
2122
+ this.assetType,
2123
+ this.entryUid,
2124
+ locale
2125
+ );
2126
+ if (hasText(locale)) builder.locale(locale);
2127
+ const entry = await builder.execute();
2128
+ const status = entry?.file?.status;
2129
+ if (entry && status === "ready") return entry;
2130
+ if (status === "failed") {
2131
+ const message = entry?.file?.processing?.error?.message ?? "File processing failed";
2132
+ throw new Error(`Asset ${this.assetType}/${this.entryUid}: ${message}`);
2133
+ }
2134
+ if (Date.now() >= deadline) {
2135
+ throw new Error(
2136
+ `Timed out after ${timeoutMs}ms waiting for ${this.assetType}/${this.entryUid} (status: ${status ?? "unknown"})`
2137
+ );
2138
+ }
2139
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
2140
+ }
2141
+ }
2142
+ };
2143
+ __name(_AssetFileBuilder, "AssetFileBuilder");
2144
+ var AssetFileBuilder = _AssetFileBuilder;
2145
+ var _AssetUploadBuilder = class _AssetUploadBuilder {
2146
+ constructor(httpClient, assetType, file, defaultLocale) {
2147
+ this.httpClient = httpClient;
2148
+ this.assetType = assetType;
2149
+ this.file = file;
2150
+ this.defaultLocale = defaultLocale;
2151
+ __publicField(this, "_fileName");
2152
+ __publicField(this, "_visibility");
2153
+ __publicField(this, "_locale");
2154
+ __publicField(this, "_publish");
2155
+ __publicField(this, "_content", {});
2156
+ __publicField(this, "_slug");
2157
+ __publicField(this, "_waitForReady", false);
2158
+ __publicField(this, "_waitOptions", {});
2159
+ __publicField(this, "_onProgress");
2160
+ __publicField(this, "_validate");
2161
+ __publicField(this, "_maxPartRetries", 3);
2162
+ }
2163
+ /** Subscribe to client → storage upload progress (single PUT + multipart). */
2164
+ onProgress(callback) {
2165
+ this._onProgress = callback;
2166
+ return this;
2167
+ }
2168
+ /**
2169
+ * Validate the file client-side (UX only) against explicit constraints before
2170
+ * any bytes leave the machine. Rejects instantly with a {@link FileValidationError}.
2171
+ */
2172
+ validate(constraints) {
2173
+ this._validate = constraints;
2174
+ return this;
2175
+ }
2176
+ /** Bounded per-part retry attempts for multipart (default 3). */
2177
+ maxPartRetries(attempts) {
2178
+ this._maxPartRetries = Math.max(0, attempts);
2179
+ return this;
2180
+ }
2181
+ /** Set the original file name (defaults to `file.name` for `File` inputs). */
2182
+ filename(name) {
2183
+ this._fileName = name;
2184
+ return this;
2185
+ }
2186
+ /** Set the initial delivery visibility (default `public`). */
2187
+ visibility(visibility) {
2188
+ this._visibility = visibility;
2189
+ return this;
2190
+ }
2191
+ /** Target locale for file-localized asset types. */
2192
+ locale(locale) {
2193
+ this._locale = locale;
2194
+ return this;
2195
+ }
2196
+ /** Suppress (or enable) auto-publish on ready. */
2197
+ publish(publish) {
2198
+ this._publish = publish;
2199
+ return this;
2200
+ }
2201
+ /** Set the asset's metadata field values (e.g. `{ alt: '...' }`). */
2202
+ content(content) {
2203
+ this._content = content;
2204
+ return this;
2205
+ }
2206
+ /** Set an explicit slug for the new entry. */
2207
+ slug(slug) {
2208
+ this._slug = slug;
2209
+ return this;
2210
+ }
2211
+ /** Wait until the file binding becomes `ready` before resolving. */
2212
+ waitForReady(options = true) {
2213
+ if (options === false) {
2214
+ this._waitForReady = false;
2215
+ } else {
2216
+ this._waitForReady = true;
2217
+ if (typeof options === "object") this._waitOptions = options;
2218
+ }
2219
+ return this;
2220
+ }
2221
+ /** Execute the full upload flow and resolve with the asset entry. */
2222
+ async execute() {
2223
+ const fileName = this._fileName ?? this.file.name;
2224
+ if (!fileName) {
2225
+ throw new Error('A file name is required: pass a File, or call .filename("name.ext")');
2226
+ }
2227
+ const locale = this._locale ?? this.defaultLocale;
2228
+ if (this._validate) {
2229
+ const violations = validateFile(this.file, this._validate);
2230
+ if (violations.length > 0) {
2231
+ throw new FileValidationError(
2232
+ `File validation failed: ${violations.map((v) => v.message).join("; ")}`,
2233
+ violations
2234
+ );
2235
+ }
2236
+ }
2237
+ const hash = await computeSha256Hex(this.file);
2238
+ const client = new AssetClient(this.httpClient, this.assetType, this.defaultLocale);
2239
+ const created = await client.create(this._content, {
2240
+ ...hasText(this._slug) ? { slug: this._slug } : {},
2241
+ ...hasText(locale) ? { locale } : {},
2242
+ fileName,
2243
+ ...this._visibility !== void 0 ? { visibility: this._visibility } : {},
2244
+ ...this._publish != null ? { publish: this._publish } : {}
2245
+ });
2246
+ const entryUid = created._metadata.id;
2247
+ const fileBuilder = client.file(entryUid);
2248
+ const presigned = await fileBuilder.presign({
2249
+ fileName,
2250
+ ...hasText(this.file.type) ? { contentType: this.file.type } : {},
2251
+ ...this.file.size > 0 ? { size: this.file.size } : {},
2252
+ ...hasText(locale) ? { locale } : {},
2253
+ ...hasText(hash) ? { hash } : {}
2254
+ });
2255
+ if (presigned.mode === "multipart") {
2256
+ await this.uploadMultipart(fileBuilder, presigned, entryUid, locale);
2257
+ } else {
2258
+ await this.uploadSingle(presigned, entryUid);
2259
+ }
2260
+ await fileBuilder.confirm({
2261
+ ...hasText(locale) ? { locale } : {},
2262
+ ...hasText(hash) ? { hash } : {}
2263
+ });
2264
+ if (this._waitForReady) {
2265
+ return fileBuilder.waitUntilReady({
2266
+ ...this._waitOptions,
2267
+ ...hasText(locale) ? { locale } : {}
2268
+ });
2269
+ }
2270
+ return created;
2271
+ }
2272
+ /** Single presigned PUT (≤ 50 MB / Stream POST). */
2273
+ async uploadSingle(presigned, entryUid) {
2274
+ if (!hasText(presigned.uploadUrl)) {
2275
+ throw new FileUploadError("INTERNAL", "Presign did not return an upload URL", {});
2276
+ }
2277
+ const total = this.file.size;
2278
+ this.emitProgress(0, total);
2279
+ const uploadResponse = await fetch(presigned.uploadUrl, {
2280
+ method: presigned.method,
2281
+ headers: presigned.headers,
2282
+ body: this.file
2283
+ });
2284
+ if (!uploadResponse.ok) {
2285
+ throw new FileUploadError(
2286
+ "INTERNAL",
2287
+ `Upload failed (${uploadResponse.status} ${uploadResponse.statusText}) for ${this.assetType}/${entryUid}`,
2288
+ { retriable: uploadResponse.status >= 500, statusCode: uploadResponse.status }
2289
+ );
2290
+ }
2291
+ this.emitProgress(total, total);
2292
+ }
2293
+ /**
2294
+ * Resumable R2 multipart: slice into `partSize` chunks, skip already-uploaded
2295
+ * parts (resume via `list-parts`), PUT each remaining part with bounded retry,
2296
+ * then `complete`. Aborts the session on unrecoverable failure.
2297
+ */
2298
+ async uploadMultipart(fileBuilder, presigned, entryUid, locale) {
2299
+ const { uploadId, objectKey, partSize } = presigned;
2300
+ if (!hasText(uploadId) || !hasText(objectKey) || partSize == null || partSize <= 0) {
2301
+ throw new FileUploadError("INTERNAL", "Incomplete multipart session from presign", {});
2302
+ }
2303
+ const target = { uploadId, objectKey, ...hasText(locale) ? { locale } : {} };
2304
+ const total = this.file.size;
2305
+ const partCount = Math.max(1, Math.ceil(total / partSize));
2306
+ const existing = /* @__PURE__ */ new Map();
2307
+ try {
2308
+ for (const part of await fileBuilder.listParts(target)) existing.set(part.partNumber, part);
2309
+ } catch {
2310
+ }
2311
+ const parts = [];
2312
+ let uploaded = [...existing.values()].reduce((sum, p) => sum + (p.size ?? 0), 0);
2313
+ this.emitProgress(uploaded, total);
2314
+ try {
2315
+ for (let partNumber = 1; partNumber <= partCount; partNumber += 1) {
2316
+ const already = existing.get(partNumber);
2317
+ if (already) {
2318
+ parts.push(already);
2319
+ continue;
2320
+ }
2321
+ const start = (partNumber - 1) * partSize;
2322
+ const blob = this.file.slice(start, Math.min(start + partSize, total));
2323
+ const etag = await this.putPartWithRetry(fileBuilder, target, partNumber, blob);
2324
+ parts.push({ partNumber, etag, size: blob.size });
2325
+ uploaded += blob.size;
2326
+ this.emitProgress(uploaded, total);
2327
+ }
2328
+ await fileBuilder.completeMultipart({ ...target, parts });
2329
+ } catch (error) {
2330
+ await fileBuilder.abortMultipart(target).catch(() => {
2331
+ });
2332
+ if (error instanceof FileUploadError) throw error;
2333
+ throw new FileUploadError(
2334
+ "INTERNAL",
2335
+ `Multipart upload failed for ${this.assetType}/${entryUid}: ${error instanceof Error ? error.message : String(error)}`,
2336
+ { retriable: true, cause: error instanceof Error ? error : void 0 }
2337
+ );
2338
+ }
2339
+ }
2340
+ /** PUT a single part, retrying transient failures up to `_maxPartRetries`. */
2341
+ async putPartWithRetry(fileBuilder, target, partNumber, blob) {
2342
+ let lastError;
2343
+ for (let attempt = 0; attempt <= this._maxPartRetries; attempt += 1) {
2344
+ try {
2345
+ const { url } = await fileBuilder.signPart({ ...target, partNumber });
2346
+ const response = await fetch(url, { method: "PUT", body: blob });
2347
+ if (!response.ok) {
2348
+ const retriable = response.status >= 500 || response.status === 408 || response.status === 429;
2349
+ if (!retriable) {
2350
+ throw new FileUploadError(
2351
+ "INTERNAL",
2352
+ `Part ${partNumber} upload failed (${response.status} ${response.statusText})`,
2353
+ { statusCode: response.status }
2354
+ );
2355
+ }
2356
+ lastError = new Error(`part ${partNumber} -> ${response.status}`);
2357
+ } else {
2358
+ const etag = response.headers.get("etag") ?? response.headers.get("ETag");
2359
+ if (etag == null || etag === "") {
2360
+ throw new FileUploadError(
2361
+ "INTERNAL",
2362
+ `Part ${partNumber} response is missing an ETag header`,
2363
+ {}
2364
+ );
2365
+ }
2366
+ return etag;
2367
+ }
2368
+ } catch (error) {
2369
+ if (error instanceof FileUploadError && !error.retryable) throw error;
2370
+ lastError = error;
2371
+ }
2372
+ if (attempt < this._maxPartRetries) await new Promise((r) => setTimeout(r, 200 * 2 ** attempt));
2373
+ }
2374
+ throw new FileUploadError(
2375
+ "INTERNAL",
2376
+ `Part ${partNumber} failed after ${this._maxPartRetries + 1} attempts: ${lastError instanceof Error ? lastError.message : String(lastError)}`,
2377
+ { retriable: true, cause: lastError instanceof Error ? lastError : void 0 }
2378
+ );
2379
+ }
2380
+ emitProgress(loaded, total) {
2381
+ if (!this._onProgress) return;
2382
+ const progress = total > 0 ? Math.max(0, Math.min(100, Math.round(loaded / total * 100))) : 0;
2383
+ this._onProgress({ phase: "upload", loaded, total, progress });
2384
+ }
2385
+ };
2386
+ __name(_AssetUploadBuilder, "AssetUploadBuilder");
2387
+ var AssetUploadBuilder = _AssetUploadBuilder;
2388
+ var _AssetClient = class _AssetClient {
2389
+ constructor(httpClient, assetType, defaultLocale) {
2390
+ this.httpClient = httpClient;
2391
+ this.assetType = assetType;
2392
+ this.defaultLocale = defaultLocale;
2393
+ }
2394
+ /** Create a query builder for this asset type. */
2395
+ query() {
2396
+ return new ContentQueryBuilder(
2397
+ this.httpClient,
2398
+ this.assetType,
2399
+ this.defaultLocale
2400
+ );
2401
+ }
2402
+ /** Find an asset entry by id (or slug) with fluent options. */
2403
+ findById(id) {
2404
+ return new ContentByIdBuilder(
2405
+ this.httpClient,
2406
+ this.assetType,
2407
+ id,
2408
+ this.defaultLocale
2409
+ );
2410
+ }
2411
+ /** Fetch a single asset entry by id (or slug), or `null` if not found. */
2412
+ async fetchOne(id, options) {
2413
+ const builder = this.findById(id);
2414
+ if (options?.include != null) builder.include(options.include);
2415
+ if (options?.locale != null && options.locale !== "") builder.locale(options.locale);
2416
+ return builder.execute();
2417
+ }
2418
+ /** Fetch the first asset entry matching the conditions, or `null`. */
2419
+ async fetchFirst(where, locale) {
2420
+ const builder = this.query();
2421
+ if (where != null) builder.where(where);
2422
+ if (locale != null && locale !== "") builder.locale(locale);
2423
+ return builder.first();
2424
+ }
2425
+ /**
2426
+ * Create a new asset entry as a draft. The binary is uploaded separately via
2427
+ * `file(uid)` (or use the high-level `upload()` helper), and the entry
2428
+ * auto-publishes when its file becomes ready (unless `publish: false`).
2429
+ */
2430
+ async create(data, options) {
2431
+ const { idempotencyKey, ...rest } = options ?? {};
2432
+ return this.httpClient.fetchPayload(
2433
+ "/v1/{contentType}",
2434
+ "post",
2435
+ {
2436
+ path: { contentType: this.assetType },
2437
+ body: { content: data, ...rest },
2438
+ headers: writeHeaders({ idempotencyKey })
2439
+ }
2440
+ );
2441
+ }
2442
+ /** Update an asset entry's metadata fields (and/or slug). */
2443
+ async update(id, data, options) {
2444
+ const { idempotencyKey, ifMatch, ...rest } = options ?? {};
2445
+ return this.httpClient.fetchPayload(
2446
+ "/v1/{contentType}/{id}",
2447
+ "patch",
2448
+ {
2449
+ path: { contentType: this.assetType, id },
2450
+ body: { content: data, ...rest },
2451
+ headers: writeHeaders({ idempotencyKey, ifMatch })
2452
+ }
2453
+ );
2454
+ }
2455
+ /** Delete an asset entry (cascades file-byte cleanup + gateway purge). */
2456
+ async delete(id, options) {
2457
+ await this.httpClient.send("/v1/{contentType}/{id}", "delete", {
2458
+ path: { contentType: this.assetType, id },
2459
+ headers: writeHeaders(options)
2460
+ });
2461
+ }
2462
+ /** Get the file sub-resource builder for a specific asset entry. */
2463
+ file(entryUid) {
2464
+ return new AssetFileBuilder(this.httpClient, this.assetType, entryUid, this.defaultLocale);
2465
+ }
2466
+ /** Start a high-level upload (create → presign → PUT → confirm). */
2467
+ upload(file) {
2468
+ return new AssetUploadBuilder(this.httpClient, this.assetType, file, this.defaultLocale);
2469
+ }
2470
+ /** Get the asset type id. */
2471
+ getAssetType() {
2472
+ return this.assetType;
2473
+ }
2474
+ /** Get the current default locale. */
2475
+ getDefaultLocale() {
2476
+ return this.defaultLocale;
2477
+ }
2478
+ /** Create a new AssetClient for this type with a different default locale. */
2479
+ withLocale(locale) {
2480
+ return new _AssetClient(this.httpClient, this.assetType, locale);
2481
+ }
2482
+ };
2483
+ __name(_AssetClient, "AssetClient");
2484
+ var AssetClient = _AssetClient;
2485
+ function isAssetEntry(entry) {
2486
+ if (entry == null || typeof entry !== "object") return false;
2487
+ const metadata = entry._metadata;
2488
+ return metadata?.entryType === "asset";
2489
+ }
2490
+ __name(isAssetEntry, "isAssetEntry");
2491
+
2492
+ // src/content/singleton-client.ts
2493
+ var _SingletonClient = class _SingletonClient {
2494
+ constructor(httpClient, singletonKey) {
2495
+ this.httpClient = httpClient;
2496
+ this.singletonKey = singletonKey;
2497
+ __publicField(this, "includeFields");
2498
+ __publicField(this, "localeValue");
2499
+ }
2500
+ /**
2501
+ * Include reference fields in the response
2502
+ * @param fields - Reference field names to populate
2503
+ */
2504
+ include(fields) {
2505
+ this.includeFields = fields;
2506
+ return this;
2507
+ }
2508
+ /**
2509
+ * Set locale for localized content
2510
+ * @param locale - Locale code (e.g., 'en', 'de', 'fr')
2511
+ */
2512
+ locale(locale) {
2513
+ this.localeValue = locale;
2514
+ return this;
2515
+ }
2516
+ /**
2517
+ * Fetch the singleton content
2518
+ * @param options - Optional fetch options (alternative to fluent methods)
2519
+ */
2520
+ async fetch(options) {
2521
+ const includeValue = options?.include ?? this.includeFields;
2522
+ options?.locale ?? this.localeValue;
2523
+ if (includeValue) {
2524
+ includeValue.join(",");
2525
+ }
2526
+ try {
2527
+ return (await this.fetchWithTag(options)).content;
2528
+ } catch (error) {
2529
+ if (isResourceNotFound(error)) return null;
2530
+ throw error;
2531
+ }
2532
+ }
2533
+ /**
2534
+ * Fetch the singleton **and the entity tag that read served**, which is what
2535
+ * `update`'s `ifMatch` takes (`INV-API-CONDITIONAL-WRITE-IS-REACHABLE`).
2536
+ *
2537
+ * `entityTag` is absent on a cache HIT: a cached body cannot know the current
2538
+ * version, and a stale tag would refuse the very next write.
2539
+ */
2540
+ async fetchWithTag(options) {
2541
+ const query = {};
2542
+ const includeValue = options?.include ?? this.includeFields;
2543
+ const localeValueFinal = options?.locale ?? this.localeValue;
2544
+ if (includeValue) query.include = includeValue.join(",");
2545
+ if (localeValueFinal != null && localeValueFinal !== "") query.locale = localeValueFinal;
2546
+ const response = await this.httpClient.send(
2547
+ "/v1/singletons/{key}",
2548
+ "get",
2549
+ { path: { key: this.singletonKey }, query }
2550
+ );
2551
+ return { content: readPayload(response.body), entityTag: entityTagOf(response) };
2552
+ }
2553
+ /**
2554
+ * Update singleton content. The API auto-publishes on PATCH — there is no
2555
+ * separate publish route; calling `update()` writes and publishes.
2556
+ * @param data - The content fields to update
2557
+ * @param locale - Optional locale for localized content (overrides fluent locale)
2558
+ * @param options - `If-Match` / `Idempotency-Key`, both declared on this route
2559
+ */
2560
+ async update(data, locale, options) {
2561
+ const finalLocale = locale ?? this.localeValue;
2562
+ return this.httpClient.fetchPayload(
2563
+ "/v1/singletons/{key}",
2564
+ "patch",
2565
+ {
2566
+ path: { key: this.singletonKey },
2567
+ body: {
2568
+ content: data,
2569
+ ...finalLocale != null && finalLocale !== "" && { locale: finalLocale }
2570
+ },
2571
+ headers: writeHeaders(options)
2572
+ }
2573
+ );
2574
+ }
2575
+ /**
2576
+ * Check if singleton exists
2577
+ */
2578
+ async exists() {
2579
+ try {
2580
+ const result = await this.fetch();
2581
+ return result !== null;
2582
+ } catch {
2583
+ return false;
2584
+ }
2585
+ }
2586
+ /**
2587
+ * Get version history for one locale of the singleton.
2588
+ *
2589
+ * Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
2590
+ * schema default, no fallback is applied, and a locale with no history returns an empty array
2591
+ * rather than another locale's rows. Every row names the locale it belongs to.
2592
+ */
2593
+ async versions(options) {
2594
+ const payload = await this.httpClient.fetchPayload("/v1/singletons/{key}/versions", "get", {
2595
+ path: { key: this.singletonKey },
2596
+ query: {
2597
+ limit: options?.limit ?? 10,
2598
+ ...options?.locale === void 0 ? {} : { locale: options.locale }
2599
+ }
2600
+ });
2601
+ return payload.versions;
2602
+ }
2603
+ /**
2604
+ * Get a specific version of the singleton.
2605
+ *
2606
+ * `locale` defaults to the schema default. Version numbers are per locale, so version 2 is
2607
+ * different content in each one.
2608
+ */
2609
+ async version(versionNumber, options) {
2610
+ try {
2611
+ return await this.httpClient.fetchPayload("/v1/singletons/{key}/versions/{versionNumber}", "get", {
2612
+ path: { key: this.singletonKey, versionNumber: String(versionNumber) },
2613
+ query: options?.locale === void 0 ? void 0 : { locale: options.locale }
2614
+ });
2615
+ } catch (error) {
2616
+ if (isResourceNotFound(error)) return null;
2617
+ throw error;
2618
+ }
2619
+ }
2620
+ /**
2621
+ * Get the singleton key
2622
+ */
2623
+ getSingletonKey() {
2624
+ return this.singletonKey;
2625
+ }
2626
+ /**
2627
+ * Reset fluent options for reuse
2628
+ */
2629
+ reset() {
2630
+ this.includeFields = void 0;
2631
+ this.localeValue = void 0;
2632
+ return this;
2633
+ }
2634
+ };
2635
+ __name(_SingletonClient, "SingletonClient");
2636
+ var SingletonClient = _SingletonClient;
2637
+
2638
+ // src/content/settings-client.ts
2639
+ var _SettingsClient = class _SettingsClient {
2640
+ constructor(httpClient, groupId) {
2641
+ this.httpClient = httpClient;
2642
+ this.groupId = groupId;
2643
+ __publicField(this, "includeFields");
2644
+ __publicField(this, "localeValue");
2645
+ }
2646
+ /**
2647
+ * Include reference fields in the response
2648
+ * @param fields - Reference field names to populate
2649
+ */
2650
+ include(fields) {
2651
+ this.includeFields = fields;
2652
+ return this;
2653
+ }
2654
+ /**
2655
+ * Set locale for localized settings
2656
+ * @param locale - Locale code (e.g., 'en', 'de', 'fr')
2657
+ */
2658
+ locale(locale) {
2659
+ this.localeValue = locale;
2660
+ return this;
2661
+ }
2662
+ /**
2663
+ * Fetch the settings group
2664
+ * @param options - Optional fetch options (alternative to fluent methods)
2665
+ */
2666
+ async fetch(options) {
2667
+ const includeValue = options?.include ?? this.includeFields;
2668
+ options?.locale ?? this.localeValue;
2669
+ if (includeValue) {
2670
+ includeValue.join(",");
2671
+ }
2672
+ try {
2673
+ return (await this.fetchWithTag(options)).settings;
2674
+ } catch (error) {
2675
+ if (isResourceNotFound(error)) return null;
2676
+ throw error;
2677
+ }
2678
+ }
2679
+ /**
2680
+ * Update settings group
2681
+ * @param settings - The settings fields to update
2682
+ * @param locale - Optional locale for localized settings (overrides fluent locale)
2683
+ */
2684
+ async update(settings, locale, options) {
2685
+ const finalLocale = locale ?? this.localeValue;
2686
+ const body = finalLocale != null && finalLocale !== "" ? { ...settings, locale: finalLocale } : settings;
2687
+ return this.httpClient.fetchPayload(
2688
+ "/v1/settings/{groupId}",
2689
+ "patch",
2690
+ { path: { groupId: this.groupId }, body, headers: writeHeaders(options) }
2691
+ );
2692
+ }
2693
+ /**
2694
+ * Fetch the group **and the entity tag that read served**, which is what
2695
+ * `update`'s and `reset`'s `ifMatch` take
2696
+ * (`INV-API-CONDITIONAL-WRITE-IS-REACHABLE`).
2697
+ */
2698
+ async fetchWithTag(options) {
2699
+ const query = {};
2700
+ const includeValue = options?.include ?? this.includeFields;
2701
+ const localeValueFinal = options?.locale ?? this.localeValue;
2702
+ if (includeValue) query.include = includeValue.join(",");
2703
+ if (localeValueFinal != null && localeValueFinal !== "") query.locale = localeValueFinal;
2704
+ const response = await this.httpClient.send(
2705
+ "/v1/settings/{groupId}",
2706
+ "get",
2707
+ { path: { groupId: this.groupId }, query }
2708
+ );
2709
+ return { settings: readPayload(response.body), entityTag: entityTagOf(response) };
2710
+ }
2711
+ /**
2712
+ * Reset settings to default values
2713
+ * @param locale - Optional locale for localized settings
2714
+ */
2715
+ async reset(locale, options) {
2716
+ const finalLocale = locale ?? this.localeValue;
2717
+ return this.httpClient.fetchPayload(
2718
+ "/v1/settings/{groupId}/reset",
2719
+ "post",
2720
+ {
2721
+ path: { groupId: this.groupId },
2722
+ body: finalLocale != null && finalLocale !== "" ? { locale: finalLocale } : void 0,
2723
+ headers: writeHeaders(options)
2724
+ }
2725
+ );
2726
+ }
2727
+ /**
2728
+ * Get default settings for this group
2729
+ */
2730
+ async getDefaults() {
2731
+ return this.httpClient.fetchPayload(
2732
+ "/v1/settings/{groupId}/defaults",
2733
+ "get",
2734
+ { path: { groupId: this.groupId } }
2735
+ );
2736
+ }
2737
+ /**
2738
+ * Check if settings group exists
2739
+ */
2740
+ async exists() {
2741
+ try {
2742
+ const result = await this.fetch();
2743
+ return result !== null;
2744
+ } catch (error) {
2745
+ if (isResourceNotFound(error)) return false;
2746
+ throw error;
2747
+ }
2748
+ }
2749
+ /**
2750
+ * Get version history for one locale of the settings group.
2751
+ *
2752
+ * Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
2753
+ * schema default, no fallback is applied, and a locale with no history returns an empty array
2754
+ * rather than another locale's rows. Every row names the locale it belongs to.
2755
+ */
2756
+ async versions(options) {
2757
+ const payload = await this.httpClient.fetchPayload("/v1/settings/{groupId}/versions", "get", {
2758
+ path: { groupId: this.groupId },
2759
+ query: {
2760
+ limit: options?.limit ?? 10,
2761
+ ...options?.locale === void 0 ? {} : { locale: options.locale }
2762
+ }
2763
+ });
2764
+ return payload.versions;
2765
+ }
2766
+ /**
2767
+ * Get a specific version of the settings.
2768
+ *
2769
+ * `locale` defaults to the schema default. Version numbers are per locale, so version 2 is
2770
+ * different content in each one.
2771
+ */
2772
+ async version(versionNumber, options) {
2773
+ try {
2774
+ return await this.httpClient.fetchPayload("/v1/settings/{groupId}/versions/{versionNumber}", "get", {
2775
+ path: { groupId: this.groupId, versionNumber: String(versionNumber) },
2776
+ query: options?.locale === void 0 ? void 0 : { locale: options.locale }
2777
+ });
2778
+ } catch (error) {
2779
+ if (isResourceNotFound(error)) return null;
2780
+ throw error;
2781
+ }
2782
+ }
2783
+ /**
2784
+ * Get the settings group ID
2785
+ */
2786
+ getGroupId() {
2787
+ return this.groupId;
2788
+ }
2789
+ /**
2790
+ * Reset fluent options for reuse
2791
+ */
2792
+ resetOptions() {
2793
+ this.includeFields = void 0;
2794
+ this.localeValue = void 0;
2795
+ return this;
2796
+ }
2797
+ };
2798
+ __name(_SettingsClient, "SettingsClient");
2799
+ var SettingsClient = _SettingsClient;
2800
+
2801
+ // src/search/search-client.ts
2802
+ var _SearchBuilder = class _SearchBuilder {
2803
+ constructor(httpClient, query) {
2804
+ this.httpClient = httpClient;
2805
+ __publicField(this, "query");
2806
+ __publicField(this, "searchOptions", {});
2807
+ this.query = query;
2808
+ }
2809
+ /**
2810
+ * Search within a single content type
2811
+ * @param contentType - Content type to search in
2812
+ */
2813
+ in(contentType) {
2814
+ this.searchOptions.contentType = contentType;
2815
+ this.searchOptions.contentTypes = void 0;
2816
+ return this;
2817
+ }
2818
+ /**
2819
+ * Search across multiple content types
2820
+ * @param contentTypes - Array of content types or '*' for all
2821
+ */
2822
+ across(contentTypes) {
2823
+ this.searchOptions.contentTypes = contentTypes;
2824
+ this.searchOptions.contentType = void 0;
2825
+ return this;
2826
+ }
2827
+ /**
2828
+ * Add filter conditions
2829
+ * @param conditions - Filter conditions
2830
+ */
2831
+ where(conditions) {
2832
+ this.searchOptions.where = {
2833
+ ...this.searchOptions.where,
2834
+ ...conditions
2835
+ };
2836
+ return this;
2837
+ }
2838
+ /**
2839
+ * Specify which fields to search in
2840
+ * @param fields - Field names to search
2841
+ */
2842
+ searchFields(fields) {
2843
+ this.searchOptions.searchFields = fields;
2844
+ return this;
2845
+ }
2846
+ /**
2847
+ * Project specific fields in results
2848
+ * @param projection - Field mapping
2849
+ */
2850
+ fields(projection) {
2851
+ this.searchOptions.fields = projection;
2852
+ return this;
2853
+ }
2854
+ /**
2855
+ * Limit number of results
2856
+ * @param count - Maximum results
2857
+ */
2858
+ limit(count) {
2859
+ this.searchOptions.limit = count;
2860
+ return this;
2861
+ }
2862
+ /**
2863
+ * Skip results for pagination
2864
+ * @param count - Number to skip
2865
+ */
2866
+ offset(count) {
2867
+ this.searchOptions.offset = count;
2868
+ return this;
2869
+ }
2870
+ /**
2871
+ * Include relevance scores in results
2872
+ */
2873
+ includeScore() {
2874
+ this.searchOptions.includeScore = true;
2875
+ return this;
2876
+ }
2877
+ /**
2878
+ * Include score breakdown explanation
2879
+ */
2880
+ explain() {
2881
+ this.searchOptions.explain = true;
2882
+ return this;
2883
+ }
2884
+ /**
2885
+ * Set locale for localized content
2886
+ * @param locale - Locale code
2887
+ */
2888
+ locale(locale) {
2889
+ this.searchOptions.locale = locale;
2890
+ return this;
2891
+ }
2892
+ /**
2893
+ * Execute the search query
2894
+ */
2895
+ async execute() {
2896
+ const body = {
2897
+ q: this.query
2898
+ };
2899
+ if (this.searchOptions.contentType != null && this.searchOptions.contentType !== "") {
2900
+ body.contentType = this.searchOptions.contentType;
2901
+ }
2902
+ if (this.searchOptions.contentTypes != null) {
2903
+ body.contentTypes = this.searchOptions.contentTypes;
2904
+ }
2905
+ if (this.searchOptions.where && Object.keys(this.searchOptions.where).length > 0) {
2906
+ body.where = this.searchOptions.where;
2907
+ }
2908
+ if (this.searchOptions.searchFields) {
2909
+ body.searchFields = this.searchOptions.searchFields;
2910
+ }
2911
+ if (this.searchOptions.fields) {
2912
+ body.fields = this.searchOptions.fields;
2913
+ }
2914
+ if (this.searchOptions.limit !== void 0) {
2915
+ body.limit = this.searchOptions.limit;
2916
+ }
2917
+ if (this.searchOptions.offset !== void 0) {
2918
+ body.offset = this.searchOptions.offset;
2919
+ }
2920
+ if (this.searchOptions.includeScore === true) {
2921
+ body.includeScore = true;
2922
+ }
2923
+ if (this.searchOptions.explain === true) {
2924
+ body.explain = true;
2925
+ }
2926
+ if (this.searchOptions.locale != null && this.searchOptions.locale !== "") {
2927
+ body.locale = this.searchOptions.locale;
2928
+ }
2929
+ const response = await this.httpClient.send(
2930
+ "/v1/search",
2931
+ "post",
2932
+ { body }
2933
+ );
2934
+ return response.body;
2935
+ }
2936
+ /**
2937
+ * Execute and return just the items (convenience method)
2938
+ */
2939
+ async items() {
2940
+ return readPayload(await this.execute());
2941
+ }
2942
+ /**
2943
+ * Get the first result
2944
+ */
2945
+ async first() {
2946
+ return readPayload(await this.limit(1).execute())[0] ?? null;
2947
+ }
2948
+ };
2949
+ __name(_SearchBuilder, "SearchBuilder");
2950
+ var SearchBuilder = _SearchBuilder;
2951
+ var _AutocompleteBuilder = class _AutocompleteBuilder {
2952
+ constructor(httpClient, query) {
2953
+ this.httpClient = httpClient;
2954
+ __publicField(this, "query");
2955
+ __publicField(this, "autocompleteOptions", {});
2956
+ this.query = query;
2957
+ }
2958
+ /**
2959
+ * Autocomplete within a content type
2960
+ * @param contentType - Content type to search
2961
+ */
2962
+ in(contentType) {
2963
+ this.autocompleteOptions.contentType = contentType;
2964
+ return this;
2965
+ }
2966
+ /**
2967
+ * Field to autocomplete on
2968
+ * @param fieldName - Field name (supports nested like 'category.name')
2969
+ */
2970
+ field(fieldName) {
2971
+ this.autocompleteOptions.field = fieldName;
2972
+ return this;
2973
+ }
2974
+ /**
2975
+ * Enable fuzzy matching for typo tolerance
2976
+ */
2977
+ fuzzy() {
2978
+ this.autocompleteOptions.fuzzy = true;
2979
+ return this;
2980
+ }
2981
+ /**
2982
+ * Add filter conditions
2983
+ * @param conditions - Filter conditions
2984
+ */
2985
+ where(conditions) {
2986
+ this.autocompleteOptions.where = {
2987
+ ...this.autocompleteOptions.where,
2988
+ ...conditions
2989
+ };
2990
+ return this;
2991
+ }
2992
+ /**
2993
+ * Limit number of suggestions
2994
+ * @param count - Maximum suggestions
2995
+ */
2996
+ limit(count) {
2997
+ this.autocompleteOptions.limit = count;
2998
+ return this;
2999
+ }
3000
+ /**
3001
+ * Set locale for localized content
3002
+ * @param locale - Locale code
3003
+ */
3004
+ locale(locale) {
3005
+ this.autocompleteOptions.locale = locale;
3006
+ return this;
3007
+ }
3008
+ /**
3009
+ * Execute the autocomplete query
3010
+ */
3011
+ async execute() {
3012
+ if (this.autocompleteOptions.contentType == null || this.autocompleteOptions.contentType === "") {
3013
+ throw new Error('Content type is required for autocomplete. Use .in("contentType")');
3014
+ }
3015
+ if (this.autocompleteOptions.field == null || this.autocompleteOptions.field === "") {
3016
+ throw new Error('Field is required for autocomplete. Use .field("fieldName")');
3017
+ }
3018
+ const body = {
3019
+ q: this.query,
3020
+ contentType: this.autocompleteOptions.contentType,
3021
+ field: this.autocompleteOptions.field
3022
+ };
3023
+ if (this.autocompleteOptions.fuzzy === true) {
3024
+ body.fuzzy = true;
3025
+ }
3026
+ if (this.autocompleteOptions.where && Object.keys(this.autocompleteOptions.where).length > 0) {
3027
+ body.where = this.autocompleteOptions.where;
3028
+ }
3029
+ if (this.autocompleteOptions.limit !== void 0) {
3030
+ body.limit = this.autocompleteOptions.limit;
3031
+ }
3032
+ if (this.autocompleteOptions.locale != null && this.autocompleteOptions.locale !== "") {
3033
+ body.locale = this.autocompleteOptions.locale;
3034
+ }
3035
+ const response = await this.httpClient.send("/v1/search/autocomplete", "post", { body });
3036
+ return response.body;
3037
+ }
3038
+ /**
3039
+ * Get just the suggestion texts
3040
+ */
3041
+ async texts() {
3042
+ return readPayload(await this.execute()).map((suggestion) => suggestion.text);
3043
+ }
3044
+ };
3045
+ __name(_AutocompleteBuilder, "AutocompleteBuilder");
3046
+ var AutocompleteBuilder = _AutocompleteBuilder;
3047
+ var _SimilarBuilder = class _SimilarBuilder {
3048
+ constructor(httpClient, sourceId) {
3049
+ this.httpClient = httpClient;
3050
+ __publicField(this, "sourceId");
3051
+ __publicField(this, "similarOptions", {});
3052
+ this.sourceId = sourceId;
3053
+ }
3054
+ /**
3055
+ * Find similar content within a content type
3056
+ * @param contentType - Content type to search
3057
+ */
3058
+ in(contentType) {
3059
+ this.similarOptions.contentType = contentType;
3060
+ return this;
3061
+ }
3062
+ /**
3063
+ * Add filter conditions
3064
+ * @param conditions - Filter conditions
3065
+ */
3066
+ where(conditions) {
3067
+ this.similarOptions.where = {
3068
+ ...this.similarOptions.where,
3069
+ ...conditions
3070
+ };
3071
+ return this;
3072
+ }
3073
+ /**
3074
+ * Limit number of results
3075
+ * @param count - Maximum results
3076
+ */
3077
+ limit(count) {
3078
+ this.similarOptions.limit = count;
3079
+ return this;
3080
+ }
3081
+ /**
3082
+ * Set locale for localized content
3083
+ * @param locale - Locale code
3084
+ */
3085
+ locale(locale) {
3086
+ this.similarOptions.locale = locale;
3087
+ return this;
3088
+ }
3089
+ /**
3090
+ * Execute the similar query
3091
+ */
3092
+ async execute() {
3093
+ if (this.similarOptions.contentType == null || this.similarOptions.contentType === "") {
3094
+ throw new Error('Content type is required for similar search. Use .in("contentType")');
3095
+ }
3096
+ const body = {
3097
+ source: this.sourceId,
3098
+ contentType: this.similarOptions.contentType
3099
+ };
3100
+ if (this.similarOptions.where && Object.keys(this.similarOptions.where).length > 0) {
3101
+ body.where = this.similarOptions.where;
3102
+ }
3103
+ if (this.similarOptions.limit !== void 0) {
3104
+ body.limit = this.similarOptions.limit;
3105
+ }
3106
+ if (this.similarOptions.locale != null && this.similarOptions.locale !== "") {
3107
+ body.locale = this.similarOptions.locale;
3108
+ }
3109
+ const response = await this.httpClient.send(
3110
+ "/v1/search/similar",
3111
+ "post",
3112
+ { body }
3113
+ );
3114
+ return response.body;
3115
+ }
3116
+ /**
3117
+ * Get just the similar items
3118
+ */
3119
+ async items() {
3120
+ return readPayload(await this.execute());
3121
+ }
3122
+ /**
3123
+ * Get the most similar item
3124
+ */
3125
+ async first() {
3126
+ return readPayload(await this.limit(1).execute())[0] ?? null;
3127
+ }
3128
+ };
3129
+ __name(_SimilarBuilder, "SimilarBuilder");
3130
+ var SimilarBuilder = _SimilarBuilder;
3131
+ var _SearchClient = class _SearchClient {
3132
+ constructor(httpClient) {
3133
+ this.httpClient = httpClient;
3134
+ }
3135
+ /**
3136
+ * Start a search query
3137
+ * @param query - Search query string
3138
+ */
3139
+ search(query) {
3140
+ return new SearchBuilder(this.httpClient, query);
3141
+ }
3142
+ /**
3143
+ * Start an autocomplete query
3144
+ * @param query - Partial query to autocomplete
3145
+ */
3146
+ autocomplete(query) {
3147
+ return new AutocompleteBuilder(this.httpClient, query);
3148
+ }
3149
+ /**
3150
+ * Find content similar to a given entry
3151
+ * @param sourceId - Entry ID to find similar content for
3152
+ */
3153
+ similar(sourceId) {
3154
+ return new SimilarBuilder(this.httpClient, sourceId);
3155
+ }
3156
+ /**
3157
+ * Quick search helper - searches all content types
3158
+ * @param query - Search query
3159
+ * @param limit - Max results (default 20)
3160
+ */
3161
+ async global(query, limit = 20) {
3162
+ return this.search(query).across("*").limit(limit).execute();
3163
+ }
3164
+ };
3165
+ __name(_SearchClient, "SearchClient");
3166
+ var SearchClient = _SearchClient;
3167
+
3168
+ // src/batch/batch-client.ts
3169
+ var _BatchBuilder = class _BatchBuilder {
3170
+ constructor(httpClient) {
3171
+ this.httpClient = httpClient;
3172
+ __publicField(this, "operations", []);
3173
+ __publicField(this, "defaultOptions", {
3174
+ atomic: false,
3175
+ dryRun: false,
3176
+ returnData: true,
3177
+ continueOnError: true
3178
+ });
3179
+ }
3180
+ // ==========================================================================
3181
+ // ENTRY OPERATIONS
3182
+ // ==========================================================================
3183
+ /**
3184
+ * Add a create operation
3185
+ * @param contentType - Content type to create
3186
+ * @param data - Entry data with content field
3187
+ * @param id - Optional operation ID for tracking
3188
+ */
3189
+ create(contentType, data, id) {
3190
+ this.operations.push({
3191
+ id,
3192
+ method: "POST",
3193
+ path: `/${contentType}`,
3194
+ body: data
3195
+ });
3196
+ return this;
3197
+ }
3198
+ /**
3199
+ * Add an update operation (partial update).
3200
+ *
3201
+ * The submitted fields are merged into the entry and the rest are left as they are. The merge is
3202
+ * field-level rather than deep: sending an object-typed field replaces that field's whole value.
3203
+ *
3204
+ * @param contentType - Content type
3205
+ * @param entryId - Entry ID to update
3206
+ * @param data - Fields to update
3207
+ * @param id - Optional operation ID for tracking
3208
+ */
3209
+ update(contentType, entryId, data, id) {
3210
+ this.operations.push({
3211
+ id,
3212
+ method: "PATCH",
3213
+ path: `/${contentType}/${entryId}`,
3214
+ body: data
3215
+ });
3216
+ return this;
3217
+ }
3218
+ /**
3219
+ * Add a replace operation (full replacement).
3220
+ *
3221
+ * The payload becomes the entry's content for the addressed locale: fields you do not send are
3222
+ * cleared. Send the whole entry, or use {@link BatchClient.update} to change part of one.
3223
+ *
3224
+ * @param contentType - Content type
3225
+ * @param entryId - Entry ID to replace
3226
+ * @param data - Complete entry data
3227
+ * @param id - Optional operation ID for tracking
3228
+ */
3229
+ replace(contentType, entryId, data, id) {
3230
+ this.operations.push({
3231
+ id,
3232
+ method: "PUT",
3233
+ path: `/${contentType}/${entryId}`,
3234
+ body: data
3235
+ });
3236
+ return this;
3237
+ }
3238
+ /**
3239
+ * Add a delete operation
3240
+ * @param contentType - Content type
3241
+ * @param entryId - Entry ID to delete
3242
+ * @param id - Optional operation ID for tracking
3243
+ */
3244
+ delete(contentType, entryId, id) {
3245
+ this.operations.push({
3246
+ id,
3247
+ method: "DELETE",
3248
+ path: `/${contentType}/${entryId}`
3249
+ });
3250
+ return this;
3251
+ }
3252
+ // ==========================================================================
3253
+ // SINGLETON OPERATIONS
3254
+ // ==========================================================================
3255
+ /**
3256
+ * Add a singleton upsert operation
3257
+ * @param singletonKey - Singleton key
3258
+ * @param data - Singleton content
3259
+ * @param id - Optional operation ID for tracking
3260
+ */
3261
+ upsertSingleton(singletonKey, data, id) {
3262
+ this.operations.push({
3263
+ id,
3264
+ method: "PATCH",
3265
+ path: `/_singletons/${singletonKey}`,
3266
+ body: data
3267
+ });
3268
+ return this;
3269
+ }
3270
+ /**
3271
+ * Add a singleton create operation (alias for upsert with POST)
3272
+ * @param singletonKey - Singleton key
3273
+ * @param data - Singleton content
3274
+ * @param id - Optional operation ID for tracking
3275
+ */
3276
+ createSingleton(singletonKey, data, id) {
3277
+ this.operations.push({
3278
+ id,
3279
+ method: "POST",
3280
+ path: `/_singletons/${singletonKey}`,
3281
+ body: data
3282
+ });
3283
+ return this;
3284
+ }
3285
+ // ==========================================================================
3286
+ // RAW OPERATIONS
3287
+ // ==========================================================================
3288
+ /**
3289
+ * Add a raw operation (for advanced use cases)
3290
+ * @param operation - The operation to add
3291
+ */
3292
+ raw(operation) {
3293
+ this.operations.push(operation);
3294
+ return this;
3295
+ }
3296
+ /**
3297
+ * Add multiple raw operations
3298
+ * @param operations - Operations to add
3299
+ */
3300
+ rawMany(operations) {
3301
+ this.operations.push(...operations);
3302
+ return this;
3303
+ }
3304
+ // ==========================================================================
3305
+ // BULK HELPERS
3306
+ // ==========================================================================
3307
+ /**
3308
+ * Bulk create multiple entries of the same content type
3309
+ * @param contentType - Content type
3310
+ * @param items - Array of entry data
3311
+ */
3312
+ bulkCreate(contentType, items) {
3313
+ for (const item of items) {
3314
+ const { id, ...data } = item;
3315
+ this.create(contentType, data, id);
3316
+ }
3317
+ return this;
3318
+ }
3319
+ /**
3320
+ * Bulk update multiple entries
3321
+ * @param contentType - Content type
3322
+ * @param updates - Array of { entryId, data } pairs
3323
+ */
3324
+ bulkUpdate(contentType, updates) {
3325
+ for (const update of updates) {
3326
+ this.update(contentType, update.entryId, update.data, update.id);
3327
+ }
3328
+ return this;
3329
+ }
3330
+ /**
3331
+ * Bulk delete multiple entries
3332
+ * @param contentType - Content type
3333
+ * @param entryIds - Entry IDs to delete
3334
+ */
3335
+ bulkDelete(contentType, entryIds) {
3336
+ for (const entryId of entryIds) {
3337
+ this.delete(contentType, entryId);
3338
+ }
3339
+ return this;
3340
+ }
3341
+ // ==========================================================================
3342
+ // CONFIGURATION
3343
+ // ==========================================================================
3344
+ /**
3345
+ * Configure default options for execution
3346
+ * @param options - Batch options
3347
+ */
3348
+ configure(options) {
3349
+ this.defaultOptions = { ...this.defaultOptions, ...options };
3350
+ return this;
3351
+ }
3352
+ /**
3353
+ * Enable atomic mode (all-or-nothing)
3354
+ */
3355
+ atomic() {
3356
+ this.defaultOptions.atomic = true;
3357
+ return this;
3358
+ }
3359
+ /**
3360
+ * Enable dry-run mode (validate without executing)
3361
+ */
3362
+ dryRun() {
3363
+ this.defaultOptions.dryRun = true;
3364
+ return this;
3365
+ }
3366
+ /**
3367
+ * Disable returning full data in response
3368
+ */
3369
+ noData() {
3370
+ this.defaultOptions.returnData = false;
3371
+ return this;
3372
+ }
3373
+ /**
3374
+ * Stop on first error (non-atomic mode)
3375
+ */
3376
+ stopOnError() {
3377
+ this.defaultOptions.continueOnError = false;
3378
+ return this;
3379
+ }
3380
+ // ==========================================================================
3381
+ // EXECUTION
3382
+ // ==========================================================================
3383
+ /**
3384
+ * Get the current list of operations
3385
+ */
3386
+ getOperations() {
3387
+ return [...this.operations];
3388
+ }
3389
+ /**
3390
+ * Get the number of operations
3391
+ */
3392
+ size() {
3393
+ return this.operations.length;
3394
+ }
3395
+ /**
3396
+ * Clear all operations
3397
+ */
3398
+ clear() {
3399
+ this.operations = [];
3400
+ return this;
3401
+ }
3402
+ /**
3403
+ * Clone the builder
3404
+ */
3405
+ clone() {
3406
+ const cloned = new _BatchBuilder(this.httpClient);
3407
+ cloned.operations = [...this.operations];
3408
+ cloned.defaultOptions = { ...this.defaultOptions };
3409
+ return cloned;
3410
+ }
3411
+ /**
3412
+ * Execute the batch operations
3413
+ * @param options - Override default options
3414
+ */
3415
+ async execute(options) {
3416
+ if (this.operations.length === 0) {
3417
+ throw new Error(
3418
+ "No operations to execute. Add operations using .create(), .update(), .delete(), etc."
3419
+ );
3420
+ }
3421
+ if (this.operations.length > 100) {
3422
+ throw new Error("Maximum 100 operations per batch. Split into multiple batches.");
3423
+ }
3424
+ const finalOptions = { ...this.defaultOptions, ...options };
3425
+ return this.httpClient.fetchPayload("/v1/batch", "post", {
3426
+ body: { operations: this.operations, options: finalOptions }
3427
+ });
3428
+ }
3429
+ /**
3430
+ * Validate operations without executing (convenience for dry-run)
3431
+ */
3432
+ async validate() {
3433
+ return this.execute({ dryRun: true });
3434
+ }
3435
+ /**
3436
+ * Execute and throw if any operation failed
3437
+ */
3438
+ async executeOrThrow(options) {
3439
+ const response = await this.execute(options);
3440
+ if (response.summary.failed > 0) {
3441
+ const failedOps = response.results.filter(
3442
+ (result) => "error" in result
3443
+ );
3444
+ const errorMessages = failedOps.map(
3445
+ (op) => `Operation ${op.index}${op.id != null && op.id !== "" ? ` (${op.id})` : ""}: ${op.error.code} \u2014 ${op.error.messages.join(" ")}`
3446
+ ).join("; ");
3447
+ throw new Error(
3448
+ `Batch execution failed: ${response.summary.failed} of ${response.summary.total} operations failed. ${errorMessages}`
3449
+ );
3450
+ }
3451
+ return response;
3452
+ }
3453
+ };
3454
+ __name(_BatchBuilder, "BatchBuilder");
3455
+ var BatchBuilder = _BatchBuilder;
3456
+ var _BatchClient = class _BatchClient {
3457
+ constructor(httpClient) {
3458
+ this.httpClient = httpClient;
3459
+ }
3460
+ /**
3461
+ * Create a new batch builder
3462
+ */
3463
+ create() {
3464
+ return new BatchBuilder(this.httpClient);
3465
+ }
3466
+ /**
3467
+ * Quick bulk create entries
3468
+ * @param contentType - Content type
3469
+ * @param items - Array of entry data
3470
+ * @param options - Batch options
3471
+ */
3472
+ async bulkCreate(contentType, items, options) {
3473
+ return this.create().bulkCreate(contentType, items).execute(options);
3474
+ }
3475
+ /**
3476
+ * Quick bulk update entries
3477
+ * @param contentType - Content type
3478
+ * @param updates - Array of updates
3479
+ * @param options - Batch options
3480
+ */
3481
+ async bulkUpdate(contentType, updates, options) {
3482
+ return this.create().bulkUpdate(contentType, updates).execute(options);
3483
+ }
3484
+ /**
3485
+ * Quick bulk delete entries
3486
+ * @param contentType - Content type
3487
+ * @param entryIds - Entry IDs to delete
3488
+ * @param options - Batch options
3489
+ */
3490
+ async bulkDelete(contentType, entryIds, options) {
3491
+ return this.create().bulkDelete(contentType, entryIds).execute(options);
3492
+ }
3493
+ /**
3494
+ * Execute raw batch operations
3495
+ * @param operations - Array of operations
3496
+ * @param options - Batch options
3497
+ */
3498
+ async execute(operations, options) {
3499
+ return this.create().rawMany(operations).execute(options);
3500
+ }
3501
+ };
3502
+ __name(_BatchClient, "BatchClient");
3503
+ var BatchClient = _BatchClient;
3504
+
3505
+ // src/queries/adhoc-query-client.ts
3506
+ var _AdhocQueryBuilder = class _AdhocQueryBuilder {
3507
+ constructor(httpClient) {
3508
+ this.httpClient = httpClient;
3509
+ __publicField(this, "queryDef", {});
3510
+ __publicField(this, "parameters", {});
3511
+ __publicField(this, "options", {});
3512
+ }
3513
+ // ==========================================================================
3514
+ // QUERY BLOCKS
3515
+ // ==========================================================================
3516
+ /**
3517
+ * Add a fetch block to retrieve content
3518
+ * @param config - Fetch configuration
3519
+ */
3520
+ fetch(config) {
3521
+ this.queryDef.fetch = config;
3522
+ return this;
3523
+ }
3524
+ /**
3525
+ * Fetch from a content type
3526
+ * @param contentType - Content type to fetch
3527
+ */
3528
+ from(contentType) {
3529
+ this.queryDef.fetch = { ...this.queryDef.fetch, contentType };
3530
+ return this;
3531
+ }
3532
+ /**
3533
+ * Fetch a singleton
3534
+ * @param singletonKey - Singleton key
3535
+ */
3536
+ singleton(singletonKey) {
3537
+ this.queryDef.fetch = { ...this.queryDef.fetch, singleton: singletonKey };
3538
+ return this;
3539
+ }
3540
+ /**
3541
+ * Add aggregate block
3542
+ * @param config - Aggregate configuration
3543
+ */
3544
+ aggregate(config) {
3545
+ this.queryDef.aggregate = config;
3546
+ return this;
3547
+ }
3548
+ /**
3549
+ * Add search block
3550
+ * @param config - Search configuration
3551
+ */
3552
+ search(config) {
3553
+ this.queryDef.search = config;
3554
+ return this;
3555
+ }
3556
+ /**
3557
+ * Add similar block
3558
+ * @param config - Similar configuration
3559
+ */
3560
+ similar(config) {
3561
+ this.queryDef.similar = config;
3562
+ return this;
3563
+ }
3564
+ // ==========================================================================
3565
+ // FETCH MODIFIERS
3566
+ // ==========================================================================
3567
+ /**
3568
+ * Add where conditions to fetch
3569
+ * @param conditions - Filter conditions
3570
+ */
3571
+ where(conditions) {
3572
+ this.queryDef.fetch = {
3573
+ ...this.queryDef.fetch,
3574
+ where: { ...this.queryDef.fetch?.where, ...conditions }
3575
+ };
3576
+ return this;
3577
+ }
3578
+ /**
3579
+ * Add include for reference population
3580
+ * @param fields - Reference fields to include
3581
+ */
3582
+ include(fields) {
3583
+ this.queryDef.fetch = {
3584
+ ...this.queryDef.fetch,
3585
+ include: fields
3586
+ };
3587
+ return this;
3588
+ }
3589
+ /**
3590
+ * Add sort specification
3591
+ * @param sort - Sort configuration
3592
+ */
3593
+ sort(sort) {
3594
+ this.queryDef.fetch = {
3595
+ ...this.queryDef.fetch,
3596
+ sort: { ...this.queryDef.fetch?.sort, ...sort }
3597
+ };
3598
+ return this;
3599
+ }
3600
+ /**
3601
+ * Sort by field ascending
3602
+ * @param field - Field to sort by
3603
+ */
3604
+ sortAsc(field) {
3605
+ return this.sort({ [field]: "asc" });
3606
+ }
3607
+ /**
3608
+ * Sort by field descending
3609
+ * @param field - Field to sort by
3610
+ */
3611
+ sortDesc(field) {
3612
+ return this.sort({ [field]: "desc" });
3613
+ }
3614
+ /**
3615
+ * Limit results
3616
+ * @param count - Maximum results
3617
+ */
3618
+ limit(count) {
3619
+ this.queryDef.fetch = {
3620
+ ...this.queryDef.fetch,
3621
+ limit: count
3622
+ };
3623
+ return this;
3624
+ }
3625
+ /**
3626
+ * Skip results
3627
+ * @param count - Number to skip
3628
+ */
3629
+ offset(count) {
3630
+ this.queryDef.fetch = {
3631
+ ...this.queryDef.fetch,
3632
+ offset: count
3633
+ };
3634
+ return this;
3635
+ }
3636
+ // ==========================================================================
3637
+ // PROJECTIONS & FILTERS
3638
+ // ==========================================================================
3639
+ /**
3640
+ * Select and transform fields in output
3641
+ * @param projection - Field mapping (outputField: sourceField)
3642
+ */
3643
+ select(projection) {
3644
+ this.queryDef.select = { ...this.queryDef.select, ...projection };
3645
+ return this;
3646
+ }
3647
+ /**
3648
+ * Add a post-fetch filter (supports ${param} syntax)
3649
+ * @param field - Field path to filter
3650
+ * @param condition - Filter condition
3651
+ */
3652
+ filter(field, condition) {
3653
+ this.queryDef.filters = { ...this.queryDef.filters, [field]: condition };
3654
+ return this;
3655
+ }
3656
+ /**
3657
+ * Add full-text search
3658
+ * @param config - Full-text configuration
3659
+ */
3660
+ fullText(config) {
3661
+ this.queryDef.fullText = config;
3662
+ return this;
3663
+ }
3664
+ // ==========================================================================
3665
+ // PARAMETERS
3666
+ // ==========================================================================
3667
+ /**
3668
+ * Set query parameters
3669
+ * @param params - Parameter values
3670
+ */
3671
+ params(params) {
3672
+ this.parameters = { ...this.parameters, ...params };
3673
+ return this;
3674
+ }
3675
+ /**
3676
+ * Set a single parameter
3677
+ * @param name - Parameter name
3678
+ * @param value - Parameter value
3679
+ */
3680
+ param(name, value) {
3681
+ this.parameters[name] = value;
3682
+ return this;
3683
+ }
3684
+ // ==========================================================================
3685
+ // OPTIONS
3686
+ // ==========================================================================
3687
+ /**
3688
+ * Enable debug mode
3689
+ */
3690
+ debug() {
3691
+ this.options.debug = true;
3692
+ return this;
3693
+ }
3694
+ /**
3695
+ * Skip cache for this request
3696
+ */
3697
+ skipCache() {
3698
+ this.options.skipCache = true;
3699
+ return this;
3700
+ }
3701
+ /**
3702
+ * Set custom timeout
3703
+ * @param ms - Timeout in milliseconds (1000-60000)
3704
+ */
3705
+ timeout(ms) {
3706
+ if (ms < 1e3 || ms > 6e4) {
3707
+ throw new Error("Timeout must be between 1000 and 60000 milliseconds");
3708
+ }
3709
+ this.options.timeout = ms;
3710
+ return this;
3711
+ }
3712
+ /**
3713
+ * Set cache policy
3714
+ * @param ttl - Cache TTL in seconds
3715
+ * @param strategy - Cache strategy
3716
+ */
3717
+ cache(ttl, strategy) {
3718
+ this.queryDef.cache = { ttl, strategy };
3719
+ return this;
3720
+ }
3721
+ // ==========================================================================
3722
+ // EXECUTION
3723
+ // ==========================================================================
3724
+ /**
3725
+ * Get the query definition (for debugging)
3726
+ */
3727
+ getDefinition() {
3728
+ return { ...this.queryDef };
3729
+ }
3730
+ /**
3731
+ * Get the parameters (for debugging)
3732
+ */
3733
+ getParameters() {
3734
+ return { ...this.parameters };
3735
+ }
3736
+ /**
3737
+ * Execute the query
3738
+ */
3739
+ async execute() {
3740
+ if (!this.queryDef.fetch && !this.queryDef.aggregate && !this.queryDef.search && !this.queryDef.similar) {
3741
+ throw new Error(
3742
+ "Query must have at least one of: fetch, aggregate, search, or similar. Use .from(), .aggregate(), .search(), or .similar()"
3743
+ );
3744
+ }
3745
+ const body = {
3746
+ query: this.queryDef
3747
+ };
3748
+ if (Object.keys(this.parameters).length > 0) {
3749
+ body.parameters = this.parameters;
3750
+ }
3751
+ if (Object.keys(this.options).length > 0) {
3752
+ body.options = this.options;
3753
+ }
3754
+ return this.httpClient.fetchPayload(
3755
+ "/v1/query",
3756
+ "post",
3757
+ { body }
3758
+ );
3759
+ }
3760
+ /**
3761
+ * Execute and return the records as an array (for list queries).
3762
+ */
3763
+ async items() {
3764
+ const { result } = await this.execute();
3765
+ if (result === void 0) return [];
3766
+ return Array.isArray(result) ? result : [result];
3767
+ }
3768
+ /**
3769
+ * Execute and return the single record (for singleton queries).
3770
+ */
3771
+ async data() {
3772
+ const { result } = await this.execute();
3773
+ if (Array.isArray(result)) return result[0];
3774
+ return result;
3775
+ }
3776
+ /**
3777
+ * Clone the builder
3778
+ */
3779
+ clone() {
3780
+ const cloned = new _AdhocQueryBuilder(this.httpClient);
3781
+ cloned.queryDef = JSON.parse(JSON.stringify(this.queryDef));
3782
+ cloned.parameters = { ...this.parameters };
3783
+ cloned.options = { ...this.options };
3784
+ return cloned;
3785
+ }
3786
+ };
3787
+ __name(_AdhocQueryBuilder, "AdhocQueryBuilder");
3788
+ var AdhocQueryBuilder = _AdhocQueryBuilder;
3789
+ var _AdhocQueryClient = class _AdhocQueryClient {
3790
+ constructor(httpClient) {
3791
+ this.httpClient = httpClient;
3792
+ }
3793
+ /**
3794
+ * Create a new query builder
3795
+ */
3796
+ build() {
3797
+ return new AdhocQueryBuilder(this.httpClient);
3798
+ }
3799
+ /**
3800
+ * Execute a query definition directly
3801
+ * @param definition - Query definition
3802
+ * @param parameters - Parameter values
3803
+ * @param options - Execution options
3804
+ */
3805
+ async execute(definition, parameters, options) {
3806
+ const body = {
3807
+ query: definition
3808
+ };
3809
+ if (parameters && Object.keys(parameters).length > 0) {
3810
+ body.parameters = parameters;
3811
+ }
3812
+ if (options && Object.keys(options).length > 0) {
3813
+ body.options = options;
3814
+ }
3815
+ return this.httpClient.fetchPayload(
3816
+ "/v1/query",
3817
+ "post",
3818
+ { body }
3819
+ );
3820
+ }
3821
+ /**
3822
+ * Quick fetch helper
3823
+ * @param contentType - Content type
3824
+ * @param options - Fetch options
3825
+ */
3826
+ async fetch(contentType, options) {
3827
+ const { result } = await this.execute({ fetch: { contentType, ...options } });
3828
+ if (result === void 0) return [];
3829
+ return Array.isArray(result) ? result : [result];
3830
+ }
3831
+ /**
3832
+ * Quick singleton fetch helper
3833
+ * @param singletonKey - Singleton key
3834
+ */
3835
+ async fetchSingleton(singletonKey) {
3836
+ const { result } = await this.execute({ fetch: { singleton: singletonKey } });
3837
+ if (Array.isArray(result)) return result[0];
3838
+ return result;
3839
+ }
3840
+ /**
3841
+ * Quick aggregate helper
3842
+ * @param source - Source content type
3843
+ * @param metrics - Metrics to compute
3844
+ * @param groupBy - Optional grouping field
3845
+ */
3846
+ async aggregate(source, metrics, groupBy) {
3847
+ const { result } = await this.execute({ aggregate: { source, metrics, by: groupBy } });
3848
+ if (result === void 0) return [];
3849
+ return Array.isArray(result) ? result : [result];
3850
+ }
3851
+ };
3852
+ __name(_AdhocQueryClient, "AdhocQueryClient");
3853
+ var AdhocQueryClient = _AdhocQueryClient;
3854
+
3855
+ // src/config/dev-detection.ts
3856
+ function getProcess() {
3857
+ return typeof process !== "undefined" ? process : void 0;
3858
+ }
3859
+ __name(getProcess, "getProcess");
3860
+ function getBuiltin(proc, id) {
3861
+ if (proc == null || typeof proc.getBuiltinModule !== "function") return null;
3862
+ try {
3863
+ return proc.getBuiltinModule(id);
3864
+ } catch {
3865
+ return null;
3866
+ }
3867
+ }
3868
+ __name(getBuiltin, "getBuiltin");
3869
+ function isProduction(proc) {
3870
+ return proc?.env?.NODE_ENV === "production";
3871
+ }
3872
+ __name(isProduction, "isProduction");
3873
+ function resolveFromEnv(proc) {
3874
+ const dataset = proc?.env?.RELYIO_DEV_DATASET;
3875
+ const apiKey = proc?.env?.RELYIO_DEV_API_KEY;
3876
+ if (dataset != null && dataset !== "" && apiKey != null && apiKey !== "") {
3877
+ return { dataset, apiKey, source: "env" };
3878
+ }
3879
+ return null;
3880
+ }
3881
+ __name(resolveFromEnv, "resolveFromEnv");
3882
+ function resolveFromFile(proc) {
3883
+ if (proc == null || typeof proc.cwd !== "function") return null;
3884
+ const fs = getBuiltin(proc, "node:fs");
3885
+ const path = getBuiltin(proc, "node:path");
3886
+ if (fs == null || path == null) return null;
3887
+ let dir = proc.cwd();
3888
+ for (; ; ) {
3889
+ const candidate = path.join(dir, ".relyio", "dev.json");
3890
+ try {
3891
+ if (fs.existsSync(candidate)) {
3892
+ const parsed = JSON.parse(fs.readFileSync(candidate, "utf8"));
3893
+ if (parsed.datasetId != null && parsed.datasetId !== "" && parsed.previewApiKey != null && parsed.previewApiKey !== "") {
3894
+ if (parsed.expiresAt != null && Number.isFinite(new Date(parsed.expiresAt).getTime()) && new Date(parsed.expiresAt).getTime() < Date.now()) {
3895
+ return null;
3896
+ }
3897
+ return { dataset: parsed.datasetId, apiKey: parsed.previewApiKey, source: "file" };
3898
+ }
3899
+ }
3900
+ } catch {
3901
+ }
3902
+ const parent = path.dirname(dir);
3903
+ if (parent === dir) break;
3904
+ dir = parent;
3905
+ }
3906
+ return null;
3907
+ }
3908
+ __name(resolveFromFile, "resolveFromFile");
3909
+ function resolveDevOverride(dev) {
3910
+ if (dev === false) return null;
3911
+ const proc = getProcess();
3912
+ if (dev !== true && isProduction(proc)) return null;
3913
+ return resolveFromEnv(proc) ?? resolveFromFile(proc);
3914
+ }
3915
+ __name(resolveDevOverride, "resolveDevOverride");
3916
+
3917
+ // src/config/types.ts
3918
+ var DEFAULT_CONFIG = {
3919
+ baseUrl: "https://api.relyio.com",
3920
+ timeout: 3e4,
3921
+ retryAttempts: 3,
3922
+ useSsl: true,
3923
+ environment: "production",
3924
+ headers: {},
3925
+ browser: {
3926
+ includeCredentials: true,
3927
+ useRelativeUrls: false
3928
+ },
3929
+ cache: {
3930
+ enabled: true,
3931
+ ttl: 5 * 60 * 1e3,
3932
+ // 5 minutes
3933
+ maxEntries: 1e3,
3934
+ maxSize: 50 * 1024 * 1024,
3935
+ // 50MB
3936
+ strategies: ["memory", "stale-while-revalidate"]
3937
+ },
3938
+ realtime: {
3939
+ enabled: true,
3940
+ maxReconnectAttempts: 10,
3941
+ reconnectDelay: 1e3,
3942
+ heartbeatInterval: 3e4
3943
+ },
3944
+ debug: {
3945
+ enabled: false,
3946
+ logRequests: false,
3947
+ logCache: false,
3948
+ logWebSocket: false
3949
+ }
3950
+ };
3951
+ function validateConfig(config) {
3952
+ if (!config.apiKey || config.apiKey.length === 0) {
3953
+ throw new Error("API key is required");
3954
+ }
3955
+ if (typeof config.apiKey !== "string") {
3956
+ throw new Error("API key must be a string");
3957
+ }
3958
+ if (config.baseUrl != null && typeof config.baseUrl !== "string") {
3959
+ throw new Error("Base URL must be a string");
3960
+ }
3961
+ if (config.timeout != null && (typeof config.timeout !== "number" || config.timeout < 0)) {
3962
+ throw new Error("Timeout must be a positive number");
3963
+ }
3964
+ if (config.retryAttempts != null && (typeof config.retryAttempts !== "number" || config.retryAttempts < 0)) {
3965
+ throw new Error("Retry attempts must be a positive number");
3966
+ }
3967
+ }
3968
+ __name(validateConfig, "validateConfig");
3969
+ var devOverrideNotified = false;
3970
+ function mergeConfig(userConfig) {
3971
+ validateConfig(userConfig);
3972
+ const merged = {
3973
+ ...DEFAULT_CONFIG,
3974
+ ...userConfig,
3975
+ headers: {
3976
+ ...DEFAULT_CONFIG.headers,
3977
+ ...userConfig.headers
3978
+ },
3979
+ browser: {
3980
+ ...DEFAULT_CONFIG.browser,
3981
+ ...userConfig.browser
3982
+ },
3983
+ cache: {
3984
+ ...DEFAULT_CONFIG.cache,
3985
+ ...userConfig.cache
3986
+ },
3987
+ realtime: {
3988
+ ...DEFAULT_CONFIG.realtime,
3989
+ ...userConfig.realtime
3990
+ },
3991
+ debug: {
3992
+ ...DEFAULT_CONFIG.debug,
3993
+ ...userConfig.debug
3994
+ }
3995
+ };
3996
+ const devOverride = resolveDevOverride(userConfig.dev);
3997
+ if (devOverride != null) {
3998
+ merged.apiKey = devOverride.apiKey;
3999
+ merged.dataset = devOverride.dataset;
4000
+ if (!devOverrideNotified) {
4001
+ devOverrideNotified = true;
4002
+ console.info(
4003
+ `[RelyIO] Sandbox dev mode active (${devOverride.source}) \u2014 targeting dataset "${devOverride.dataset}" with a scoped preview key.`
4004
+ );
4005
+ }
4006
+ }
4007
+ return merged;
4008
+ }
4009
+ __name(mergeConfig, "mergeConfig");
4010
+
4011
+ // src/client/create-client.ts
4012
+ var API_VERSION_SEGMENT = "v1";
4013
+ var _TypedRelyIOClient = class _TypedRelyIOClient {
4014
+ constructor(config) {
4015
+ __publicField(this, "httpClient");
4016
+ __publicField(this, "config");
4017
+ __publicField(this, "_search");
4018
+ __publicField(this, "_batch");
4019
+ __publicField(this, "_adhocQuery");
4020
+ __publicField(this, "_schema");
4021
+ const { schema, ...clientConfig } = config;
4022
+ this._schema = schema;
4023
+ this.config = mergeConfig(clientConfig);
4024
+ this.httpClient = new HttpClient(this.config);
4025
+ this._search = new SearchClient(this.httpClient);
4026
+ this._batch = new BatchClient(this.httpClient);
4027
+ this._adhocQuery = new AdhocQueryClient(this.httpClient);
4028
+ }
4029
+ // ============================================================================
4030
+ // CORE CLIENTS
4031
+ // ============================================================================
4032
+ /**
4033
+ * Get the schema definition
4034
+ */
4035
+ get schema() {
4036
+ return this._schema;
4037
+ }
4038
+ /**
4039
+ * Get the ad-hoc query client
4040
+ */
4041
+ get query() {
4042
+ return this._adhocQuery;
4043
+ }
4044
+ // ============================================================================
4045
+ // CONTENT OPERATIONS
4046
+ // ============================================================================
4047
+ /**
4048
+ * Get a content client for a specific content type
4049
+ * Type-safe when schema is provided: autocompletes content type names AND field names
4050
+ *
4051
+ * @example
4052
+ * ```typescript
4053
+ * const products = await relyio.content('product')
4054
+ * .query()
4055
+ * .where({ status: 'active' }) // ← Field names autocomplete with schema!
4056
+ * .locale('en-US')
4057
+ * .limit(20)
4058
+ * .execute()
4059
+ * ```
4060
+ */
4061
+ content(contentType) {
4062
+ return new ContentClient(this.httpClient, contentType, this.config.locale);
4063
+ }
4064
+ /**
4065
+ * Get an asset client for a specific asset type.
4066
+ *
4067
+ * Mirrors `content()` but targets `entryType: 'asset'` entries on the same
4068
+ * dynamic `/{assetTypeId}` routes, and adds the `file(entryUid)` sub-resource
4069
+ * builder + a high-level `upload()` helper. Type-safe when a schema is
4070
+ * provided: autocompletes asset type names AND metadata field names.
4071
+ *
4072
+ * @example
4073
+ * ```typescript
4074
+ * const photo = await relyio.asset('productPhoto').upload(file)
4075
+ * .filename('shoe.jpg')
4076
+ * .visibility('public')
4077
+ * .execute()
4078
+ *
4079
+ * const heroUrl = await relyio.asset('productPhoto').file(photo._metadata.id).url({ variantId: 'hero' })
4080
+ * ```
4081
+ */
4082
+ asset(assetType) {
4083
+ return new AssetClient(this.httpClient, assetType, this.config.locale);
4084
+ }
4085
+ /**
4086
+ * Get a singleton client for a specific singleton key
4087
+ * Type-safe when schema is provided: autocompletes singleton names AND field names
4088
+ *
4089
+ * @example
4090
+ * ```typescript
4091
+ * const homepage = await relyio.singleton('homepage')
4092
+ * .include(['featuredProducts'])
4093
+ * .locale('en')
4094
+ * .fetch()
4095
+ * ```
4096
+ */
4097
+ singleton(key) {
4098
+ return new SingletonClient(this.httpClient, key);
4099
+ }
4100
+ /**
4101
+ * Get a settings client for a specific settings group
4102
+ * Type-safe when schema is provided: autocompletes settings group names AND field names
4103
+ *
4104
+ * @example
4105
+ * ```typescript
4106
+ * const emailConfig = await relyio.settings('email-config')
4107
+ * .include(['defaultTemplate'])
4108
+ * .fetch()
4109
+ * ```
4110
+ */
4111
+ settings(groupId) {
4112
+ return new SettingsClient(this.httpClient, groupId);
4113
+ }
4114
+ // ============================================================================
4115
+ // SEARCH OPERATIONS
4116
+ // ============================================================================
4117
+ /**
4118
+ * Start a search query with full-text, semantic, or hybrid search
4119
+ *
4120
+ * @example
4121
+ * ```typescript
4122
+ * const results = await relyio.search('wireless headphones')
4123
+ * .in('product')
4124
+ * .where({ status: 'active' })
4125
+ * .limit(20)
4126
+ * .includeScore()
4127
+ * .execute()
4128
+ * ```
4129
+ */
4130
+ search(query) {
4131
+ return this._search.search(query);
4132
+ }
4133
+ /**
4134
+ * Start an autocomplete query for search suggestions
4135
+ *
4136
+ * @example
4137
+ * ```typescript
4138
+ * const suggestions = await relyio.autocomplete('wire')
4139
+ * .in('product')
4140
+ * .field('title')
4141
+ * .fuzzy()
4142
+ * .limit(10)
4143
+ * .execute()
4144
+ * ```
4145
+ */
4146
+ autocomplete(query) {
4147
+ return this._search.autocomplete(query);
4148
+ }
4149
+ /**
4150
+ * Find content similar to a given entry using vector search
4151
+ *
4152
+ * @example
4153
+ * ```typescript
4154
+ * const similar = await relyio.similar('entry_abc123')
4155
+ * .in('product')
4156
+ * .locale('fr-FR')
4157
+ * .limit(5)
4158
+ * .execute()
4159
+ * ```
4160
+ */
4161
+ similar(sourceId) {
4162
+ return this._search.similar(sourceId);
4163
+ }
4164
+ // ============================================================================
4165
+ // BATCH OPERATIONS
4166
+ // ============================================================================
4167
+ /**
4168
+ * Start a batch operation for bulk create/update/delete
4169
+ *
4170
+ * @example
4171
+ * ```typescript
4172
+ * const result = await relyio.batch()
4173
+ * .create('product', { content: { title: 'iPhone', price: 999 } })
4174
+ * .update('product', 'entry_abc', { content: { price: 899 } })
4175
+ * .delete('product', 'entry_xyz')
4176
+ * .upsertSingleton('homepage', { content: { hero: 'Welcome!' } })
4177
+ * .execute({ atomic: true })
4178
+ *
4179
+ * console.log(result.summary.succeeded)
4180
+ * ```
4181
+ */
4182
+ batch() {
4183
+ return this._batch.create();
4184
+ }
4185
+ // ============================================================================
4186
+ // QUERY OPERATIONS
4187
+ // ============================================================================
4188
+ /**
4189
+ * Build and execute an ad-hoc query dynamically
4190
+ *
4191
+ * @example
4192
+ * ```typescript
4193
+ * const result = await relyio.adhoc()
4194
+ * .from('product')
4195
+ * .where({ status: 'active' })
4196
+ * .include(['brand', 'categories'])
4197
+ * .select({
4198
+ * id: 'id',
4199
+ * title: 'title',
4200
+ * price: 'pricing.basePrice'
4201
+ * })
4202
+ * .limit(20)
4203
+ * .execute()
4204
+ * ```
4205
+ */
4206
+ adhoc() {
4207
+ return this._adhocQuery.build();
4208
+ }
4209
+ /**
4210
+ * Execute a predefined query by name (from schema)
4211
+ * Type-safe when schema is provided: autocompletes query names
4212
+ *
4213
+ * @example
4214
+ * ```typescript
4215
+ * const featured = await relyio.executeQuery('featured-products', {
4216
+ * limit: 10,
4217
+ * category: 'electronics'
4218
+ * })
4219
+ * ```
4220
+ */
4221
+ async executeQuery(queryName, params) {
4222
+ const response = await this.httpClient.request({
4223
+ method: "GET",
4224
+ url: `/${API_VERSION_SEGMENT}/${String(queryName)}`,
4225
+ params: params ?? {}
4226
+ });
4227
+ const payload = readPayload(response.body);
4228
+ return Array.isArray(payload) ? payload : [payload];
4229
+ }
4230
+ /**
4231
+ * Get schema information from the API
4232
+ */
4233
+ async getSchemaInfo(contentType) {
4234
+ return contentType == null ? this.httpClient.fetchPayload("/v1/meta/schema", "get", {}) : this.httpClient.fetchPayload("/v1/meta/schema/{contentType}", "get", {
4235
+ path: { contentType }
4236
+ });
4237
+ }
4238
+ /**
4239
+ * List all content types from the API
4240
+ */
4241
+ async listContentTypes() {
4242
+ return this.httpClient.fetchPayload("/v1/meta/content-types", "get", {});
4243
+ }
4244
+ /**
4245
+ * Get API health status
4246
+ */
4247
+ async health() {
4248
+ return this.httpClient.fetchPayload("/health", "get", {});
4249
+ }
4250
+ /**
4251
+ * Check if the API is ready
4252
+ */
4253
+ async ready() {
4254
+ try {
4255
+ const payload = await this.httpClient.fetchPayload("/health/ready", "get", {});
4256
+ return payload.status === "ok";
4257
+ } catch {
4258
+ return false;
4259
+ }
4260
+ }
4261
+ /**
4262
+ * Test the connection to the API
4263
+ */
4264
+ async testConnection() {
4265
+ try {
4266
+ await this.health();
4267
+ return true;
4268
+ } catch {
4269
+ return false;
4270
+ }
4271
+ }
4272
+ /**
4273
+ * Update the configuration and reinitialize all clients
4274
+ */
4275
+ updateConfig(newConfig) {
4276
+ this.config = mergeConfig({ ...this.config, ...newConfig });
4277
+ this.httpClient = new HttpClient(this.config);
4278
+ this._search = new SearchClient(this.httpClient);
4279
+ this._batch = new BatchClient(this.httpClient);
4280
+ this._adhocQuery = new AdhocQueryClient(this.httpClient);
4281
+ }
4282
+ /**
4283
+ * Get the current configuration
4284
+ */
4285
+ getConfig() {
4286
+ return { ...this.config };
4287
+ }
4288
+ /**
4289
+ * Set the API key
4290
+ */
4291
+ setApiKey(apiKey) {
4292
+ this.config.apiKey = apiKey;
4293
+ this.httpClient.setAuthToken(apiKey);
4294
+ }
4295
+ /**
4296
+ * Get the HTTP client instance (for advanced usage)
4297
+ */
4298
+ getHttpClient() {
4299
+ return this.httpClient;
4300
+ }
4301
+ // ============================================================================
4302
+ // LOCALE OPERATIONS
4303
+ // ============================================================================
4304
+ /**
4305
+ * Create a locale-scoped client
4306
+ * All content operations on the returned client will use the specified locale
4307
+ *
4308
+ * Type-safe when schema is provided: autocompletes valid locale codes!
4309
+ *
4310
+ * @example
4311
+ * ```typescript
4312
+ * const spanish = relyio.withLocale('es-ES') // ← Autocompletes with schema!
4313
+ *
4314
+ * // All operations use Spanish
4315
+ * const products = await spanish.content('product').query().execute()
4316
+ * const homepage = await spanish.singleton('homepage').fetch()
4317
+ *
4318
+ * // Original client unchanged
4319
+ * const englishProducts = await relyio.content('product').query().execute()
4320
+ * ```
4321
+ */
4322
+ withLocale(locale) {
4323
+ const newConfig = {
4324
+ ...this.getConfig(),
4325
+ locale,
4326
+ schema: this._schema
4327
+ };
4328
+ return new _TypedRelyIOClient(newConfig);
4329
+ }
4330
+ /**
4331
+ * Get the current default locale
4332
+ */
4333
+ getLocale() {
4334
+ return this.config.locale;
4335
+ }
4336
+ /**
4337
+ * Get available locales from the API
4338
+ *
4339
+ * @example
4340
+ * ```typescript
4341
+ * const { locales, defaultLocale } = await relyio.getLocales()
4342
+ *
4343
+ * // Build language switcher
4344
+ * const options = locales.map(l => ({
4345
+ * code: l.code,
4346
+ * label: l.displayName,
4347
+ * isDefault: l.default,
4348
+ * }))
4349
+ * ```
4350
+ */
4351
+ async getLocales(search) {
4352
+ const params = {};
4353
+ if (search !== void 0 && search !== "") {
4354
+ params.search = search;
4355
+ }
4356
+ return this.httpClient.fetchPayload("/v1/meta/locales", "get", { query: params });
4357
+ }
4358
+ /**
4359
+ * Get the default locale from the API
4360
+ */
4361
+ async getDefaultLocale() {
4362
+ const { defaultLocale } = await this.getLocales();
4363
+ return defaultLocale;
4364
+ }
4365
+ };
4366
+ __name(_TypedRelyIOClient, "TypedRelyIOClient");
4367
+ var TypedRelyIOClient = _TypedRelyIOClient;
4368
+ function createClient(config) {
4369
+ return new TypedRelyIOClient(config);
4370
+ }
4371
+ __name(createClient, "createClient");
4372
+
4373
+ export { AdhocQueryBuilder, AdhocQueryClient, AssetClient, AssetFileBuilder, AssetUploadBuilder, AuthenticationError, AuthorizationError, AutocompleteBuilder, BaseValidationError, BatchBuilder, BatchClient, ConnectionError, ContentByIdBuilder, ContentClient, ContentQueryBuilder, ErrorMapper, FileUploadError, FileValidationError, HttpClient, InvalidApiKeyError, InvalidFieldTypeError, InvalidPayloadError, MethodNotAllowedError, MissingApiKeyError, NetworkError, PayloadTooLargeError, PlanFeatureUnavailableError, RateLimitError, ReadOnlyKeyError, RequiredFieldError, ResourceConflictError, ResourceExpiredError, ResourceNotFoundError, SDKError, SchemaValidationError, SearchBuilder, SearchClient, ServerError, ServiceIndeterminateError, SettingsClient, SimilarBuilder, SingletonClient, TimeoutError, TransactionRolledBackError, TypedRelyIOClient, UnknownContractError, UsageQuotaExceededError, ValidationError, createClient, entityTagOf, isAssetEntry, isResourceNotFound, validateFile };
4374
+ //# sourceMappingURL=chunk-RJBIJ2ZK.js.map
4375
+ //# sourceMappingURL=chunk-RJBIJ2ZK.js.map