@world-engines/scenario-review-snapshot 0.0.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,118 @@
1
+ import type { ArtifactV5, ArtifactCompilerWitnessIdentity, FrozenArtifactBundle, FrozenArtifactObjectIdentity, PublishedArtifactHead, Sha256Hex } from "./artifact.js";
2
+ declare const frozenArtifactPrefixBrand: unique symbol;
3
+ declare const frozenArtifactObjectKeyBrand: unique symbol;
4
+ declare const publishOperationKeyBrand: unique symbol;
5
+ export type FrozenArtifactPrefix = string & {
6
+ readonly [frozenArtifactPrefixBrand]: true;
7
+ };
8
+ export type FrozenArtifactObjectKey = string & {
9
+ readonly [frozenArtifactObjectKeyBrand]: true;
10
+ };
11
+ export type PublishOperationKey = string & {
12
+ readonly [publishOperationKeyBrand]: true;
13
+ };
14
+ export interface WriteOnceArtifactObject {
15
+ readonly key: FrozenArtifactObjectKey;
16
+ readonly sha256: Sha256Hex;
17
+ readonly size_bytes: number;
18
+ readonly bytes: Uint8Array;
19
+ }
20
+ export interface ArtifactObjectReadbackReceipt {
21
+ readonly key: FrozenArtifactObjectKey;
22
+ readonly kind: FrozenArtifactObjectIdentity["kind"];
23
+ readonly relative_path: string;
24
+ readonly media_type: string;
25
+ readonly sha256: Sha256Hex;
26
+ readonly size_bytes: number;
27
+ }
28
+ export type WriteOncePutResult = {
29
+ readonly disposition: "created";
30
+ readonly key: FrozenArtifactObjectKey;
31
+ readonly sha256: Sha256Hex;
32
+ } | {
33
+ readonly disposition: "already_exists_identical";
34
+ readonly key: FrozenArtifactObjectKey;
35
+ readonly sha256: Sha256Hex;
36
+ };
37
+ /** 已存在但 hash/size 不同必须抛冲突,不得覆盖。 */
38
+ export interface WriteOnceArtifactStore {
39
+ /** 实现必须先重算 bytes 的 hash/size,再执行 conditional create。 */
40
+ putIfAbsent(object: WriteOnceArtifactObject): Promise<WriteOncePutResult>;
41
+ readVerified(key: FrozenArtifactObjectKey, expected: Readonly<{
42
+ sha256: Sha256Hex;
43
+ size_bytes: number;
44
+ }>): Promise<Uint8Array>;
45
+ }
46
+ export interface SubmitFrozenArtifactInput {
47
+ readonly operation_key: PublishOperationKey;
48
+ readonly bundle: FrozenArtifactBundle;
49
+ readonly expected_previous_head_digest: Sha256Hex | null;
50
+ }
51
+ export interface SubmittedPublishAttempt {
52
+ readonly attempt_id: string;
53
+ readonly operation_key: PublishOperationKey;
54
+ readonly scenario_id: string;
55
+ readonly epoch: number;
56
+ readonly runtime_contract_hash: Sha256Hex;
57
+ readonly source_revision_digest: Sha256Hex;
58
+ readonly artifact_canonical_digest: Sha256Hex;
59
+ /**
60
+ * Parsed from the submitted witness objects after their bytes are matched
61
+ * against the ArtifactV5 resource identities. It is never trusted from a
62
+ * parallel request field or response echo.
63
+ */
64
+ readonly compiler_witness: ArtifactCompilerWitnessIdentity;
65
+ /** 由受信服务端从冻结对象生成,不能由 Creator 自报。 */
66
+ readonly review_snapshot_hash: Sha256Hex;
67
+ readonly review_coverage_hash: Sha256Hex;
68
+ readonly state: PublishAttemptState;
69
+ readonly object_readbacks: readonly ArtifactObjectReadbackReceipt[];
70
+ }
71
+ export type PublishAttemptState = "pending_review" | "claimed" | "approved" | "warning" | "rejected" | "needs_info" | "scheduled" | "published";
72
+ export interface FinalizeApprovedArtifactInput {
73
+ readonly attempt_id: string;
74
+ readonly scenario_id: string;
75
+ readonly epoch: number;
76
+ readonly runtime_contract_hash: Sha256Hex;
77
+ readonly source_revision_digest: Sha256Hex;
78
+ readonly artifact_canonical_digest: Sha256Hex;
79
+ readonly expected_previous_head_digest: Sha256Hex | null;
80
+ }
81
+ export type FinalizeApprovedArtifactResult = {
82
+ readonly disposition: "published";
83
+ readonly head: PublishedArtifactHead;
84
+ } | {
85
+ readonly disposition: "already_published_identical";
86
+ readonly head: PublishedArtifactHead;
87
+ };
88
+ export interface ResolvePublishedArtifactInput {
89
+ readonly scenario_id: string;
90
+ readonly epoch: number;
91
+ readonly runtime_contract_hash: Sha256Hex;
92
+ /** 必填;禁止退化为“当前 ScenarioRecord”。 */
93
+ readonly artifact_canonical_digest: Sha256Hex;
94
+ }
95
+ export interface ResolvedPublishedArtifact {
96
+ readonly artifact: ArtifactV5;
97
+ readonly head: PublishedArtifactHead;
98
+ readonly object_reader: PublishedArtifactObjectReader;
99
+ readonly object_readbacks: readonly ArtifactObjectReadbackReceipt[];
100
+ }
101
+ export interface PublishedArtifactObjectReader {
102
+ readonly objects: readonly FrozenArtifactObjectIdentity[];
103
+ /** 实现必须拒绝不属于 `objects` 的 identity。 */
104
+ readVerified(object: FrozenArtifactObjectIdentity): Promise<Uint8Array>;
105
+ }
106
+ /**
107
+ * 深模块接口:submit 只创建待审 attempt;approval 不发布;只有显式 finalize 才创建 head。
108
+ */
109
+ export interface PublishAttemptCoordinator {
110
+ /** 实现进入 Interface seam 后必须立即 parse/copy bundle,且不得在 copy 前 await。 */
111
+ submitFrozenArtifact(input: SubmitFrozenArtifactInput): Promise<SubmittedPublishAttempt>;
112
+ finalizeApprovedArtifact(input: FinalizeApprovedArtifactInput): Promise<FinalizeApprovedArtifactResult>;
113
+ resolvePublishedArtifact(input: ResolvePublishedArtifactInput): Promise<ResolvedPublishedArtifact>;
114
+ }
115
+ export declare function publishOperationKey(value: string): PublishOperationKey;
116
+ export declare function buildFrozenArtifactPrefix(scenarioId: string, canonicalDigest: Sha256Hex): FrozenArtifactPrefix;
117
+ export declare function buildFrozenArtifactObjectKey(scenarioId: string, canonicalDigest: Sha256Hex, relativePath: string): FrozenArtifactObjectKey;
118
+ export {};
@@ -0,0 +1,33 @@
1
+ const SHA256_PATTERN = /^[0-9a-f]{64}$/u;
2
+ const OPERATION_KEY_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
3
+ export function publishOperationKey(value) {
4
+ if (!OPERATION_KEY_PATTERN.test(value))
5
+ throw new Error("publish_operation_key_invalid");
6
+ return value;
7
+ }
8
+ export function buildFrozenArtifactPrefix(scenarioId, canonicalDigest) {
9
+ const scenario = requireSegment(scenarioId, "frozen_artifact_scenario_id_invalid");
10
+ if (!SHA256_PATTERN.test(canonicalDigest))
11
+ throw new Error("frozen_artifact_digest_invalid");
12
+ return `scenario-releases/${encodeURIComponent(scenario)}/${canonicalDigest}`;
13
+ }
14
+ export function buildFrozenArtifactObjectKey(scenarioId, canonicalDigest, relativePath) {
15
+ const prefix = buildFrozenArtifactPrefix(scenarioId, canonicalDigest);
16
+ const path = requireRelativePath(relativePath);
17
+ return `${prefix}/${path}`;
18
+ }
19
+ function requireSegment(value, code) {
20
+ if (typeof value !== "string" || value.length === 0 || value.trim() !== value || value.normalize("NFC") !== value) {
21
+ throw new Error(code);
22
+ }
23
+ return value;
24
+ }
25
+ function requireRelativePath(value) {
26
+ const path = requireSegment(value, "frozen_artifact_object_relative_path_invalid");
27
+ if (path.startsWith("/")
28
+ || path.endsWith("/")
29
+ || path.includes("\\")
30
+ || path.split("/").some((part) => part.length === 0 || part === "." || part === ".."))
31
+ throw new Error("frozen_artifact_object_relative_path_invalid");
32
+ return path;
33
+ }
@@ -0,0 +1,26 @@
1
+ import { type CompileTargetProfile } from "@world-engines/tmw";
2
+ import { type ProjectFileTree } from "@world-engines/chatplay-vite-plugin/project-sync";
3
+ import type { ServerBoundViewCompiler, ServerBoundViewProjectCodec } from "./bound-view-freeze.js";
4
+ /**
5
+ * Sandbox Node build worker 的唯一运行时依赖。gzip-tar codec 必须来自同一受信
6
+ * worker image;snapshot 包不依赖 creator-editor/browser implementation。
7
+ */
8
+ export interface SandboxNodeGzipTarCodec {
9
+ pack(project: ProjectFileTree): Promise<Uint8Array>;
10
+ unpack(bytes: Uint8Array): Promise<ProjectFileTree>;
11
+ }
12
+ export interface CreateSandboxNodeBoundViewCompilerOptions {
13
+ /** 已经由 worker admission 选定的 active compiler profile。 */
14
+ readonly target_profile: CompileTargetProfile;
15
+ readonly gzip_tar: SandboxNodeGzipTarCodec;
16
+ }
17
+ export interface SandboxNodeBoundViewCompiler {
18
+ readonly codec: ServerBoundViewProjectCodec<ProjectFileTree>;
19
+ readonly compiler: ServerBoundViewCompiler<ProjectFileTree>;
20
+ }
21
+ /**
22
+ * 给 server build worker 的实际 factory:SVP decode 是固定生产 codec,TMW
23
+ * registry/cache/compiler 也固定;只有 worker image 的 gzip-tar implementation
24
+ * 需要注入,保证 source pack/unpack 是同一可信 codec。
25
+ */
26
+ export declare function createSandboxNodeBoundViewCompiler(options: CreateSandboxNodeBoundViewCompilerOptions): SandboxNodeBoundViewCompiler;
@@ -0,0 +1,34 @@
1
+ import { InMemoryCompilerStageCache, buildCurrentTmw3NeutralCompilerStageRegistry, compileNeutralScenarioSource, } from "@world-engines/tmw";
2
+ import { decodeSvp, } from "@world-engines/chatplay-vite-plugin/project-sync";
3
+ import { materializeNeutralArtifactCompilation, } from "./neutral-artifact-assembler.js";
4
+ /**
5
+ * 给 server build worker 的实际 factory:SVP decode 是固定生产 codec,TMW
6
+ * registry/cache/compiler 也固定;只有 worker image 的 gzip-tar implementation
7
+ * 需要注入,保证 source pack/unpack 是同一可信 codec。
8
+ */
9
+ export function createSandboxNodeBoundViewCompiler(options) {
10
+ const stages = buildCurrentTmw3NeutralCompilerStageRegistry();
11
+ const cache = new InMemoryCompilerStageCache();
12
+ const codec = Object.freeze({
13
+ decode_svp(bytes) {
14
+ return decodeSvp(bytes);
15
+ },
16
+ async pack_gzip_tar(project) {
17
+ const packed = await options.gzip_tar.pack(project);
18
+ if (!(packed instanceof Uint8Array) || packed.byteLength === 0) {
19
+ throw new Error("server_bound_view_gzip_tar_pack_invalid");
20
+ }
21
+ return packed.slice();
22
+ },
23
+ });
24
+ const compiler = Object.freeze({
25
+ async compile(source) {
26
+ const outcome = await compileNeutralScenarioSource(source, options.target_profile, stages, cache);
27
+ if (!outcome.ok) {
28
+ throw new Error(`server_bound_view_compile_failed:${outcome.diagnostics.map((item) => item.code).join(",")}`);
29
+ }
30
+ return await materializeNeutralArtifactCompilation(source, options.target_profile, outcome, async (bytes) => await options.gzip_tar.unpack(bytes));
31
+ },
32
+ });
33
+ return Object.freeze({ codec, compiler });
34
+ }
@@ -0,0 +1,5 @@
1
+ import type { JsonValue, ScenarioReviewFragment, ScenarioReviewRecord, ScenarioReviewSnapshot, ScenarioReviewSnapshotInput, ScenarioReviewSnapshotLimits } from "./types.js";
2
+ export declare const DEFAULT_SCENARIO_REVIEW_SNAPSHOT_LIMITS: ScenarioReviewSnapshotLimits;
3
+ export declare function stableRelationId(edge: JsonValue): string;
4
+ export declare function buildScenarioReviewSnapshot(rawInput: ScenarioReviewSnapshotInput, rawLimits?: Partial<ScenarioReviewSnapshotLimits>): ScenarioReviewSnapshot;
5
+ export declare function reconstructRecordPayload(record: ScenarioReviewRecord, fragments: readonly ScenarioReviewFragment[]): JsonValue;