@b10cks/client 1.3.0 → 1.5.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/README.md +183 -2
- package/dist/index.d.ts +214 -4
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +352 -118
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -16,9 +16,13 @@ import { ApiClient, createB10cksDataApi } from '@b10cks/client'
|
|
|
16
16
|
const client = new ApiClient({
|
|
17
17
|
baseUrl: 'https://api.b10cks.com/api',
|
|
18
18
|
token: 'your-access-token',
|
|
19
|
+
version: 'published', // 'published' (default) or 'draft'
|
|
20
|
+
rv: 0, // revision token — pass Date.now() to bypass CDN cache
|
|
19
21
|
})
|
|
20
22
|
|
|
23
|
+
// Factory function — equivalent to new B10cksDataApi(client)
|
|
21
24
|
const dataApi = createB10cksDataApi(client)
|
|
25
|
+
// or: import { B10cksDataApi } from '@b10cks/client'; const dataApi = new B10cksDataApi(client)
|
|
22
26
|
|
|
23
27
|
// Fetch a page of contents
|
|
24
28
|
const contents = await dataApi.getContents({ vid: 'published', page: 1, per_page: 20 })
|
|
@@ -143,6 +147,20 @@ const params = serializeFilter({
|
|
|
143
147
|
|
|
144
148
|
Pass `{ allPages: true }` as the second argument to any collection method to fetch every page automatically.
|
|
145
149
|
|
|
150
|
+
## `ApiClient` configuration
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
interface B10cksApiClientOptions {
|
|
154
|
+
baseUrl: string // Base URL of the b10cks data API (include `/api`)
|
|
155
|
+
token: string // Space access token
|
|
156
|
+
version?: 'published' | 'draft' // Content version to fetch (default: 'published')
|
|
157
|
+
rv?: string | number // Revision token; use Date.now() to bypass CDN cache
|
|
158
|
+
fetchClient?: FetchClient // Custom fetch implementation (required in environments without globalThis.fetch)
|
|
159
|
+
getRv?: () => string | number // Custom getter for the shared revision token
|
|
160
|
+
setRv?: (value: string | number) => void // Custom setter for the shared revision token
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
146
164
|
## Low-level `ApiClient`
|
|
147
165
|
|
|
148
166
|
`ApiClient` implements the `DataApiClient` interface and can be used directly for one-off requests:
|
|
@@ -150,8 +168,12 @@ Pass `{ allPages: true }` as the second argument to any collection method to fet
|
|
|
150
168
|
```typescript
|
|
151
169
|
const client = new ApiClient({ baseUrl, token })
|
|
152
170
|
|
|
153
|
-
// GET with custom params
|
|
154
|
-
const data = await client.get('contents', { page: 1,
|
|
171
|
+
// GET with custom params — all extra keys are forwarded as query params as-is
|
|
172
|
+
const data = await client.get('contents', { page: 1, language_iso: 'de', vid: 'published' })
|
|
173
|
+
|
|
174
|
+
// Per-request rv override — pass rv in params to override the instance-level revision token
|
|
175
|
+
// (useful to bypass CDN cache for a single request without affecting other calls)
|
|
176
|
+
const fresh = await client.get('contents', { rv: Date.now() })
|
|
155
177
|
|
|
156
178
|
// GET all pages
|
|
157
179
|
const all = await client.getAll('blocks')
|
|
@@ -176,6 +198,165 @@ const result = await client.post('redirects/lookup', { source: '/old' })
|
|
|
176
198
|
| `sitemap` | GET (list) |
|
|
177
199
|
| `spaces/me` | GET |
|
|
178
200
|
|
|
201
|
+
## Link resolution
|
|
202
|
+
|
|
203
|
+
`resolveB10cksLink` converts a `B10cksLink` value (the union type emitted by the type generator for `link`-type fields) into a plain `{ href, target }` object. Locale prefixing and router integration are left to the caller.
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
import { resolveB10cksLink } from '@b10cks/client'
|
|
207
|
+
|
|
208
|
+
const resolved = resolveB10cksLink(block.ctaLink)
|
|
209
|
+
// resolved: { href: 'https://example.com', target: '_blank' }
|
|
210
|
+
// or: { href: 'mailto:hi@example.com', target: '_self' }
|
|
211
|
+
// or: undefined (when link is nullish or type === 'asset')
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Sitemap utilities
|
|
215
|
+
|
|
216
|
+
Framework-agnostic helpers for building multilingual sitemaps from `IBSitemapEntry[]`.
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
import {
|
|
220
|
+
buildLocalizedPath,
|
|
221
|
+
filterSitemapEntries,
|
|
222
|
+
renderSitemapXml,
|
|
223
|
+
renderSitemapIndex,
|
|
224
|
+
} from '@b10cks/client'
|
|
225
|
+
|
|
226
|
+
// Build a rooted locale-prefixed path from a content entry
|
|
227
|
+
buildLocalizedPath('about', 'en') // → '/en/about'
|
|
228
|
+
buildLocalizedPath('home', 'en') // → '/en'
|
|
229
|
+
buildLocalizedPath('de/uber-uns', 'de') // → '/de/uber-uns' (no double prefix)
|
|
230
|
+
|
|
231
|
+
// Filter: deduplicate, drop noindex, optionally restrict to one locale
|
|
232
|
+
const filtered = filterSitemapEntries(entries, {
|
|
233
|
+
siteUrl: 'https://example.com',
|
|
234
|
+
locale: 'en',
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
// Render <urlset> XML
|
|
238
|
+
const xml = renderSitemapXml(filtered, 'https://example.com')
|
|
239
|
+
|
|
240
|
+
// Render <sitemapindex> XML for multi-sitemap setups
|
|
241
|
+
const index = renderSitemapIndex(['/sitemap-en.xml', '/sitemap-de.xml'], 'https://example.com')
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Preview bridge & visual editing
|
|
245
|
+
|
|
246
|
+
When a page is rendered inside the b10cks visual editor (in an `<iframe>`), the SDK exchanges `postMessage` events with the editor so blocks can be selected, hovered, and live-updated while editing. These are the framework-agnostic building blocks — the `@b10cks/vue`, `@b10cks/react`, `@b10cks/svelte`, `@b10cks/nuxt`, and `@b10cks/next` packages wrap them in idiomatic directives/hooks/actions.
|
|
247
|
+
|
|
248
|
+
### `previewBridge`
|
|
249
|
+
|
|
250
|
+
A singleton that bridges the preview iframe and the editor.
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
import { previewBridge } from '@b10cks/client'
|
|
254
|
+
|
|
255
|
+
// Call once on the client when your app boots (the framework packages do this for you).
|
|
256
|
+
previewBridge.init({ allowedOrigins: ['https://app.b10cks.com'] })
|
|
257
|
+
|
|
258
|
+
previewBridge.isInPreviewMode() // true only inside the editor iframe
|
|
259
|
+
previewBridge.selectItem(blockId) // tell the editor to select a block
|
|
260
|
+
previewBridge.selectField(blockId, path) // deep-select a nested field (e.g. rich text)
|
|
261
|
+
previewBridge.updateFieldAt(blockId, ['headline'], 'New text') // stream an inline edit
|
|
262
|
+
|
|
263
|
+
// Subscribe to editor → preview events; returns an unsubscribe function.
|
|
264
|
+
const off = previewBridge.on('CONTENT_UPDATE', ({ content }) => { /* … */ })
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Event protocol:
|
|
268
|
+
|
|
269
|
+
| Event | Direction | Payload | Purpose |
|
|
270
|
+
|---|---|---|---|
|
|
271
|
+
| `SELECT_UPDATE` | both | `{ selectedItem }` | Select a block |
|
|
272
|
+
| `HOVER_UPDATE` | editor → preview | `{ selectedItem }` | Hover-highlight a block |
|
|
273
|
+
| `FIELD_SELECT` | preview → editor | `{ itemId, path }` | Deep-select a field so the editor opens its own editor |
|
|
274
|
+
| `FIELD_UPDATE` | preview → editor | `{ itemId, path?, field?, value }` | Stream an inline edit |
|
|
275
|
+
| `CONTENT_UPDATE` | editor → preview | `{ content }` | Replace the whole content tree |
|
|
276
|
+
| `CONTENT_PATCH` | editor → preview | `{ path, value }` | Replace a single value at `path` |
|
|
277
|
+
|
|
278
|
+
`path` is a `FieldPath` (`(string | number)[]`) that addresses any value at any depth, including array indices — e.g. `['body', 2, 'headline']`.
|
|
279
|
+
|
|
280
|
+
#### Security
|
|
281
|
+
|
|
282
|
+
By default the bridge locks onto the origin of the first message it receives (trust-on-first-use) and ignores everything else afterwards; outbound messages are then targeted to that origin instead of `*`. Pass `allowedOrigins` to `init()` to restrict the handshake to a known list of editor origins.
|
|
283
|
+
|
|
284
|
+
### Editable DOM helpers
|
|
285
|
+
|
|
286
|
+
`attachEditable` and `attachEditableField` wire a DOM element to the bridge and return a cleanup function. Both are no-ops outside preview mode.
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import { attachEditable, attachEditableField } from '@b10cks/client'
|
|
290
|
+
|
|
291
|
+
// Selectable block: click selects it; editor-driven select/hover toggle outline classes.
|
|
292
|
+
const detach = attachEditable(el, { id: block.id })
|
|
293
|
+
|
|
294
|
+
// Inline string field (contenteditable, streams plain-text edits):
|
|
295
|
+
attachEditableField(el, { id: block.id, field: 'headline' })
|
|
296
|
+
|
|
297
|
+
// Rich text / complex field — deep-select instead of editing inline:
|
|
298
|
+
attachEditableField(el, { id: block.id, path: ['body'], mode: 'select' })
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Scroll offset (fixed headers)
|
|
302
|
+
|
|
303
|
+
When a block is selected it is scrolled into view with `block: 'nearest'` (so it never jumps when already visible) and honors the `--b10cks-scroll-offset` CSS variable as `scroll-margin-top`. Set it to your fixed header's height so selection doesn't overshoot beneath it — either in CSS:
|
|
304
|
+
|
|
305
|
+
```css
|
|
306
|
+
:root { --b10cks-scroll-offset: 80px; }
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
or from JS (the framework packages expose a `scrollOffset` option that calls this):
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import { ensurePreviewStyles, setPreviewScrollOffset } from '@b10cks/client'
|
|
313
|
+
|
|
314
|
+
ensurePreviewStyles() // inject the outline + scroll-margin styles once
|
|
315
|
+
setPreviewScrollOffset(80) // number → px, or pass a string like '5rem'
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### `PreviewStore` — reactive live content
|
|
319
|
+
|
|
320
|
+
`PreviewStore` is a framework-agnostic, subscribable holder for the content tree. `bindPreviewStore` feeds `CONTENT_UPDATE`/`CONTENT_PATCH` events into it, so any complex field — including rich text — re-renders from the new snapshot. The framework packages expose this as `usePreviewContent` / `createPreviewContent`.
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
import { PreviewStore, bindPreviewStore, setAtPath, getAtPath } from '@b10cks/client'
|
|
324
|
+
|
|
325
|
+
const store = new PreviewStore(initialContent)
|
|
326
|
+
const offBridge = bindPreviewStore(store)
|
|
327
|
+
const off = store.subscribe(() => render(store.getSnapshot()))
|
|
328
|
+
|
|
329
|
+
// Immutable path helpers used internally — also exported for your own use:
|
|
330
|
+
const next = setAtPath(content, ['body', 0, 'headline'], 'New')
|
|
331
|
+
const value = getAtPath(content, ['body', 0, 'headline'])
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## TypeScript
|
|
335
|
+
|
|
336
|
+
Common types exported from the package root:
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
import type {
|
|
340
|
+
B10cksLink, // Union type for link fields (url | email | internal | asset)
|
|
341
|
+
B10cksLinkResolved, // Return type of resolveB10cksLink
|
|
342
|
+
IBContent, // A content entry (generic: IBContent<YourContentShape>)
|
|
343
|
+
IBContentBlock, // Base block shape with id and block fields
|
|
344
|
+
IBBlock, // A block schema
|
|
345
|
+
IBDataEntry, // A data source entry (key/value)
|
|
346
|
+
IBDataSource, // A data source definition
|
|
347
|
+
IBSitemapEntry, // Sitemap entry with full_slug, language_iso, meta, published_at
|
|
348
|
+
IBSeoMeta, // robots and canonical fields
|
|
349
|
+
IBSpace, // Space info
|
|
350
|
+
IBRedirect, // Redirect rule (source, target, status_code)
|
|
351
|
+
IBSearchResult, // Search result extending IBContent with relevance_score
|
|
352
|
+
IBSearchResponse, // Wrapper around IBSearchResult[]
|
|
353
|
+
IBCollectionResponse,// Paginated list envelope
|
|
354
|
+
IBMeta, // Pagination metadata (total, last_page, per_page, …)
|
|
355
|
+
IBResponse, // Single-item envelope { data, rv }
|
|
356
|
+
B10cksApiClientOptions,
|
|
357
|
+
} from '@b10cks/client'
|
|
358
|
+
```
|
|
359
|
+
|
|
179
360
|
## License
|
|
180
361
|
|
|
181
362
|
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,13 @@ export declare class ApiClient {
|
|
|
5
5
|
private readonly fetchClient;
|
|
6
6
|
private readonly getRvFn?;
|
|
7
7
|
private readonly setRvFn?;
|
|
8
|
+
/**
|
|
9
|
+
* Per-instance revision store, used when no `getRv`/`setRv` callbacks are
|
|
10
|
+
* supplied. Kept on the instance (not module scope) so concurrent requests
|
|
11
|
+
* in a server runtime cannot leak revisions into one another. Server callers
|
|
12
|
+
* that need request-scoped persistence should pass `getRv`/`setRv`.
|
|
13
|
+
*/
|
|
14
|
+
private rvValue;
|
|
8
15
|
constructor(options: B10cksApiClientOptions, requestUrl?: URL | string);
|
|
9
16
|
get<T>(endpoint: Endpoint, params?: Omit<IBBaseQueryParams, 'token'> & Record<string, unknown>): Promise<ApiResourceResponse<T>>;
|
|
10
17
|
post<T>(endpoint: string, body?: unknown, params?: Omit<IBBaseQueryParams, 'token'> & Record<string, unknown>): Promise<T>;
|
|
@@ -24,6 +31,44 @@ declare type ApiQueryParams = Omit<IBBaseQueryParams, 'token'> & Record<string,
|
|
|
24
31
|
|
|
25
32
|
declare type ApiResourceResponse<T> = IBResponse<T> | T;
|
|
26
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Wire a DOM element as a selectable block: click selects it in the editor,
|
|
36
|
+
* and editor-driven select/hover toggle outline classes. Honors the configured
|
|
37
|
+
* scroll offset and only scrolls when the element isn't already in view.
|
|
38
|
+
* Returns a cleanup function. No-op outside preview mode.
|
|
39
|
+
*/
|
|
40
|
+
export declare function attachEditable(el: HTMLElement, options: AttachEditableOptions): () => void;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Wire a DOM element for field editing. Returns a cleanup function. No-op
|
|
44
|
+
* outside preview mode. See {@link AttachEditableFieldOptions.mode}.
|
|
45
|
+
*/
|
|
46
|
+
export declare function attachEditableField(el: HTMLElement, options: AttachEditableFieldOptions): () => void;
|
|
47
|
+
|
|
48
|
+
export declare interface AttachEditableFieldOptions {
|
|
49
|
+
id: string;
|
|
50
|
+
/** @deprecated Use `path`. Kept for flat string fields. */
|
|
51
|
+
field?: string;
|
|
52
|
+
path?: FieldPath;
|
|
53
|
+
/**
|
|
54
|
+
* `inline` makes the element contenteditable and streams plain-text edits
|
|
55
|
+
* back to the editor — suitable for simple string fields only. `select`
|
|
56
|
+
* instead deep-selects the field so the editor opens its own editor, which
|
|
57
|
+
* is the right choice for rich text and other complex types. Default
|
|
58
|
+
* `inline`, or `select` automatically when no `field` is given but a `path`
|
|
59
|
+
* targets a complex value.
|
|
60
|
+
*/
|
|
61
|
+
mode?: EditableFieldMode;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export declare interface AttachEditableOptions {
|
|
65
|
+
id: string;
|
|
66
|
+
onSelectChange?: (selected: boolean) => void;
|
|
67
|
+
onHoverChange?: (hovered: boolean) => void;
|
|
68
|
+
/** Scroll the element into view when it becomes selected. Default true. */
|
|
69
|
+
scrollOnSelect?: boolean;
|
|
70
|
+
}
|
|
71
|
+
|
|
27
72
|
export declare interface B10cksApiClientOptions {
|
|
28
73
|
baseUrl: string;
|
|
29
74
|
token: string;
|
|
@@ -65,16 +110,67 @@ export declare class B10cksDataApi {
|
|
|
65
110
|
private unwrapCollection;
|
|
66
111
|
}
|
|
67
112
|
|
|
113
|
+
export declare type B10cksLink = {
|
|
114
|
+
type: 'url';
|
|
115
|
+
url: string;
|
|
116
|
+
anchor?: string;
|
|
117
|
+
target?: '_self' | '_blank' | '_parent' | '_top';
|
|
118
|
+
rel?: string;
|
|
119
|
+
} | {
|
|
120
|
+
type: 'email';
|
|
121
|
+
email: string;
|
|
122
|
+
subject?: string;
|
|
123
|
+
body?: string;
|
|
124
|
+
cc?: string;
|
|
125
|
+
bcc?: string;
|
|
126
|
+
} | {
|
|
127
|
+
type: 'internal';
|
|
128
|
+
url: string;
|
|
129
|
+
title: string;
|
|
130
|
+
content: string;
|
|
131
|
+
params?: string;
|
|
132
|
+
anchor?: string;
|
|
133
|
+
target?: '_self' | '_blank' | '_parent' | '_top';
|
|
134
|
+
} | {
|
|
135
|
+
type: 'asset';
|
|
136
|
+
id: string;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export declare interface B10cksLinkResolved {
|
|
140
|
+
href: string;
|
|
141
|
+
target: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Feed the singleton bridge's content events into a {@link PreviewStore}.
|
|
146
|
+
* Returns an unsubscribe function. No-op outside preview mode.
|
|
147
|
+
*/
|
|
148
|
+
export declare function bindPreviewStore<T>(store: PreviewStore<T>): () => void;
|
|
149
|
+
|
|
68
150
|
export declare type BridgeEvent = {
|
|
69
151
|
type: EventType;
|
|
70
152
|
payload: EventPayloadMap[EventType];
|
|
71
153
|
b10cksId?: string;
|
|
72
154
|
};
|
|
73
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Combines a b10cks `full_slug` and `language_iso` into a rooted, locale-prefixed path.
|
|
158
|
+
*
|
|
159
|
+
* - The slug `home` is treated as the root (`/` or `/<locale>`).
|
|
160
|
+
* - Slugs that already start with the locale prefix are not double-prefixed.
|
|
161
|
+
*/
|
|
162
|
+
export declare function buildLocalizedPath(fullSlug: string | null | undefined, languageIso: string | null | undefined): string;
|
|
163
|
+
|
|
74
164
|
export declare interface CollectionFetchOptions {
|
|
75
165
|
allPages?: boolean;
|
|
76
166
|
}
|
|
77
167
|
|
|
168
|
+
/** Granular update: replace the value at `path` within the content tree. */
|
|
169
|
+
export declare type ContentPatchEvent = {
|
|
170
|
+
path: FieldPath;
|
|
171
|
+
value: unknown;
|
|
172
|
+
};
|
|
173
|
+
|
|
78
174
|
export declare type ContentSortField = 'published_at' | 'updated_at' | 'created_at' | `content.${string}`;
|
|
79
175
|
|
|
80
176
|
export declare type ContentSortItem = ContentSortField | `-${ContentSortField}`;
|
|
@@ -115,27 +211,62 @@ export declare type DateFilter = string | {
|
|
|
115
211
|
'!null': true;
|
|
116
212
|
};
|
|
117
213
|
|
|
214
|
+
export declare type EditableFieldMode = 'inline' | 'select';
|
|
215
|
+
|
|
118
216
|
export declare type Endpoint = 'blocks' | `blocks/${string}` | 'contents' | `contents/${string}` | `datasources/${string}/entries` | 'datasources' | 'redirects' | 'search' | 'sitemap' | 'spaces/me';
|
|
119
217
|
|
|
218
|
+
/**
|
|
219
|
+
* Inject the preview outline styles once. Selected/hovered blocks get an
|
|
220
|
+
* outline; `.b10cks-preview` carries a `scroll-margin-top` so scroll-into-view
|
|
221
|
+
* clears a fixed app header. Set the offset via {@link setPreviewScrollOffset}
|
|
222
|
+
* or the `--b10cks-scroll-offset` CSS variable.
|
|
223
|
+
*/
|
|
224
|
+
export declare function ensurePreviewStyles(): void;
|
|
225
|
+
|
|
120
226
|
declare type EventCallback<T> = (payload: T) => void;
|
|
121
227
|
|
|
122
228
|
export declare type EventPayloadMap = {
|
|
123
229
|
CONTENT_UPDATE: ContentUpdateEvent;
|
|
230
|
+
CONTENT_PATCH: ContentPatchEvent;
|
|
124
231
|
SELECT_UPDATE: SelectUpdateEvent;
|
|
125
232
|
HOVER_UPDATE: SelectUpdateEvent;
|
|
126
233
|
FIELD_UPDATE: FieldUpdateEvent;
|
|
234
|
+
FIELD_SELECT: FieldSelectEvent;
|
|
127
235
|
};
|
|
128
236
|
|
|
129
|
-
export declare type EventType = 'CONTENT_UPDATE' | 'SELECT_UPDATE' | 'HOVER_UPDATE' | 'FIELD_UPDATE';
|
|
237
|
+
export declare type EventType = 'CONTENT_UPDATE' | 'CONTENT_PATCH' | 'SELECT_UPDATE' | 'HOVER_UPDATE' | 'FIELD_UPDATE' | 'FIELD_SELECT';
|
|
130
238
|
|
|
131
239
|
export declare type FetchClient = (input: URL | string | RequestInfo, init?: RequestInit) => Promise<unknown>;
|
|
132
240
|
|
|
241
|
+
/** Addresses a field within a block, supporting nested objects and arrays. */
|
|
242
|
+
export declare type FieldPath = (string | number)[];
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Deep-select a specific field (e.g. a rich text field) so the editor opens
|
|
246
|
+
* its own editor for that field instead of editing it inline in the preview.
|
|
247
|
+
*/
|
|
248
|
+
export declare type FieldSelectEvent = {
|
|
249
|
+
itemId: string;
|
|
250
|
+
path: FieldPath;
|
|
251
|
+
};
|
|
252
|
+
|
|
133
253
|
export declare type FieldUpdateEvent = {
|
|
134
254
|
itemId: string;
|
|
135
|
-
field
|
|
136
|
-
|
|
255
|
+
/** Path to the field within the block. Preferred over `field`. */
|
|
256
|
+
path?: FieldPath;
|
|
257
|
+
/** @deprecated Use `path`. Kept for flat string fields. */
|
|
258
|
+
field?: string;
|
|
259
|
+
value: unknown;
|
|
137
260
|
};
|
|
138
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Filters sitemap entries by locale, deduplicates by resolved URL, and drops `noindex` entries.
|
|
264
|
+
*/
|
|
265
|
+
export declare function filterSitemapEntries(entries: IBSitemapEntry[], options?: SitemapFilterOptions): IBSitemapEntry[];
|
|
266
|
+
|
|
267
|
+
/** Read the value at `path` within `target`, or undefined if absent. */
|
|
268
|
+
export declare function getAtPath(target: unknown, path: FieldPath): unknown;
|
|
269
|
+
|
|
139
270
|
export declare interface GetConfigOptions extends Omit<IBContentQueryParams, 'token' | 'full_slug'> {
|
|
140
271
|
slug?: string;
|
|
141
272
|
language?: string;
|
|
@@ -374,24 +505,63 @@ export declare type IdFilter = string | {
|
|
|
374
505
|
'!null': true;
|
|
375
506
|
};
|
|
376
507
|
|
|
508
|
+
declare type Listener = () => void;
|
|
509
|
+
|
|
510
|
+
export declare function normalizePathSegment(value: string | null | undefined): string;
|
|
511
|
+
|
|
377
512
|
export declare class PreviewBridge {
|
|
378
513
|
private static instance;
|
|
379
514
|
private readonly listeners;
|
|
380
515
|
private initialized;
|
|
516
|
+
private allowedOrigins;
|
|
517
|
+
/** Origin of the editor, captured from the first trusted message. */
|
|
518
|
+
private parentOrigin;
|
|
381
519
|
private constructor();
|
|
382
520
|
static getInstance(): PreviewBridge;
|
|
383
|
-
init(): void;
|
|
521
|
+
init(options?: PreviewBridgeInitOptions): void;
|
|
384
522
|
destroy(): void;
|
|
385
523
|
isInPreviewMode(): boolean;
|
|
386
524
|
on<T extends EventType>(eventType: T, callback: EventCallback<EventPayloadMap[T]>): () => void;
|
|
387
525
|
selectItem(selectedItem: string): void;
|
|
526
|
+
/** Deep-select a nested field (e.g. a rich text field) in the editor. */
|
|
527
|
+
selectField(itemId: string, path: FieldPath): void;
|
|
528
|
+
/** @deprecated Prefer {@link updateFieldAt} with a path. */
|
|
388
529
|
updateField(itemId: string, field: string, value: string): void;
|
|
530
|
+
/** Stream an inline edit back to the editor, addressed by path. */
|
|
531
|
+
updateFieldAt(itemId: string, path: FieldPath, value: unknown): void;
|
|
532
|
+
private post;
|
|
389
533
|
private handleMessage;
|
|
534
|
+
private isOriginTrusted;
|
|
390
535
|
private notify;
|
|
391
536
|
}
|
|
392
537
|
|
|
393
538
|
export declare const previewBridge: PreviewBridge;
|
|
394
539
|
|
|
540
|
+
export declare interface PreviewBridgeInitOptions {
|
|
541
|
+
/**
|
|
542
|
+
* Origins the editor is allowed to post from. When provided, messages from
|
|
543
|
+
* any other origin are ignored. When omitted, the bridge locks onto the
|
|
544
|
+
* origin of the first valid message it receives (trust-on-first-use).
|
|
545
|
+
*/
|
|
546
|
+
allowedOrigins?: string[];
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* A framework-agnostic, reactive holder for the content tree shown in the
|
|
551
|
+
* preview. The editor pushes whole-tree (`CONTENT_UPDATE`) or granular
|
|
552
|
+
* (`CONTENT_PATCH`) changes; subscribers re-render from the new snapshot.
|
|
553
|
+
*/
|
|
554
|
+
export declare class PreviewStore<T = Record<string, unknown>> {
|
|
555
|
+
private content;
|
|
556
|
+
private readonly listeners;
|
|
557
|
+
constructor(initial: T);
|
|
558
|
+
subscribe: (listener: Listener) => (() => void);
|
|
559
|
+
getSnapshot: () => T;
|
|
560
|
+
setContent(next: T): void;
|
|
561
|
+
patch(path: FieldPath, value: unknown): void;
|
|
562
|
+
private emit;
|
|
563
|
+
}
|
|
564
|
+
|
|
395
565
|
export declare interface RedirectFetchOptions extends CollectionFetchOptions {
|
|
396
566
|
forceRefresh?: boolean;
|
|
397
567
|
}
|
|
@@ -401,12 +571,51 @@ export declare type RedirectMap = Record<string, {
|
|
|
401
571
|
status_code: number;
|
|
402
572
|
}>;
|
|
403
573
|
|
|
574
|
+
/**
|
|
575
|
+
* Renders a list of sitemap paths as a `<sitemapindex>` XML string.
|
|
576
|
+
*/
|
|
577
|
+
export declare function renderSitemapIndex(paths: string[], siteUrl?: string): string;
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Renders `IBSitemapEntry[]` as a `<urlset>` XML string.
|
|
581
|
+
* Pass `siteUrl` to emit absolute `<loc>` values; without it, relative paths are used.
|
|
582
|
+
*/
|
|
583
|
+
export declare function renderSitemapXml(entries: IBSitemapEntry[], siteUrl?: string): string;
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Resolves a B10cksLink value to a plain { href, target } object.
|
|
587
|
+
*
|
|
588
|
+
* - `'email'` links produce a `mailto:` href with optional subject/body/cc/bcc query params.
|
|
589
|
+
* - `'url'` and `'internal'` links use the stored `url` field; an `anchor` is appended as a
|
|
590
|
+
* hash fragment when present.
|
|
591
|
+
* - `'asset'` links cannot be resolved to a URL without the asset record — returns `undefined`.
|
|
592
|
+
* - Locale prefixing and router integration are intentionally left to the caller.
|
|
593
|
+
*/
|
|
594
|
+
export declare function resolveB10cksLink(link: B10cksLink | undefined | null): B10cksLinkResolved | undefined;
|
|
595
|
+
|
|
404
596
|
export declare type SelectUpdateEvent = {
|
|
405
597
|
selectedItem: string;
|
|
406
598
|
};
|
|
407
599
|
|
|
408
600
|
export declare function serializeFilter(filter: Record<string, unknown>): Record<string, string>;
|
|
409
601
|
|
|
602
|
+
/** Return a copy of `target` with the value at `path` replaced. Immutable. */
|
|
603
|
+
export declare function setAtPath<T>(target: T, path: FieldPath, value: unknown): T;
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Set the scroll offset used when a selected block is scrolled into view.
|
|
607
|
+
* Pass your fixed header's height so selection no longer overshoots beneath it.
|
|
608
|
+
* A number is treated as pixels; strings are used verbatim (e.g. `"5rem"`).
|
|
609
|
+
*/
|
|
610
|
+
export declare function setPreviewScrollOffset(offset: number | string): void;
|
|
611
|
+
|
|
612
|
+
export declare interface SitemapFilterOptions {
|
|
613
|
+
/** Absolute base URL used for deduplication. Without it, paths are compared as strings. */
|
|
614
|
+
siteUrl?: string;
|
|
615
|
+
/** Only include entries for this locale (ISO code). */
|
|
616
|
+
locale?: string;
|
|
617
|
+
}
|
|
618
|
+
|
|
410
619
|
export declare type StringFilter = string | {
|
|
411
620
|
eq: string;
|
|
412
621
|
} | {
|
|
@@ -451,6 +660,7 @@ export declare namespace types {
|
|
|
451
660
|
IBSpace,
|
|
452
661
|
IBRedirect,
|
|
453
662
|
IBContentQueryParams,
|
|
663
|
+
B10cksLink,
|
|
454
664
|
B10cksApiClientOptions,
|
|
455
665
|
StringFilter,
|
|
456
666
|
IdFilter,
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,19 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function P(i){if(!i)return;if(i.type==="email"){const n=new URLSearchParams;i.subject&&n.set("subject",i.subject),i.body&&n.set("body",i.body),i.cc&&n.set("cc",i.cc),i.bcc&&n.set("bcc",i.bcc);const s=n.toString();return{href:`mailto:${i.email}${s?`?${s}`:""}`,target:"_self"}}if(i.type==="asset")return;const t=i.target??"_self";let e=i.url??"";return"anchor"in i&&i.anchor&&(e=`${e.trimEnd()}#${i.anchor}`),{href:e,target:t}}function T(i){if(i!=null){if(typeof i=="boolean"||typeof i=="number")return String(i);if(typeof i=="string")return i;if(typeof i=="object"&&!Array.isArray(i)){const t=i;if("null"in t)return"null:";if("!null"in t)return"!null:";if("between"in t){const[n,s]=t.between;return`${n}...${s}`}const e=["eq","neq","like","!like","^like","like$","lt","gt","lte","gte","in","!in","empty","!empty"];for(const n of e)if(n in t){const s=t[n];return Array.isArray(s)?`${n}:${s.join(",")}`:`${n}:${String(s)}`}}}}function R(i){const t={};for(const[e,n]of Object.entries(i)){const s=T(n);s!==void 0&&(t[e]=s)}return t}function m(i,t,e){const n=t&&typeof t=="object"?R(t):{},s=Array.isArray(e)?{sort:e.join(",")}:e!=null?{sort:e}:{};return{...i,...n,...s}}class A{constructor(t){this.client=t}redirectsCache=null;configCache=new Map;async getResource(t,e={}){const n=await this.client.get(t,e);return this.unwrapResource(n)}async getCollection(t,e={},n={}){if(n.allPages)return this.client.getAll(t,e);const s=await this.client.get(t,e);return this.unwrapCollection(s)}async getContent(t,e={}){return this.getResource(`contents/${t}`,e)}async getContents(t={},e={}){const{filter:n,sort:s,...r}=t;return this.getCollection("contents",m(r,n,s),e)}async getBlock(t,e={}){return this.getResource(`blocks/${t}`,e)}async getBlocks(t={},e={}){const{filter:n,...s}=t;return this.getCollection("blocks",m(s,n,void 0),e)}async search(t){const e=await this.client.get("search",t);if(typeof e=="object"&&e!==null&&"data"in e&&"meta"in e)return e;if(typeof e=="object"&&e!==null&&"data"in e){const n=e.data;if(typeof n=="object"&&n!==null&&"meta"in n&&"data"in n)return n}return e}async getSitemap(t={},e={}){return this.getCollection("sitemap",t,e)}async getDataEntries(t,e={},n={}){return this.getCollection(`datasources/${t}/entries`,e,n)}async getDataSources(t={},e={}){return this.getCollection("datasources",t,e)}async getSpace(t={}){return this.getResource("spaces/me",t)}async lookupRedirect(t){if(!this.client.post)throw new Error("lookupRedirect requires a client that supports POST. Use ApiClient from @b10cks/client.");return this.client.post("redirects/lookup",{source:t})}async getRedirects(t={},e=!1){const{allPages:n=!1,forceRefresh:s=!1}=typeof e=="boolean"?{allPages:!0,forceRefresh:e}:e;if(n&&this.redirectsCache&&!s)return this.redirectsCache;const{filter:r,...o}=t,a=m(o,r,void 0),c=await this.getCollection("redirects",a,{allPages:n}),d=Object.fromEntries(c.map(({source:g,target:u,status_code:f})=>[g,{target:u,status_code:f}]));return n&&(this.redirectsCache=d),d}async getConfig({slug:t="_config",language_iso:e,language:n,bypassCache:s=!1,...r}={}){const o=e??n,a=JSON.stringify({slug:t,language_iso:o,...r});if(!s&&this.configCache.has(a))return this.configCache.get(a);const d=(await this.getContent(t,{...r,language_iso:o})).content??{};return s||this.configCache.set(a,d),d}async syncRevision(t=426713400){const n=(await this.getSpace()).rv||t;return this.client.setRv(n),n}clearCache(){this.redirectsCache=null,this.configCache.clear()}unwrapResource(t){return typeof t=="object"&&t!==null&&"data"in t?t.data:t}unwrapCollection(t){if(Array.isArray(t))return t;if(typeof t=="object"&&t!==null&&"data"in t){if(Array.isArray(t.data))return t.data;if(typeof t.data=="object"&&t.data!==null&&"data"in t.data&&Array.isArray(t.data.data))return t.data.data}return[]}}function k(i){return new A(i)}const j=new Set(["CONTENT_UPDATE","CONTENT_PATCH","SELECT_UPDATE","HOVER_UPDATE","FIELD_UPDATE","FIELD_SELECT"]),L="B10CKS_BRIDGE_READY";class h{static instance;listeners={};initialized=!1;allowedOrigins=null;parentOrigin=null;constructor(){}static getInstance(){return h.instance||(h.instance=new h),h.instance}init(t={}){!this.isInPreviewMode()||this.initialized||(this.allowedOrigins=t.allowedOrigins??null,window.addEventListener("message",this.handleMessage),this.initialized=!0,window.parent.postMessage({type:L},"*"))}destroy(){this.initialized&&typeof window<"u"&&window.removeEventListener("message",this.handleMessage),this.initialized=!1,this.parentOrigin=null;for(const t of Object.keys(this.listeners))this.listeners[t]?.clear()}isInPreviewMode(){return typeof window<"u"&&window.self!==window.top}on(t,e){if(!this.isInPreviewMode())return()=>{};const n=this.listeners[t]||new Set;return this.listeners[t]=n,n.add(e),()=>{n.delete(e)}}selectItem(t){this.post("SELECT_UPDATE",{selectedItem:t})}selectField(t,e){this.post("FIELD_SELECT",{itemId:t,path:e})}updateField(t,e,n){this.post("FIELD_UPDATE",{itemId:t,field:e,value:n})}updateFieldAt(t,e,n){this.post("FIELD_UPDATE",{itemId:t,path:e,value:n})}post(t,e){this.isInPreviewMode()&&window.parent.postMessage({type:t,payload:e},this.parentOrigin??"*")}handleMessage=t=>{if(!this.isOriginTrusted(t.origin)||!t.data||typeof t.data!="object")return;const{type:e,payload:n}=t.data;!e||!j.has(e)||!n||(!this.parentOrigin&&t.origin&&t.origin!=="null"&&(this.parentOrigin=t.origin),this.notify(e,n))};isOriginTrusted(t){return this.parentOrigin?t===this.parentOrigin:this.allowedOrigins?this.allowedOrigins.includes(t):!0}notify(t,e){const n=this.listeners[t];if(n)for(const s of n)s(e)}}const l=h.getInstance(),C="b10cks-preview-style",S="--b10cks-scroll-offset";function v(){if(typeof document>"u"||document.getElementById(C))return;const i=document.createElement("style");i.id=C,i.textContent=`
|
|
2
|
+
.b10cks-preview { scroll-margin-top: var(${S}, 0px); }
|
|
3
|
+
.b10cks-hover,
|
|
4
|
+
.b10cks-preview:hover {
|
|
5
|
+
outline: 2px dashed rgba(59, 130, 246, 0.5);
|
|
6
|
+
outline-offset: 2px;
|
|
7
|
+
}
|
|
8
|
+
.b10cks-selected {
|
|
9
|
+
outline: 2px solid rgb(59, 130, 246) !important;
|
|
10
|
+
outline-offset: 2px;
|
|
11
|
+
}
|
|
12
|
+
`,document.head.appendChild(i)}function _(i){if(typeof document>"u")return;const t=typeof i=="number"?`${i}px`:i;document.documentElement.style.setProperty(S,t)}function F(i,t){if(!l.isInPreviewMode()||!t.id)return()=>{};v();const{id:e,onSelectChange:n,onHoverChange:s,scrollOnSelect:r=!0}=t;i.classList.add("b10cks-preview");const o=u=>{u.preventDefault(),u.stopPropagation(),l.selectItem(e)},a=({selectedItem:u})=>{const f=u===e;i.classList.toggle("b10cks-selected",f),f&&r&&$(i),n?.(f)},c=({selectedItem:u})=>{const f=u===e;i.classList.toggle("b10cks-hover",f),s?.(f)};i.addEventListener("click",o);const d=l.on("SELECT_UPDATE",a),g=l.on("HOVER_UPDATE",c);return()=>{i.removeEventListener("click",o),d(),g(),i.classList.remove("b10cks-preview","b10cks-selected","b10cks-hover")}}function O(i,t){if(!l.isInPreviewMode()||!t.id)return()=>{};const{id:e,field:n,path:s,mode:r="inline"}=t;if(r==="select"){v(),i.classList.add("b10cks-preview");const a=c=>{c.preventDefault(),c.stopPropagation(),s?l.selectField(e,s):l.selectItem(e)};return i.addEventListener("click",a),()=>{i.removeEventListener("click",a),i.classList.remove("b10cks-preview")}}i.setAttribute("contenteditable","true");const o=a=>{const c=a.target.innerText;s?l.updateFieldAt(e,s,c):l.updateField(e,n??"",c)};return i.addEventListener("input",o),()=>{i.removeEventListener("input",o),i.removeAttribute("contenteditable")}}function $(i){typeof i.scrollIntoView=="function"&&i.scrollIntoView({block:"nearest",behavior:"smooth"})}function D(i,t){let e=i;for(const n of t){if(e==null||typeof e!="object")return;e=e[n]}return e}function p(i,t,e){if(t.length===0)return e;const[n,...s]=t;if(n===void 0)return e;if(typeof n=="number"){const o=Array.isArray(i)?i.slice():[];return o[n]=p(o[n],s,e),o}const r=i&&typeof i=="object"&&!Array.isArray(i)?{...i}:{};return r[n]=p(r[n],s,e),r}class I{content;listeners=new Set;constructor(t){this.content=t}subscribe=t=>(this.listeners.add(t),()=>{this.listeners.delete(t)});getSnapshot=()=>this.content;setContent(t){this.content=t,this.emit()}patch(t,e){this.content=p(this.content,t,e),this.emit()}emit(){for(const t of this.listeners)t()}}function U(i){const t=l.on("CONTENT_UPDATE",({content:n})=>{i.setContent(n)}),e=l.on("CONTENT_PATCH",({path:n,value:s})=>{i.patch(n,s)});return()=>{t(),e()}}function y(i){return(i??"").trim().replace(/^\/+|\/+$/g,"")}function w(i,t){const e=y(i),n=y(t);if(!n)return e&&e!=="home"?`/${e}`:"/";if(!e||e==="home")return`/${n}`;const s=`${n}/`;return e===n||e.startsWith(s)?`/${e}`:`/${n}/${e}`}function E(i,t){if(!t)return null;try{return new URL(i,t).toString()}catch{return null}}function b(i){return i.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function x(i,t={}){const{siteUrl:e,locale:n}=t,s=new Set;return i.filter(r=>{if(n&&r.language_iso!==n||r.meta?.robots?.toLowerCase().includes("noindex"))return!1;const o=w(r.full_slug,r.language_iso),a=e?E(o,e)??o:o;return s.has(a)?!1:(s.add(a),!0)})}function z(i,t){return['<?xml version="1.0" encoding="UTF-8"?>','<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',i.map(n=>{const s=w(n.full_slug,n.language_iso),r=t?E(s,t):s;if(!r)return"";const o=[" <url>",` <loc>${b(r)}</loc>`];return n.published_at&&o.push(` <lastmod>${b(n.published_at)}</lastmod>`),o.push(" </url>"),o.join(`
|
|
13
|
+
`)}).filter(Boolean).join(`
|
|
14
|
+
`),"</urlset>"].join(`
|
|
15
|
+
`)}function M(i,t){return['<?xml version="1.0" encoding="UTF-8"?>','<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',i.map(n=>{const s=t?E(n,t):n;return s?[" <sitemap>",` <loc>${b(s)}</loc>`," </sitemap>"].join(`
|
|
16
|
+
`):""}).filter(Boolean).join(`
|
|
17
|
+
`),"</sitemapindex>"].join(`
|
|
18
|
+
`)}const B=Object.freeze(Object.defineProperty({__proto__:null},Symbol.toStringTag,{value:"Module"}));class N{baseUrl;token;vid;fetchClient;getRvFn;setRvFn;rvValue=0;constructor(t,e){this.baseUrl=t.baseUrl.endsWith("/")?t.baseUrl.slice(0,-1):t.baseUrl,this.token=t.token;const n=typeof globalThis.fetch=="function"?globalThis.fetch.bind(globalThis):null;if(t.fetchClient)this.fetchClient=t.fetchClient;else if(n)this.fetchClient=n;else throw new Error("No fetch implementation available. Provide `fetchClient` in ApiClient options.");this.getRvFn=t.getRv,this.setRvFn=t.setRv;const s=this.resolveRequestUrl(e);this.vid=t.version||"published",this.setRv(s?.searchParams.get("b10cks_rv")||t.rv||0)}async get(t,e={}){const n=this.buildUrl(t,{vid:this.vid,rv:this.getRv(),...e,token:this.token}),s=await this.fetchClient(n),r=await this.parseResponse(s);return this.hasRevision(r)&&this.setRv(r.rv),r}async post(t,e,n={}){const s=this.buildUrl(t,{vid:this.vid,rv:this.getRv(),...n,token:this.token}),r=await this.fetchClient(s,{method:"POST",headers:{"Content-Type":"application/json"},body:e!==void 0?JSON.stringify(e):void 0});return this.parseResponse(r)}async getAll(t,e={}){const n=await this.get(t,{...e,page:1}),s=this.normalizeCollectionResponse(n);if(s.rv&&this.setRv(s.rv),!s.meta||s.meta.last_page<=1)return s.data;const r=Array.from({length:s.meta.last_page-1},(a,c)=>this.get(t,{...e,page:c+2})),o=await Promise.all(r);return s.data.concat(o.flatMap(a=>this.normalizeCollectionResponse(a).data))}setRv(t){this.setRvFn?this.setRvFn(t):this.rvValue=t}getRv(){return this.getRvFn?this.getRvFn():this.rvValue}async parseResponse(t){if(this.isFetchResponse(t)){if(!t.ok)throw new Error(`Request failed with status ${t.status}`);return await t.json()}return t}normalizeCollectionResponse(t){if(this.isCollectionResponseEnvelope(t)){const e=t.data;return{data:e.data,meta:e.meta,rv:t.rv||e.rv}}if(Array.isArray(t))return{data:t,meta:void 0,rv:void 0};if(typeof t=="object"&&t!==null&&"data"in t){const{data:e,meta:n,rv:s}=t;return{data:e,meta:n,rv:s}}return{data:[],meta:void 0,rv:void 0}}buildUrl(t,e){const n=new URL(`${this.baseUrl}/v1/${t}`);return Object.entries(e).forEach(([s,r])=>{r!=null&&n.searchParams.append(s,String(r))}),n.toString()}resolveRequestUrl(t){return t?t instanceof URL?t:new URL(t,"http://localhost"):null}isFetchResponse(t){return typeof t=="object"&&t!==null&&"json"in t&&typeof t.json=="function"&&"ok"in t}hasRevision(t){return typeof t=="object"&&t!==null&&"rv"in t}isCollectionResponseEnvelope(t){return typeof t=="object"&&t!==null&&"data"in t&&typeof t.data=="object"&&t.data!==null&&"data"in t.data&&Array.isArray(t.data.data)}}exports.ApiClient=N;exports.B10cksDataApi=A;exports.PreviewBridge=h;exports.PreviewStore=I;exports.attachEditable=F;exports.attachEditableField=O;exports.bindPreviewStore=U;exports.buildLocalizedPath=w;exports.createB10cksDataApi=k;exports.ensurePreviewStyles=v;exports.filterSitemapEntries=x;exports.getAtPath=D;exports.normalizePathSegment=y;exports.previewBridge=l;exports.renderSitemapIndex=M;exports.renderSitemapXml=z;exports.resolveB10cksLink=P;exports.serializeFilter=R;exports.setAtPath=p;exports.setPreviewScrollOffset=_;exports.types=B;
|
|
2
19
|
//# sourceMappingURL=index.js.map
|