smoodly 0.0.16 → 0.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +156 -21
  2. package/dist/admin/client-ops.js +1 -1
  3. package/dist/admin/custom-section.d.ts +10 -0
  4. package/dist/admin/custom-section.js +10 -0
  5. package/dist/admin/editor/CanvasOverlay.d.ts +4 -4
  6. package/dist/admin/editor/CanvasOverlay.js +5 -5
  7. package/dist/admin/editor/EditorView.js +140 -108
  8. package/dist/admin/editor/GlobalInspector.d.ts +24 -0
  9. package/dist/admin/editor/{SharedInspector.js → GlobalInspector.js} +4 -4
  10. package/dist/admin/editor/InsertPicker.d.ts +6 -5
  11. package/dist/admin/editor/InsertPicker.js +6 -4
  12. package/dist/admin/editor/InspectorFields.d.ts +21 -0
  13. package/dist/admin/editor/InspectorFields.js +22 -0
  14. package/dist/admin/editor/Outline.d.ts +0 -1
  15. package/dist/admin/editor/Outline.js +3 -3
  16. package/dist/admin/editor/{shared-edit.d.ts → global-edit.d.ts} +10 -10
  17. package/dist/admin/editor/{shared-edit.js → global-edit.js} +4 -4
  18. package/dist/admin/editor/useGlobalEdit.d.ts +6 -0
  19. package/dist/admin/editor/{useSharedEdit.js → useGlobalEdit.js} +4 -4
  20. package/dist/admin/forms/FieldWidget.d.ts +14 -1
  21. package/dist/admin/forms/FieldWidget.js +38 -11
  22. package/dist/admin/forms/ListField.d.ts +9 -1
  23. package/dist/admin/forms/ListField.js +16 -8
  24. package/dist/admin/forms/RichtextElementCard.js +11 -5
  25. package/dist/admin/forms/RowsWidget.d.ts +13 -0
  26. package/dist/admin/forms/RowsWidget.js +26 -0
  27. package/dist/admin/forms/SpanBar.d.ts +5 -0
  28. package/dist/admin/forms/SpanBar.js +37 -0
  29. package/dist/admin/forms/richtext-insert.d.ts +2 -2
  30. package/dist/admin/forms/richtext-insert.js +3 -3
  31. package/dist/admin/forms/richtext-nodes.js +1 -1
  32. package/dist/admin/forms/tabs.d.ts +15 -9
  33. package/dist/admin/forms/tabs.js +19 -23
  34. package/dist/admin/forms/useRichtextEditor.js +8 -1
  35. package/dist/admin/global-items.d.ts +9 -0
  36. package/dist/admin/{shared-items.js → global-items.js} +17 -16
  37. package/dist/admin/index.d.ts +3 -3
  38. package/dist/admin/index.js +1 -1
  39. package/dist/admin/ops-impl.js +65 -54
  40. package/dist/admin/ops.d.ts +6 -6
  41. package/dist/admin/serialize.d.ts +18 -6
  42. package/dist/admin/serialize.js +27 -4
  43. package/dist/admin/shell/AdminApp.js +6 -6
  44. package/dist/admin/shell/GlobalFields.d.ts +24 -0
  45. package/dist/admin/shell/GlobalFields.js +19 -0
  46. package/dist/admin/shell/{SharedForm.d.ts → GlobalForm.d.ts} +1 -1
  47. package/dist/admin/shell/{SharedForm.js → GlobalForm.js} +36 -26
  48. package/dist/admin/shell/{SharedList.d.ts → GlobalList.d.ts} +1 -1
  49. package/dist/admin/shell/{SharedList.js → GlobalList.js} +9 -9
  50. package/dist/admin/shell/IconRail.js +13 -6
  51. package/dist/admin/shell/PagesList.js +1 -6
  52. package/dist/admin/shell/{shared-list.d.ts → global-list.d.ts} +3 -3
  53. package/dist/admin/shell/{shared-list.js → global-list.js} +2 -2
  54. package/dist/admin/tree-ops.d.ts +10 -8
  55. package/dist/admin/tree-ops.js +28 -16
  56. package/dist/admin/ui/HistoryModal.js +1 -1
  57. package/dist/admin/ui/primitives.d.ts +3 -1
  58. package/dist/admin/ui/primitives.js +2 -2
  59. package/dist/admin/ui/theme.js +54 -14
  60. package/dist/admin/validate.d.ts +27 -2
  61. package/dist/admin/validate.js +47 -10
  62. package/dist/collections.d.ts +3 -3
  63. package/dist/collections.js +1 -1
  64. package/dist/conditions.d.ts +33 -0
  65. package/dist/conditions.js +79 -0
  66. package/dist/config.d.ts +26 -19
  67. package/dist/config.js +26 -25
  68. package/dist/css.d.ts +7 -0
  69. package/dist/css.js +57 -0
  70. package/dist/custom/CustomSection.d.ts +26 -0
  71. package/dist/custom/CustomSection.js +20 -0
  72. package/dist/custom/css.d.ts +3 -0
  73. package/dist/custom/css.js +28 -0
  74. package/dist/custom/index.d.ts +26 -0
  75. package/dist/custom/index.js +16 -0
  76. package/dist/custom/rows.d.ts +28 -0
  77. package/dist/custom/rows.js +129 -0
  78. package/dist/custom/schema.d.ts +32 -0
  79. package/dist/custom/schema.js +39 -0
  80. package/dist/entry-store.d.ts +4 -4
  81. package/dist/entry-store.js +17 -17
  82. package/dist/fields.d.ts +5 -2
  83. package/dist/fields.js +4 -2
  84. package/dist/{shared-id.d.ts → global-id.d.ts} +1 -1
  85. package/dist/{shared-id.js → global-id.js} +4 -4
  86. package/dist/global.d.ts +57 -0
  87. package/dist/global.js +51 -0
  88. package/dist/index.d.ts +28 -18
  89. package/dist/index.js +10 -5
  90. package/dist/media.js +1 -1
  91. package/dist/next/index.d.ts +1 -1
  92. package/dist/next/page-renderer.d.ts +4 -2
  93. package/dist/next/page-renderer.js +9 -9
  94. package/dist/next/queries.d.ts +6 -6
  95. package/dist/next/queries.js +7 -7
  96. package/dist/page.js +2 -2
  97. package/dist/pairing.d.ts +13 -7
  98. package/dist/pairing.js +4 -4
  99. package/dist/refs.d.ts +2 -2
  100. package/dist/refs.js +4 -4
  101. package/dist/render.d.ts +13 -1
  102. package/dist/render.js +10 -5
  103. package/dist/resolve.d.ts +11 -6
  104. package/dist/resolve.js +22 -12
  105. package/dist/revalidate.d.ts +4 -4
  106. package/dist/revalidate.js +4 -4
  107. package/dist/richtext-render.js +2 -2
  108. package/dist/richtext-walk.d.ts +5 -5
  109. package/dist/richtext-walk.js +4 -4
  110. package/dist/schema.d.ts +15 -10
  111. package/dist/schema.js +19 -7
  112. package/dist/section-wrapper.d.ts +18 -6
  113. package/dist/section-wrapper.js +24 -17
  114. package/dist/site.d.ts +15 -5
  115. package/dist/site.js +24 -10
  116. package/dist/sql-space.js +1 -1
  117. package/dist/sql.js +2 -2
  118. package/dist/store.d.ts +7 -0
  119. package/dist/store.js +6 -0
  120. package/dist/styles.d.ts +27 -0
  121. package/dist/styles.js +60 -0
  122. package/dist/supabase-entry-store.js +14 -14
  123. package/dist/supabase-store.js +2 -1
  124. package/dist/zones.d.ts +9 -7
  125. package/dist/zones.js +5 -5
  126. package/package.json +1 -1
  127. package/dist/admin/editor/SharedInspector.d.ts +0 -23
  128. package/dist/admin/editor/useSharedEdit.d.ts +0 -6
  129. package/dist/admin/shared-items.d.ts +0 -9
  130. package/dist/admin/shell/SharedFields.d.ts +0 -21
  131. package/dist/admin/shell/SharedFields.js +0 -15
  132. package/dist/shared.d.ts +0 -53
  133. package/dist/shared.js +0 -45
@@ -1,5 +1,5 @@
1
1
  import type { CollectionSchema, EntryOrder } from "./collections.ts";
2
- import type { SharedSchema } from "./shared.ts";
2
+ import type { GlobalSchema } from "./global.ts";
3
3
  import { type RefEdge, type SectionLike } from "./refs.ts";
4
4
  import { MemoryRefIndex } from "./ref-index.ts";
5
5
  import { type PathIndex } from "./path-index.ts";
@@ -82,7 +82,7 @@ export type AddEntryLocaleOptions = {
82
82
  export type EntryStoreOptions = {
83
83
  paths?: PathIndex;
84
84
  locales?: LocaleSet;
85
- shared?: SharedSchema[];
85
+ globals?: GlobalSchema[];
86
86
  /** Registered Elements a richtext document may embed (spec 2026-09-08 block nodes §2). */
87
87
  elements?: SectionLike[];
88
88
  };
@@ -154,8 +154,8 @@ export interface EntryStore {
154
154
  pathsOf(collection: string, id: string): Promise<Record<string, string>>;
155
155
  }
156
156
  export declare function schemaOf(collections: CollectionSchema<any>[], name: string): CollectionSchema<any>;
157
- /** A shared item is a collection with exactly one entry (spec 2026-09-07). */
158
- export declare const isSharedSchema: (schema: CollectionSchema<any>) => boolean;
157
+ /** A global item is a collection with exactly one entry (spec 2026-09-07). */
158
+ export declare const isGlobalSchema: (schema: CollectionSchema<any>) => boolean;
159
159
  export declare const DEFAULT_ENTRY_LOCALES: LocaleSet;
160
160
  export declare const entryErrors: {
161
161
  notFound: (collection: string, id: string) => Error;
@@ -13,7 +13,7 @@ import { collectionDepth, collectionOrder } from "./collections.js";
13
13
  import { collectEntryRefs } from "./refs.js";
14
14
  import { MemoryRefIndex } from "./ref-index.js";
15
15
  import { MemoryPathIndex } from "./path-index.js";
16
- import { sharedEntryId } from "./shared-id.js";
16
+ import { globalEntryId } from "./global-id.js";
17
17
  import { DEFAULT_SPACE_ID } from "./sql-space.js";
18
18
  import { assertDepth, assertSupportedLocale, chainOf, entryPathRows, slugOf, unsupportedLocale, } from "./paths.js";
19
19
  /** The field types whose value is an array: a scalar `where` on one is
@@ -40,8 +40,8 @@ export function schemaOf(collections, name) {
40
40
  throw new Error(`smoodly: no collection named "${name}".`);
41
41
  return schema;
42
42
  }
43
- /** A shared item is a collection with exactly one entry (spec 2026-09-07). */
44
- export const isSharedSchema = (schema) => schema.kind === "shared";
43
+ /** A global item is a collection with exactly one entry (spec 2026-09-07). */
44
+ export const isGlobalSchema = (schema) => schema.kind === "global";
45
45
  let counter = 0;
46
46
  const uid = (prefix) => `${prefix}-${++counter}-${Date.now().toString(36)}`;
47
47
  export const DEFAULT_ENTRY_LOCALES = { default: "en", supported: ["en"] };
@@ -62,11 +62,11 @@ export const entryErrors = {
62
62
  lastLocale: (id) => new Error(`smoodly: entry "${id}" must exist in at least one locale — delete the entry instead.`),
63
63
  localeInUse: (locale, titles) => new Error(`smoodly: child entries still exist in locale "${locale}" — remove it from ${titles.map((t) => `"${t}"`).join(", ")} first.`),
64
64
  moveLocales: (locale) => new Error(`smoodly: the destination parent does not exist in locale "${locale}" — the entry cannot move under it.`),
65
- // Shared items (spec 2026-09-07 §3): one row, no URL, every locale, code-owned.
66
- singleton: (name) => new Error(`smoodly: shared item "${name}" already exists — it is a singleton.`),
67
- owned: (name, verb) => new Error(`smoodly: shared item "${name}" is owned by code — ${verb}.`),
68
- noSlug: (name) => new Error(`smoodly: shared item "${name}" has no URL — it cannot take a slug.`),
69
- everyLocale: (name) => new Error(`smoodly: shared item "${name}" exists in every locale — it cannot be removed from one.`),
65
+ // Global items (spec 2026-09-07 §3): one row, no URL, every locale, code-owned.
66
+ singleton: (name) => new Error(`smoodly: global item "${name}" already exists — it is a singleton.`),
67
+ owned: (name, verb) => new Error(`smoodly: global item "${name}" is owned by code — ${verb}.`),
68
+ noSlug: (name) => new Error(`smoodly: global item "${name}" has no URL — it cannot take a slug.`),
69
+ everyLocale: (name) => new Error(`smoodly: global item "${name}" exists in every locale — it cannot be removed from one.`),
70
70
  foreignVersion: (collection, id, locale, versionId) => new Error(`smoodly: "${versionId}" is not a version of entry "${id}" in "${collection}", locale "${locale}".`),
71
71
  };
72
72
  /** The keys a locale row owns: every field with .localized(), except
@@ -167,7 +167,7 @@ export class MemoryEntryStore {
167
167
  this.byId = (id) => this.entries.get(id);
168
168
  this.paths = options.paths ?? new MemoryPathIndex();
169
169
  this.locales = options.locales ?? DEFAULT_ENTRY_LOCALES;
170
- this.schemas = [...collections, ...(options.shared ?? [])];
170
+ this.schemas = [...collections, ...(options.globals ?? [])];
171
171
  this.elements = options.elements;
172
172
  }
173
173
  schema(collection) {
@@ -304,7 +304,7 @@ export class MemoryEntryStore {
304
304
  const schema = this.schema(collection);
305
305
  assertSupportedLocale(options.locale, this.locales);
306
306
  const parentId = options.parentId ?? null;
307
- if (isSharedSchema(schema)) {
307
+ if (isGlobalSchema(schema)) {
308
308
  if ([...this.entries.values()].some((e) => e.collection === collection))
309
309
  throw entryErrors.singleton(collection);
310
310
  if (slugOf(fields) !== null)
@@ -316,10 +316,10 @@ export class MemoryEntryStore {
316
316
  this.assertSiblingSlug(collection, parentId, options.locale, slug);
317
317
  const now = Date.now();
318
318
  const entry = {
319
- // A shared item's id is derived, not minted (spec 2026-09-07 §10):
319
+ // A global item's id is derived, not minted (spec 2026-09-07 §10):
320
320
  // the same uuid v5 the Supabase adapter computes, so self-host and
321
321
  // cloud agree on the row a materialization would create.
322
- id: isSharedSchema(schema) ? await sharedEntryId(DEFAULT_SPACE_ID, collection) : uid("entry"),
322
+ id: isGlobalSchema(schema) ? await globalEntryId(DEFAULT_SPACE_ID, collection) : uid("entry"),
323
323
  collection, parentId, fields: shared,
324
324
  locales: {
325
325
  [options.locale]: {
@@ -393,7 +393,7 @@ export class MemoryEntryStore {
393
393
  const row = entryLocaleRow(entry, locale);
394
394
  this.ensureLiveSnapshot(entry, locale);
395
395
  const { shared, localized, slug } = splitFields(fields, schema);
396
- if (isSharedSchema(schema) && slug !== null)
396
+ if (isGlobalSchema(schema) && slug !== null)
397
397
  throw entryErrors.noSlug(collection);
398
398
  this.assertSiblingSlug(collection, entry.parentId, locale, slug, id);
399
399
  const before = { fields: entry.fields, row: { ...row } };
@@ -479,7 +479,7 @@ export class MemoryEntryStore {
479
479
  }
480
480
  async removeLocale(collection, id, locale) {
481
481
  const schema = this.schema(collection);
482
- if (isSharedSchema(schema))
482
+ if (isGlobalSchema(schema))
483
483
  throw entryErrors.everyLocale(collection);
484
484
  const entry = this.must(collection, id);
485
485
  const row = entryLocaleRow(entry, locale);
@@ -533,7 +533,7 @@ export class MemoryEntryStore {
533
533
  return v ? structuredClone(v) : null;
534
534
  }
535
535
  async move(collection, id, to) {
536
- if (isSharedSchema(this.schema(collection)))
536
+ if (isGlobalSchema(this.schema(collection)))
537
537
  throw entryErrors.owned(collection, "it has no tree position");
538
538
  const entry = this.must(collection, id);
539
539
  const subtree = this.subtree(entry);
@@ -572,7 +572,7 @@ export class MemoryEntryStore {
572
572
  const entry = this.row(collection, id);
573
573
  if (!entry)
574
574
  return;
575
- if (isSharedSchema(this.schema(collection)))
575
+ if (isGlobalSchema(this.schema(collection)))
576
576
  throw entryErrors.owned(collection, "remove the registration to remove it");
577
577
  if ([...this.entries.values()].some((e) => e.parentId === id))
578
578
  throw entryErrors.hasChildren(collection, id);
@@ -587,7 +587,7 @@ export class MemoryEntryStore {
587
587
  this.refs.remove({ sourceKind: "entry", sourceId: id });
588
588
  }
589
589
  async reorder(collection, orderedIds) {
590
- if (isSharedSchema(this.schema(collection)))
590
+ if (isGlobalSchema(this.schema(collection)))
591
591
  throw entryErrors.owned(collection, "it has no order");
592
592
  orderedIds.forEach((id, i) => {
593
593
  const entry = this.row(collection, id);
package/dist/fields.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type Toolset } from "./toolset.ts";
2
2
  import { type ResolvedFile, type ResolvedImage, type ResolvedVideo } from "./media.ts";
3
+ import { type Condition, when } from "./conditions.ts";
3
4
  export type Descriptor = {
4
5
  type: string;
5
6
  [key: string]: unknown;
@@ -43,7 +44,8 @@ export type FieldBuilder<Value = unknown, Flags extends BuilderFlags = {}> = {
43
44
  * - no call — hydrate the entry itself; its refs stay ids
44
45
  */
45
46
  resolve(...projection: (string | Record<string, unknown>)[]): FieldBuilder<Value, Flags>;
46
- tab(tab: "content" | "styles" | "media" | "meta"): FieldBuilder<Value, Flags>;
47
+ /** Hide the field while the condition holds (spec 2026-09-14 §12): it leaves the form and validation skips it; the stored value is kept. */
48
+ hidden(condition: Condition): FieldBuilder<Value, Flags>;
47
49
  /** phantom, type-level only */
48
50
  readonly __value?: Value;
49
51
  readonly __flags?: Flags;
@@ -83,7 +85,8 @@ export declare const f: {
83
85
  richtext: (opts?: {
84
86
  toolset?: Toolset;
85
87
  }) => FieldBuilder<unknown, {}>;
86
- dataAttributes: () => FieldBuilder<Record<string, string>, {}>;
88
+ /** A condition for `.hidden()`: `f.when("settings.mediaType").is("video")`. */
89
+ when: typeof when;
87
90
  boolean: () => FieldBuilder<boolean, {}>;
88
91
  /** One value from a list, shown as a dropdown. */
89
92
  select: <const O extends readonly OptionInput[]>(options: O) => FieldBuilder<OptionValue<O[number]>, {}>;
package/dist/fields.js CHANGED
@@ -3,6 +3,7 @@
3
3
  // keyed by descriptor type. Chaining is immutable.
4
4
  import { DEFAULT_TOOLSET } from "./toolset.js";
5
5
  import { parseAspect } from "./media.js";
6
+ import { when } from "./conditions.js";
6
7
  /** Normalizes a schema's option list to objects; refuses an empty list,
7
8
  * since a choice with nothing to choose is a schema bug (spec 2026-09-10
8
9
  * page fields §1). */
@@ -43,7 +44,7 @@ function builder(descriptor) {
43
44
  return chain({ resolve: projection[0] });
44
45
  return chain({ resolve: Object.fromEntries(projection.map((k) => [k, true])) });
45
46
  },
46
- tab: (tab) => chain({ tab }),
47
+ hidden: (condition) => chain({ hidden: condition }),
47
48
  };
48
49
  }
49
50
  export const describePath = (path) => (path === "" ? "the item" : `"${path}"`);
@@ -97,7 +98,8 @@ export const f = {
97
98
  video: () => builder({ type: "video" }),
98
99
  file: () => builder({ type: "file" }),
99
100
  richtext: (opts) => builder({ type: "richtext", toolset: opts?.toolset ?? DEFAULT_TOOLSET }),
100
- dataAttributes: () => builder({ type: "dataAttributes" }),
101
+ /** A condition for `.hidden()`: `f.when("settings.mediaType").is("video")`. */
102
+ when,
101
103
  boolean: () => builder({ type: "boolean" }),
102
104
  /** One value from a list, shown as a dropdown. */
103
105
  select: (options) => builder({ type: "select", options: normalizeOptions(options) }),
@@ -1,3 +1,3 @@
1
1
  /** RFC 4122 §4.3 uuid v5: sha1(namespace bytes ‖ name bytes), version 5,
2
2
  * variant 10xx, first 16 bytes of the digest. */
3
- export declare function sharedEntryId(space: string, name: string): Promise<string>;
3
+ export declare function globalEntryId(space: string, name: string): Promise<string>;
@@ -1,8 +1,8 @@
1
- // The row id of a shared item (spec 2026-09-07 §10 "§3 row id"): uuid v5
1
+ // The row id of a global item (spec 2026-09-07 §10 "§3 row id"): uuid v5
2
2
  // of (space id as the namespace, item name as the name). Deterministic in
3
3
  // both adapters, so a second concurrent materialization of the same item
4
4
  // hits the `entries` primary key instead of adding an unremovable
5
- // duplicate — `delete` refuses every shared row. The space is part of it
5
+ // duplicate — `delete` refuses every global row. The space is part of it
6
6
  // because the primary key is `id` alone and, in the cloud, many spaces
7
7
  // share one table: a name-only id would make space B's footer collide
8
8
  // with space A's.
@@ -16,7 +16,7 @@ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
16
16
  /** The namespace's 16 raw bytes — RFC 4122 hashes the bytes, not the text. */
17
17
  function uuidBytes(uuid) {
18
18
  if (!UUID_RE.test(uuid))
19
- throw new Error(`smoodly: "${uuid}" is not a uuid — a shared item's namespace is the space id.`);
19
+ throw new Error(`smoodly: "${uuid}" is not a uuid — a global item's namespace is the space id.`);
20
20
  const hex = uuid.replace(/-/g, "");
21
21
  const bytes = new Uint8Array(16);
22
22
  for (let i = 0; i < 16; i++)
@@ -25,7 +25,7 @@ function uuidBytes(uuid) {
25
25
  }
26
26
  /** RFC 4122 §4.3 uuid v5: sha1(namespace bytes ‖ name bytes), version 5,
27
27
  * variant 10xx, first 16 bytes of the digest. */
28
- export async function sharedEntryId(space, name) {
28
+ export async function globalEntryId(space, name) {
29
29
  const input = new Uint8Array([...uuidBytes(space), ...new TextEncoder().encode(name)]);
30
30
  const digest = new Uint8Array(await globalThis.crypto.subtle.digest("SHA-1", input));
31
31
  const bytes = digest.subarray(0, 16);
@@ -0,0 +1,57 @@
1
+ import type { CollectionSchema } from "./collections.ts";
2
+ import type { Descriptor } from "./fields.ts";
3
+ import type { PairedComponent } from "./pairing.tsx";
4
+ import type { BuilderMap, NamespaceValues, SectionSchema } from "./schema.ts";
5
+ import type { StyleProps } from "./styles.ts";
6
+ /** The reserved tree node type of a placement. */
7
+ export declare const GLOBAL_NODE_TYPE = "global";
8
+ /** The reserved keys a visual item's settings, styles steps and css live under in its row (spec 2026-09-14 §8). */
9
+ export declare const SETTINGS_KEY = "$settings";
10
+ export declare const STYLES_KEY = "$styles";
11
+ export declare const CSS_KEY = "$css";
12
+ /** The node id a layout-rendered visual item carries (spec 2026-09-13 §1):
13
+ * `getGlobal` stamps it into the styles' `__smd`, the section wrapper emits it,
14
+ * the canvas selects by it. A placement keeps its own tree node id
15
+ * (`global-xxxxxxxx`, no colon). */
16
+ export declare const GLOBAL_NODE_PREFIX = "global:";
17
+ export declare const globalNodeId: (name: string) => string;
18
+ /** The item a layout node id names, or null for any other id. */
19
+ export declare function globalNameOf(id: string): string | null;
20
+ export type GlobalSchema<V = Record<string, unknown>, N extends string = string> = CollectionSchema<any, N> & {
21
+ kind: "global";
22
+ /** The registered section a visual item renders through; absent = an object item. */
23
+ section?: string;
24
+ /** The section's settings descriptors (empty for an object item). */
25
+ settings: Record<string, Descriptor>;
26
+ sample?: Record<string, unknown>;
27
+ /** phantom: what getGlobal returns */
28
+ readonly __value?: V;
29
+ };
30
+ export type GlobalLink = {
31
+ item: string;
32
+ ref: string;
33
+ };
34
+ /** The placement a tree node is, or null for any other node. Accepts a
35
+ * bare `{ type, fields }` shape or a full tree node — `id` (and any
36
+ * other tree-node property) is ignored. */
37
+ export declare function globalLink(node: {
38
+ id?: string;
39
+ type: string;
40
+ fields?: Record<string, unknown>;
41
+ }): GlobalLink | null;
42
+ type GlobalInput<N extends string = string> = {
43
+ name: N;
44
+ title: string;
45
+ };
46
+ export declare function globalItem<F extends BuilderMap, const N extends string = string>(input: GlobalInput<N> & {
47
+ fields: F;
48
+ section?: undefined;
49
+ }): GlobalSchema<NamespaceValues<F>, N>;
50
+ export declare function globalItem<F extends BuilderMap, St extends BuilderMap, const N extends string = string>(input: GlobalInput<N> & {
51
+ section: PairedComponent<SectionSchema<F, St>, F, St>;
52
+ fields?: undefined;
53
+ }): GlobalSchema<NamespaceValues<F> & {
54
+ settings: NamespaceValues<St>;
55
+ styles: StyleProps;
56
+ }, N>;
57
+ export {};
package/dist/global.js ADDED
@@ -0,0 +1,51 @@
1
+ /** The reserved tree node type of a placement. */
2
+ export const GLOBAL_NODE_TYPE = "global";
3
+ /** The reserved keys a visual item's settings, styles steps and css live under in its row (spec 2026-09-14 §8). */
4
+ export const SETTINGS_KEY = "$settings";
5
+ export const STYLES_KEY = "$styles";
6
+ export const CSS_KEY = "$css";
7
+ const RESERVED_KEYS = [SETTINGS_KEY, STYLES_KEY, CSS_KEY];
8
+ /** The node id a layout-rendered visual item carries (spec 2026-09-13 §1):
9
+ * `getGlobal` stamps it into the styles' `__smd`, the section wrapper emits it,
10
+ * the canvas selects by it. A placement keeps its own tree node id
11
+ * (`global-xxxxxxxx`, no colon). */
12
+ export const GLOBAL_NODE_PREFIX = "global:";
13
+ export const globalNodeId = (name) => `${GLOBAL_NODE_PREFIX}${name}`;
14
+ /** The item a layout node id names, or null for any other id. */
15
+ export function globalNameOf(id) {
16
+ return id.startsWith(GLOBAL_NODE_PREFIX) && id.length > GLOBAL_NODE_PREFIX.length ? id.slice(GLOBAL_NODE_PREFIX.length) : null;
17
+ }
18
+ /** The placement a tree node is, or null for any other node. Accepts a
19
+ * bare `{ type, fields }` shape or a full tree node — `id` (and any
20
+ * other tree-node property) is ignored. */
21
+ export function globalLink(node) {
22
+ if (node.type !== GLOBAL_NODE_TYPE)
23
+ return null;
24
+ const { item, ref } = node.fields ?? {};
25
+ return typeof item === "string" && typeof ref === "string" ? { item, ref } : null;
26
+ }
27
+ /** `smoodly.global()`: named `globalItem` here so nothing shadows the `global` idiom. */
28
+ export function globalItem(input) {
29
+ if (!input?.name)
30
+ throw new Error("smoodly: a global item requires a name.");
31
+ if ((input.fields === undefined) === (input.section === undefined)) {
32
+ throw new Error(`smoodly: global item "${input.name}" must declare exactly one of \`section\` or \`fields\`.`);
33
+ }
34
+ const fields = input.section
35
+ ? input.section.schema.fields
36
+ : Object.fromEntries(Object.entries(input.fields).map(([k, b]) => [k, b.descriptor]));
37
+ for (const key of RESERVED_KEYS) {
38
+ if (Object.prototype.hasOwnProperty.call(fields, key)) {
39
+ throw new Error(`smoodly: global item "${input.name}" has a field named "${key}" — that key is reserved for a visual item's ${key === SETTINGS_KEY ? "settings" : key === STYLES_KEY ? "styles" : "css"}.`);
40
+ }
41
+ }
42
+ return {
43
+ kind: "global",
44
+ name: input.name,
45
+ title: input.title,
46
+ fields,
47
+ settings: input.section ? input.section.schema.settings : {},
48
+ ...(input.section ? { section: input.section.schema.name } : {}),
49
+ ...(input.section?.schema.sample ? { sample: input.section.schema.sample } : {}),
50
+ };
51
+ }
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import { toolset } from "./toolset.ts";
4
4
  import { Section } from "./section-wrapper.tsx";
5
5
  import { page } from "./render.tsx";
6
6
  import { entryPage } from "./entry-page.tsx";
7
- import { shared } from "./shared.ts";
7
+ import { globalItem } from "./global.ts";
8
8
  import { marks } from "./marks.ts";
9
9
  export { Zone, renderPage, EMPTY_PAGE_CONTEXT } from "./render.tsx";
10
10
  export type { PageTree, TreeNode, ZoneContent, PairedPage, Registry, PageContext, PageContextLink, PageLink, PageViewProps } from "./render.tsx";
@@ -14,6 +14,11 @@ export type { PageSchema } from "./page.ts";
14
14
  export { fixedSlug } from "./page.ts";
15
15
  export type { EntryPageSchema, PairedEntryPage, EntryPageProps } from "./entry-page.tsx";
16
16
  export { f, normalizeOptions, optionsOf, optionValues } from "./fields.ts";
17
+ export { when, evaluate, isHidden, assertConditions, splitConditionPath } from "./conditions.ts";
18
+ export { DEFAULT_STYLE_VALUES, STYLE_KEYS, SPACING_NONE, resolveStyleValues, styleDescriptors, inlineStyles } from "./styles.ts";
19
+ export type { StyleValues, StyleValuesInput, StyleProps, StyleKey } from "./styles.ts";
20
+ export * from "./custom/index.ts";
21
+ export type { Condition, ConditionOp, ConditionScope } from "./conditions.ts";
17
22
  export { defaultsOf, withDefaults } from "./field-defaults.ts";
18
23
  export { filterPageTree } from "./page-tree.ts";
19
24
  export { ASSET_COLLECTION, DEFAULT_MEDIA, MEDIA_TYPES, FULL_CROP, CENTER_HOTSPOT, parseAspect, cropAspect, clamp01, isMediaValue, collectAssetIds, applyAssets, } from "./media.ts";
@@ -39,7 +44,7 @@ export { SupabaseEntryStore } from "./supabase-entry-store.ts";
39
44
  export { SupabasePathIndex } from "./supabase-path-index.ts";
40
45
  export type { EntryStore, EntryRecord, EntryLocale, EntryVersion, EntryUsage, ListOptions, CreateEntryOptions, AddEntryLocaleOptions, EntryStoreOptions, Where, WhereValue, } from "./entry-store.ts";
41
46
  export { entryErrors, compareEntries, DEFAULT_ENTRY_LOCALES, localizedKeys, splitFields, entryLocaleRow, entryFieldsIn, entryRefEdges, entryTitleIn, matchesWhere, } from "./entry-store.ts";
42
- export { affectedTargets, pageTag, entryTag, sharedTag, pagesTreeTag, collectionTag } from "./revalidate.ts";
47
+ export { affectedTargets, pageTag, entryTag, globalTag, pagesTreeTag, collectionTag } from "./revalidate.ts";
43
48
  export type { AffectedTargets } from "./revalidate.ts";
44
49
  export { resolveTree, resolveFields, resolveMedia } from "./resolve.ts";
45
50
  export type { EntryFetcher, ResolveFieldsOptions, AssetFetcher } from "./resolve.ts";
@@ -56,21 +61,28 @@ export type { CollectionSchema, EntryOrder } from "./collections.ts";
56
61
  export { DEFAULT_TOOLSET, type Toolset, type ToolsetMark, type ToolsetNode } from "./toolset.ts";
57
62
  export { collectionOrder, collectionDepth, DEFAULT_ORDER } from "./collections.ts";
58
63
  export type { ZonePolicy } from "./zones.ts";
59
- export { SHARED_NODE_TYPE, STYLES_KEY, sharedLink } from "./shared.ts";
60
- export { sharedEntryId } from "./shared-id.ts";
64
+ export { GLOBAL_NODE_TYPE, SETTINGS_KEY, STYLES_KEY, CSS_KEY, globalLink } from "./global.ts";
65
+ export { SMD_KEY } from "./section-wrapper.tsx";
66
+ export type { SmdInternal } from "./section-wrapper.tsx";
67
+ export { CSS_MAX, cssProblem, safeCss, scopedCss } from "./css.ts";
68
+ export { globalEntryId } from "./global-id.ts";
61
69
  export { DEFAULT_SPACE_ID } from "./sql-space.ts";
62
- export type { SharedSchema, SharedLink } from "./shared.ts";
70
+ export type { GlobalSchema, GlobalLink } from "./global.ts";
63
71
  export declare const smoodly: {
64
72
  schema: {
65
73
  page: typeof import("./page.ts").pageSchema;
66
- section<F extends import("./schema.ts").BuilderMap = {}, S extends import("./schema.ts").BuilderMap = {}, M extends import("./schema.ts").BuilderMap = {}>(input: {
74
+ section<F extends import("./schema.ts").BuilderMap = {}, S extends import("./schema.ts").BuilderMap = {}>(input: {
67
75
  name: string;
68
76
  title: string;
69
77
  icon?: string;
70
78
  description?: string;
71
79
  fields?: F | undefined;
72
- styles?: S | undefined;
73
- meta?: M | undefined;
80
+ settings?: S | undefined;
81
+ meta?: never;
82
+ styles?: false | {
83
+ omit: string[];
84
+ };
85
+ css?: false;
74
86
  sample?: Partial<{ [K_1 in Exclude<keyof F, { [K in keyof F]: F[K] extends {
75
87
  __flags?: infer Fl;
76
88
  } ? Fl extends {
@@ -88,18 +100,19 @@ export declare const smoodly: {
88
100
  } ? Fl extends {
89
101
  optional: true;
90
102
  } ? K_3 : never : never; }[keyof S]]?: import("./fields.ts").ValueOf<S[K_5]> | undefined; }> | undefined;
91
- styleDefaults?: false | {
92
- omit: string[];
93
- };
94
103
  }): import("./schema.ts").SectionSchema<F, S>;
95
- element<F extends import("./schema.ts").BuilderMap = {}, S extends import("./schema.ts").BuilderMap = {}, M extends import("./schema.ts").BuilderMap = {}>(input: {
104
+ element<F extends import("./schema.ts").BuilderMap = {}, S extends import("./schema.ts").BuilderMap = {}>(input: {
96
105
  name: string;
97
106
  title: string;
98
107
  icon?: string;
99
108
  description?: string;
100
109
  fields?: F | undefined;
101
- styles?: S | undefined;
102
- meta?: M | undefined;
110
+ settings?: S | undefined;
111
+ meta?: never;
112
+ styles?: false | {
113
+ omit: string[];
114
+ };
115
+ css?: false;
103
116
  sample?: Partial<{ [K_1 in Exclude<keyof F, { [K in keyof F]: F[K] extends {
104
117
  __flags?: infer Fl;
105
118
  } ? Fl extends {
@@ -117,9 +130,6 @@ export declare const smoodly: {
117
130
  } ? Fl extends {
118
131
  optional: true;
119
132
  } ? K_3 : never : never; }[keyof S]]?: import("./fields.ts").ValueOf<S[K_5]> | undefined; }> | undefined;
120
- styleDefaults?: false | {
121
- omit: string[];
122
- };
123
133
  } & {
124
134
  contexts: ("richtext" | "column")[];
125
135
  }): import("./schema.ts").ElementSchema<F, S>;
@@ -130,7 +140,7 @@ export declare const smoodly: {
130
140
  entryPage: typeof entryPage;
131
141
  collection: typeof collection;
132
142
  toolset: typeof toolset;
133
- shared: typeof shared;
143
+ global: typeof globalItem;
134
144
  Section: typeof Section;
135
145
  marks: typeof marks;
136
146
  };
package/dist/index.js CHANGED
@@ -5,12 +5,15 @@ import { toolset } from "./toolset.js";
5
5
  import { Section } from "./section-wrapper.js";
6
6
  import { page } from "./render.js";
7
7
  import { entryPage } from "./entry-page.js";
8
- import { shared } from "./shared.js";
8
+ import { globalItem } from "./global.js";
9
9
  import { marks } from "./marks.js";
10
10
  export { Zone, renderPage, EMPTY_PAGE_CONTEXT } from "./render.js";
11
11
  export { RichText, defaultRichTextImage } from "./richtext-render.js";
12
12
  export { fixedSlug } from "./page.js";
13
13
  export { f, normalizeOptions, optionsOf, optionValues } from "./fields.js";
14
+ export { when, evaluate, isHidden, assertConditions, splitConditionPath } from "./conditions.js";
15
+ export { DEFAULT_STYLE_VALUES, STYLE_KEYS, SPACING_NONE, resolveStyleValues, styleDescriptors, inlineStyles } from "./styles.js";
16
+ export * from "./custom/index.js";
14
17
  export { defaultsOf, withDefaults } from "./field-defaults.js";
15
18
  export { filterPageTree } from "./page-tree.js";
16
19
  export { ASSET_COLLECTION, DEFAULT_MEDIA, MEDIA_TYPES, FULL_CROP, CENTER_HOTSPOT, parseAspect, cropAspect, clamp01, isMediaValue, collectAssetIds, applyAssets, } from "./media.js";
@@ -30,15 +33,17 @@ export { MemoryEntryStore } from "./entry-store.js";
30
33
  export { SupabaseEntryStore } from "./supabase-entry-store.js";
31
34
  export { SupabasePathIndex } from "./supabase-path-index.js";
32
35
  export { entryErrors, compareEntries, DEFAULT_ENTRY_LOCALES, localizedKeys, splitFields, entryLocaleRow, entryFieldsIn, entryRefEdges, entryTitleIn, matchesWhere, } from "./entry-store.js";
33
- export { affectedTargets, pageTag, entryTag, sharedTag, pagesTreeTag, collectionTag } from "./revalidate.js";
36
+ export { affectedTargets, pageTag, entryTag, globalTag, pagesTreeTag, collectionTag } from "./revalidate.js";
34
37
  export { resolveTree, resolveFields, resolveMedia } from "./resolve.js";
35
38
  export { SEGMENT_RE, isSegment, assertSegment, joinPath, splitPath, segmentFor, isHomeNode, pagePathIn, chainOf, assertDepth, pagePath, pagePathRows, entryPathRows, collectionSegment, buildPageTree, perLocaleSegments, assertSupportedLocale, unsupportedLocale, } from "./paths.js";
36
39
  export { fixedPathFor } from "./localize.js";
37
40
  export { pathOptions, pageErrors, localeRow, pageRefEdges, DEFAULT_LOCALES } from "./store.js";
38
41
  export { DEFAULT_TOOLSET } from "./toolset.js";
39
42
  export { collectionOrder, collectionDepth, DEFAULT_ORDER } from "./collections.js";
40
- export { SHARED_NODE_TYPE, STYLES_KEY, sharedLink } from "./shared.js";
41
- export { sharedEntryId } from "./shared-id.js";
43
+ export { GLOBAL_NODE_TYPE, SETTINGS_KEY, STYLES_KEY, CSS_KEY, globalLink } from "./global.js";
44
+ export { SMD_KEY } from "./section-wrapper.js";
45
+ export { CSS_MAX, cssProblem, safeCss, scopedCss } from "./css.js";
46
+ export { globalEntryId } from "./global-id.js";
42
47
  export { DEFAULT_SPACE_ID } from "./sql-space.js";
43
48
  export const smoodly = {
44
49
  schema,
@@ -48,7 +53,7 @@ export const smoodly = {
48
53
  entryPage,
49
54
  collection,
50
55
  toolset,
51
- shared,
56
+ global: globalItem,
52
57
  Section,
53
58
  marks,
54
59
  };
package/dist/media.js CHANGED
@@ -43,7 +43,7 @@ export function collectAssetIds(values, descriptors, out, elements = {}) {
43
43
  out.add(value.asset);
44
44
  }
45
45
  else if (d.type === "richtext") {
46
- // Block nodes (spec 2026-09-08 block nodes §2): image nodes, and media inside a known element's fields and styles.
46
+ // Block nodes (spec 2026-09-08 block nodes §2): image nodes, and media inside a known element's fields and settings.
47
47
  for (const node of richtextBlocks(value)) {
48
48
  if (node.type === IMAGE_NODE) {
49
49
  const image = node.attrs.image;
@@ -2,4 +2,4 @@ export { createPageRenderer } from "./page-renderer.tsx";
2
2
  export type { PageRendererOptions, PathRenderOptions, PageRegistration } from "./page-renderer.tsx";
3
3
  export { metadataFrom } from "./meta.ts";
4
4
  export { createSmoodlyQueries } from "./queries.ts";
5
- export type { SmoodlyQueries, QueryOptions, EntriesQuery, TypedEntryItem, SharedValue } from "./queries.ts";
5
+ export type { SmoodlyQueries, QueryOptions, EntriesQuery, TypedEntryItem, GlobalValue } from "./queries.ts";
@@ -2,7 +2,7 @@ import type { ComponentType, ReactElement } from "react";
2
2
  import type { Metadata } from "next";
3
3
  import type { Descriptor } from "../fields.ts";
4
4
  import { type PairedPage } from "../render.tsx";
5
- import type { SharedSchema } from "../shared.ts";
5
+ import type { GlobalSchema } from "../global.ts";
6
6
  import { type SmoodlySite } from "../site.ts";
7
7
  /** A registered section, as renderPage's registry needs it. */
8
8
  type SectionEntry = ComponentType<any> & {
@@ -22,6 +22,8 @@ export type PageRegistration = ((props: any) => ReactElement) & {
22
22
  export type PageRendererOptions = {
23
23
  site: SmoodlySite;
24
24
  sections: SectionEntry[];
25
+ /** Registered Elements: what the custom section's default richtext renderer needs when no RichText is bound (spec 2026-09-14 §6). */
26
+ elements?: SectionEntry[];
25
27
  pages: ReadonlyArray<PageRegistration>;
26
28
  /** Locale-relative CMS path → site URL. Default: the path itself. With
27
29
  * next-intl: `(path, locale) => getPathname({ locale, href: path })`. */
@@ -32,7 +34,7 @@ export type PathRenderOptions = {
32
34
  searchParams?: Promise<Record<string, string | string[] | undefined>>;
33
35
  };
34
36
  export declare function createPageRenderer(options: PageRendererOptions): {
35
- getSmoodlyShared: <V>(item: SharedSchema<V>, opts?: {
37
+ getSmoodlyGlobal: <V>(item: GlobalSchema<V>, opts?: {
36
38
  locale?: string;
37
39
  }) => Promise<V | null>;
38
40
  renderSmoodlyPath: (segments: string[], opts?: PathRenderOptions) => Promise<ReactElement<unknown, string | import("react").JSXElementConstructor<any>>>;
@@ -7,7 +7,7 @@ import { EditorBridge } from "../admin/next/bridge.js";
7
7
  import { fixedPathFor } from "../localize.js";
8
8
  import { joinPath } from "../paths.js";
9
9
  import { renderPage } from "../render.js";
10
- import { entryTag, pageTag, sharedTag } from "../revalidate.js";
10
+ import { entryTag, pageTag, globalTag } from "../revalidate.js";
11
11
  import { pageContextOf } from "../site.js";
12
12
  import { metadataFrom } from "./meta.js";
13
13
  export function createPageRenderer(options) {
@@ -35,7 +35,7 @@ export function createPageRenderer(options) {
35
35
  notFound();
36
36
  }
37
37
  const page = pageContextOf(hit, (path) => href(path, locale));
38
- return renderPage(Page, hit.tree, { sections: options.sections }, { editor, page });
38
+ return renderPage(Page, hit.tree, { sections: options.sections, elements: options.elements, styles: site.styles, custom: site.custom }, { editor, page });
39
39
  }
40
40
  const View = entryPages.get(hit.collection);
41
41
  if (!View) {
@@ -86,20 +86,20 @@ export function createPageRenderer(options) {
86
86
  * error surfaces as a rejected promise like every other failure. */
87
87
  const fixedPath = (Page) => (locale) => fixedPathFor(Page.schema, locale, site.locales, site.homePageSlug);
88
88
  const literal = (segments) => () => joinPath(segments);
89
- /** A shared item for a layout: cached per (item, locale) under the
90
- * shared tag outside draft mode, the live draft inside it. */
91
- async function getSmoodlyShared(item, opts) {
89
+ /** A global item for a layout: cached per (item, locale) under the
90
+ * global tag outside draft mode, the live draft inside it. */
91
+ async function getSmoodlyGlobal(item, opts) {
92
92
  await connection();
93
93
  const locale = opts?.locale ?? site.locales.default;
94
94
  const { isEnabled: draft } = await draftMode();
95
95
  if (draft)
96
- return site.getShared(item, { locale, draft: true });
97
- return unstable_cache(() => site.getShared(item, { locale }), ["smoodly-shared", item.name, locale], {
98
- tags: [sharedTag(item.name)],
96
+ return site.getGlobal(item, { locale, draft: true });
97
+ return unstable_cache(() => site.getGlobal(item, { locale }), ["smoodly-global", item.name, locale], {
98
+ tags: [globalTag(item.name)],
99
99
  })();
100
100
  }
101
101
  return {
102
- getSmoodlyShared,
102
+ getSmoodlyGlobal,
103
103
  renderSmoodlyPath: (segments, opts) => page(literal(segments), opts, any),
104
104
  smoodlyMetadata: (segments, opts) => metadata(literal(segments), opts, any),
105
105
  /** A fixed registration rendered from the developer's own route file. */
@@ -1,6 +1,6 @@
1
1
  import type { CollectionSchema } from "../collections.ts";
2
2
  import type { EntryRecord } from "../entry-store.ts";
3
- import type { SharedSchema } from "../shared.ts";
3
+ import type { GlobalSchema } from "../global.ts";
4
4
  import type { EntryQuery, PageTreeItem, SiteEntryItem, SitePage, SmoodlySite } from "../site.ts";
5
5
  export type QueryOptions = {
6
6
  locale?: string;
@@ -17,8 +17,8 @@ export type TypedEntryItem<C extends readonly CollectionSchema<any, string>[], N
17
17
  fields: EntryFields<C, N>;
18
18
  };
19
19
  };
20
- export type SharedValue<S extends readonly SharedSchema<any, string>[], N> = string extends S[number]["name"] ? Record<string, unknown> : NonNullable<ByName<S[number], N>["__value"]>;
21
- export type SmoodlyQueries<C extends readonly CollectionSchema<any, string>[], S extends readonly SharedSchema<any, string>[]> = {
20
+ export type GlobalValue<S extends readonly GlobalSchema<any, string>[], N> = string extends S[number]["name"] ? Record<string, unknown> : NonNullable<ByName<S[number], N>["__value"]>;
21
+ export type SmoodlyQueries<C extends readonly CollectionSchema<any, string>[], S extends readonly GlobalSchema<any, string>[]> = {
22
22
  /** The published page tree in a locale, every item with its page fields. */
23
23
  getPageTree(options?: QueryOptions): Promise<PageTreeItem[]>;
24
24
  /** A page by locale-relative path ("/company/about-us") or id. */
@@ -26,11 +26,11 @@ export type SmoodlyQueries<C extends readonly CollectionSchema<any, string>[], S
26
26
  /** Published entries of a collection: `where` (shared fields), `order`, `limit`, `parent` run in the store. */
27
27
  getEntries<N extends C[number]["name"]>(collection: N, options?: EntriesQuery): Promise<TypedEntryItem<C, N>[]>;
28
28
  getEntry<N extends C[number]["name"]>(collection: N, idOrPath: string, options?: QueryOptions): Promise<TypedEntryItem<C, N> | null>;
29
- getShared<N extends S[number]["name"]>(item: N, options?: QueryOptions): Promise<SharedValue<S, N> | null>;
29
+ getGlobal<N extends S[number]["name"]>(item: N, options?: QueryOptions): Promise<GlobalValue<S, N> | null>;
30
30
  };
31
- export declare function createSmoodlyQueries<const C extends readonly CollectionSchema<any, string>[], const S extends readonly SharedSchema<any, string>[] = []>(options: {
31
+ export declare function createSmoodlyQueries<const C extends readonly CollectionSchema<any, string>[], const S extends readonly GlobalSchema<any, string>[] = []>(options: {
32
32
  site: SmoodlySite;
33
33
  collections: C;
34
- shared?: S;
34
+ globals?: S;
35
35
  }): SmoodlyQueries<C, S>;
36
36
  export {};