@obelism/content 0.6.0 → 0.8.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/bridge.mjs CHANGED
@@ -2,6 +2,167 @@ import { P as PREVIEW_PARAMS, U as UID_ATTRIBUTE, E as ENTRY_ATTRIBUTE } from '.
2
2
  import { SITE_EDITING_COOKIE, SITE_REQUEST_HEADER } from './site.mjs';
3
3
  import { n as normalizeUrl, D as DEFAULT_URL } from './config-c6qktlz6.mjs';
4
4
 
5
+ // Click rates on the page: in the visual editor, a small label on each block
6
+ // that numbers has clicks for ("24% clicked"), from the editor's `stats`
7
+ // message. The editor's "Show click rates" switch turns it on and off. Plain
8
+ // DOM in a shadow root, like the prompt box, in a fixed layer that follows
9
+ // the blocks as the page scrolls, resizes and re-renders.
10
+ //
11
+ // Sites tag a block's clickable element with `data-numbers-id={block._uid}`
12
+ // and load Obelism numbers' script; the CMS reads the rates from numbers
13
+ // (the CMS's content/docs/guides/visual-editor.mdx, "Click rates").
14
+ const DEFAULT_STATS_LABELS = {
15
+ clicked: '{rate}% clicked',
16
+ title: '{clickers} of {viewers} visitors of its page clicked it in the last 30 days ({clicks} clicks)'
17
+ };
18
+ const fill = (template, values)=>template.replace(/\{(\w+)\}/g, (match, key)=>key in values ? String(values[key]) : match);
19
+ // The same tokens as the prompt box: near-black pill, beige text, the orange
20
+ // accent for the rate.
21
+ const CSS$1 = `
22
+ :host { all: initial; }
23
+ .layer {
24
+ position: fixed; inset: 0; pointer-events: none;
25
+ z-index: 2147483646;
26
+ font: 600 12px/1 'InterVariable', 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
27
+ -webkit-font-smoothing: antialiased;
28
+ }
29
+ .badge {
30
+ position: absolute; transform: translateX(-100%);
31
+ display: inline-flex; gap: 6px; align-items: center;
32
+ padding: 6px 10px; white-space: nowrap; cursor: pointer;
33
+ pointer-events: auto; border: 0;
34
+ color: rgb(238 236 233); background: rgb(12 12 12 / .88);
35
+ border-radius: 5em; box-shadow: 0 6px 16px -8px rgb(12 12 12 / .5);
36
+ font: inherit;
37
+ }
38
+ .badge::before {
39
+ content: ''; width: 8px; height: 8px; border-radius: 50%;
40
+ background: rgb(212 130 30);
41
+ }
42
+ .badge[data-place='beside'] { transform: translateY(-50%); }
43
+ .badge[data-place='above'] { transform: translate(-100%, -100%); }
44
+ .badge:focus-visible { outline: 2px solid rgb(212 130 30); outline-offset: 2px; }
45
+ `;
46
+ // Inset from a block's top-right corner, or gap beside a small element.
47
+ const INSET = 8;
48
+ // Below this an element is a button or a link, not a section: its label goes
49
+ // beside it (or above, without room on the right) so it doesn't cover it.
50
+ const SMALL_HEIGHT = 64;
51
+ // Room a label needs beside an element.
52
+ const LABEL_WIDTH = 140;
53
+ // Where a label goes for an element's box: inside the top-right corner of a
54
+ // block, beside a small element, or above one at the right edge.
55
+ const placeLabel = (rect, viewportWidth)=>{
56
+ if (rect.height >= SMALL_HEIGHT) return {
57
+ place: 'inside',
58
+ top: Math.max(rect.top, 0) + INSET,
59
+ left: rect.right - INSET
60
+ };
61
+ if (rect.right + INSET + LABEL_WIDTH <= viewportWidth) return {
62
+ place: 'beside',
63
+ top: rect.top + rect.height / 2,
64
+ left: rect.right + INSET
65
+ };
66
+ return {
67
+ place: 'above',
68
+ top: rect.top - INSET / 2,
69
+ left: rect.right
70
+ };
71
+ };
72
+ const mountStatsOverlay = (win, { selector, onSelect, labels: labelOverrides })=>{
73
+ const doc = win.document;
74
+ const labels = {
75
+ ...DEFAULT_STATS_LABELS,
76
+ ...labelOverrides
77
+ };
78
+ const host = doc.createElement('div');
79
+ host.setAttribute('data-obelism-stats', '');
80
+ const shadow = host.attachShadow({
81
+ mode: 'open'
82
+ });
83
+ const style = doc.createElement('style');
84
+ style.textContent = CSS$1;
85
+ const layer = doc.createElement('div');
86
+ layer.className = 'layer';
87
+ shadow.append(style, layer);
88
+ doc.body.appendChild(host);
89
+ let stats = {};
90
+ let visible = false;
91
+ let frame = null;
92
+ const render = ()=>{
93
+ frame = null;
94
+ layer.replaceChildren();
95
+ layer.hidden = !visible;
96
+ if (!visible) return;
97
+ const height = win.innerHeight;
98
+ for (const [uid, block] of Object.entries(stats)){
99
+ const element = doc.querySelector(selector(uid));
100
+ if (!element) continue;
101
+ const rect = element.getBoundingClientRect();
102
+ // Not rendered, or off screen.
103
+ if (!rect.width && !rect.height) continue;
104
+ if (rect.bottom < 0 || rect.top > height) continue;
105
+ const badge = doc.createElement('button');
106
+ badge.type = 'button';
107
+ badge.className = 'badge';
108
+ badge.dataset.uid = uid;
109
+ badge.textContent = fill(labels.clicked, {
110
+ rate: Math.round(block.rate * 100)
111
+ });
112
+ badge.title = fill(labels.title, {
113
+ clickers: block.clickers,
114
+ viewers: block.viewers,
115
+ clicks: block.clicks
116
+ });
117
+ const { place, top, left } = placeLabel(rect, win.innerWidth);
118
+ badge.dataset.place = place;
119
+ badge.style.top = `${top}px`;
120
+ badge.style.left = `${left}px`;
121
+ badge.addEventListener('click', ()=>onSelect(uid));
122
+ layer.appendChild(badge);
123
+ }
124
+ };
125
+ // At most once a frame, however many scroll and mutation events come in.
126
+ const schedule = ()=>{
127
+ if (frame !== null || !visible) return;
128
+ frame = win.requestAnimationFrame(render);
129
+ };
130
+ win.addEventListener('scroll', schedule, {
131
+ capture: true,
132
+ passive: true
133
+ });
134
+ win.addEventListener('resize', schedule);
135
+ // The site re-renders blocks on every `update`; follow them. Our own
136
+ // layer lives in a shadow root, so its changes don't come back here.
137
+ const Observer = win.MutationObserver;
138
+ const observer = typeof Observer === 'function' ? new Observer(schedule) : null;
139
+ observer?.observe(doc.body, {
140
+ childList: true,
141
+ subtree: true
142
+ });
143
+ return {
144
+ update (nextStats, nextVisible) {
145
+ stats = nextStats;
146
+ visible = nextVisible;
147
+ if (frame !== null) {
148
+ win.cancelAnimationFrame?.(frame);
149
+ frame = null;
150
+ }
151
+ render();
152
+ },
153
+ refresh: schedule,
154
+ destroy () {
155
+ if (frame !== null) win.cancelAnimationFrame?.(frame);
156
+ win.removeEventListener('scroll', schedule, {
157
+ capture: true
158
+ });
159
+ win.removeEventListener('resize', schedule);
160
+ observer?.disconnect();
161
+ host.remove();
162
+ }
163
+ };
164
+ };
165
+
5
166
  // The site's half of the visual editor (the CMS's public/bridge.js, as a
6
167
  // module). Inside the editor's iframe it outlines blocks, tells the editor
7
168
  // which one was clicked, hands the editor's live, unsaved entry to listeners
@@ -13,7 +174,7 @@ import { n as normalizeUrl, D as DEFAULT_URL } from './config-c6qktlz6.mjs';
13
174
  // 'select' | 'prompt' | 'undo', uid?, id?, prompt? }
14
175
  // - editor → site: { source: 'obelism-content-editor', type: 'connect' |
15
176
  // 'update' | 'select' | 'saved' | 'published' | 'features' |
16
- // 'promptResult' | 'promptState', … }
177
+ // 'promptResult' | 'promptState' | 'stats', … }
17
178
  const BRIDGE_SOURCE = 'obelism-content-bridge';
18
179
  const EDITOR_SOURCE = 'obelism-content-editor';
19
180
  // How long a prompt may take before it counts as failed.
@@ -29,7 +190,9 @@ const INITIAL_STATE = {
29
190
  unsaved: false,
30
191
  saving: false,
31
192
  publishing: false,
32
- selecting: false
193
+ selecting: false,
194
+ stats: {},
195
+ statsVisible: false
33
196
  };
34
197
  const createEmitter = ()=>{
35
198
  const listeners = {
@@ -70,6 +233,22 @@ const INERT_METHODS = {
70
233
  select: ()=>{},
71
234
  setSelecting: ()=>{}
72
235
  };
236
+ const isCount = (value)=>typeof value === 'number' && Number.isFinite(value) && value >= 0;
237
+ // The editor's `stats`, keeping only well-formed entries.
238
+ const readStats = (value)=>{
239
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return {};
240
+ const stats = {};
241
+ for (const [uid, block] of Object.entries(value)){
242
+ const { clicks, clickers, viewers, rate } = block ?? {};
243
+ if (isCount(clicks) && isCount(clickers) && isCount(viewers) && isCount(rate)) stats[uid] = {
244
+ clicks,
245
+ clickers,
246
+ viewers,
247
+ rate
248
+ };
249
+ }
250
+ return stats;
251
+ };
73
252
  // The selector of the element marked with a block's uid.
74
253
  const blockSelector = (uid)=>`[${UID_ATTRIBUTE}="${uid.replace(/["\\]/g, '\\$&')}"]`;
75
254
  // `cmsOrigin` is the only origin messages are accepted from and sent to.
@@ -198,6 +377,17 @@ const createBridge = (win, cmsOrigin)=>{
198
377
  uid
199
378
  });
200
379
  };
380
+ // Mounted with the first rates, so pages without numbers never get it.
381
+ let overlay = null;
382
+ const showStats = ()=>{
383
+ if (!overlay && !Object.keys(state.stats).length) return;
384
+ overlay ??= mountStatsOverlay(win, {
385
+ selector: blockSelector,
386
+ onSelect: (uid)=>bridge.select(uid)
387
+ });
388
+ overlay.update(state.stats, state.statsVisible);
389
+ };
390
+ cleanup.push(()=>overlay?.destroy());
201
391
  cleanup.push(()=>{
202
392
  for (const id of pending.keys()){
203
393
  settle(id)?.reject(new Error('The bridge was destroyed'));
@@ -218,6 +408,7 @@ const createBridge = (win, cmsOrigin)=>{
218
408
  });
219
409
  // Re-apply the selection to whatever the site rendered.
220
410
  win.requestAnimationFrame(()=>highlight(data.selectedUid, false));
411
+ overlay?.refresh();
221
412
  } else if (data.type === 'select') {
222
413
  highlight(data.uid, true);
223
414
  } else if (data.type === 'saved' || data.type === 'published') {
@@ -227,6 +418,13 @@ const createBridge = (win, cmsOrigin)=>{
227
418
  setState({
228
419
  features: data.features.filter((feature)=>typeof feature === 'string')
229
420
  });
421
+ } else if (data.type === 'stats') {
422
+ // An editor from before the switch sends no `visible`: show them.
423
+ setState({
424
+ stats: readStats(data.stats),
425
+ statsVisible: data.visible !== false
426
+ });
427
+ showStats();
230
428
  } else if (data.type === 'promptState') {
231
429
  setState({
232
430
  canUndo: data.canUndo === true
@@ -1019,7 +1217,7 @@ const createSiteBridge = (win, basePath, { pagePath = (path)=>`/${path}` } = {})
1019
1217
  locale: locale(),
1020
1218
  from: pageEntryId()
1021
1219
  });
1022
- const url = pagePath(created.path);
1220
+ const url = pagePath(created.path, locale() ?? '');
1023
1221
  win.location.assign(url);
1024
1222
  return {
1025
1223
  summary: created.summary,
@@ -1187,4 +1385,4 @@ const getContentBridge = ({ url, prompt = true, pagePath } = {})=>{
1187
1385
  return bridge;
1188
1386
  };
1189
1387
 
1190
- export { DEFAULT_PROMPT_LABELS, INITIAL_STATE, getContentBridge, mountPromptBox, peekContentBridge };
1388
+ export { DEFAULT_PROMPT_LABELS, DEFAULT_STATS_LABELS, INITIAL_STATE, getContentBridge, mountPromptBox, mountStatsOverlay, peekContentBridge };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RichTextFormat, E as Entry, a as EntryList, M as ModelFile, A as Asset, B as Block, I as ImproveBlock, b as EntryStub, c as RichTextNode } from './types-nyvor49r.js';
2
- export { C as ContentTypeDefinition, d as ContentTypeKind, e as Environment, F as FieldDefinition, f as FieldType, g as RichTextDocument, h as RichTextMark } from './types-nyvor49r.js';
1
+ import { R as RichTextFormat, E as Entry, a as RedirectList, b as Redirect, c as EntryList, M as ModelFile, A as Asset, B as Block, I as ImproveBlock, d as EntryStub, e as RichTextNode } from './types-2evub96q.js';
2
+ export { C as ContentTypeDefinition, f as ContentTypeKind, g as Environment, F as FieldDefinition, h as FieldType, i as RichTextDocument, j as RichTextMark } from './types-2evub96q.js';
3
3
 
4
4
  type ContentClientOptions = {
5
5
  token: string;
@@ -26,11 +26,29 @@ type EntriesQuery = RequestOptions & {
26
26
  limit?: number | undefined;
27
27
  skip?: number | undefined;
28
28
  };
29
+ type RedirectsQuery = {
30
+ locale?: string | undefined;
31
+ limit?: number | undefined;
32
+ skip?: number | undefined;
33
+ init?: RequestInit | undefined;
34
+ };
35
+ type PageLookup<TEntry extends Entry = Entry> = {
36
+ entry: TEntry;
37
+ redirect?: undefined;
38
+ } | {
39
+ entry?: undefined;
40
+ redirect: {
41
+ path: string;
42
+ };
43
+ };
29
44
  declare class ContentClient {
30
45
  #private;
31
46
  readonly url: string;
32
47
  constructor({ token, url, locale, depth, richText, timeout, init, fetch: fetchImpl, }: ContentClientOptions);
33
48
  getPage: <TEntry extends Entry = Entry>(path: string, options?: RequestOptions) => Promise<TEntry | null>;
49
+ findPage: <TEntry extends Entry = Entry>(path: string, options?: RequestOptions) => Promise<PageLookup<TEntry> | null>;
50
+ getRedirects: ({ locale, limit, skip, init, }?: RedirectsQuery) => Promise<RedirectList>;
51
+ getAllRedirects(query?: Omit<RedirectsQuery, 'skip'>): AsyncGenerator<Redirect, void, undefined>;
34
52
  getEntry: <TEntry extends Entry = Entry>(id: string, options?: RequestOptions) => Promise<TEntry | null>;
35
53
  getEntries: <TEntry extends Entry = Entry>({ contentType, parentPath, fields, order, limit, skip, ...options }?: EntriesQuery) => Promise<EntryList<TEntry>>;
36
54
  getFirstEntry: <TEntry extends Entry = Entry>(query?: Omit<EntriesQuery, "limit" | "skip">) => Promise<TEntry | null>;
@@ -98,6 +116,6 @@ declare const richTextToHtml: (doc: RichTextNode | null | undefined, { renderEnt
98
116
  declare const headingLevel: (node: RichTextNode) => 1 | 2 | 3 | 4 | 5 | 6;
99
117
  declare const richTextToPlainText: (doc: RichTextNode | null | undefined) => string;
100
118
 
101
- export { Asset, Block, ContentApiError, ContentClient, DEFAULT_URL, ENTRY_ATTRIBUTE, Entry, EntryList, EntryStub, IMPROVE_BLOCK, ImproveBlock, ModelFile, PREVIEW_PARAMS, RichTextFormat, RichTextNode, SAFE_HREF, UID_ATTRIBUTE, editable, escapeHtml, headingLevel, imageSrcSet, imageUrl, isImproveBlock, pickImproveVariant, readPreviewParams, richTextToHtml, richTextToPlainText };
102
- export type { ContentClientOptions, EntriesQuery, ImageTransform, PreviewParams, RequestOptions, RichTextHtmlOptions };
119
+ export { Asset, Block, ContentApiError, ContentClient, DEFAULT_URL, ENTRY_ATTRIBUTE, Entry, EntryList, EntryStub, IMPROVE_BLOCK, ImproveBlock, ModelFile, PREVIEW_PARAMS, Redirect, RedirectList, RichTextFormat, RichTextNode, SAFE_HREF, UID_ATTRIBUTE, editable, escapeHtml, headingLevel, imageSrcSet, imageUrl, isImproveBlock, pickImproveVariant, readPreviewParams, richTextToHtml, richTextToPlainText };
120
+ export type { ContentClientOptions, EntriesQuery, ImageTransform, PageLookup, PreviewParams, RedirectsQuery, RequestOptions, RichTextHtmlOptions };
103
121
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sources":["../src/client.ts","../src/config.ts","../src/editable.ts","../src/errors.ts","../src/images.ts","../src/improve.ts","../src/preview.ts","../src/richText.ts"],"mappings":";;;AACA,KAAK,oBAAoB;AACzB;AACA;AACA;AACA;AACA,eAAe,cAAc;AAC7B;AACA,WAAW,WAAW;AACtB,mBAAmB,KAAK;AACxB;AACA,KAAK,cAAc;AACnB;AACA;AACA,eAAe,cAAc;AAC7B,WAAW,WAAW;AACtB;AACA,KAAK,gBAAgB;AACrB,KAAK,YAAY,GAAG,cAAc;AAClC;AACA;AACA,aAAa,MAAM,SAAS,gBAAgB,YAAY,gBAAgB;AACxE;AACA;AACA;AACA;AACA,cAAc,aAAa;AAC3B;AACA;AACA,2FAA2F,oBAAoB;AAC/G,6BAA6B,KAAK,GAAG,KAAK,0BAA0B,cAAc,KAAK,OAAO;AAC9F,8BAA8B,KAAK,GAAG,KAAK,wBAAwB,cAAc,KAAK,OAAO;AAC7F,gCAAgC,KAAK,GAAG,KAAK,wEAAwE,YAAY,KAAK,OAAO,CAAC,SAAS;AACvJ,mCAAmC,KAAK,GAAG,KAAK,UAAU,IAAI,CAAC,YAAY,wBAAwB,OAAO;AAC1G,iCAAiC,KAAK,GAAG,KAAK,UAAU,IAAI,CAAC,YAAY,YAAY,cAAc;AACnG,gCAAgC,IAAI,CAAC,cAAc,cAAc,OAAO,CAAC,SAAS;AAClF;;ACpCA,cAAc,WAAW;;ACAzB,cAAc,aAAa;AAC3B,cAAc,eAAe;AAC7B,KAAK,QAAQ;AACb;AACA;AACA;AACA,cAAc,QAAQ;AACtB;AACA;AACA;AACA;AACA,yBAAyB,QAAQ;;ACXjC,cAAc,eAAe,SAAS,KAAK;AAC3C;AACA;AACA;AACA;AACA;;ACJA,KAAK,cAAc;AACnB;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,QAAQ,UAAU,IAAI,CAAC,KAAK,+BAA+B,cAAc;AACvF,cAAc,WAAW,UAAU,IAAI,CAAC,KAAK,iDAAiD,IAAI,CAAC,cAAc;;ACRjH,cAAc,aAAa;AAC3B,cAAc,cAAc,UAAU,KAAK,cAAc,YAAY;AACrE,cAAc,kBAAkB,kBAAkB,KAAK,SAAS,YAAY;;ACH5E,cAAc,cAAc;AAC5B;AACA;AACA;AACA;AACA;AACA,KAAK,aAAa;AAClB;AACA;AACA;AACA;AACA,KAAK,iBAAiB,GAAG,GAAG,GAAG,eAAe,YAAY,MAAM;AAChE,cAAc,iBAAiB,UAAU,iBAAiB,KAAK,aAAa;;ACX5E,cAAc,SAAS,EAAE,MAAM;AAC/B,cAAc,UAAU;AACxB,KAAK,mBAAmB;AACxB,0BAA0B,KAAK,GAAG,SAAS,QAAQ,YAAY;AAC/D,0BAA0B,KAAK,QAAQ,YAAY;AACnD;AACA,cAAc,cAAc,QAAQ,YAAY,oDAAoD,mBAAmB;AACvH,cAAc,YAAY,SAAS,YAAY;AAC/C,cAAc,mBAAmB,QAAQ,YAAY;;","names":[]}
1
+ {"version":3,"file":"index.d.mts","sources":["../src/client.ts","../src/config.ts","../src/editable.ts","../src/errors.ts","../src/images.ts","../src/improve.ts","../src/preview.ts","../src/richText.ts"],"mappings":";;;AACA,KAAK,oBAAoB;AACzB;AACA;AACA;AACA;AACA,eAAe,cAAc;AAC7B;AACA,WAAW,WAAW;AACtB,mBAAmB,KAAK;AACxB;AACA,KAAK,cAAc;AACnB;AACA;AACA,eAAe,cAAc;AAC7B,WAAW,WAAW;AACtB;AACA,KAAK,gBAAgB;AACrB,KAAK,YAAY,GAAG,cAAc;AAClC;AACA;AACA,aAAa,MAAM,SAAS,gBAAgB,YAAY,gBAAgB;AACxE;AACA;AACA;AACA;AACA,KAAK,cAAc;AACnB;AACA;AACA;AACA,WAAW,WAAW;AACtB;AACA,KAAK,UAAU,gBAAgB,KAAK,GAAG,KAAK;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,aAAa;AAC3B;AACA;AACA,2FAA2F,oBAAoB;AAC/G,6BAA6B,KAAK,GAAG,KAAK,0BAA0B,cAAc,KAAK,OAAO;AAC9F,8BAA8B,KAAK,GAAG,KAAK,0BAA0B,cAAc,KAAK,OAAO,CAAC,UAAU;AAC1G,oDAAoD,cAAc,KAAK,OAAO,CAAC,YAAY;AAC3F,4BAA4B,IAAI,CAAC,cAAc,YAAY,cAAc,CAAC,QAAQ;AAClF,8BAA8B,KAAK,GAAG,KAAK,wBAAwB,cAAc,KAAK,OAAO;AAC7F,gCAAgC,KAAK,GAAG,KAAK,wEAAwE,YAAY,KAAK,OAAO,CAAC,SAAS;AACvJ,mCAAmC,KAAK,GAAG,KAAK,UAAU,IAAI,CAAC,YAAY,wBAAwB,OAAO;AAC1G,iCAAiC,KAAK,GAAG,KAAK,UAAU,IAAI,CAAC,YAAY,YAAY,cAAc;AACnG,gCAAgC,IAAI,CAAC,cAAc,cAAc,OAAO,CAAC,SAAS;AAClF;;ACtDA,cAAc,WAAW;;ACAzB,cAAc,aAAa;AAC3B,cAAc,eAAe;AAC7B,KAAK,QAAQ;AACb;AACA;AACA;AACA,cAAc,QAAQ;AACtB;AACA;AACA;AACA;AACA,yBAAyB,QAAQ;;ACXjC,cAAc,eAAe,SAAS,KAAK;AAC3C;AACA;AACA;AACA;AACA;;ACJA,KAAK,cAAc;AACnB;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,QAAQ,UAAU,IAAI,CAAC,KAAK,+BAA+B,cAAc;AACvF,cAAc,WAAW,UAAU,IAAI,CAAC,KAAK,iDAAiD,IAAI,CAAC,cAAc;;ACRjH,cAAc,aAAa;AAC3B,cAAc,cAAc,UAAU,KAAK,cAAc,YAAY;AACrE,cAAc,kBAAkB,kBAAkB,KAAK,SAAS,YAAY;;ACH5E,cAAc,cAAc;AAC5B;AACA;AACA;AACA;AACA;AACA,KAAK,aAAa;AAClB;AACA;AACA;AACA;AACA,KAAK,iBAAiB,GAAG,GAAG,GAAG,eAAe,YAAY,MAAM;AAChE,cAAc,iBAAiB,UAAU,iBAAiB,KAAK,aAAa;;ACX5E,cAAc,SAAS,EAAE,MAAM;AAC/B,cAAc,UAAU;AACxB,KAAK,mBAAmB;AACxB,0BAA0B,KAAK,GAAG,SAAS,QAAQ,YAAY;AAC/D,0BAA0B,KAAK,QAAQ,YAAY;AACnD;AACA,cAAc,cAAc,QAAQ,YAAY,oDAAoD,mBAAmB;AACvH,cAAc,YAAY,SAAS,YAAY;AAC/C,cAAc,mBAAmB,QAAQ,YAAY;;","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RichTextFormat, E as Entry, a as EntryList, M as ModelFile, A as Asset, B as Block, I as ImproveBlock, b as EntryStub, c as RichTextNode } from './types-nyvor49r.js';
2
- export { C as ContentTypeDefinition, d as ContentTypeKind, e as Environment, F as FieldDefinition, f as FieldType, g as RichTextDocument, h as RichTextMark } from './types-nyvor49r.js';
1
+ import { R as RichTextFormat, E as Entry, a as RedirectList, b as Redirect, c as EntryList, M as ModelFile, A as Asset, B as Block, I as ImproveBlock, d as EntryStub, e as RichTextNode } from './types-2evub96q.js';
2
+ export { C as ContentTypeDefinition, f as ContentTypeKind, g as Environment, F as FieldDefinition, h as FieldType, i as RichTextDocument, j as RichTextMark } from './types-2evub96q.js';
3
3
 
4
4
  type ContentClientOptions = {
5
5
  token: string;
@@ -26,11 +26,29 @@ type EntriesQuery = RequestOptions & {
26
26
  limit?: number | undefined;
27
27
  skip?: number | undefined;
28
28
  };
29
+ type RedirectsQuery = {
30
+ locale?: string | undefined;
31
+ limit?: number | undefined;
32
+ skip?: number | undefined;
33
+ init?: RequestInit | undefined;
34
+ };
35
+ type PageLookup<TEntry extends Entry = Entry> = {
36
+ entry: TEntry;
37
+ redirect?: undefined;
38
+ } | {
39
+ entry?: undefined;
40
+ redirect: {
41
+ path: string;
42
+ };
43
+ };
29
44
  declare class ContentClient {
30
45
  #private;
31
46
  readonly url: string;
32
47
  constructor({ token, url, locale, depth, richText, timeout, init, fetch: fetchImpl, }: ContentClientOptions);
33
48
  getPage: <TEntry extends Entry = Entry>(path: string, options?: RequestOptions) => Promise<TEntry | null>;
49
+ findPage: <TEntry extends Entry = Entry>(path: string, options?: RequestOptions) => Promise<PageLookup<TEntry> | null>;
50
+ getRedirects: ({ locale, limit, skip, init, }?: RedirectsQuery) => Promise<RedirectList>;
51
+ getAllRedirects(query?: Omit<RedirectsQuery, 'skip'>): AsyncGenerator<Redirect, void, undefined>;
34
52
  getEntry: <TEntry extends Entry = Entry>(id: string, options?: RequestOptions) => Promise<TEntry | null>;
35
53
  getEntries: <TEntry extends Entry = Entry>({ contentType, parentPath, fields, order, limit, skip, ...options }?: EntriesQuery) => Promise<EntryList<TEntry>>;
36
54
  getFirstEntry: <TEntry extends Entry = Entry>(query?: Omit<EntriesQuery, "limit" | "skip">) => Promise<TEntry | null>;
@@ -98,6 +116,6 @@ declare const richTextToHtml: (doc: RichTextNode | null | undefined, { renderEnt
98
116
  declare const headingLevel: (node: RichTextNode) => 1 | 2 | 3 | 4 | 5 | 6;
99
117
  declare const richTextToPlainText: (doc: RichTextNode | null | undefined) => string;
100
118
 
101
- export { Asset, Block, ContentApiError, ContentClient, DEFAULT_URL, ENTRY_ATTRIBUTE, Entry, EntryList, EntryStub, IMPROVE_BLOCK, ImproveBlock, ModelFile, PREVIEW_PARAMS, RichTextFormat, RichTextNode, SAFE_HREF, UID_ATTRIBUTE, editable, escapeHtml, headingLevel, imageSrcSet, imageUrl, isImproveBlock, pickImproveVariant, readPreviewParams, richTextToHtml, richTextToPlainText };
102
- export type { ContentClientOptions, EntriesQuery, ImageTransform, PreviewParams, RequestOptions, RichTextHtmlOptions };
119
+ export { Asset, Block, ContentApiError, ContentClient, DEFAULT_URL, ENTRY_ATTRIBUTE, Entry, EntryList, EntryStub, IMPROVE_BLOCK, ImproveBlock, ModelFile, PREVIEW_PARAMS, Redirect, RedirectList, RichTextFormat, RichTextNode, SAFE_HREF, UID_ATTRIBUTE, editable, escapeHtml, headingLevel, imageSrcSet, imageUrl, isImproveBlock, pickImproveVariant, readPreviewParams, richTextToHtml, richTextToPlainText };
120
+ export type { ContentClientOptions, EntriesQuery, ImageTransform, PageLookup, PreviewParams, RedirectsQuery, RequestOptions, RichTextHtmlOptions };
103
121
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sources":["../src/client.ts","../src/config.ts","../src/editable.ts","../src/errors.ts","../src/images.ts","../src/improve.ts","../src/preview.ts","../src/richText.ts"],"mappings":";;;AACA,KAAK,oBAAoB;AACzB;AACA;AACA;AACA;AACA,eAAe,cAAc;AAC7B;AACA,WAAW,WAAW;AACtB,mBAAmB,KAAK;AACxB;AACA,KAAK,cAAc;AACnB;AACA;AACA,eAAe,cAAc;AAC7B,WAAW,WAAW;AACtB;AACA,KAAK,gBAAgB;AACrB,KAAK,YAAY,GAAG,cAAc;AAClC;AACA;AACA,aAAa,MAAM,SAAS,gBAAgB,YAAY,gBAAgB;AACxE;AACA;AACA;AACA;AACA,cAAc,aAAa;AAC3B;AACA;AACA,2FAA2F,oBAAoB;AAC/G,6BAA6B,KAAK,GAAG,KAAK,0BAA0B,cAAc,KAAK,OAAO;AAC9F,8BAA8B,KAAK,GAAG,KAAK,wBAAwB,cAAc,KAAK,OAAO;AAC7F,gCAAgC,KAAK,GAAG,KAAK,wEAAwE,YAAY,KAAK,OAAO,CAAC,SAAS;AACvJ,mCAAmC,KAAK,GAAG,KAAK,UAAU,IAAI,CAAC,YAAY,wBAAwB,OAAO;AAC1G,iCAAiC,KAAK,GAAG,KAAK,UAAU,IAAI,CAAC,YAAY,YAAY,cAAc;AACnG,gCAAgC,IAAI,CAAC,cAAc,cAAc,OAAO,CAAC,SAAS;AAClF;;ACpCA,cAAc,WAAW;;ACAzB,cAAc,aAAa;AAC3B,cAAc,eAAe;AAC7B,KAAK,QAAQ;AACb;AACA;AACA;AACA,cAAc,QAAQ;AACtB;AACA;AACA;AACA;AACA,yBAAyB,QAAQ;;ACXjC,cAAc,eAAe,SAAS,KAAK;AAC3C;AACA;AACA;AACA;AACA;;ACJA,KAAK,cAAc;AACnB;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,QAAQ,UAAU,IAAI,CAAC,KAAK,+BAA+B,cAAc;AACvF,cAAc,WAAW,UAAU,IAAI,CAAC,KAAK,iDAAiD,IAAI,CAAC,cAAc;;ACRjH,cAAc,aAAa;AAC3B,cAAc,cAAc,UAAU,KAAK,cAAc,YAAY;AACrE,cAAc,kBAAkB,kBAAkB,KAAK,SAAS,YAAY;;ACH5E,cAAc,cAAc;AAC5B;AACA;AACA;AACA;AACA;AACA,KAAK,aAAa;AAClB;AACA;AACA;AACA;AACA,KAAK,iBAAiB,GAAG,GAAG,GAAG,eAAe,YAAY,MAAM;AAChE,cAAc,iBAAiB,UAAU,iBAAiB,KAAK,aAAa;;ACX5E,cAAc,SAAS,EAAE,MAAM;AAC/B,cAAc,UAAU;AACxB,KAAK,mBAAmB;AACxB,0BAA0B,KAAK,GAAG,SAAS,QAAQ,YAAY;AAC/D,0BAA0B,KAAK,QAAQ,YAAY;AACnD;AACA,cAAc,cAAc,QAAQ,YAAY,oDAAoD,mBAAmB;AACvH,cAAc,YAAY,SAAS,YAAY;AAC/C,cAAc,mBAAmB,QAAQ,YAAY;;","names":[]}
1
+ {"version":3,"file":"index.d.ts","sources":["../src/client.ts","../src/config.ts","../src/editable.ts","../src/errors.ts","../src/images.ts","../src/improve.ts","../src/preview.ts","../src/richText.ts"],"mappings":";;;AACA,KAAK,oBAAoB;AACzB;AACA;AACA;AACA;AACA,eAAe,cAAc;AAC7B;AACA,WAAW,WAAW;AACtB,mBAAmB,KAAK;AACxB;AACA,KAAK,cAAc;AACnB;AACA;AACA,eAAe,cAAc;AAC7B,WAAW,WAAW;AACtB;AACA,KAAK,gBAAgB;AACrB,KAAK,YAAY,GAAG,cAAc;AAClC;AACA;AACA,aAAa,MAAM,SAAS,gBAAgB,YAAY,gBAAgB;AACxE;AACA;AACA;AACA;AACA,KAAK,cAAc;AACnB;AACA;AACA;AACA,WAAW,WAAW;AACtB;AACA,KAAK,UAAU,gBAAgB,KAAK,GAAG,KAAK;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,aAAa;AAC3B;AACA;AACA,2FAA2F,oBAAoB;AAC/G,6BAA6B,KAAK,GAAG,KAAK,0BAA0B,cAAc,KAAK,OAAO;AAC9F,8BAA8B,KAAK,GAAG,KAAK,0BAA0B,cAAc,KAAK,OAAO,CAAC,UAAU;AAC1G,oDAAoD,cAAc,KAAK,OAAO,CAAC,YAAY;AAC3F,4BAA4B,IAAI,CAAC,cAAc,YAAY,cAAc,CAAC,QAAQ;AAClF,8BAA8B,KAAK,GAAG,KAAK,wBAAwB,cAAc,KAAK,OAAO;AAC7F,gCAAgC,KAAK,GAAG,KAAK,wEAAwE,YAAY,KAAK,OAAO,CAAC,SAAS;AACvJ,mCAAmC,KAAK,GAAG,KAAK,UAAU,IAAI,CAAC,YAAY,wBAAwB,OAAO;AAC1G,iCAAiC,KAAK,GAAG,KAAK,UAAU,IAAI,CAAC,YAAY,YAAY,cAAc;AACnG,gCAAgC,IAAI,CAAC,cAAc,cAAc,OAAO,CAAC,SAAS;AAClF;;ACtDA,cAAc,WAAW;;ACAzB,cAAc,aAAa;AAC3B,cAAc,eAAe;AAC7B,KAAK,QAAQ;AACb;AACA;AACA;AACA,cAAc,QAAQ;AACtB;AACA;AACA;AACA;AACA,yBAAyB,QAAQ;;ACXjC,cAAc,eAAe,SAAS,KAAK;AAC3C;AACA;AACA;AACA;AACA;;ACJA,KAAK,cAAc;AACnB;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,QAAQ,UAAU,IAAI,CAAC,KAAK,+BAA+B,cAAc;AACvF,cAAc,WAAW,UAAU,IAAI,CAAC,KAAK,iDAAiD,IAAI,CAAC,cAAc;;ACRjH,cAAc,aAAa;AAC3B,cAAc,cAAc,UAAU,KAAK,cAAc,YAAY;AACrE,cAAc,kBAAkB,kBAAkB,KAAK,SAAS,YAAY;;ACH5E,cAAc,cAAc;AAC5B;AACA;AACA;AACA;AACA;AACA,KAAK,aAAa;AAClB;AACA;AACA;AACA;AACA,KAAK,iBAAiB,GAAG,GAAG,GAAG,eAAe,YAAY,MAAM;AAChE,cAAc,iBAAiB,UAAU,iBAAiB,KAAK,aAAa;;ACX5E,cAAc,SAAS,EAAE,MAAM;AAC/B,cAAc,UAAU;AACxB,KAAK,mBAAmB;AACxB,0BAA0B,KAAK,GAAG,SAAS,QAAQ,YAAY;AAC/D,0BAA0B,KAAK,QAAQ,YAAY;AACnD;AACA,cAAc,cAAc,QAAQ,YAAY,oDAAoD,mBAAmB;AACvH,cAAc,YAAY,SAAS,YAAY;AAC/C,cAAc,mBAAmB,QAAQ,YAAY;;","names":[]}
package/dist/index.js CHANGED
@@ -42,17 +42,45 @@ class ContentClient {
42
42
  #fetch;
43
43
  constructor({ token, url, locale, depth, richText, timeout, init, fetch: fetchImpl }){
44
44
  // The page at a path (`blog/hello`), or null when there is none. A site's
45
- // catch-all route asks for this.
46
- this.getPage = async (path, options = {})=>{
45
+ // catch-all route asks for this. The path is looked up in `locale`'s
46
+ // paths (the default locale's when left out or `*`): pages can have a
47
+ // slug per locale.
48
+ this.getPage = async (path, options = {})=>(await this.findPage(path, options))?.entry ?? null;
49
+ // Like getPage, but a path a page moved away from answers where it is
50
+ // now, so the site can send a 301 there instead of a 404.
51
+ //
52
+ // const found = await content.findPage(path, { locale })
53
+ // if (found?.redirect) return redirect(`/${locale}/${found.redirect.path}`, 301)
54
+ // if (!found) return notFound()
55
+ this.findPage = async (path, options = {})=>{
47
56
  const trimmed = trimSlashes(path);
48
57
  if (!trimmed) throw new Error('getPage needs a path');
49
58
  const result = await this.#request('/pages', {
50
59
  path: trimmed
51
60
  }, options, {
52
- notFound: true
61
+ notFound: 'body'
53
62
  });
54
- return result?.entry ?? null;
63
+ if (result && 'entry' in result) return {
64
+ entry: result.entry
65
+ };
66
+ const to = result?.redirect?.path;
67
+ return typeof to === 'string' ? {
68
+ redirect: {
69
+ path: to
70
+ }
71
+ } : null;
55
72
  };
73
+ // One page of redirects: every path a page moved away from, per locale,
74
+ // with where it is now. For redirect rules built ahead of time.
75
+ this.getRedirects = ({ locale, limit, skip, init } = {})=>this.#request('/redirects', {
76
+ limit,
77
+ skip
78
+ }, {
79
+ locale,
80
+ init
81
+ }, {
82
+ defaults: false
83
+ });
56
84
  // An entry by id, or null when there is none (or it isn't published, for a
57
85
  // delivery token).
58
86
  this.getEntry = async (id, options = {})=>{
@@ -93,6 +121,21 @@ class ContentClient {
93
121
  this.#init = init;
94
122
  this.#fetch = fetchImpl ?? ((...args)=>fetch(...args));
95
123
  }
124
+ // Every redirect, fetching pages of `limit` (default 1000) as it goes.
125
+ async *getAllRedirects(query = {}) {
126
+ const limit = query.limit ?? 1000;
127
+ let skip = 0;
128
+ while(true){
129
+ const page = await this.getRedirects({
130
+ ...query,
131
+ limit,
132
+ skip
133
+ });
134
+ yield* page.items;
135
+ skip += page.items.length;
136
+ if (page.items.length === 0 || skip >= page.total) return;
137
+ }
138
+ }
96
139
  // Every entry matching the query, fetching pages of `limit` (default 100)
97
140
  // as it goes.
98
141
  //
@@ -111,7 +154,8 @@ class ContentClient {
111
154
  if (page.items.length === 0 || skip >= page.total) return;
112
155
  }
113
156
  }
114
- // null for a 404 when `notFound` is set; throws ContentApiError otherwise.
157
+ // For a 404, null when `notFound` is set, or the body as is for 'body';
158
+ // throws ContentApiError otherwise.
115
159
  async #request(path, query, { init, ...options }, { notFound = false, defaults = true } = {}) {
116
160
  // Checked here rather than in the constructor, so a module creating a
117
161
  // client still loads (and a build still runs) without the variable.
@@ -149,7 +193,7 @@ class ContentClient {
149
193
  timeout
150
194
  ]) : timeout
151
195
  });
152
- if (notFound && response.status === 404) return null;
196
+ if (notFound === true && response.status === 404) return null;
153
197
  const text = await response.text();
154
198
  let body = text;
155
199
  try {
@@ -157,6 +201,9 @@ class ContentClient {
157
201
  } catch {
158
202
  // Not JSON: keep the text for the error.
159
203
  }
204
+ if (notFound === 'body' && response.status === 404) {
205
+ return typeof body === 'object' && body !== null ? body : null;
206
+ }
160
207
  if (!response.ok) throw new ContentApiError(response.status, url, body);
161
208
  return body;
162
209
  }
package/dist/index.mjs CHANGED
@@ -40,17 +40,45 @@ class ContentClient {
40
40
  #fetch;
41
41
  constructor({ token, url, locale, depth, richText, timeout, init, fetch: fetchImpl }){
42
42
  // The page at a path (`blog/hello`), or null when there is none. A site's
43
- // catch-all route asks for this.
44
- this.getPage = async (path, options = {})=>{
43
+ // catch-all route asks for this. The path is looked up in `locale`'s
44
+ // paths (the default locale's when left out or `*`): pages can have a
45
+ // slug per locale.
46
+ this.getPage = async (path, options = {})=>(await this.findPage(path, options))?.entry ?? null;
47
+ // Like getPage, but a path a page moved away from answers where it is
48
+ // now, so the site can send a 301 there instead of a 404.
49
+ //
50
+ // const found = await content.findPage(path, { locale })
51
+ // if (found?.redirect) return redirect(`/${locale}/${found.redirect.path}`, 301)
52
+ // if (!found) return notFound()
53
+ this.findPage = async (path, options = {})=>{
45
54
  const trimmed = trimSlashes(path);
46
55
  if (!trimmed) throw new Error('getPage needs a path');
47
56
  const result = await this.#request('/pages', {
48
57
  path: trimmed
49
58
  }, options, {
50
- notFound: true
59
+ notFound: 'body'
51
60
  });
52
- return result?.entry ?? null;
61
+ if (result && 'entry' in result) return {
62
+ entry: result.entry
63
+ };
64
+ const to = result?.redirect?.path;
65
+ return typeof to === 'string' ? {
66
+ redirect: {
67
+ path: to
68
+ }
69
+ } : null;
53
70
  };
71
+ // One page of redirects: every path a page moved away from, per locale,
72
+ // with where it is now. For redirect rules built ahead of time.
73
+ this.getRedirects = ({ locale, limit, skip, init } = {})=>this.#request('/redirects', {
74
+ limit,
75
+ skip
76
+ }, {
77
+ locale,
78
+ init
79
+ }, {
80
+ defaults: false
81
+ });
54
82
  // An entry by id, or null when there is none (or it isn't published, for a
55
83
  // delivery token).
56
84
  this.getEntry = async (id, options = {})=>{
@@ -91,6 +119,21 @@ class ContentClient {
91
119
  this.#init = init;
92
120
  this.#fetch = fetchImpl ?? ((...args)=>fetch(...args));
93
121
  }
122
+ // Every redirect, fetching pages of `limit` (default 1000) as it goes.
123
+ async *getAllRedirects(query = {}) {
124
+ const limit = query.limit ?? 1000;
125
+ let skip = 0;
126
+ while(true){
127
+ const page = await this.getRedirects({
128
+ ...query,
129
+ limit,
130
+ skip
131
+ });
132
+ yield* page.items;
133
+ skip += page.items.length;
134
+ if (page.items.length === 0 || skip >= page.total) return;
135
+ }
136
+ }
94
137
  // Every entry matching the query, fetching pages of `limit` (default 100)
95
138
  // as it goes.
96
139
  //
@@ -109,7 +152,8 @@ class ContentClient {
109
152
  if (page.items.length === 0 || skip >= page.total) return;
110
153
  }
111
154
  }
112
- // null for a 404 when `notFound` is set; throws ContentApiError otherwise.
155
+ // For a 404, null when `notFound` is set, or the body as is for 'body';
156
+ // throws ContentApiError otherwise.
113
157
  async #request(path, query, { init, ...options }, { notFound = false, defaults = true } = {}) {
114
158
  // Checked here rather than in the constructor, so a module creating a
115
159
  // client still loads (and a build still runs) without the variable.
@@ -147,7 +191,7 @@ class ContentClient {
147
191
  timeout
148
192
  ]) : timeout
149
193
  });
150
- if (notFound && response.status === 404) return null;
194
+ if (notFound === true && response.status === 404) return null;
151
195
  const text = await response.text();
152
196
  let body = text;
153
197
  try {
@@ -155,6 +199,9 @@ class ContentClient {
155
199
  } catch {
156
200
  // Not JSON: keep the text for the error.
157
201
  }
202
+ if (notFound === 'body' && response.status === 404) {
203
+ return typeof body === 'object' && body !== null ? body : null;
204
+ }
158
205
  if (!response.ok) throw new ContentApiError(response.status, url, body);
159
206
  return body;
160
207
  }
@@ -17,6 +17,7 @@ type Entry<TFields extends Record<string, unknown> = Record<string, unknown>, TC
17
17
  name: string;
18
18
  slug: string | null;
19
19
  path: string | null;
20
+ paths: Record<string, string>;
20
21
  publishedAt: string | null;
21
22
  firstPublishedAt: string | null;
22
23
  updatedAt: string;
@@ -55,6 +56,17 @@ type EntryList<TEntry extends Entry = Entry> = {
55
56
  limit: number;
56
57
  skip: number;
57
58
  };
59
+ type Redirect = {
60
+ locale: string;
61
+ from: string;
62
+ to: string;
63
+ };
64
+ type RedirectList = {
65
+ items: Redirect[];
66
+ total: number;
67
+ limit: number;
68
+ skip: number;
69
+ };
58
70
  type ContentTypeKind = 'page' | 'data' | 'block';
59
71
  type BaseField = {
60
72
  apiId: string;
@@ -121,5 +133,5 @@ type ModelFile = {
121
133
  contentTypes: ContentTypeDefinition[];
122
134
  };
123
135
 
124
- export type { Asset as A, Block as B, ContentTypeDefinition as C, Entry as E, FieldDefinition as F, ImproveBlock as I, ModelFile as M, RichTextFormat as R, EntryList as a, EntryStub as b, RichTextNode as c, ContentTypeKind as d, Environment as e, FieldType as f, RichTextDocument as g, RichTextMark as h };
125
- //# sourceMappingURL=types-nyvor49r.d.ts.map
136
+ export type { Asset as A, Block as B, ContentTypeDefinition as C, Entry as E, FieldDefinition as F, ImproveBlock as I, ModelFile as M, RichTextFormat as R, RedirectList as a, Redirect as b, EntryList as c, EntryStub as d, RichTextNode as e, ContentTypeKind as f, Environment as g, FieldType as h, RichTextDocument as i, RichTextMark as j };
137
+ //# sourceMappingURL=types-2evub96q.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-2evub96q.d.ts","sources":["../src/types.ts"],"mappings":"AAAA,KAAK,WAAW;AAChB,KAAK,cAAc;AACnB,KAAK,KAAK;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,MAAM;AAC1B,kBAAkB,MAAM;AACxB;AACA,KAAK,KAAK,iBAAiB,MAAM,oBAAoB,MAAM;AAC3D;AACA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB;AACA;AACA;AACA;AACA;AACA,KAAK,SAAS;AACd;AACA;AACA;AACA,KAAK,KAAK,iBAAiB,MAAM,oBAAoB,MAAM;AAC3D;AACA;AACA;AACA,KAAK,YAAY,gBAAgB,KAAK,GAAG,KAAK,IAAI,KAAK;AACvD;AACA;AACA,cAAc,MAAM;AACpB;AACA,KAAK,YAAY;AACjB;AACA,YAAY,MAAM;AAClB;AACA,KAAK,YAAY;AACjB;AACA,YAAY,MAAM;AAClB,cAAc,YAAY;AAC1B;AACA,YAAY,YAAY;AACxB;AACA,KAAK,gBAAgB,GAAG,YAAY;AACpC;AACA;AACA,KAAK,SAAS,gBAAgB,KAAK,GAAG,KAAK;AAC3C;AACA;AACA;AACA;AACA;AACA,KAAK,QAAQ;AACb;AACA;AACA;AACA;AACA,KAAK,YAAY;AACjB,WAAW,QAAQ;AACnB;AACA;AACA;AACA;AACA,KAAK,eAAe;AACpB,KAAK,SAAS;AACd;AACA;AACA;AACA;AACA;AACA;AACA,KAAK,eAAe,GAAG,SAAS;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK,SAAS,GAAG,eAAe;AAChC,KAAK,qBAAqB;AAC1B;AACA;AACA,UAAU,eAAe;AACzB;AACA,YAAY,eAAe;AAC3B;AACA,KAAK,SAAS;AACd;AACA;AACA,kBAAkB,qBAAqB;AACvC;;","names":[]}
@@ -5,6 +5,7 @@ type WebhookEntry = {
5
5
  contentType: string;
6
6
  name: string;
7
7
  path: string | null;
8
+ paths: Record<string, string>;
8
9
  };
9
10
  type WebhookEventOf<TType extends string, TData> = {
10
11
  type: TType;
@@ -25,6 +26,7 @@ type EntryDeletedEvent = WebhookEventOf<'entry.deleted', {
25
26
  type EntryMovedEvent = WebhookEventOf<'entry.moved', {
26
27
  entry: WebhookEntry;
27
28
  previousPath: string | null;
29
+ previousPaths: Record<string, string>;
28
30
  }>;
29
31
  type AssetUpdatedEvent = WebhookEventOf<'asset.updated', {
30
32
  asset: {
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.d.mts","sources":["../src/webhooks.ts"],"mappings":";;AACA,KAAK,YAAY;AACjB;AACA;AACA;AACA;AACA;AACA,KAAK,cAAc;AACnB;AACA;AACA;AACA,iBAAiB,WAAW;AAC5B;AACA;AACA,KAAK,mBAAmB,GAAG,cAAc;AACzC,WAAW,YAAY;AACvB;AACA,KAAK,qBAAqB,GAAG,cAAc;AAC3C,WAAW,YAAY;AACvB;AACA,KAAK,iBAAiB,GAAG,cAAc;AACvC,WAAW,YAAY;AACvB;AACA,KAAK,eAAe,GAAG,cAAc;AACrC,WAAW,YAAY;AACvB;AACA;AACA,KAAK,iBAAiB,GAAG,cAAc;AACvC;AACA;AACA;AACA;AACA,aAAa,YAAY;AACzB;AACA,KAAK,iBAAiB,GAAG,cAAc;AACvC;AACA;AACA;AACA;AACA;AACA,KAAK,mBAAmB,GAAG,cAAc;AACzC;AACA;AACA;AACA,KAAK,gBAAgB,GAAG,cAAc,iBAAiB,MAAM;AAC7D,KAAK,YAAY,GAAG,mBAAmB,GAAG,qBAAqB,GAAG,iBAAiB,GAAG,eAAe,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,mBAAmB,GAAG,gBAAgB;AACtL,KAAK,gBAAgB,GAAG,YAAY;AACpC,cAAc,wBAAwB,SAAS,KAAK;AACpD;AACA;AACA,KAAK,cAAc;AACnB;AACA,aAAa,OAAO,GAAG,MAAM,0CAA0C,QAAQ;AAC/E;AACA,KAAK,oBAAoB;AACzB;AACA;AACA;AACA,cAAc,aAAa,YAAY,OAAO,GAAG,cAAc,wCAAwC,oBAAoB,KAAK,OAAO,CAAC,YAAY;AACpJ,KAAK,qBAAqB;AAC1B;AACA,qBAAqB,YAAY;AACjC;AACA;AACA;AACA;AACA,cAAc,oBAAoB,mCAAmC,qBAAqB,eAAe,OAAO,KAAK,OAAO,CAAC,QAAQ","names":[]}
1
+ {"version":3,"file":"webhooks.d.mts","sources":["../src/webhooks.ts"],"mappings":";;AACA,KAAK,YAAY;AACjB;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB;AACA,KAAK,cAAc;AACnB;AACA;AACA;AACA,iBAAiB,WAAW;AAC5B;AACA;AACA,KAAK,mBAAmB,GAAG,cAAc;AACzC,WAAW,YAAY;AACvB;AACA,KAAK,qBAAqB,GAAG,cAAc;AAC3C,WAAW,YAAY;AACvB;AACA,KAAK,iBAAiB,GAAG,cAAc;AACvC,WAAW,YAAY;AACvB;AACA,KAAK,eAAe,GAAG,cAAc;AACrC,WAAW,YAAY;AACvB;AACA,mBAAmB,MAAM;AACzB;AACA,KAAK,iBAAiB,GAAG,cAAc;AACvC;AACA;AACA;AACA;AACA,aAAa,YAAY;AACzB;AACA,KAAK,iBAAiB,GAAG,cAAc;AACvC;AACA;AACA;AACA;AACA;AACA,KAAK,mBAAmB,GAAG,cAAc;AACzC;AACA;AACA;AACA,KAAK,gBAAgB,GAAG,cAAc,iBAAiB,MAAM;AAC7D,KAAK,YAAY,GAAG,mBAAmB,GAAG,qBAAqB,GAAG,iBAAiB,GAAG,eAAe,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,mBAAmB,GAAG,gBAAgB;AACtL,KAAK,gBAAgB,GAAG,YAAY;AACpC,cAAc,wBAAwB,SAAS,KAAK;AACpD;AACA;AACA,KAAK,cAAc;AACnB;AACA,aAAa,OAAO,GAAG,MAAM,0CAA0C,QAAQ;AAC/E;AACA,KAAK,oBAAoB;AACzB;AACA;AACA;AACA,cAAc,aAAa,YAAY,OAAO,GAAG,cAAc,wCAAwC,oBAAoB,KAAK,OAAO,CAAC,YAAY;AACpJ,KAAK,qBAAqB;AAC1B;AACA,qBAAqB,YAAY;AACjC;AACA;AACA;AACA;AACA,cAAc,oBAAoB,mCAAmC,qBAAqB,eAAe,OAAO,KAAK,OAAO,CAAC,QAAQ","names":[]}