@cogenta/schema 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/define-collection.d.ts +8 -0
- package/dist/define-collection.d.ts.map +1 -0
- package/dist/define-collection.js +311 -0
- package/dist/define-collection.js.map +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -0
- package/dist/fields.d.ts +117 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +107 -0
- package/dist/fields.js.map +1 -0
- package/dist/generate-schema-json.d.ts +61 -0
- package/dist/generate-schema-json.d.ts.map +1 -0
- package/dist/generate-schema-json.js +128 -0
- package/dist/generate-schema-json.js.map +1 -0
- package/dist/generate-types.d.ts +5 -0
- package/dist/generate-types.d.ts.map +1 -0
- package/dist/generate-types.js +220 -0
- package/dist/generate-types.js.map +1 -0
- package/dist/id.d.ts +8 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +8 -0
- package/dist/id.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/rich-text.d.ts +164 -0
- package/dist/rich-text.d.ts.map +1 -0
- package/dist/rich-text.js +97 -0
- package/dist/rich-text.js.map +1 -0
- package/dist/routing/ids.d.ts +18 -0
- package/dist/routing/ids.d.ts.map +1 -0
- package/dist/routing/ids.js +41 -0
- package/dist/routing/ids.js.map +1 -0
- package/dist/routing/index.d.ts +13 -0
- package/dist/routing/index.d.ts.map +1 -0
- package/dist/routing/index.js +7 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/routing/redirects.d.ts +76 -0
- package/dist/routing/redirects.d.ts.map +1 -0
- package/dist/routing/redirects.js +237 -0
- package/dist/routing/redirects.js.map +1 -0
- package/dist/routing/resolve.d.ts +38 -0
- package/dist/routing/resolve.d.ts.map +1 -0
- package/dist/routing/resolve.js +23 -0
- package/dist/routing/resolve.js.map +1 -0
- package/dist/routing/router.d.ts +51 -0
- package/dist/routing/router.d.ts.map +1 -0
- package/dist/routing/router.js +132 -0
- package/dist/routing/router.js.map +1 -0
- package/dist/routing/slug-change.d.ts +39 -0
- package/dist/routing/slug-change.d.ts.map +1 -0
- package/dist/routing/slug-change.js +44 -0
- package/dist/routing/slug-change.js.map +1 -0
- package/dist/routing/slug.d.ts +82 -0
- package/dist/routing/slug.d.ts.map +1 -0
- package/dist/routing/slug.js +124 -0
- package/dist/routing/slug.js.map +1 -0
- package/dist/routing/slugify.d.ts +29 -0
- package/dist/routing/slugify.d.ts.map +1 -0
- package/dist/routing/slugify.js +104 -0
- package/dist/routing/slugify.js.map +1 -0
- package/dist/scheduling/index.d.ts +3 -0
- package/dist/scheduling/index.d.ts.map +1 -0
- package/dist/scheduling/index.js +2 -0
- package/dist/scheduling/index.js.map +1 -0
- package/dist/scheduling/publish.d.ts +71 -0
- package/dist/scheduling/publish.d.ts.map +1 -0
- package/dist/scheduling/publish.js +122 -0
- package/dist/scheduling/publish.js.map +1 -0
- package/dist/search/extract.d.ts +25 -0
- package/dist/search/extract.d.ts.map +1 -0
- package/dist/search/extract.js +188 -0
- package/dist/search/extract.js.map +1 -0
- package/dist/search/index.d.ts +36 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +44 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/mysql.d.ts +7 -0
- package/dist/search/mysql.d.ts.map +1 -0
- package/dist/search/mysql.js +121 -0
- package/dist/search/mysql.js.map +1 -0
- package/dist/search/postgres.d.ts +9 -0
- package/dist/search/postgres.d.ts.map +1 -0
- package/dist/search/postgres.js +167 -0
- package/dist/search/postgres.js.map +1 -0
- package/dist/search/query.d.ts +35 -0
- package/dist/search/query.d.ts.map +1 -0
- package/dist/search/query.js +116 -0
- package/dist/search/query.js.map +1 -0
- package/dist/search/sqlite.d.ts +16 -0
- package/dist/search/sqlite.d.ts.map +1 -0
- package/dist/search/sqlite.js +166 -0
- package/dist/search/sqlite.js.map +1 -0
- package/dist/search/table.d.ts +49 -0
- package/dist/search/table.d.ts.map +1 -0
- package/dist/search/table.js +86 -0
- package/dist/search/table.js.map +1 -0
- package/dist/search/text.d.ts +42 -0
- package/dist/search/text.d.ts.map +1 -0
- package/dist/search/text.js +56 -0
- package/dist/search/text.js.map +1 -0
- package/dist/search/types.d.ts +98 -0
- package/dist/search/types.d.ts.map +1 -0
- package/dist/search/types.js +2 -0
- package/dist/search/types.js.map +1 -0
- package/dist/store/columns.d.ts +33 -0
- package/dist/store/columns.d.ts.map +1 -0
- package/dist/store/columns.js +113 -0
- package/dist/store/columns.js.map +1 -0
- package/dist/store/cursor.d.ts +23 -0
- package/dist/store/cursor.d.ts.map +1 -0
- package/dist/store/cursor.js +36 -0
- package/dist/store/cursor.js.map +1 -0
- package/dist/store/diff.d.ts +59 -0
- package/dist/store/diff.d.ts.map +1 -0
- package/dist/store/diff.js +124 -0
- package/dist/store/diff.js.map +1 -0
- package/dist/store/fragments.d.ts +13 -0
- package/dist/store/fragments.d.ts.map +1 -0
- package/dist/store/fragments.js +25 -0
- package/dist/store/fragments.js.map +1 -0
- package/dist/store/index.d.ts +22 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +16 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/naming.d.ts +25 -0
- package/dist/store/naming.d.ts.map +1 -0
- package/dist/store/naming.js +80 -0
- package/dist/store/naming.js.map +1 -0
- package/dist/store/read-only.d.ts +16 -0
- package/dist/store/read-only.d.ts.map +1 -0
- package/dist/store/read-only.js +36 -0
- package/dist/store/read-only.js.map +1 -0
- package/dist/store/store.d.ts +52 -0
- package/dist/store/store.d.ts.map +1 -0
- package/dist/store/store.js +706 -0
- package/dist/store/store.js.map +1 -0
- package/dist/store/tables.d.ts +40 -0
- package/dist/store/tables.d.ts.map +1 -0
- package/dist/store/tables.js +267 -0
- package/dist/store/tables.js.map +1 -0
- package/dist/store/types.d.ts +105 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/types.js +2 -0
- package/dist/store/types.js.map +1 -0
- package/dist/store/uuid.d.ts +6 -0
- package/dist/store/uuid.d.ts.map +1 -0
- package/dist/store/uuid.js +64 -0
- package/dist/store/uuid.js.map +1 -0
- package/dist/store/values.d.ts +40 -0
- package/dist/store/values.d.ts.map +1 -0
- package/dist/store/values.js +160 -0
- package/dist/store/values.js.map +1 -0
- package/dist/system-fields.d.ts +60 -0
- package/dist/system-fields.d.ts.map +1 -0
- package/dist/system-fields.js +73 -0
- package/dist/system-fields.js.map +1 -0
- package/dist/types.d.ts +101 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +32 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +54 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +183 -0
- package/dist/validation.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* The rich text document, contract A § "Texte riche" and ADR-0013.
|
|
4
|
+
*
|
|
5
|
+
* A restricted Portable Text model: a list of typed blocks carrying text,
|
|
6
|
+
* semantic marks and annotations that reference site entities. No HTML, no
|
|
7
|
+
* Markdown, no editor-internal format — a stored `<div class="…">` would tie an
|
|
8
|
+
* article to one theme for good, and would have to be sanitised on every read.
|
|
9
|
+
*
|
|
10
|
+
* `h1` is deliberately absent: the page title is the only `h1`, and leaving it
|
|
11
|
+
* available in the body breaks the heading outline and accessibility with it.
|
|
12
|
+
*/
|
|
13
|
+
export declare const RICH_TEXT_STYLES: readonly ['normal', 'h2', 'h3', 'h4', 'blockquote'];
|
|
14
|
+
export type RichTextStyle = (typeof RICH_TEXT_STYLES)[number];
|
|
15
|
+
export declare const RICH_TEXT_LIST_ITEMS: readonly ['bullet', 'number'];
|
|
16
|
+
export type RichTextListItem = (typeof RICH_TEXT_LIST_ITEMS)[number];
|
|
17
|
+
/** Marks that need no definition. Anything else in `marks` is a `markDefs._key`. */
|
|
18
|
+
export declare const RICH_TEXT_DECORATORS: readonly ['strong', 'em', 'code'];
|
|
19
|
+
export type RichTextDecorator = (typeof RICH_TEXT_DECORATORS)[number];
|
|
20
|
+
declare const spanSchema: z.ZodObject<{
|
|
21
|
+
_key: z.ZodString;
|
|
22
|
+
_type: z.ZodLiteral<"span">;
|
|
23
|
+
text: z.ZodString;
|
|
24
|
+
marks: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
25
|
+
}, z.core.$strict>;
|
|
26
|
+
/**
|
|
27
|
+
* An internal link references an *entity*, not a URL. Moving or renaming the
|
|
28
|
+
* target does not break the link, and deleting the target is detectable —
|
|
29
|
+
* neither is true of a stored href.
|
|
30
|
+
*/
|
|
31
|
+
declare const markDefinitionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
32
|
+
_key: z.ZodString;
|
|
33
|
+
_type: z.ZodLiteral<"link">;
|
|
34
|
+
href: z.ZodString;
|
|
35
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
36
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
37
|
+
_key: z.ZodString;
|
|
38
|
+
_type: z.ZodLiteral<"internalLink">;
|
|
39
|
+
collection: z.ZodString;
|
|
40
|
+
id: z.ZodString;
|
|
41
|
+
}, z.core.$strict>], "_type">;
|
|
42
|
+
declare const textBlockSchema: z.ZodObject<{
|
|
43
|
+
_key: z.ZodString;
|
|
44
|
+
_type: z.ZodLiteral<"block">;
|
|
45
|
+
style: z.ZodEnum<{
|
|
46
|
+
blockquote: "blockquote";
|
|
47
|
+
h2: "h2";
|
|
48
|
+
h3: "h3";
|
|
49
|
+
h4: "h4";
|
|
50
|
+
normal: "normal";
|
|
51
|
+
}>;
|
|
52
|
+
listItem: z.ZodOptional<z.ZodEnum<{
|
|
53
|
+
bullet: "bullet";
|
|
54
|
+
number: "number";
|
|
55
|
+
}>>;
|
|
56
|
+
level: z.ZodOptional<z.ZodNumber>;
|
|
57
|
+
children: z.ZodArray<z.ZodObject<{
|
|
58
|
+
_key: z.ZodString;
|
|
59
|
+
_type: z.ZodLiteral<"span">;
|
|
60
|
+
text: z.ZodString;
|
|
61
|
+
marks: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
62
|
+
}, z.core.$strict>>;
|
|
63
|
+
markDefs: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
64
|
+
_key: z.ZodString;
|
|
65
|
+
_type: z.ZodLiteral<"link">;
|
|
66
|
+
href: z.ZodString;
|
|
67
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
68
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
69
|
+
_key: z.ZodString;
|
|
70
|
+
_type: z.ZodLiteral<"internalLink">;
|
|
71
|
+
collection: z.ZodString;
|
|
72
|
+
id: z.ZodString;
|
|
73
|
+
}, z.core.$strict>], "_type">>>;
|
|
74
|
+
}, z.core.$strict>;
|
|
75
|
+
declare const mediaNodeSchema: z.ZodObject<{
|
|
76
|
+
_key: z.ZodString;
|
|
77
|
+
_type: z.ZodLiteral<"media">;
|
|
78
|
+
id: z.ZodString;
|
|
79
|
+
caption: z.ZodOptional<z.ZodString>;
|
|
80
|
+
}, z.core.$strict>;
|
|
81
|
+
export declare const richTextNodeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
82
|
+
_key: z.ZodString;
|
|
83
|
+
_type: z.ZodLiteral<"block">;
|
|
84
|
+
style: z.ZodEnum<{
|
|
85
|
+
blockquote: "blockquote";
|
|
86
|
+
h2: "h2";
|
|
87
|
+
h3: "h3";
|
|
88
|
+
h4: "h4";
|
|
89
|
+
normal: "normal";
|
|
90
|
+
}>;
|
|
91
|
+
listItem: z.ZodOptional<z.ZodEnum<{
|
|
92
|
+
bullet: "bullet";
|
|
93
|
+
number: "number";
|
|
94
|
+
}>>;
|
|
95
|
+
level: z.ZodOptional<z.ZodNumber>;
|
|
96
|
+
children: z.ZodArray<z.ZodObject<{
|
|
97
|
+
_key: z.ZodString;
|
|
98
|
+
_type: z.ZodLiteral<"span">;
|
|
99
|
+
text: z.ZodString;
|
|
100
|
+
marks: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
101
|
+
}, z.core.$strict>>;
|
|
102
|
+
markDefs: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
103
|
+
_key: z.ZodString;
|
|
104
|
+
_type: z.ZodLiteral<"link">;
|
|
105
|
+
href: z.ZodString;
|
|
106
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
107
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
108
|
+
_key: z.ZodString;
|
|
109
|
+
_type: z.ZodLiteral<"internalLink">;
|
|
110
|
+
collection: z.ZodString;
|
|
111
|
+
id: z.ZodString;
|
|
112
|
+
}, z.core.$strict>], "_type">>>;
|
|
113
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
114
|
+
_key: z.ZodString;
|
|
115
|
+
_type: z.ZodLiteral<"media">;
|
|
116
|
+
id: z.ZodString;
|
|
117
|
+
caption: z.ZodOptional<z.ZodString>;
|
|
118
|
+
}, z.core.$strict>], "_type">;
|
|
119
|
+
export declare const richTextDocumentSchema: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
120
|
+
_key: z.ZodString;
|
|
121
|
+
_type: z.ZodLiteral<"block">;
|
|
122
|
+
style: z.ZodEnum<{
|
|
123
|
+
blockquote: "blockquote";
|
|
124
|
+
h2: "h2";
|
|
125
|
+
h3: "h3";
|
|
126
|
+
h4: "h4";
|
|
127
|
+
normal: "normal";
|
|
128
|
+
}>;
|
|
129
|
+
listItem: z.ZodOptional<z.ZodEnum<{
|
|
130
|
+
bullet: "bullet";
|
|
131
|
+
number: "number";
|
|
132
|
+
}>>;
|
|
133
|
+
level: z.ZodOptional<z.ZodNumber>;
|
|
134
|
+
children: z.ZodArray<z.ZodObject<{
|
|
135
|
+
_key: z.ZodString;
|
|
136
|
+
_type: z.ZodLiteral<"span">;
|
|
137
|
+
text: z.ZodString;
|
|
138
|
+
marks: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
139
|
+
}, z.core.$strict>>;
|
|
140
|
+
markDefs: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
141
|
+
_key: z.ZodString;
|
|
142
|
+
_type: z.ZodLiteral<"link">;
|
|
143
|
+
href: z.ZodString;
|
|
144
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
145
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
146
|
+
_key: z.ZodString;
|
|
147
|
+
_type: z.ZodLiteral<"internalLink">;
|
|
148
|
+
collection: z.ZodString;
|
|
149
|
+
id: z.ZodString;
|
|
150
|
+
}, z.core.$strict>], "_type">>>;
|
|
151
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
152
|
+
_key: z.ZodString;
|
|
153
|
+
_type: z.ZodLiteral<"media">;
|
|
154
|
+
id: z.ZodString;
|
|
155
|
+
caption: z.ZodOptional<z.ZodString>;
|
|
156
|
+
}, z.core.$strict>], "_type">>;
|
|
157
|
+
export type RichTextSpan = z.infer<typeof spanSchema>;
|
|
158
|
+
export type RichTextMarkDefinition = z.infer<typeof markDefinitionSchema>;
|
|
159
|
+
export type RichTextBlock = z.infer<typeof textBlockSchema>;
|
|
160
|
+
export type RichTextMediaNode = z.infer<typeof mediaNodeSchema>;
|
|
161
|
+
export type RichTextNode = z.infer<typeof richTextNodeSchema>;
|
|
162
|
+
export type RichTextDocument = z.infer<typeof richTextDocumentSchema>;
|
|
163
|
+
export {};
|
|
164
|
+
//# sourceMappingURL=rich-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-text.d.ts","sourceRoot":"","sources":["../src/rich-text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,gBAAgB,YAAI,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,CAAU,CAAA;AAEnF,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE7D,eAAO,MAAM,oBAAoB,YAAI,QAAQ,EAAE,QAAQ,CAAU,CAAA;AAEjE,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEpE,oFAAoF;AACpF,eAAO,MAAM,oBAAoB,YAAI,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAU,CAAA;AAErE,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAA;AAQrE,QAAA,MAAM,UAAU;;;;;kBAKd,CAAA;AAEF;;;;GAIG;AACH,QAAA,MAAM,oBAAoB;;;;;;;;;;6BAaxB,CAAA;AAEF,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBASnB,CAAA;AAEF,QAAA,MAAM,eAAe;;;;;kBAKnB,CAAA;AAEF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAAoE,CAAA;AAEnG,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BAgCjC,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA;AACrD,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA;AACzE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAC3D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAC/D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAC7D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* The rich text document, contract A § "Texte riche" and ADR-0013.
|
|
4
|
+
*
|
|
5
|
+
* A restricted Portable Text model: a list of typed blocks carrying text,
|
|
6
|
+
* semantic marks and annotations that reference site entities. No HTML, no
|
|
7
|
+
* Markdown, no editor-internal format — a stored `<div class="…">` would tie an
|
|
8
|
+
* article to one theme for good, and would have to be sanitised on every read.
|
|
9
|
+
*
|
|
10
|
+
* `h1` is deliberately absent: the page title is the only `h1`, and leaving it
|
|
11
|
+
* available in the body breaks the heading outline and accessibility with it.
|
|
12
|
+
*/
|
|
13
|
+
export const RICH_TEXT_STYLES = ['normal', 'h2', 'h3', 'h4', 'blockquote'];
|
|
14
|
+
export const RICH_TEXT_LIST_ITEMS = ['bullet', 'number'];
|
|
15
|
+
/** Marks that need no definition. Anything else in `marks` is a `markDefs._key`. */
|
|
16
|
+
export const RICH_TEXT_DECORATORS = ['strong', 'em', 'code'];
|
|
17
|
+
/**
|
|
18
|
+
* Stable across edits: diffs, comments and anchors are all keyed by it. A key
|
|
19
|
+
* that changes on every save makes a per-block comment thread impossible.
|
|
20
|
+
*/
|
|
21
|
+
const keySchema = z.string().min(1);
|
|
22
|
+
const spanSchema = z.strictObject({
|
|
23
|
+
_key: keySchema,
|
|
24
|
+
_type: z.literal('span'),
|
|
25
|
+
text: z.string(),
|
|
26
|
+
marks: z.array(z.string().min(1)).default([]),
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* An internal link references an *entity*, not a URL. Moving or renaming the
|
|
30
|
+
* target does not break the link, and deleting the target is detectable —
|
|
31
|
+
* neither is true of a stored href.
|
|
32
|
+
*/
|
|
33
|
+
const markDefinitionSchema = z.discriminatedUnion('_type', [
|
|
34
|
+
z.strictObject({
|
|
35
|
+
_key: keySchema,
|
|
36
|
+
_type: z.literal('link'),
|
|
37
|
+
href: z.string().min(1),
|
|
38
|
+
rel: z.string().optional(),
|
|
39
|
+
}),
|
|
40
|
+
z.strictObject({
|
|
41
|
+
_key: keySchema,
|
|
42
|
+
_type: z.literal('internalLink'),
|
|
43
|
+
collection: z.string().min(1),
|
|
44
|
+
id: z.string().min(1),
|
|
45
|
+
}),
|
|
46
|
+
]);
|
|
47
|
+
const textBlockSchema = z.strictObject({
|
|
48
|
+
_key: keySchema,
|
|
49
|
+
_type: z.literal('block'),
|
|
50
|
+
style: z.enum(RICH_TEXT_STYLES),
|
|
51
|
+
listItem: z.enum(RICH_TEXT_LIST_ITEMS).optional(),
|
|
52
|
+
/** List nesting, from 1. Only meaningful together with `listItem`. */
|
|
53
|
+
level: z.number().int().min(1).optional(),
|
|
54
|
+
children: z.array(spanSchema),
|
|
55
|
+
markDefs: z.array(markDefinitionSchema).default([]),
|
|
56
|
+
});
|
|
57
|
+
const mediaNodeSchema = z.strictObject({
|
|
58
|
+
_key: keySchema,
|
|
59
|
+
_type: z.literal('media'),
|
|
60
|
+
id: z.string().min(1),
|
|
61
|
+
caption: z.string().optional(),
|
|
62
|
+
});
|
|
63
|
+
export const richTextNodeSchema = z.discriminatedUnion('_type', [textBlockSchema, mediaNodeSchema]);
|
|
64
|
+
export const richTextDocumentSchema = z.array(richTextNodeSchema).superRefine((nodes, context) => {
|
|
65
|
+
// Two nodes sharing a key silently break every consumer that addresses a
|
|
66
|
+
// node by key: comments land on the wrong paragraph, diffs pair the wrong
|
|
67
|
+
// blocks. Cheaper to reject on write than to untangle later.
|
|
68
|
+
const seen = new Set();
|
|
69
|
+
for (const [index, node] of nodes.entries()) {
|
|
70
|
+
if (seen.has(node._key)) {
|
|
71
|
+
context.addIssue({
|
|
72
|
+
code: 'custom',
|
|
73
|
+
message: `duplicate _key "${node._key}"`,
|
|
74
|
+
path: [index, '_key'],
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
seen.add(node._key);
|
|
78
|
+
}
|
|
79
|
+
for (const [index, node] of nodes.entries()) {
|
|
80
|
+
if (node._type !== 'block')
|
|
81
|
+
continue;
|
|
82
|
+
const defined = new Set(node.markDefs.map((definition) => definition._key));
|
|
83
|
+
for (const [childIndex, child] of node.children.entries()) {
|
|
84
|
+
for (const mark of child.marks) {
|
|
85
|
+
const isDecorator = RICH_TEXT_DECORATORS.includes(mark);
|
|
86
|
+
if (!isDecorator && !defined.has(mark)) {
|
|
87
|
+
context.addIssue({
|
|
88
|
+
code: 'custom',
|
|
89
|
+
message: `mark "${mark}" is neither a decorator nor a markDefs key`,
|
|
90
|
+
path: [index, 'children', childIndex, 'marks'],
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=rich-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-text.js","sourceRoot":"","sources":["../src/rich-text.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UUIDv7, generated by the application (ADR-0015).
|
|
3
|
+
*
|
|
4
|
+
* `node:crypto` ships `randomUUID` for v4 only, and v4 is exactly what ADR-0015
|
|
5
|
+
* rules out: random keys fragment a B-tree on insert, which degrades writes as
|
|
6
|
+
* the table grows. v7 puts a 48-bit millisecond timestamp first, so new rows
|
|
7
|
+
* land at the end of the index.
|
|
8
|
+
*
|
|
9
|
+
* Layout, per RFC 9562 §5.7:
|
|
10
|
+
*
|
|
11
|
+
* 0 1 2 3
|
|
12
|
+
* | unix_ts_ms (48 bits) | ver | rand_a | var | rand_b |
|
|
13
|
+
*
|
|
14
|
+
* Same-millisecond ordering is not guaranteed and is not needed: nothing here
|
|
15
|
+
* sorts by identifier for correctness, only for index locality.
|
|
16
|
+
*/
|
|
17
|
+
export declare function uuidv7(): string;
|
|
18
|
+
//# sourceMappingURL=ids.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/routing/ids.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,MAAM,IAAI,MAAM,CA0B/B"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { randomFillSync } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* UUIDv7, generated by the application (ADR-0015).
|
|
4
|
+
*
|
|
5
|
+
* `node:crypto` ships `randomUUID` for v4 only, and v4 is exactly what ADR-0015
|
|
6
|
+
* rules out: random keys fragment a B-tree on insert, which degrades writes as
|
|
7
|
+
* the table grows. v7 puts a 48-bit millisecond timestamp first, so new rows
|
|
8
|
+
* land at the end of the index.
|
|
9
|
+
*
|
|
10
|
+
* Layout, per RFC 9562 §5.7:
|
|
11
|
+
*
|
|
12
|
+
* 0 1 2 3
|
|
13
|
+
* | unix_ts_ms (48 bits) | ver | rand_a | var | rand_b |
|
|
14
|
+
*
|
|
15
|
+
* Same-millisecond ordering is not guaranteed and is not needed: nothing here
|
|
16
|
+
* sorts by identifier for correctness, only for index locality.
|
|
17
|
+
*/
|
|
18
|
+
export function uuidv7() {
|
|
19
|
+
const bytes = new Uint8Array(16);
|
|
20
|
+
randomFillSync(bytes);
|
|
21
|
+
const milliseconds = Date.now();
|
|
22
|
+
// Big-endian 48-bit timestamp. `Math.floor(ms / 2 ** 32)` rather than a shift:
|
|
23
|
+
// bitwise operators in JavaScript truncate to 32 bits and would drop the top.
|
|
24
|
+
bytes[0] = Math.floor(milliseconds / 2 ** 40) & 0xff;
|
|
25
|
+
bytes[1] = Math.floor(milliseconds / 2 ** 32) & 0xff;
|
|
26
|
+
bytes[2] = Math.floor(milliseconds / 2 ** 24) & 0xff;
|
|
27
|
+
bytes[3] = Math.floor(milliseconds / 2 ** 16) & 0xff;
|
|
28
|
+
bytes[4] = Math.floor(milliseconds / 2 ** 8) & 0xff;
|
|
29
|
+
bytes[5] = milliseconds & 0xff;
|
|
30
|
+
bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x70; // version 7
|
|
31
|
+
bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80; // variant 10
|
|
32
|
+
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
33
|
+
return [
|
|
34
|
+
hex.slice(0, 8),
|
|
35
|
+
hex.slice(8, 12),
|
|
36
|
+
hex.slice(12, 16),
|
|
37
|
+
hex.slice(16, 20),
|
|
38
|
+
hex.slice(20, 32),
|
|
39
|
+
].join('-');
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=ids.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/routing/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE5C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,MAAM;IACpB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;IAChC,cAAc,CAAC,KAAK,CAAC,CAAA;IAErB,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC/B,+EAA+E;IAC/E,8EAA8E;IAC9E,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACpD,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACpD,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACpD,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACpD,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAA;IACnD,KAAK,CAAC,CAAC,CAAC,GAAG,YAAY,GAAG,IAAI,CAAA;IAE9B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA,CAAC,YAAY;IACvD,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA,CAAC,aAAa;IAExD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAEpF,OAAO;QACL,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAChB,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;QACjB,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;QACjB,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;KAClB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type { AddRedirectInput, ListRedirectsOptions, RedirectReason, RedirectRecord, RedirectResolution, RedirectStatus, RedirectStore, RedirectStoreOptions, } from './redirects.js';
|
|
2
|
+
export { createRedirectStore, REDIRECT_REASONS, REDIRECTS_TABLE } from './redirects.js';
|
|
3
|
+
export type { EntryLookup, ResolveUrlOptions, UrlResolution } from './resolve.js';
|
|
4
|
+
export { resolveUrl } from './resolve.js';
|
|
5
|
+
export type { RouteMatch, RouteOptions } from './router.js';
|
|
6
|
+
export { buildPath, matchPath, normalisePath } from './router.js';
|
|
7
|
+
export type { DeriveSlugInput, SlugScope, SlugTakenCheck, SqlSlugScope, UniqueSlugOptions, } from './slug.js';
|
|
8
|
+
export { deriveSlug, slugSourceField, sqlSlugTaken, uniqueSlug } from './slug.js';
|
|
9
|
+
export type { SlugChange } from './slug-change.js';
|
|
10
|
+
export { recordSlugChange } from './slug-change.js';
|
|
11
|
+
export type { SlugifyOptions } from './slugify.js';
|
|
12
|
+
export { DEFAULT_SLUG_MAX_LENGTH, isSlug, slugify, slugifyOrThrow } from './slugify.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,oBAAoB,GACrB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACvF,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACjE,YAAY,EACV,eAAe,EACf,SAAS,EACT,cAAc,EACd,YAAY,EACZ,iBAAiB,GAClB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACjF,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createRedirectStore, REDIRECT_REASONS, REDIRECTS_TABLE } from './redirects.js';
|
|
2
|
+
export { resolveUrl } from './resolve.js';
|
|
3
|
+
export { buildPath, matchPath, normalisePath } from './router.js';
|
|
4
|
+
export { deriveSlug, slugSourceField, sqlSlugTaken, uniqueSlug } from './slug.js';
|
|
5
|
+
export { recordSlugChange } from './slug-change.js';
|
|
6
|
+
export { DEFAULT_SLUG_MAX_LENGTH, isSlug, slugify, slugifyOrThrow } from './slugify.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAEvF,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAQjE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAEnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type DatabaseHandle } from '@cogenta/core';
|
|
2
|
+
/**
|
|
3
|
+
* The redirect table.
|
|
4
|
+
*
|
|
5
|
+
* L1 calls unresolved redirects "a daily nuisance that WordPress and Drupal do
|
|
6
|
+
* not solve" and asks that this work without anyone thinking about it. Two
|
|
7
|
+
* things make that true, and both are enforced here rather than left to callers:
|
|
8
|
+
*
|
|
9
|
+
* - **Chains are flattened.** When A already points at B and B starts pointing
|
|
10
|
+
* at C, the row for A is rewritten to C. Otherwise every rename adds a hop,
|
|
11
|
+
* and a page renamed five times costs a visitor five round trips.
|
|
12
|
+
* - **Loops are refused.** A→B→A serves nothing but an infinite redirect, so it
|
|
13
|
+
* is rejected at write time, where there is still a human to tell.
|
|
14
|
+
*/
|
|
15
|
+
export declare const REDIRECTS_TABLE = "cogenta_redirects";
|
|
16
|
+
export declare const REDIRECT_REASONS: readonly ['slug-change', 'manual', 'import'];
|
|
17
|
+
export type RedirectReason = (typeof REDIRECT_REASONS)[number];
|
|
18
|
+
/** 308 and 307 are deliberately absent: a moved page is a GET, and 301 is what search engines act on. */
|
|
19
|
+
export type RedirectStatus = 301 | 302;
|
|
20
|
+
export interface RedirectRecord {
|
|
21
|
+
readonly id: string;
|
|
22
|
+
readonly from: string;
|
|
23
|
+
readonly to: string;
|
|
24
|
+
readonly status: RedirectStatus;
|
|
25
|
+
readonly collection: string | null;
|
|
26
|
+
readonly entryId: string | null;
|
|
27
|
+
readonly locale: string | null;
|
|
28
|
+
readonly reason: RedirectReason;
|
|
29
|
+
/** Epoch milliseconds. */
|
|
30
|
+
readonly createdAt: number;
|
|
31
|
+
}
|
|
32
|
+
export interface AddRedirectInput {
|
|
33
|
+
readonly from: string;
|
|
34
|
+
readonly to: string;
|
|
35
|
+
readonly status?: RedirectStatus;
|
|
36
|
+
readonly collection?: string;
|
|
37
|
+
readonly entryId?: string;
|
|
38
|
+
readonly locale?: string;
|
|
39
|
+
readonly reason?: RedirectReason;
|
|
40
|
+
}
|
|
41
|
+
export interface ListRedirectsOptions {
|
|
42
|
+
readonly limit?: number;
|
|
43
|
+
readonly collection?: string;
|
|
44
|
+
readonly locale?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface RedirectResolution {
|
|
47
|
+
readonly to: string;
|
|
48
|
+
readonly status: RedirectStatus;
|
|
49
|
+
}
|
|
50
|
+
export interface RedirectStore {
|
|
51
|
+
/** Creates the table if it is missing. Called for you by every other method. */
|
|
52
|
+
ensureTable(): Promise<void>;
|
|
53
|
+
add(input: AddRedirectInput): Promise<RedirectRecord>;
|
|
54
|
+
/** The final destination of a path, following any chain left by an import. */
|
|
55
|
+
resolve(path: string): Promise<RedirectResolution | null>;
|
|
56
|
+
list(options?: ListRedirectsOptions): Promise<RedirectRecord[]>;
|
|
57
|
+
remove(from: string): Promise<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* Drops any redirect leaving `path`, because real content serves it again.
|
|
60
|
+
*
|
|
61
|
+
* The counterpart of `add`'s loop refusal: moving a page back to its old URL
|
|
62
|
+
* is legitimate, and it is this call — not a silently repaired cycle — that
|
|
63
|
+
* expresses it.
|
|
64
|
+
*/
|
|
65
|
+
release(path: string): Promise<boolean>;
|
|
66
|
+
}
|
|
67
|
+
export interface RedirectStoreOptions {
|
|
68
|
+
readonly db: DatabaseHandle;
|
|
69
|
+
/** Injected so the tests do not have to wait for a clock. */
|
|
70
|
+
readonly now?: () => number;
|
|
71
|
+
/** Injected so a test can assert on identifiers. Defaults to UUIDv7 (ADR-0015). */
|
|
72
|
+
readonly newId?: () => string;
|
|
73
|
+
readonly table?: string;
|
|
74
|
+
}
|
|
75
|
+
export declare function createRedirectStore(options: RedirectStoreOptions): RedirectStore;
|
|
76
|
+
//# sourceMappingURL=redirects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redirects.d.ts","sourceRoot":"","sources":["../../src/routing/redirects.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAKpB,MAAM,eAAe,CAAA;AAItB;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,eAAe,sBAAsB,CAAA;AAoBlD,eAAO,MAAM,gBAAgB,YAAI,aAAa,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAA;AAE5E,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE9D,yGAAyG;AACzG,MAAM,MAAM,cAAc,GAAG,GAAG,GAAG,GAAG,CAAA;AAEtC,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,0BAA0B;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAA;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAA;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5B,GAAG,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;IACrD,8EAA8E;IAC9E,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAA;IACzD,IAAI,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAA;IAC/D,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACtC;;;;;;OAMG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACxC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAA;IAC3B,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAA;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB;AAcD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAgOhF"}
|