@abraca/schema 2.3.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/abracadabra-schema.cjs +853 -0
- package/dist/abracadabra-schema.cjs.map +1 -0
- package/dist/abracadabra-schema.esm.js +781 -0
- package/dist/abracadabra-schema.esm.js.map +1 -0
- package/dist/index.d.ts +2538 -0
- package/package.json +41 -0
- package/src/crdt.ts +63 -0
- package/src/generated/calendar.ts +35 -0
- package/src/generated/chart.ts +35 -0
- package/src/generated/checklist.ts +35 -0
- package/src/generated/dashboard.ts +35 -0
- package/src/generated/doc.ts +35 -0
- package/src/generated/gallery.ts +35 -0
- package/src/generated/graph.ts +35 -0
- package/src/generated/json-schema/calendar.json +140 -0
- package/src/generated/json-schema/chart.json +164 -0
- package/src/generated/json-schema/checklist.json +138 -0
- package/src/generated/json-schema/dashboard.json +122 -0
- package/src/generated/json-schema/doc.json +122 -0
- package/src/generated/json-schema/gallery.json +157 -0
- package/src/generated/json-schema/graph.json +125 -0
- package/src/generated/json-schema/kanban.json +145 -0
- package/src/generated/json-schema/map.json +125 -0
- package/src/generated/json-schema/outline.json +122 -0
- package/src/generated/json-schema/overview.json +122 -0
- package/src/generated/json-schema/plugin-manifest.json +221 -0
- package/src/generated/json-schema/prose.json +122 -0
- package/src/generated/json-schema/sheets.json +135 -0
- package/src/generated/json-schema/slides.json +129 -0
- package/src/generated/json-schema/table.json +136 -0
- package/src/generated/json-schema/timeline.json +122 -0
- package/src/generated/kanban.ts +35 -0
- package/src/generated/map.ts +35 -0
- package/src/generated/markdown/calendar.md +59 -0
- package/src/generated/markdown/chart.md +62 -0
- package/src/generated/markdown/checklist.md +58 -0
- package/src/generated/markdown/dashboard.md +56 -0
- package/src/generated/markdown/doc.md +56 -0
- package/src/generated/markdown/gallery.md +61 -0
- package/src/generated/markdown/graph.md +57 -0
- package/src/generated/markdown/kanban.md +62 -0
- package/src/generated/markdown/map.md +57 -0
- package/src/generated/markdown/outline.md +56 -0
- package/src/generated/markdown/overview.md +56 -0
- package/src/generated/markdown/prose.md +56 -0
- package/src/generated/markdown/sheets.md +59 -0
- package/src/generated/markdown/slides.md +57 -0
- package/src/generated/markdown/table.md +58 -0
- package/src/generated/markdown/timeline.md +56 -0
- package/src/generated/outline.ts +35 -0
- package/src/generated/overview.ts +35 -0
- package/src/generated/prose.ts +35 -0
- package/src/generated/rust/calendar.rs +125 -0
- package/src/generated/rust/chart.rs +151 -0
- package/src/generated/rust/checklist.rs +123 -0
- package/src/generated/rust/dashboard.rs +101 -0
- package/src/generated/rust/doc.rs +101 -0
- package/src/generated/rust/gallery.rs +146 -0
- package/src/generated/rust/graph.rs +104 -0
- package/src/generated/rust/kanban.rs +127 -0
- package/src/generated/rust/map.rs +104 -0
- package/src/generated/rust/outline.rs +101 -0
- package/src/generated/rust/overview.rs +101 -0
- package/src/generated/rust/prose.rs +101 -0
- package/src/generated/rust/sheets.rs +110 -0
- package/src/generated/rust/slides.rs +111 -0
- package/src/generated/rust/table.rs +121 -0
- package/src/generated/rust/timeline.rs +101 -0
- package/src/generated/sheets.ts +35 -0
- package/src/generated/slides.ts +35 -0
- package/src/generated/table.ts +35 -0
- package/src/generated/timeline.ts +35 -0
- package/src/index.ts +389 -0
- package/src/manifest/plugin-manifest.ts +212 -0
- package/src/query.ts +150 -0
- package/src/types/calendar.ts +23 -0
- package/src/types/chart.ts +36 -0
- package/src/types/checklist.ts +22 -0
- package/src/types/dashboard.ts +18 -0
- package/src/types/doc.ts +19 -0
- package/src/types/gallery.ts +24 -0
- package/src/types/graph.ts +21 -0
- package/src/types/kanban.ts +27 -0
- package/src/types/map.ts +21 -0
- package/src/types/outline.ts +17 -0
- package/src/types/overview.ts +17 -0
- package/src/types/prose.ts +19 -0
- package/src/types/sheets.ts +24 -0
- package/src/types/slides.ts +22 -0
- package/src/types/table.ts +22 -0
- package/src/types/timeline.ts +18 -0
- package/src/types/universal.ts +59 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime validation schema for plugin manifests (manifest v1).
|
|
3
|
+
*
|
|
4
|
+
* The TypeScript types live in `@abraca/plugin/src/manifest.ts` and stay
|
|
5
|
+
* pure — `@abraca/plugin` itself ships zero schemas per `feedback_schema_free_core`.
|
|
6
|
+
* This file is the opt-in Zod validator used by:
|
|
7
|
+
*
|
|
8
|
+
* - the registry server's submission pipeline (verifies submitted manifests
|
|
9
|
+
* before storing the artifact)
|
|
10
|
+
* - the `@abraca/plugin-cli` `validate` command (local pre-submit linting)
|
|
11
|
+
* - hosts (`cou-shell`, `@abraca/nuxt`) before instantiating an external
|
|
12
|
+
* plugin, when they want runtime validation in addition to the
|
|
13
|
+
* compile-time `PluginManifest` typing.
|
|
14
|
+
*
|
|
15
|
+
* The inferred shape is asserted to be structurally identical to
|
|
16
|
+
* `PluginManifest` from `@abraca/plugin` via `_check` type aliases below —
|
|
17
|
+
* if either side drifts, the typecheck fails.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
|
|
22
|
+
import type {
|
|
23
|
+
PluginManifest,
|
|
24
|
+
PluginCapability,
|
|
25
|
+
} from "@abraca/plugin";
|
|
26
|
+
|
|
27
|
+
// ── Capability vocabulary ─────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Capabilities with no dynamic suffix. Anything outside this set and the two
|
|
31
|
+
* prefix families (`network[:*]`, `page-type:<slug>`) is rejected.
|
|
32
|
+
*
|
|
33
|
+
* Encoded as a regex pattern (not a `.refine()` callback) so the
|
|
34
|
+
* Zod-to-JSON-Schema codegen captures it — otherwise the registry server's
|
|
35
|
+
* Rust validator would have to re-implement the vocabulary in parallel.
|
|
36
|
+
*/
|
|
37
|
+
const CAPABILITY_PATTERN =
|
|
38
|
+
"^(fs:read|fs:write|clipboard:read|clipboard:write|doc-read|doc-write|awareness|server-runner|command-palette|toolbar|bubble-menu|slash-command|drag-handle|chat:send|chat:read|notifications:show|network|network:\\S+|page-type:[a-z][a-z0-9-]*)$";
|
|
39
|
+
|
|
40
|
+
export const PluginCapabilitySchema = z
|
|
41
|
+
.string()
|
|
42
|
+
.regex(new RegExp(CAPABILITY_PATTERN), {
|
|
43
|
+
message:
|
|
44
|
+
"unknown plugin capability — see PluginCapability in @abraca/plugin",
|
|
45
|
+
})
|
|
46
|
+
.transform((s) => s as PluginCapability);
|
|
47
|
+
|
|
48
|
+
// ── Primitive field schemas ───────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
/** Lowercase-kebab slug. Starts with a letter; no consecutive dashes; no trailing dash. */
|
|
51
|
+
export const PluginIdSchema = z
|
|
52
|
+
.string()
|
|
53
|
+
.regex(
|
|
54
|
+
/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,
|
|
55
|
+
"id must be lowercase-kebab (e.g. 'spatial', 'plugin-coder', 'my-2nd-plugin')",
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Strict semver `MAJOR.MINOR.PATCH` with optional pre-release / build metadata.
|
|
60
|
+
* Reference: https://semver.org/spec/v2.0.0.html#backusnaur-form-grammar-for-valid-semver-versions
|
|
61
|
+
*/
|
|
62
|
+
export const SemverSchema = z
|
|
63
|
+
.string()
|
|
64
|
+
.regex(
|
|
65
|
+
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/,
|
|
66
|
+
"version must be valid semver (e.g. '1.2.3', '0.1.0-alpha.1')",
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Loose semver range — accepts `^1.2.3`, `~1.2`, `>=1.0 <2`, `1.x`, etc.
|
|
71
|
+
* Not parsed here; the registry server runs `semver.validRange` for strict
|
|
72
|
+
* validation. We just guard against obvious junk.
|
|
73
|
+
*/
|
|
74
|
+
export const SemverRangeSchema = z
|
|
75
|
+
.string()
|
|
76
|
+
.min(1)
|
|
77
|
+
.max(80)
|
|
78
|
+
.regex(/^[\d.xX*~^<>=|\s&,a-zA-Z+-]+$/, "invalid semver range");
|
|
79
|
+
|
|
80
|
+
/** `sha256-<64 hex chars>`. */
|
|
81
|
+
export const IntegritySchema = z
|
|
82
|
+
.string()
|
|
83
|
+
.regex(
|
|
84
|
+
/^sha256-[0-9a-f]{64}$/,
|
|
85
|
+
"integrity must be 'sha256-' + 64 lowercase hex chars",
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
/** Relative POSIX path. No `..` segments, no absolute, no protocols. */
|
|
89
|
+
export const RelativePathSchema = z
|
|
90
|
+
.string()
|
|
91
|
+
.min(1)
|
|
92
|
+
.max(256)
|
|
93
|
+
.refine(
|
|
94
|
+
(p) =>
|
|
95
|
+
!p.startsWith("/") &&
|
|
96
|
+
!/^[a-z]+:\/\//i.test(p) &&
|
|
97
|
+
!p.split("/").includes(".."),
|
|
98
|
+
"must be a relative path with no '..' segments",
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// ── Sub-schemas ───────────────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
export const PluginManifestAuthorSchema = z.object({
|
|
104
|
+
github: z.string().min(1).max(64).optional(),
|
|
105
|
+
name: z.string().min(1).max(120).optional(),
|
|
106
|
+
url: z.string().url().max(512).optional(),
|
|
107
|
+
email: z.string().email().max(254).optional(),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
export const PluginPricingSchema = z.enum(["free", "optional", "paid"]);
|
|
111
|
+
|
|
112
|
+
export const PluginVersionStatusSchema = z.enum([
|
|
113
|
+
"live",
|
|
114
|
+
"pending",
|
|
115
|
+
"rejected",
|
|
116
|
+
"superseded",
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
export const PluginManifestContributesSchema = z.object({
|
|
120
|
+
pageTypes: z.array(z.string().min(1)).readonly().optional(),
|
|
121
|
+
extensions: z.array(z.string().min(1)).readonly().optional(),
|
|
122
|
+
awarenessFields: z.array(z.string().min(1)).readonly().optional(),
|
|
123
|
+
serverRunners: z.array(z.string().min(1)).readonly().optional(),
|
|
124
|
+
commands: z.array(z.string().min(1)).readonly().optional(),
|
|
125
|
+
settingsPanels: z.array(z.string().min(1)).readonly().optional(),
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// ── Top-level manifest schema ─────────────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
export const PluginManifestSchema = z.object({
|
|
131
|
+
manifestVersion: z.literal(1),
|
|
132
|
+
id: PluginIdSchema,
|
|
133
|
+
name: z.string().min(1).max(80).optional(),
|
|
134
|
+
version: SemverSchema,
|
|
135
|
+
author: PluginManifestAuthorSchema,
|
|
136
|
+
license: z.string().min(1).max(80),
|
|
137
|
+
description: z.string().min(1).max(280),
|
|
138
|
+
readme: z.string().max(100_000).optional(),
|
|
139
|
+
homepage: z.string().url().max(512).optional(),
|
|
140
|
+
/** `github:org/repo` shorthand or any URL — registry server normalises. */
|
|
141
|
+
repository: z
|
|
142
|
+
.string()
|
|
143
|
+
.min(3)
|
|
144
|
+
.max(512)
|
|
145
|
+
.optional(),
|
|
146
|
+
minAbracadabraVersion: SemverRangeSchema.optional(),
|
|
147
|
+
entry: RelativePathSchema,
|
|
148
|
+
integrity: IntegritySchema,
|
|
149
|
+
pricing: PluginPricingSchema.optional(),
|
|
150
|
+
screenshots: z.array(RelativePathSchema).max(20).readonly().optional(),
|
|
151
|
+
categories: z.array(z.string().min(1).max(40)).max(10).readonly().optional(),
|
|
152
|
+
capabilities: z.object({
|
|
153
|
+
required: z.array(PluginCapabilitySchema).readonly(),
|
|
154
|
+
optional: z.array(PluginCapabilitySchema).readonly().optional(),
|
|
155
|
+
}),
|
|
156
|
+
contributes: PluginManifestContributesSchema.optional(),
|
|
157
|
+
peerDeps: z.record(z.string(), SemverRangeSchema).optional(),
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// ── Type identity assertions ──────────────────────────────────────────────────
|
|
161
|
+
//
|
|
162
|
+
// If either of these aliases fails to typecheck, the Zod schema has drifted
|
|
163
|
+
// from `PluginManifest` in @abraca/plugin and the two halves of the contract
|
|
164
|
+
// are out of sync. CI runs vue-tsc which catches the drift at build time.
|
|
165
|
+
|
|
166
|
+
type _SchemaInfersPluginManifest = z.infer<typeof PluginManifestSchema> extends PluginManifest
|
|
167
|
+
? true
|
|
168
|
+
: never;
|
|
169
|
+
|
|
170
|
+
type _PluginManifestSatisfiesSchema = PluginManifest extends z.infer<typeof PluginManifestSchema>
|
|
171
|
+
? true
|
|
172
|
+
: never;
|
|
173
|
+
|
|
174
|
+
// Force the aliases to be referenced so tsc doesn't elide them.
|
|
175
|
+
const _check1: _SchemaInfersPluginManifest = true;
|
|
176
|
+
const _check2: _PluginManifestSatisfiesSchema = true;
|
|
177
|
+
void _check1;
|
|
178
|
+
void _check2;
|
|
179
|
+
|
|
180
|
+
// ── Convenience helpers ───────────────────────────────────────────────────────
|
|
181
|
+
|
|
182
|
+
export interface ManifestValidationIssue {
|
|
183
|
+
readonly path: ReadonlyArray<PropertyKey>;
|
|
184
|
+
readonly message: string;
|
|
185
|
+
readonly code?: string;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export type ManifestValidationResult =
|
|
189
|
+
| { ok: true; value: PluginManifest }
|
|
190
|
+
| { ok: false; errors: ReadonlyArray<ManifestValidationIssue> };
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Parse and validate a manifest. Always returns a result object — never
|
|
194
|
+
* throws. Useful for surface UIs (the registry submission flow, the CLI's
|
|
195
|
+
* `validate` command) that want to render every issue at once.
|
|
196
|
+
*/
|
|
197
|
+
export function validatePluginManifest(
|
|
198
|
+
value: unknown,
|
|
199
|
+
): ManifestValidationResult {
|
|
200
|
+
const parsed = PluginManifestSchema.safeParse(value);
|
|
201
|
+
if (parsed.success) {
|
|
202
|
+
return { ok: true, value: parsed.data as PluginManifest };
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
ok: false,
|
|
206
|
+
errors: parsed.error.issues.map((i) => ({
|
|
207
|
+
path: i.path,
|
|
208
|
+
message: i.message,
|
|
209
|
+
code: i.code,
|
|
210
|
+
})),
|
|
211
|
+
};
|
|
212
|
+
}
|
package/src/query.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V2 query layer — predicate AST.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors InstantDB / Prisma `where` shapes: column → predicate pairs
|
|
5
|
+
* composed with boolean AND/OR/NOT. The Rust compiler at
|
|
6
|
+
* `crates/abracadabra/src/query.rs` walks the same shape and emits
|
|
7
|
+
* indexed SQL against `doc_meta_index`.
|
|
8
|
+
*
|
|
9
|
+
* Columns are restricted to the universal-meta projection: `priority`,
|
|
10
|
+
* `dateStart`, `dateEnd`, `tags`, `status`, `assignedTo`. Anything else
|
|
11
|
+
* is rejected. Adding a column requires both:
|
|
12
|
+
* 1. A new column on `doc_meta_index` (migration in `abracadabra-rs`)
|
|
13
|
+
* 2. A new entry in `META_COLUMNS` below
|
|
14
|
+
*
|
|
15
|
+
* The schema is intentionally narrow — only the operators the v2 query
|
|
16
|
+
* layer can actually execute against indexed columns are accepted. New
|
|
17
|
+
* operators require server changes; the schema is the contract.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Columns
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Whitelisted indexed columns on `doc_meta_index`. Adding to this list
|
|
28
|
+
* requires a parallel migration on the server. Order is the canonical
|
|
29
|
+
* documentation order — not enforced.
|
|
30
|
+
*/
|
|
31
|
+
export const META_COLUMNS = [
|
|
32
|
+
"priority",
|
|
33
|
+
"dateStart",
|
|
34
|
+
"dateEnd",
|
|
35
|
+
"tags",
|
|
36
|
+
"status",
|
|
37
|
+
"assignedTo",
|
|
38
|
+
] as const;
|
|
39
|
+
|
|
40
|
+
export type MetaColumn = (typeof META_COLUMNS)[number];
|
|
41
|
+
|
|
42
|
+
const ColumnEnum = z.enum(META_COLUMNS);
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Operators
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
const ScalarValue = z.union([z.string(), z.number(), z.boolean(), z.null()]);
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Numeric / lexicographic comparison operators. Apply to integer
|
|
52
|
+
* (`priority`), date (`dateStart`, `dateEnd`), and string
|
|
53
|
+
* (`status`, `assignedTo`) columns. Strings compare lexicographically
|
|
54
|
+
* — useful for date filtering on the SQLite path where dates are TEXT.
|
|
55
|
+
*/
|
|
56
|
+
const RangeOps = z.strictObject({
|
|
57
|
+
eq: ScalarValue.optional(),
|
|
58
|
+
neq: ScalarValue.optional(),
|
|
59
|
+
gt: ScalarValue.optional(),
|
|
60
|
+
gte: ScalarValue.optional(),
|
|
61
|
+
lt: ScalarValue.optional(),
|
|
62
|
+
lte: ScalarValue.optional(),
|
|
63
|
+
in: z.array(ScalarValue).optional(),
|
|
64
|
+
between: z.tuple([ScalarValue, ScalarValue]).optional(),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Operators for the `tags` column. `tags` is a JSON array.
|
|
69
|
+
* `contains: "x"` matches when the array includes the string `x`.
|
|
70
|
+
* `containsAll: ["x","y"]` requires all listed tags to be present.
|
|
71
|
+
* `containsAny: ["x","y"]` requires at least one.
|
|
72
|
+
*/
|
|
73
|
+
const TagOps = z.strictObject({
|
|
74
|
+
contains: z.string().optional(),
|
|
75
|
+
containsAll: z.array(z.string()).optional(),
|
|
76
|
+
containsAny: z.array(z.string()).optional(),
|
|
77
|
+
isEmpty: z.boolean().optional(),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
/** Per-column predicate. `null` => column IS NULL. */
|
|
81
|
+
const ColumnPredicate = z.union([
|
|
82
|
+
ScalarValue, // shorthand `{ priority: 3 }` == `{ priority: { eq: 3 } }`
|
|
83
|
+
RangeOps,
|
|
84
|
+
TagOps,
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// Composition
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* A clause is either:
|
|
93
|
+
* - A leaf: `{ column: predicate, ... }` with multiple columns AND-ed
|
|
94
|
+
* implicitly.
|
|
95
|
+
* - A composition node: `{ AND: [clause, ...] }`, `{ OR: [...] }`,
|
|
96
|
+
* `{ NOT: clause }`.
|
|
97
|
+
*
|
|
98
|
+
* The Zod schema below tolerates mixing leaf columns and composer keys
|
|
99
|
+
* at the same level; the Rust compiler rejects that case with a clear
|
|
100
|
+
* error. Keeping the Zod schema permissive on this point lets us evolve
|
|
101
|
+
* the rule without re-versioning the wire shape.
|
|
102
|
+
*/
|
|
103
|
+
export interface WhereClause {
|
|
104
|
+
readonly AND?: ReadonlyArray<WhereClause>;
|
|
105
|
+
readonly OR?: ReadonlyArray<WhereClause>;
|
|
106
|
+
readonly NOT?: WhereClause;
|
|
107
|
+
readonly priority?: z.infer<typeof ColumnPredicate>;
|
|
108
|
+
readonly dateStart?: z.infer<typeof ColumnPredicate>;
|
|
109
|
+
readonly dateEnd?: z.infer<typeof ColumnPredicate>;
|
|
110
|
+
readonly tags?: z.infer<typeof ColumnPredicate>;
|
|
111
|
+
readonly status?: z.infer<typeof ColumnPredicate>;
|
|
112
|
+
readonly assignedTo?: z.infer<typeof ColumnPredicate>;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export const WhereClauseSchema: z.ZodType<WhereClause> = z.lazy(() =>
|
|
116
|
+
z.strictObject({
|
|
117
|
+
AND: z.array(WhereClauseSchema).optional(),
|
|
118
|
+
OR: z.array(WhereClauseSchema).optional(),
|
|
119
|
+
NOT: WhereClauseSchema.optional(),
|
|
120
|
+
priority: ColumnPredicate.optional(),
|
|
121
|
+
dateStart: ColumnPredicate.optional(),
|
|
122
|
+
dateEnd: ColumnPredicate.optional(),
|
|
123
|
+
tags: ColumnPredicate.optional(),
|
|
124
|
+
status: ColumnPredicate.optional(),
|
|
125
|
+
assignedTo: ColumnPredicate.optional(),
|
|
126
|
+
}),
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Parse + normalise a raw `where` object. Returns a discriminated
|
|
131
|
+
* result so call sites can render server-friendly error messages on
|
|
132
|
+
* the wire.
|
|
133
|
+
*/
|
|
134
|
+
export function parseWhereClause(
|
|
135
|
+
raw: unknown,
|
|
136
|
+
):
|
|
137
|
+
| { ok: true; value: WhereClause }
|
|
138
|
+
| { ok: false; errors: ReadonlyArray<{ path: ReadonlyArray<PropertyKey>; message: string }> } {
|
|
139
|
+
const parsed = WhereClauseSchema.safeParse(raw);
|
|
140
|
+
if (parsed.success) {
|
|
141
|
+
return { ok: true, value: parsed.data };
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
ok: false,
|
|
145
|
+
errors: parsed.error.issues.map((i) => ({
|
|
146
|
+
path: i.path,
|
|
147
|
+
message: i.message,
|
|
148
|
+
})),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `calendar` — event calendar with month/week/day views. Direct
|
|
3
|
+
* children are events (untyped); per-event `datetimeStart` /
|
|
4
|
+
* `datetimeEnd` / `allDay` / `color` use universal keys.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
9
|
+
import { UniversalMeta } from "./universal.ts";
|
|
10
|
+
|
|
11
|
+
export const CalendarMeta = UniversalMeta.extend({
|
|
12
|
+
calendarWeekStart: z.enum(["sun", "mon"]).optional(),
|
|
13
|
+
calendarView: z.enum(["month", "week", "day"]).optional(),
|
|
14
|
+
calendarShowWeekNumbers: z.boolean().optional(),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export const Calendar = defineDocType({
|
|
18
|
+
name: "calendar",
|
|
19
|
+
version: 1,
|
|
20
|
+
meta: CalendarMeta,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const calendarSchema = defineSchema({ types: [Calendar] });
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chart` — manual data points or aggregation over document trees.
|
|
3
|
+
* Direct children are data points (untyped); per-point `number` /
|
|
4
|
+
* `color` / `tags` use universal keys.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
9
|
+
import { UniversalMeta } from "./universal.ts";
|
|
10
|
+
|
|
11
|
+
export const ChartMeta = UniversalMeta.extend({
|
|
12
|
+
chartType: z.enum(["bar", "stacked bar", "line", "donut", "treemap"]).optional(),
|
|
13
|
+
chartMetric: z
|
|
14
|
+
.enum([
|
|
15
|
+
"value",
|
|
16
|
+
"type",
|
|
17
|
+
"tag",
|
|
18
|
+
"status",
|
|
19
|
+
"priority",
|
|
20
|
+
"activity",
|
|
21
|
+
"completion",
|
|
22
|
+
])
|
|
23
|
+
.optional(),
|
|
24
|
+
chartColorScheme: z.enum(["default", "warm", "cool", "mono"]).optional(),
|
|
25
|
+
chartLimit: z.number().int().min(3).max(30).optional(),
|
|
26
|
+
chartShowLegend: z.boolean().optional(),
|
|
27
|
+
chartShowValues: z.boolean().optional(),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export const Chart = defineDocType({
|
|
31
|
+
name: "chart",
|
|
32
|
+
version: 1,
|
|
33
|
+
meta: ChartMeta,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const chartSchema = defineSchema({ types: [Chart] });
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `checklist` — collaborative checklist with sub-tasks and due dates.
|
|
3
|
+
* Unlimited descendant nesting; all descendants are untyped (per-task
|
|
4
|
+
* `checked` / `priority` / `dateEnd` flow through universal keys).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
9
|
+
import { UniversalMeta } from "./universal.ts";
|
|
10
|
+
|
|
11
|
+
export const ChecklistMeta = UniversalMeta.extend({
|
|
12
|
+
checklistFilter: z.enum(["all", "active", "completed"]).optional(),
|
|
13
|
+
checklistSort: z.enum(["manual", "priority", "due"]).optional(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export const Checklist = defineDocType({
|
|
17
|
+
name: "checklist",
|
|
18
|
+
version: 1,
|
|
19
|
+
meta: ChecklistMeta,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const checklistSchema = defineSchema({ types: [Checklist] });
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dashboard` — arranges documents as draggable icons / widgets.
|
|
3
|
+
* Descendants are untyped; per-item `desk*` layout keys flow through
|
|
4
|
+
* the untyped meta path.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
8
|
+
import { UniversalMeta } from "./universal.ts";
|
|
9
|
+
|
|
10
|
+
export const DashboardMeta = UniversalMeta;
|
|
11
|
+
|
|
12
|
+
export const Dashboard = defineDocType({
|
|
13
|
+
name: "dashboard",
|
|
14
|
+
version: 1,
|
|
15
|
+
meta: DashboardMeta,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const dashboardSchema = defineSchema({ types: [Dashboard] });
|
package/src/types/doc.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `doc` — the default rich-text page type. Body is a TipTap-backed
|
|
3
|
+
* `Y.Text`; descendants are untyped tree entries.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
7
|
+
import { ytext } from "../crdt.ts";
|
|
8
|
+
import { UniversalMeta } from "./universal.ts";
|
|
9
|
+
|
|
10
|
+
export const DocMeta = UniversalMeta;
|
|
11
|
+
|
|
12
|
+
export const Doc = defineDocType({
|
|
13
|
+
name: "doc",
|
|
14
|
+
version: 1,
|
|
15
|
+
meta: DocMeta,
|
|
16
|
+
body: ytext(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const docSchema = defineSchema({ types: [Doc] });
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `gallery` — visual grid of items with rich content. Direct children
|
|
3
|
+
* are items (untyped tree entries).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
8
|
+
import { UniversalMeta } from "./universal.ts";
|
|
9
|
+
|
|
10
|
+
export const GalleryMeta = UniversalMeta.extend({
|
|
11
|
+
galleryColumns: z.number().int().min(1).max(6).optional(),
|
|
12
|
+
galleryAspect: z.enum(["square", "4:3", "3:2", "16:9", "free"]).optional(),
|
|
13
|
+
galleryCardStyle: z.enum(["default", "compact", "detailed"]).optional(),
|
|
14
|
+
galleryShowLabels: z.boolean().optional(),
|
|
15
|
+
gallerySortBy: z.enum(["manual", "date", "name", "rating"]).optional(),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const Gallery = defineDocType({
|
|
19
|
+
name: "gallery",
|
|
20
|
+
version: 1,
|
|
21
|
+
meta: GalleryMeta,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export const gallerySchema = defineSchema({ types: [Gallery] });
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `graph` — force-directed knowledge graph rendering. Descendants are
|
|
3
|
+
* untyped (per-node `graphX` / `graphY` / `graphPinned` are written to
|
|
4
|
+
* descendant meta but not validated by the registry).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
9
|
+
import { UniversalMeta } from "./universal.ts";
|
|
10
|
+
|
|
11
|
+
export const GraphMeta = UniversalMeta.extend({
|
|
12
|
+
showRefEdges: z.boolean().optional(),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const Graph = defineDocType({
|
|
16
|
+
name: "graph",
|
|
17
|
+
version: 1,
|
|
18
|
+
meta: GraphMeta,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const graphSchema = defineSchema({ types: [Graph] });
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `kanban` — drag-and-drop board. Direct children are columns;
|
|
3
|
+
* grandchildren are cards. Both descendants are untyped tree entries
|
|
4
|
+
* — only the board itself carries `type: "kanban"` and the per-board
|
|
5
|
+
* view-config keys below.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
10
|
+
import { UniversalMeta } from "./universal.ts";
|
|
11
|
+
|
|
12
|
+
export const KanbanMeta = UniversalMeta.extend({
|
|
13
|
+
kanbanColumnWidth: z.enum(["narrow", "default", "wide"]).optional(),
|
|
14
|
+
kanbanShowIcon: z.boolean().optional(),
|
|
15
|
+
kanbanShowTags: z.boolean().optional(),
|
|
16
|
+
kanbanShowPriority: z.boolean().optional(),
|
|
17
|
+
kanbanShowDueDate: z.boolean().optional(),
|
|
18
|
+
kanbanShowCover: z.boolean().optional(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const Kanban = defineDocType({
|
|
22
|
+
name: "kanban",
|
|
23
|
+
version: 1,
|
|
24
|
+
meta: KanbanMeta,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const kanbanSchema = defineSchema({ types: [Kanban] });
|
package/src/types/map.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `map` — collaborative world map. Direct children are markers / lines
|
|
3
|
+
* / measure entries (untyped, distinguished by descendant `geoType`
|
|
4
|
+
* key flowing through the untyped meta path).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
9
|
+
import { UniversalMeta } from "./universal.ts";
|
|
10
|
+
|
|
11
|
+
export const MapMeta = UniversalMeta.extend({
|
|
12
|
+
mapShowLabels: z.boolean().optional(),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const MapDocType = defineDocType({
|
|
16
|
+
name: "map",
|
|
17
|
+
version: 1,
|
|
18
|
+
meta: MapMeta,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const mapSchema = defineSchema({ types: [MapDocType] });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `outline` — hierarchical outline with keyboard navigation. Unlimited
|
|
3
|
+
* descendant nesting; all descendants are untyped.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
7
|
+
import { UniversalMeta } from "./universal.ts";
|
|
8
|
+
|
|
9
|
+
export const OutlineMeta = UniversalMeta;
|
|
10
|
+
|
|
11
|
+
export const Outline = defineDocType({
|
|
12
|
+
name: "outline",
|
|
13
|
+
version: 1,
|
|
14
|
+
meta: OutlineMeta,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export const outlineSchema = defineSchema({ types: [Outline] });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `overview` — space home: activity, people, stats. Descendants are
|
|
3
|
+
* regular pages; no overview-specific config keys today.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
7
|
+
import { UniversalMeta } from "./universal.ts";
|
|
8
|
+
|
|
9
|
+
export const OverviewMeta = UniversalMeta;
|
|
10
|
+
|
|
11
|
+
export const Overview = defineDocType({
|
|
12
|
+
name: "overview",
|
|
13
|
+
version: 1,
|
|
14
|
+
meta: OverviewMeta,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export const overviewSchema = defineSchema({ types: [Overview] });
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `prose` — long-form prose with serif typography. Same body shape as
|
|
3
|
+
* `doc` (Y.Text TipTap content); descendants are untyped.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
7
|
+
import { ytext } from "../crdt.ts";
|
|
8
|
+
import { UniversalMeta } from "./universal.ts";
|
|
9
|
+
|
|
10
|
+
export const ProseMeta = UniversalMeta;
|
|
11
|
+
|
|
12
|
+
export const Prose = defineDocType({
|
|
13
|
+
name: "prose",
|
|
14
|
+
version: 1,
|
|
15
|
+
meta: ProseMeta,
|
|
16
|
+
body: ytext(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const proseSchema = defineSchema({ types: [Prose] });
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sheets` — spreadsheet with formulas + formatting. Direct children
|
|
3
|
+
* are columns; grandchildren are positional cells (both untyped).
|
|
4
|
+
* Per-cell `formula` / `bold` / `bgColor` / `numberFormat` etc. flow
|
|
5
|
+
* through the untyped meta path.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { defineDocType, defineSchema } from "../index.ts";
|
|
10
|
+
import { UniversalMeta } from "./universal.ts";
|
|
11
|
+
|
|
12
|
+
export const SheetsMeta = UniversalMeta.extend({
|
|
13
|
+
sheetsDefaultColWidth: z.number().min(40).max(500).optional(),
|
|
14
|
+
sheetsDefaultRowHeight: z.number().min(20).max(100).optional(),
|
|
15
|
+
sheetsShowGridlines: z.boolean().optional(),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const Sheets = defineDocType({
|
|
19
|
+
name: "sheets",
|
|
20
|
+
version: 1,
|
|
21
|
+
meta: SheetsMeta,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export const sheetsSchema = defineSchema({ types: [Sheets] });
|