@sigrun/sigrun 0.1.4 → 0.1.6
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/CHANGELOG.md +61 -0
- package/README.md +24 -2
- package/THIRD_PARTY_NOTICES.md +23 -0
- package/dist/blocks/builders.js +125 -0
- package/dist/blocks/images.js +57 -0
- package/dist/blocks/index.js +20 -0
- package/dist/blocks/limits.js +26 -0
- package/dist/blocks/placements.js +99 -0
- package/dist/blocks/schema.js +559 -0
- package/dist/blocks/validate.js +602 -0
- package/dist/config.js +31 -0
- package/dist/extension.d.ts +476 -9
- package/dist/harness/agent-env.js +62 -0
- package/dist/harness/boot.js +8 -1
- package/dist/harness/event-bus.js +33 -0
- package/dist/harness/identity/users.js +3 -2
- package/dist/harness/loader.js +369 -13
- package/dist/harness/packages.js +71 -2
- package/dist/harness/seam-host.js +69 -2
- package/dist/harness/settings.js +5 -0
- package/dist/harness/workspace.js +6 -4
- package/dist/jobs/fire.js +11 -0
- package/dist/jobs/spec.js +19 -0
- package/dist/serve.js +29 -39
- package/dist/server/auth/pipeline.js +16 -1
- package/dist/server/conversation-ops.js +482 -10
- package/dist/server/gateway.js +122 -0
- package/dist/server/helpers.js +26 -0
- package/dist/server/host-bridge.js +141 -4
- package/dist/server/index.js +27 -0
- package/dist/server/notifications.js +6 -2
- package/dist/server/routes/conversations.js +37 -93
- package/dist/server/routes/events.js +39 -0
- package/dist/server/routes/ext-assets.js +84 -0
- package/dist/server/routes/extensions.js +31 -1
- package/dist/server/routes/files.js +38 -83
- package/dist/server/routes/meta.js +35 -1
- package/dist/server/routes/providers.js +5 -21
- package/dist/server/routes/submissions.js +36 -111
- package/dist/server/routes/surfaces.js +387 -0
- package/dist/server/routes/users.js +6 -1
- package/dist/server/session-meta.js +12 -6
- package/dist/server/shutdown.js +85 -0
- package/dist/server/surfaces/access-cache.js +43 -0
- package/dist/server/surfaces/dedup.js +67 -0
- package/dist/server/surfaces/instance.js +42 -0
- package/dist/server/surfaces/mime.js +73 -0
- package/dist/server/surfaces/rate-limit.js +63 -0
- package/dist/server/surfaces/service.js +493 -0
- package/dist/server/surfaces/watchers.js +94 -0
- package/node_modules/@sigrun/shared/CHANGELOG.md +9 -0
- package/node_modules/@sigrun/shared/dist/blocks/format.d.ts +28 -0
- package/node_modules/@sigrun/shared/dist/blocks/format.js +199 -0
- package/node_modules/@sigrun/shared/dist/blocks/icons.d.ts +12 -0
- package/node_modules/@sigrun/shared/dist/blocks/icons.js +64 -0
- package/node_modules/@sigrun/shared/dist/blocks/index.d.ts +25 -0
- package/node_modules/@sigrun/shared/dist/blocks/index.js +21 -0
- package/node_modules/@sigrun/shared/dist/blocks/instance.d.ts +29 -0
- package/node_modules/@sigrun/shared/dist/blocks/instance.js +51 -0
- package/node_modules/@sigrun/shared/dist/blocks/lttb.d.ts +16 -0
- package/node_modules/@sigrun/shared/dist/blocks/lttb.js +67 -0
- package/node_modules/@sigrun/shared/dist/blocks/ops.d.ts +44 -0
- package/node_modules/@sigrun/shared/dist/blocks/ops.js +294 -0
- package/node_modules/@sigrun/shared/dist/blocks/text.d.ts +43 -0
- package/node_modules/@sigrun/shared/dist/blocks/text.js +790 -0
- package/node_modules/@sigrun/shared/dist/blocks/transport.d.ts +77 -0
- package/node_modules/@sigrun/shared/dist/blocks/transport.js +11 -0
- package/node_modules/@sigrun/shared/dist/blocks/types.d.ts +541 -0
- package/node_modules/@sigrun/shared/dist/blocks/types.js +17 -0
- package/node_modules/@sigrun/shared/dist/jobs.d.ts +9 -0
- package/node_modules/@sigrun/shared/dist/live.d.ts +71 -0
- package/node_modules/@sigrun/shared/dist/live.js +82 -0
- package/node_modules/@sigrun/shared/dist/session-meta.d.ts +19 -3
- package/node_modules/@sigrun/shared/dist/settings.d.ts +7 -0
- package/node_modules/@sigrun/shared/dist/views.d.ts +81 -3
- package/node_modules/@sigrun/shared/package.json +10 -2
- package/package.json +11 -5
- package/webui/dist/assets/index-CiYInlLx.css +1 -0
- package/webui/dist/assets/index-JDfOQV9z.js +52 -0
- package/webui/dist/index.html +2 -2
- package/webui/dist/assets/index-BiSMljer.css +0 -1
- package/webui/dist/assets/index-hVLvsizV.js +0 -50
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The typebox wire schemas for every block and field (spec §5/§6.1),
|
|
3
|
+
* each compiled once into its own `Validator` (spec §14.2 validation).
|
|
4
|
+
*
|
|
5
|
+
* Design notes:
|
|
6
|
+
* - Schemas are the wire contract, so they deliberately do NOT set
|
|
7
|
+
* `additionalProperties: false`: unknown props pass through and
|
|
8
|
+
* channels ignore them (the block-set version governs what exists).
|
|
9
|
+
* - `Tone`, `IconName` and `Format` are enums/patterns built from the
|
|
10
|
+
* shared constants; an unknown icon name fails here, at the icon
|
|
11
|
+
* prop's own path.
|
|
12
|
+
* - Bindable props are `Union([literal, Binding])` throughout; the
|
|
13
|
+
* literal-ness of STRUCTURAL props (`display`, `groups`, `reorder`,
|
|
14
|
+
* `mode`, field `name`s, `columns`, handler names) is enforced by the
|
|
15
|
+
* second walk in `validate.ts`, not the schema, so the error can say
|
|
16
|
+
* "must be a literal" instead of an anyOf mismatch.
|
|
17
|
+
* - Child slots (`children`, `sidebar`, `main`, `detail`,
|
|
18
|
+
* `columns[].block`, `collection.item`, `form` children, a field's
|
|
19
|
+
* `list.item`, `page.switcher`, a bulk action's `form.root`) are
|
|
20
|
+
* deliberately loose here (any object): `validate.ts` walks the tree
|
|
21
|
+
* and validates every child node against ITS compiled validator, so
|
|
22
|
+
* one broken block is one precise error instead of a union mismatch
|
|
23
|
+
* per sibling branch.
|
|
24
|
+
* - `Compile` (typebox/compile) builds each validator; its errors are
|
|
25
|
+
* read from `instancePath`, relative to the node the validator ran
|
|
26
|
+
* against.
|
|
27
|
+
*/
|
|
28
|
+
import { Compile } from "typebox/compile";
|
|
29
|
+
import { Type } from "typebox";
|
|
30
|
+
import { ICON_NAMES } from "@sigrun/shared/blocks";
|
|
31
|
+
// ─── atoms ────────────────────────────────────────────────────────────────
|
|
32
|
+
/** Any JSON value (spec: null, boolean, number, string, array, object). */
|
|
33
|
+
const JsonValue = Type.Unsafe({
|
|
34
|
+
anyOf: [
|
|
35
|
+
{ type: "null" },
|
|
36
|
+
{ type: "boolean" },
|
|
37
|
+
{ type: "number" },
|
|
38
|
+
{ type: "string" },
|
|
39
|
+
{ type: "array", items: { $ref: "JsonValue" } },
|
|
40
|
+
{ type: "object" },
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
/** A JSON Pointer binding into the data model (spec §4.2). */
|
|
44
|
+
const Binding = Type.Object({ $: Type.String() });
|
|
45
|
+
/** Meaning-based tones (spec §10.1). */
|
|
46
|
+
const Tone = Type.Unsafe({
|
|
47
|
+
type: "string",
|
|
48
|
+
enum: ["neutral", "accent", "good", "warn", "bad", "info"],
|
|
49
|
+
});
|
|
50
|
+
/** Icons: the closed 49-name set (spec §10.2). */
|
|
51
|
+
const IconName = Type.Unsafe({ type: "string", enum: ICON_NAMES });
|
|
52
|
+
/** Width tokens `s`/`m`/`l`. */
|
|
53
|
+
const Size = Type.Unsafe({ type: "string", enum: ["s", "m", "l"] });
|
|
54
|
+
/** The one width condition with a case (spec §12.2). */
|
|
55
|
+
const WidthCondition = Type.Unsafe({ type: "string", enum: ["atLeast:regular"] });
|
|
56
|
+
/** The v1 format set (spec §5.3), including `currency:<ISO 4217>`. */
|
|
57
|
+
const Format = Type.Unsafe({
|
|
58
|
+
anyOf: [
|
|
59
|
+
{
|
|
60
|
+
type: "string",
|
|
61
|
+
enum: [
|
|
62
|
+
"number",
|
|
63
|
+
"compact",
|
|
64
|
+
"percent",
|
|
65
|
+
"bytes",
|
|
66
|
+
"duration",
|
|
67
|
+
"datetime",
|
|
68
|
+
"date",
|
|
69
|
+
"time",
|
|
70
|
+
"relative",
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
{ type: "string", pattern: "^currency:[A-Za-z]{3}$" },
|
|
74
|
+
],
|
|
75
|
+
});
|
|
76
|
+
/** `T | Binding` unions for bindable props (referenced by name). */
|
|
77
|
+
const BindableString = Type.Union([Type.String(), Type.Ref("Binding")]);
|
|
78
|
+
const BindableNumber = Type.Union([Type.Number(), Type.Ref("Binding")]);
|
|
79
|
+
const BindableBoolean = Type.Union([Type.Boolean(), Type.Ref("Binding")]);
|
|
80
|
+
const BindableJsonValue = Type.Union([Type.Ref("JsonValue"), Type.Ref("Binding")]);
|
|
81
|
+
const BindableTone = Type.Union([Type.Ref("Tone"), Type.Ref("Binding")]);
|
|
82
|
+
const BindableIcon = Type.Union([Type.Ref("IconName"), Type.Ref("Binding")]);
|
|
83
|
+
/** Any object: the loose child slots (validated by the walk, not here). */
|
|
84
|
+
const AnyObject = Type.Object({}, { additionalProperties: true });
|
|
85
|
+
/** Props every block may carry (spec §4.1). */
|
|
86
|
+
const BlockBase = {
|
|
87
|
+
id: Type.Optional(Type.String()),
|
|
88
|
+
visibleAt: Type.Optional(WidthCondition),
|
|
89
|
+
fallback: Type.Optional(Type.String()),
|
|
90
|
+
};
|
|
91
|
+
// ─── actions (spec §6.1, verbatim) ────────────────────────────────────────
|
|
92
|
+
const CoreTarget = Type.Union([
|
|
93
|
+
Type.Object({ conversation: Type.Integer() }),
|
|
94
|
+
Type.Object({ job: Type.String() }),
|
|
95
|
+
Type.Object({ settings: Type.String() }),
|
|
96
|
+
Type.Object({
|
|
97
|
+
view: Type.Object({
|
|
98
|
+
extension: Type.String(),
|
|
99
|
+
id: Type.String(),
|
|
100
|
+
params: Type.Optional(Type.Object({}, { additionalProperties: true })),
|
|
101
|
+
}),
|
|
102
|
+
}),
|
|
103
|
+
]);
|
|
104
|
+
const Confirm = Type.Object({
|
|
105
|
+
title: Type.String(),
|
|
106
|
+
body: Type.Optional(Type.String()),
|
|
107
|
+
tone: Type.Optional(Type.Unsafe({ type: "string", enum: ["bad", "warn"] })),
|
|
108
|
+
confirmLabel: Type.Optional(Type.String()),
|
|
109
|
+
});
|
|
110
|
+
const Action = Type.Union([
|
|
111
|
+
Type.Object({
|
|
112
|
+
type: Type.Literal("submit"),
|
|
113
|
+
name: Type.String(),
|
|
114
|
+
turn: Type.Optional(Type.Boolean()),
|
|
115
|
+
confirm: Type.Optional(Type.Ref("Confirm")),
|
|
116
|
+
}),
|
|
117
|
+
Type.Object({
|
|
118
|
+
type: Type.Literal("navigate"),
|
|
119
|
+
params: Type.Optional(Type.Object({}, { additionalProperties: true })),
|
|
120
|
+
target: Type.Optional(Type.Ref("CoreTarget")),
|
|
121
|
+
}),
|
|
122
|
+
Type.Object({
|
|
123
|
+
type: Type.Literal("move"),
|
|
124
|
+
name: Type.String(),
|
|
125
|
+
turn: Type.Optional(Type.Boolean()),
|
|
126
|
+
}),
|
|
127
|
+
Type.Object({
|
|
128
|
+
type: Type.Literal("edit"),
|
|
129
|
+
name: Type.String(),
|
|
130
|
+
turn: Type.Optional(Type.Boolean()),
|
|
131
|
+
}),
|
|
132
|
+
Type.Object({ type: Type.Literal("open"), url: Type.String() }),
|
|
133
|
+
Type.Object({
|
|
134
|
+
type: Type.Literal("copy"),
|
|
135
|
+
text: Type.Union([Type.String(), Type.Ref("Binding")]),
|
|
136
|
+
}),
|
|
137
|
+
Type.Object({ type: Type.Literal("restart"), confirm: Type.Optional(Type.Ref("Confirm")) }),
|
|
138
|
+
]);
|
|
139
|
+
/** A block-offered button (spec §6.1). */
|
|
140
|
+
const ActionButton = Type.Object({
|
|
141
|
+
id: Type.String(),
|
|
142
|
+
label: BindableString,
|
|
143
|
+
icon: Type.Optional(Type.Ref("IconName")),
|
|
144
|
+
action: Type.Ref("Action"),
|
|
145
|
+
});
|
|
146
|
+
// ─── field fragments (spec §5.6) ──────────────────────────────────────────
|
|
147
|
+
/** The props every field type shares (spec §5.6). */
|
|
148
|
+
const FieldBase = {
|
|
149
|
+
name: Type.String(),
|
|
150
|
+
label: BindableString,
|
|
151
|
+
help: Type.Optional(BindableString),
|
|
152
|
+
placeholder: Type.Optional(BindableString),
|
|
153
|
+
required: Type.Optional(Type.Boolean()),
|
|
154
|
+
disabled: Type.Optional(Type.Boolean()),
|
|
155
|
+
/** §13; settings only. */
|
|
156
|
+
apply: Type.Optional(Type.Unsafe({ type: "string", enum: ["live", "restart"] })),
|
|
157
|
+
min: Type.Optional(Type.Number()),
|
|
158
|
+
max: Type.Optional(Type.Number()),
|
|
159
|
+
minLength: Type.Optional(Type.Integer()),
|
|
160
|
+
maxLength: Type.Optional(Type.Integer()),
|
|
161
|
+
pattern: Type.Optional(Type.String()),
|
|
162
|
+
};
|
|
163
|
+
/** A `choice` option (spec §5.6). */
|
|
164
|
+
const ChoiceOption = Type.Object({
|
|
165
|
+
id: Type.String(),
|
|
166
|
+
label: BindableString,
|
|
167
|
+
description: Type.Optional(BindableString),
|
|
168
|
+
tone: Type.Optional(Type.Ref("Tone")),
|
|
169
|
+
recommended: Type.Optional(Type.Boolean()),
|
|
170
|
+
preview: Type.Optional(Type.String()),
|
|
171
|
+
});
|
|
172
|
+
// ─── block schemas (spec §5.1–5.5); child slots are loose ─────────────────
|
|
173
|
+
const PageBlock = Type.Object({
|
|
174
|
+
...BlockBase,
|
|
175
|
+
type: Type.Literal("page"),
|
|
176
|
+
title: BindableString,
|
|
177
|
+
subtitle: Type.Optional(BindableString),
|
|
178
|
+
switcher: Type.Optional(AnyObject),
|
|
179
|
+
actions: Type.Optional(Type.Array(Type.Ref("ActionButton"))),
|
|
180
|
+
sidebar: Type.Optional(Type.Array(AnyObject)),
|
|
181
|
+
main: Type.Array(AnyObject),
|
|
182
|
+
detail: Type.Optional(Type.Array(AnyObject)),
|
|
183
|
+
empty: Type.Optional(Type.Object({
|
|
184
|
+
icon: Type.Ref("IconName"),
|
|
185
|
+
title: Type.String(),
|
|
186
|
+
hint: Type.Optional(Type.String()),
|
|
187
|
+
})),
|
|
188
|
+
});
|
|
189
|
+
const StackBlock = Type.Object({
|
|
190
|
+
...BlockBase,
|
|
191
|
+
type: Type.Literal("stack"),
|
|
192
|
+
children: Type.Array(AnyObject),
|
|
193
|
+
gap: Type.Optional(Size),
|
|
194
|
+
});
|
|
195
|
+
const ColumnsBlock = Type.Object({
|
|
196
|
+
...BlockBase,
|
|
197
|
+
type: Type.Literal("columns"),
|
|
198
|
+
children: Type.Array(Type.Object({
|
|
199
|
+
weight: Type.Optional(Type.Number()),
|
|
200
|
+
minWidth: Type.Optional(Size),
|
|
201
|
+
block: AnyObject,
|
|
202
|
+
})),
|
|
203
|
+
});
|
|
204
|
+
const GridBlock = Type.Object({
|
|
205
|
+
...BlockBase,
|
|
206
|
+
type: Type.Literal("grid"),
|
|
207
|
+
minItemWidth: Size,
|
|
208
|
+
children: Type.Array(Type.Object({
|
|
209
|
+
span: Type.Optional(Type.Unsafe({ type: ["integer", "string"], enum: [1, 2, "full"] })),
|
|
210
|
+
block: AnyObject,
|
|
211
|
+
})),
|
|
212
|
+
});
|
|
213
|
+
const SectionBlock = Type.Object({
|
|
214
|
+
...BlockBase,
|
|
215
|
+
type: Type.Literal("section"),
|
|
216
|
+
title: Type.Optional(BindableString),
|
|
217
|
+
subtitle: Type.Optional(BindableString),
|
|
218
|
+
tone: Type.Optional(BindableTone),
|
|
219
|
+
collapsible: Type.Optional(Type.Boolean()),
|
|
220
|
+
collapsed: Type.Optional(Type.Boolean()),
|
|
221
|
+
children: Type.Array(AnyObject),
|
|
222
|
+
});
|
|
223
|
+
const MarkdownBlock = Type.Object({
|
|
224
|
+
...BlockBase,
|
|
225
|
+
type: Type.Literal("markdown"),
|
|
226
|
+
text: BindableString,
|
|
227
|
+
});
|
|
228
|
+
const FieldsRow = Type.Object({
|
|
229
|
+
label: BindableString,
|
|
230
|
+
value: BindableJsonValue,
|
|
231
|
+
tone: Type.Optional(BindableTone),
|
|
232
|
+
icon: Type.Optional(BindableIcon),
|
|
233
|
+
});
|
|
234
|
+
const FieldsBlock = Type.Object({
|
|
235
|
+
...BlockBase,
|
|
236
|
+
type: Type.Literal("fields"),
|
|
237
|
+
rows: Type.Union([Type.Array(FieldsRow), Type.Ref("Binding")]),
|
|
238
|
+
});
|
|
239
|
+
const StatBlock = Type.Object({
|
|
240
|
+
...BlockBase,
|
|
241
|
+
type: Type.Literal("stat"),
|
|
242
|
+
label: BindableString,
|
|
243
|
+
value: BindableJsonValue,
|
|
244
|
+
unit: Type.Optional(BindableString),
|
|
245
|
+
format: Type.Optional(Format),
|
|
246
|
+
tone: Type.Optional(BindableTone),
|
|
247
|
+
icon: Type.Optional(BindableIcon),
|
|
248
|
+
size: Type.Optional(Size),
|
|
249
|
+
caption: Type.Optional(BindableString),
|
|
250
|
+
sparkline: Type.Optional(Type.Array(Type.Number())),
|
|
251
|
+
});
|
|
252
|
+
const CalloutBlock = Type.Object({
|
|
253
|
+
...BlockBase,
|
|
254
|
+
type: Type.Literal("callout"),
|
|
255
|
+
tone: BindableTone,
|
|
256
|
+
title: BindableString,
|
|
257
|
+
body: Type.Optional(BindableString),
|
|
258
|
+
actions: Type.Optional(Type.Array(Type.Ref("ActionButton"))),
|
|
259
|
+
});
|
|
260
|
+
const ImageBlock = Type.Object({
|
|
261
|
+
...BlockBase,
|
|
262
|
+
type: Type.Literal("image"),
|
|
263
|
+
src: BindableString,
|
|
264
|
+
alt: BindableString,
|
|
265
|
+
});
|
|
266
|
+
const ChartBlock = Type.Object({
|
|
267
|
+
...BlockBase,
|
|
268
|
+
type: Type.Literal("chart"),
|
|
269
|
+
title: Type.Optional(BindableString),
|
|
270
|
+
x: Type.Object({
|
|
271
|
+
kind: Type.Unsafe({ type: "string", enum: ["time", "category", "number"] }),
|
|
272
|
+
format: Type.Optional(Format),
|
|
273
|
+
label: Type.Optional(BindableString),
|
|
274
|
+
}),
|
|
275
|
+
y: Type.Optional(Type.Object({
|
|
276
|
+
format: Type.Optional(Format),
|
|
277
|
+
unit: Type.Optional(BindableString),
|
|
278
|
+
label: Type.Optional(BindableString),
|
|
279
|
+
min: Type.Optional(Type.Number()),
|
|
280
|
+
max: Type.Optional(Type.Number()),
|
|
281
|
+
})),
|
|
282
|
+
series: Type.Array(Type.Object({
|
|
283
|
+
name: BindableString,
|
|
284
|
+
kind: Type.Unsafe({ type: "string", enum: ["line", "area", "bar"] }),
|
|
285
|
+
data: Type.Union([
|
|
286
|
+
Type.Ref("Binding"),
|
|
287
|
+
Type.Array(Type.Tuple([Type.Number(), Type.Number()])),
|
|
288
|
+
]),
|
|
289
|
+
})),
|
|
290
|
+
stacked: Type.Optional(Type.Boolean()),
|
|
291
|
+
thresholds: Type.Optional(Type.Array(Type.Object({
|
|
292
|
+
at: Type.Number(),
|
|
293
|
+
tone: Type.Ref("Tone"),
|
|
294
|
+
label: Type.Optional(BindableString),
|
|
295
|
+
}))),
|
|
296
|
+
});
|
|
297
|
+
const MeterBlock = Type.Object({
|
|
298
|
+
...BlockBase,
|
|
299
|
+
type: Type.Literal("meter"),
|
|
300
|
+
value: BindableNumber,
|
|
301
|
+
min: Type.Optional(Type.Number()),
|
|
302
|
+
max: Type.Optional(Type.Number()),
|
|
303
|
+
label: Type.Optional(BindableString),
|
|
304
|
+
format: Type.Optional(Format),
|
|
305
|
+
thresholds: Type.Optional(Type.Array(Type.Object({ at: Type.Number(), tone: Type.Ref("Tone") }))),
|
|
306
|
+
});
|
|
307
|
+
const LogBlock = Type.Object({
|
|
308
|
+
...BlockBase,
|
|
309
|
+
type: Type.Literal("log"),
|
|
310
|
+
lines: Type.Ref("Binding"),
|
|
311
|
+
follow: Type.Optional(Type.Boolean()),
|
|
312
|
+
wrap: Type.Optional(Type.Boolean()),
|
|
313
|
+
tones: Type.Optional(Type.Record(Type.String(), Type.Ref("Tone"))),
|
|
314
|
+
});
|
|
315
|
+
const TreeBlockSchema = Type.Object({
|
|
316
|
+
...BlockBase,
|
|
317
|
+
type: Type.Literal("tree"),
|
|
318
|
+
nodes: Type.Ref("Binding"),
|
|
319
|
+
onExpand: Type.Optional(Type.String()),
|
|
320
|
+
onActivate: Type.Optional(Type.Ref("Action")),
|
|
321
|
+
});
|
|
322
|
+
const DiffBlock = Type.Object({
|
|
323
|
+
...BlockBase,
|
|
324
|
+
type: Type.Literal("diff"),
|
|
325
|
+
before: Type.String(),
|
|
326
|
+
after: Type.String(),
|
|
327
|
+
path: Type.Optional(Type.String()),
|
|
328
|
+
lang: Type.Optional(Type.String()),
|
|
329
|
+
});
|
|
330
|
+
const DetailsBlock = Type.Object({
|
|
331
|
+
...BlockBase,
|
|
332
|
+
type: Type.Literal("details"),
|
|
333
|
+
value: Type.Ref("JsonValue"),
|
|
334
|
+
});
|
|
335
|
+
// ─── collection (spec §5.5) and the card template (§5.5.1) ────────────────
|
|
336
|
+
const CardMeta = Type.Union([
|
|
337
|
+
Type.Object({ icon: Type.Optional(BindableIcon), text: BindableString }),
|
|
338
|
+
Type.Object({
|
|
339
|
+
person: Type.Object({ user: BindableString, name: BindableString }),
|
|
340
|
+
}),
|
|
341
|
+
Type.Object({ time: BindableString, format: Type.Optional(Format) }),
|
|
342
|
+
]);
|
|
343
|
+
const Card = Type.Object({
|
|
344
|
+
eyebrow: Type.Optional(BindableString),
|
|
345
|
+
title: BindableString,
|
|
346
|
+
subtitle: Type.Optional(BindableString),
|
|
347
|
+
body: Type.Optional(BindableString),
|
|
348
|
+
image: Type.Optional(BindableString),
|
|
349
|
+
icon: Type.Optional(BindableIcon),
|
|
350
|
+
badges: Type.Optional(Type.Array(Type.Object({ text: BindableString, tone: Type.Optional(BindableTone) }))),
|
|
351
|
+
meta: Type.Optional(Type.Array(CardMeta)),
|
|
352
|
+
metrics: Type.Optional(Type.Array(Type.Object({
|
|
353
|
+
label: BindableString,
|
|
354
|
+
value: BindableJsonValue,
|
|
355
|
+
format: Type.Optional(Format),
|
|
356
|
+
}))),
|
|
357
|
+
tone: Type.Optional(BindableTone),
|
|
358
|
+
actions: Type.Optional(Type.Array(Type.Ref("ActionButton"))),
|
|
359
|
+
status: Type.Optional(Type.Object({
|
|
360
|
+
label: BindableString,
|
|
361
|
+
tone: Type.Optional(BindableTone),
|
|
362
|
+
spinner: Type.Optional(BindableBoolean),
|
|
363
|
+
})),
|
|
364
|
+
quiet: Type.Optional(BindableBoolean),
|
|
365
|
+
deps: Type.Optional(Type.Union([Type.Array(Type.String()), Type.Ref("Binding")])),
|
|
366
|
+
});
|
|
367
|
+
const BulkAction = Type.Object({
|
|
368
|
+
id: Type.String(),
|
|
369
|
+
label: BindableString,
|
|
370
|
+
icon: Type.Optional(Type.Ref("IconName")),
|
|
371
|
+
onSubmit: Type.String(),
|
|
372
|
+
form: Type.Optional(Type.Object({ v: Type.Number(), root: AnyObject })),
|
|
373
|
+
});
|
|
374
|
+
const CollectionBlock = Type.Object({
|
|
375
|
+
...BlockBase,
|
|
376
|
+
type: Type.Literal("collection"),
|
|
377
|
+
items: Type.Ref("Binding"),
|
|
378
|
+
item: AnyObject,
|
|
379
|
+
display: Type.Unsafe({
|
|
380
|
+
type: "string",
|
|
381
|
+
enum: ["list", "table", "lanes", "grid", "calendar"],
|
|
382
|
+
}),
|
|
383
|
+
groupBy: Type.Optional(Type.String()),
|
|
384
|
+
groups: Type.Optional(Type.Array(Type.Object({
|
|
385
|
+
id: Type.String(),
|
|
386
|
+
title: BindableString,
|
|
387
|
+
tone: Type.Optional(Type.Ref("Tone")),
|
|
388
|
+
collapsed: Type.Optional(Type.Boolean()),
|
|
389
|
+
}))),
|
|
390
|
+
sort: Type.Optional(Type.Object({
|
|
391
|
+
field: Type.String(),
|
|
392
|
+
dir: Type.Unsafe({ type: "string", enum: ["asc", "desc"] }),
|
|
393
|
+
})),
|
|
394
|
+
select: Type.Optional(Type.Unsafe({ type: "string", enum: ["single", "multi"] })),
|
|
395
|
+
bulkActions: Type.Optional(Type.Array(BulkAction)),
|
|
396
|
+
checkable: Type.Optional(Type.String()),
|
|
397
|
+
reorder: Type.Optional(Type.Object({
|
|
398
|
+
within: Type.Optional(Type.Boolean()),
|
|
399
|
+
across: Type.Optional(Type.Boolean()),
|
|
400
|
+
})),
|
|
401
|
+
children: Type.Optional(Type.String()),
|
|
402
|
+
numbered: Type.Optional(Type.Boolean()),
|
|
403
|
+
onMove: Type.Optional(Type.String()),
|
|
404
|
+
onCheck: Type.Optional(Type.String()),
|
|
405
|
+
onActivate: Type.Optional(Type.Ref("Action")),
|
|
406
|
+
columns: Type.Optional(Type.Array(Type.Object({
|
|
407
|
+
field: Type.String(),
|
|
408
|
+
label: BindableString,
|
|
409
|
+
format: Type.Optional(Format),
|
|
410
|
+
cell: Type.Optional(Type.Unsafe({ type: "string", enum: ["text", "meter", "badge"] })),
|
|
411
|
+
sortable: Type.Optional(Type.Boolean()),
|
|
412
|
+
priority: Type.Optional(Type.Unsafe({ type: "string", enum: ["high", "low"] })),
|
|
413
|
+
width: Type.Optional(Size),
|
|
414
|
+
}))),
|
|
415
|
+
time: Type.Optional(Type.Object({
|
|
416
|
+
start: Type.String(),
|
|
417
|
+
end: Type.Optional(Type.String()),
|
|
418
|
+
allDay: Type.Optional(Type.String()),
|
|
419
|
+
range: Type.Unsafe({ type: "string", enum: ["month", "week", "day", "agenda"] }),
|
|
420
|
+
onResize: Type.Optional(Type.String()),
|
|
421
|
+
onCreate: Type.Optional(Type.String()),
|
|
422
|
+
})),
|
|
423
|
+
overflow: Type.Optional(Type.Unsafe({ type: "string", enum: ["wrap", "scroll"] })),
|
|
424
|
+
});
|
|
425
|
+
// ─── fields (spec §5.6) ───────────────────────────────────────────────────
|
|
426
|
+
const TextField = Type.Object({
|
|
427
|
+
...FieldBase,
|
|
428
|
+
type: Type.Literal("text"),
|
|
429
|
+
kind: Type.Optional(Type.Unsafe({ type: "string", enum: ["plain", "search", "email", "url"] })),
|
|
430
|
+
suggest: Type.Optional(Type.Ref("Binding")),
|
|
431
|
+
});
|
|
432
|
+
const LongtextField = Type.Object({
|
|
433
|
+
...FieldBase,
|
|
434
|
+
type: Type.Literal("longtext"),
|
|
435
|
+
syntax: Type.Optional(Type.Unsafe({ type: "string", enum: ["plain", "markdown", "code"] })),
|
|
436
|
+
lang: Type.Optional(Type.String()),
|
|
437
|
+
rows: Type.Optional(Type.Integer()),
|
|
438
|
+
});
|
|
439
|
+
const NumberField = Type.Object({
|
|
440
|
+
...FieldBase,
|
|
441
|
+
type: Type.Literal("number"),
|
|
442
|
+
step: Type.Optional(Type.Number()),
|
|
443
|
+
format: Type.Optional(Format),
|
|
444
|
+
});
|
|
445
|
+
const ToggleField = Type.Object({
|
|
446
|
+
...FieldBase,
|
|
447
|
+
type: Type.Literal("toggle"),
|
|
448
|
+
});
|
|
449
|
+
const ChoiceField = Type.Object({
|
|
450
|
+
...FieldBase,
|
|
451
|
+
type: Type.Literal("choice"),
|
|
452
|
+
options: Type.Union([Type.Array(ChoiceOption), Type.Ref("Binding")]),
|
|
453
|
+
multi: Type.Optional(Type.Boolean()),
|
|
454
|
+
allowOther: Type.Optional(Type.Object({ label: Type.Optional(Type.String()) })),
|
|
455
|
+
});
|
|
456
|
+
const DateField = Type.Object({
|
|
457
|
+
...FieldBase,
|
|
458
|
+
type: Type.Literal("date"),
|
|
459
|
+
});
|
|
460
|
+
const DatetimeField = Type.Object({
|
|
461
|
+
...FieldBase,
|
|
462
|
+
type: Type.Literal("datetime"),
|
|
463
|
+
});
|
|
464
|
+
const DaterangeField = Type.Object({
|
|
465
|
+
...FieldBase,
|
|
466
|
+
type: Type.Literal("daterange"),
|
|
467
|
+
presets: Type.Optional(Type.Array(Type.Object({ id: Type.String(), label: Type.String(), duration: Type.String() }))),
|
|
468
|
+
});
|
|
469
|
+
const SecretField = Type.Object({
|
|
470
|
+
...FieldBase,
|
|
471
|
+
type: Type.Literal("secret"),
|
|
472
|
+
});
|
|
473
|
+
const FileField = Type.Object({
|
|
474
|
+
...FieldBase,
|
|
475
|
+
type: Type.Literal("file"),
|
|
476
|
+
accept: Type.Optional(Type.String()),
|
|
477
|
+
maxBytes: Type.Optional(Type.Integer()),
|
|
478
|
+
multi: Type.Optional(Type.Boolean()),
|
|
479
|
+
onUpload: Type.String(),
|
|
480
|
+
});
|
|
481
|
+
const ListField = Type.Object({
|
|
482
|
+
...FieldBase,
|
|
483
|
+
type: Type.Literal("list"),
|
|
484
|
+
item: AnyObject,
|
|
485
|
+
reorder: Type.Optional(Type.Boolean()),
|
|
486
|
+
});
|
|
487
|
+
const FormBlock = Type.Object({
|
|
488
|
+
...BlockBase,
|
|
489
|
+
type: Type.Literal("form"),
|
|
490
|
+
bind: Type.String(),
|
|
491
|
+
mode: Type.Unsafe({ type: "string", enum: ["submit", "live", "inline"] }),
|
|
492
|
+
onSubmit: Type.Optional(Type.String()),
|
|
493
|
+
submitLabel: Type.Optional(BindableString),
|
|
494
|
+
turn: Type.Optional(Type.Boolean()),
|
|
495
|
+
children: Type.Array(AnyObject),
|
|
496
|
+
});
|
|
497
|
+
// ─── compiling one validator per node kind ────────────────────────────────
|
|
498
|
+
/** The shared `$defs` every per-node cyclic compile resolves refs against. */
|
|
499
|
+
const DEFS = {
|
|
500
|
+
JsonValue,
|
|
501
|
+
Binding,
|
|
502
|
+
Tone,
|
|
503
|
+
IconName,
|
|
504
|
+
BindableTone,
|
|
505
|
+
BindableIcon,
|
|
506
|
+
CoreTarget,
|
|
507
|
+
Confirm,
|
|
508
|
+
Action,
|
|
509
|
+
ActionButton,
|
|
510
|
+
};
|
|
511
|
+
/** Compile one schema as the root of its own cyclic definition set. */
|
|
512
|
+
function compileSelf(self) {
|
|
513
|
+
return Compile(Type.Cyclic({ ...DEFS, Self: self }, "Self"));
|
|
514
|
+
}
|
|
515
|
+
/** One compiled validator per block type, keyed by its `type` literal. */
|
|
516
|
+
const BLOCK_ENTRIES = [
|
|
517
|
+
["page", compileSelf(PageBlock)],
|
|
518
|
+
["stack", compileSelf(StackBlock)],
|
|
519
|
+
["columns", compileSelf(ColumnsBlock)],
|
|
520
|
+
["grid", compileSelf(GridBlock)],
|
|
521
|
+
["section", compileSelf(SectionBlock)],
|
|
522
|
+
["markdown", compileSelf(MarkdownBlock)],
|
|
523
|
+
["fields", compileSelf(FieldsBlock)],
|
|
524
|
+
["stat", compileSelf(StatBlock)],
|
|
525
|
+
["callout", compileSelf(CalloutBlock)],
|
|
526
|
+
["image", compileSelf(ImageBlock)],
|
|
527
|
+
["chart", compileSelf(ChartBlock)],
|
|
528
|
+
["meter", compileSelf(MeterBlock)],
|
|
529
|
+
["log", compileSelf(LogBlock)],
|
|
530
|
+
["tree", compileSelf(TreeBlockSchema)],
|
|
531
|
+
["diff", compileSelf(DiffBlock)],
|
|
532
|
+
["details", compileSelf(DetailsBlock)],
|
|
533
|
+
["collection", compileSelf(CollectionBlock)],
|
|
534
|
+
["form", compileSelf(FormBlock)],
|
|
535
|
+
];
|
|
536
|
+
/** One compiled validator per block type, keyed by its `type` literal. */
|
|
537
|
+
export const BLOCK_VALIDATORS = new Map(BLOCK_ENTRIES);
|
|
538
|
+
/** One compiled validator per field type, keyed by its `type` literal. */
|
|
539
|
+
const FIELD_ENTRIES = [
|
|
540
|
+
["text", compileSelf(TextField)],
|
|
541
|
+
["longtext", compileSelf(LongtextField)],
|
|
542
|
+
["number", compileSelf(NumberField)],
|
|
543
|
+
["toggle", compileSelf(ToggleField)],
|
|
544
|
+
["choice", compileSelf(ChoiceField)],
|
|
545
|
+
["date", compileSelf(DateField)],
|
|
546
|
+
["datetime", compileSelf(DatetimeField)],
|
|
547
|
+
["daterange", compileSelf(DaterangeField)],
|
|
548
|
+
["secret", compileSelf(SecretField)],
|
|
549
|
+
["file", compileSelf(FileField)],
|
|
550
|
+
["list", compileSelf(ListField)],
|
|
551
|
+
];
|
|
552
|
+
/** One compiled validator per field type, keyed by its `type` literal. */
|
|
553
|
+
export const FIELD_VALIDATORS = new Map(FIELD_ENTRIES);
|
|
554
|
+
/** The compiled validator for `Action` objects (spec §6.1). */
|
|
555
|
+
export const ACTION_VALIDATOR = compileSelf(Action);
|
|
556
|
+
/** The compiled validator for action buttons (spec §6.1). */
|
|
557
|
+
export const ACTION_BUTTON_VALIDATOR = compileSelf(ActionButton);
|
|
558
|
+
/** The compiled validator for a collection's card template (spec §5.5.1). */
|
|
559
|
+
export const CARD_VALIDATOR = compileSelf(Card);
|