@lostgradient/weft 0.17.0 → 0.19.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/README.md +3 -1
- package/dist/cli/conformance.js +14 -18
- package/dist/cli/generated/operation-catalog.snapshot.json +331 -16
- package/dist/cli/generated/operation-client.generated.d.ts +39 -6
- package/dist/cli/generated/operation-client.generated.js +6 -0
- package/dist/core/context/child-workflow-pipe.d.ts +1 -1
- package/dist/core/context/child-workflow-pipe.js +1 -1
- package/dist/core/engine/construction.d.ts +2 -0
- package/dist/core/engine/construction.js +3 -0
- package/dist/core/engine/index.js +1 -0
- package/dist/core/engine/listing.d.ts +1 -0
- package/dist/core/engine/listing.js +6 -4
- package/dist/core/weft-error.d.ts +1 -1
- package/dist/core/weft-error.js +2 -1
- package/dist/core/worker-execution-dispatcher.d.ts +8 -0
- package/dist/core/worker-execution-dispatcher.js +4 -0
- package/dist/core/worker-execution-strategy-options.d.ts +16 -0
- package/dist/core/worker-execution-strategy.js +71 -89
- package/dist/core/worker-fault-handling.d.ts +45 -0
- package/dist/core/worker-fault-handling.js +88 -0
- package/dist/core/worker-protocol.d.ts +18 -1
- package/dist/core/worker-protocol.js +1 -1
- package/dist/core/worker-realm-readiness.d.ts +78 -0
- package/dist/core/worker-realm-readiness.js +127 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +28 -1
- package/dist/json-schema.js +1 -1
- package/dist/runtime/portable.d.ts +14 -0
- package/dist/runtime/portable.js +10 -0
- package/dist/server/authorization-scope.d.ts +32 -2
- package/dist/server/index.d.ts +73 -8
- package/dist/server/index.js +11 -3
- package/dist/server/operations/get-principal.d.ts +75 -0
- package/dist/server/operations/get-principal.js +41 -0
- package/dist/server/operations/get-task-diagnostics.d.ts +43 -18
- package/dist/server/operations/get-task-diagnostics.js +87 -126
- package/dist/server/operations/get-worker-diagnostics.d.ts +177 -0
- package/dist/server/operations/get-worker-diagnostics.js +117 -0
- package/dist/server/operations/list-worker-registration-rejections.d.ts +79 -0
- package/dist/server/operations/list-worker-registration-rejections.js +60 -0
- package/dist/server/operations/list-workers.js +1 -3
- package/dist/server/operations/static-registrations.d.ts +28 -0
- package/dist/server/operations/static-registrations.js +248 -0
- package/dist/server/rest-bindings.d.ts +5 -0
- package/dist/server/rest-bindings.js +34 -313
- package/dist/server/runtime/authentication-bridge.js +6 -14
- package/dist/server/runtime/context.d.ts +23 -0
- package/dist/server/runtime/task-dispatch.d.ts +7 -1
- package/dist/server/runtime/task-dispatch.js +126 -55
- package/dist/server/runtime/task-ledger-completion.d.ts +68 -0
- package/dist/server/runtime/task-ledger-completion.js +72 -0
- package/dist/server/runtime/task-ledger-recovery.d.ts +55 -0
- package/dist/server/runtime/task-ledger-recovery.js +73 -0
- package/dist/server/runtime/task-ledger-runtime.d.ts +64 -0
- package/dist/server/runtime/task-ledger-runtime.js +34 -0
- package/dist/server/runtime/task-metrics.d.ts +6 -4
- package/dist/server/runtime/task-polling.d.ts +14 -12
- package/dist/server/runtime/task-polling.js +106 -82
- package/dist/server/runtime/task-reconciliation.d.ts +35 -8
- package/dist/server/runtime/task-reconciliation.js +75 -74
- package/dist/server/runtime/task-result-resolution.d.ts +2 -10
- package/dist/server/runtime/task-result-resolution.js +0 -67
- package/dist/server/runtime/task-result-view.d.ts +82 -0
- package/dist/server/runtime/task-result-view.js +48 -0
- package/dist/server/runtime/websocket-worker-messaging.d.ts +16 -0
- package/dist/server/runtime/websocket-worker-messaging.js +32 -0
- package/dist/server/runtime/websocket-worker-registration.d.ts +41 -0
- package/dist/server/runtime/websocket-worker-registration.js +134 -0
- package/dist/server/runtime/websocket-worker.d.ts +0 -1
- package/dist/server/runtime/websocket-worker.js +64 -116
- package/dist/server/serve-internals.d.ts +9 -6
- package/dist/server/serve-internals.js +14 -40
- package/dist/server/task-ledger-codec.d.ts +40 -0
- package/dist/server/task-ledger-codec.js +195 -0
- package/dist/server/task-ledger-keys.d.ts +13 -0
- package/dist/server/task-ledger-keys.js +5 -0
- package/dist/server/task-ledger-limits.d.ts +34 -0
- package/dist/server/task-ledger-limits.js +5 -0
- package/dist/server/task-ledger-transition-helpers.d.ts +38 -0
- package/dist/server/task-ledger-transition-helpers.js +42 -0
- package/dist/server/task-ledger-transitions-cancellation.d.ts +31 -0
- package/dist/server/task-ledger-transitions-cancellation.js +73 -0
- package/dist/server/task-ledger-transitions.d.ts +129 -0
- package/dist/server/task-ledger-transitions.js +162 -0
- package/dist/server/task-ledger-types.d.ts +220 -0
- package/dist/server/task-ledger-types.js +1 -0
- package/dist/server/task-ledger.d.ts +17 -0
- package/dist/server/task-ledger.js +24 -0
- package/dist/server/task-state.d.ts +25 -152
- package/dist/server/task-state.js +0 -188
- package/dist/server/worker-admission-policy.d.ts +70 -0
- package/dist/server/worker-admission-policy.js +0 -0
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/index.d.ts +0 -2
- package/dist/storage/interface.d.ts +0 -2
- package/dist/storage/interface.js +1 -1
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +1 -1
- package/dist/storage/postgres.js +1 -1
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +1 -1
- package/dist/storage/web-extension.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -1
- package/dist/worker/index.d.ts +2 -0
- package/dist/worker/index.js +30 -4
- package/dist/worker/manifest/canonical-json.d.ts +20 -0
- package/dist/worker/manifest/canonical-json.js +13 -0
- package/dist/worker/manifest/capabilities.d.ts +24 -0
- package/dist/worker/manifest/capabilities.js +74 -0
- package/dist/worker/manifest/content-digest.d.ts +20 -0
- package/dist/worker/manifest/content-digest.js +13 -0
- package/dist/worker/manifest/declared-shape-digest.d.ts +14 -0
- package/dist/worker/manifest/declared-shape-digest.js +4 -0
- package/dist/worker/manifest/digest.d.ts +82 -0
- package/dist/worker/manifest/digest.js +9 -0
- package/dist/worker/manifest/execution-identity.d.ts +92 -0
- package/dist/worker/manifest/execution-identity.js +36 -0
- package/dist/worker/manifest/failure.d.ts +59 -0
- package/dist/worker/manifest/failure.js +4 -0
- package/dist/worker/manifest/index.d.ts +22 -0
- package/dist/worker/manifest/index.js +23 -0
- package/dist/worker/manifest/internal-realm.d.ts +50 -0
- package/dist/worker/manifest/internal-realm.js +39 -0
- package/dist/worker/manifest/is-record.d.ts +12 -0
- package/dist/worker/manifest/is-record.js +6 -0
- package/dist/worker/manifest/json-scan.d.ts +26 -0
- package/dist/worker/manifest/json-scan.js +88 -0
- package/dist/worker/manifest/limits.d.ts +138 -0
- package/dist/worker/manifest/limits.js +1 -0
- package/dist/worker/manifest/normalize.d.ts +63 -0
- package/dist/worker/manifest/normalize.js +73 -0
- package/dist/worker/manifest/parse-json.d.ts +24 -0
- package/dist/worker/manifest/parse-json.js +15 -0
- package/dist/worker/manifest/parse.d.ts +86 -0
- package/dist/worker/manifest/parse.js +188 -0
- package/dist/worker/manifest/registry-contract-builder.d.ts +120 -0
- package/dist/worker/manifest/registry-contract-builder.js +65 -0
- package/dist/worker/manifest/types.d.ts +263 -0
- package/dist/worker/manifest/types.js +1 -0
- package/dist/worker/manifest/utf8.d.ts +13 -0
- package/dist/worker/manifest/utf8.js +7 -0
- package/dist/worker/options.d.ts +55 -8
- package/dist/worker/options.js +65 -9
- package/dist/worker/protocol-internals.d.ts +1 -2
- package/dist/worker/protocol-internals.js +0 -5
- package/dist/worker/protocol-messages.d.ts +33 -17
- package/dist/worker/protocol-schemas.d.ts +36 -74
- package/dist/worker/protocol-schemas.js +25 -18
- package/dist/worker/protocol-version.d.ts +18 -14
- package/dist/worker/protocol-version.js +1 -1
- package/dist/worker/protocol.js +1 -1
- package/dist/worker/registry/deployment-consistency.d.ts +78 -0
- package/dist/worker/registry/deployment-consistency.js +27 -0
- package/dist/worker/registry/drain.d.ts +14 -0
- package/dist/worker/registry/drain.js +24 -0
- package/dist/worker/registry/rejections.d.ts +31 -0
- package/dist/worker/registry/rejections.js +10 -0
- package/dist/worker/registry/summary.d.ts +0 -3
- package/dist/worker/registry/summary.js +2 -5
- package/dist/worker/registry/types.d.ts +10 -3
- package/dist/worker/registry.d.ts +47 -2
- package/dist/worker/registry.js +45 -32
- package/dist/workers/workflow-worker-entry.d.ts +12 -7
- package/dist/workers/workflow-worker-entry.js +9 -2
- package/package.json +3 -3
- package/dist/server/task-resolved-record.d.ts +0 -12
- package/dist/server/task-resolved-record.js +0 -35
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { validateWorkflowOrActivityName } from "../../core/types/name-grammar.js";
|
|
2
|
+
import { parseManifestCapabilities } from "./capabilities.js";
|
|
3
|
+
import { manifestFailure } from "./failure.js";
|
|
4
|
+
import { isRecord } from "./is-record.js";
|
|
5
|
+
import {
|
|
6
|
+
MAX_MANIFEST_ACTIVITY_COUNT,
|
|
7
|
+
MAX_MANIFEST_IDENTIFIER_BYTES,
|
|
8
|
+
MAX_MANIFEST_WORKFLOW_COUNT,
|
|
9
|
+
MAX_NORMALIZED_MANIFEST_BYTES
|
|
10
|
+
} from "./limits.js";
|
|
11
|
+
import { canonicalWorkerManifestJson, normalizeWorkerManifest } from "./normalize.js";
|
|
12
|
+
import { WORKER_MANIFEST_VERSION } from "./types.js";
|
|
13
|
+
import { utf8ByteLength } from "./utf8.js";
|
|
14
|
+
function parseIdentifier(value, path) {
|
|
15
|
+
if (typeof value !== "string" || value.length === 0)
|
|
16
|
+
return manifestFailure("invalid_field", "must be a non-empty string", path);
|
|
17
|
+
const bytes = utf8ByteLength(value);
|
|
18
|
+
if (bytes > MAX_MANIFEST_IDENTIFIER_BYTES)
|
|
19
|
+
return manifestFailure("identifier_too_long", `is ${bytes} bytes, exceeding the maximum identifier size of ${MAX_MANIFEST_IDENTIFIER_BYTES}`, path);
|
|
20
|
+
return { ok: !0, value };
|
|
21
|
+
}
|
|
22
|
+
function checkKey(key, kind, path) {
|
|
23
|
+
if (key.length === 0)
|
|
24
|
+
return manifestFailure("invalid_field", "must not be an empty string", path);
|
|
25
|
+
const bytes = utf8ByteLength(key);
|
|
26
|
+
if (bytes > MAX_MANIFEST_IDENTIFIER_BYTES)
|
|
27
|
+
return manifestFailure("identifier_too_long", `is ${bytes} bytes, exceeding the maximum identifier size of ${MAX_MANIFEST_IDENTIFIER_BYTES}`, path);
|
|
28
|
+
try {
|
|
29
|
+
validateWorkflowOrActivityName(key, kind);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
return manifestFailure("invalid_field", error instanceof Error ? error.message : "is not a wire-safe name", path);
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
function parseProtocolVersion(value) {
|
|
36
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)
|
|
37
|
+
return manifestFailure("invalid_field", "must be a positive safe integer", "manifest.protocolVersion");
|
|
38
|
+
return { ok: !0, value };
|
|
39
|
+
}
|
|
40
|
+
function parseRuntime(value, path) {
|
|
41
|
+
if (!isRecord(value))
|
|
42
|
+
return manifestFailure("invalid_field", "must be a JSON object", path);
|
|
43
|
+
const name = parseIdentifier(value.name, `${path}.name`);
|
|
44
|
+
if (!name.ok)
|
|
45
|
+
return name;
|
|
46
|
+
const rawVersion = value.version;
|
|
47
|
+
if (typeof rawVersion !== "string")
|
|
48
|
+
return manifestFailure("invalid_field", "must be a string", `${path}.version`);
|
|
49
|
+
const versionBytes = utf8ByteLength(rawVersion);
|
|
50
|
+
if (versionBytes > MAX_MANIFEST_IDENTIFIER_BYTES)
|
|
51
|
+
return manifestFailure("identifier_too_long", `is ${versionBytes} bytes, exceeding the maximum identifier size of ${MAX_MANIFEST_IDENTIFIER_BYTES}`, `${path}.version`);
|
|
52
|
+
return { ok: !0, runtime: { name: name.value, version: rawVersion } };
|
|
53
|
+
}
|
|
54
|
+
function parseDeployment(value, path) {
|
|
55
|
+
if (!isRecord(value))
|
|
56
|
+
return manifestFailure("invalid_field", "must be a JSON object", path);
|
|
57
|
+
const name = parseIdentifier(value.name, `${path}.name`);
|
|
58
|
+
if (!name.ok)
|
|
59
|
+
return name;
|
|
60
|
+
const buildId = parseIdentifier(value.buildId, `${path}.buildId`);
|
|
61
|
+
if (!buildId.ok)
|
|
62
|
+
return buildId;
|
|
63
|
+
const artifactDigest = parseIdentifier(value.artifactDigest, `${path}.artifactDigest`);
|
|
64
|
+
if (!artifactDigest.ok)
|
|
65
|
+
return artifactDigest;
|
|
66
|
+
return {
|
|
67
|
+
ok: !0,
|
|
68
|
+
deployment: {
|
|
69
|
+
name: name.value,
|
|
70
|
+
buildId: buildId.value,
|
|
71
|
+
artifactDigest: artifactDigest.value
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function parseActivity(value, path) {
|
|
76
|
+
if (!isRecord(value))
|
|
77
|
+
return manifestFailure("invalid_field", "must be a JSON object", path);
|
|
78
|
+
const contractHash = parseIdentifier(value.contractHash, `${path}.contractHash`);
|
|
79
|
+
if (!contractHash.ok)
|
|
80
|
+
return contractHash;
|
|
81
|
+
const implementationRevision = parseIdentifier(value.implementationRevision, `${path}.implementationRevision`);
|
|
82
|
+
if (!implementationRevision.ok)
|
|
83
|
+
return implementationRevision;
|
|
84
|
+
return {
|
|
85
|
+
ok: !0,
|
|
86
|
+
activity: {
|
|
87
|
+
contractHash: contractHash.value,
|
|
88
|
+
implementationRevision: implementationRevision.value
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function parseActivities(value, path) {
|
|
93
|
+
if (!isRecord(value))
|
|
94
|
+
return manifestFailure("invalid_field", "must be a JSON object", path);
|
|
95
|
+
const names = Object.keys(value);
|
|
96
|
+
if (names.length > MAX_MANIFEST_ACTIVITY_COUNT)
|
|
97
|
+
return manifestFailure("too_many_activities", `declares ${names.length} activities, exceeding the maximum of ${MAX_MANIFEST_ACTIVITY_COUNT}`, path);
|
|
98
|
+
const activities = Object.create(null);
|
|
99
|
+
for (const name of names) {
|
|
100
|
+
const keyFailure = checkKey(name, "activity", `${path} key ${JSON.stringify(name)}`);
|
|
101
|
+
if (keyFailure !== void 0)
|
|
102
|
+
return keyFailure;
|
|
103
|
+
const activity = parseActivity(value[name], `${path}.${name}`);
|
|
104
|
+
if (!activity.ok)
|
|
105
|
+
return activity;
|
|
106
|
+
activities[name] = activity.activity;
|
|
107
|
+
}
|
|
108
|
+
return { ok: !0, activities };
|
|
109
|
+
}
|
|
110
|
+
function parseWorkflow(value, path) {
|
|
111
|
+
if (!isRecord(value))
|
|
112
|
+
return manifestFailure("invalid_field", "must be a JSON object", path);
|
|
113
|
+
const workflowVersion = parseIdentifier(value.workflowVersion, `${path}.workflowVersion`);
|
|
114
|
+
if (!workflowVersion.ok)
|
|
115
|
+
return workflowVersion;
|
|
116
|
+
const workflowRevision = parseIdentifier(value.workflowRevision, `${path}.workflowRevision`);
|
|
117
|
+
if (!workflowRevision.ok)
|
|
118
|
+
return workflowRevision;
|
|
119
|
+
const contractHash = parseIdentifier(value.contractHash, `${path}.contractHash`);
|
|
120
|
+
if (!contractHash.ok)
|
|
121
|
+
return contractHash;
|
|
122
|
+
const activities = parseActivities(value.activities, `${path}.activities`);
|
|
123
|
+
if (!activities.ok)
|
|
124
|
+
return activities;
|
|
125
|
+
return {
|
|
126
|
+
ok: !0,
|
|
127
|
+
workflow: {
|
|
128
|
+
workflowVersion: workflowVersion.value,
|
|
129
|
+
workflowRevision: workflowRevision.value,
|
|
130
|
+
contractHash: contractHash.value,
|
|
131
|
+
activities: activities.activities
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function parseWorkflows(value, path) {
|
|
136
|
+
if (!isRecord(value))
|
|
137
|
+
return manifestFailure("invalid_field", "must be a JSON object", path);
|
|
138
|
+
const names = Object.keys(value);
|
|
139
|
+
if (names.length > MAX_MANIFEST_WORKFLOW_COUNT)
|
|
140
|
+
return manifestFailure("too_many_workflows", `declares ${names.length} workflows, exceeding the maximum of ${MAX_MANIFEST_WORKFLOW_COUNT}`, path);
|
|
141
|
+
const workflows = Object.create(null);
|
|
142
|
+
for (const name of names) {
|
|
143
|
+
const keyFailure = checkKey(name, "workflow", `${path} key ${JSON.stringify(name)}`);
|
|
144
|
+
if (keyFailure !== void 0)
|
|
145
|
+
return keyFailure;
|
|
146
|
+
const workflow = parseWorkflow(value[name], `${path}.${name}`);
|
|
147
|
+
if (!workflow.ok)
|
|
148
|
+
return workflow;
|
|
149
|
+
workflows[name] = workflow.workflow;
|
|
150
|
+
}
|
|
151
|
+
return { ok: !0, workflows };
|
|
152
|
+
}
|
|
153
|
+
export function parseWorkerManifest(value) {
|
|
154
|
+
if (!isRecord(value))
|
|
155
|
+
return manifestFailure("not_an_object", "manifest must be a JSON object");
|
|
156
|
+
if (value.manifestVersion !== WORKER_MANIFEST_VERSION)
|
|
157
|
+
return manifestFailure("unsupported_manifest_version", `manifest.manifestVersion must be ${String(WORKER_MANIFEST_VERSION)}`);
|
|
158
|
+
const protocolVersion = parseProtocolVersion(value.protocolVersion);
|
|
159
|
+
if (!protocolVersion.ok)
|
|
160
|
+
return protocolVersion;
|
|
161
|
+
const sdkVersion = parseIdentifier(value.sdkVersion, "manifest.sdkVersion");
|
|
162
|
+
if (!sdkVersion.ok)
|
|
163
|
+
return sdkVersion;
|
|
164
|
+
const runtime = parseRuntime(value.runtime, "manifest.runtime");
|
|
165
|
+
if (!runtime.ok)
|
|
166
|
+
return runtime;
|
|
167
|
+
const deployment = parseDeployment(value.deployment, "manifest.deployment");
|
|
168
|
+
if (!deployment.ok)
|
|
169
|
+
return deployment;
|
|
170
|
+
const workflows = parseWorkflows(value.workflows, "manifest.workflows");
|
|
171
|
+
if (!workflows.ok)
|
|
172
|
+
return workflows;
|
|
173
|
+
const capabilities = parseManifestCapabilities(value.capabilities, "manifest.capabilities");
|
|
174
|
+
if (!capabilities.ok)
|
|
175
|
+
return capabilities;
|
|
176
|
+
const manifest = normalizeWorkerManifest({
|
|
177
|
+
manifestVersion: WORKER_MANIFEST_VERSION,
|
|
178
|
+
protocolVersion: protocolVersion.value,
|
|
179
|
+
sdkVersion: sdkVersion.value,
|
|
180
|
+
runtime: runtime.runtime,
|
|
181
|
+
deployment: deployment.deployment,
|
|
182
|
+
workflows: workflows.workflows,
|
|
183
|
+
capabilities: capabilities.capabilities
|
|
184
|
+
}), canonicalJson = canonicalWorkerManifestJson(manifest), canonicalBytes = utf8ByteLength(canonicalJson);
|
|
185
|
+
if (canonicalBytes > MAX_NORMALIZED_MANIFEST_BYTES)
|
|
186
|
+
return manifestFailure("manifest_too_large", `normalizes to ${canonicalBytes} bytes, exceeding the maximum of ${MAX_NORMALIZED_MANIFEST_BYTES}`, "manifest");
|
|
187
|
+
return { ok: !0, manifest, canonicalJson };
|
|
188
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Real worker manifest production from an engine's canonical workflow
|
|
3
|
+
* registry (WFT-29).
|
|
4
|
+
*
|
|
5
|
+
* `RemoteWorkerOptions` and the internal Worker realm both fall back to
|
|
6
|
+
* `declared-shape:` placeholders when no real build tooling supplies a
|
|
7
|
+
* manifest — see {@link declaredShapeDigest}. This module is that build
|
|
8
|
+
* tooling: it derives `WorkerWorkflowContract`/`WorkerActivityContract`
|
|
9
|
+
* values from the *same* normalized representation `buildRegistrySnapshot`
|
|
10
|
+
* produces for `GET /v1/registry` and `weft codegen`, hashed with the
|
|
11
|
+
* collision-resistant {@link sha256Hex} rather than the cache-key-quality
|
|
12
|
+
* FNV-1a scheme those placeholders use.
|
|
13
|
+
*
|
|
14
|
+
* Intended use is a build script: construct an `Engine` with every workflow
|
|
15
|
+
* the artifact bundles registered (never started), call
|
|
16
|
+
* {@link buildWorkerManifestFromRegistry}, and pass the result as
|
|
17
|
+
* `RemoteWorkerOptions.manifest`.
|
|
18
|
+
*
|
|
19
|
+
* @module worker/manifest/registry-contract-builder
|
|
20
|
+
*/
|
|
21
|
+
import type { Engine } from '../../core/engine.ts';
|
|
22
|
+
import { WeftError } from '../../core/weft-error.ts';
|
|
23
|
+
import type { WorkerDeploymentIdentity, WorkerManifest, WorkerRuntimeIdentity } from './types.ts';
|
|
24
|
+
/**
|
|
25
|
+
* Thrown when {@link buildWorkerManifestFromRegistry} is asked to advertise a
|
|
26
|
+
* workflow or activity name that the source `Engine` has not registered.
|
|
27
|
+
*
|
|
28
|
+
* This is a build-time tooling error, thrown before any manifest reaches the
|
|
29
|
+
* wire — analogous to the engine's own `RegistrySchemaConversionError`.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { WorkerManifestBuildError } from '@lostgradient/weft';
|
|
34
|
+
*
|
|
35
|
+
* try {
|
|
36
|
+
* throw new WorkerManifestBuildError('workflow "checkout" is not registered');
|
|
37
|
+
* } catch (error) {
|
|
38
|
+
* console.log(error instanceof WorkerManifestBuildError); // true
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare class WorkerManifestBuildError extends WeftError<'WorkerManifestBuildError'> {
|
|
43
|
+
constructor(message: string);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Options accepted by {@link buildWorkerManifestFromRegistry}.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import type { WorkerManifestFromRegistryOptions } from '@lostgradient/weft';
|
|
51
|
+
*
|
|
52
|
+
* const options: WorkerManifestFromRegistryOptions = {
|
|
53
|
+
* workflows: { checkout: ['charge'] },
|
|
54
|
+
* deployment: { name: 'billing', buildId: '2026.08.18-3', artifactDigest: 'sha256:41d0e2' },
|
|
55
|
+
* runtime: { name: 'bun', version: '1.3.14' },
|
|
56
|
+
* };
|
|
57
|
+
* console.log(options.workflows['checkout']);
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export interface WorkerManifestFromRegistryOptions {
|
|
61
|
+
/**
|
|
62
|
+
* Workflow types this worker instance can execute, each mapped to the
|
|
63
|
+
* activity names it invokes. Every key must name a workflow the source
|
|
64
|
+
* `Engine` has registered, and every activity name must be one the same
|
|
65
|
+
* `Engine` has registered — the engine's activity registry is a flat
|
|
66
|
+
* namespace, not partitioned per workflow, so this association is the one
|
|
67
|
+
* thing the registry genuinely cannot supply on its own.
|
|
68
|
+
*/
|
|
69
|
+
workflows: Readonly<Record<string, readonly string[]>>;
|
|
70
|
+
/** Immutable deployment artifact identity. Required — never derived. */
|
|
71
|
+
deployment: WorkerDeploymentIdentity;
|
|
72
|
+
/**
|
|
73
|
+
* Runtime that will execute the deployed artifact. Required rather than
|
|
74
|
+
* defaulted: a build script's own process (often a CI runner) is not
|
|
75
|
+
* necessarily the runtime the artifact deploys to, so live detection here
|
|
76
|
+
* would silently assert the wrong identity.
|
|
77
|
+
*/
|
|
78
|
+
runtime: WorkerRuntimeIdentity;
|
|
79
|
+
/** Weft worker SDK release the deployed artifact bundles. Defaults to this package's `VERSION`. */
|
|
80
|
+
sdkVersion?: string;
|
|
81
|
+
/** RemoteWorker wire protocol version. Defaults to `REMOTE_WORKER_PROTOCOL_VERSION`. */
|
|
82
|
+
protocolVersion?: number;
|
|
83
|
+
/** Bounded descriptive capability data. Defaults to `{}`. */
|
|
84
|
+
capabilities?: WorkerManifest['capabilities'];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Build a real worker manifest from an engine's canonical workflow and
|
|
88
|
+
* activity registrations.
|
|
89
|
+
*
|
|
90
|
+
* `implementationRevision` on every activity contract is set to
|
|
91
|
+
* `options.deployment.buildId`: a schema identifies the *contract*, not the
|
|
92
|
+
* code behind it, so there is no honest schema-derived source for "which
|
|
93
|
+
* implementation" — the build that produced this artifact is the closest
|
|
94
|
+
* available honest answer.
|
|
95
|
+
*
|
|
96
|
+
* Throws {@link WorkerManifestBuildError} if `options.workflows` names a
|
|
97
|
+
* workflow or activity the source `Engine` has not registered, and a
|
|
98
|
+
* (non-public) schema-conversion error if a registered schema cannot be
|
|
99
|
+
* converted to JSON Schema.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* import { buildWorkerManifestFromRegistry, Engine, workflow } from '@lostgradient/weft';
|
|
104
|
+
*
|
|
105
|
+
* const engine = new Engine();
|
|
106
|
+
* engine.register(
|
|
107
|
+
* workflow({ name: 'checkout', version: '2.1.0' }).execute(async function* () {}),
|
|
108
|
+
* );
|
|
109
|
+
*
|
|
110
|
+
* const manifest = await buildWorkerManifestFromRegistry(engine, {
|
|
111
|
+
* workflows: { checkout: [] },
|
|
112
|
+
* deployment: { name: 'billing', buildId: '2026.08.18-3', artifactDigest: 'sha256:41d0e2' },
|
|
113
|
+
* runtime: { name: 'bun', version: '1.3.14' },
|
|
114
|
+
* });
|
|
115
|
+
*
|
|
116
|
+
* console.log(manifest.workflows['checkout']?.workflowVersion); // '2.1.0'
|
|
117
|
+
* engine[Symbol.dispose]();
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export declare function buildWorkerManifestFromRegistry(engine: Engine, options: WorkerManifestFromRegistryOptions): Promise<WorkerManifest>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildRegistrySnapshot
|
|
3
|
+
} from "../../core/registry-snapshot.js";
|
|
4
|
+
import { WeftError } from "../../core/weft-error.js";
|
|
5
|
+
import { VERSION } from "../../version.js";
|
|
6
|
+
import { REMOTE_WORKER_PROTOCOL_VERSION } from "../protocol.js";
|
|
7
|
+
import { canonicalJsonStringify } from "./canonical-json.js";
|
|
8
|
+
import { sha256Hex } from "./content-digest.js";
|
|
9
|
+
import { WORKER_MANIFEST_VERSION } from "./types.js";
|
|
10
|
+
|
|
11
|
+
export class WorkerManifestBuildError extends WeftError {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super("WorkerManifestBuildError", message);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function findWorkflowEntry(snapshot, workflowType) {
|
|
17
|
+
const entry = snapshot.workflows[workflowType];
|
|
18
|
+
if (entry === void 0)
|
|
19
|
+
throw new WorkerManifestBuildError(`Cannot build a worker manifest: workflow type "${workflowType}" is not registered on the source Engine.`);
|
|
20
|
+
return entry;
|
|
21
|
+
}
|
|
22
|
+
function findActivityEntry(snapshot, workflowType, activityName) {
|
|
23
|
+
const entry = snapshot.activities[activityName];
|
|
24
|
+
if (entry === void 0)
|
|
25
|
+
throw new WorkerManifestBuildError(`Cannot build a worker manifest: activity "${activityName}" declared under workflow "${workflowType}" is not registered on the source Engine.`);
|
|
26
|
+
return entry;
|
|
27
|
+
}
|
|
28
|
+
function workflowContractPayload(entry) {
|
|
29
|
+
return {
|
|
30
|
+
inputSchema: entry.inputSchema,
|
|
31
|
+
outputSchema: entry.outputSchema,
|
|
32
|
+
signals: entry.signals,
|
|
33
|
+
updates: entry.updates,
|
|
34
|
+
queries: entry.queries
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function activityContractPayload(entry) {
|
|
38
|
+
return { inputSchema: entry.inputSchema, outputSchema: entry.outputSchema };
|
|
39
|
+
}
|
|
40
|
+
async function buildActivityContract(snapshot, workflowType, activityName, implementationRevision) {
|
|
41
|
+
const entry = findActivityEntry(snapshot, workflowType, activityName);
|
|
42
|
+
return { contractHash: await sha256Hex(canonicalJsonStringify(activityContractPayload(entry))), implementationRevision };
|
|
43
|
+
}
|
|
44
|
+
async function buildWorkflowContract(snapshot, workflowVersionsByType, workflowType, activityNames, implementationRevision) {
|
|
45
|
+
const entry = findWorkflowEntry(snapshot, workflowType), workflowVersion = workflowVersionsByType.get(workflowType), contractHash = await sha256Hex(canonicalJsonStringify(workflowContractPayload(entry))), workflowRevision = await sha256Hex(canonicalJsonStringify({ ...entry, version: workflowVersion })), sortedActivityNames = [...activityNames].toSorted(), activityContracts = await Promise.all(sortedActivityNames.map((activityName) => buildActivityContract(snapshot, workflowType, activityName, implementationRevision))), activities = {};
|
|
46
|
+
sortedActivityNames.forEach((activityName, index) => {
|
|
47
|
+
activities[activityName] = activityContracts[index];
|
|
48
|
+
});
|
|
49
|
+
return { workflowVersion, workflowRevision, contractHash, activities };
|
|
50
|
+
}
|
|
51
|
+
export async function buildWorkerManifestFromRegistry(engine, options) {
|
|
52
|
+
const snapshot = buildRegistrySnapshot(engine), workflowVersionsByType = new Map(engine.listWorkflowDefinitions().map((definition) => [definition.type, definition.version])), sortedWorkflowTypes = Object.keys(options.workflows).toSorted(), workflowContracts = await Promise.all(sortedWorkflowTypes.map((workflowType) => buildWorkflowContract(snapshot, workflowVersionsByType, workflowType, options.workflows[workflowType] ?? [], options.deployment.buildId))), workflows = {};
|
|
53
|
+
sortedWorkflowTypes.forEach((workflowType, index) => {
|
|
54
|
+
workflows[workflowType] = workflowContracts[index];
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
manifestVersion: WORKER_MANIFEST_VERSION,
|
|
58
|
+
protocolVersion: options.protocolVersion ?? REMOTE_WORKER_PROTOCOL_VERSION,
|
|
59
|
+
sdkVersion: options.sdkVersion ?? VERSION,
|
|
60
|
+
runtime: options.runtime,
|
|
61
|
+
deployment: options.deployment,
|
|
62
|
+
workflows,
|
|
63
|
+
capabilities: options.capabilities ?? {}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical worker manifest and execution-identity vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* One manifest answers every identity question about a worker at once, with
|
|
5
|
+
* each question in its own field:
|
|
6
|
+
*
|
|
7
|
+
* | Field | Question answered | Stability |
|
|
8
|
+
* | ----------------- | ------------------------------------------------ | ------------------------------- |
|
|
9
|
+
* | `manifestVersion` | Can the host parse this manifest shape? | Changes with manifest schema |
|
|
10
|
+
* | `protocolVersion` | Can these peers exchange wire messages? | Changes with wire semantics |
|
|
11
|
+
* | `sdkVersion` | Which Weft worker SDK produced this worker? | Package release |
|
|
12
|
+
* | `runtime` | Which runtime executes the worker? | Runtime deployment |
|
|
13
|
+
* | `deployment.name` | Which logical service owns this worker? | Stable service identity |
|
|
14
|
+
* | `buildId` | Which operator-visible release is this? | Immutable within a deployment |
|
|
15
|
+
* | `artifactDigest` | Which exact executable bytes are loaded? | Content-addressed and immutable |
|
|
16
|
+
* | `workflowVersion` | Which replay compatibility boundary is declared? | Workflow author controlled |
|
|
17
|
+
* | `contractHash` | Which public payload contract is implemented? | Deterministic contract identity |
|
|
18
|
+
*
|
|
19
|
+
* A Git SHA is deliberately absent from that table: repositories may be dirty,
|
|
20
|
+
* builds may inject configuration, and one commit may produce several
|
|
21
|
+
* artifacts, so a commit is metadata rather than an executable identity.
|
|
22
|
+
*
|
|
23
|
+
* @module worker/manifest/types
|
|
24
|
+
*/
|
|
25
|
+
import type { JSONValue } from '../../core/json.ts';
|
|
26
|
+
/**
|
|
27
|
+
* Current worker manifest schema version.
|
|
28
|
+
*
|
|
29
|
+
* This is a different axis from the RemoteWorker wire protocol version:
|
|
30
|
+
* `manifestVersion` answers "can the host parse this shape", while
|
|
31
|
+
* `protocolVersion` answers "can these peers exchange messages". Bump this
|
|
32
|
+
* only when the manifest's own structure changes incompatibly; unknown
|
|
33
|
+
* versions are rejected before registration rather than best-effort parsed.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { WORKER_MANIFEST_VERSION } from '@lostgradient/weft';
|
|
38
|
+
*
|
|
39
|
+
* const canParse = (received: number): boolean => received === WORKER_MANIFEST_VERSION;
|
|
40
|
+
* console.log(canParse(1));
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare const WORKER_MANIFEST_VERSION = 1;
|
|
44
|
+
/**
|
|
45
|
+
* Deterministic identity of one activity implementation inside a workflow.
|
|
46
|
+
*
|
|
47
|
+
* `contractHash` identifies the public payload contract — what callers may
|
|
48
|
+
* send and expect back. `implementationRevision` identifies the code behind
|
|
49
|
+
* that contract, which may change without changing the contract.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* import type { WorkerActivityContract } from '@lostgradient/weft';
|
|
54
|
+
*
|
|
55
|
+
* const charge: WorkerActivityContract = {
|
|
56
|
+
* contractHash: 'sha256:2b1f0c9d',
|
|
57
|
+
* implementationRevision: 'rev-41',
|
|
58
|
+
* };
|
|
59
|
+
* console.log(charge.contractHash);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export type WorkerActivityContract = Readonly<{
|
|
63
|
+
/** Deterministic identity of this activity's public payload contract. */
|
|
64
|
+
contractHash: string;
|
|
65
|
+
/** Identity of the implementation currently bound to that contract. */
|
|
66
|
+
implementationRevision: string;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Deterministic identity of one workflow an artifact can execute, including
|
|
70
|
+
* every activity it exposes.
|
|
71
|
+
*
|
|
72
|
+
* Activity keys are canonical runtime activity names. An activity is qualified
|
|
73
|
+
* structurally by the workflow that contains it rather than only through a
|
|
74
|
+
* dotted string, so the same activity name may appear under two workflows
|
|
75
|
+
* without collision.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import type { WorkerWorkflowContract } from '@lostgradient/weft';
|
|
80
|
+
*
|
|
81
|
+
* const checkout: WorkerWorkflowContract = {
|
|
82
|
+
* workflowVersion: '2.1.0',
|
|
83
|
+
* workflowRevision: 'rev-88',
|
|
84
|
+
* contractHash: 'sha256:9ab3',
|
|
85
|
+
* activities: { charge: { contractHash: 'sha256:2b1f', implementationRevision: 'rev-41' } },
|
|
86
|
+
* };
|
|
87
|
+
* console.log(Object.keys(checkout.activities));
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export type WorkerWorkflowContract = Readonly<{
|
|
91
|
+
/** Semantic replay-compatibility boundary declared by the workflow author. */
|
|
92
|
+
workflowVersion: string;
|
|
93
|
+
/** Identity of the exact workflow definition loaded from this artifact. */
|
|
94
|
+
workflowRevision: string;
|
|
95
|
+
/** Deterministic identity of the workflow's public payload contract. */
|
|
96
|
+
contractHash: string;
|
|
97
|
+
/** Activities this workflow exposes, keyed by canonical activity name. */
|
|
98
|
+
activities: Readonly<Record<string, WorkerActivityContract>>;
|
|
99
|
+
}>;
|
|
100
|
+
/**
|
|
101
|
+
* Immutable deployment artifact identity.
|
|
102
|
+
*
|
|
103
|
+
* `(name, buildId)` identifies exactly one `artifactDigest` within one server
|
|
104
|
+
* scope. Shipping different bytes means choosing a new `buildId` — reusing one
|
|
105
|
+
* is a registration conflict, not an update.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* import type { WorkerDeploymentIdentity } from '@lostgradient/weft';
|
|
110
|
+
*
|
|
111
|
+
* const deployment: WorkerDeploymentIdentity = {
|
|
112
|
+
* name: 'billing',
|
|
113
|
+
* buildId: '2026.08.18-3',
|
|
114
|
+
* artifactDigest: 'sha256:41d0e2',
|
|
115
|
+
* };
|
|
116
|
+
* console.log(deployment.buildId);
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export type WorkerDeploymentIdentity = Readonly<{
|
|
120
|
+
/** Logical service that owns this worker. */
|
|
121
|
+
name: string;
|
|
122
|
+
/** Operator-visible release identity, immutable within the deployment. */
|
|
123
|
+
buildId: string;
|
|
124
|
+
/** Content-addressed digest of the complete executable artifact. */
|
|
125
|
+
artifactDigest: string;
|
|
126
|
+
}>;
|
|
127
|
+
/**
|
|
128
|
+
* Runtime that executes a worker process.
|
|
129
|
+
*
|
|
130
|
+
* `version` is an empty string on runtimes that expose none — a browser or
|
|
131
|
+
* edge worker — rather than being omitted, so the field is always answerable.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* import type { WorkerRuntimeIdentity } from '@lostgradient/weft';
|
|
136
|
+
*
|
|
137
|
+
* const runtime: WorkerRuntimeIdentity = { name: 'bun', version: '1.3.14' };
|
|
138
|
+
* console.log(`${runtime.name} ${runtime.version}`);
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export type WorkerRuntimeIdentity = Readonly<{
|
|
142
|
+
/** Runtime name, such as `bun` or `node`. */
|
|
143
|
+
name: string;
|
|
144
|
+
/** Runtime version, or an empty string where the runtime exposes none. */
|
|
145
|
+
version: string;
|
|
146
|
+
}>;
|
|
147
|
+
/**
|
|
148
|
+
* Everything a worker asserts about itself, validated by the host before the
|
|
149
|
+
* worker becomes routing-eligible.
|
|
150
|
+
*
|
|
151
|
+
* Worker readiness means the server accepted a validated manifest — not merely
|
|
152
|
+
* that a socket opened. Digests and contract hashes carried here are checked
|
|
153
|
+
* against trusted records rather than believed because the worker asserted
|
|
154
|
+
* them, and `capabilities` never grants authorization on its own.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```ts
|
|
158
|
+
* import { WORKER_MANIFEST_VERSION, type WorkerManifest } from '@lostgradient/weft';
|
|
159
|
+
*
|
|
160
|
+
* const manifest: WorkerManifest = {
|
|
161
|
+
* manifestVersion: WORKER_MANIFEST_VERSION,
|
|
162
|
+
* protocolVersion: 2,
|
|
163
|
+
* sdkVersion: '0.18.0',
|
|
164
|
+
* runtime: { name: 'bun', version: '1.3.14' },
|
|
165
|
+
* deployment: { name: 'billing', buildId: '2026.08.18-3', artifactDigest: 'sha256:41d0e2' },
|
|
166
|
+
* workflows: {},
|
|
167
|
+
* capabilities: {},
|
|
168
|
+
* };
|
|
169
|
+
* console.log(manifest.deployment.name);
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
export type WorkerManifest = Readonly<{
|
|
173
|
+
/** Manifest schema version; unknown values are rejected, not tolerated. */
|
|
174
|
+
manifestVersion: typeof WORKER_MANIFEST_VERSION;
|
|
175
|
+
/** RemoteWorker wire protocol version these peers will speak. */
|
|
176
|
+
protocolVersion: number;
|
|
177
|
+
/** Weft worker SDK release that produced this worker. */
|
|
178
|
+
sdkVersion: string;
|
|
179
|
+
/** Runtime executing the worker process. */
|
|
180
|
+
runtime: WorkerRuntimeIdentity;
|
|
181
|
+
/** Immutable deployment artifact identity. */
|
|
182
|
+
deployment: WorkerDeploymentIdentity;
|
|
183
|
+
/** Workflows this artifact can execute, keyed by canonical workflow name. */
|
|
184
|
+
workflows: Readonly<Record<string, WorkerWorkflowContract>>;
|
|
185
|
+
/** Bounded descriptive capability data; never an authorization claim. */
|
|
186
|
+
capabilities: Readonly<Record<string, JSONValue>>;
|
|
187
|
+
}>;
|
|
188
|
+
/**
|
|
189
|
+
* Routing input: the constraints a task places on the worker that may execute
|
|
190
|
+
* it.
|
|
191
|
+
*
|
|
192
|
+
* An omitted field lets policy choose any eligible value. It is *not* an
|
|
193
|
+
* empty-string wildcard, and it is not a claim that the field does not matter
|
|
194
|
+
* once the task is leased — see {@link WorkerExecutionIdentity}, which is
|
|
195
|
+
* always complete.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```ts
|
|
199
|
+
* import type { WorkerExecutionRequirement } from '@lostgradient/weft';
|
|
200
|
+
*
|
|
201
|
+
* // Pin the deployment, let policy pick any eligible build within it.
|
|
202
|
+
* const requirement: WorkerExecutionRequirement = { deploymentName: 'billing' };
|
|
203
|
+
* console.log(requirement.buildId === undefined);
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
export type WorkerExecutionRequirement = Readonly<{
|
|
207
|
+
/** Required logical service, when the task pins one. */
|
|
208
|
+
deploymentName?: string;
|
|
209
|
+
/** Required operator-visible release, when the task pins one. */
|
|
210
|
+
buildId?: string;
|
|
211
|
+
/** Required executable artifact, when the task pins exact bytes. */
|
|
212
|
+
artifactDigest?: string;
|
|
213
|
+
/** Required workflow definition revision, when the task pins one. */
|
|
214
|
+
workflowRevision?: string;
|
|
215
|
+
/** Required activity contract identity, when the task pins one. */
|
|
216
|
+
activityContractHash?: string;
|
|
217
|
+
}>;
|
|
218
|
+
/**
|
|
219
|
+
* Observed execution: the complete identity of the worker that actually holds
|
|
220
|
+
* a lease on an attempt.
|
|
221
|
+
*
|
|
222
|
+
* Every field is populated from the accepted manifest plus the live session.
|
|
223
|
+
* A worker cannot self-report a different execution identity in its result,
|
|
224
|
+
* which is what makes this safe to persist as provenance.
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```ts
|
|
228
|
+
* import type { WorkerExecutionIdentity } from '@lostgradient/weft';
|
|
229
|
+
*
|
|
230
|
+
* function describe(identity: WorkerExecutionIdentity): string {
|
|
231
|
+
* return `${identity.deploymentName}@${identity.buildId} (${identity.workerId})`;
|
|
232
|
+
* }
|
|
233
|
+
* console.log(typeof describe);
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
export type WorkerExecutionIdentity = Readonly<{
|
|
237
|
+
/** Live process instance that holds the lease. */
|
|
238
|
+
workerId: string;
|
|
239
|
+
/** Digest of the manifest the server accepted from that instance. */
|
|
240
|
+
manifestDigest: string;
|
|
241
|
+
/** Wire protocol version negotiated with that instance. */
|
|
242
|
+
protocolVersion: number;
|
|
243
|
+
/** Weft worker SDK release that produced the instance. */
|
|
244
|
+
sdkVersion: string;
|
|
245
|
+
/** Runtime name executing the instance. */
|
|
246
|
+
runtimeName: string;
|
|
247
|
+
/** Runtime version executing the instance. */
|
|
248
|
+
runtimeVersion: string;
|
|
249
|
+
/** Logical service that owns the instance. */
|
|
250
|
+
deploymentName: string;
|
|
251
|
+
/** Operator-visible release the instance is running. */
|
|
252
|
+
buildId: string;
|
|
253
|
+
/** Executable artifact the instance loaded. */
|
|
254
|
+
artifactDigest: string;
|
|
255
|
+
/** Workflow that executed the attempt. */
|
|
256
|
+
workflowType: string;
|
|
257
|
+
/** Workflow definition revision that executed the attempt. */
|
|
258
|
+
workflowRevision: string;
|
|
259
|
+
/** Activity that executed the attempt. */
|
|
260
|
+
activityName: string;
|
|
261
|
+
/** Contract identity of that activity. */
|
|
262
|
+
activityContractHash: string;
|
|
263
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const WORKER_MANIFEST_VERSION = 1;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UTF-8 byte measurement for manifest bounds.
|
|
3
|
+
*
|
|
4
|
+
* Manifest limits are expressed in bytes rather than code units so a worker
|
|
5
|
+
* cannot smuggle several times the intended payload through astral-plane
|
|
6
|
+
* characters, each of which costs one UTF-16 `.length` but four UTF-8 bytes.
|
|
7
|
+
*
|
|
8
|
+
* @module worker/manifest/utf8
|
|
9
|
+
*/
|
|
10
|
+
/** UTF-8 byte length of a string. */
|
|
11
|
+
export declare function utf8ByteLength(value: string): number;
|
|
12
|
+
/** Encode a string to UTF-8 bytes. */
|
|
13
|
+
export declare function utf8Encode(value: string): Uint8Array;
|