@protoyard/blueprint 0.0.0-stage → 1.1.1
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/LICENSE +21 -0
- package/README.md +1145 -2
- package/dist/aggregate.d.ts +83 -0
- package/dist/aggregate.js +268 -0
- package/dist/app-model.d.ts +76 -0
- package/dist/app-model.js +287 -0
- package/dist/archetypes/index.d.ts +1 -0
- package/dist/archetypes/index.js +1 -0
- package/dist/archetypes/schema.d.ts +126 -0
- package/dist/archetypes/schema.js +77 -0
- package/dist/audit.d.ts +52 -0
- package/dist/audit.js +149 -0
- package/dist/authoring/deck-lint.d.ts +32 -0
- package/dist/authoring/deck-lint.js +567 -0
- package/dist/authoring/index.d.ts +1 -0
- package/dist/authoring/index.js +1 -0
- package/dist/authoring/select-deck-layouts.d.ts +50 -0
- package/dist/authoring/select-deck-layouts.js +213 -0
- package/dist/authoring-apis.d.ts +13 -0
- package/dist/authoring-apis.js +13 -0
- package/dist/authoring-validation.d.ts +65 -0
- package/dist/authoring-validation.js +267 -0
- package/dist/avatar.d.ts +25 -0
- package/dist/avatar.js +30 -0
- package/dist/brand.d.ts +70 -0
- package/dist/brand.js +294 -0
- package/dist/brief/archetypes.d.ts +28 -0
- package/dist/brief/archetypes.js +798 -0
- package/dist/brief/content-synthesize.d.ts +31 -0
- package/dist/brief/content-synthesize.js +210 -0
- package/dist/brief/deck-outlines.d.ts +96 -0
- package/dist/brief/deck-outlines.js +561 -0
- package/dist/brief/draft-bodies.d.ts +29 -0
- package/dist/brief/draft-bodies.js +224 -0
- package/dist/brief/fields.d.ts +19 -0
- package/dist/brief/fields.js +229 -0
- package/dist/brief/index.d.ts +8 -0
- package/dist/brief/index.js +8 -0
- package/dist/brief/kind-detection.d.ts +69 -0
- package/dist/brief/kind-detection.js +353 -0
- package/dist/brief/limits.d.ts +117 -0
- package/dist/brief/limits.js +217 -0
- package/dist/brief/page-doc-outlines.d.ts +80 -0
- package/dist/brief/page-doc-outlines.js +485 -0
- package/dist/brief/synthesize.d.ts +59 -0
- package/dist/brief/synthesize.js +511 -0
- package/dist/brief/text.d.ts +13 -0
- package/dist/brief/text.js +59 -0
- package/dist/canvas-screen.d.ts +31 -0
- package/dist/canvas-screen.js +33 -0
- package/dist/canvas-seed.d.ts +58 -0
- package/dist/canvas-seed.js +82 -0
- package/dist/computed/evaluate.d.ts +11 -0
- package/dist/computed/evaluate.js +101 -0
- package/dist/computed/index.d.ts +4 -0
- package/dist/computed/index.js +3 -0
- package/dist/computed/public.d.ts +14 -0
- package/dist/computed/public.js +19 -0
- package/dist/computed/schema.d.ts +10 -0
- package/dist/computed/schema.js +140 -0
- package/dist/computed/types.d.ts +70 -0
- package/dist/computed/types.js +1 -0
- package/dist/computed/validate.d.ts +6 -0
- package/dist/computed/validate.js +146 -0
- package/dist/csv-guard.d.ts +15 -0
- package/dist/csv-guard.js +29 -0
- package/dist/csv.d.ts +85 -0
- package/dist/csv.js +288 -0
- package/dist/files.d.ts +35 -0
- package/dist/files.js +246 -0
- package/dist/form-schema.d.ts +124 -0
- package/dist/form-schema.js +300 -0
- package/dist/generator-version.d.ts +11 -0
- package/dist/generator-version.js +51 -0
- package/dist/generator.d.ts +34 -0
- package/dist/generator.js +445 -0
- package/dist/identity.d.ts +34 -0
- package/dist/identity.js +91 -0
- package/dist/import/csv-shape.d.ts +40 -0
- package/dist/import/csv-shape.js +265 -0
- package/dist/import/json-shape.d.ts +55 -0
- package/dist/import/json-shape.js +491 -0
- package/dist/import/limits.d.ts +13 -0
- package/dist/import/limits.js +14 -0
- package/dist/import/sqlite-schema.d.ts +36 -0
- package/dist/import/sqlite-schema.js +729 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +58 -0
- package/dist/kinds/anchors.d.ts +18 -0
- package/dist/kinds/anchors.js +46 -0
- package/dist/kinds/bodies.d.ts +6 -0
- package/dist/kinds/bodies.js +32 -0
- package/dist/kinds/brand-runtime.d.ts +19 -0
- package/dist/kinds/brand-runtime.js +35 -0
- package/dist/kinds/deck.d.ts +8 -0
- package/dist/kinds/deck.js +34 -0
- package/dist/kinds/doc.d.ts +19 -0
- package/dist/kinds/doc.js +41 -0
- package/dist/kinds/embed/index.d.ts +39 -0
- package/dist/kinds/embed/index.js +91 -0
- package/dist/kinds/envelope.d.ts +159 -0
- package/dist/kinds/envelope.js +78 -0
- package/dist/kinds/index.d.ts +11 -0
- package/dist/kinds/index.js +11 -0
- package/dist/kinds/kind.d.ts +36 -0
- package/dist/kinds/kind.js +55 -0
- package/dist/kinds/limits.d.ts +64 -0
- package/dist/kinds/limits.js +190 -0
- package/dist/kinds/page-doc-runtime.d.ts +37 -0
- package/dist/kinds/page-doc-runtime.js +55 -0
- package/dist/kinds/page.d.ts +16 -0
- package/dist/kinds/page.js +67 -0
- package/dist/kinds/parse.d.ts +18 -0
- package/dist/kinds/parse.js +27 -0
- package/dist/kinds/runtime.d.ts +128 -0
- package/dist/kinds/runtime.js +206 -0
- package/dist/kinds/services.d.ts +49 -0
- package/dist/kinds/services.js +249 -0
- package/dist/kinds/testing.d.ts +9 -0
- package/dist/kinds/testing.js +16 -0
- package/dist/migrations.d.ts +97 -0
- package/dist/migrations.js +351 -0
- package/dist/motion.d.ts +50 -0
- package/dist/motion.js +52 -0
- package/dist/notifications.d.ts +19 -0
- package/dist/notifications.js +177 -0
- package/dist/patch.d.ts +122 -0
- package/dist/patch.js +322 -0
- package/dist/policy.d.ts +23 -0
- package/dist/policy.js +105 -0
- package/dist/runtime-definition.d.ts +39 -0
- package/dist/runtime-definition.js +74 -0
- package/dist/scenarios.d.ts +9 -0
- package/dist/scenarios.js +49 -0
- package/dist/schema/blueprint.schema.json +10191 -0
- package/dist/schema-json.d.ts +6 -0
- package/dist/schema-json.js +36 -0
- package/dist/schema.d.ts +6348 -0
- package/dist/schema.js +1269 -0
- package/dist/search.d.ts +16 -0
- package/dist/search.js +96 -0
- package/dist/services.d.ts +89 -0
- package/dist/services.js +898 -0
- package/dist/share.d.ts +78 -0
- package/dist/share.js +234 -0
- package/dist/sheet-screen.d.ts +49 -0
- package/dist/sheet-screen.js +91 -0
- package/dist/storage.d.ts +43 -0
- package/dist/storage.js +179 -0
- package/dist/stream.d.ts +26 -0
- package/dist/stream.js +173 -0
- package/dist/untrusted.d.ts +63 -0
- package/dist/untrusted.js +502 -0
- package/dist/validation-tasks.d.ts +178 -0
- package/dist/validation-tasks.js +199 -0
- package/dist/validation.d.ts +35 -0
- package/dist/validation.js +312 -0
- package/dist/variants.d.ts +112 -0
- package/dist/variants.js +283 -0
- package/dist/workflows/index.d.ts +3 -0
- package/dist/workflows/index.js +3 -0
- package/dist/workflows/schema.d.ts +50 -0
- package/dist/workflows/schema.js +34 -0
- package/dist/workflows/transition.d.ts +15 -0
- package/dist/workflows/transition.js +25 -0
- package/dist/workflows/validate.d.ts +17 -0
- package/dist/workflows/validate.js +140 -0
- package/package.json +120 -3
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type { Deck } from '@protoyard/decks/schema';
|
|
2
|
+
import type { DocDocument, PageDocument } from '@protoyard/pages';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { type Blueprint } from '../schema.ts';
|
|
5
|
+
import { type BlueprintKind, type ContentKind } from './kind.ts';
|
|
6
|
+
/**
|
|
7
|
+
* The kind union (ADR-036): `parseAnyBlueprint` accepts an app (no `kind`, or
|
|
8
|
+
* `kind: "app"`, parsed by the unchanged app schema) or a content kind whose
|
|
9
|
+
* body schema its engine package supplies (`bodies.ts`). `parseBlueprint`
|
|
10
|
+
* stays app-only, so every consumer that reads `.entities` keeps its type.
|
|
11
|
+
*
|
|
12
|
+
* A content blueprint is strict: the shared root keys plus `kind` and one body
|
|
13
|
+
* key named after the kind. Content schemas load through a kind-specific
|
|
14
|
+
* dynamic import; app parsing never loads deck, page, or doc validators.
|
|
15
|
+
* App-only keys (entities, roles, screens, layout, archetype, notifications,
|
|
16
|
+
* history, validation) are rejected there.
|
|
17
|
+
*/
|
|
18
|
+
declare const BlueprintBaseSchema: z.ZodObject<{
|
|
19
|
+
$schema: z.ZodOptional<z.ZodString>;
|
|
20
|
+
formatVersion: z.ZodLiteral<1>;
|
|
21
|
+
name: z.ZodString;
|
|
22
|
+
description: z.ZodOptional<z.ZodString>;
|
|
23
|
+
catalog: z.ZodOptional<z.ZodObject<{
|
|
24
|
+
category: z.ZodEnum<{
|
|
25
|
+
marketing: "marketing";
|
|
26
|
+
starter: "starter";
|
|
27
|
+
productivity: "productivity";
|
|
28
|
+
communication: "communication";
|
|
29
|
+
sales: "sales";
|
|
30
|
+
support: "support";
|
|
31
|
+
finance: "finance";
|
|
32
|
+
commerce: "commerce";
|
|
33
|
+
marketplace: "marketplace";
|
|
34
|
+
ai: "ai";
|
|
35
|
+
analytics: "analytics";
|
|
36
|
+
"developer-tools": "developer-tools";
|
|
37
|
+
design: "design";
|
|
38
|
+
education: "education";
|
|
39
|
+
health: "health";
|
|
40
|
+
hr: "hr";
|
|
41
|
+
operations: "operations";
|
|
42
|
+
media: "media";
|
|
43
|
+
social: "social";
|
|
44
|
+
travel: "travel";
|
|
45
|
+
"real-estate": "real-estate";
|
|
46
|
+
"internal-tools": "internal-tools";
|
|
47
|
+
}>;
|
|
48
|
+
productType: z.ZodOptional<z.ZodString>;
|
|
49
|
+
platforms: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
50
|
+
desktop: "desktop";
|
|
51
|
+
mobile: "mobile";
|
|
52
|
+
tablet: "tablet";
|
|
53
|
+
web: "web";
|
|
54
|
+
widget: "widget";
|
|
55
|
+
extension: "extension";
|
|
56
|
+
plugin: "plugin";
|
|
57
|
+
}>>>;
|
|
58
|
+
shell: z.ZodOptional<z.ZodEnum<{
|
|
59
|
+
tablet: "tablet";
|
|
60
|
+
auto: "auto";
|
|
61
|
+
none: "none";
|
|
62
|
+
phone: "phone";
|
|
63
|
+
"desktop-window": "desktop-window";
|
|
64
|
+
browser: "browser";
|
|
65
|
+
"widget-host": "widget-host";
|
|
66
|
+
"extension-popup": "extension-popup";
|
|
67
|
+
"side-panel": "side-panel";
|
|
68
|
+
}>>;
|
|
69
|
+
features: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
70
|
+
highlights: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
71
|
+
difficulty: z.ZodOptional<z.ZodEnum<{
|
|
72
|
+
beginner: "beginner";
|
|
73
|
+
intermediate: "intermediate";
|
|
74
|
+
advanced: "advanced";
|
|
75
|
+
}>>;
|
|
76
|
+
}, z.core.$strict>>;
|
|
77
|
+
tags: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
78
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
79
|
+
category: z.ZodOptional<z.ZodString>;
|
|
80
|
+
brand: z.ZodOptional<z.ZodObject<{
|
|
81
|
+
id: z.ZodOptional<z.ZodString>;
|
|
82
|
+
name: z.ZodOptional<z.ZodString>;
|
|
83
|
+
seed: z.ZodOptional<z.ZodString>;
|
|
84
|
+
secondary: z.ZodOptional<z.ZodString>;
|
|
85
|
+
preset: z.ZodOptional<z.ZodEnum<{
|
|
86
|
+
violet: "violet";
|
|
87
|
+
ocean: "ocean";
|
|
88
|
+
emerald: "emerald";
|
|
89
|
+
rose: "rose";
|
|
90
|
+
amber: "amber";
|
|
91
|
+
monochrome: "monochrome";
|
|
92
|
+
}>>;
|
|
93
|
+
styleProfile: z.ZodOptional<z.ZodEnum<{
|
|
94
|
+
flat: "flat";
|
|
95
|
+
soft: "soft";
|
|
96
|
+
crisp: "crisp";
|
|
97
|
+
editorial: "editorial";
|
|
98
|
+
rounded: "rounded";
|
|
99
|
+
mono: "mono";
|
|
100
|
+
}>>;
|
|
101
|
+
font: z.ZodOptional<z.ZodEnum<{
|
|
102
|
+
system: "system";
|
|
103
|
+
humanist: "humanist";
|
|
104
|
+
geometric: "geometric";
|
|
105
|
+
grotesk: "grotesk";
|
|
106
|
+
editorial: "editorial";
|
|
107
|
+
rounded: "rounded";
|
|
108
|
+
condensed: "condensed";
|
|
109
|
+
mono: "mono";
|
|
110
|
+
}>>;
|
|
111
|
+
radius: z.ZodOptional<z.ZodString>;
|
|
112
|
+
density: z.ZodOptional<z.ZodNumber>;
|
|
113
|
+
libraryTheme: z.ZodOptional<z.ZodString>;
|
|
114
|
+
}, z.core.$strict>>;
|
|
115
|
+
motion: z.ZodOptional<z.ZodObject<{
|
|
116
|
+
level: z.ZodEnum<{
|
|
117
|
+
none: "none";
|
|
118
|
+
subtle: "subtle";
|
|
119
|
+
full: "full";
|
|
120
|
+
}>;
|
|
121
|
+
}, z.core.$strict>>;
|
|
122
|
+
}, z.core.$strict>;
|
|
123
|
+
/** Root fields every kind shares (name, description, catalog, tags, icon, category, brand). */
|
|
124
|
+
export type BlueprintBase = z.output<typeof BlueprintBaseSchema>;
|
|
125
|
+
/**
|
|
126
|
+
* The parsed body of each content kind, as defined by its engine package.
|
|
127
|
+
*/
|
|
128
|
+
export interface KindBodies {
|
|
129
|
+
deck: Deck;
|
|
130
|
+
page: PageDocument;
|
|
131
|
+
doc: DocDocument;
|
|
132
|
+
}
|
|
133
|
+
export type ContentBlueprint<K extends ContentKind> = BlueprintBase & {
|
|
134
|
+
kind: K;
|
|
135
|
+
} & {
|
|
136
|
+
[P in K]: KindBodies[P];
|
|
137
|
+
};
|
|
138
|
+
export type DeckBlueprint = ContentBlueprint<'deck'>;
|
|
139
|
+
export type PageBlueprint = ContentBlueprint<'page'>;
|
|
140
|
+
export type DocBlueprint = ContentBlueprint<'doc'>;
|
|
141
|
+
/** Any parsed blueprint. Apps carry no `kind` once parsed; content kinds always do. */
|
|
142
|
+
export type AnyBlueprint = Blueprint | DeckBlueprint | PageBlueprint | DocBlueprint;
|
|
143
|
+
/**
|
|
144
|
+
* The whole-blueprint schema of a content kind around its body schema (cached
|
|
145
|
+
* per kind). @internal Used by `parseAnyBlueprint` and `kinds/parse.ts`.
|
|
146
|
+
*/
|
|
147
|
+
export declare function contentBlueprintSchema(kind: ContentKind, body: z.ZodType): z.ZodType;
|
|
148
|
+
/** Validates any kind of blueprint. Never throws; an unknown kind fails on `kind`. */
|
|
149
|
+
export declare function safeParseAnyBlueprint(input: unknown): Promise<z.ZodSafeParseResult<AnyBlueprint>>;
|
|
150
|
+
/** Validates any kind of blueprint; throws a `ZodError` on failure. */
|
|
151
|
+
export declare function parseAnyBlueprint(input: unknown): Promise<AnyBlueprint>;
|
|
152
|
+
/** The kind of a parsed blueprint (`app` when it has none). */
|
|
153
|
+
export declare function blueprintKind(blueprint: AnyBlueprint): BlueprintKind;
|
|
154
|
+
export declare function isAppBlueprint(blueprint: AnyBlueprint): blueprint is Blueprint;
|
|
155
|
+
export declare function isContentBlueprint(blueprint: AnyBlueprint): blueprint is DeckBlueprint | PageBlueprint | DocBlueprint;
|
|
156
|
+
export declare function isDeckBlueprint(blueprint: AnyBlueprint): blueprint is DeckBlueprint;
|
|
157
|
+
export declare function isPageBlueprint(blueprint: AnyBlueprint): blueprint is PageBlueprint;
|
|
158
|
+
export declare function isDocBlueprint(blueprint: AnyBlueprint): blueprint is DocBlueprint;
|
|
159
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { BLUEPRINT_BASE_SHAPE, BlueprintSchema } from "../schema.js";
|
|
3
|
+
import { kindBodySchema } from "./bodies.js";
|
|
4
|
+
import { detectBlueprintKind } from "./kind.js";
|
|
5
|
+
/**
|
|
6
|
+
* The kind union (ADR-036): `parseAnyBlueprint` accepts an app (no `kind`, or
|
|
7
|
+
* `kind: "app"`, parsed by the unchanged app schema) or a content kind whose
|
|
8
|
+
* body schema its engine package supplies (`bodies.ts`). `parseBlueprint`
|
|
9
|
+
* stays app-only, so every consumer that reads `.entities` keeps its type.
|
|
10
|
+
*
|
|
11
|
+
* A content blueprint is strict: the shared root keys plus `kind` and one body
|
|
12
|
+
* key named after the kind. Content schemas load through a kind-specific
|
|
13
|
+
* dynamic import; app parsing never loads deck, page, or doc validators.
|
|
14
|
+
* App-only keys (entities, roles, screens, layout, archetype, notifications,
|
|
15
|
+
* history, validation) are rejected there.
|
|
16
|
+
*/
|
|
17
|
+
const BlueprintBaseSchema = z.strictObject(BLUEPRINT_BASE_SHAPE);
|
|
18
|
+
const contentSchemas = new Map();
|
|
19
|
+
/**
|
|
20
|
+
* The whole-blueprint schema of a content kind around its body schema (cached
|
|
21
|
+
* per kind). @internal Used by `parseAnyBlueprint` and `kinds/parse.ts`.
|
|
22
|
+
*/
|
|
23
|
+
export function contentBlueprintSchema(kind, body) {
|
|
24
|
+
const cached = contentSchemas.get(kind);
|
|
25
|
+
if (cached?.body === body)
|
|
26
|
+
return cached.schema;
|
|
27
|
+
const schema = z.strictObject({
|
|
28
|
+
...BLUEPRINT_BASE_SHAPE,
|
|
29
|
+
kind: z.literal(kind),
|
|
30
|
+
[kind]: body,
|
|
31
|
+
});
|
|
32
|
+
contentSchemas.set(kind, { body, schema });
|
|
33
|
+
return schema;
|
|
34
|
+
}
|
|
35
|
+
function failure(message, input) {
|
|
36
|
+
const error = new z.ZodError([{ code: 'custom', path: ['kind'], message, input }]);
|
|
37
|
+
return { success: false, error: error };
|
|
38
|
+
}
|
|
39
|
+
/** Validates any kind of blueprint. Never throws; an unknown kind fails on `kind`. */
|
|
40
|
+
export async function safeParseAnyBlueprint(input) {
|
|
41
|
+
const detected = detectBlueprintKind(input);
|
|
42
|
+
const kind = input?.kind;
|
|
43
|
+
if (!detected.ok)
|
|
44
|
+
return failure(detected.message, kind);
|
|
45
|
+
if (detected.kind === 'app')
|
|
46
|
+
return BlueprintSchema.safeParse(input);
|
|
47
|
+
const body = await kindBodySchema(detected.kind);
|
|
48
|
+
if (!body) {
|
|
49
|
+
return failure(`Blueprint kind "${detected.kind}" is not available in this build of Protoyard yet.`, kind);
|
|
50
|
+
}
|
|
51
|
+
return contentBlueprintSchema(detected.kind, body).safeParse(input);
|
|
52
|
+
}
|
|
53
|
+
/** Validates any kind of blueprint; throws a `ZodError` on failure. */
|
|
54
|
+
export async function parseAnyBlueprint(input) {
|
|
55
|
+
const result = await safeParseAnyBlueprint(input);
|
|
56
|
+
if (!result.success)
|
|
57
|
+
throw result.error;
|
|
58
|
+
return result.data;
|
|
59
|
+
}
|
|
60
|
+
/** The kind of a parsed blueprint (`app` when it has none). */
|
|
61
|
+
export function blueprintKind(blueprint) {
|
|
62
|
+
return 'kind' in blueprint ? blueprint.kind : 'app';
|
|
63
|
+
}
|
|
64
|
+
export function isAppBlueprint(blueprint) {
|
|
65
|
+
return !('kind' in blueprint);
|
|
66
|
+
}
|
|
67
|
+
export function isContentBlueprint(blueprint) {
|
|
68
|
+
return 'kind' in blueprint;
|
|
69
|
+
}
|
|
70
|
+
export function isDeckBlueprint(blueprint) {
|
|
71
|
+
return blueprintKind(blueprint) === 'deck';
|
|
72
|
+
}
|
|
73
|
+
export function isPageBlueprint(blueprint) {
|
|
74
|
+
return blueprintKind(blueprint) === 'page';
|
|
75
|
+
}
|
|
76
|
+
export function isDocBlueprint(blueprint) {
|
|
77
|
+
return blueprintKind(blueprint) === 'doc';
|
|
78
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@protoyard/blueprint/kinds` — the runtime of content-kind blueprints (deck,
|
|
3
|
+
* page, doc; ADR-036): `defineKindRuntime` (the prototype definition shared by
|
|
4
|
+
* the player and generated kind prototypes) and `createKindServices` (the
|
|
5
|
+
* persistent `BlockStateHost` and form responses). A subpath so app
|
|
6
|
+
* prototypes and the universal player never load it.
|
|
7
|
+
*/
|
|
8
|
+
export { defineKindRuntime, kindBrandTheme, kindDefaultThemeId } from './brand-runtime.ts';
|
|
9
|
+
export { definePrototypeFromDoc, definePrototypeFromPage, PAGES_DEFAULT_SCENARIO, PAGES_GENERATOR_VERSION, type PageDocRuntimeOptions, } from './page-doc-runtime.ts';
|
|
10
|
+
export { type AnyContentBlueprint, defineKindPrototype, KIND_CAPABILITIES, KIND_DATABASE_VERSIONS, KIND_DEFAULT_SCENARIO, KIND_GENERATOR_VERSION, KIND_PERSONAS, KIND_ROLES, KIND_SCHEMA_VERSION, KIND_STORES, type KindPrototypeOptions, type KindRole, type KindRuntimeOptions, kindPolicy, kindScenarios, kindWorld, } from './runtime.ts';
|
|
11
|
+
export { createKindServices, type FormResponse, FormResponseError, findDocumentBlock, formResponseSchema, type KindServices, type KindServicesOptions, } from './services.ts';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@protoyard/blueprint/kinds` — the runtime of content-kind blueprints (deck,
|
|
3
|
+
* page, doc; ADR-036): `defineKindRuntime` (the prototype definition shared by
|
|
4
|
+
* the player and generated kind prototypes) and `createKindServices` (the
|
|
5
|
+
* persistent `BlockStateHost` and form responses). A subpath so app
|
|
6
|
+
* prototypes and the universal player never load it.
|
|
7
|
+
*/
|
|
8
|
+
export { defineKindRuntime, kindBrandTheme, kindDefaultThemeId } from "./brand-runtime.js";
|
|
9
|
+
export { definePrototypeFromDoc, definePrototypeFromPage, PAGES_DEFAULT_SCENARIO, PAGES_GENERATOR_VERSION, } from "./page-doc-runtime.js";
|
|
10
|
+
export { defineKindPrototype, KIND_CAPABILITIES, KIND_DATABASE_VERSIONS, KIND_DEFAULT_SCENARIO, KIND_GENERATOR_VERSION, KIND_PERSONAS, KIND_ROLES, KIND_SCHEMA_VERSION, KIND_STORES, kindPolicy, kindScenarios, kindWorld, } from "./runtime.js";
|
|
11
|
+
export { createKindServices, FormResponseError, findDocumentBlock, formResponseSchema, } from "./services.js";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blueprint kinds (ADR-036). A blueprint's `kind` decides its renderer at both
|
|
3
|
+
* levels (player and `generate`), its synthesizer, variants and validation
|
|
4
|
+
* summary. A missing `kind` means `app`, so every blueprint written before
|
|
5
|
+
* kinds existed keeps its meaning and its content identity.
|
|
6
|
+
*
|
|
7
|
+
* Not to be confused with the registry's `ProjectKind` (prototype, template,
|
|
8
|
+
* blueprint) in `@protoyard/core`: that names where a project comes from, this
|
|
9
|
+
* names what a blueprint renders as.
|
|
10
|
+
*/
|
|
11
|
+
/** Every kind this version understands, in display order. */
|
|
12
|
+
export declare const BLUEPRINT_KINDS: readonly ["app", "deck", "page", "doc"];
|
|
13
|
+
export type BlueprintKind = (typeof BLUEPRINT_KINDS)[number];
|
|
14
|
+
/** Kinds made of content (blocks) rather than entities; each has a body key named after it. */
|
|
15
|
+
export declare const CONTENT_KINDS: readonly ["deck", "page", "doc"];
|
|
16
|
+
export type ContentKind = (typeof CONTENT_KINDS)[number];
|
|
17
|
+
/** The kind a blueprint without `kind` has. */
|
|
18
|
+
export declare const DEFAULT_BLUEPRINT_KIND: BlueprintKind;
|
|
19
|
+
export declare function isBlueprintKind(value: unknown): value is BlueprintKind;
|
|
20
|
+
export declare function isContentKind(value: unknown): value is ContentKind;
|
|
21
|
+
/** The friendly message for a `kind` this version does not know. */
|
|
22
|
+
export declare function unknownKindMessage(kind: string): string;
|
|
23
|
+
export type KindDetection = {
|
|
24
|
+
ok: true;
|
|
25
|
+
kind: BlueprintKind;
|
|
26
|
+
} | {
|
|
27
|
+
ok: false;
|
|
28
|
+
message: string;
|
|
29
|
+
fix: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Reads the kind of unparsed input without validating anything else: a
|
|
33
|
+
* missing or `undefined` kind is `app`. Loaders use it to pick a schema (and,
|
|
34
|
+
* in the player, a renderer) before parsing.
|
|
35
|
+
*/
|
|
36
|
+
export declare function detectBlueprintKind(input: unknown): KindDetection;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blueprint kinds (ADR-036). A blueprint's `kind` decides its renderer at both
|
|
3
|
+
* levels (player and `generate`), its synthesizer, variants and validation
|
|
4
|
+
* summary. A missing `kind` means `app`, so every blueprint written before
|
|
5
|
+
* kinds existed keeps its meaning and its content identity.
|
|
6
|
+
*
|
|
7
|
+
* Not to be confused with the registry's `ProjectKind` (prototype, template,
|
|
8
|
+
* blueprint) in `@protoyard/core`: that names where a project comes from, this
|
|
9
|
+
* names what a blueprint renders as.
|
|
10
|
+
*/
|
|
11
|
+
/** Every kind this version understands, in display order. */
|
|
12
|
+
export const BLUEPRINT_KINDS = ['app', 'deck', 'page', 'doc'];
|
|
13
|
+
/** Kinds made of content (blocks) rather than entities; each has a body key named after it. */
|
|
14
|
+
export const CONTENT_KINDS = ['deck', 'page', 'doc'];
|
|
15
|
+
/** The kind a blueprint without `kind` has. */
|
|
16
|
+
export const DEFAULT_BLUEPRINT_KIND = 'app';
|
|
17
|
+
export function isBlueprintKind(value) {
|
|
18
|
+
return typeof value === 'string' && BLUEPRINT_KINDS.includes(value);
|
|
19
|
+
}
|
|
20
|
+
export function isContentKind(value) {
|
|
21
|
+
return typeof value === 'string' && CONTENT_KINDS.includes(value);
|
|
22
|
+
}
|
|
23
|
+
/** The friendly message for a `kind` this version does not know. */
|
|
24
|
+
export function unknownKindMessage(kind) {
|
|
25
|
+
const shown = kind.length > 40 ? `${kind.slice(0, 40)}…` : kind;
|
|
26
|
+
return `Blueprint kind "${shown}" needs a newer Protoyard (this version supports ${BLUEPRINT_KINDS.join(', ')}).`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Reads the kind of unparsed input without validating anything else: a
|
|
30
|
+
* missing or `undefined` kind is `app`. Loaders use it to pick a schema (and,
|
|
31
|
+
* in the player, a renderer) before parsing.
|
|
32
|
+
*/
|
|
33
|
+
export function detectBlueprintKind(input) {
|
|
34
|
+
if (input === null || typeof input !== 'object' || Array.isArray(input)) {
|
|
35
|
+
return { ok: true, kind: DEFAULT_BLUEPRINT_KIND };
|
|
36
|
+
}
|
|
37
|
+
const kind = Object.hasOwn(input, 'kind') ? input.kind : undefined;
|
|
38
|
+
if (kind === undefined)
|
|
39
|
+
return { ok: true, kind: DEFAULT_BLUEPRINT_KIND };
|
|
40
|
+
if (typeof kind !== 'string') {
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
message: `Blueprint "kind" must be a string (one of ${BLUEPRINT_KINDS.join(', ')}).`,
|
|
44
|
+
fix: 'Set "kind" to app, deck, page or doc, or remove it for an app.',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (!isBlueprintKind(kind)) {
|
|
48
|
+
return {
|
|
49
|
+
ok: false,
|
|
50
|
+
message: unknownKindMessage(kind),
|
|
51
|
+
fix: 'Update Protoyard, or set "kind" to one this version supports.',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return { ok: true, kind };
|
|
55
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ContentKind } from './kind.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Untrusted-input rules for content-kind blueprints (deck, page, doc;
|
|
4
|
+
* ADR-036): size caps checked before any schema runs, the multiline string
|
|
5
|
+
* allowlist, and the embedded-app walk. Pure and dependency-free on purpose:
|
|
6
|
+
* the untrusted loader sits on the player's first screen, and importing the
|
|
7
|
+
* block or deck engines here would put them there for every app.
|
|
8
|
+
*
|
|
9
|
+
* The multiline allowlist is a fixed set of schema field names (the block
|
|
10
|
+
* engine's markdown fields, list item text, code blocks, deck layout code,
|
|
11
|
+
* speaker notes). It is never
|
|
12
|
+
* read from the data: a document can only use the fields the schemas define.
|
|
13
|
+
*/
|
|
14
|
+
export interface UntrustedDocumentLimits {
|
|
15
|
+
/** Serialized UTF-8 bytes of a content document (media data URIs count). */
|
|
16
|
+
maxBytes: number;
|
|
17
|
+
/** JSON nesting depth. */
|
|
18
|
+
maxDepth: number;
|
|
19
|
+
/** Slides in a deck. */
|
|
20
|
+
maxSlides: number;
|
|
21
|
+
/** Blocks in one slide (nested container blocks included). */
|
|
22
|
+
maxBlocksPerSlide: number;
|
|
23
|
+
/** Blocks in the whole document (nested container blocks included). */
|
|
24
|
+
maxBlocks: number;
|
|
25
|
+
/** Chart data points (labels × series) across every chart block. */
|
|
26
|
+
maxChartPoints: number;
|
|
27
|
+
/** `embed-app` blocks in the document. */
|
|
28
|
+
maxEmbeddedApps: number;
|
|
29
|
+
}
|
|
30
|
+
export declare const DEFAULT_UNTRUSTED_DOCUMENT_LIMITS: Readonly<UntrustedDocumentLimits>;
|
|
31
|
+
/** How a string value is cleaned: controls stripped, newlines kept, or newlines and tabs kept. */
|
|
32
|
+
export type TextContext = 'plain' | 'multiline' | 'code';
|
|
33
|
+
/**
|
|
34
|
+
* The text context of `key` inside `record` (its parent object). Speaker
|
|
35
|
+
* notes and the block markdown fields keep newlines. Code keeps tabs too: a
|
|
36
|
+
* `code` block's `code`, and a deck layout's code object (`{ lang, source }`,
|
|
37
|
+
* the `code-with-callout` layout's `props.code`). List item text is markdown,
|
|
38
|
+
* and every other string (titles, labels, ids, a big stat's `source` caption)
|
|
39
|
+
* stays one line.
|
|
40
|
+
*/
|
|
41
|
+
export declare function textContextFor(key: string, record: Readonly<Record<string, unknown>>, inListItems: boolean): TextContext;
|
|
42
|
+
export interface ContentLimitIssue {
|
|
43
|
+
path: (string | number)[];
|
|
44
|
+
message: string;
|
|
45
|
+
fix: string;
|
|
46
|
+
}
|
|
47
|
+
export interface EmbeddedApp {
|
|
48
|
+
path: (string | number)[];
|
|
49
|
+
app: unknown;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Walks a sanitized content document and checks the caps the schemas do not
|
|
53
|
+
* express across the whole document: slide count, blocks per slide and in
|
|
54
|
+
* total (nested container blocks count), chart points and embedded apps. It
|
|
55
|
+
* returns the first problem, or the embedded apps to validate next.
|
|
56
|
+
*/
|
|
57
|
+
export declare function checkContentLimits(root: Readonly<Record<string, unknown>>, kind: ContentKind, limits: UntrustedDocumentLimits): {
|
|
58
|
+
issue: ContentLimitIssue;
|
|
59
|
+
} | {
|
|
60
|
+
issue: null;
|
|
61
|
+
embeddedApps: EmbeddedApp[];
|
|
62
|
+
};
|
|
63
|
+
/** Whether `value` holds an `embed-app` block anywhere (embedded apps may not embed again). */
|
|
64
|
+
export declare function containsEmbeddedApp(value: unknown): boolean;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
export const DEFAULT_UNTRUSTED_DOCUMENT_LIMITS = Object.freeze({
|
|
2
|
+
// Matches the block engine's guard (BLOCK_LIMITS.maxBytes): room for the
|
|
3
|
+
// 512 KB of raster data URIs a document may carry.
|
|
4
|
+
maxBytes: 1024 * 1024,
|
|
5
|
+
maxDepth: 32,
|
|
6
|
+
// The deck schema's own caps (DECK_LIMITS.slides) and the block engine's
|
|
7
|
+
// document cap (BLOCK_LIMITS.maxBlocks).
|
|
8
|
+
maxSlides: 200,
|
|
9
|
+
maxBlocksPerSlide: 200,
|
|
10
|
+
maxBlocks: 2_000,
|
|
11
|
+
// Eight full charts (366 labels × 8 series is one chart's schema maximum).
|
|
12
|
+
maxChartPoints: 8 * 366 * 8,
|
|
13
|
+
maxEmbeddedApps: 8,
|
|
14
|
+
});
|
|
15
|
+
/** Block fields that hold markdown or multi-line prose (mirrors the block engine's guard). */
|
|
16
|
+
const MULTILINE_FIELDS = new Set([
|
|
17
|
+
'markdown',
|
|
18
|
+
'quote',
|
|
19
|
+
'body',
|
|
20
|
+
'prompt',
|
|
21
|
+
'explanation',
|
|
22
|
+
'description',
|
|
23
|
+
]);
|
|
24
|
+
/**
|
|
25
|
+
* The text context of `key` inside `record` (its parent object). Speaker
|
|
26
|
+
* notes and the block markdown fields keep newlines. Code keeps tabs too: a
|
|
27
|
+
* `code` block's `code`, and a deck layout's code object (`{ lang, source }`,
|
|
28
|
+
* the `code-with-callout` layout's `props.code`). List item text is markdown,
|
|
29
|
+
* and every other string (titles, labels, ids, a big stat's `source` caption)
|
|
30
|
+
* stays one line.
|
|
31
|
+
*/
|
|
32
|
+
export function textContextFor(key, record, inListItems) {
|
|
33
|
+
if (key === 'code' && record.type === 'code')
|
|
34
|
+
return 'code';
|
|
35
|
+
if (key === 'source' && typeof record.lang === 'string')
|
|
36
|
+
return 'code';
|
|
37
|
+
if (key === 'notes' && typeof record.id === 'string')
|
|
38
|
+
return 'multiline';
|
|
39
|
+
if (MULTILINE_FIELDS.has(key))
|
|
40
|
+
return 'multiline';
|
|
41
|
+
if (inListItems && key === 'text')
|
|
42
|
+
return 'multiline';
|
|
43
|
+
return 'plain';
|
|
44
|
+
}
|
|
45
|
+
const isRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
46
|
+
/** Blocks directly in `value` when it is a block list (`blocks` arrays, `columns` cells). */
|
|
47
|
+
function* blockLists(record, path) {
|
|
48
|
+
if (Array.isArray(record.blocks))
|
|
49
|
+
yield { list: record.blocks, path: [...path, 'blocks'] };
|
|
50
|
+
if (record.type === 'columns' && Array.isArray(record.columns)) {
|
|
51
|
+
for (const [i, column] of record.columns.entries()) {
|
|
52
|
+
if (Array.isArray(column))
|
|
53
|
+
yield { list: column, path: [...path, 'columns', i] };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (record.type === 'tabs' && Array.isArray(record.panels)) {
|
|
57
|
+
for (const [i, panel] of record.panels.entries()) {
|
|
58
|
+
if (isRecord(panel) && Array.isArray(panel.blocks)) {
|
|
59
|
+
yield { list: panel.blocks, path: [...path, 'panels', i, 'blocks'] };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Walks a sanitized content document and checks the caps the schemas do not
|
|
66
|
+
* express across the whole document: slide count, blocks per slide and in
|
|
67
|
+
* total (nested container blocks count), chart points and embedded apps. It
|
|
68
|
+
* returns the first problem, or the embedded apps to validate next.
|
|
69
|
+
*/
|
|
70
|
+
export function checkContentLimits(root, kind, limits) {
|
|
71
|
+
const body = root[kind];
|
|
72
|
+
if (!isRecord(body))
|
|
73
|
+
return { issue: null, embeddedApps: [] };
|
|
74
|
+
const tooMany = (path, what, actual, max) => ({
|
|
75
|
+
issue: {
|
|
76
|
+
path,
|
|
77
|
+
message: `This ${kind} has ${actual} ${what}; the limit is ${max}.`,
|
|
78
|
+
fix: `Reduce it to at most ${max} ${what}.`,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
if (kind === 'deck' && Array.isArray(body.slides) && body.slides.length > limits.maxSlides) {
|
|
82
|
+
return tooMany([kind, 'slides'], 'slides', body.slides.length, limits.maxSlides);
|
|
83
|
+
}
|
|
84
|
+
let total = 0;
|
|
85
|
+
let chartPoints = 0;
|
|
86
|
+
const embeddedApps = [];
|
|
87
|
+
// Each block list is counted against its slide (decks) and the document.
|
|
88
|
+
const walkList = (list, path, slide) => {
|
|
89
|
+
for (const [index, value] of list.entries()) {
|
|
90
|
+
if (!isRecord(value))
|
|
91
|
+
continue;
|
|
92
|
+
const blockPath = [...path, index];
|
|
93
|
+
total += 1;
|
|
94
|
+
if (total > limits.maxBlocks) {
|
|
95
|
+
return tooMany(blockPath, 'blocks', total, limits.maxBlocks).issue;
|
|
96
|
+
}
|
|
97
|
+
if (slide) {
|
|
98
|
+
slide.count += 1;
|
|
99
|
+
if (slide.count > limits.maxBlocksPerSlide) {
|
|
100
|
+
return {
|
|
101
|
+
path: blockPath,
|
|
102
|
+
message: `A slide has more than ${limits.maxBlocksPerSlide} blocks.`,
|
|
103
|
+
fix: `Split the slide or keep it to at most ${limits.maxBlocksPerSlide} blocks.`,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if ((value.type === 'chart' || value.type === 'chart-controls') && isRecord(value.spec)) {
|
|
108
|
+
const labels = Array.isArray(value.spec.labels) ? value.spec.labels.length : 0;
|
|
109
|
+
const series = Array.isArray(value.spec.series) ? value.spec.series.length : 0;
|
|
110
|
+
chartPoints += labels * Math.max(1, series);
|
|
111
|
+
if (chartPoints > limits.maxChartPoints) {
|
|
112
|
+
return tooMany([...blockPath, 'spec'], 'chart points', chartPoints, limits.maxChartPoints)
|
|
113
|
+
.issue;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (value.type === 'embed-app') {
|
|
117
|
+
embeddedApps.push({ path: [...blockPath, 'app'], app: value.app });
|
|
118
|
+
if (embeddedApps.length > limits.maxEmbeddedApps) {
|
|
119
|
+
return tooMany(blockPath, 'embedded apps', embeddedApps.length, limits.maxEmbeddedApps)
|
|
120
|
+
.issue;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
for (const nested of blockLists(value, blockPath)) {
|
|
124
|
+
const problem = walkList(nested.list, nested.path, slide);
|
|
125
|
+
if (problem)
|
|
126
|
+
return problem;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
};
|
|
131
|
+
// A catalog `chart` slide carries its spec in props: it counts against the same
|
|
132
|
+
// document chart-point budget as chart blocks, or a deck of chart slides
|
|
133
|
+
// could ask a viewer's browser to draw far more than the limit allows.
|
|
134
|
+
if (kind === 'deck' && Array.isArray(body.slides)) {
|
|
135
|
+
for (const [i, slide] of body.slides.entries()) {
|
|
136
|
+
if (!isRecord(slide) || !isRecord(slide.props) || !isRecord(slide.props.spec))
|
|
137
|
+
continue;
|
|
138
|
+
const spec = slide.props.spec;
|
|
139
|
+
const labels = Array.isArray(spec.labels) ? spec.labels.length : 0;
|
|
140
|
+
const series = Array.isArray(spec.series) ? spec.series.length : 0;
|
|
141
|
+
chartPoints += labels * Math.max(1, series);
|
|
142
|
+
if (chartPoints > limits.maxChartPoints) {
|
|
143
|
+
return tooMany([kind, 'slides', i, 'props', 'spec'], 'chart points', chartPoints, limits.maxChartPoints);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const lists = [];
|
|
148
|
+
if (kind === 'deck' && Array.isArray(body.slides)) {
|
|
149
|
+
for (const [i, slide] of body.slides.entries()) {
|
|
150
|
+
if (isRecord(slide) && Array.isArray(slide.blocks)) {
|
|
151
|
+
lists.push({ list: slide.blocks, path: [kind, 'slides', i, 'blocks'], slide: true });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else if (kind === 'page' && Array.isArray(body.sections)) {
|
|
156
|
+
for (const [i, section] of body.sections.entries()) {
|
|
157
|
+
if (isRecord(section) && Array.isArray(section.blocks)) {
|
|
158
|
+
lists.push({ list: section.blocks, path: [kind, 'sections', i, 'blocks'], slide: false });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else if (Array.isArray(body.blocks)) {
|
|
163
|
+
lists.push({ list: body.blocks, path: [kind, 'blocks'], slide: false });
|
|
164
|
+
}
|
|
165
|
+
for (const { list, path, slide } of lists) {
|
|
166
|
+
const problem = walkList(list, path, slide ? { count: 0, path } : null);
|
|
167
|
+
if (problem)
|
|
168
|
+
return { issue: problem };
|
|
169
|
+
}
|
|
170
|
+
return { issue: null, embeddedApps };
|
|
171
|
+
}
|
|
172
|
+
/** Whether `value` holds an `embed-app` block anywhere (embedded apps may not embed again). */
|
|
173
|
+
export function containsEmbeddedApp(value) {
|
|
174
|
+
const stack = [value];
|
|
175
|
+
let seen = 0;
|
|
176
|
+
while (stack.length > 0 && seen < 100_000) {
|
|
177
|
+
const node = stack.pop();
|
|
178
|
+
seen += 1;
|
|
179
|
+
if (Array.isArray(node))
|
|
180
|
+
stack.push(...node);
|
|
181
|
+
else if (isRecord(node)) {
|
|
182
|
+
if (node.type === 'embed-app')
|
|
183
|
+
return true;
|
|
184
|
+
for (const key of Object.keys(node))
|
|
185
|
+
stack.push(node[key]);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Fail closed: a value too large to finish scanning is treated as nested.
|
|
189
|
+
return stack.length > 0;
|
|
190
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { PrototypeDefinition } from '@protoyard/core';
|
|
2
|
+
import type { DocDocument, PageDocument } from '@protoyard/pages';
|
|
3
|
+
/**
|
|
4
|
+
* Options for building a page/doc runtime from a document body alone
|
|
5
|
+
* (when the caller does not already have a full content blueprint).
|
|
6
|
+
*/
|
|
7
|
+
export interface PageDocRuntimeOptions {
|
|
8
|
+
/** Storage namespace (IndexedDB name), usually the blueprint content namespace. */
|
|
9
|
+
namespace: string;
|
|
10
|
+
/** Manifest slug; defaults to the namespace. */
|
|
11
|
+
slug?: string;
|
|
12
|
+
/** Manifest version. */
|
|
13
|
+
version?: string;
|
|
14
|
+
/** Root blueprint metadata takes precedence over the document's title and description. */
|
|
15
|
+
name?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
category?: string;
|
|
18
|
+
tags?: string[];
|
|
19
|
+
icon?: string;
|
|
20
|
+
}
|
|
21
|
+
/** Kind default scenario id (shared content-kind runtime). */
|
|
22
|
+
export declare const PAGES_DEFAULT_SCENARIO = "default";
|
|
23
|
+
/** Kind generator version (shared content-kind runtime). */
|
|
24
|
+
export declare const PAGES_GENERATOR_VERSION = 1;
|
|
25
|
+
/**
|
|
26
|
+
* Builds the shared content-kind runtime for a page document body by wrapping
|
|
27
|
+
* it as a `kind: "page"` blueprint and calling {@link defineKindPrototype}.
|
|
28
|
+
* The wrapper has no `brand` (the default theme), so it never loads brand
|
|
29
|
+
* resolution or the palette generator a seed brand needs.
|
|
30
|
+
* Lives in `@protoyard/blueprint/kinds` so `@protoyard/pages` stays free of a
|
|
31
|
+
* blueprint dependency (no package cycle).
|
|
32
|
+
*/
|
|
33
|
+
export declare function definePrototypeFromPage(page: PageDocument, options: PageDocRuntimeOptions): PrototypeDefinition;
|
|
34
|
+
/**
|
|
35
|
+
* Builds the shared content-kind runtime for a doc document body.
|
|
36
|
+
*/
|
|
37
|
+
export declare function definePrototypeFromDoc(doc: DocDocument, options: PageDocRuntimeOptions): PrototypeDefinition;
|