@skyphusion-labs/vivijure-core 0.9.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/LICENSE +661 -0
- package/README.md +87 -0
- package/dist/audio-routing.d.ts +2 -0
- package/dist/audio-routing.d.ts.map +1 -0
- package/dist/audio-routing.js +4 -0
- package/dist/audio-routing.js.map +1 -0
- package/dist/audio-stage.d.ts +4 -0
- package/dist/audio-stage.d.ts.map +1 -0
- package/dist/audio-stage.js +25 -0
- package/dist/audio-stage.js.map +1 -0
- package/dist/beat-analyze.d.ts +22 -0
- package/dist/beat-analyze.d.ts.map +1 -0
- package/dist/beat-analyze.js +111 -0
- package/dist/beat-analyze.js.map +1 -0
- package/dist/beat-sync-types.d.ts +33 -0
- package/dist/beat-sync-types.d.ts.map +1 -0
- package/dist/beat-sync-types.js +4 -0
- package/dist/beat-sync-types.js.map +1 -0
- package/dist/bundle-assembler.d.ts +54 -0
- package/dist/bundle-assembler.d.ts.map +1 -0
- package/dist/bundle-assembler.js +376 -0
- package/dist/bundle-assembler.js.map +1 -0
- package/dist/bundle-durations.d.ts +5 -0
- package/dist/bundle-durations.d.ts.map +1 -0
- package/dist/bundle-durations.js +68 -0
- package/dist/bundle-durations.js.map +1 -0
- package/dist/bundle-storyboard.d.ts +11 -0
- package/dist/bundle-storyboard.d.ts.map +1 -0
- package/dist/bundle-storyboard.js +82 -0
- package/dist/bundle-storyboard.js.map +1 -0
- package/dist/captions.d.ts +25 -0
- package/dist/captions.d.ts.map +1 -0
- package/dist/captions.js +56 -0
- package/dist/captions.js.map +1 -0
- package/dist/cast-db.d.ts +61 -0
- package/dist/cast-db.d.ts.map +1 -0
- package/dist/cast-db.js +324 -0
- package/dist/cast-db.js.map +1 -0
- package/dist/cast-lora-train.d.ts +18 -0
- package/dist/cast-lora-train.d.ts.map +1 -0
- package/dist/cast-lora-train.js +215 -0
- package/dist/cast-lora-train.js.map +1 -0
- package/dist/cast-loras.d.ts +21 -0
- package/dist/cast-loras.d.ts.map +1 -0
- package/dist/cast-loras.js +69 -0
- package/dist/cast-loras.js.map +1 -0
- package/dist/clip-content-validate.d.ts +43 -0
- package/dist/clip-content-validate.d.ts.map +1 -0
- package/dist/clip-content-validate.js +115 -0
- package/dist/clip-content-validate.js.map +1 -0
- package/dist/clip-job-model.d.ts +42 -0
- package/dist/clip-job-model.d.ts.map +1 -0
- package/dist/clip-job-model.js +8 -0
- package/dist/clip-job-model.js.map +1 -0
- package/dist/clip-validate.d.ts +33 -0
- package/dist/clip-validate.d.ts.map +1 -0
- package/dist/clip-validate.js +247 -0
- package/dist/clip-validate.js.map +1 -0
- package/dist/d1-retry.d.ts +20 -0
- package/dist/d1-retry.d.ts.map +1 -0
- package/dist/d1-retry.js +67 -0
- package/dist/d1-retry.js.map +1 -0
- package/dist/db-env.d.ts +6 -0
- package/dist/db-env.d.ts.map +1 -0
- package/dist/db-env.js +2 -0
- package/dist/db-env.js.map +1 -0
- package/dist/dialogue-lines.d.ts +23 -0
- package/dist/dialogue-lines.d.ts.map +1 -0
- package/dist/dialogue-lines.js +84 -0
- package/dist/dialogue-lines.js.map +1 -0
- package/dist/film-advance-lease.d.ts +9 -0
- package/dist/film-advance-lease.d.ts.map +1 -0
- package/dist/film-advance-lease.js +19 -0
- package/dist/film-advance-lease.js.map +1 -0
- package/dist/film-model.d.ts +415 -0
- package/dist/film-model.d.ts.map +1 -0
- package/dist/film-model.js +541 -0
- package/dist/film-model.js.map +1 -0
- package/dist/film-orchestrator.d.ts +216 -0
- package/dist/film-orchestrator.d.ts.map +1 -0
- package/dist/film-orchestrator.js +2204 -0
- package/dist/film-orchestrator.js.map +1 -0
- package/dist/film-render-bridge.d.ts +26 -0
- package/dist/film-render-bridge.d.ts.map +1 -0
- package/dist/film-render-bridge.js +176 -0
- package/dist/film-render-bridge.js.map +1 -0
- package/dist/finish-hash.d.ts +10 -0
- package/dist/finish-hash.d.ts.map +1 -0
- package/dist/finish-hash.js +60 -0
- package/dist/finish-hash.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/key-safety.d.ts +5 -0
- package/dist/key-safety.d.ts.map +1 -0
- package/dist/key-safety.js +23 -0
- package/dist/key-safety.js.map +1 -0
- package/dist/lora-bundle.d.ts +19 -0
- package/dist/lora-bundle.d.ts.map +1 -0
- package/dist/lora-bundle.js +75 -0
- package/dist/lora-bundle.js.map +1 -0
- package/dist/lora-keys.d.ts +2 -0
- package/dist/lora-keys.d.ts.map +1 -0
- package/dist/lora-keys.js +4 -0
- package/dist/lora-keys.js.map +1 -0
- package/dist/modules/conformance.d.ts +58 -0
- package/dist/modules/conformance.d.ts.map +1 -0
- package/dist/modules/conformance.js +369 -0
- package/dist/modules/conformance.js.map +1 -0
- package/dist/modules/manifest-validate.d.ts +5 -0
- package/dist/modules/manifest-validate.d.ts.map +1 -0
- package/dist/modules/manifest-validate.js +60 -0
- package/dist/modules/manifest-validate.js.map +1 -0
- package/dist/modules/registry.d.ts +184 -0
- package/dist/modules/registry.d.ts.map +1 -0
- package/dist/modules/registry.js +653 -0
- package/dist/modules/registry.js.map +1 -0
- package/dist/modules/render-pipeline.d.ts +38 -0
- package/dist/modules/render-pipeline.d.ts.map +1 -0
- package/dist/modules/render-pipeline.js +40 -0
- package/dist/modules/render-pipeline.js.map +1 -0
- package/dist/modules/types.d.ts +544 -0
- package/dist/modules/types.d.ts.map +1 -0
- package/dist/modules/types.js +57 -0
- package/dist/modules/types.js.map +1 -0
- package/dist/operator-config.d.ts +20 -0
- package/dist/operator-config.d.ts.map +1 -0
- package/dist/operator-config.js +85 -0
- package/dist/operator-config.js.map +1 -0
- package/dist/output-extract.d.ts +8 -0
- package/dist/output-extract.d.ts.map +1 -0
- package/dist/output-extract.js +129 -0
- package/dist/output-extract.js.map +1 -0
- package/dist/planner-prompt.d.ts +12 -0
- package/dist/planner-prompt.d.ts.map +1 -0
- package/dist/planner-prompt.js +337 -0
- package/dist/planner-prompt.js.map +1 -0
- package/dist/planner-yaml.d.ts +15 -0
- package/dist/planner-yaml.d.ts.map +1 -0
- package/dist/planner-yaml.js +157 -0
- package/dist/planner-yaml.js.map +1 -0
- package/dist/platform/fetcher.d.ts +3 -0
- package/dist/platform/fetcher.d.ts.map +1 -0
- package/dist/platform/fetcher.js +7 -0
- package/dist/platform/fetcher.js.map +1 -0
- package/dist/platform/index.d.ts +6 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +5 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/object-store-r2.d.ts +26 -0
- package/dist/platform/object-store-r2.d.ts.map +1 -0
- package/dist/platform/object-store-r2.js +74 -0
- package/dist/platform/object-store-r2.js.map +1 -0
- package/dist/platform/orchestrator-context.d.ts +20 -0
- package/dist/platform/orchestrator-context.d.ts.map +1 -0
- package/dist/platform/orchestrator-context.js +28 -0
- package/dist/platform/orchestrator-context.js.map +1 -0
- package/dist/platform/r2-types.d.ts +41 -0
- package/dist/platform/r2-types.d.ts.map +1 -0
- package/dist/platform/r2-types.js +3 -0
- package/dist/platform/r2-types.js.map +1 -0
- package/dist/platform/types.d.ts +90 -0
- package/dist/platform/types.d.ts.map +1 -0
- package/dist/platform/types.js +23 -0
- package/dist/platform/types.js.map +1 -0
- package/dist/preflight.d.ts +57 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +243 -0
- package/dist/preflight.js.map +1 -0
- package/dist/presign.d.ts +5 -0
- package/dist/presign.d.ts.map +1 -0
- package/dist/presign.js +24 -0
- package/dist/presign.js.map +1 -0
- package/dist/public-id.d.ts +8 -0
- package/dist/public-id.d.ts.map +1 -0
- package/dist/public-id.js +25 -0
- package/dist/public-id.js.map +1 -0
- package/dist/render-adopt.d.ts +3 -0
- package/dist/render-adopt.d.ts.map +1 -0
- package/dist/render-adopt.js +92 -0
- package/dist/render-adopt.js.map +1 -0
- package/dist/render-log.d.ts +25 -0
- package/dist/render-log.d.ts.map +1 -0
- package/dist/render-log.js +139 -0
- package/dist/render-log.js.map +1 -0
- package/dist/render-module-config.d.ts +28 -0
- package/dist/render-module-config.d.ts.map +1 -0
- package/dist/render-module-config.js +124 -0
- package/dist/render-module-config.js.map +1 -0
- package/dist/render-mux.d.ts +18 -0
- package/dist/render-mux.d.ts.map +1 -0
- package/dist/render-mux.js +69 -0
- package/dist/render-mux.js.map +1 -0
- package/dist/render-orchestrator.d.ts +71 -0
- package/dist/render-orchestrator.d.ts.map +1 -0
- package/dist/render-orchestrator.js +376 -0
- package/dist/render-orchestrator.js.map +1 -0
- package/dist/render-sweep.d.ts +5 -0
- package/dist/render-sweep.d.ts.map +1 -0
- package/dist/render-sweep.js +62 -0
- package/dist/render-sweep.js.map +1 -0
- package/dist/renders-db.d.ts +129 -0
- package/dist/renders-db.d.ts.map +1 -0
- package/dist/renders-db.js +752 -0
- package/dist/renders-db.js.map +1 -0
- package/dist/runpod-submit.d.ts +151 -0
- package/dist/runpod-submit.d.ts.map +1 -0
- package/dist/runpod-submit.js +469 -0
- package/dist/runpod-submit.js.map +1 -0
- package/dist/runpod-types.d.ts +2 -0
- package/dist/runpod-types.d.ts.map +1 -0
- package/dist/runpod-types.js +4 -0
- package/dist/runpod-types.js.map +1 -0
- package/dist/scatter-notify.d.ts +4 -0
- package/dist/scatter-notify.d.ts.map +1 -0
- package/dist/scatter-notify.js +43 -0
- package/dist/scatter-notify.js.map +1 -0
- package/dist/scatter-orchestrator-types.d.ts +56 -0
- package/dist/scatter-orchestrator-types.d.ts.map +1 -0
- package/dist/scatter-orchestrator-types.js +3 -0
- package/dist/scatter-orchestrator-types.js.map +1 -0
- package/dist/scatter-orchestrator.d.ts +70 -0
- package/dist/scatter-orchestrator.d.ts.map +1 -0
- package/dist/scatter-orchestrator.js +614 -0
- package/dist/scatter-orchestrator.js.map +1 -0
- package/dist/scatter.d.ts +35 -0
- package/dist/scatter.d.ts.map +1 -0
- package/dist/scatter.js +171 -0
- package/dist/scatter.js.map +1 -0
- package/dist/secret-store.d.ts +5 -0
- package/dist/secret-store.d.ts.map +1 -0
- package/dist/secret-store.js +19 -0
- package/dist/secret-store.js.map +1 -0
- package/dist/shot-durations-parse.d.ts +3 -0
- package/dist/shot-durations-parse.d.ts.map +1 -0
- package/dist/shot-durations-parse.js +43 -0
- package/dist/shot-durations-parse.js.map +1 -0
- package/dist/srt.d.ts +11 -0
- package/dist/srt.d.ts.map +1 -0
- package/dist/srt.js +54 -0
- package/dist/srt.js.map +1 -0
- package/dist/storyboard-ids.d.ts +2 -0
- package/dist/storyboard-ids.d.ts.map +1 -0
- package/dist/storyboard-ids.js +12 -0
- package/dist/storyboard-ids.js.map +1 -0
- package/dist/storyboard-projects-db.d.ts +31 -0
- package/dist/storyboard-projects-db.d.ts.map +1 -0
- package/dist/storyboard-projects-db.js +153 -0
- package/dist/storyboard-projects-db.js.map +1 -0
- package/dist/storyboard-validate.d.ts +72 -0
- package/dist/storyboard-validate.d.ts.map +1 -0
- package/dist/storyboard-validate.js +595 -0
- package/dist/storyboard-validate.js.map +1 -0
- package/dist/structured-events.d.ts +6 -0
- package/dist/structured-events.d.ts.map +1 -0
- package/dist/structured-events.js +15 -0
- package/dist/structured-events.js.map +1 -0
- package/dist/tar.d.ts +9 -0
- package/dist/tar.d.ts.map +1 -0
- package/dist/tar.js +151 -0
- package/dist/tar.js.map +1 -0
- package/dist/voices.d.ts +12 -0
- package/dist/voices.d.ts.map +1 -0
- package/dist/voices.js +37 -0
- package/dist/voices.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Safe relative key / path segment helpers (ported from vivijure shared.ts).
|
|
2
|
+
export const BUNDLE_KEY_PREFIX = "bundles/";
|
|
3
|
+
const REL_KEY_CHARS = /^[A-Za-z0-9._\-\/]+$/;
|
|
4
|
+
export function isSafeRelKey(key) {
|
|
5
|
+
if (typeof key !== "string" || key.length === 0 || key.length > 1024)
|
|
6
|
+
return false;
|
|
7
|
+
if (key.startsWith("/"))
|
|
8
|
+
return false;
|
|
9
|
+
if (!REL_KEY_CHARS.test(key))
|
|
10
|
+
return false;
|
|
11
|
+
return !key.split("/").includes("..");
|
|
12
|
+
}
|
|
13
|
+
export function isSafeBundleKey(key) {
|
|
14
|
+
return isSafeRelKey(key) && key.startsWith(BUNDLE_KEY_PREFIX);
|
|
15
|
+
}
|
|
16
|
+
export function sanitizeKeySegment(raw, fallback = "project") {
|
|
17
|
+
const s = raw
|
|
18
|
+
.replace(/[^A-Za-z0-9._\-]/g, "_")
|
|
19
|
+
.replace(/\.\.+/g, "_")
|
|
20
|
+
.replace(/^[._-]+/, "");
|
|
21
|
+
return s.length > 0 ? s : fallback;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=key-safety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-safety.js","sourceRoot":"","sources":["../src/key-safety.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAE5C,MAAM,aAAa,GAAG,sBAAsB,CAAC;AAE7C,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,IAAI;QAAE,OAAO,KAAK,CAAC;IACnF,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,QAAQ,GAAG,SAAS;IAClE,MAAM,CAAC,GAAG,GAAG;SACV,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC;SACjC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC1B,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { StoryboardValidated } from "./storyboard-validate.js";
|
|
2
|
+
import type { CastMember } from "./cast-db.js";
|
|
3
|
+
export interface LoraBundleTrainingImage {
|
|
4
|
+
key: string;
|
|
5
|
+
}
|
|
6
|
+
export interface LoraBundleCharacterRef {
|
|
7
|
+
name: string;
|
|
8
|
+
prompt: string;
|
|
9
|
+
trainingImages: LoraBundleTrainingImage[];
|
|
10
|
+
portrait?: LoraBundleTrainingImage;
|
|
11
|
+
}
|
|
12
|
+
export interface LoraBundleArgs {
|
|
13
|
+
storyboard: StoryboardValidated;
|
|
14
|
+
characterRefs: Record<string, LoraBundleCharacterRef>;
|
|
15
|
+
}
|
|
16
|
+
export declare function buildLoraTrainingBundleArgs(cast: CastMember, bundleSuffix: string): LoraBundleArgs;
|
|
17
|
+
export declare function deriveLoraDestKey(castId: number, timestamp: number): string;
|
|
18
|
+
export declare function extractTrainedLoraKey(output: unknown): string | null;
|
|
19
|
+
//# sourceMappingURL=lora-bundle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lora-bundle.d.ts","sourceRoot":"","sources":["../src/lora-bundle.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,uBAAuB,EAAE,CAAC;IAC1C,QAAQ,CAAC,EAAE,uBAAuB,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,mBAAmB,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;CACvD;AAMD,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,UAAU,EAChB,YAAY,EAAE,MAAM,GACnB,cAAc,CAiChB;AAOD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3E;AAOD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAcpE"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Pure helpers for standalone LoRA training bundles.
|
|
2
|
+
//
|
|
3
|
+
// Route handlers wrap these with env-touching pieces (assembleBundle,
|
|
4
|
+
// submitTrainLoraJob). Keeping data-shaping here lets vitest cover the
|
|
5
|
+
// bundle-builder logic without importing cloudflare:workers.
|
|
6
|
+
// Build the (storyboard, characterRefs) tuple that assembleBundle takes
|
|
7
|
+
// for a single-slot LoRA training bundle. The synthesized storyboard
|
|
8
|
+
// satisfies the validator: one scene with a non-empty prompt that
|
|
9
|
+
// references slot A, which is also the only entry in use_characters.
|
|
10
|
+
export function buildLoraTrainingBundleArgs(cast, bundleSuffix) {
|
|
11
|
+
const safeSlug = cast.slug || `cast-${cast.id}`;
|
|
12
|
+
const projectName = `lora-${safeSlug}-${bundleSuffix}`;
|
|
13
|
+
return {
|
|
14
|
+
storyboard: {
|
|
15
|
+
title: projectName,
|
|
16
|
+
projectName,
|
|
17
|
+
full_prompt: "",
|
|
18
|
+
duration_seconds: undefined,
|
|
19
|
+
clip_seconds: undefined,
|
|
20
|
+
style_prefix: "",
|
|
21
|
+
style_category: "None",
|
|
22
|
+
style_preset: "None",
|
|
23
|
+
use_characters: ["A"],
|
|
24
|
+
cast_rules: "",
|
|
25
|
+
scenes: [
|
|
26
|
+
{
|
|
27
|
+
id: "lora_train_shot",
|
|
28
|
+
prompt: "lora training reference shot (not rendered)",
|
|
29
|
+
character_slots: ["A"],
|
|
30
|
+
target_seconds: 1,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
characterRefs: {
|
|
35
|
+
A: {
|
|
36
|
+
name: cast.name,
|
|
37
|
+
prompt: cast.bible || cast.name,
|
|
38
|
+
trainingImages: cast.ref_keys.map((r) => ({ key: r.key })),
|
|
39
|
+
portrait: cast.portrait_key ? { key: cast.portrait_key } : undefined,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Build the destination R2 key for the trained .safetensors. Per-cast
|
|
45
|
+
// prefix lets a future GC pass enumerate by cast id; the timestamp
|
|
46
|
+
// version keeps retraining immutable so an in-flight render that
|
|
47
|
+
// references the prior key does not break. The GPU backend may use its
|
|
48
|
+
// own convention; this is returned to the client for traceability.
|
|
49
|
+
export function deriveLoraDestKey(castId, timestamp) {
|
|
50
|
+
return `loras/cast-${castId}/${timestamp}.safetensors`;
|
|
51
|
+
}
|
|
52
|
+
// The trained-LoRA R2 key from a completed train_lora job envelope. The clean-room
|
|
53
|
+
// backend returns it nested under result.lora[slot].lora_id (a cast-training bundle
|
|
54
|
+
// is single-slot, so it's the one entry); the legacy vivijure-serverless envelope
|
|
55
|
+
// used a top-level lora_key. Reads both shapes so the cast page harvests the key
|
|
56
|
+
// either way; returns null only if neither carries one.
|
|
57
|
+
export function extractTrainedLoraKey(output) {
|
|
58
|
+
if (!output || typeof output !== "object")
|
|
59
|
+
return null;
|
|
60
|
+
const o = output;
|
|
61
|
+
if (typeof o.lora_key === "string" && o.lora_key)
|
|
62
|
+
return o.lora_key;
|
|
63
|
+
const lora = o.lora;
|
|
64
|
+
if (lora && typeof lora === "object" && !Array.isArray(lora)) {
|
|
65
|
+
for (const entry of Object.values(lora)) {
|
|
66
|
+
if (entry && typeof entry === "object") {
|
|
67
|
+
const id = entry.lora_id;
|
|
68
|
+
if (typeof id === "string" && id)
|
|
69
|
+
return id;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=lora-bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lora-bundle.js","sourceRoot":"","sources":["../src/lora-bundle.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,EAAE;AACF,sEAAsE;AACtE,uEAAuE;AACvE,6DAA6D;AAqB7D,wEAAwE;AACxE,qEAAqE;AACrE,kEAAkE;AAClE,qEAAqE;AACrE,MAAM,UAAU,2BAA2B,CACzC,IAAgB,EAChB,YAAoB;IAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,IAAI,QAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;IAChD,MAAM,WAAW,GAAG,QAAQ,QAAQ,IAAI,YAAY,EAAE,CAAC;IACvD,OAAO;QACL,UAAU,EAAE;YACV,KAAK,EAAE,WAAW;YAClB,WAAW;YACX,WAAW,EAAE,EAAE;YACf,gBAAgB,EAAE,SAAS;YAC3B,YAAY,EAAE,SAAS;YACvB,YAAY,EAAE,EAAE;YAChB,cAAc,EAAE,MAAM;YACtB,YAAY,EAAE,MAAM;YACpB,cAAc,EAAE,CAAC,GAAG,CAAC;YACrB,UAAU,EAAE,EAAE;YACd,MAAM,EAAE;gBACN;oBACE,EAAE,EAAE,iBAAiB;oBACrB,MAAM,EAAE,6CAA6C;oBACrD,eAAe,EAAE,CAAC,GAAG,CAAC;oBACtB,cAAc,EAAE,CAAC;iBAClB;aACF;SACF;QACD,aAAa,EAAE;YACb,CAAC,EAAE;gBACD,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,MAAM,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI;gBAC/B,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;gBAC1D,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS;aACrE;SACF;KACF,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,mEAAmE;AACnE,iEAAiE;AACjE,uEAAuE;AACvE,mEAAmE;AACnE,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,SAAiB;IACjE,OAAO,cAAc,MAAM,IAAI,SAAS,cAAc,CAAC;AACzD,CAAC;AAED,mFAAmF;AACnF,oFAAoF;AACpF,kFAAkF;AAClF,iFAAiF;AACjF,wDAAwD;AACxD,MAAM,UAAU,qBAAqB,CAAC,MAAe;IACnD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACvD,MAAM,CAAC,GAAG,MAAiC,CAAC;IAC5C,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ;QAAE,OAAO,CAAC,CAAC,QAAQ,CAAC;IACpE,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;IACpB,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,IAA+B,CAAC,EAAE,CAAC;YACnE,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACvC,MAAM,EAAE,GAAI,KAA+B,CAAC,OAAO,CAAC;gBACpD,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE;oBAAE,OAAO,EAAE,CAAC;YAC9C,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lora-keys.d.ts","sourceRoot":"","sources":["../src/lora-keys.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lora-keys.js","sourceRoot":"","sources":["../src/lora-keys.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,SAAiB;IACjE,OAAO,cAAc,MAAM,IAAI,SAAS,cAAc,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface ConformanceCheck {
|
|
2
|
+
name: string;
|
|
3
|
+
pass: boolean;
|
|
4
|
+
detail: string;
|
|
5
|
+
}
|
|
6
|
+
/** Validate a module's manifest (the GET /module.json body) against the contract. */
|
|
7
|
+
export declare function checkManifest(raw: unknown): ConformanceCheck[];
|
|
8
|
+
/** Validate that a body is a well-formed InvokeResponse: { ok:true, output } or { ok:false, error:string }. */
|
|
9
|
+
export declare function checkInvokeResponse(raw: unknown): ConformanceCheck;
|
|
10
|
+
/** Validate that a body is a well-formed CancelResponse: { ok:true } or { ok:false, error:string }. A
|
|
11
|
+
* module whose manifest advertises `cancelable` must answer POST /cancel with this shape (a bad/unknown
|
|
12
|
+
* token is DATA -> ok:false with a reason, never a crash), so the core can trust ok:true as "the job is
|
|
13
|
+
* not running on our account" and degrade-log on ok:false (#327 / #328). */
|
|
14
|
+
export declare function checkCancelResponse(raw: unknown): ConformanceCheck;
|
|
15
|
+
/** Validate that a hook's success output honors its typed contract shape (the payload inside
|
|
16
|
+
* `{ ok:true, output }`). Use this AFTER checkInvokeResponse confirms the envelope: a module can be
|
|
17
|
+
* envelope-correct yet return a payload that breaks the hook contract, which the core would then
|
|
18
|
+
* hand downstream as garbage. An unknown hook name is itself a failure. */
|
|
19
|
+
export declare function checkHookOutput(hook: string, output: unknown): ConformanceCheck;
|
|
20
|
+
/** Terminal-seam guard for a module's RESOLVED hook output. The generic transport (invokeModule /
|
|
21
|
+
* pollModule) is payload-agnostic -- it also backs dispatchChain's output->input fold and dispatchPickOne
|
|
22
|
+
* and cannot enforce a specific hook's contract without rejecting those legitimate toy payloads. The
|
|
23
|
+
* ORCHESTRATOR that consumes a hook enforces it instead: after awaitInvoke / pollModule resolves, the
|
|
24
|
+
* payload IS the real contract type. Returns a concise, traceable degrade reason (module id + hook + what
|
|
25
|
+
* broke, so it reads cleanly on the event channel) when the output violates the hook contract, or null
|
|
26
|
+
* when it honors it, so the core never threads an envelope-correct but malformed payload downstream
|
|
27
|
+
* (#345 / F5b). A legitimate soft-degrade (ok:true + passthrough + `degraded`) still carries its required
|
|
28
|
+
* contract fields, so it passes this guard untouched -- only a genuinely malformed payload is caught. */
|
|
29
|
+
export declare function hookOutputViolation(moduleId: string, hook: string, output: unknown): string | null;
|
|
30
|
+
/** True iff every check passed. */
|
|
31
|
+
export declare function allPass(checks: ConformanceCheck[]): boolean;
|
|
32
|
+
/** The failed checks, for a concise report. */
|
|
33
|
+
export declare function failures(checks: ConformanceCheck[]): ConformanceCheck[];
|
|
34
|
+
/** A Fetcher-shaped module handle: the SAME thing `MODULE_DISPATCH.get(script)` and a service binding
|
|
35
|
+
* both return. The live runner is transport-agnostic -- it drives whatever Fetcher it is handed. */
|
|
36
|
+
export interface ConformanceFetcher {
|
|
37
|
+
fetch(input: Request | string, init?: RequestInit): Promise<Response>;
|
|
38
|
+
}
|
|
39
|
+
/** Run the conformance suite against a LIVE module Fetcher at install time (docs/module-dispatch.md 4.3).
|
|
40
|
+
* Drives the module over the SAME transport it will run on (a dispatched user Worker, or a service
|
|
41
|
+
* binding), asserting: a valid manifest at GET /module.json; a well-formed InvokeResponse ENVELOPE for
|
|
42
|
+
* its first hook; and that a bad-hook request DEGRADES (HTTP 200 + { ok:false }, never a crash). The
|
|
43
|
+
* install route INSERTs the registry row ONLY when every check passes; a resident-but-failing module is
|
|
44
|
+
* never installed and never dispatched. Total: a network failure becomes a failed check, never a throw.
|
|
45
|
+
*
|
|
46
|
+
* SCOPE (be honest about what this gate proves): it validates the CONTRACT WIRING -- manifest shape,
|
|
47
|
+
* the invoke/degrade envelope, and, for a SYNCHRONOUS hook (a module that answers `ok:true + output`
|
|
48
|
+
* right away, e.g. plan.enhance), the typed hook OUTPUT via checkHookOutput. It deliberately does NOT
|
|
49
|
+
* validate the typed output of an ASYNC hook (motion.backend / keyframe / finish / speech / master),
|
|
50
|
+
* which answers `ok:true + pending + poll`: proving that output shape would require POLLING THE JOB TO
|
|
51
|
+
* COMPLETION, i.e. triggering the module's real (often GPU) work just to install it -- an unacceptable
|
|
52
|
+
* cost + side effect for an install gate. Typed-output conformance for async hooks is therefore the
|
|
53
|
+
* MODULE'S OWN responsibility, proven by its conformance CI (checkHookOutput over a controlled
|
|
54
|
+
* completion in tests/conformance.live.test.ts / `npm run conformance`), not by this install-time gate.
|
|
55
|
+
* The gate blocks a mis-wired or non-degrading module; it does not (and cannot cheaply) re-run an async
|
|
56
|
+
* module's per-shot output contract. */
|
|
57
|
+
export declare function runLiveConformance(fetcher: ConformanceFetcher): Promise<ConformanceCheck[]>;
|
|
58
|
+
//# sourceMappingURL=conformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conformance.d.ts","sourceRoot":"","sources":["../../src/modules/conformance.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAkCD,qFAAqF;AACrF,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,EAAE,CAoB9D;AAED,+GAA+G;AAC/G,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,CAUlE;AAED;;;6EAG6E;AAC7E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,CAMlE;AA0GD;;;4EAG4E;AAC5E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,gBAAgB,CAO/E;AAED;;;;;;;;0GAQ0G;AAC1G,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAGlG;AAED,mCAAmC;AACnC,wBAAgB,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAE3D;AAED,+CAA+C;AAC/C,wBAAgB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,EAAE,CAEvE;AAID;qGACqG;AACrG,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACvE;AAyBD;;;;;;;;;;;;;;;;;yCAiByC;AACzC,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA4DjG"}
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
// Module conformance harness (vivijure-module/2; /1 accepted transitionally).
|
|
2
|
+
//
|
|
3
|
+
// The "does this module honor the contract?" checker. Anyone writing a module (in this repo or
|
|
4
|
+
// another) runs these checks against their worker to know it will plug into the core cleanly:
|
|
5
|
+
// - its GET /module.json is a valid manifest (api version, name, version, known hooks, sane
|
|
6
|
+
// config_schema + provides),
|
|
7
|
+
// - its POST /invoke returns a well-formed InvokeResponse,
|
|
8
|
+
// - and it degrades (a bad request is DATA -- HTTP 200 with { ok:false }, never a crash).
|
|
9
|
+
//
|
|
10
|
+
// The pure checks here are dependency-free + unit-tested; the live runner (tests/conformance.live
|
|
11
|
+
// .test.ts) drives them against a deployed module URL. This is the conformance half of the module
|
|
12
|
+
// SDK: the contract is the law, and this is how a contributor proves they obey it.
|
|
13
|
+
import { SUPPORTED_MODULE_APIS } from "./types.js";
|
|
14
|
+
import { validateManifest } from "./manifest-validate.js";
|
|
15
|
+
const ok = (name, detail = "ok") => ({ name, pass: true, detail });
|
|
16
|
+
const bad = (name, detail) => ({ name, pass: false, detail });
|
|
17
|
+
const FIELD_TYPES = ["int", "float", "bool", "enum", "string"];
|
|
18
|
+
const FIELD_SCOPES = ["render", "install"];
|
|
19
|
+
/** One config_schema field has a valid type and a default consistent with that type. */
|
|
20
|
+
function checkConfigField(key, f) {
|
|
21
|
+
const label = "config." + key;
|
|
22
|
+
if (!f || typeof f !== "object")
|
|
23
|
+
return bad(label, "field is not an object");
|
|
24
|
+
const ff = f;
|
|
25
|
+
const t = ff.type;
|
|
26
|
+
if (typeof t !== "string" || !FIELD_TYPES.includes(t))
|
|
27
|
+
return bad(label, "bad field type " + String(t));
|
|
28
|
+
// scope is optional (omitted => "render", a per-render knob); when present it must be a known scope.
|
|
29
|
+
if (ff.scope !== undefined && (typeof ff.scope !== "string" || !FIELD_SCOPES.includes(ff.scope))) {
|
|
30
|
+
return bad(label, "bad field scope " + String(ff.scope));
|
|
31
|
+
}
|
|
32
|
+
if (t === "enum") {
|
|
33
|
+
if (!Array.isArray(ff.values) || ff.values.length === 0)
|
|
34
|
+
return bad(label, "enum needs a non-empty values[]");
|
|
35
|
+
if (typeof ff.default !== "string" || !ff.values.includes(ff.default)) {
|
|
36
|
+
return bad(label, "enum default must be one of values");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else if (t === "bool") {
|
|
40
|
+
if (typeof ff.default !== "boolean")
|
|
41
|
+
return bad(label, "bool default must be a boolean");
|
|
42
|
+
}
|
|
43
|
+
else if (t === "string") {
|
|
44
|
+
if (typeof ff.default !== "string")
|
|
45
|
+
return bad(label, "string default must be a string");
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
if (typeof ff.default !== "number")
|
|
49
|
+
return bad(label, t + " default must be a number");
|
|
50
|
+
}
|
|
51
|
+
return ok(label, String(t));
|
|
52
|
+
}
|
|
53
|
+
/** Validate a module's manifest (the GET /module.json body) against the contract. */
|
|
54
|
+
export function checkManifest(raw) {
|
|
55
|
+
const checks = [];
|
|
56
|
+
const m = validateManifest(raw);
|
|
57
|
+
if (typeof m === "string") {
|
|
58
|
+
checks.push(bad("manifest", m));
|
|
59
|
+
return checks;
|
|
60
|
+
}
|
|
61
|
+
checks.push(ok("manifest", m.name + " v" + m.version));
|
|
62
|
+
checks.push(SUPPORTED_MODULE_APIS.has(String(m.api))
|
|
63
|
+
? ok("api-version", String(m.api))
|
|
64
|
+
: bad("api-version", String(m.api) + " not in " + [...SUPPORTED_MODULE_APIS].join("/")));
|
|
65
|
+
checks.push(ok("hooks", m.hooks.join(", ")));
|
|
66
|
+
if (m.config_schema) {
|
|
67
|
+
for (const [k, f] of Object.entries(m.config_schema))
|
|
68
|
+
checks.push(checkConfigField(k, f));
|
|
69
|
+
}
|
|
70
|
+
if (m.provides) {
|
|
71
|
+
const good = m.provides.every((p) => p && typeof p.id === "string" && typeof p.label === "string");
|
|
72
|
+
checks.push(good ? ok("provides", String(m.provides.length)) : bad("provides", "each provides[] needs id + label"));
|
|
73
|
+
}
|
|
74
|
+
return checks;
|
|
75
|
+
}
|
|
76
|
+
/** Validate that a body is a well-formed InvokeResponse: { ok:true, output } or { ok:false, error:string }. */
|
|
77
|
+
export function checkInvokeResponse(raw) {
|
|
78
|
+
if (!raw || typeof raw !== "object")
|
|
79
|
+
return bad("invoke-response", "not an object");
|
|
80
|
+
const r = raw;
|
|
81
|
+
if (r.ok === true) {
|
|
82
|
+
if ("output" in r)
|
|
83
|
+
return ok("invoke-response", "ok:true + output");
|
|
84
|
+
if (r.pending === true && typeof r.poll === "string")
|
|
85
|
+
return ok("invoke-response", "ok:true + pending + poll");
|
|
86
|
+
return bad("invoke-response", "ok:true but neither output nor pending+poll");
|
|
87
|
+
}
|
|
88
|
+
if (r.ok === false)
|
|
89
|
+
return typeof r.error === "string" ? ok("invoke-response", "ok:false + error") : bad("invoke-response", "ok:false but error is not a string");
|
|
90
|
+
return bad("invoke-response", "missing boolean `ok`");
|
|
91
|
+
}
|
|
92
|
+
/** Validate that a body is a well-formed CancelResponse: { ok:true } or { ok:false, error:string }. A
|
|
93
|
+
* module whose manifest advertises `cancelable` must answer POST /cancel with this shape (a bad/unknown
|
|
94
|
+
* token is DATA -> ok:false with a reason, never a crash), so the core can trust ok:true as "the job is
|
|
95
|
+
* not running on our account" and degrade-log on ok:false (#327 / #328). */
|
|
96
|
+
export function checkCancelResponse(raw) {
|
|
97
|
+
if (!raw || typeof raw !== "object")
|
|
98
|
+
return bad("cancel-response", "not an object");
|
|
99
|
+
const r = raw;
|
|
100
|
+
if (r.ok === true)
|
|
101
|
+
return ok("cancel-response", "ok:true");
|
|
102
|
+
if (r.ok === false)
|
|
103
|
+
return typeof r.error === "string" ? ok("cancel-response", "ok:false + error") : bad("cancel-response", "ok:false but error is not a string");
|
|
104
|
+
return bad("cancel-response", "missing boolean `ok`");
|
|
105
|
+
}
|
|
106
|
+
// --------------------------------------------------------------------------- hook output payloads
|
|
107
|
+
const isRec = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
108
|
+
const isStr = (v) => typeof v === "string";
|
|
109
|
+
const isNum = (v) => typeof v === "number" && Number.isFinite(v);
|
|
110
|
+
const isStrArr = (v) => Array.isArray(v) && v.every(isStr);
|
|
111
|
+
/** Per-hook output validators: the typed payload each hook must return inside `{ ok:true, output }`.
|
|
112
|
+
* Validating the envelope (checkInvokeResponse) is not enough -- a `finish` module that returns
|
|
113
|
+
* `{ ok:true, output:{} }` is well-formed at the envelope but breaks the contract. Each returns a
|
|
114
|
+
* reason string on a shape violation, or null when the payload honors the hook's contract. Only the
|
|
115
|
+
* REQUIRED fields are enforced; optional contract fields are not demanded (mirrors the runtime,
|
|
116
|
+
* which treats hint fields as optional). */
|
|
117
|
+
const HOOK_OUTPUT_CHECKS = {
|
|
118
|
+
keyframe: (o) => {
|
|
119
|
+
if (!isStr(o.project))
|
|
120
|
+
return "keyframe output needs a string project";
|
|
121
|
+
if (!Array.isArray(o.keyframes))
|
|
122
|
+
return "keyframe output needs a keyframes[]";
|
|
123
|
+
const bad = o.keyframes.find((k) => !isRec(k) || !isStr(k.shot_id) || !isStr(k.keyframe_key));
|
|
124
|
+
if (bad)
|
|
125
|
+
return "each keyframe needs shot_id + keyframe_key";
|
|
126
|
+
// Optional: trained_loras maps slot -> R2 key (string -> string).
|
|
127
|
+
if (o.trained_loras !== undefined) {
|
|
128
|
+
if (!isRec(o.trained_loras))
|
|
129
|
+
return "keyframe output trained_loras must be an object";
|
|
130
|
+
if (Object.values(o.trained_loras).some((v) => !isStr(v))) {
|
|
131
|
+
return "keyframe output trained_loras values must be R2 key strings";
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
},
|
|
136
|
+
"motion.backend": (o) => {
|
|
137
|
+
if (!isStr(o.shot_id))
|
|
138
|
+
return "motion output needs a string shot_id";
|
|
139
|
+
if (!isStr(o.clip_key))
|
|
140
|
+
return "motion output needs a string clip_key";
|
|
141
|
+
if (!isNum(o.fps))
|
|
142
|
+
return "motion output needs a numeric fps";
|
|
143
|
+
if (!isNum(o.frames))
|
|
144
|
+
return "motion output needs a numeric frames";
|
|
145
|
+
return null;
|
|
146
|
+
},
|
|
147
|
+
finish: (o) => {
|
|
148
|
+
if (!isStr(o.shot_id))
|
|
149
|
+
return "finish output needs a string shot_id";
|
|
150
|
+
if (!isStr(o.clip_key))
|
|
151
|
+
return "finish output needs a string clip_key";
|
|
152
|
+
if (!isNum(o.out_fps))
|
|
153
|
+
return "finish output needs a numeric out_fps";
|
|
154
|
+
if (!isNum(o.frames))
|
|
155
|
+
return "finish output needs a numeric frames";
|
|
156
|
+
if (!isStrArr(o.applied))
|
|
157
|
+
return "finish output needs an applied string[]";
|
|
158
|
+
return null;
|
|
159
|
+
},
|
|
160
|
+
score: (o) => {
|
|
161
|
+
if (!isStr(o.film_key))
|
|
162
|
+
return "score output needs a string film_key";
|
|
163
|
+
if (!isStrArr(o.applied))
|
|
164
|
+
return "score output needs an applied string[]";
|
|
165
|
+
if (o.degraded !== undefined && !isStr(o.degraded))
|
|
166
|
+
return "score degraded, when present, must be a string (the chain degrade reason)";
|
|
167
|
+
return null;
|
|
168
|
+
},
|
|
169
|
+
dialogue: (o) => {
|
|
170
|
+
if (!isStr(o.project))
|
|
171
|
+
return "dialogue output needs a string project";
|
|
172
|
+
if (!Array.isArray(o.audio))
|
|
173
|
+
return "dialogue output needs an audio[]";
|
|
174
|
+
const badEntry = o.audio.find((a) => !isRec(a) || !isStr(a.shot_id) || !isStr(a.audio_key) || !isStr(a.voice_id));
|
|
175
|
+
if (badEntry)
|
|
176
|
+
return "each dialogue audio needs shot_id + audio_key + voice_id";
|
|
177
|
+
if (!isStrArr(o.applied))
|
|
178
|
+
return "dialogue output needs an applied string[]";
|
|
179
|
+
return null;
|
|
180
|
+
},
|
|
181
|
+
speech: (o) => {
|
|
182
|
+
if (!isStr(o.shot_id))
|
|
183
|
+
return "speech output needs a string shot_id";
|
|
184
|
+
if (!isStr(o.audio_key))
|
|
185
|
+
return "speech output needs a string audio_key";
|
|
186
|
+
if (!isStrArr(o.applied))
|
|
187
|
+
return "speech output needs an applied string[]";
|
|
188
|
+
return null;
|
|
189
|
+
},
|
|
190
|
+
"plan.enhance": (o) => {
|
|
191
|
+
if (!isRec(o.storyboard))
|
|
192
|
+
return "plan.enhance output needs a storyboard object";
|
|
193
|
+
if (!Array.isArray(o.storyboard.scenes)) {
|
|
194
|
+
return "plan.enhance storyboard needs a scenes[]";
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
},
|
|
198
|
+
"cast.image": (o) => {
|
|
199
|
+
if (!isNum(o.cast_id))
|
|
200
|
+
return "cast.image output needs a numeric cast_id";
|
|
201
|
+
if (!Array.isArray(o.images))
|
|
202
|
+
return "cast.image output needs an images[]";
|
|
203
|
+
const bad = o.images.find((i) => !isRec(i) || !isStr(i.key) || !isStr(i.mime));
|
|
204
|
+
if (bad)
|
|
205
|
+
return "each cast.image needs key + mime";
|
|
206
|
+
if (!isStrArr(o.applied))
|
|
207
|
+
return "cast.image output needs an applied string[]";
|
|
208
|
+
return null;
|
|
209
|
+
},
|
|
210
|
+
notify: (o) => {
|
|
211
|
+
if (!isStrArr(o.delivered))
|
|
212
|
+
return "notify output needs a delivered string[]";
|
|
213
|
+
return null;
|
|
214
|
+
},
|
|
215
|
+
master: (o) => {
|
|
216
|
+
if (!isStr(o.audio_key))
|
|
217
|
+
return "master output needs a string audio_key";
|
|
218
|
+
if (!isStrArr(o.applied))
|
|
219
|
+
return "master output needs an applied string[]";
|
|
220
|
+
return null;
|
|
221
|
+
},
|
|
222
|
+
"film.finish": (o) => {
|
|
223
|
+
if (!isStr(o.film_key))
|
|
224
|
+
return "film.finish output needs a string film_key";
|
|
225
|
+
// applied/degraded stay OPTIONAL (vendored-contract back-compat; the core defaults `applied ?? []`)
|
|
226
|
+
// but a present value must honor the type -- a malformed applied would otherwise flow into job
|
|
227
|
+
// state unchecked (film-orchestrator records it verbatim).
|
|
228
|
+
if (o.applied !== undefined && !isStrArr(o.applied))
|
|
229
|
+
return "film.finish applied, when present, must be a string[]";
|
|
230
|
+
if (o.degraded !== undefined && !isStr(o.degraded))
|
|
231
|
+
return "film.finish degraded, when present, must be a string (the uncarded reason)";
|
|
232
|
+
if (o.prepend_seconds !== undefined && (typeof o.prepend_seconds !== "number" || !Number.isFinite(o.prepend_seconds) || o.prepend_seconds < 0))
|
|
233
|
+
return "film.finish prepend_seconds, when present, must be a non-negative finite number";
|
|
234
|
+
return null;
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
/** Validate that a hook's success output honors its typed contract shape (the payload inside
|
|
238
|
+
* `{ ok:true, output }`). Use this AFTER checkInvokeResponse confirms the envelope: a module can be
|
|
239
|
+
* envelope-correct yet return a payload that breaks the hook contract, which the core would then
|
|
240
|
+
* hand downstream as garbage. An unknown hook name is itself a failure. */
|
|
241
|
+
export function checkHookOutput(hook, output) {
|
|
242
|
+
const label = "output." + hook;
|
|
243
|
+
const validator = HOOK_OUTPUT_CHECKS[hook];
|
|
244
|
+
if (!validator)
|
|
245
|
+
return bad(label, "unknown hook " + hook);
|
|
246
|
+
if (!isRec(output))
|
|
247
|
+
return bad(label, "output is not an object");
|
|
248
|
+
const reason = validator(output);
|
|
249
|
+
return reason ? bad(label, reason) : ok(label);
|
|
250
|
+
}
|
|
251
|
+
/** Terminal-seam guard for a module's RESOLVED hook output. The generic transport (invokeModule /
|
|
252
|
+
* pollModule) is payload-agnostic -- it also backs dispatchChain's output->input fold and dispatchPickOne
|
|
253
|
+
* and cannot enforce a specific hook's contract without rejecting those legitimate toy payloads. The
|
|
254
|
+
* ORCHESTRATOR that consumes a hook enforces it instead: after awaitInvoke / pollModule resolves, the
|
|
255
|
+
* payload IS the real contract type. Returns a concise, traceable degrade reason (module id + hook + what
|
|
256
|
+
* broke, so it reads cleanly on the event channel) when the output violates the hook contract, or null
|
|
257
|
+
* when it honors it, so the core never threads an envelope-correct but malformed payload downstream
|
|
258
|
+
* (#345 / F5b). A legitimate soft-degrade (ok:true + passthrough + `degraded`) still carries its required
|
|
259
|
+
* contract fields, so it passes this guard untouched -- only a genuinely malformed payload is caught. */
|
|
260
|
+
export function hookOutputViolation(moduleId, hook, output) {
|
|
261
|
+
const check = checkHookOutput(hook, output);
|
|
262
|
+
return check.pass ? null : `module ${moduleId} violated ${hook} contract: ${check.detail}`;
|
|
263
|
+
}
|
|
264
|
+
/** True iff every check passed. */
|
|
265
|
+
export function allPass(checks) {
|
|
266
|
+
return checks.every((c) => c.pass);
|
|
267
|
+
}
|
|
268
|
+
/** The failed checks, for a concise report. */
|
|
269
|
+
export function failures(checks) {
|
|
270
|
+
return checks.filter((c) => !c.pass);
|
|
271
|
+
}
|
|
272
|
+
// The bad-hook the degrade check submits; deliberately not a real HookName so a conformant module must
|
|
273
|
+
// answer HTTP 200 + { ok:false } (data, never a crash / 4xx / 5xx).
|
|
274
|
+
const DEGRADE_PROBE_HOOK = "not.a.real.hook";
|
|
275
|
+
async function fetchJson(fetcher, path, init) {
|
|
276
|
+
try {
|
|
277
|
+
const res = await fetcher.fetch("https://module" + path, init);
|
|
278
|
+
let body = null;
|
|
279
|
+
try {
|
|
280
|
+
body = await res.json();
|
|
281
|
+
}
|
|
282
|
+
catch (e) {
|
|
283
|
+
return { status: res.status, body: null, err: `body not JSON: ${e.message}` };
|
|
284
|
+
}
|
|
285
|
+
return { status: res.status, body };
|
|
286
|
+
}
|
|
287
|
+
catch (e) {
|
|
288
|
+
return { status: 0, body: null, err: `unreachable: ${e.message}` };
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/** Run the conformance suite against a LIVE module Fetcher at install time (docs/module-dispatch.md 4.3).
|
|
292
|
+
* Drives the module over the SAME transport it will run on (a dispatched user Worker, or a service
|
|
293
|
+
* binding), asserting: a valid manifest at GET /module.json; a well-formed InvokeResponse ENVELOPE for
|
|
294
|
+
* its first hook; and that a bad-hook request DEGRADES (HTTP 200 + { ok:false }, never a crash). The
|
|
295
|
+
* install route INSERTs the registry row ONLY when every check passes; a resident-but-failing module is
|
|
296
|
+
* never installed and never dispatched. Total: a network failure becomes a failed check, never a throw.
|
|
297
|
+
*
|
|
298
|
+
* SCOPE (be honest about what this gate proves): it validates the CONTRACT WIRING -- manifest shape,
|
|
299
|
+
* the invoke/degrade envelope, and, for a SYNCHRONOUS hook (a module that answers `ok:true + output`
|
|
300
|
+
* right away, e.g. plan.enhance), the typed hook OUTPUT via checkHookOutput. It deliberately does NOT
|
|
301
|
+
* validate the typed output of an ASYNC hook (motion.backend / keyframe / finish / speech / master),
|
|
302
|
+
* which answers `ok:true + pending + poll`: proving that output shape would require POLLING THE JOB TO
|
|
303
|
+
* COMPLETION, i.e. triggering the module's real (often GPU) work just to install it -- an unacceptable
|
|
304
|
+
* cost + side effect for an install gate. Typed-output conformance for async hooks is therefore the
|
|
305
|
+
* MODULE'S OWN responsibility, proven by its conformance CI (checkHookOutput over a controlled
|
|
306
|
+
* completion in tests/conformance.live.test.ts / `npm run conformance`), not by this install-time gate.
|
|
307
|
+
* The gate blocks a mis-wired or non-degrading module; it does not (and cannot cheaply) re-run an async
|
|
308
|
+
* module's per-shot output contract. */
|
|
309
|
+
export async function runLiveConformance(fetcher) {
|
|
310
|
+
const checks = [];
|
|
311
|
+
// 1) manifest
|
|
312
|
+
const man = await fetchJson(fetcher, "/module.json");
|
|
313
|
+
if ("err" in man || man.status !== 200) {
|
|
314
|
+
const why = "err" in man ? man.err : `GET /module.json -> ${man.status}`;
|
|
315
|
+
checks.push(bad("manifest", why));
|
|
316
|
+
return checks; // no manifest -> nothing else can be meaningfully checked
|
|
317
|
+
}
|
|
318
|
+
const manifestChecks = checkManifest(man.body);
|
|
319
|
+
checks.push(...manifestChecks);
|
|
320
|
+
const manifest = validateManifest(man.body);
|
|
321
|
+
if (typeof manifest === "string")
|
|
322
|
+
return checks; // checkManifest already recorded the failure
|
|
323
|
+
// 2) first-hook invoke: well-formed envelope (+ typed payload when synchronous)
|
|
324
|
+
const hook = manifest.hooks[0];
|
|
325
|
+
const probe = await fetchJson(fetcher, "/invoke", {
|
|
326
|
+
method: "POST",
|
|
327
|
+
headers: { "content-type": "application/json" },
|
|
328
|
+
body: JSON.stringify({
|
|
329
|
+
hook,
|
|
330
|
+
// A plan.enhance-shaped input; for other hooks the module simply degrades (ok:false), which is
|
|
331
|
+
// still a conformant envelope. The gate validates the CONTRACT WIRING, not a real render.
|
|
332
|
+
input: { storyboard: { scenes: [{ prompt: "a quiet street at night" }] } },
|
|
333
|
+
config: {},
|
|
334
|
+
context: { project: "conformance", job_id: "install-gate" },
|
|
335
|
+
}),
|
|
336
|
+
});
|
|
337
|
+
if ("err" in probe || probe.status !== 200) {
|
|
338
|
+
const why = "err" in probe ? probe.err : `POST /invoke -> ${probe.status}`;
|
|
339
|
+
checks.push(bad("invoke", why));
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
const env = checkInvokeResponse(probe.body);
|
|
343
|
+
checks.push(env);
|
|
344
|
+
const b = probe.body;
|
|
345
|
+
// Typed output is validated ONLY for a synchronous answer. An async module returns pending here, and
|
|
346
|
+
// proving its output shape would mean polling its real (GPU) job to completion at install time --
|
|
347
|
+
// see the SCOPE note above; async output conformance is the module's own CI, not this gate.
|
|
348
|
+
if (env.pass && b.ok === true && b.pending !== true) {
|
|
349
|
+
checks.push(checkHookOutput(hook, b.output));
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// 3) degrade: a bad hook is DATA (HTTP 200 + ok:false), never a crash
|
|
353
|
+
const deg = await fetchJson(fetcher, "/invoke", {
|
|
354
|
+
method: "POST",
|
|
355
|
+
headers: { "content-type": "application/json" },
|
|
356
|
+
body: JSON.stringify({ hook: DEGRADE_PROBE_HOOK, input: {}, config: {}, context: { project: "conformance", job_id: "install-gate-degrade" } }),
|
|
357
|
+
});
|
|
358
|
+
if ("err" in deg || deg.status !== 200) {
|
|
359
|
+
const why = "err" in deg ? deg.err : `POST /invoke (bad hook) -> ${deg.status}`;
|
|
360
|
+
checks.push(bad("degrade", why));
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
const shape = checkInvokeResponse(deg.body);
|
|
364
|
+
const okFalse = !!deg.body && typeof deg.body === "object" && deg.body.ok === false;
|
|
365
|
+
checks.push(shape.pass && okFalse ? ok("degrade", "bad hook -> 200 + ok:false") : bad("degrade", "bad hook must return 200 + ok:false"));
|
|
366
|
+
}
|
|
367
|
+
return checks;
|
|
368
|
+
}
|
|
369
|
+
//# sourceMappingURL=conformance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conformance.js","sourceRoot":"","sources":["../../src/modules/conformance.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,EAAE;AACF,+FAA+F;AAC/F,8FAA8F;AAC9F,8FAA8F;AAC9F,iCAAiC;AACjC,6DAA6D;AAC7D,4FAA4F;AAC5F,EAAE;AACF,kGAAkG;AAClG,kGAAkG;AAClG,mFAAmF;AAEnF,OAAO,EAAE,qBAAqB,EAAiB,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAQ1D,MAAM,EAAE,GAAG,CAAC,IAAY,EAAE,MAAM,GAAG,IAAI,EAAoB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AAC7F,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,MAAc,EAAoB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;AAEhG,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC/D,MAAM,YAAY,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AAE3C,wFAAwF;AACxF,SAAS,gBAAgB,CAAC,GAAW,EAAE,CAAU;IAC/C,MAAM,KAAK,GAAG,SAAS,GAAG,GAAG,CAAC;IAC9B,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC,KAAK,EAAE,wBAAwB,CAAC,CAAC;IAC7E,MAAM,EAAE,GAAG,CAA4B,CAAC;IACxC,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;IAClB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,GAAG,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACxG,qGAAqG;IACrG,IAAI,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACjG,OAAO,GAAG,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,KAAK,MAAM,EAAE,CAAC;QACjB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,GAAG,CAAC,KAAK,EAAE,iCAAiC,CAAC,CAAC;QAC9G,IAAI,OAAO,EAAE,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAE,EAAE,CAAC,MAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;YACrF,OAAO,GAAG,CAAC,KAAK,EAAE,oCAAoC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;SAAM,IAAI,CAAC,KAAK,MAAM,EAAE,CAAC;QACxB,IAAI,OAAO,EAAE,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,GAAG,CAAC,KAAK,EAAE,gCAAgC,CAAC,CAAC;IAC3F,CAAC;SAAM,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC1B,IAAI,OAAO,EAAE,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAO,GAAG,CAAC,KAAK,EAAE,iCAAiC,CAAC,CAAC;IAC3F,CAAC;SAAM,CAAC;QACN,IAAI,OAAO,EAAE,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAO,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,2BAA2B,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,MAAM,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;QAChC,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACvD,MAAM,CAAC,IAAI,CAAE,qBAA6C,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC3E,CAAC,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAClC,CAAC,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,UAAU,GAAG,CAAC,GAAG,qBAAqB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3F,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7C,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;QACpB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5F,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC;QACnG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,kCAAkC,CAAC,CAAC,CAAC;IACtH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,+GAA+G;AAC/G,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC;IACpF,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;QAClB,IAAI,QAAQ,IAAI,CAAC;YAAE,OAAO,EAAE,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,CAAC;QACpE,IAAI,CAAC,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC,iBAAiB,EAAE,0BAA0B,CAAC,CAAC;QAC/G,OAAO,GAAG,CAAC,iBAAiB,EAAE,6CAA6C,CAAC,CAAC;IAC/E,CAAC;IACD,IAAI,CAAC,CAAC,EAAE,KAAK,KAAK;QAAE,OAAO,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,EAAE,oCAAoC,CAAC,CAAC;IAClK,OAAO,GAAG,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,CAAC;AACxD,CAAC;AAED;;;6EAG6E;AAC7E,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC;IACpF,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC;IAC3D,IAAI,CAAC,CAAC,EAAE,KAAK,KAAK;QAAE,OAAO,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,EAAE,oCAAoC,CAAC,CAAC;IAClK,OAAO,GAAG,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,CAAC;AACxD,CAAC;AAED,mGAAmG;AAEnG,MAAM,KAAK,GAAG,CAAC,CAAU,EAAgC,EAAE,CACzD,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACpD,MAAM,KAAK,GAAG,CAAC,CAAU,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;AACjE,MAAM,KAAK,GAAG,CAAC,CAAU,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvF,MAAM,QAAQ,GAAG,CAAC,CAAU,EAAiB,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAEnF;;;;;6CAK6C;AAC7C,MAAM,kBAAkB,GAAoE;IAC1F,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;QACd,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,wCAAwC,CAAC;QACvE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;YAAE,OAAO,qCAAqC,CAAC;QAC9E,MAAM,GAAG,GAAI,CAAC,CAAC,SAAuB,CAAC,IAAI,CACzC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAChE,CAAC;QACF,IAAI,GAAG;YAAE,OAAO,4CAA4C,CAAC;QAC7D,kEAAkE;QAClE,IAAI,CAAC,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;YAClC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC;gBAAE,OAAO,iDAAiD,CAAC;YACtF,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1D,OAAO,6DAA6D,CAAC;YACvE,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE;QACtB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,sCAAsC,CAAC;QACrE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAE,OAAO,uCAAuC,CAAC;QACvE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;YAAE,OAAO,mCAAmC,CAAC;QAC9D,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;YAAE,OAAO,sCAAsC,CAAC;QACpE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;QACZ,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,sCAAsC,CAAC;QACrE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAE,OAAO,uCAAuC,CAAC;QACvE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,uCAAuC,CAAC;QACtE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;YAAE,OAAO,sCAAsC,CAAC;QACpE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,yCAAyC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE;QACX,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAE,OAAO,sCAAsC,CAAC;QACtE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,wCAAwC,CAAC;QAC1E,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAE,OAAO,2EAA2E,CAAC;QACvI,OAAO,IAAI,CAAC;IACd,CAAC;IACD,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;QACd,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,wCAAwC,CAAC;QACvE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,OAAO,kCAAkC,CAAC;QACvE,MAAM,QAAQ,GAAI,CAAC,CAAC,KAAmB,CAAC,IAAI,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CACnF,CAAC;QACF,IAAI,QAAQ;YAAE,OAAO,0DAA0D,CAAC;QAChF,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,2CAA2C,CAAC;QAC7E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;QACZ,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,sCAAsC,CAAC;QACrE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;YAAE,OAAO,wCAAwC,CAAC;QACzE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,yCAAyC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE;QACpB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;YAAE,OAAO,+CAA+C,CAAC;QACjF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAE,CAAC,CAAC,UAAsC,CAAC,MAAM,CAAC,EAAE,CAAC;YACrE,OAAO,0CAA0C,CAAC;QACpD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE;QAClB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,2CAA2C,CAAC;QAC1E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;YAAE,OAAO,qCAAqC,CAAC;QAC3E,MAAM,GAAG,GAAI,CAAC,CAAC,MAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9F,IAAI,GAAG;YAAE,OAAO,kCAAkC,CAAC;QACnD,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,6CAA6C,CAAC;QAC/E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;QACZ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;YAAE,OAAO,0CAA0C,CAAC;QAC9E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;QACZ,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;YAAE,OAAO,wCAAwC,CAAC;QACzE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,yCAAyC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE;QACnB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAE,OAAO,4CAA4C,CAAC;QAC5E,oGAAoG;QACpG,+FAA+F;QAC/F,2DAA2D;QAC3D,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,OAAO,uDAAuD,CAAC;QACpH,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAE,OAAO,4EAA4E,CAAC;QACxI,IAAI,CAAC,CAAC,eAAe,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,CAAC,eAAe,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,eAAe,GAAG,CAAC,CAAC;YAAE,OAAO,iFAAiF,CAAC;QACzO,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC;AAEF;;;4EAG4E;AAC5E,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,MAAe;IAC3D,MAAM,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC;IAC/B,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAgB,CAAC,CAAC;IACvD,IAAI,CAAC,SAAS;QAAE,OAAO,GAAG,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC,CAAC;IAC1D,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,GAAG,CAAC,KAAK,EAAE,yBAAyB,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;AACjD,CAAC;AAED;;;;;;;;0GAQ0G;AAC1G,MAAM,UAAU,mBAAmB,CAAC,QAAgB,EAAE,IAAY,EAAE,MAAe;IACjF,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,QAAQ,aAAa,IAAI,cAAc,KAAK,CAAC,MAAM,EAAE,CAAC;AAC7F,CAAC;AAED,mCAAmC;AACnC,MAAM,UAAU,OAAO,CAAC,MAA0B;IAChD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,QAAQ,CAAC,MAA0B;IACjD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAUD,uGAAuG;AACvG,oEAAoE;AACpE,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAE7C,KAAK,UAAU,SAAS,CACtB,OAA2B,EAC3B,IAAY,EACZ,IAAkB;IAElB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,gBAAgB,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC;QAC/D,IAAI,IAAI,GAAY,IAAI,CAAC;QACzB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC1B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,kBAAmB,CAAW,CAAC,OAAO,EAAE,EAAE,CAAC;QAC3F,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IACtC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,gBAAiB,CAAW,CAAC,OAAO,EAAE,EAAE,CAAC;IAChF,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;yCAiByC;AACzC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAA2B;IAClE,MAAM,MAAM,GAAuB,EAAE,CAAC;IAEtC,cAAc;IACd,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IACrD,IAAI,KAAK,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,uBAAuB,GAAG,CAAC,MAAM,EAAE,CAAC;QACzE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;QAClC,OAAO,MAAM,CAAC,CAAC,0DAA0D;IAC3E,CAAC;IACD,MAAM,cAAc,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,CAAC,6CAA6C;IAE9F,gFAAgF;IAChF,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,SAAS,EAAE;QAChD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,IAAI;YACJ,+FAA+F;YAC/F,0FAA0F;YAC1F,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAC,EAAE,EAAE;YAC1E,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE;SAC5D,CAAC;KACH,CAAC,CAAC;IACH,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,mBAAmB,KAAK,CAAC,MAAM,EAAE,CAAC;QAC3E,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,GAAG,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjB,MAAM,CAAC,GAAG,KAAK,CAAC,IAA6D,CAAC;QAC9E,qGAAqG;QACrG,kGAAkG;QAClG,4FAA4F;QAC5F,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YACpD,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAED,sEAAsE;IACtE,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,SAAS,EAAE;QAC9C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,sBAAsB,EAAE,EAAE,CAAC;KAC/I,CAAC,CAAC;IACH,IAAI,KAAK,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,8BAA8B,GAAG,CAAC,MAAM,EAAE,CAAC;QAChF,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;IACnC,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAK,GAAG,CAAC,IAAyB,CAAC,EAAE,KAAK,KAAK,CAAC;QAC1G,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,EAAE,4BAA4B,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,qCAAqC,CAAC,CAAC,CAAC;IAC3I,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type ModuleManifest } from "./types.js";
|
|
2
|
+
/** Validate a parsed manifest enough to trust it in the registry. Returns the typed manifest or a
|
|
3
|
+
* reason string. We check the contract version, a name, and that every declared hook is known. */
|
|
4
|
+
export declare function validateManifest(raw: unknown): ModuleManifest | string;
|
|
5
|
+
//# sourceMappingURL=manifest-validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-validate.d.ts","sourceRoot":"","sources":["../../src/modules/manifest-validate.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAEpB;mGACmG;AACnG,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,GAAG,MAAM,CA0CtE"}
|