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