@anvpx/motion-schema 0.0.0-stage → 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.
@@ -0,0 +1,254 @@
1
+ import { z } from "zod";
2
+ import { toJsonPointer } from "./errors.js";
3
+ import { forbiddenKeys, reservedKey } from "./reserved-keys.js";
4
+ import { APPROVALS, EASES, MOVES, SceneEntryBaseSchema, SHOTS, SLUG, SLUG_MESSAGE, TRANSITIONS, } from "./storyboard.js";
5
+ import { toValidationError } from "./validate.js";
6
+ /** Manifest format version; a breaking change bumps it. */
7
+ export const TEMPLATE_VERSION = 1;
8
+ /**
9
+ * Blueprint scene-prop transforms (`{"$slot": name, "as": ...}`), closed set. `flow-nodes`: labels to
10
+ * `{id,label}`; `flow-edges`: "A>B" or "A>B|label" to `{from,to,label}`; `flow-chain`: labels to a
11
+ * consecutive-edge chain.
12
+ */
13
+ export const SLOT_TRANSFORMS = ["flow-nodes", "flow-edges", "flow-chain"];
14
+ /** Length classes of a pacing document. */
15
+ export const LENGTH_CLASSES = ["short", "standard", "long"];
16
+ const SLOT_NAME = /^[a-z][A-Za-z0-9]*$/;
17
+ const SEMVER = /^\d+\.\d+\.\d+$/;
18
+ const slug = z.string().regex(SLUG, SLUG_MESSAGE);
19
+ const semver = z.string().regex(SEMVER, "must be semver x.y.z");
20
+ const slotName = reservedKey.regex(SLOT_NAME, "must be camelCase (a-z, A-Z, 0-9)");
21
+ /** A path inside the template folder: relative, forward slashes, no `..`. */
22
+ const relativePath = z
23
+ .string()
24
+ .min(1)
25
+ .refine((path) => !path.startsWith("/") &&
26
+ !path.includes("\\") &&
27
+ !/^[a-zA-Z]:/.test(path) &&
28
+ !path.split("/").includes(".."), "must be a relative path inside the template folder");
29
+ const count = z.number().int().nonnegative();
30
+ const ASPECT = /^\d+:\d+$/;
31
+ const slugs = (min, max) => z.array(slug).min(min).max(max);
32
+ /** Fields shared by manifest and blueprint `discover`; caps keep list output skimmable (docs/STORE.md 1.1). */
33
+ const discoverFields = {
34
+ /** 2-4 sentences, each <= 120 chars: what this is for. */
35
+ useCases: z.array(z.string().min(1).max(120)).min(2).max(4),
36
+ audience: slugs(1, 5).optional(),
37
+ /** WHEN to pick it. */
38
+ goodFor: z.string().min(1).max(100),
39
+ /** WHEN NOT to pick it; scoring sinks a match here. */
40
+ notFor: z.string().min(1).max(100).optional(),
41
+ tags: slugs(3, 8),
42
+ tone: slugs(1, 3).optional(),
43
+ /** Aspect ratios such as `16:9`; platform data lives in packages/schema/data/platforms. */
44
+ aspects: z.array(z.string().regex(ASPECT, "must look like 16:9")).min(1).max(6).optional(),
45
+ };
46
+ /** Template level `discover`; lengths are derived from its blueprints, never stored. */
47
+ export const ManifestDiscoverSchema = z.strictObject(discoverFields);
48
+ /** Blueprint level `discover`; `lengths` are seconds. */
49
+ export const BlueprintDiscoverSchema = z.strictObject({
50
+ ...discoverFields,
51
+ lengths: z
52
+ .strictObject({ min: z.number().int().positive(), max: z.number().int().positive() })
53
+ .refine(({ min, max }) => min <= max, "min must be <= max")
54
+ .optional(),
55
+ });
56
+ const requirement = {
57
+ required: z.boolean().optional(),
58
+ optional: z.boolean().optional(),
59
+ };
60
+ const notBoth = (slot) => !(slot.required === true && slot.optional === true);
61
+ const NOT_BOTH = "a slot cannot be both required and optional";
62
+ const TextSlotSchema = z
63
+ .strictObject({
64
+ type: z.literal("text"),
65
+ ...requirement,
66
+ min: count.optional(),
67
+ max: count.optional(),
68
+ default: z.string().optional(),
69
+ })
70
+ .refine(notBoth, NOT_BOTH);
71
+ const TextListSlotSchema = z
72
+ .strictObject({
73
+ type: z.literal("text[]"),
74
+ ...requirement,
75
+ min: count.optional(),
76
+ max: count.optional(),
77
+ itemMax: count.optional(),
78
+ })
79
+ .refine(notBoth, NOT_BOTH);
80
+ const NumberSlotSchema = z
81
+ .strictObject({
82
+ type: z.literal("number"),
83
+ ...requirement,
84
+ min: z.number().optional(),
85
+ max: z.number().optional(),
86
+ int: z.boolean().optional(),
87
+ default: z.number().optional(),
88
+ })
89
+ .refine(notBoth, NOT_BOTH);
90
+ const EnumSlotSchema = z
91
+ .strictObject({
92
+ type: z.literal("enum"),
93
+ values: z.array(z.string().min(1)).min(1),
94
+ default: z.string().optional(),
95
+ })
96
+ .refine((slot) => slot.default === undefined || slot.values.includes(slot.default), "default must be one of values");
97
+ /** One object (`list` absent) or a list of objects (`list: true`, with `min`/`max` item counts). */
98
+ const ObjectSlotSchema = z
99
+ .strictObject({
100
+ type: z.literal("object"),
101
+ fields: z.record(slotName, z.enum(["text", "number"])),
102
+ ...requirement,
103
+ list: z.boolean().optional(),
104
+ min: count.optional(),
105
+ max: count.optional(),
106
+ })
107
+ .refine(notBoth, NOT_BOTH)
108
+ .refine((slot) => Object.keys(slot.fields).length > 0, "fields must not be empty");
109
+ export const SlotSchema = z.discriminatedUnion("type", [
110
+ TextSlotSchema,
111
+ TextListSlotSchema,
112
+ NumberSlotSchema,
113
+ EnumSlotSchema,
114
+ ObjectSlotSchema,
115
+ ]);
116
+ /** A blueprint scene: a storyboard scene whose props may hold `$slot`/`$spread`/`$item` constructs. */
117
+ export const BlueprintSceneSchema = SceneEntryBaseSchema.extend({
118
+ /** Include the scene only when this slot is set. */
119
+ when: slotName.optional(),
120
+ });
121
+ /** One scene per item of a list slot; `$item` inside refers to the current item, ids get `-<n>`. */
122
+ export const BlueprintRepeatSchema = z.strictObject({
123
+ $repeat: slotName,
124
+ when: slotName.optional(),
125
+ scene: BlueprintSceneSchema,
126
+ });
127
+ export const BlueprintDocSchema = z.strictObject({
128
+ id: slug,
129
+ purpose: z.string().min(1).max(200),
130
+ discover: BlueprintDiscoverSchema.optional(),
131
+ slots: z.record(slotName, SlotSchema),
132
+ /** A complete slot set; must instantiate with every style (checked by template validation). */
133
+ example: z.record(slotName, z.unknown()),
134
+ /** Storyboard meta; `title` may be a `$slot` construct. Defaults to the `title` slot when text. */
135
+ meta: z
136
+ .strictObject({
137
+ title: z.unknown().optional(),
138
+ lang: z.string().min(2).optional(),
139
+ /**
140
+ * Render-gate default the blueprint stamps into generated storyboards (PLAN 7d.3 twin):
141
+ * "auto" (absent, current behaviour) or "confirm". Additive, optional.
142
+ */
143
+ approval: z.enum(APPROVALS).optional(),
144
+ })
145
+ .optional(),
146
+ scenes: z.array(z.union([BlueprintRepeatSchema, BlueprintSceneSchema])).min(1),
147
+ });
148
+ const FileRefSchema = z.strictObject({ id: slug, file: relativePath });
149
+ const ThemeRefSchema = z.strictObject({
150
+ id: slug,
151
+ file: relativePath,
152
+ mode: z.enum(["light", "dark"]),
153
+ pair: slug.optional(),
154
+ });
155
+ const idsUnique = (items) => new Set(items.map((item) => item.id)).size === items.length;
156
+ export const TemplateManifestSchema = z
157
+ .strictObject({
158
+ templateVersion: z.literal(TEMPLATE_VERSION),
159
+ id: slug,
160
+ version: semver,
161
+ title: z.string().min(1),
162
+ summary: z.string().min(1).max(140),
163
+ domains: z.array(slug),
164
+ discover: ManifestDiscoverSchema.optional(),
165
+ requires: z.strictObject({
166
+ storyboard: z.number().int().positive(),
167
+ scenes: z.array(z.string().min(1)),
168
+ }),
169
+ themes: z.array(ThemeRefSchema).min(1),
170
+ styles: z.array(FileRefSchema).min(1),
171
+ blueprints: z.array(FileRefSchema).min(1),
172
+ pacing: relativePath,
173
+ copy: relativePath,
174
+ license: z.string().min(1),
175
+ })
176
+ .superRefine((manifest, ctx) => {
177
+ for (const key of ["themes", "styles", "blueprints"]) {
178
+ if (!idsUnique(manifest[key])) {
179
+ ctx.addIssue({ code: "custom", path: [key], message: `duplicate ${key} id` });
180
+ }
181
+ }
182
+ const themes = new Map(manifest.themes.map((theme) => [theme.id, theme]));
183
+ manifest.themes.forEach((theme, index) => {
184
+ if (theme.pair === undefined)
185
+ return;
186
+ const other = themes.get(theme.pair);
187
+ if (other?.pair !== theme.id || other.mode === theme.mode) {
188
+ ctx.addIssue({
189
+ code: "custom",
190
+ path: ["themes", index, "pair"],
191
+ message: `pair "${theme.pair}" must name a theme of the other mode that pairs back`,
192
+ });
193
+ }
194
+ });
195
+ });
196
+ const DirectionSchema = z.strictObject({
197
+ shot: z.enum(SHOTS).optional(),
198
+ move: z.enum(MOVES).optional(),
199
+ ease: z.enum(EASES).optional(),
200
+ transition: z.enum(TRANSITIONS).optional(),
201
+ });
202
+ const FrameSchema = z.union([
203
+ z.strictObject({
204
+ width: z.number().int().positive(),
205
+ height: z.number().int().positive(),
206
+ fps: z.number().int().positive(),
207
+ }),
208
+ z.strictObject({ platform: slug }),
209
+ ]);
210
+ export const StylePresetSchema = z.strictObject({
211
+ id: slug,
212
+ theme: slug,
213
+ frame: FrameSchema.optional(),
214
+ direction: DirectionSchema.optional(),
215
+ /** Scene type -> default props; explicit blueprint values win. */
216
+ props: z.record(reservedKey, z.record(reservedKey, z.unknown())).optional(),
217
+ });
218
+ const seconds = z.number().positive();
219
+ const perLength = z.strictObject({ short: seconds, standard: seconds, long: seconds });
220
+ const range = z.tuple([count, count]).refine(([low, high]) => low <= high, "min must be <= max");
221
+ const target = z.strictObject({ scenes: range, totalSec: range });
222
+ export const PacingDocSchema = z.strictObject({
223
+ wordsPerSecond: seconds,
224
+ /** Scene type -> seconds per length class. */
225
+ sceneSeconds: z.record(reservedKey, perLength),
226
+ lengths: z.strictObject({ short: target, standard: target, long: target }),
227
+ });
228
+ /** Forbidden keys (prototype-polluting, execution-shaped) first, then the schema; pointer errors. */
229
+ const parseDoc = (schema, input) => {
230
+ const forbidden = forbiddenKeys(input, []);
231
+ if (forbidden.length > 0) {
232
+ return {
233
+ ok: false,
234
+ errors: forbidden.map(({ path, message, suggestion }) => suggestion === undefined
235
+ ? { path: toJsonPointer(path), message }
236
+ : { path: toJsonPointer(path), message, suggestion }),
237
+ };
238
+ }
239
+ const parsed = schema.safeParse(input);
240
+ if (parsed.success)
241
+ return { ok: true, value: parsed.data };
242
+ return { ok: false, errors: parsed.error.issues.map((issue) => toValidationError(issue, input)) };
243
+ };
244
+ export const parseTemplateManifest = (input) => parseDoc(TemplateManifestSchema, input);
245
+ export const parseBlueprintDoc = (input) => parseDoc(BlueprintDocSchema, input);
246
+ export const parseStylePreset = (input) => parseDoc(StylePresetSchema, input);
247
+ export const parsePacingDoc = (input) => parseDoc(PacingDocSchema, input);
248
+ /** JSON Schemas of the template documents, for editors and constrained decoding. */
249
+ export const templateJsonSchemas = () => ({
250
+ manifest: z.toJSONSchema(TemplateManifestSchema, { io: "input" }),
251
+ blueprint: z.toJSONSchema(BlueprintDocSchema, { io: "input" }),
252
+ style: z.toJSONSchema(StylePresetSchema, { io: "input" }),
253
+ pacing: z.toJSONSchema(PacingDocSchema, { io: "input" }),
254
+ });
@@ -0,0 +1,28 @@
1
+ /** Colour keys of a foreground/background pair that must meet WCAG AA text contrast. */
2
+ export interface TextPair {
3
+ readonly fg: string;
4
+ readonly bg: string;
5
+ }
6
+ /** Flat JS projection of a DTCG theme; produced by `@anvpx/motion-themes`. */
7
+ export interface ResolvedTheme {
8
+ readonly name: string;
9
+ /** Colour key -> hex, e.g. `bg`, `fg`, `accent`, `muted`. */
10
+ readonly colors: Readonly<Record<string, string>>;
11
+ /** Categorical chart palette, in order. */
12
+ readonly chart: readonly string[];
13
+ /** Font role -> CSS font-family stack. */
14
+ readonly fonts: Readonly<Record<string, string>>;
15
+ /** Type scale step -> px. */
16
+ readonly fontSizes: Readonly<Record<string, number>>;
17
+ /** Spacing step -> px. */
18
+ readonly spacing: Readonly<Record<string, number>>;
19
+ /** Radius step -> px. */
20
+ readonly radii: Readonly<Record<string, number>>;
21
+ /** Opacity step (subtle|medium|full) -> 0..1. */
22
+ readonly opacities: Readonly<Record<string, number>>;
23
+ /** Motion duration name -> seconds. */
24
+ readonly durations: Readonly<Record<string, number>>;
25
+ readonly textPairs: readonly TextPair[];
26
+ /** Extra custom properties (`--mk-*` name -> CSS value) from optional token groups; absent when the theme sets none. */
27
+ readonly vars?: Readonly<Record<string, string>>;
28
+ }
package/dist/theme.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,44 @@
1
+ import { z } from "zod";
2
+ export declare const TIMING_SOURCES: readonly ["authored", "voice"];
3
+ /**
4
+ * Finite numbers only (zod 4 rejects NaN and Infinity); scenes sorted, non-overlapping, unique slugs.
5
+ *
6
+ * Voice (additive, v1 — no version bump): a `voice`-source row may carry per-scene `words`
7
+ * (aligner timings on the same absolute clock; sorted, non-overlapping) and the manifest may
8
+ * carry the full `audio` analysis. Both are optional; older manifests stay valid.
9
+ */
10
+ export declare const TimingManifestSchema: z.ZodObject<{
11
+ source: z.ZodEnum<{
12
+ authored: "authored";
13
+ voice: "voice";
14
+ }>;
15
+ scenes: z.ZodArray<z.ZodObject<{
16
+ id: z.ZodString;
17
+ start: z.ZodNumber;
18
+ duration: z.ZodNumber;
19
+ words: z.ZodOptional<z.ZodArray<z.ZodObject<{
20
+ w: z.ZodString;
21
+ start: z.ZodNumber;
22
+ end: z.ZodNumber;
23
+ confidence: z.ZodOptional<z.ZodNumber>;
24
+ }, z.core.$strict>>>;
25
+ }, z.core.$strict>>;
26
+ audio: z.ZodOptional<z.ZodObject<{
27
+ words: z.ZodArray<z.ZodObject<{
28
+ w: z.ZodString;
29
+ start: z.ZodNumber;
30
+ end: z.ZodNumber;
31
+ confidence: z.ZodOptional<z.ZodNumber>;
32
+ }, z.core.$strict>>;
33
+ silences: z.ZodOptional<z.ZodArray<z.ZodObject<{
34
+ start: z.ZodNumber;
35
+ end: z.ZodNumber;
36
+ }, z.core.$strict>>>;
37
+ peaks: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
38
+ model: z.ZodOptional<z.ZodString>;
39
+ modelRevision: z.ZodOptional<z.ZodString>;
40
+ modelLicense: z.ZodOptional<z.ZodString>;
41
+ duration: z.ZodOptional<z.ZodNumber>;
42
+ }, z.core.$strict>>;
43
+ }, z.core.$strict>;
44
+ export type TimingManifest = z.output<typeof TimingManifestSchema>;
package/dist/timing.js ADDED
@@ -0,0 +1,44 @@
1
+ import { z } from "zod";
2
+ import { AudioAnalysisSchema, WordTimingsSchema } from "./audio.js";
3
+ import { SLUG, SLUG_MESSAGE } from "./storyboard.js";
4
+ export const TIMING_SOURCES = ["authored", "voice"];
5
+ const checkScenes = (scenes, ctx) => {
6
+ const seen = new Set();
7
+ scenes.forEach((scene, index) => {
8
+ if (seen.has(scene.id)) {
9
+ ctx.addIssue({
10
+ code: "custom",
11
+ path: [index, "id"],
12
+ message: `duplicate scene id "${scene.id}"`,
13
+ });
14
+ }
15
+ seen.add(scene.id);
16
+ const prev = scenes[index - 1];
17
+ if (prev && scene.start < prev.start + prev.duration) {
18
+ ctx.addIssue({
19
+ code: "custom",
20
+ path: [index, "start"],
21
+ message: `scene "${scene.id}" overlaps "${prev.id}"`,
22
+ });
23
+ }
24
+ });
25
+ };
26
+ /**
27
+ * Finite numbers only (zod 4 rejects NaN and Infinity); scenes sorted, non-overlapping, unique slugs.
28
+ *
29
+ * Voice (additive, v1 — no version bump): a `voice`-source row may carry per-scene `words`
30
+ * (aligner timings on the same absolute clock; sorted, non-overlapping) and the manifest may
31
+ * carry the full `audio` analysis. Both are optional; older manifests stay valid.
32
+ */
33
+ export const TimingManifestSchema = z.strictObject({
34
+ source: z.enum(TIMING_SOURCES),
35
+ scenes: z
36
+ .array(z.strictObject({
37
+ id: z.string().regex(SLUG, SLUG_MESSAGE),
38
+ start: z.number().min(0),
39
+ duration: z.number().positive(),
40
+ words: WordTimingsSchema.optional(),
41
+ }))
42
+ .superRefine(checkScenes),
43
+ audio: AudioAnalysisSchema.optional(),
44
+ });
@@ -0,0 +1,5 @@
1
+ import type { z } from "zod";
2
+ import { type Result, type ValidationError } from "./errors.ts";
3
+ import { type Storyboard } from "./storyboard.ts";
4
+ export declare const toValidationError: (issue: z.core.$ZodIssue, input: unknown) => ValidationError;
5
+ export declare const validateStoryboard: (input: unknown) => Result<Storyboard>;
@@ -0,0 +1,58 @@
1
+ import { toJsonPointer } from "./errors.js";
2
+ import { forbiddenKeys } from "./reserved-keys.js";
3
+ import { StoryboardSchema } from "./storyboard.js";
4
+ import { readVersion, STORYBOARD_VERSION } from "./version.js";
5
+ const valueAt = (root, path) => path.reduce((node, key) => (typeof node === "object" && node !== null ? Reflect.get(node, key) : undefined), root);
6
+ export const toValidationError = (issue, input) => {
7
+ const path = toJsonPointer(issue.path);
8
+ if (issue.code === "invalid_value") {
9
+ const received = JSON.stringify(valueAt(input, issue.path));
10
+ return {
11
+ path,
12
+ message: `${received} invalid`,
13
+ suggestion: `use one of: ${issue.values.join("|")}`,
14
+ };
15
+ }
16
+ if (issue.code === "unrecognized_keys") {
17
+ const keys = issue.keys.join(", ");
18
+ return {
19
+ path,
20
+ message: `unknown key(s): ${keys}`,
21
+ suggestion: `remove ${keys} (check spelling against the catalog)`,
22
+ };
23
+ }
24
+ const suggestion = issue.code === "custom" ? issue.params?.suggestion : undefined;
25
+ return typeof suggestion === "string"
26
+ ? { path, message: issue.message, suggestion }
27
+ : { path, message: issue.message };
28
+ };
29
+ export const validateStoryboard = (input) => {
30
+ const version = readVersion(input);
31
+ if (!version.ok)
32
+ return { ok: false, errors: [version.error] };
33
+ if (version.version !== STORYBOARD_VERSION) {
34
+ return {
35
+ ok: false,
36
+ errors: [
37
+ {
38
+ path: "/version",
39
+ message: `unknown version ${version.version}`,
40
+ suggestion: `use "version": ${STORYBOARD_VERSION}`,
41
+ },
42
+ ],
43
+ };
44
+ }
45
+ const forbidden = forbiddenKeys(input, []);
46
+ if (forbidden.length > 0) {
47
+ return {
48
+ ok: false,
49
+ errors: forbidden.map(({ path, message, suggestion }) => suggestion === undefined
50
+ ? { path: toJsonPointer(path), message }
51
+ : { path: toJsonPointer(path), message, suggestion }),
52
+ };
53
+ }
54
+ const parsed = StoryboardSchema.safeParse(input);
55
+ if (parsed.success)
56
+ return { ok: true, value: parsed.data };
57
+ return { ok: false, errors: parsed.error.issues.map((issue) => toValidationError(issue, input)) };
58
+ };
@@ -0,0 +1,10 @@
1
+ import type { ValidationError } from "./errors.ts";
2
+ export declare const STORYBOARD_VERSION = 1;
3
+ export type VersionRead = {
4
+ readonly ok: true;
5
+ readonly version: number;
6
+ } | {
7
+ readonly ok: false;
8
+ readonly error: ValidationError;
9
+ };
10
+ export declare const readVersion: (input: unknown) => VersionRead;
@@ -0,0 +1,19 @@
1
+ export const STORYBOARD_VERSION = 1;
2
+ const isRecord = (input) => typeof input === "object" && input !== null && !Array.isArray(input);
3
+ const reject = (path, message, suggestion) => ({
4
+ ok: false,
5
+ error: { path, message, suggestion },
6
+ });
7
+ export const readVersion = (input) => {
8
+ if (!isRecord(input)) {
9
+ return reject("", "storyboard must be a JSON object", `start with {"version": ${STORYBOARD_VERSION}, "meta": {...}, "scenes": [...]}`);
10
+ }
11
+ const { version } = input;
12
+ if (version === undefined) {
13
+ return reject("/version", "version is required", `add "version": ${STORYBOARD_VERSION}`);
14
+ }
15
+ if (typeof version !== "number" || !Number.isInteger(version)) {
16
+ return reject("/version", "version must be an integer", `use "version": ${STORYBOARD_VERSION}`);
17
+ }
18
+ return { ok: true, version };
19
+ };
package/package.json CHANGED
@@ -1,6 +1,36 @@
1
1
  {
2
2
  "name": "@anvpx/motion-schema",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "Zod contracts and JSON Schema for @anvpx/motion storyboards.",
5
+ "license": "MIT",
6
+ "author": "anvpx",
7
+ "type": "module",
8
+ "engines": {
9
+ "node": ">=22"
10
+ },
11
+ "keywords": [
12
+ "motion-kit",
13
+ "schema",
14
+ "zod",
15
+ "storyboard",
16
+ "video"
17
+ ],
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "exports": {
22
+ ".": "./dist/index.js",
23
+ "./package.json": "./package.json"
24
+ },
25
+ "files": [
26
+ "dist/**/*.js",
27
+ "dist/**/*.d.ts",
28
+ "data/**/*.json"
29
+ ],
30
+ "dependencies": {
31
+ "zod": "4.6.7"
32
+ },
33
+ "scripts": {
34
+ "snapshot:update": "node scripts/snapshot-update.mjs"
35
+ }
6
36
  }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.