@8ux-co/eelzap 0.0.0-stage → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,2055 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __typeError = (msg) => {
7
+ throw TypeError(msg);
8
+ };
9
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
23
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
24
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
25
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
26
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
27
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
28
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ CollectionFieldsResource: () => CollectionFieldsResource,
34
+ CollectionSectionsResource: () => CollectionSectionsResource,
35
+ CollectionsResource: () => CollectionsResource,
36
+ CommentsResource: () => CommentsResource,
37
+ DocumentFieldsResource: () => DocumentFieldsResource,
38
+ DocumentSectionsResource: () => DocumentSectionsResource,
39
+ DocumentSeoResource: () => DocumentSeoResource,
40
+ DocumentValuesResource: () => DocumentValuesResource,
41
+ DocumentVersionsResource: () => DocumentVersionsResource,
42
+ DocumentsResource: () => DocumentsResource,
43
+ EelZapClient: () => EelZapClient,
44
+ EelZapError: () => EelZapError,
45
+ EelZapNetworkError: () => EelZapNetworkError,
46
+ ItemQueryBuilder: () => ItemQueryBuilder,
47
+ ItemSeoResource: () => ItemSeoResource,
48
+ ItemVersionsResource: () => ItemVersionsResource,
49
+ ItemsResource: () => ItemsResource,
50
+ MediaResource: () => MediaResource,
51
+ MemoryCacheAdapter: () => MemoryCacheAdapter,
52
+ PreviewTokensResource: () => PreviewTokensResource,
53
+ SiteResource: () => SiteResource,
54
+ SitesResource: () => SitesResource,
55
+ WEBHOOK_SIGNATURE_HEADER: () => WEBHOOK_SIGNATURE_HEADER,
56
+ WEBHOOK_TIMESTAMP_HEADER: () => WEBHOOK_TIMESTAMP_HEADER,
57
+ WEBHOOK_TOLERANCE_SECONDS: () => WEBHOOK_TOLERANCE_SECONDS,
58
+ cachedFetch: () => cachedFetch,
59
+ cleanStega: () => cleanStega,
60
+ createClient: () => createClient,
61
+ getMediaUrl: () => getMediaUrl,
62
+ hasStega: () => hasStega,
63
+ isEelZapError: () => isEelZapError,
64
+ verifyWebhookSignature: () => verifyWebhookSignature,
65
+ webhookChanges: () => webhookChanges
66
+ });
67
+ module.exports = __toCommonJS(src_exports);
68
+
69
+ // src/utils.ts
70
+ function normalizeBaseUrl(baseUrl) {
71
+ return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
72
+ }
73
+ function isPreviewToken(apiKey) {
74
+ return apiKey.trim().startsWith("zpt_");
75
+ }
76
+ function previewParam(options) {
77
+ return options.preview ? options.stega === false ? { preview: 1, stega: 0 } : { preview: 1 } : {};
78
+ }
79
+ function markPreview(value) {
80
+ if (value && typeof value === "object") {
81
+ Object.defineProperty(value, /* @__PURE__ */ Symbol.for("eelzap.preview"), { value: true });
82
+ }
83
+ return value;
84
+ }
85
+ function isPreviewResult(value) {
86
+ return !!value && typeof value === "object" && value[/* @__PURE__ */ Symbol.for("eelzap.preview")] === true;
87
+ }
88
+ function newIdempotencyKey() {
89
+ const crypto = globalThis.crypto;
90
+ return crypto?.randomUUID ? crypto.randomUUID() : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
91
+ }
92
+ function toArrayParam(values) {
93
+ return values && values.length > 0 ? values.join(",") : void 0;
94
+ }
95
+ function mergeRequestOptions(defaults, options) {
96
+ return {
97
+ ...defaults,
98
+ ...options
99
+ };
100
+ }
101
+ function cleanParams(params) {
102
+ return Object.fromEntries(
103
+ Object.entries(params).flatMap(([key, value]) => {
104
+ return value === void 0 ? [] : [[key, String(value)]];
105
+ })
106
+ );
107
+ }
108
+ function normalizeHeaderValue(value) {
109
+ if (value === void 0) {
110
+ return void 0;
111
+ }
112
+ if (value === null) {
113
+ return void 0;
114
+ }
115
+ const trimmed = value.trim();
116
+ return trimmed.length > 0 ? trimmed : void 0;
117
+ }
118
+ function isOperatorMap(value) {
119
+ return typeof value === "object" && !Array.isArray(value);
120
+ }
121
+ function serializeFilters(filters) {
122
+ if (!filters) {
123
+ return {};
124
+ }
125
+ return Object.entries(filters).reduce((acc, [field, value]) => {
126
+ if (!isOperatorMap(value)) {
127
+ acc[`filter[${field}]`] = String(value);
128
+ return acc;
129
+ }
130
+ for (const [operator, operatorValue] of Object.entries(value)) {
131
+ if (operatorValue === void 0) {
132
+ continue;
133
+ }
134
+ const serializedValue = Array.isArray(operatorValue) ? operatorValue.join(",") : String(operatorValue);
135
+ acc[`filter[${field}][${operator}]`] = serializedValue;
136
+ }
137
+ return acc;
138
+ }, {});
139
+ }
140
+ function maskApiKey(apiKey) {
141
+ if (apiKey.length <= 8) {
142
+ return "***";
143
+ }
144
+ return `${apiKey.slice(0, 4)}...${apiKey.slice(-4)}`;
145
+ }
146
+
147
+ // src/cache.ts
148
+ var _store;
149
+ var MemoryCacheAdapter = class {
150
+ constructor() {
151
+ __privateAdd(this, _store, /* @__PURE__ */ new Map());
152
+ }
153
+ get(key) {
154
+ return __privateGet(this, _store).get(key);
155
+ }
156
+ set(key, value) {
157
+ __privateGet(this, _store).set(key, value);
158
+ }
159
+ /** Returns the number of cached entries. */
160
+ get size() {
161
+ return __privateGet(this, _store).size;
162
+ }
163
+ /** Removes a specific key from the cache. */
164
+ delete(key) {
165
+ return __privateGet(this, _store).delete(key);
166
+ }
167
+ /** Removes all cached entries. */
168
+ clear() {
169
+ __privateGet(this, _store).clear();
170
+ }
171
+ };
172
+ _store = new WeakMap();
173
+ async function cachedFetch(keyOrOptions, fetcher, adapter) {
174
+ const options = typeof keyOrOptions === "string" ? {
175
+ key: keyOrOptions,
176
+ fetcher,
177
+ adapter,
178
+ strategy: "network-first"
179
+ } : {
180
+ ...keyOrOptions,
181
+ strategy: keyOrOptions.strategy ?? "network-first"
182
+ };
183
+ if (options.strategy === "cache-first") {
184
+ const cached = await options.adapter.get(options.key);
185
+ if (cached !== void 0) {
186
+ return cached;
187
+ }
188
+ return store(options.adapter, options.key, await options.fetcher());
189
+ }
190
+ try {
191
+ return await store(options.adapter, options.key, await options.fetcher());
192
+ } catch (error) {
193
+ const cached = await options.adapter.get(options.key);
194
+ if (cached !== void 0) {
195
+ return cached;
196
+ }
197
+ throw error;
198
+ }
199
+ }
200
+ async function store(adapter, key, result) {
201
+ if (!isPreviewResult(result)) await adapter.set(key, result);
202
+ return result;
203
+ }
204
+
205
+ // src/errors.ts
206
+ var EelZapError = class extends Error {
207
+ constructor(code, message, status, details = []) {
208
+ super(message);
209
+ __publicField(this, "code");
210
+ __publicField(this, "status");
211
+ /** Per-field problems when the API refused the input; empty otherwise. */
212
+ __publicField(this, "details");
213
+ this.name = "EelZapError";
214
+ this.code = code;
215
+ this.status = status;
216
+ this.details = details;
217
+ }
218
+ };
219
+ var EelZapNetworkError = class extends EelZapError {
220
+ constructor(cause, message = "Network request failed.") {
221
+ super("NETWORK_ERROR", message, 0);
222
+ __publicField(this, "cause");
223
+ this.name = "EelZapNetworkError";
224
+ this.cause = cause;
225
+ }
226
+ };
227
+ function isEelZapError(error) {
228
+ return error instanceof EelZapError;
229
+ }
230
+
231
+ // src/paths.ts
232
+ function trimSlashes(value) {
233
+ return value.replace(/^\/+|\/+$/g, "");
234
+ }
235
+ function buildResourcePath(...segments) {
236
+ const normalized = segments.map(trimSlashes).filter((segment) => segment.length > 0);
237
+ return `/${normalized.join("/")}`;
238
+ }
239
+ function normalizePathPrefix(pathPrefix) {
240
+ const trimmed = trimSlashes(pathPrefix);
241
+ return trimmed.length > 0 ? `${trimmed}/` : "";
242
+ }
243
+
244
+ // src/retry.ts
245
+ function resolveRetry(retry) {
246
+ if (retry === false) return null;
247
+ const options = retry === true || retry === void 0 ? {} : retry;
248
+ const resolved = {
249
+ retries: options.retries ?? 3,
250
+ maxDelayMs: options.maxDelayMs ?? 6e4,
251
+ baseDelayMs: options.baseDelayMs ?? 500,
252
+ onRetry: options.onRetry
253
+ };
254
+ return resolved.retries > 0 ? resolved : null;
255
+ }
256
+ function isRepeatable(method, headers, body) {
257
+ if (method === "GET" || method === "HEAD") return true;
258
+ return headers.has("Idempotency-Key") && (body == null || typeof body === "string");
259
+ }
260
+ function parseRetryAfter(value, now) {
261
+ if (value === null) return null;
262
+ const trimmed = value.trim();
263
+ if (/^\d+$/.test(trimmed)) return Number(trimmed) * 1e3;
264
+ const date = Date.parse(trimmed);
265
+ return Number.isNaN(date) ? null : Math.max(0, date - now);
266
+ }
267
+ function retryDelay(response, attempt, options, now = Date.now(), random = Math.random) {
268
+ if (attempt > options.retries) return null;
269
+ if (response.status !== 429 && response.status !== 503) return null;
270
+ const retryAfter = parseRetryAfter(response.headers.get("Retry-After"), now);
271
+ if (retryAfter !== null) {
272
+ if (retryAfter > options.maxDelayMs) return null;
273
+ return Math.min(options.maxDelayMs, retryAfter + Math.floor(random() * 1e3));
274
+ }
275
+ if (response.status === 503) return null;
276
+ const step = Math.min(options.maxDelayMs, options.baseDelayMs * 2 ** (attempt - 1));
277
+ return Math.floor(step / 2 + random() * (step / 2));
278
+ }
279
+
280
+ // src/http.ts
281
+ var _config, _HttpClient_instances, request_fn, read_fn, withJsonBody_fn;
282
+ var HttpClient = class {
283
+ constructor(config) {
284
+ __privateAdd(this, _HttpClient_instances);
285
+ __privateAdd(this, _config);
286
+ __privateSet(this, _config, config);
287
+ }
288
+ async get(path, options) {
289
+ return __privateMethod(this, _HttpClient_instances, request_fn).call(this, "GET", path, options);
290
+ }
291
+ async post(path, body, options) {
292
+ return __privateMethod(this, _HttpClient_instances, request_fn).call(this, "POST", path, __privateMethod(this, _HttpClient_instances, withJsonBody_fn).call(this, body, options));
293
+ }
294
+ async patch(path, body, options) {
295
+ return __privateMethod(this, _HttpClient_instances, request_fn).call(this, "PATCH", path, __privateMethod(this, _HttpClient_instances, withJsonBody_fn).call(this, body, options));
296
+ }
297
+ async put(path, body, options) {
298
+ return __privateMethod(this, _HttpClient_instances, request_fn).call(this, "PUT", path, __privateMethod(this, _HttpClient_instances, withJsonBody_fn).call(this, body, options));
299
+ }
300
+ async delete(path, body, options) {
301
+ return __privateMethod(this, _HttpClient_instances, request_fn).call(this, "DELETE", path, __privateMethod(this, _HttpClient_instances, withJsonBody_fn).call(this, body, options));
302
+ }
303
+ async upload(url, body, headers) {
304
+ const controller = new AbortController();
305
+ const timeoutId = setTimeout(() => {
306
+ controller.abort();
307
+ }, __privateGet(this, _config).timeout);
308
+ try {
309
+ const response = await __privateGet(this, _config).fetch(url, {
310
+ method: "PUT",
311
+ body,
312
+ headers,
313
+ signal: controller.signal
314
+ });
315
+ if (!response.ok) {
316
+ throw await this.toEelZapError(response);
317
+ }
318
+ } catch (error) {
319
+ if (error instanceof EelZapError) {
320
+ throw error;
321
+ }
322
+ throw new EelZapNetworkError(
323
+ error,
324
+ error instanceof Error ? error.message : "Network request failed."
325
+ );
326
+ } finally {
327
+ clearTimeout(timeoutId);
328
+ }
329
+ }
330
+ async request(path, options) {
331
+ return this.get(path, options);
332
+ }
333
+ async toEelZapError(response) {
334
+ const contentType = response.headers.get("Content-Type") ?? "";
335
+ if (contentType.includes("application/json")) {
336
+ const payload = await response.json();
337
+ const code = payload.error?.code ?? "INTERNAL_ERROR";
338
+ const message = payload.error?.message ?? `Request failed with status ${String(response.status)}.`;
339
+ const status = payload.error?.status ?? response.status;
340
+ const details = Array.isArray(payload.error?.details) ? payload.error.details : [];
341
+ return new EelZapError(code, message, status, details);
342
+ }
343
+ return new EelZapError(
344
+ "INTERNAL_ERROR",
345
+ `Request failed with status ${String(response.status)}.`,
346
+ response.status
347
+ );
348
+ }
349
+ };
350
+ _config = new WeakMap();
351
+ _HttpClient_instances = new WeakSet();
352
+ request_fn = async function(method, path, options) {
353
+ const prefix = normalizePathPrefix(__privateGet(this, _config).pathPrefix);
354
+ const normalizedPath = path.replace(/^\/+/, "");
355
+ const url = new URL(`${prefix}${normalizedPath}`, __privateGet(this, _config).baseUrl);
356
+ for (const [key, value] of Object.entries(cleanParams(options?.params ?? {}))) {
357
+ url.searchParams.set(key, value);
358
+ }
359
+ const headers = new Headers(__privateGet(this, _config).defaultHeaders);
360
+ for (const [key, value] of new Headers(options?.headers).entries()) {
361
+ headers.set(key, value);
362
+ }
363
+ headers.set("Authorization", `Bearer ${__privateGet(this, _config).apiKey}`);
364
+ if (options?.contentType) {
365
+ headers.set("Content-Type", options.contentType);
366
+ } else if (!headers.has("Content-Type") && options?.body !== void 0) {
367
+ headers.set("Content-Type", "application/json");
368
+ }
369
+ const retry = __privateGet(this, _config).retry;
370
+ const repeatable = retry ? isRepeatable(method, headers, options?.body) : false;
371
+ for (let attempt = 1; ; attempt++) {
372
+ const controller = new AbortController();
373
+ const timeoutId = setTimeout(() => {
374
+ controller.abort();
375
+ }, __privateGet(this, _config).timeout);
376
+ let delayMs;
377
+ let status;
378
+ try {
379
+ const response = await __privateGet(this, _config).fetch(url.toString(), {
380
+ method,
381
+ body: options?.body,
382
+ headers,
383
+ signal: controller.signal
384
+ });
385
+ delayMs = repeatable && retry ? retryDelay(response, attempt, retry) : null;
386
+ if (delayMs === null) {
387
+ return await __privateMethod(this, _HttpClient_instances, read_fn).call(this, url, response);
388
+ }
389
+ status = response.status;
390
+ await response.body?.cancel().catch(() => void 0);
391
+ } catch (error) {
392
+ if (error instanceof EelZapError) {
393
+ throw error;
394
+ }
395
+ throw new EelZapNetworkError(
396
+ error,
397
+ error instanceof Error ? error.message : "Network request failed."
398
+ );
399
+ } finally {
400
+ clearTimeout(timeoutId);
401
+ }
402
+ retry?.onRetry?.({ attempt, delayMs, status, method, url: url.toString() });
403
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
404
+ }
405
+ };
406
+ read_fn = async function(url, response) {
407
+ if (response.status === 304 || response.status === 204) {
408
+ return void 0;
409
+ }
410
+ if (!response.ok) {
411
+ throw await this.toEelZapError(response);
412
+ }
413
+ const data = await response.json();
414
+ return url.searchParams.get("preview") === "1" || isPreviewToken(__privateGet(this, _config).apiKey) ? markPreview(data) : data;
415
+ };
416
+ withJsonBody_fn = function(body, options) {
417
+ if (body === void 0) {
418
+ return options;
419
+ }
420
+ return {
421
+ ...options,
422
+ body: JSON.stringify(body),
423
+ contentType: "application/json"
424
+ };
425
+ };
426
+
427
+ // src/resources/resource-helpers.ts
428
+ function normalizeFieldInput(input) {
429
+ if (input.label || !input.name) {
430
+ return input;
431
+ }
432
+ return {
433
+ ...input,
434
+ label: input.name
435
+ };
436
+ }
437
+ function toDeleteBody(options) {
438
+ if (!options?.deleteMediaIds || options.deleteMediaIds.length === 0) {
439
+ return void 0;
440
+ }
441
+ return {
442
+ deleteMediaIds: options.deleteMediaIds
443
+ };
444
+ }
445
+ function idempotent(options) {
446
+ return { headers: { "Idempotency-Key": options?.idempotencyKey ?? newIdempotencyKey() } };
447
+ }
448
+
449
+ // src/resources/collection-fields.ts
450
+ var _http;
451
+ var CollectionFieldsResource = class {
452
+ /**
453
+ * @internal
454
+ */
455
+ constructor(http) {
456
+ __privateAdd(this, _http);
457
+ __privateSet(this, _http, http);
458
+ }
459
+ /**
460
+ * Lists all fields in a collection.
461
+ */
462
+ async list(collectionKey) {
463
+ const response = await __privateGet(this, _http).get(
464
+ buildResourcePath("collections", collectionKey, "fields")
465
+ );
466
+ return response.fields;
467
+ }
468
+ /**
469
+ * Creates a field in a collection.
470
+ *
471
+ * Sends an `Idempotency-Key` (required of suite bearers): a fresh one per
472
+ * call, or `options.idempotencyKey` to make your own retry safe.
473
+ */
474
+ async create(collectionKey, input, options) {
475
+ const response = await __privateGet(this, _http).post(
476
+ buildResourcePath("collections", collectionKey, "fields"),
477
+ normalizeFieldInput(input),
478
+ idempotent(options)
479
+ );
480
+ return response.field;
481
+ }
482
+ /**
483
+ * Updates a field in a collection.
484
+ */
485
+ async update(collectionKey, fieldId, input) {
486
+ const response = await __privateGet(this, _http).patch(
487
+ buildResourcePath("collections", collectionKey, "fields", fieldId),
488
+ normalizeFieldInput(input)
489
+ );
490
+ return response.field;
491
+ }
492
+ /**
493
+ * Deletes a field from a collection.
494
+ */
495
+ async delete(collectionKey, fieldId) {
496
+ return __privateGet(this, _http).delete(
497
+ buildResourcePath("collections", collectionKey, "fields", fieldId)
498
+ );
499
+ }
500
+ /**
501
+ * Lists the collection's archived (soft-deleted) fields, most recently
502
+ * deleted first. Their values are kept, which is what makes `restore` work.
503
+ *
504
+ * `GET /collections/{collectionKey}/fields/deleted`. Secret key, or suite
505
+ * bearer with `zap:content:read`.
506
+ */
507
+ async listDeleted(collectionKey) {
508
+ const response = await __privateGet(this, _http).get(
509
+ buildResourcePath("collections", collectionKey, "fields", "deleted")
510
+ );
511
+ return response.fields;
512
+ }
513
+ /**
514
+ * Brings an archived field back with every value it held, at the end of the
515
+ * root list (outside any section).
516
+ *
517
+ * `POST /collections/{collectionKey}/fields/{fieldId}/restore`. Secret key,
518
+ * or suite bearer with `zap:schema:write` and the Zap ADMIN role.
519
+ */
520
+ async restore(collectionKey, fieldId) {
521
+ const response = await __privateGet(this, _http).post(
522
+ buildResourcePath("collections", collectionKey, "fields", fieldId, "restore")
523
+ );
524
+ return response.field;
525
+ }
526
+ /**
527
+ * Reorders collection fields.
528
+ */
529
+ async reorder(collectionKey, fieldIds) {
530
+ return __privateGet(this, _http).put(
531
+ buildResourcePath("collections", collectionKey, "fields", "reorder"),
532
+ { fieldIds }
533
+ );
534
+ }
535
+ };
536
+ _http = new WeakMap();
537
+
538
+ // src/resources/collection-sections.ts
539
+ var _http2;
540
+ var CollectionSectionsResource = class {
541
+ /**
542
+ * @internal
543
+ */
544
+ constructor(http) {
545
+ __privateAdd(this, _http2);
546
+ __privateSet(this, _http2, http);
547
+ }
548
+ /**
549
+ * Lists all sections in a collection.
550
+ */
551
+ async list(collectionKey) {
552
+ const response = await __privateGet(this, _http2).get(
553
+ buildResourcePath("collections", collectionKey, "sections")
554
+ );
555
+ return response.sections;
556
+ }
557
+ /**
558
+ * Gets a single section from a collection.
559
+ */
560
+ async get(collectionKey, sectionId) {
561
+ const response = await __privateGet(this, _http2).get(
562
+ buildResourcePath("collections", collectionKey, "sections", sectionId)
563
+ );
564
+ return response.section;
565
+ }
566
+ /**
567
+ * Creates a section in a collection.
568
+ *
569
+ * Sends an `Idempotency-Key` (required of suite bearers): a fresh one per
570
+ * call, or `options.idempotencyKey` to make your own retry safe.
571
+ */
572
+ async create(collectionKey, input, options) {
573
+ const response = await __privateGet(this, _http2).post(
574
+ buildResourcePath("collections", collectionKey, "sections"),
575
+ input,
576
+ idempotent(options)
577
+ );
578
+ return response.section;
579
+ }
580
+ /**
581
+ * Updates a section in a collection.
582
+ */
583
+ async update(collectionKey, sectionId, input) {
584
+ const response = await __privateGet(this, _http2).patch(
585
+ buildResourcePath("collections", collectionKey, "sections", sectionId),
586
+ input
587
+ );
588
+ return response.section;
589
+ }
590
+ /**
591
+ * Deletes a section from a collection.
592
+ */
593
+ async delete(collectionKey, sectionId) {
594
+ return __privateGet(this, _http2).delete(
595
+ buildResourcePath("collections", collectionKey, "sections", sectionId)
596
+ );
597
+ }
598
+ };
599
+ _http2 = new WeakMap();
600
+
601
+ // src/resources/collections.ts
602
+ var _http3, _defaults;
603
+ var CollectionsResource = class {
604
+ /**
605
+ * @internal
606
+ */
607
+ constructor(http, defaults) {
608
+ __publicField(this, "fields");
609
+ __publicField(this, "sections");
610
+ __privateAdd(this, _http3);
611
+ __privateAdd(this, _defaults);
612
+ __privateSet(this, _http3, http);
613
+ __privateSet(this, _defaults, defaults);
614
+ this.fields = new CollectionFieldsResource(http);
615
+ this.sections = new CollectionSectionsResource(http);
616
+ }
617
+ /**
618
+ * Lists all collections available to the current API key.
619
+ */
620
+ async list(options) {
621
+ return __privateGet(this, _http3).get(buildResourcePath("collections"), {
622
+ params: {
623
+ status: options?.status ?? __privateGet(this, _defaults).status
624
+ }
625
+ });
626
+ }
627
+ /**
628
+ * Retrieves the schema for a single collection.
629
+ */
630
+ async get(collectionKey, options) {
631
+ return __privateGet(this, _http3).get(buildResourcePath("collections", collectionKey), {
632
+ params: {
633
+ status: options?.status ?? __privateGet(this, _defaults).status
634
+ }
635
+ });
636
+ }
637
+ /**
638
+ * Creates a collection.
639
+ *
640
+ * Sends an `Idempotency-Key` (required of suite bearers): a fresh one per
641
+ * call, or `options.idempotencyKey` to make your own retry safe.
642
+ */
643
+ async create(input, options) {
644
+ const response = await __privateGet(this, _http3).post(
645
+ buildResourcePath("collections"),
646
+ input,
647
+ idempotent(options)
648
+ );
649
+ return response.collection;
650
+ }
651
+ /**
652
+ * Updates a collection.
653
+ */
654
+ async update(collectionKey, input) {
655
+ const response = await __privateGet(this, _http3).patch(
656
+ buildResourcePath("collections", collectionKey),
657
+ input
658
+ );
659
+ return response.collection;
660
+ }
661
+ /**
662
+ * Deletes a collection.
663
+ */
664
+ async delete(collectionKey, options) {
665
+ return __privateGet(this, _http3).delete(
666
+ buildResourcePath("collections", collectionKey),
667
+ toDeleteBody(options)
668
+ );
669
+ }
670
+ };
671
+ _http3 = new WeakMap();
672
+ _defaults = new WeakMap();
673
+
674
+ // src/resources/comments.ts
675
+ var _http4;
676
+ var CommentsResource = class {
677
+ /**
678
+ * @internal
679
+ */
680
+ constructor(http) {
681
+ __privateAdd(this, _http4);
682
+ __privateSet(this, _http4, http);
683
+ }
684
+ /**
685
+ * Lists the site's threads, newest first, optionally on one record (an
686
+ * entry by `collection` + `slug`, or a `document`). `counts` covers both
687
+ * statuses whatever `status` filters.
688
+ *
689
+ * `GET /comments`.
690
+ */
691
+ async list(options) {
692
+ return __privateGet(this, _http4).get("/comments", {
693
+ // Named one by one: the route's query is strict, so a stray key would be a 400.
694
+ params: {
695
+ collection: options?.collection,
696
+ slug: options?.slug,
697
+ document: options?.document,
698
+ isChangeRequest: options?.isChangeRequest,
699
+ status: options?.status,
700
+ resolution: options?.resolution,
701
+ pageUrl: options?.pageUrl,
702
+ assignee: options?.assignee,
703
+ page: options?.page,
704
+ pageSize: options?.pageSize
705
+ }
706
+ });
707
+ }
708
+ /**
709
+ * Retrieves a thread and its comments, oldest first.
710
+ *
711
+ * `GET /comments/{id}`.
712
+ */
713
+ async get(id) {
714
+ return __privateGet(this, _http4).get(buildResourcePath("comments", id));
715
+ }
716
+ /**
717
+ * Opens a thread with its first comment. Anchors and proposed values name
718
+ * fields by key. Sends an `Idempotency-Key`. 404 for an unknown record, 422
719
+ * `INVALID_ANCHOR` / `INVALID_PROPOSED_VALUE` / `ASSIGNEE_NO_SEAT`, 429
720
+ * `RATE_LIMITED`.
721
+ *
722
+ * `POST /comments`.
723
+ *
724
+ * @example
725
+ * ```ts
726
+ * await zap.comments.create({
727
+ * collection: 'blog',
728
+ * slug: 'hello-world',
729
+ * isChangeRequest: true,
730
+ * body: 'Shorter title?',
731
+ * proposedValues: [{ fieldKey: 'title', value: 'Hello' }],
732
+ * })
733
+ * ```
734
+ */
735
+ async create(input, options) {
736
+ return __privateGet(this, _http4).post("/comments", input, idempotent(options));
737
+ }
738
+ /**
739
+ * Changes a thread: `status` (resolve, reopen), a change request's
740
+ * `resolution`, the `isChangeRequest` flag, the assignee, or the first
741
+ * comment's text. 409 `STATUS_CONFLICT`, `INVALID_TRANSITION`,
742
+ * `HAS_PROPOSAL`; 422 `NOT_A_CHANGE_REQUEST`, `HAS_LINKED_TASKS` (turning
743
+ * the flag off while a Swarm task is linked).
744
+ *
745
+ * `PATCH /comments/{id}`.
746
+ */
747
+ async update(id, input) {
748
+ return __privateGet(this, _http4).patch(buildResourcePath("comments", id), input);
749
+ }
750
+ /**
751
+ * Replies on a thread. Sends an `Idempotency-Key`.
752
+ *
753
+ * `POST /comments/{id}/replies`.
754
+ */
755
+ async reply(id, input, options) {
756
+ return __privateGet(this, _http4).post(
757
+ buildResourcePath("comments", id, "replies"),
758
+ input,
759
+ idempotent(options)
760
+ );
761
+ }
762
+ /**
763
+ * «Aplicar al borrador»: writes an open change request's proposed values
764
+ * into the record's draft and resolves it as APPLIED. 409 `NO_PROPOSAL` /
765
+ * `NOT_OPEN`.
766
+ *
767
+ * `POST /comments/{id}/apply`.
768
+ */
769
+ async apply(id) {
770
+ return __privateGet(this, _http4).post(buildResourcePath("comments", id, "apply"));
771
+ }
772
+ /**
773
+ * Writes proposed values straight into the record's draft, recorded as a
774
+ * change request already resolved as APPLIED; nobody is notified. 403 when
775
+ * the site has live editing off. Sends an `Idempotency-Key`.
776
+ *
777
+ * `POST /comments/save-to-draft`.
778
+ */
779
+ async saveToDraft(input, options) {
780
+ return __privateGet(this, _http4).post(
781
+ buildResourcePath("comments", "save-to-draft"),
782
+ input,
783
+ idempotent(options)
784
+ );
785
+ }
786
+ /**
787
+ * What the site's suggestion client shows on one page: the viewer, whether
788
+ * live editing is on, the field types of the records tagged there and the
789
+ * page's open threads. `refs` are `data-zap-ref` values (`collection/slug`
790
+ * or `doc:key`); at most 20 are read.
791
+ *
792
+ * `GET /comments/on-page`. Answers only the site's own suggestion client.
793
+ */
794
+ async onPage(url, refs = []) {
795
+ return __privateGet(this, _http4).get(buildResourcePath("comments", "on-page"), {
796
+ params: { url, refs: refs.length > 0 ? refs.join(",") : void 0 }
797
+ });
798
+ }
799
+ };
800
+ _http4 = new WeakMap();
801
+
802
+ // src/resources/document-versions.ts
803
+ var _http5;
804
+ var DocumentVersionsResource = class {
805
+ /** @internal */
806
+ constructor(http) {
807
+ __privateAdd(this, _http5);
808
+ __privateSet(this, _http5, http);
809
+ }
810
+ /**
811
+ * Lists a document's versions, newest first.
812
+ */
813
+ async list(documentKey) {
814
+ return __privateGet(this, _http5).get(
815
+ buildResourcePath("documents", documentKey, "versions")
816
+ );
817
+ }
818
+ /**
819
+ * Gets one version with its snapshot (values and SEO).
820
+ */
821
+ async get(documentKey, versionId) {
822
+ const response = await __privateGet(this, _http5).get(
823
+ buildResourcePath("documents", documentKey, "versions", versionId)
824
+ );
825
+ return response.version;
826
+ }
827
+ /**
828
+ * Opens a draft from the document's live state. Fails with `DUPLICATE_KEY`
829
+ * (409) when the document already has one.
830
+ */
831
+ async createDraft(documentKey, input) {
832
+ const response = await __privateGet(this, _http5).post(
833
+ buildResourcePath("documents", documentKey, "versions"),
834
+ input
835
+ );
836
+ return response.version;
837
+ }
838
+ /**
839
+ * Stages values on the open draft without touching the live document.
840
+ * Fails with `VALIDATION_ERROR` (400) when there is no open draft.
841
+ */
842
+ async updateDraft(documentKey, input) {
843
+ const response = await __privateGet(this, _http5).put(
844
+ buildResourcePath("documents", documentKey, "versions", "draft"),
845
+ input
846
+ );
847
+ return response.version;
848
+ }
849
+ /**
850
+ * Discards the open draft. Fails with `NOT_FOUND` (404) when there is none.
851
+ */
852
+ async discardDraft(documentKey) {
853
+ await __privateGet(this, _http5).delete(
854
+ buildResourcePath("documents", documentKey, "versions", "draft")
855
+ );
856
+ }
857
+ /**
858
+ * Publishes the open draft: its values go live and it becomes the
859
+ * document's published version. Fails with `NOT_FOUND` (404) when there is
860
+ * no draft.
861
+ */
862
+ async publishDraft(documentKey) {
863
+ const response = await __privateGet(this, _http5).post(
864
+ buildResourcePath("documents", documentKey, "versions", "draft", "publish")
865
+ );
866
+ return response.version;
867
+ }
868
+ /**
869
+ * Restores a past version over the live document and records the restore
870
+ * as a NEW published version (history is never rewritten). Refused (409)
871
+ * for a draft version, or while the document has an open draft.
872
+ */
873
+ async rollback(documentKey, versionId) {
874
+ const response = await __privateGet(this, _http5).post(
875
+ buildResourcePath("documents", documentKey, "versions", versionId, "rollback")
876
+ );
877
+ return response.version;
878
+ }
879
+ };
880
+ _http5 = new WeakMap();
881
+
882
+ // src/resources/document-fields.ts
883
+ var _http6;
884
+ var DocumentFieldsResource = class {
885
+ /**
886
+ * @internal
887
+ */
888
+ constructor(http) {
889
+ __privateAdd(this, _http6);
890
+ __privateSet(this, _http6, http);
891
+ }
892
+ /**
893
+ * Lists all fields in a document.
894
+ */
895
+ async list(documentKey) {
896
+ const response = await __privateGet(this, _http6).get(
897
+ buildResourcePath("documents", documentKey, "fields")
898
+ );
899
+ return response.fields;
900
+ }
901
+ /**
902
+ * Gets a single field in a document.
903
+ */
904
+ async get(documentKey, fieldId) {
905
+ const response = await __privateGet(this, _http6).get(
906
+ buildResourcePath("documents", documentKey, "fields", fieldId)
907
+ );
908
+ return response.field;
909
+ }
910
+ /**
911
+ * Creates a field in a document.
912
+ *
913
+ * Sends an `Idempotency-Key` (required of suite bearers): a fresh one per
914
+ * call, or `options.idempotencyKey` to make your own retry safe.
915
+ */
916
+ async create(documentKey, input, options) {
917
+ const response = await __privateGet(this, _http6).post(
918
+ buildResourcePath("documents", documentKey, "fields"),
919
+ normalizeFieldInput(input),
920
+ idempotent(options)
921
+ );
922
+ return response.field;
923
+ }
924
+ /**
925
+ * Updates a field in a document.
926
+ */
927
+ async update(documentKey, fieldId, input) {
928
+ const response = await __privateGet(this, _http6).patch(
929
+ buildResourcePath("documents", documentKey, "fields", fieldId),
930
+ normalizeFieldInput(input)
931
+ );
932
+ return response.field;
933
+ }
934
+ /**
935
+ * Deletes a field from a document.
936
+ */
937
+ async delete(documentKey, fieldId) {
938
+ return __privateGet(this, _http6).delete(
939
+ buildResourcePath("documents", documentKey, "fields", fieldId)
940
+ );
941
+ }
942
+ /**
943
+ * Lists the document's archived (soft-deleted) fields, most recently
944
+ * deleted first. Their values are kept, which is what makes `restore` work.
945
+ *
946
+ * `GET /documents/{documentKey}/fields/deleted`. Secret key, or suite bearer
947
+ * with `zap:content:read`.
948
+ */
949
+ async listDeleted(documentKey) {
950
+ const response = await __privateGet(this, _http6).get(
951
+ buildResourcePath("documents", documentKey, "fields", "deleted")
952
+ );
953
+ return response.fields;
954
+ }
955
+ /**
956
+ * Brings an archived field back with every value it held, at the end of the
957
+ * root list (outside any section).
958
+ *
959
+ * `POST /documents/{documentKey}/fields/{fieldId}/restore`. Secret key, or
960
+ * suite bearer with `zap:schema:write` and the Zap ADMIN role.
961
+ */
962
+ async restore(documentKey, fieldId) {
963
+ const response = await __privateGet(this, _http6).post(
964
+ buildResourcePath("documents", documentKey, "fields", fieldId, "restore")
965
+ );
966
+ return response.field;
967
+ }
968
+ /**
969
+ * Reorders document fields.
970
+ */
971
+ async reorder(documentKey, fieldIds) {
972
+ return __privateGet(this, _http6).post(
973
+ buildResourcePath("documents", documentKey, "fields", "reorder"),
974
+ { fieldIds }
975
+ );
976
+ }
977
+ };
978
+ _http6 = new WeakMap();
979
+
980
+ // src/resources/document-sections.ts
981
+ var _http7;
982
+ var DocumentSectionsResource = class {
983
+ /**
984
+ * @internal
985
+ */
986
+ constructor(http) {
987
+ __privateAdd(this, _http7);
988
+ __privateSet(this, _http7, http);
989
+ }
990
+ /**
991
+ * Lists all sections in a document.
992
+ */
993
+ async list(documentKey) {
994
+ const response = await __privateGet(this, _http7).get(
995
+ buildResourcePath("documents", documentKey, "sections")
996
+ );
997
+ return response.sections;
998
+ }
999
+ /**
1000
+ * Gets a single section from a document.
1001
+ */
1002
+ async get(documentKey, sectionId) {
1003
+ const response = await __privateGet(this, _http7).get(
1004
+ buildResourcePath("documents", documentKey, "sections", sectionId)
1005
+ );
1006
+ return response.section;
1007
+ }
1008
+ /**
1009
+ * Creates a section in a document.
1010
+ *
1011
+ * Sends an `Idempotency-Key` (required of suite bearers): a fresh one per
1012
+ * call, or `options.idempotencyKey` to make your own retry safe.
1013
+ */
1014
+ async create(documentKey, input, options) {
1015
+ const response = await __privateGet(this, _http7).post(
1016
+ buildResourcePath("documents", documentKey, "sections"),
1017
+ input,
1018
+ idempotent(options)
1019
+ );
1020
+ return response.section;
1021
+ }
1022
+ /**
1023
+ * Updates a section in a document.
1024
+ */
1025
+ async update(documentKey, sectionId, input) {
1026
+ const response = await __privateGet(this, _http7).patch(
1027
+ buildResourcePath("documents", documentKey, "sections", sectionId),
1028
+ input
1029
+ );
1030
+ return response.section;
1031
+ }
1032
+ /**
1033
+ * Deletes a section from a document.
1034
+ */
1035
+ async delete(documentKey, sectionId) {
1036
+ return __privateGet(this, _http7).delete(
1037
+ buildResourcePath("documents", documentKey, "sections", sectionId)
1038
+ );
1039
+ }
1040
+ };
1041
+ _http7 = new WeakMap();
1042
+
1043
+ // src/resources/document-seo.ts
1044
+ var _http8;
1045
+ var DocumentSeoResource = class {
1046
+ /**
1047
+ * @internal
1048
+ */
1049
+ constructor(http) {
1050
+ __privateAdd(this, _http8);
1051
+ __privateSet(this, _http8, http);
1052
+ }
1053
+ /**
1054
+ * Gets SEO metadata for a document.
1055
+ */
1056
+ async get(documentKey, options) {
1057
+ const response = await __privateGet(this, _http8).get(
1058
+ buildResourcePath("documents", documentKey, "seo"),
1059
+ {
1060
+ params: {
1061
+ locale: options?.locale
1062
+ }
1063
+ }
1064
+ );
1065
+ return response.seo;
1066
+ }
1067
+ /**
1068
+ * Updates SEO metadata for a document.
1069
+ */
1070
+ async update(documentKey, input) {
1071
+ const response = await __privateGet(this, _http8).put(
1072
+ buildResourcePath("documents", documentKey, "seo"),
1073
+ input
1074
+ );
1075
+ return response.seo;
1076
+ }
1077
+ };
1078
+ _http8 = new WeakMap();
1079
+
1080
+ // src/resources/document-values.ts
1081
+ var _http9;
1082
+ var DocumentValuesResource = class {
1083
+ /**
1084
+ * @internal
1085
+ */
1086
+ constructor(http) {
1087
+ __privateAdd(this, _http9);
1088
+ __privateSet(this, _http9, http);
1089
+ }
1090
+ /**
1091
+ * Gets all document values.
1092
+ */
1093
+ async get(documentKey) {
1094
+ const response = await __privateGet(this, _http9).get(
1095
+ buildResourcePath("documents", documentKey, "values")
1096
+ );
1097
+ return response.values;
1098
+ }
1099
+ /**
1100
+ * Updates document values by field key.
1101
+ */
1102
+ async update(documentKey, values, options) {
1103
+ const response = await __privateGet(this, _http9).put(
1104
+ buildResourcePath("documents", documentKey, "values"),
1105
+ {
1106
+ locale: options?.locale,
1107
+ values
1108
+ }
1109
+ );
1110
+ return response.values;
1111
+ }
1112
+ };
1113
+ _http9 = new WeakMap();
1114
+
1115
+ // src/resources/documents.ts
1116
+ var _http10, _defaults2;
1117
+ var DocumentsResource = class {
1118
+ /**
1119
+ * @internal
1120
+ */
1121
+ constructor(http, defaults) {
1122
+ __publicField(this, "fields");
1123
+ __publicField(this, "sections");
1124
+ __publicField(this, "values");
1125
+ __publicField(this, "seo");
1126
+ __privateAdd(this, _http10);
1127
+ __privateAdd(this, _defaults2);
1128
+ __privateSet(this, _http10, http);
1129
+ __privateSet(this, _defaults2, defaults);
1130
+ this.fields = new DocumentFieldsResource(http);
1131
+ this.sections = new DocumentSectionsResource(http);
1132
+ this.values = new DocumentValuesResource(http);
1133
+ this.seo = new DocumentSeoResource(http);
1134
+ }
1135
+ /**
1136
+ * Lists all documents available to the current API key.
1137
+ */
1138
+ async list(options) {
1139
+ const merged = mergeRequestOptions(__privateGet(this, _defaults2), options);
1140
+ return __privateGet(this, _http10).get(buildResourcePath("documents"), {
1141
+ params: {
1142
+ locale: merged.locale,
1143
+ status: merged.status,
1144
+ ...previewParam(merged)
1145
+ }
1146
+ });
1147
+ }
1148
+ /**
1149
+ * Retrieves a single document by key.
1150
+ */
1151
+ async get(documentKey, options) {
1152
+ const merged = mergeRequestOptions(__privateGet(this, _defaults2), options);
1153
+ return __privateGet(this, _http10).get(buildResourcePath("documents", documentKey), {
1154
+ params: {
1155
+ locale: merged.locale,
1156
+ status: merged.status,
1157
+ fields: toArrayParam(merged.fields),
1158
+ ...previewParam(merged)
1159
+ }
1160
+ });
1161
+ }
1162
+ /**
1163
+ * Creates a document.
1164
+ *
1165
+ * Sends an `Idempotency-Key` (required of suite bearers): a fresh one per
1166
+ * call, or `options.idempotencyKey` to make your own retry safe.
1167
+ */
1168
+ async create(input, options) {
1169
+ const response = await __privateGet(this, _http10).post(
1170
+ buildResourcePath("documents"),
1171
+ input,
1172
+ idempotent(options)
1173
+ );
1174
+ return response.document;
1175
+ }
1176
+ /**
1177
+ * Updates a document.
1178
+ */
1179
+ async update(documentKey, input) {
1180
+ const response = await __privateGet(this, _http10).patch(
1181
+ buildResourcePath("documents", documentKey),
1182
+ input
1183
+ );
1184
+ return response.document;
1185
+ }
1186
+ /**
1187
+ * Deletes a document.
1188
+ */
1189
+ async delete(documentKey, options) {
1190
+ return __privateGet(this, _http10).delete(
1191
+ buildResourcePath("documents", documentKey),
1192
+ toDeleteBody(options)
1193
+ );
1194
+ }
1195
+ /**
1196
+ * Publishes a document.
1197
+ */
1198
+ async publish(documentKey) {
1199
+ const response = await __privateGet(this, _http10).post(
1200
+ buildResourcePath("documents", documentKey, "publish")
1201
+ );
1202
+ return response.document;
1203
+ }
1204
+ /**
1205
+ * Unpublishes a document.
1206
+ */
1207
+ async unpublish(documentKey) {
1208
+ const response = await __privateGet(this, _http10).post(
1209
+ buildResourcePath("documents", documentKey, "unpublish")
1210
+ );
1211
+ return response.document;
1212
+ }
1213
+ };
1214
+ _http10 = new WeakMap();
1215
+ _defaults2 = new WeakMap();
1216
+
1217
+ // src/resources/item-versions.ts
1218
+ var _http11;
1219
+ var ItemVersionsResource = class {
1220
+ /** @internal */
1221
+ constructor(http) {
1222
+ __privateAdd(this, _http11);
1223
+ __privateSet(this, _http11, http);
1224
+ }
1225
+ /**
1226
+ * Lists an item's versions, newest first.
1227
+ */
1228
+ async list(collectionKey, slug) {
1229
+ return __privateGet(this, _http11).get(
1230
+ buildResourcePath("collections", collectionKey, "items", slug, "versions")
1231
+ );
1232
+ }
1233
+ /**
1234
+ * Gets one version with its snapshot (values, SEO and slugs).
1235
+ */
1236
+ async get(collectionKey, slug, versionId) {
1237
+ const response = await __privateGet(this, _http11).get(
1238
+ buildResourcePath("collections", collectionKey, "items", slug, "versions", versionId)
1239
+ );
1240
+ return response.version;
1241
+ }
1242
+ /**
1243
+ * Opens a draft from the item's live state. Fails with `DUPLICATE_KEY` (409)
1244
+ * when the item already has one.
1245
+ */
1246
+ async createDraft(collectionKey, slug, input) {
1247
+ const response = await __privateGet(this, _http11).post(
1248
+ buildResourcePath("collections", collectionKey, "items", slug, "versions"),
1249
+ input
1250
+ );
1251
+ return response.version;
1252
+ }
1253
+ /**
1254
+ * Stages values (and optionally a new slug) on the open draft without
1255
+ * touching the live item. Fails with `VALIDATION_ERROR` (400) when there is
1256
+ * no open draft.
1257
+ */
1258
+ async updateDraft(collectionKey, slug, input) {
1259
+ const response = await __privateGet(this, _http11).put(
1260
+ buildResourcePath("collections", collectionKey, "items", slug, "versions", "draft"),
1261
+ input
1262
+ );
1263
+ return response.version;
1264
+ }
1265
+ /**
1266
+ * Discards the open draft. Fails with `NOT_FOUND` (404) when there is none.
1267
+ */
1268
+ async discardDraft(collectionKey, slug) {
1269
+ await __privateGet(this, _http11).delete(
1270
+ buildResourcePath("collections", collectionKey, "items", slug, "versions", "draft")
1271
+ );
1272
+ }
1273
+ /**
1274
+ * Publishes the open draft: its values go live and it becomes the item's
1275
+ * published version. Fails with `NOT_FOUND` (404) when there is no draft.
1276
+ */
1277
+ async publishDraft(collectionKey, slug) {
1278
+ const response = await __privateGet(this, _http11).post(
1279
+ buildResourcePath(
1280
+ "collections",
1281
+ collectionKey,
1282
+ "items",
1283
+ slug,
1284
+ "versions",
1285
+ "draft",
1286
+ "publish"
1287
+ )
1288
+ );
1289
+ return response.version;
1290
+ }
1291
+ /**
1292
+ * Restores a past version over the live item and records the restore as a
1293
+ * NEW published version (history is never rewritten). Refused (409) for a
1294
+ * draft version, or while the item has an open draft.
1295
+ */
1296
+ async rollback(collectionKey, slug, versionId) {
1297
+ const response = await __privateGet(this, _http11).post(
1298
+ buildResourcePath(
1299
+ "collections",
1300
+ collectionKey,
1301
+ "items",
1302
+ slug,
1303
+ "versions",
1304
+ versionId,
1305
+ "rollback"
1306
+ )
1307
+ );
1308
+ return response.version;
1309
+ }
1310
+ };
1311
+ _http11 = new WeakMap();
1312
+
1313
+ // src/query-builder.ts
1314
+ var _http12, _defaults3, _collectionKey, _options;
1315
+ var _ItemQueryBuilder = class _ItemQueryBuilder {
1316
+ /**
1317
+ * @internal
1318
+ */
1319
+ constructor(http, defaults, collectionKey, options = {}) {
1320
+ __privateAdd(this, _http12);
1321
+ __privateAdd(this, _defaults3);
1322
+ __privateAdd(this, _collectionKey);
1323
+ __privateAdd(this, _options);
1324
+ __privateSet(this, _http12, http);
1325
+ __privateSet(this, _defaults3, defaults);
1326
+ __privateSet(this, _collectionKey, collectionKey);
1327
+ __privateSet(this, _options, options);
1328
+ }
1329
+ /**
1330
+ * Overrides the request locale.
1331
+ */
1332
+ locale(locale) {
1333
+ return this.clone({ locale });
1334
+ }
1335
+ /**
1336
+ * Overrides the delivery status filter.
1337
+ */
1338
+ status(status) {
1339
+ return this.clone({ status });
1340
+ }
1341
+ /**
1342
+ * Adds or replaces a field filter.
1343
+ */
1344
+ filter(field, value) {
1345
+ return this.clone({
1346
+ filter: {
1347
+ ...__privateGet(this, _options).filter ?? {},
1348
+ [field]: value
1349
+ }
1350
+ });
1351
+ }
1352
+ /**
1353
+ * Sets the sort expression.
1354
+ */
1355
+ sort(sort) {
1356
+ return this.clone({ sort });
1357
+ }
1358
+ /**
1359
+ * Selects a sparse set of content fields.
1360
+ */
1361
+ fields(fields) {
1362
+ return this.clone({ fields });
1363
+ }
1364
+ /**
1365
+ * Sets the current page.
1366
+ */
1367
+ page(page) {
1368
+ return this.clone({ page });
1369
+ }
1370
+ /**
1371
+ * Sets the page size.
1372
+ */
1373
+ pageSize(pageSize) {
1374
+ return this.clone({ pageSize });
1375
+ }
1376
+ /**
1377
+ * Executes the built request.
1378
+ */
1379
+ async get() {
1380
+ const resource = new ItemsResource(__privateGet(this, _http12), __privateGet(this, _defaults3));
1381
+ return resource.list(__privateGet(this, _collectionKey), __privateGet(this, _options));
1382
+ }
1383
+ /**
1384
+ * Returns the current request options as a plain object.
1385
+ */
1386
+ toJSON() {
1387
+ return {
1388
+ ...__privateGet(this, _options),
1389
+ filter: __privateGet(this, _options).filter ? { ...__privateGet(this, _options).filter } : void 0,
1390
+ fields: __privateGet(this, _options).fields ? [...__privateGet(this, _options).fields] : void 0
1391
+ };
1392
+ }
1393
+ clone(partial) {
1394
+ return new _ItemQueryBuilder(__privateGet(this, _http12), __privateGet(this, _defaults3), __privateGet(this, _collectionKey), {
1395
+ ...__privateGet(this, _options),
1396
+ ...partial
1397
+ });
1398
+ }
1399
+ };
1400
+ _http12 = new WeakMap();
1401
+ _defaults3 = new WeakMap();
1402
+ _collectionKey = new WeakMap();
1403
+ _options = new WeakMap();
1404
+ var ItemQueryBuilder = _ItemQueryBuilder;
1405
+
1406
+ // src/resources/item-seo.ts
1407
+ var _http13;
1408
+ var ItemSeoResource = class {
1409
+ /**
1410
+ * @internal
1411
+ */
1412
+ constructor(http) {
1413
+ __privateAdd(this, _http13);
1414
+ __privateSet(this, _http13, http);
1415
+ }
1416
+ /**
1417
+ * Gets SEO metadata for an item.
1418
+ */
1419
+ async get(collectionKey, slug, options) {
1420
+ const response = await __privateGet(this, _http13).get(
1421
+ buildResourcePath("collections", collectionKey, "items", slug, "seo"),
1422
+ {
1423
+ params: {
1424
+ locale: options?.locale
1425
+ }
1426
+ }
1427
+ );
1428
+ return response.seo;
1429
+ }
1430
+ /**
1431
+ * Updates SEO metadata for an item.
1432
+ */
1433
+ async update(collectionKey, slug, input) {
1434
+ const response = await __privateGet(this, _http13).patch(
1435
+ buildResourcePath("collections", collectionKey, "items", slug, "seo"),
1436
+ input
1437
+ );
1438
+ return response.seo;
1439
+ }
1440
+ };
1441
+ _http13 = new WeakMap();
1442
+
1443
+ // src/resources/items.ts
1444
+ var _http14, _defaults4;
1445
+ var ItemsResource = class {
1446
+ /**
1447
+ * @internal
1448
+ */
1449
+ constructor(http, defaults) {
1450
+ __publicField(this, "seo");
1451
+ __privateAdd(this, _http14);
1452
+ __privateAdd(this, _defaults4);
1453
+ __privateSet(this, _http14, http);
1454
+ __privateSet(this, _defaults4, defaults);
1455
+ this.seo = new ItemSeoResource(http);
1456
+ }
1457
+ /**
1458
+ * Lists items in a collection.
1459
+ */
1460
+ async list(collectionKey, options) {
1461
+ const merged = mergeRequestOptions(__privateGet(this, _defaults4), options);
1462
+ return __privateGet(this, _http14).get(
1463
+ buildResourcePath("collections", collectionKey, "items"),
1464
+ {
1465
+ params: {
1466
+ locale: merged.locale,
1467
+ status: merged.status,
1468
+ fields: toArrayParam(merged.fields),
1469
+ page: merged.page,
1470
+ pageSize: merged.pageSize,
1471
+ sort: merged.sort,
1472
+ ...serializeFilters(merged.filter),
1473
+ ...previewParam(merged)
1474
+ }
1475
+ }
1476
+ );
1477
+ }
1478
+ /**
1479
+ * Retrieves a single item by slug.
1480
+ */
1481
+ async get(collectionKey, slug, options) {
1482
+ const merged = mergeRequestOptions(__privateGet(this, _defaults4), options);
1483
+ return __privateGet(this, _http14).get(
1484
+ buildResourcePath("collections", collectionKey, "items", slug),
1485
+ {
1486
+ params: {
1487
+ locale: merged.locale,
1488
+ status: merged.status,
1489
+ fields: toArrayParam(merged.fields),
1490
+ ...previewParam(merged)
1491
+ }
1492
+ }
1493
+ );
1494
+ }
1495
+ /**
1496
+ * Starts a lazy fluent query builder for a collection.
1497
+ */
1498
+ collection(collectionKey) {
1499
+ return new ItemQueryBuilder(__privateGet(this, _http14), __privateGet(this, _defaults4), collectionKey);
1500
+ }
1501
+ /**
1502
+ * Creates an item in a collection.
1503
+ *
1504
+ * Sends an `Idempotency-Key` (required of suite bearers): a fresh one per
1505
+ * call, or `options.idempotencyKey` to make your own retry safe.
1506
+ */
1507
+ async create(collectionKey, input, options) {
1508
+ const response = await __privateGet(this, _http14).post(
1509
+ buildResourcePath("collections", collectionKey, "items"),
1510
+ input,
1511
+ idempotent(options)
1512
+ );
1513
+ return response.item;
1514
+ }
1515
+ /**
1516
+ * Updates an item by slug.
1517
+ */
1518
+ async update(collectionKey, slug, input) {
1519
+ const response = await __privateGet(this, _http14).patch(
1520
+ buildResourcePath("collections", collectionKey, "items", slug),
1521
+ input
1522
+ );
1523
+ return response.item;
1524
+ }
1525
+ /**
1526
+ * Deletes an item by slug.
1527
+ */
1528
+ async delete(collectionKey, slug, options) {
1529
+ return __privateGet(this, _http14).delete(
1530
+ buildResourcePath("collections", collectionKey, "items", slug),
1531
+ toDeleteBody(options)
1532
+ );
1533
+ }
1534
+ /**
1535
+ * Publishes an item by slug.
1536
+ */
1537
+ async publish(collectionKey, slug) {
1538
+ const response = await __privateGet(this, _http14).post(
1539
+ buildResourcePath("collections", collectionKey, "items", slug, "publish")
1540
+ );
1541
+ return response.item;
1542
+ }
1543
+ /**
1544
+ * Unpublishes an item by slug.
1545
+ */
1546
+ async unpublish(collectionKey, slug) {
1547
+ const response = await __privateGet(this, _http14).post(
1548
+ buildResourcePath("collections", collectionKey, "items", slug, "unpublish")
1549
+ );
1550
+ return response.item;
1551
+ }
1552
+ };
1553
+ _http14 = new WeakMap();
1554
+ _defaults4 = new WeakMap();
1555
+
1556
+ // src/resources/media.ts
1557
+ function isBlobFile(file) {
1558
+ return typeof Blob !== "undefined" && file instanceof Blob;
1559
+ }
1560
+ function toUploadBody(file) {
1561
+ if (isBlobFile(file)) {
1562
+ return file;
1563
+ }
1564
+ if (ArrayBuffer.isView(file)) {
1565
+ const bytes = file.buffer instanceof ArrayBuffer ? file.buffer.slice(file.byteOffset, file.byteOffset + file.byteLength) : new Uint8Array(file.buffer, file.byteOffset, file.byteLength).slice().buffer;
1566
+ return new Blob([bytes]);
1567
+ }
1568
+ return file;
1569
+ }
1570
+ function getUploadSize(file) {
1571
+ if (isBlobFile(file)) {
1572
+ return file.size;
1573
+ }
1574
+ if (ArrayBuffer.isView(file)) {
1575
+ return file.byteLength;
1576
+ }
1577
+ return file instanceof ArrayBuffer ? file.byteLength : 0;
1578
+ }
1579
+ var _http15;
1580
+ var MediaResource = class {
1581
+ /**
1582
+ * @internal
1583
+ */
1584
+ constructor(http) {
1585
+ __privateAdd(this, _http15);
1586
+ __privateSet(this, _http15, http);
1587
+ }
1588
+ /**
1589
+ * Lists media for the current site.
1590
+ */
1591
+ async list(params) {
1592
+ return __privateGet(this, _http15).get(buildResourcePath("media"), {
1593
+ params: {
1594
+ search: params?.search,
1595
+ page: params?.page,
1596
+ pageSize: params?.pageSize,
1597
+ sort: params?.sort,
1598
+ type: params?.type,
1599
+ status: params?.status,
1600
+ usage: params?.usage
1601
+ }
1602
+ });
1603
+ }
1604
+ /**
1605
+ * Gets a single media item.
1606
+ */
1607
+ async get(id) {
1608
+ return __privateGet(this, _http15).get(buildResourcePath("media", id));
1609
+ }
1610
+ /**
1611
+ * Updates media metadata.
1612
+ */
1613
+ async update(id, input) {
1614
+ const response = await __privateGet(this, _http15).patch(
1615
+ buildResourcePath("media", id),
1616
+ input
1617
+ );
1618
+ return response.media;
1619
+ }
1620
+ /**
1621
+ * Deletes media.
1622
+ */
1623
+ async delete(id) {
1624
+ return __privateGet(this, _http15).delete(buildResourcePath("media", id));
1625
+ }
1626
+ /**
1627
+ * Publishes media.
1628
+ */
1629
+ async publish(id) {
1630
+ const response = await __privateGet(this, _http15).post(
1631
+ buildResourcePath("media", id, "publish")
1632
+ );
1633
+ return response.media;
1634
+ }
1635
+ /**
1636
+ * Unpublishes media.
1637
+ */
1638
+ async unpublish(id) {
1639
+ const response = await __privateGet(this, _http15).post(
1640
+ buildResourcePath("media", id, "unpublish")
1641
+ );
1642
+ return response.media;
1643
+ }
1644
+ /**
1645
+ * Requests a presigned upload URL.
1646
+ */
1647
+ async createUploadUrl(input) {
1648
+ return __privateGet(this, _http15).post(buildResourcePath("media", "upload-url"), input);
1649
+ }
1650
+ /**
1651
+ * Confirms a completed upload.
1652
+ */
1653
+ async confirmUpload(input) {
1654
+ const response = await __privateGet(this, _http15).post(
1655
+ buildResourcePath("media", "confirm"),
1656
+ input
1657
+ );
1658
+ return response.media;
1659
+ }
1660
+ /**
1661
+ * Fetches a file from a URL into the media library, server-side (SSRF
1662
+ * guarded, type allowlist, size ceiling). The file starts private (`DRAFT`):
1663
+ * the answer carries a 15-minute `signedUrl` and no `url` until `publish`.
1664
+ *
1665
+ * `POST /media/from-url`. Secret key, or suite bearer with
1666
+ * `zap:media:write`. Sends an `Idempotency-Key` (required of suite bearers;
1667
+ * a retry with the same key replays the first answer without downloading
1668
+ * again). Server-side only: the API's general CORS does not allow that
1669
+ * header from a browser.
1670
+ */
1671
+ async fromUrl(input, options) {
1672
+ return __privateGet(this, _http15).post(
1673
+ buildResourcePath("media", "from-url"),
1674
+ input,
1675
+ idempotent(options)
1676
+ );
1677
+ }
1678
+ /**
1679
+ * Uploads media using the public presigned URL flow.
1680
+ */
1681
+ async upload(input) {
1682
+ const upload = await this.createUploadUrl({
1683
+ filename: input.filename,
1684
+ contentType: input.contentType,
1685
+ size: getUploadSize(input.file),
1686
+ width: input.width,
1687
+ height: input.height
1688
+ });
1689
+ await __privateGet(this, _http15).upload(upload.uploadUrl, toUploadBody(input.file), {
1690
+ "Content-Type": input.contentType
1691
+ });
1692
+ const media = await this.confirmUpload({
1693
+ mediaId: upload.mediaId,
1694
+ key: upload.key,
1695
+ filename: input.filename,
1696
+ contentType: input.contentType,
1697
+ size: getUploadSize(input.file),
1698
+ width: input.width,
1699
+ height: input.height
1700
+ });
1701
+ const alt = normalizeHeaderValue(input.alt);
1702
+ const title = normalizeHeaderValue(input.title);
1703
+ const description = normalizeHeaderValue(input.description);
1704
+ if (!alt && !title && !description) {
1705
+ return media;
1706
+ }
1707
+ return this.update(media.id, {
1708
+ alt: alt ?? null,
1709
+ title: title ?? null,
1710
+ description: description ?? null
1711
+ });
1712
+ }
1713
+ };
1714
+ _http15 = new WeakMap();
1715
+
1716
+ // src/resources/preview-tokens.ts
1717
+ var _http16;
1718
+ var PreviewTokensResource = class {
1719
+ /**
1720
+ * @internal
1721
+ */
1722
+ constructor(http) {
1723
+ __privateAdd(this, _http16);
1724
+ __privateSet(this, _http16, http);
1725
+ }
1726
+ /**
1727
+ * Checks that the client's preview token is live AND was minted for the
1728
+ * site `siteApiKey` belongs to, before trusting it (what a draft-mode route
1729
+ * does before turning draft mode on). Rejects with `EelZapError` 401 for an
1730
+ * unknown, revoked or expired token, 403 `WRONG_SITE` for another site's.
1731
+ *
1732
+ * `GET /preview/token`. The client's `apiKey` must be the `zpt_` token
1733
+ * itself (any other bearer is 403); `siteApiKey` is one of the site's own
1734
+ * API keys (public or secret), sent as `X-Zap-Site-Api-Key`.
1735
+ *
1736
+ * @example
1737
+ * ```ts
1738
+ * const zap = createClient({ apiKey: token })
1739
+ * const { site, expiresAt } = await zap.previewTokens.validate(process.env.ZAP_PUBLIC_KEY!)
1740
+ * ```
1741
+ */
1742
+ async validate(siteApiKey) {
1743
+ return __privateGet(this, _http16).get("/preview/token", {
1744
+ headers: { "X-Zap-Site-Api-Key": siteApiKey }
1745
+ });
1746
+ }
1747
+ };
1748
+ _http16 = new WeakMap();
1749
+
1750
+ // src/resources/site.ts
1751
+ var _http17;
1752
+ var SiteResource = class {
1753
+ /**
1754
+ * @internal
1755
+ */
1756
+ constructor(http) {
1757
+ __privateAdd(this, _http17);
1758
+ __privateSet(this, _http17, http);
1759
+ }
1760
+ /**
1761
+ * Resolves the current site from the authenticated API key.
1762
+ */
1763
+ async get() {
1764
+ return __privateGet(this, _http17).get(buildResourcePath("site"));
1765
+ }
1766
+ /**
1767
+ * Sets the site's URL and «Otros dominios» (`PATCH /site`), under the same
1768
+ * rules as the site's settings page, and resolves to the updated site.
1769
+ * Server code only: it needs a `secret_` key or an ADMIN suite credential.
1770
+ */
1771
+ async update(input) {
1772
+ return __privateGet(this, _http17).patch(buildResourcePath("site"), input);
1773
+ }
1774
+ };
1775
+ _http17 = new WeakMap();
1776
+
1777
+ // src/resources/sites.ts
1778
+ var _http18;
1779
+ var SitesResource = class {
1780
+ /**
1781
+ * @internal
1782
+ */
1783
+ constructor(http) {
1784
+ __privateAdd(this, _http18);
1785
+ __privateSet(this, _http18, http);
1786
+ }
1787
+ /**
1788
+ * Lists the workspace's sites, newest first. Each one's `key` or `id` is a
1789
+ * valid `X-Eel-Site` for every other call; this is how a suite client
1790
+ * learns which sites it can address.
1791
+ *
1792
+ * `GET /sites`. Suite bearer only (`eel_sk_` / `eel_at_`), `zap:sites:read`;
1793
+ * needs no `X-Eel-Site`. Site keys are refused: a site key is one site.
1794
+ */
1795
+ async list() {
1796
+ const response = await __privateGet(this, _http18).get("/sites");
1797
+ return response.sites;
1798
+ }
1799
+ };
1800
+ _http18 = new WeakMap();
1801
+
1802
+ // src/client.ts
1803
+ var _http19, _defaults5, _config2;
1804
+ var EelZapClient = class {
1805
+ constructor(config) {
1806
+ __publicField(this, "site");
1807
+ __publicField(this, "sites");
1808
+ __publicField(this, "collections");
1809
+ __publicField(this, "items");
1810
+ __publicField(this, "documents");
1811
+ __publicField(this, "media");
1812
+ __publicField(this, "itemVersions");
1813
+ __publicField(this, "documentVersions");
1814
+ __publicField(this, "previewTokens");
1815
+ __publicField(this, "comments");
1816
+ __privateAdd(this, _http19);
1817
+ __privateAdd(this, _defaults5);
1818
+ __privateAdd(this, _config2);
1819
+ if (!config.apiKey.trim()) {
1820
+ throw new TypeError("apiKey is required.");
1821
+ }
1822
+ const fetchImpl = config.fetch ?? globalThis.fetch;
1823
+ if (typeof fetchImpl !== "function") {
1824
+ throw new TypeError("A fetch implementation is required.");
1825
+ }
1826
+ __privateSet(this, _defaults5, {
1827
+ locale: config.locale,
1828
+ status: config.status,
1829
+ // A preview token only ever reads previews; say so on the wire too.
1830
+ preview: config.preview ?? (isPreviewToken(config.apiKey) || void 0)
1831
+ });
1832
+ __privateSet(this, _config2, {
1833
+ apiKey: config.apiKey,
1834
+ baseUrl: normalizeBaseUrl(config.baseUrl ?? "https://api.eelzap.com"),
1835
+ pathPrefix: config.pathPrefix ?? "/v1",
1836
+ defaultHeaders: config.defaultHeaders,
1837
+ timeout: config.timeout ?? 3e4
1838
+ });
1839
+ __privateSet(this, _http19, new HttpClient({
1840
+ apiKey: __privateGet(this, _config2).apiKey,
1841
+ baseUrl: __privateGet(this, _config2).baseUrl,
1842
+ pathPrefix: __privateGet(this, _config2).pathPrefix,
1843
+ fetch: fetchImpl,
1844
+ defaultHeaders: __privateGet(this, _config2).defaultHeaders,
1845
+ timeout: __privateGet(this, _config2).timeout,
1846
+ retry: resolveRetry(config.retry)
1847
+ }));
1848
+ this.site = new SiteResource(__privateGet(this, _http19));
1849
+ this.sites = new SitesResource(__privateGet(this, _http19));
1850
+ this.collections = new CollectionsResource(__privateGet(this, _http19), __privateGet(this, _defaults5));
1851
+ this.items = new ItemsResource(__privateGet(this, _http19), __privateGet(this, _defaults5));
1852
+ this.documents = new DocumentsResource(__privateGet(this, _http19), __privateGet(this, _defaults5));
1853
+ this.media = new MediaResource(__privateGet(this, _http19));
1854
+ this.itemVersions = new ItemVersionsResource(__privateGet(this, _http19));
1855
+ this.documentVersions = new DocumentVersionsResource(__privateGet(this, _http19));
1856
+ this.previewTokens = new PreviewTokensResource(__privateGet(this, _http19));
1857
+ this.comments = new CommentsResource(__privateGet(this, _http19));
1858
+ }
1859
+ /**
1860
+ * Returns a masked string representation safe for logs.
1861
+ */
1862
+ toString() {
1863
+ return `EelZapClient(baseUrl=${__privateGet(this, _config2).baseUrl}, pathPrefix=${__privateGet(this, _config2).pathPrefix}, apiKey=${maskApiKey(__privateGet(this, _config2).apiKey)})`;
1864
+ }
1865
+ };
1866
+ _http19 = new WeakMap();
1867
+ _defaults5 = new WeakMap();
1868
+ _config2 = new WeakMap();
1869
+ function createClient(config) {
1870
+ return new EelZapClient(config);
1871
+ }
1872
+
1873
+ // src/media-url.ts
1874
+ function getMediaUrl(media) {
1875
+ return media?.url ?? media?.signedUrl ?? null;
1876
+ }
1877
+
1878
+ // src/stega.ts
1879
+ var PREFIX = "\u2060\u200D\u200C\u200C\u200D\u200D\u200C\u2060";
1880
+ var MARKER_RE = /⁠‍‌‌‍‍‌⁠(?:[​‌][​‌‍⁠]{3})*/g;
1881
+ function hasStega(value) {
1882
+ return typeof value === "string" && value.includes(PREFIX);
1883
+ }
1884
+ function cleanString(text) {
1885
+ return text.includes(PREFIX) ? text.replace(MARKER_RE, "") : text;
1886
+ }
1887
+ function cleanStega(value) {
1888
+ if (typeof value === "string") return cleanString(value);
1889
+ if (Array.isArray(value)) return value.map((item) => cleanStega(item));
1890
+ if (value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
1891
+ const out = {};
1892
+ for (const [key, item] of Object.entries(value)) out[key] = cleanStega(item);
1893
+ return out;
1894
+ }
1895
+ return value;
1896
+ }
1897
+
1898
+ // src/webhook.ts
1899
+ var WEBHOOK_SIGNATURE_HEADER = "X-Eel-Signature";
1900
+ var WEBHOOK_TIMESTAMP_HEADER = "X-Eel-Timestamp";
1901
+ var WEBHOOK_TOLERANCE_SECONDS = 300;
1902
+ var SECRET_PREFIX = "whsec_";
1903
+ var SIGNATURE_PREFIX = "v1=";
1904
+ var HMAC_SHA256_HEX_LENGTH = 64;
1905
+ function readHeader(headers, name) {
1906
+ if (typeof headers.get === "function") {
1907
+ return headers.get(name);
1908
+ }
1909
+ const wanted = name.toLowerCase();
1910
+ for (const [key, value] of Object.entries(headers)) {
1911
+ if (key.toLowerCase() !== wanted || value === void 0) continue;
1912
+ if (typeof value === "string") return value;
1913
+ return value.length === 1 ? value[0] ?? null : null;
1914
+ }
1915
+ return null;
1916
+ }
1917
+ function hexToBytes(value) {
1918
+ if (value.length !== HMAC_SHA256_HEX_LENGTH || !/^[0-9a-f]+$/i.test(value)) {
1919
+ return null;
1920
+ }
1921
+ const bytes = new Uint8Array(value.length / 2);
1922
+ for (let index = 0; index < bytes.length; index += 1) {
1923
+ bytes[index] = Number.parseInt(value.slice(index * 2, index * 2 + 2), 16);
1924
+ }
1925
+ return bytes;
1926
+ }
1927
+ function getSubtle() {
1928
+ const subtle = globalThis.crypto?.subtle;
1929
+ if (!subtle) {
1930
+ throw new Error(
1931
+ "verifyWebhookSignature needs WebCrypto (globalThis.crypto.subtle). Node 18 does not expose it by default: use Node 20+, or set globalThis.crypto to node:crypto's webcrypto at startup."
1932
+ );
1933
+ }
1934
+ return subtle;
1935
+ }
1936
+ async function verifyWebhookSignature(payload, headers, secret, options = {}) {
1937
+ if (typeof payload !== "string" || typeof secret !== "string" || !headers || typeof headers !== "object") {
1938
+ return false;
1939
+ }
1940
+ const key = secret.startsWith(SECRET_PREFIX) ? secret.slice(SECRET_PREFIX.length) : secret;
1941
+ if (!key) {
1942
+ return false;
1943
+ }
1944
+ const timestamp = readHeader(headers, WEBHOOK_TIMESTAMP_HEADER)?.trim();
1945
+ if (!timestamp || !/^\d+$/.test(timestamp)) {
1946
+ return false;
1947
+ }
1948
+ const nowSeconds = (options.now ?? /* @__PURE__ */ new Date()).getTime() / 1e3;
1949
+ const tolerance = options.toleranceSeconds ?? WEBHOOK_TOLERANCE_SECONDS;
1950
+ if (!(Math.abs(nowSeconds - Number(timestamp)) <= tolerance)) {
1951
+ return false;
1952
+ }
1953
+ const signature = readHeader(headers, WEBHOOK_SIGNATURE_HEADER)?.trim();
1954
+ if (!signature?.startsWith(SIGNATURE_PREFIX)) {
1955
+ return false;
1956
+ }
1957
+ const signatureBytes = hexToBytes(signature.slice(SIGNATURE_PREFIX.length));
1958
+ if (!signatureBytes) {
1959
+ return false;
1960
+ }
1961
+ const subtle = getSubtle();
1962
+ const encoder = new TextEncoder();
1963
+ const hmacKey = await subtle.importKey(
1964
+ "raw",
1965
+ encoder.encode(key),
1966
+ { name: "HMAC", hash: "SHA-256" },
1967
+ false,
1968
+ ["verify"]
1969
+ );
1970
+ return subtle.verify("HMAC", hmacKey, signatureBytes, encoder.encode(`${timestamp}.${payload}`));
1971
+ }
1972
+ var CHANGE_ACTIONS = /* @__PURE__ */ new Set([
1973
+ "created",
1974
+ "updated",
1975
+ "draft_updated",
1976
+ "published",
1977
+ "unpublished",
1978
+ "deleted",
1979
+ "rolled_back",
1980
+ "uploaded"
1981
+ ]);
1982
+ function webhookChanges(payload) {
1983
+ const match = /^zap\.(item|document|media)\.([a-z_]+)$/.exec(payload.type);
1984
+ if (!match || !CHANGE_ACTIONS.has(match[2])) {
1985
+ return [];
1986
+ }
1987
+ const type = match[1];
1988
+ const action = match[2];
1989
+ if (type === "item") {
1990
+ const data2 = payload.data;
1991
+ return (data2.items ?? []).map((item) => ({
1992
+ type,
1993
+ action,
1994
+ id: item.id,
1995
+ resourceKey: item.slug,
1996
+ collectionKey: data2.collection.key,
1997
+ siteKey: data2.site.key
1998
+ }));
1999
+ }
2000
+ if (type === "document") {
2001
+ const data2 = payload.data;
2002
+ return (data2.documents ?? []).map((document) => ({
2003
+ type,
2004
+ action,
2005
+ id: document.id,
2006
+ resourceKey: document.key,
2007
+ siteKey: data2.site.key
2008
+ }));
2009
+ }
2010
+ const data = payload.data;
2011
+ return (data.media ?? []).map((media) => ({
2012
+ type,
2013
+ action,
2014
+ id: media.id,
2015
+ resourceKey: media.id,
2016
+ siteKey: data.site.key
2017
+ }));
2018
+ }
2019
+ // Annotate the CommonJS export names for ESM import in node:
2020
+ 0 && (module.exports = {
2021
+ CollectionFieldsResource,
2022
+ CollectionSectionsResource,
2023
+ CollectionsResource,
2024
+ CommentsResource,
2025
+ DocumentFieldsResource,
2026
+ DocumentSectionsResource,
2027
+ DocumentSeoResource,
2028
+ DocumentValuesResource,
2029
+ DocumentVersionsResource,
2030
+ DocumentsResource,
2031
+ EelZapClient,
2032
+ EelZapError,
2033
+ EelZapNetworkError,
2034
+ ItemQueryBuilder,
2035
+ ItemSeoResource,
2036
+ ItemVersionsResource,
2037
+ ItemsResource,
2038
+ MediaResource,
2039
+ MemoryCacheAdapter,
2040
+ PreviewTokensResource,
2041
+ SiteResource,
2042
+ SitesResource,
2043
+ WEBHOOK_SIGNATURE_HEADER,
2044
+ WEBHOOK_TIMESTAMP_HEADER,
2045
+ WEBHOOK_TOLERANCE_SECONDS,
2046
+ cachedFetch,
2047
+ cleanStega,
2048
+ createClient,
2049
+ getMediaUrl,
2050
+ hasStega,
2051
+ isEelZapError,
2052
+ verifyWebhookSignature,
2053
+ webhookChanges
2054
+ });
2055
+ //# sourceMappingURL=index.cjs.map