smoodly 0.0.45 → 0.0.47
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 +3 -3
- package/dist/addresses.d.ts +6 -7
- package/dist/addresses.js +6 -4
- package/dist/admin/PublicSans-LICENSE.txt +93 -0
- package/dist/admin/auth-config.d.ts +6 -0
- package/dist/admin/auth-config.js +1 -0
- package/dist/admin/browser/fetch-op.d.ts +10 -0
- package/dist/admin/browser/fetch-op.js +44 -0
- package/dist/admin/browser/main.d.ts +1 -0
- package/dist/admin/browser/main.js +21 -0
- package/dist/admin/custom-section.d.ts +1 -1
- package/dist/admin/drift.d.ts +1 -1
- package/dist/admin/editor/EditorView.js +14 -14
- package/dist/admin/editor/autosave.js +1 -1
- package/dist/admin/editor/canvas-address.d.ts +2 -0
- package/dist/admin/editor/canvas-address.js +8 -0
- package/dist/admin/editor/overlay-geometry.d.ts +1 -1
- package/dist/admin/editor/protocol.d.ts +18 -4
- package/dist/admin/editor/protocol.js +15 -1
- package/dist/admin/editor/useCanvasBridge.d.ts +1 -1
- package/dist/admin/editor/useCanvasBridge.js +5 -6
- package/dist/admin/editor/useInlineSession.js +4 -2
- package/dist/admin/files.d.ts +11 -0
- package/dist/admin/files.generated.js +2 -0
- package/dist/admin/files.js +8 -0
- package/dist/admin/forms/useRefOptions.d.ts +2 -2
- package/dist/admin/forms/useRefOptions.js +2 -2
- package/dist/admin/forms/useRichtextEditor.js +4 -4
- package/dist/admin/handler.d.ts +40 -0
- package/dist/admin/handler.js +151 -0
- package/dist/admin/health.d.ts +4 -0
- package/dist/admin/index.d.ts +1 -1
- package/dist/admin/ops-impl.d.ts +7 -1
- package/dist/admin/ops-impl.js +112 -35
- package/dist/admin/ops.d.ts +3 -2
- package/dist/admin/page-data.d.ts +21 -0
- package/dist/admin/page-data.js +4 -0
- package/dist/admin/page.d.ts +6 -0
- package/dist/admin/page.js +35 -0
- package/dist/admin/serialize.js +7 -7
- package/dist/admin/shell/AdminApp.js +2 -2
- package/dist/admin/shell/ContentHealthPage.js +3 -1
- package/dist/admin/shell/EntryForm.js +1 -1
- package/dist/admin/shell/router.d.ts +3 -16
- package/dist/admin/shell/router.js +3 -39
- package/dist/admin/shell/session.d.ts +2 -5
- package/dist/admin/supabase-auth.js +1 -1
- package/dist/admin/tree-ops.d.ts +1 -1
- package/dist/admin/ui/fonts.d.ts +12 -0
- package/dist/admin/ui/fonts.js +22 -0
- package/dist/admin/ui/theme.d.ts +13 -4
- package/dist/admin/ui/theme.js +28 -157
- package/dist/assemble.d.ts +60 -0
- package/dist/assemble.js +359 -0
- package/dist/astro/cache.d.ts +34 -0
- package/dist/astro/cache.js +69 -0
- package/dist/astro/components/Custom.astro +21 -0
- package/dist/astro/components/Guarded.astro +24 -0
- package/dist/astro/components/Head.astro +26 -0
- package/dist/astro/components/Image.astro +20 -0
- package/dist/astro/components/RichText.astro +23 -0
- package/dist/astro/components/Section.astro +20 -0
- package/dist/astro/components/Video.astro +5 -0
- package/dist/astro/components/Zone.astro +19 -0
- package/dist/astro/components.d.ts +6 -0
- package/dist/astro/components.js +7 -0
- package/dist/astro/content-loaders.d.ts +40 -0
- package/dist/astro/content-loaders.js +100 -0
- package/dist/astro/content.d.ts +9 -0
- package/dist/astro/content.js +17 -0
- package/dist/astro/custom.d.ts +1 -0
- package/dist/astro/custom.js +3 -0
- package/dist/astro/defaults.d.ts +20 -0
- package/dist/astro/defaults.js +21 -0
- package/dist/astro/env-files.d.ts +1 -0
- package/dist/astro/env-files.js +21 -0
- package/dist/astro/head.d.ts +13 -0
- package/dist/astro/head.js +19 -0
- package/dist/astro/image.d.ts +27 -0
- package/dist/astro/image.js +29 -0
- package/dist/astro/index.d.ts +43 -0
- package/dist/astro/index.js +111 -0
- package/dist/astro/locale-paths.d.ts +30 -0
- package/dist/astro/locale-paths.js +38 -0
- package/dist/astro/middleware.d.ts +1 -0
- package/dist/astro/middleware.js +83 -0
- package/dist/astro/preview-document.d.ts +1 -0
- package/dist/astro/preview-document.js +18 -0
- package/dist/astro/preview.d.ts +10 -0
- package/dist/astro/preview.js +72 -0
- package/dist/astro/richtext.d.ts +15 -0
- package/dist/astro/richtext.js +78 -0
- package/dist/astro/routes/admin.d.ts +3 -0
- package/dist/astro/routes/admin.js +41 -0
- package/dist/astro/routes/page.astro +17 -0
- package/dist/astro/routes/preview.astro +11 -0
- package/dist/astro/runtime.d.ts +32 -0
- package/dist/astro/runtime.js +46 -0
- package/dist/astro/scope.d.ts +45 -0
- package/dist/astro/scope.js +103 -0
- package/dist/astro/server.d.ts +14 -0
- package/dist/astro/server.js +45 -0
- package/dist/astro/shell.d.ts +67 -0
- package/dist/astro/shell.js +63 -0
- package/dist/astro/style.d.ts +1 -0
- package/dist/astro/style.js +11 -0
- package/dist/astro/views-check.d.ts +3 -0
- package/dist/astro/views-check.js +19 -0
- package/dist/astro/zone.d.ts +39 -0
- package/dist/astro/zone.js +33 -0
- package/dist/bind.d.ts +19 -0
- package/dist/bind.js +34 -0
- package/dist/bridge/bridge.d.ts +9 -0
- package/dist/bridge/bridge.js +107 -0
- package/dist/bridge/entry.d.ts +1 -0
- package/dist/bridge/entry.js +5 -0
- package/dist/bridge/preview-pill.d.ts +18 -0
- package/dist/bridge/preview-pill.js +115 -0
- package/dist/cli/import.d.ts +3 -0
- package/dist/cli/import.js +10 -1
- package/dist/cli/load-collections.js +4 -3
- package/dist/cli/load-config.d.ts +4 -0
- package/dist/cli/load-config.js +26 -0
- package/dist/cli/main.d.ts +5 -1
- package/dist/cli/main.js +24 -6
- package/dist/cli/migrate.d.ts +13 -0
- package/dist/cli/migrate.js +30 -2
- package/dist/cli/rebuild.d.ts +23 -0
- package/dist/cli/rebuild.js +22 -0
- package/dist/cli/space-io.d.ts +15 -1
- package/dist/cli/space-io.js +14 -0
- package/dist/client.js +5 -0
- package/dist/config.d.ts +28 -20
- package/dist/config.js +71 -75
- package/dist/content/content-api.d.ts +1 -1
- package/dist/content/node.d.ts +2 -3
- package/dist/content/node.js +2 -1
- package/dist/crash-message.d.ts +1 -0
- package/dist/crash-message.js +8 -0
- package/dist/css.d.ts +4 -0
- package/dist/css.js +5 -2
- package/dist/custom/CustomSection.d.ts +1 -1
- package/dist/custom/CustomSection.js +4 -8
- package/dist/custom/css.js +2 -2
- package/dist/custom/index.d.ts +6 -10
- package/dist/custom/index.js +1 -2
- package/dist/custom/layout.d.ts +5 -0
- package/dist/custom/layout.js +14 -0
- package/dist/document-stamp.d.ts +7 -0
- package/dist/document-stamp.js +48 -0
- package/dist/entry-page.d.ts +3 -18
- package/dist/env.js +1 -1
- package/dist/global-id.js +2 -2
- package/dist/global.d.ts +5 -2
- package/dist/global.js +8 -5
- package/dist/image/next-config.d.ts +3 -0
- package/dist/image/next-config.js +12 -7
- package/dist/image/remote-pattern.d.ts +1 -0
- package/dist/image/remote-pattern.js +5 -0
- package/dist/index.d.ts +15 -17
- package/dist/index.js +10 -19
- package/dist/marks.d.ts +7 -0
- package/dist/marks.js +7 -0
- package/dist/next/admin-route.d.ts +7 -0
- package/dist/next/admin-route.js +28 -0
- package/dist/next/bridge.d.ts +1 -0
- package/dist/next/bridge.js +26 -0
- package/dist/next/canvas-boundary.d.ts +1 -1
- package/dist/next/canvas-slot.d.ts +1 -0
- package/dist/next/canvas-slot.js +4 -3
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +1 -0
- package/dist/next/page-renderer.d.ts +5 -1
- package/dist/next/page-renderer.js +19 -33
- package/dist/next/preview-pill-define.d.ts +1 -0
- package/dist/next/preview-pill-define.js +10 -0
- package/dist/next/preview-pill.d.ts +0 -3
- package/dist/next/preview-pill.js +7 -50
- package/dist/next/queries.d.ts +3 -28
- package/dist/next/queries.js +3 -90
- package/dist/next/reads.d.ts +2 -0
- package/dist/next/reads.js +18 -0
- package/dist/page-context.d.ts +89 -0
- package/dist/page-context.js +8 -0
- package/dist/pairing.d.ts +2 -22
- package/dist/project.d.ts +85 -0
- package/dist/project.js +228 -0
- package/dist/published.d.ts +115 -0
- package/dist/published.js +136 -0
- package/dist/react.d.ts +61 -0
- package/dist/react.js +17 -0
- package/dist/read-shapes.d.ts +1 -1
- package/dist/reads.d.ts +80 -0
- package/dist/reads.js +142 -0
- package/dist/refs.d.ts +1 -1
- package/dist/registration.d.ts +8 -0
- package/dist/registration.js +17 -0
- package/dist/render.d.ts +5 -83
- package/dist/render.js +5 -10
- package/dist/resolve.d.ts +1 -1
- package/dist/richtext/index.d.ts +6 -2
- package/dist/richtext/index.js +3 -2
- package/dist/richtext-href.d.ts +4 -0
- package/dist/richtext-href.js +17 -0
- package/dist/richtext-render.js +1 -14
- package/dist/schema-version.d.ts +1 -1
- package/dist/schema-version.js +1 -1
- package/dist/section-crash.d.ts +2 -2
- package/dist/section-crash.js +2 -7
- package/dist/section-wrapper.d.ts +3 -10
- package/dist/section-wrapper.js +3 -2
- package/dist/site.d.ts +40 -14
- package/dist/site.js +199 -284
- package/dist/smd-key.d.ts +9 -0
- package/dist/smd-key.js +1 -0
- package/dist/sql-space.d.ts +5 -0
- package/dist/sql-space.js +11 -5
- package/dist/sql.d.ts +2 -0
- package/dist/sql.js +127 -1
- package/dist/store.d.ts +1 -1
- package/dist/supabase-published-store.d.ts +45 -0
- package/dist/supabase-published-store.js +247 -0
- package/dist/supabase-store.d.ts +1 -1
- package/dist/toolset.d.ts +2 -4
- package/dist/toolset.js +6 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/view-props.d.ts +40 -0
- package/dist/view-props.js +1 -0
- package/dist/views.d.ts +36 -0
- package/dist/views.js +52 -0
- package/dist/zones.d.ts +7 -7
- package/dist/zones.js +7 -6
- package/migrations/20261007120000_smoodly_v8.sql +154 -0
- package/migrations/20261007200000_smoodly_v9.sql +30 -0
- package/migrations/20261008120000_smoodly_v10.sql +47 -0
- package/package.json +46 -19
- package/dist/admin/next/bridge.d.ts +0 -2
- package/dist/admin/next/bridge.js +0 -129
- package/dist/admin/next/create-admin.d.ts +0 -19
- package/dist/admin/next/create-admin.js +0 -44
- package/dist/admin/next/index.d.ts +0 -8
- package/dist/admin/next/index.js +0 -8
- package/dist/admin/next/op-handler.d.ts +0 -18
- package/dist/admin/next/op-handler.js +0 -31
package/dist/render.d.ts
CHANGED
|
@@ -1,94 +1,17 @@
|
|
|
1
|
-
import { type ComponentType, type ReactElement
|
|
2
|
-
import type { PageAlternate } from "./paths.ts";
|
|
1
|
+
import { type ComponentType, type ReactElement } from "react";
|
|
3
2
|
import type { PageSchema } from "./page.ts";
|
|
4
3
|
import type { BuilderMap, Values } from "./schema.ts";
|
|
5
4
|
import { type StyleValues } from "./styles.ts";
|
|
6
|
-
import { type CustomOptions } from "./custom/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
fields: Record<string, unknown>;
|
|
11
|
-
/** The developer's knobs (spec 2026-09-14 §3). */
|
|
12
|
-
settings?: Record<string, unknown>;
|
|
13
|
-
/** Smoodly's styles steps (spec 2026-09-14 §2); absent keys are Default. */
|
|
14
|
-
styles?: Record<string, unknown>;
|
|
15
|
-
/** The custom-CSS snippet (spec 2026-09-14 §4), scoped by the wrapper. */
|
|
16
|
-
css?: string;
|
|
17
|
-
};
|
|
18
|
-
/** `meta` is the page's own metadata (SEO title, description, og image).
|
|
19
|
-
* It rides inside the tree deliberately: trees are already JSONB in
|
|
20
|
-
* page_versions, so this needs no DDL change, and page meta becomes
|
|
21
|
-
* versioned with content — draft SEO edits stay unpublished, and publish
|
|
22
|
-
* moves content and meta together. */
|
|
23
|
-
export type PageTree = {
|
|
24
|
-
zones: Record<string, TreeNode[]>;
|
|
25
|
-
meta?: Record<string, unknown>;
|
|
26
|
-
fields?: Record<string, unknown>;
|
|
27
|
-
};
|
|
28
|
-
/** Where a rendered page sits in the tree — what a view needs for
|
|
29
|
-
* breadcrumbs and sub-navigation without a query (spec 2026-09-05 §5).
|
|
30
|
-
* `path` is the locale-relative CMS path (what the content API returns);
|
|
31
|
-
* `url` is that path through the app's `href` seam — `/fi/yritys` under
|
|
32
|
-
* next-intl, `/yritys` without it — so a page shape links the same way
|
|
33
|
-
* in both layouts. `fields` is the linked page's own page fields (spec
|
|
34
|
-
* 2026-09-10 page fields §3): the published tree's outside draft mode,
|
|
35
|
-
* raw (no asset resolution), defaults applied, `{}` for a folder. */
|
|
36
|
-
export type PageLink = {
|
|
37
|
-
title: string;
|
|
38
|
-
path: string;
|
|
39
|
-
hasPage: boolean;
|
|
40
|
-
fields: Record<string, unknown>;
|
|
41
|
-
};
|
|
42
|
-
export type PageContextLink = PageLink & {
|
|
43
|
-
url: string;
|
|
44
|
-
};
|
|
45
|
-
/** The page's address in one other locale, `url` through the app's href seam (spec 2026-09-15 §3). */
|
|
46
|
-
export type PageContextAlternate = PageAlternate & {
|
|
47
|
-
url: string;
|
|
48
|
-
};
|
|
49
|
-
export type PageContext<Fields = Record<string, unknown>> = {
|
|
50
|
-
id: string;
|
|
51
|
-
title: string;
|
|
52
|
-
path: string;
|
|
53
|
-
url: string;
|
|
54
|
-
/** The locale the page was rendered in. */
|
|
55
|
-
locale: string;
|
|
56
|
-
/** The page's own fields, typed from its schema on the view; resolved, defaults applied. */
|
|
57
|
-
fields: Fields;
|
|
58
|
-
/** Root first, parent last. */
|
|
59
|
-
ancestors: ReadonlyArray<PageContextLink>;
|
|
60
|
-
children: ReadonlyArray<PageContextLink>;
|
|
61
|
-
/** One key per supported locale: the page's `{ slug, path, url }` there, or null where it is
|
|
62
|
-
* absent or unpublished (draft mode: absent only). What a language switch links to. */
|
|
63
|
-
locales: Readonly<Record<string, PageContextAlternate | null>>;
|
|
64
|
-
};
|
|
65
|
-
/** The `page` prop of a view rendered outside the site (a test, a preview
|
|
66
|
-
* of a shape): a real object, so a view never guards an optional prop, but
|
|
67
|
-
* no position in the tree. Frozen: one singleton shared by every such
|
|
68
|
-
* render, so a view that pushed onto it would leak into the next. */
|
|
69
|
-
export declare const EMPTY_PAGE_CONTEXT: PageContext;
|
|
5
|
+
import { type CustomOptions } from "./custom/CustomSection.tsx";
|
|
6
|
+
import { type EditorWrap, type PageContext, type PageTree, type ZoneContent } from "./page-context.ts";
|
|
7
|
+
export type { TreeNode, PageTree, PageLink, PageContextLink, PageContextAlternate, PageContext, ZoneContent, EditorWrap } from "./page-context.ts";
|
|
8
|
+
export { EMPTY_PAGE_CONTEXT } from "./page-context.ts";
|
|
70
9
|
type AnyPaired = ComponentType<any> & {
|
|
71
10
|
schema: {
|
|
72
11
|
name: string;
|
|
73
12
|
title?: string;
|
|
74
13
|
};
|
|
75
14
|
};
|
|
76
|
-
/** The adapter's canvas net (spec 2026-09-27 section guard §5): called per section, in editor mode only. */
|
|
77
|
-
export type EditorWrap = (child: ReactNode, section: {
|
|
78
|
-
id: string;
|
|
79
|
-
title: string;
|
|
80
|
-
}) => ReactNode;
|
|
81
|
-
export type ZoneContent = {
|
|
82
|
-
readonly name: string;
|
|
83
|
-
readonly nodes: TreeNode[];
|
|
84
|
-
readonly components: ReadonlyMap<string, AnyPaired>;
|
|
85
|
-
/** The config's CSS values behind the styles set (spec 2026-09-14 §2). */
|
|
86
|
-
readonly styleValues: StyleValues;
|
|
87
|
-
readonly editor: boolean;
|
|
88
|
-
/** Control flow the guard must let through — the adapter's (Next: unstable_rethrow; spec 2026-09-27 section guard §2). */
|
|
89
|
-
readonly rethrow?: (error: unknown) => void;
|
|
90
|
-
readonly editorWrap?: EditorWrap;
|
|
91
|
-
};
|
|
92
15
|
export declare function Zone({ of: content }: {
|
|
93
16
|
of: ZoneContent;
|
|
94
17
|
}): import("react").JSX.Element | null;
|
|
@@ -114,4 +37,3 @@ export declare function renderPage<Zones extends Record<string, unknown>>(Page:
|
|
|
114
37
|
rethrow?: (error: unknown) => void;
|
|
115
38
|
editorWrap?: EditorWrap;
|
|
116
39
|
}): ReactElement;
|
|
117
|
-
export {};
|
package/dist/render.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Fragment } from "react";
|
|
3
3
|
import { EMPTY_ATTR, NODE_ATTR, ZONE_ATTR } from "./marks.js";
|
|
4
|
-
import { SMD_KEY } from "./
|
|
4
|
+
import { SMD_KEY } from "./smd-key.js";
|
|
5
5
|
import { DEFAULT_STYLE_VALUES } from "./styles.js";
|
|
6
|
-
import { CUSTOM_NODE_TYPE
|
|
6
|
+
import { CUSTOM_NODE_TYPE } from "./custom/index.js";
|
|
7
|
+
import { createCustomSection } from "./custom/CustomSection.js";
|
|
8
|
+
import { EMPTY_PAGE_CONTEXT } from "./page-context.js";
|
|
7
9
|
import { renderGuarded } from "./section-guard.js";
|
|
8
10
|
import { PLACEHOLDER_STYLE } from "./section-crash.js";
|
|
9
|
-
|
|
10
|
-
* of a shape): a real object, so a view never guards an optional prop, but
|
|
11
|
-
* no position in the tree. Frozen: one singleton shared by every such
|
|
12
|
-
* render, so a view that pushed onto it would leak into the next. */
|
|
13
|
-
export const EMPTY_PAGE_CONTEXT = Object.freeze({
|
|
14
|
-
id: "", title: "", path: "/", url: "/", locale: "", fields: Object.freeze({}), ancestors: Object.freeze([]), children: Object.freeze([]),
|
|
15
|
-
locales: Object.freeze({}),
|
|
16
|
-
});
|
|
11
|
+
export { EMPTY_PAGE_CONTEXT } from "./page-context.js";
|
|
17
12
|
export function Zone({ of: content }) {
|
|
18
13
|
// A malformed tree (bad data, a client that skipped isPageTree) must not
|
|
19
14
|
// crash the render — treat a non-array nodes as empty rather than throw.
|
package/dist/resolve.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Descriptor } from "./fields.ts";
|
|
2
2
|
import type { CollectionSchema } from "./collections.ts";
|
|
3
|
-
import type { PageTree } from "./
|
|
3
|
+
import type { PageTree } from "./page-context.ts";
|
|
4
4
|
import { type GlobalSchema } from "./global.ts";
|
|
5
5
|
import { type AssetRecord } from "./media.ts";
|
|
6
6
|
import { type ElementSchemas } from "./richtext-walk.ts";
|
package/dist/richtext/index.d.ts
CHANGED
|
@@ -6,7 +6,11 @@ export type CreateRichTextOptions = {
|
|
|
6
6
|
/** next/image `sizes` for body images; the site's text column width. */
|
|
7
7
|
sizes?: string;
|
|
8
8
|
};
|
|
9
|
-
|
|
9
|
+
/** The bound renderer; `elements` is the list it renders, which defineViews checks against the config's richtext elements. */
|
|
10
|
+
export type BoundRichText = ((props: {
|
|
10
11
|
doc: unknown;
|
|
11
|
-
}) => ReactElement
|
|
12
|
+
}) => ReactElement) & {
|
|
13
|
+
elements: RichTextElement[];
|
|
14
|
+
};
|
|
15
|
+
export declare function createRichText({ elements, sizes }?: CreateRichTextOptions): BoundRichText;
|
|
12
16
|
export type { RichTextElement, RichTextImageProps, RichTextProps } from "../richtext-render.tsx";
|
package/dist/richtext/index.js
CHANGED
|
@@ -3,7 +3,8 @@ import { RichText } from "../richtext-render.js";
|
|
|
3
3
|
import { SmoodlyImage } from "../image/SmoodlyImage.js";
|
|
4
4
|
export function createRichText({ elements = [], sizes } = {}) {
|
|
5
5
|
const image = ({ image, caption }) => (_jsxs("figure", { children: [_jsx(SmoodlyImage, { image: image, sizes: sizes }), caption !== "" && _jsx("figcaption", { children: caption })] }));
|
|
6
|
-
|
|
6
|
+
function Bound({ doc }) {
|
|
7
7
|
return _jsx(RichText, { doc: doc, elements: elements, image: image });
|
|
8
|
-
}
|
|
8
|
+
}
|
|
9
|
+
return Object.assign(Bound, { elements });
|
|
9
10
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Only schemes an editor's link may carry reach the page: http(s), mailto, tel, and site-relative targets.
|
|
2
|
+
* Anything else (javascript:, data:, an empty href, a protocol-relative `//host` or a backslash form
|
|
3
|
+
* `/\host` that a browser treats the same way) renders the text without an anchor. */
|
|
4
|
+
const SAFE_HREF = /^(https?:|mailto:|tel:|\/(?![/\\])|#|\?|\.)/i;
|
|
5
|
+
export function safeHref(raw) {
|
|
6
|
+
if (typeof raw !== "string")
|
|
7
|
+
return null;
|
|
8
|
+
// URL parsers drop tab, LF and CR, so normalise before testing to see what the parser sees.
|
|
9
|
+
const href = raw.replace(/[\t\n\r]/g, "").trim();
|
|
10
|
+
return href !== "" && SAFE_HREF.test(href) ? href : null;
|
|
11
|
+
}
|
|
12
|
+
const ESCAPES = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
13
|
+
export function escapeHtml(text) {
|
|
14
|
+
return text.replace(/[&<>"']/g, (c) => ESCAPES[c]);
|
|
15
|
+
}
|
|
16
|
+
export const isResolvedImage = (v) => typeof v === "object" && v !== null && typeof v.url === "string"
|
|
17
|
+
&& typeof v.width === "number" && typeof v.height === "number";
|
package/dist/richtext-render.js
CHANGED
|
@@ -9,26 +9,13 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
9
9
|
// (default: a figure over a plain <img>); an `element` node renders the
|
|
10
10
|
// paired component named in `elements`, nothing when unknown.
|
|
11
11
|
import { Fragment, createElement } from "react";
|
|
12
|
+
import { isResolvedImage, safeHref } from "./richtext-href.js";
|
|
12
13
|
import { ELEMENT_NODE, IMAGE_NODE } from "./richtext-walk.js";
|
|
13
|
-
/** Only schemes an editor's link may carry reach the page: http(s), mailto, tel,
|
|
14
|
-
* and site-relative targets. Anything else (javascript:, data:, an empty href,
|
|
15
|
-
* a protocol-relative `//host` or a backslash form `/\host` that a browser
|
|
16
|
-
* treats the same way) renders the text without an anchor. */
|
|
17
|
-
const SAFE_HREF = /^(https?:|mailto:|tel:|\/(?![/\\])|#|\?|\.)/i;
|
|
18
|
-
function safeHref(raw) {
|
|
19
|
-
if (typeof raw !== "string")
|
|
20
|
-
return null;
|
|
21
|
-
// URL parsers drop tab, LF and CR, so normalise before testing to see what the parser sees.
|
|
22
|
-
const href = raw.replace(/[\t\n\r]/g, "").trim();
|
|
23
|
-
return href !== "" && SAFE_HREF.test(href) ? href : null;
|
|
24
|
-
}
|
|
25
14
|
/** Lazy by default: body images sit below the fold, and a lazy <img> is
|
|
26
15
|
* the one React does not hoist a preload hint for on the server. */
|
|
27
16
|
export function defaultRichTextImage({ image, caption }) {
|
|
28
17
|
return (_jsxs("figure", { children: [_jsx("img", { src: image.url, width: image.width, height: image.height, alt: image.alt, loading: "lazy" }), caption !== "" && _jsx("figcaption", { children: caption })] }));
|
|
29
18
|
}
|
|
30
|
-
const isResolvedImage = (v) => typeof v === "object" && v !== null && typeof v.url === "string"
|
|
31
|
-
&& typeof v.width === "number" && typeof v.height === "number";
|
|
32
19
|
export function RichText({ doc, elements = [], image = defaultRichTextImage }) {
|
|
33
20
|
const d = doc;
|
|
34
21
|
if (!d || typeof d !== "object" || d.type !== "doc" || !Array.isArray(d.content))
|
package/dist/schema-version.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** The minimum schema version the package needs. Moves ONLY in a release
|
|
2
2
|
* that adds a table, column, function or policy the package reads; a
|
|
3
3
|
* unit test holds it equal to the highest file in `migrations/`. */
|
|
4
|
-
export declare const SCHEMA_VERSION =
|
|
4
|
+
export declare const SCHEMA_VERSION = 10;
|
|
5
5
|
export declare const SCHEMA_VERSION_KEY = "schema_version";
|
|
6
6
|
export declare const CORE_FILE_RE: RegExp;
|
|
7
7
|
export declare const VIEWS_FILE_RE: RegExp;
|
package/dist/schema-version.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
/** The minimum schema version the package needs. Moves ONLY in a release
|
|
8
8
|
* that adds a table, column, function or policy the package reads; a
|
|
9
9
|
* unit test holds it equal to the highest file in `migrations/`. */
|
|
10
|
-
export const SCHEMA_VERSION =
|
|
10
|
+
export const SCHEMA_VERSION = 10;
|
|
11
11
|
export const SCHEMA_VERSION_KEY = "schema_version";
|
|
12
12
|
export const CORE_FILE_RE = /^(\d{14})_smoodly_v(\d+)\.sql$/;
|
|
13
13
|
export const VIEWS_FILE_RE = /^(\d{14})_smoodly_views\.sql$/;
|
package/dist/section-crash.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { CSSProperties } from "react";
|
|
2
|
+
import { crashMessage } from "./crash-message.ts";
|
|
3
|
+
export { crashMessage };
|
|
2
4
|
/** The canvas placeholders' look — the unknown section's too (spec 2026-09-27 editor safety §5). */
|
|
3
5
|
export declare const PLACEHOLDER_STYLE: CSSProperties;
|
|
4
|
-
/** Why it crashed, for the placeholder: the message, or the digest when a production build stripped the message. */
|
|
5
|
-
export declare function crashMessage(error: unknown): string;
|
|
6
6
|
export declare function CrashPlaceholder({ id, title, error, live }: {
|
|
7
7
|
id: string;
|
|
8
8
|
title: string;
|
package/dist/section-crash.js
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { crashMessage } from "./crash-message.js";
|
|
2
3
|
import { CRASHED_ATTR, NODE_ATTR } from "./marks.js";
|
|
4
|
+
export { crashMessage };
|
|
3
5
|
/** The canvas placeholders' look — the unknown section's too (spec 2026-09-27 editor safety §5). */
|
|
4
6
|
export const PLACEHOLDER_STYLE = {
|
|
5
7
|
padding: "24px 16px", border: "1px dashed #b54708", color: "#b54708", font: "500 14px/1.4 system-ui, sans-serif", textAlign: "center",
|
|
6
8
|
};
|
|
7
|
-
/** Why it crashed, for the placeholder: the message, or the digest when a production build stripped the message. */
|
|
8
|
-
export function crashMessage(error) {
|
|
9
|
-
const digest = typeof error === "object" && error !== null ? error.digest : undefined;
|
|
10
|
-
if (typeof digest === "string")
|
|
11
|
-
return `the server log has the error (digest ${digest})`;
|
|
12
|
-
return error instanceof Error ? error.message : String(error);
|
|
13
|
-
}
|
|
14
9
|
export function CrashPlaceholder({ id, title, error, live }) {
|
|
15
10
|
return (_jsx("div", { [NODE_ATTR]: id, [CRASHED_ATTR]: live, style: PLACEHOLDER_STYLE, children: `Section “${title}” failed to render — ${crashMessage(error)}` }));
|
|
16
11
|
}
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
-
import { type StyleProps
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
export type SmdInternal = {
|
|
6
|
-
node?: string;
|
|
7
|
-
css?: string;
|
|
8
|
-
values?: StyleValues;
|
|
9
|
-
/** Pre-scoped layout CSS (the custom section, spec 2026-09-14 §6), emitted before the editor's css so the box wins. */
|
|
10
|
-
layoutCss?: string;
|
|
11
|
-
};
|
|
2
|
+
import { type StyleProps } from "./styles.ts";
|
|
3
|
+
import { SMD_KEY, type SmdInternal } from "./smd-key.ts";
|
|
4
|
+
export { SMD_KEY, type SmdInternal };
|
|
12
5
|
export declare function Section({ as, styles, className, style, children, ...rest }: {
|
|
13
6
|
as?: keyof React.JSX.IntrinsicElements;
|
|
14
7
|
styles: StyleProps & {
|
package/dist/section-wrapper.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createElement } from "react";
|
|
|
2
2
|
import { NODE_ATTR } from "./marks.js";
|
|
3
3
|
import { DEFAULT_STYLE_VALUES, inlineStyles } from "./styles.js";
|
|
4
4
|
import { safeCss, scopedCss } from "./css.js";
|
|
5
|
+
import { SMD_KEY } from "./smd-key.js";
|
|
5
6
|
// The root wrapper every section renders through (spec 2026-09-14 §2, §4).
|
|
6
7
|
// Owns the real root element, no extra div: element choice via `as`,
|
|
7
8
|
// Smoodly's styles set rendered INLINE (an editor's step beats the
|
|
@@ -9,8 +10,8 @@ import { safeCss, scopedCss } from "./css.js";
|
|
|
9
10
|
// node id as data-smd-node always (the custom-CSS scope needs it on the
|
|
10
11
|
// live site), the scoped <style> child, and every other prop spread onto
|
|
11
12
|
// the root — settings never become attributes; the view writes its own.
|
|
12
|
-
|
|
13
|
-
export
|
|
13
|
+
// The reserved key lives in smd-key.ts (pure), re-exported here.
|
|
14
|
+
export { SMD_KEY };
|
|
14
15
|
export function Section({ as = "section", styles, className, style, children, ...rest }) {
|
|
15
16
|
const { [SMD_KEY]: smd, ...steps } = (styles ?? {});
|
|
16
17
|
const inline = inlineStyles(steps, smd?.values ?? DEFAULT_STYLE_VALUES);
|
package/dist/site.d.ts
CHANGED
|
@@ -4,18 +4,31 @@ import type { Descriptor } from "./fields.ts";
|
|
|
4
4
|
import { type EntryRecord, type EntryStore, type Where } from "./entry-store.ts";
|
|
5
5
|
import { type LocaleAlternate, type LocaleSet, type PageAlternate, type PathTarget } from "./paths.ts";
|
|
6
6
|
import type { SectionLike } from "./refs.ts";
|
|
7
|
-
import type { PageContext, PageLink, PageTree } from "./
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
7
|
+
import type { PageContext, PageLink, PageTree } from "./page-context.ts";
|
|
8
|
+
import type { GlobalSchema } from "./global.ts";
|
|
9
|
+
import type { StyleValues, StyleValuesInput } from "./styles.ts";
|
|
10
|
+
import type { CustomConfigInput, ResolvedCustom } from "./custom/index.ts";
|
|
11
11
|
import type { PageRecord, PageStore } from "./store.ts";
|
|
12
12
|
import type { PathHit } from "./path-index.ts";
|
|
13
13
|
import { type EntryItem, type PageItem, type Seo } from "./read-shapes.ts";
|
|
14
|
+
import type { SchemaOr } from "./registration.ts";
|
|
15
|
+
/** An address read with its layout's globals: the hit as `lookup` answers it, and each item's value by name. */
|
|
16
|
+
export type AddressWithGlobals = {
|
|
17
|
+
hit: SiteHit | {
|
|
18
|
+
kind: "redirect";
|
|
19
|
+
target: PathTarget;
|
|
20
|
+
} | null;
|
|
21
|
+
globals: Map<string, unknown>;
|
|
22
|
+
};
|
|
23
|
+
import type { PublishedStore } from "./published.ts";
|
|
24
|
+
import { type Projector } from "./project.ts";
|
|
14
25
|
export type SiteOptions = {
|
|
26
|
+
/** `published`: the delivery documents outside draft mode read (spec 2026-10-07 delivery model §3). */
|
|
15
27
|
stores: () => {
|
|
16
28
|
pages: PageStore;
|
|
17
29
|
entries: EntryStore;
|
|
18
30
|
assets?: AssetStore;
|
|
31
|
+
published: PublishedStore;
|
|
19
32
|
};
|
|
20
33
|
collections: CollectionSchema<any>[];
|
|
21
34
|
sections: SectionLike[];
|
|
@@ -31,18 +44,16 @@ export type SiteOptions = {
|
|
|
31
44
|
/** Page shapes (entry pages are ignored): the source of each template's page-field descriptors (spec 2026-09-10 page fields §3)
|
|
32
45
|
* and of the fixed pages' addresses (spec 2026-09-29 nested paths §3) — `config.registry.pages`. Required: a site that
|
|
33
46
|
* missed one would take its code-owned record for an orphan and drop its URLs at the first lookup. */
|
|
34
|
-
pages: ReadonlyArray<SitePageSchema
|
|
47
|
+
pages: ReadonlyArray<SchemaOr<SitePageSchema>>;
|
|
35
48
|
};
|
|
36
|
-
/** A page
|
|
49
|
+
/** A page type as the site needs it: its page fields, and a fixed page's address. */
|
|
37
50
|
export type SitePageSchema = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
seo?: true;
|
|
45
|
-
};
|
|
51
|
+
kind: string;
|
|
52
|
+
name: string;
|
|
53
|
+
title?: string;
|
|
54
|
+
slug?: string | Record<string, string>;
|
|
55
|
+
fields?: Record<string, Descriptor>;
|
|
56
|
+
seo?: true;
|
|
46
57
|
};
|
|
47
58
|
export type SitePage = {
|
|
48
59
|
kind: "page";
|
|
@@ -111,6 +122,8 @@ export interface SmoodlySite {
|
|
|
111
122
|
/** The package version and a hash of the registered model: a part of every cache key, so an upgrade or a
|
|
112
123
|
* model change never serves a unit cached in the old shape (spec 2026-09-30 tester findings §3). */
|
|
113
124
|
readonly cacheKey: string;
|
|
125
|
+
/** The document stamp a delivery row carries (DESIGN §3): the format number and the model hash, never the version. */
|
|
126
|
+
readonly stamp: string;
|
|
114
127
|
/** The resolved styles values the renderer and `getGlobal` hand the wrapper. */
|
|
115
128
|
readonly styles: StyleValues;
|
|
116
129
|
/** The custom section's resolved options the renderer hands renderPage. */
|
|
@@ -122,6 +135,17 @@ export interface SmoodlySite {
|
|
|
122
135
|
/** Everything the renderer needs for one target: null when it is a folder, unpublished (outside draft), or gone. */
|
|
123
136
|
load(target: PathTarget, locale: string, path: string, options?: LoadOptions): Promise<SiteHit | null>;
|
|
124
137
|
resolve(locale: string, path: string, options?: LoadOptions): Promise<SiteHit | null>;
|
|
138
|
+
/** The published read of an address (spec 2026-10-07 delivery model §3): one lookup of the stored document; on a miss
|
|
139
|
+
* the code-owned page, then one locate that tells a redirect row from a record to assemble and from a 404. */
|
|
140
|
+
lookup(locale: string, path: string): Promise<SiteHit | {
|
|
141
|
+
kind: "redirect";
|
|
142
|
+
target: PathTarget;
|
|
143
|
+
} | null>;
|
|
144
|
+
/** The same lookup with the layout's global items riding along (schema v9): one store call answers the page and
|
|
145
|
+
* each item's value by name, a row behind the model healed as `getGlobal` heals it. A miss brings no globals. */
|
|
146
|
+
lookupWithGlobals(locale: string, path: string, items: readonly GlobalSchema<any>[]): Promise<AddressWithGlobals>;
|
|
147
|
+
/** Writes delivery rows from the editing tables: Publish calls it, and heal on read goes through it. */
|
|
148
|
+
readonly projector: Projector;
|
|
125
149
|
/** A fixed page type (or a collection's index page) as code alone describes it, when `path` is its address in
|
|
126
150
|
* `locale`: an empty tree, the page fields' defaults, the registration's title. The renderer serves it where
|
|
127
151
|
* the index has no row — a page type added after install, a locale added to the config — until the admin
|
|
@@ -152,5 +176,7 @@ export interface SmoodlySite {
|
|
|
152
176
|
draft?: boolean;
|
|
153
177
|
}): Promise<V | null>;
|
|
154
178
|
}
|
|
179
|
+
/** The `page` prop for a loaded page. `href` is the app's seam from a
|
|
180
|
+
* locale-relative path to a site URL; the default keeps CMS paths as URLs. */
|
|
155
181
|
export declare function pageContextOf(hit: SitePage, href?: (path: string, locale: string) => string): PageContext;
|
|
156
182
|
export declare function createSmoodlySite(options: SiteOptions): SmoodlySite;
|