@uns-kit/core 3.0.33 → 3.0.34

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.
Files changed (31) hide show
  1. package/MIGRATIONS.md +25 -0
  2. package/dist/runtime/process-group-authorization.d.ts +72 -0
  3. package/dist/runtime/process-group-authorization.d.ts.map +1 -1
  4. package/dist/runtime/process-group-authorization.js +31 -0
  5. package/dist/runtime/process-group-authorization.js.map +1 -1
  6. package/dist/runtime/process-group-contract.d.ts +1 -0
  7. package/dist/runtime/process-group-contract.d.ts.map +1 -1
  8. package/dist/runtime/process-group-contract.js +2 -1
  9. package/dist/runtime/process-group-contract.js.map +1 -1
  10. package/dist/runtime/process-group-direct-contract.d.ts +181 -0
  11. package/dist/runtime/process-group-direct-contract.d.ts.map +1 -0
  12. package/dist/runtime/process-group-direct-contract.js +151 -0
  13. package/dist/runtime/process-group-direct-contract.js.map +1 -0
  14. package/dist/runtime/process-group-direct-review.d.ts +203 -0
  15. package/dist/runtime/process-group-direct-review.d.ts.map +1 -0
  16. package/dist/runtime/process-group-direct-review.js +263 -0
  17. package/dist/runtime/process-group-direct-review.js.map +1 -0
  18. package/dist/runtime/process-group-direct-runtime.d.ts +18 -0
  19. package/dist/runtime/process-group-direct-runtime.d.ts.map +1 -0
  20. package/dist/runtime/process-group-direct-runtime.js +154 -0
  21. package/dist/runtime/process-group-direct-runtime.js.map +1 -0
  22. package/dist/runtime/process-group-snapshot.mjs +44 -0
  23. package/dist/uns-mqtt/mqtt-proxy.d.ts +1 -0
  24. package/dist/uns-mqtt/mqtt-proxy.d.ts.map +1 -1
  25. package/dist/uns-mqtt/mqtt-proxy.js +5 -0
  26. package/dist/uns-mqtt/mqtt-proxy.js.map +1 -1
  27. package/dist/uns-mqtt/uns-mqtt-proxy.d.ts +6 -0
  28. package/dist/uns-mqtt/uns-mqtt-proxy.d.ts.map +1 -1
  29. package/dist/uns-mqtt/uns-mqtt-proxy.js +14 -0
  30. package/dist/uns-mqtt/uns-mqtt-proxy.js.map +1 -1
  31. package/package.json +1 -1
@@ -0,0 +1,263 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { configurationGroupSnapshot, configurationResourceHash } from "./configuration-group-contract.js";
4
+ import { authorizeProcessGroupRuntime, processGroupManifestSchema } from "./process-group-authorization.js";
5
+ import { processGroupJournalContract, processGroupJournalSchema, processGroupSourceIdentity, readConfigurationSelector, resolvedProcessGroupChannels, } from "./process-group-contract.js";
6
+ import { processGroupDirectDescriptorSchema, processGroupDirectInputSchema, processGroupRetirementPolicySchema, retiredJournalReferenceSchema, } from "./process-group-direct-contract.js";
7
+ import { describeInstalledProcessGroupGeneration, inspectGenerationJournal } from "./process-group-generation.js";
8
+ import { groupArtifactHash, groupChannelsHash, configurationAuthorizationHash as hash, readProcessGroupResource as read, sha256, } from "./process-group-resources.js";
9
+ import { normalizeRuntimeProcessGroup, selectedProcessGroupDescriptor } from "./process-group-runtime-selection.js";
10
+ const inside = (root, file) => {
11
+ const resolved = path.resolve(root, file);
12
+ if (!resolved.startsWith(path.resolve(root) + path.sep))
13
+ throw Error("Direct resource escapes installed package");
14
+ return read(resolved);
15
+ };
16
+ export function processGroupDirectDescriptor(packageRoot) {
17
+ const pkg = JSON.parse(read(path.join(packageRoot, "package.json")).toString());
18
+ return pkg.unsDatahub?.processGroupDirectRuntime === undefined
19
+ ? undefined
20
+ : processGroupDirectDescriptorSchema.parse(pkg.unsDatahub.processGroupDirectRuntime);
21
+ }
22
+ export function describeDirectProcessGroup(c) {
23
+ const descriptor = processGroupDirectDescriptor(c.packageRoot);
24
+ if (!descriptor ||
25
+ (descriptor.match && readConfigurationSelector(c.raw, descriptor.match.path) !== descriptor.match.value) ||
26
+ readConfigurationSelector(c.raw, descriptor.runtimeRolePath) !== descriptor.directRole ||
27
+ readConfigurationSelector(c.raw, descriptor.journalPath) !== undefined)
28
+ throw Error("Exact declared direct mode without an input journal required");
29
+ const publisher = readConfigurationSelector(c.raw, descriptor.publisherPath);
30
+ if (!publisher || typeof publisher !== "object" || Array.isArray(publisher))
31
+ throw Error("Explicit direct publisher required");
32
+ const selectedResources = descriptor.resources.filter((r) => readConfigurationSelector(c.raw, r.kind === "file" ? r.manifestPath : r.groupPath) !== undefined);
33
+ if (selectedResources.length !== 1)
34
+ throw Error("Select exactly one declared direct resource");
35
+ const resource = selectedResources[0];
36
+ if (resource.kind === "configuration") {
37
+ const snapshot = configurationGroupSnapshot(readConfigurationSelector(c.raw, resource.groupPath));
38
+ if (configurationResourceHash(readConfigurationSelector(c.resolved, resource.groupPath)) !==
39
+ configurationResourceHash(readConfigurationSelector(c.raw, resource.groupPath)))
40
+ throw Error("Resolved direct business resource differs from its reviewed configuration");
41
+ return {
42
+ descriptor,
43
+ resource,
44
+ groupId: snapshot.group.id,
45
+ processName: snapshot.group.processName,
46
+ resourceSha256: snapshot.sha256,
47
+ profiles: snapshot.profiles.map((p) => ({ processName: p.processName, mappingSha256: p.resourceSha256, dataGroup: p.dataGroup })),
48
+ snapshot,
49
+ };
50
+ }
51
+ const manifestPath = readConfigurationSelector(c.raw, resource.manifestPath);
52
+ const selected = resource.manifests.find((m) => m.file === manifestPath);
53
+ if (!selected)
54
+ throw Error("Unregistered direct manifest");
55
+ if (readConfigurationSelector(c.resolved, resource.manifestPath) !== selected.file)
56
+ throw Error("Resolved direct manifest selection changed");
57
+ const bytes = inside(c.packageRoot, selected.file), manifest = processGroupManifestSchema.parse(JSON.parse(bytes.toString()));
58
+ if (manifest.id !== selected.id)
59
+ throw Error("Direct manifest identity differs");
60
+ for (const p of manifest.profiles)
61
+ if (sha256(inside(c.packageRoot, path.join(path.dirname(selected.file), p.mappingFile))) !== p.mappingSha256)
62
+ throw Error("Direct profile resource changed");
63
+ return {
64
+ descriptor,
65
+ resource,
66
+ groupId: manifest.id,
67
+ processName: manifest.processName,
68
+ resourceSha256: sha256(bytes),
69
+ profiles: manifest.profiles.map(({ processName, mappingSha256, dataGroup }) => ({ processName, mappingSha256, dataGroup })),
70
+ manifest,
71
+ manifestPath: selected.file,
72
+ manifestFile: path.resolve(c.packageRoot, selected.file),
73
+ };
74
+ }
75
+ function remove(raw, keys) {
76
+ let current = raw;
77
+ const parents = [];
78
+ for (const key of keys.slice(0, -1)) {
79
+ const next = current[key];
80
+ if (!next || typeof next !== "object" || Array.isArray(next))
81
+ return;
82
+ parents.push([current, key]);
83
+ current = next;
84
+ }
85
+ delete current[keys.at(-1)];
86
+ for (const [parent, key] of parents.reverse()) {
87
+ const value = parent[key];
88
+ if (value && typeof value === "object" && !Object.keys(value).length)
89
+ delete parent[key];
90
+ else
91
+ break;
92
+ }
93
+ }
94
+ function projection(raw, d, excluded) {
95
+ const copy = structuredClone(raw);
96
+ remove(copy, d.journalPath);
97
+ remove(copy, d.runtimeRolePath);
98
+ for (const r of d.resources)
99
+ if (r.kind === "file")
100
+ remove(copy, r.manifestPath);
101
+ const uns = copy["uns"];
102
+ if (uns && typeof uns === "object" && !Array.isArray(uns))
103
+ for (const key of excluded)
104
+ delete uns[key];
105
+ // Removing a lifecycle leaf must not turn an otherwise empty publisher into a difference.
106
+ const publisher = readConfigurationSelector(copy, d.publisherPath);
107
+ if (publisher && typeof publisher === "object" && !Object.keys(publisher).length)
108
+ remove(copy, d.publisherPath);
109
+ return hash(copy);
110
+ }
111
+ /** Data-only installed-resource review. Does not stop, initialize, rewrite or grant launch authority. */
112
+ export function reviewInstalledProcessGroupDirectTransition(operationId, rawInput, configs, stateRoot, excludedUnsFields = []) {
113
+ const input = processGroupDirectInputSchema.parse(rawInput), owner = input.target.controller, first = configs.source.publisher, target = configs.target;
114
+ const pkg = (c) => JSON.parse(read(path.join(c.packageRoot, "package.json")).toString());
115
+ for (const [p, c] of [
116
+ [input.source.publisher, first],
117
+ [input.source.receiver, configs.source.receiver],
118
+ [input.target, target],
119
+ ]) {
120
+ if (path.resolve(c.packageRoot, "instances", p.instanceId) !== c.instanceDirectory ||
121
+ fs.realpathSync(c.instanceDirectory) !== c.instanceDirectory ||
122
+ pkg(c).name !== p.rttNode ||
123
+ pkg(c).version !== p.version)
124
+ throw Error("Exact installed package and instance placement required");
125
+ }
126
+ const context = (c) => ({
127
+ packageRoot: c.packageRoot,
128
+ instanceDirectory: c.instanceDirectory,
129
+ rawConfiguration: c.raw,
130
+ channels: resolvedProcessGroupChannels(c.resolved),
131
+ controllerName: owner,
132
+ stateRoot,
133
+ });
134
+ const old = authorizeProcessGroupRuntime(context(first)), receiver = authorizeProcessGroupRuntime(context(configs.source.receiver));
135
+ if (old.role !== "target" ||
136
+ receiver.role !== "receiver" ||
137
+ old.file !== receiver.file ||
138
+ old.sha256 !== receiver.sha256 ||
139
+ old.directory !== receiver.directory ||
140
+ !old.journalId ||
141
+ old.journalId !== receiver.journalId)
142
+ throw Error("Exact authorized publisher/receiver owners required");
143
+ const sourcePolicy = read(old.file, true), sourceDescriptor = selectedProcessGroupDescriptor(first.packageRoot, first.raw);
144
+ if (!sourceDescriptor)
145
+ throw Error("Missing source shared contract");
146
+ const normalized = normalizeRuntimeProcessGroup(first.raw, sourceDescriptor), direct = describeDirectProcessGroup(target), d = direct.descriptor;
147
+ const namespace = sourceDescriptor.namespace;
148
+ if (d.namespace !== namespace ||
149
+ hash(d.publisherPath) !== hash(sourceDescriptor.publisherPath) ||
150
+ hash(d.journalPath) !== hash(sourceDescriptor.journalPath) ||
151
+ hash(d.runtimeRolePath) !== hash(sourceDescriptor.runtimeRolePath) ||
152
+ direct.groupId !== old.groupId ||
153
+ direct.processName !== old.groupProcessName ||
154
+ target.raw["uns"]?.["processName"] !== old.groupProcessName ||
155
+ projection(first.raw, d, excludedUnsFields) !== projection(target.raw, d, excludedUnsFields))
156
+ throw Error("Direct business configuration, selector or group identity changed");
157
+ const channels = groupChannelsHash(context(first).channels);
158
+ if (channels !== groupChannelsHash(context(configs.source.receiver).channels) || channels !== groupChannelsHash(context(target).channels))
159
+ throw Error("Direct broker/channel identity changed");
160
+ for (const c of [first, configs.source.receiver, target])
161
+ if (resolvedProcessGroupChannels(c.resolved)[2].publishQueue?.enabled === true)
162
+ throw Error("Initial direct retirement requires disabled disk MQTT output");
163
+ let reference, sourceResourceSha256;
164
+ if (sourceDescriptor.protocolVersion === 2) {
165
+ if (direct.resource.kind !== "configuration" || !direct.snapshot)
166
+ throw Error("Resource kind must remain configuration based");
167
+ const generation = describeInstalledProcessGroupGeneration(first);
168
+ reference = generation.reference;
169
+ sourceResourceSha256 = configurationGroupSnapshot(readConfigurationSelector(first.raw, sourceDescriptor.groupPath)).sha256;
170
+ }
171
+ else {
172
+ if (direct.resource.kind !== "file" || !direct.manifest)
173
+ throw Error("Resource kind must remain file based");
174
+ const journal = processGroupJournalSchema.parse(normalized.journal);
175
+ const declared = sourceDescriptor.manifests.find((m) => m.file === journal.groupManifest);
176
+ if (!declared)
177
+ throw Error("Unregistered original manifest");
178
+ const bytes = inside(first.packageRoot, declared.file), manifest = processGroupManifestSchema.parse(JSON.parse(bytes.toString()));
179
+ sourceResourceSha256 = sha256(bytes);
180
+ const contract = processGroupJournalContract(processGroupSourceIdentity(context(first).channels[1]), journal, manifest.profiles);
181
+ reference = {
182
+ directory: old.directory,
183
+ journalId: old.journalId,
184
+ journalContractSha256: sha256(contract),
185
+ generationId: manifest.id,
186
+ contractVersion: 1,
187
+ maxRecords: journal.maxRecords,
188
+ maxBytes: journal.maxBytes,
189
+ minFreeBytes: journal.minFreeBytes,
190
+ profiles: manifest.profiles.map(({ processName, mappingSha256, dataGroup }) => ({ processName, mappingSha256, dataGroup })),
191
+ };
192
+ }
193
+ const journal = retiredJournalReferenceSchema.parse(reference);
194
+ if (sourceResourceSha256 !== direct.resourceSha256 || hash(journal.profiles) !== hash(direct.profiles))
195
+ throw Error("Direct profile resources, paths or units changed");
196
+ const usage = inspectGenerationJournal(journal); // Pending work is allowed at preview, never at policy switch.
197
+ if (!Buffer.from(sourcePolicy.toString(), "utf8").equals(sourcePolicy))
198
+ throw Error("Original policy encoding cannot be retained exactly");
199
+ const member = (placement, c) => ({
200
+ placement,
201
+ processName: String(c.raw["uns"]["processName"]),
202
+ configurationSha256: hash(c.raw),
203
+ artifactSha256: groupArtifactHash(c.packageRoot),
204
+ });
205
+ const policy = processGroupRetirementPolicySchema.parse({
206
+ schemaVersion: 5,
207
+ kind: "uns-process-group-direct-retirement",
208
+ protocolVersion: 1,
209
+ operationId,
210
+ packageName: pkg(first).name,
211
+ namespace,
212
+ groupId: old.groupId,
213
+ controllerName: owner,
214
+ stateRoot,
215
+ recovery: "open",
216
+ journal,
217
+ sourcePolicyJson: sourcePolicy.toString(),
218
+ sourcePolicySha256: sha256(sourcePolicy),
219
+ source: {
220
+ publisher: {
221
+ ...member(input.source.publisher, first),
222
+ policyConfigurationSha256: sourceDescriptor.protocolVersion === 2 ? configurationResourceHash(first.raw) : hash(first.raw),
223
+ },
224
+ receiver: {
225
+ ...member(input.source.receiver, configs.source.receiver),
226
+ policyConfigurationSha256: sourceDescriptor.protocolVersion === 2 ? configurationResourceHash(configs.source.receiver.raw) : hash(configs.source.receiver.raw),
227
+ },
228
+ },
229
+ target: {
230
+ ...member(input.target, target),
231
+ packageRoot: target.packageRoot,
232
+ descriptorSha256: hash(d),
233
+ resourceSha256: direct.resourceSha256,
234
+ channelsSha256: channels,
235
+ },
236
+ });
237
+ if (sha256(read(old.file, true)) !== policy.sourcePolicySha256)
238
+ throw Error("Original policy changed during direct review");
239
+ const targetPolicy = Buffer.from(JSON.stringify(policy));
240
+ if (targetPolicy.length > 65536)
241
+ throw Error("Retirement policy byte budget exceeded");
242
+ return {
243
+ review: {
244
+ protocolVersion: 1,
245
+ kind: "paired-to-direct",
246
+ input,
247
+ operationId,
248
+ policyFile: old.file,
249
+ sourcePolicySha256: sha256(sourcePolicy),
250
+ targetPolicySha256: sha256(targetPolicy),
251
+ journal,
252
+ source: policy.source,
253
+ target: policy.target,
254
+ namespace,
255
+ groupId: old.groupId,
256
+ delivery: { inputPausePossible: true, exactlyOnceOutput: false, brokerReplayNotTransferred: true },
257
+ usage,
258
+ },
259
+ sourcePolicy,
260
+ targetPolicy,
261
+ };
262
+ }
263
+ //# sourceMappingURL=process-group-direct-review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-group-direct-review.js","sourceRoot":"","sources":["../../src/runtime/process-group-direct-review.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport { configurationGroupSnapshot, configurationResourceHash } from \"./configuration-group-contract.js\";\nimport { authorizeProcessGroupRuntime, processGroupManifestSchema } from \"./process-group-authorization.js\";\nimport {\n processGroupJournalContract,\n processGroupJournalSchema,\n processGroupSourceIdentity,\n readConfigurationSelector,\n resolvedProcessGroupChannels,\n} from \"./process-group-contract.js\";\nimport {\n type ProcessGroupDirectDescriptor,\n type ProcessGroupDirectInput,\n processGroupDirectDescriptorSchema,\n processGroupDirectInputSchema,\n processGroupRetirementPolicySchema,\n retiredJournalReferenceSchema,\n} from \"./process-group-direct-contract.js\";\nimport { describeInstalledProcessGroupGeneration, inspectGenerationJournal } from \"./process-group-generation.js\";\nimport type { GenerationJournalReference } from \"./process-group-generation.js\";\nimport {\n groupArtifactHash,\n groupChannelsHash,\n configurationAuthorizationHash as hash,\n readProcessGroupResource as read,\n sha256,\n} from \"./process-group-resources.js\";\nimport { normalizeRuntimeProcessGroup, selectedProcessGroupDescriptor } from \"./process-group-runtime-selection.js\";\nimport type { UpgradeConfiguration } from \"./process-group-upgrade.js\";\n\ntype Config = UpgradeConfiguration;\nexport type DirectTransitionConfigurations = { source: { publisher: Config; receiver: Config }; target: Config };\nconst inside = (root: string, file: string) => {\n const resolved = path.resolve(root, file);\n if (!resolved.startsWith(path.resolve(root) + path.sep)) throw Error(\"Direct resource escapes installed package\");\n return read(resolved);\n};\nexport function processGroupDirectDescriptor(packageRoot: string): ProcessGroupDirectDescriptor | undefined {\n const pkg = JSON.parse(read(path.join(packageRoot, \"package.json\")).toString());\n return pkg.unsDatahub?.processGroupDirectRuntime === undefined\n ? undefined\n : processGroupDirectDescriptorSchema.parse(pkg.unsDatahub.processGroupDirectRuntime);\n}\nexport function describeDirectProcessGroup(c: Config) {\n const descriptor = processGroupDirectDescriptor(c.packageRoot);\n if (\n !descriptor ||\n (descriptor.match && readConfigurationSelector(c.raw, descriptor.match.path) !== descriptor.match.value) ||\n readConfigurationSelector(c.raw, descriptor.runtimeRolePath) !== descriptor.directRole ||\n readConfigurationSelector(c.raw, descriptor.journalPath) !== undefined\n )\n throw Error(\"Exact declared direct mode without an input journal required\");\n const publisher = readConfigurationSelector(c.raw, descriptor.publisherPath);\n if (!publisher || typeof publisher !== \"object\" || Array.isArray(publisher)) throw Error(\"Explicit direct publisher required\");\n const selectedResources = descriptor.resources.filter(\n (r) => readConfigurationSelector(c.raw, r.kind === \"file\" ? r.manifestPath : r.groupPath) !== undefined,\n );\n if (selectedResources.length !== 1) throw Error(\"Select exactly one declared direct resource\");\n const resource = selectedResources[0]!;\n if (resource.kind === \"configuration\") {\n const snapshot = configurationGroupSnapshot(readConfigurationSelector(c.raw, resource.groupPath));\n if (\n configurationResourceHash(readConfigurationSelector(c.resolved, resource.groupPath)) !==\n configurationResourceHash(readConfigurationSelector(c.raw, resource.groupPath))\n )\n throw Error(\"Resolved direct business resource differs from its reviewed configuration\");\n return {\n descriptor,\n resource,\n groupId: snapshot.group.id,\n processName: snapshot.group.processName,\n resourceSha256: snapshot.sha256,\n profiles: snapshot.profiles.map((p) => ({ processName: p.processName, mappingSha256: p.resourceSha256, dataGroup: p.dataGroup })),\n snapshot,\n };\n }\n const manifestPath = readConfigurationSelector(c.raw, resource.manifestPath);\n const selected = resource.manifests.find((m) => m.file === manifestPath);\n if (!selected) throw Error(\"Unregistered direct manifest\");\n if (readConfigurationSelector(c.resolved, resource.manifestPath) !== selected.file) throw Error(\"Resolved direct manifest selection changed\");\n const bytes = inside(c.packageRoot, selected.file),\n manifest = processGroupManifestSchema.parse(JSON.parse(bytes.toString()));\n if (manifest.id !== selected.id) throw Error(\"Direct manifest identity differs\");\n for (const p of manifest.profiles)\n if (sha256(inside(c.packageRoot, path.join(path.dirname(selected.file), p.mappingFile))) !== p.mappingSha256)\n throw Error(\"Direct profile resource changed\");\n return {\n descriptor,\n resource,\n groupId: manifest.id,\n processName: manifest.processName,\n resourceSha256: sha256(bytes),\n profiles: manifest.profiles.map(({ processName, mappingSha256, dataGroup }) => ({ processName, mappingSha256, dataGroup })),\n manifest,\n manifestPath: selected.file,\n manifestFile: path.resolve(c.packageRoot, selected.file),\n };\n}\nfunction remove(raw: Record<string, unknown>, keys: readonly string[]): void {\n let current = raw;\n const parents: Array<[Record<string, unknown>, string]> = [];\n for (const key of keys.slice(0, -1)) {\n const next = current[key];\n if (!next || typeof next !== \"object\" || Array.isArray(next)) return;\n parents.push([current, key]);\n current = next as Record<string, unknown>;\n }\n delete current[keys.at(-1)!];\n for (const [parent, key] of parents.reverse()) {\n const value = parent[key];\n if (value && typeof value === \"object\" && !Object.keys(value).length) delete parent[key];\n else break;\n }\n}\nfunction projection(raw: Record<string, unknown>, d: ProcessGroupDirectDescriptor, excluded: readonly string[]) {\n const copy = structuredClone(raw);\n remove(copy, d.journalPath);\n remove(copy, d.runtimeRolePath);\n for (const r of d.resources) if (r.kind === \"file\") remove(copy, r.manifestPath);\n const uns = copy[\"uns\"];\n if (uns && typeof uns === \"object\" && !Array.isArray(uns)) for (const key of excluded) delete (uns as Record<string, unknown>)[key];\n // Removing a lifecycle leaf must not turn an otherwise empty publisher into a difference.\n const publisher = readConfigurationSelector(copy, d.publisherPath);\n if (publisher && typeof publisher === \"object\" && !Object.keys(publisher).length) remove(copy, d.publisherPath);\n return hash(copy);\n}\n/** Data-only installed-resource review. Does not stop, initialize, rewrite or grant launch authority. */\nexport function reviewInstalledProcessGroupDirectTransition(\n operationId: string,\n rawInput: unknown,\n configs: DirectTransitionConfigurations,\n stateRoot: string,\n excludedUnsFields: readonly string[] = [],\n) {\n const input = processGroupDirectInputSchema.parse(rawInput),\n owner = input.target.controller,\n first = configs.source.publisher,\n target = configs.target;\n const pkg = (c: Config) => JSON.parse(read(path.join(c.packageRoot, \"package.json\")).toString());\n for (const [p, c] of [\n [input.source.publisher, first],\n [input.source.receiver, configs.source.receiver],\n [input.target, target],\n ] as const) {\n if (\n path.resolve(c.packageRoot, \"instances\", p.instanceId) !== c.instanceDirectory ||\n fs.realpathSync(c.instanceDirectory) !== c.instanceDirectory ||\n pkg(c).name !== p.rttNode ||\n pkg(c).version !== p.version\n )\n throw Error(\"Exact installed package and instance placement required\");\n }\n const context = (c: Config) => ({\n packageRoot: c.packageRoot,\n instanceDirectory: c.instanceDirectory,\n rawConfiguration: c.raw,\n channels: resolvedProcessGroupChannels(c.resolved),\n controllerName: owner,\n stateRoot,\n });\n const old = authorizeProcessGroupRuntime(context(first)),\n receiver = authorizeProcessGroupRuntime(context(configs.source.receiver));\n if (\n old.role !== \"target\" ||\n receiver.role !== \"receiver\" ||\n old.file !== receiver.file ||\n old.sha256 !== receiver.sha256 ||\n old.directory !== receiver.directory ||\n !old.journalId ||\n old.journalId !== receiver.journalId\n )\n throw Error(\"Exact authorized publisher/receiver owners required\");\n const sourcePolicy = read(old.file, true),\n sourceDescriptor = selectedProcessGroupDescriptor(first.packageRoot, first.raw);\n if (!sourceDescriptor) throw Error(\"Missing source shared contract\");\n const normalized = normalizeRuntimeProcessGroup(first.raw, sourceDescriptor),\n direct = describeDirectProcessGroup(target),\n d = direct.descriptor;\n const namespace = sourceDescriptor.namespace;\n if (\n d.namespace !== namespace ||\n hash(d.publisherPath) !== hash(sourceDescriptor.publisherPath) ||\n hash(d.journalPath) !== hash(sourceDescriptor.journalPath) ||\n hash(d.runtimeRolePath) !== hash(sourceDescriptor.runtimeRolePath) ||\n direct.groupId !== old.groupId ||\n direct.processName !== old.groupProcessName ||\n (target.raw[\"uns\"] as Record<string, unknown>)?.[\"processName\"] !== old.groupProcessName ||\n projection(first.raw, d, excludedUnsFields) !== projection(target.raw, d, excludedUnsFields)\n )\n throw Error(\"Direct business configuration, selector or group identity changed\");\n const channels = groupChannelsHash(context(first).channels);\n if (channels !== groupChannelsHash(context(configs.source.receiver).channels) || channels !== groupChannelsHash(context(target).channels))\n throw Error(\"Direct broker/channel identity changed\");\n for (const c of [first, configs.source.receiver, target])\n if ((resolvedProcessGroupChannels(c.resolved)[2] as { publishQueue?: { enabled?: boolean } }).publishQueue?.enabled === true)\n throw Error(\"Initial direct retirement requires disabled disk MQTT output\");\n let reference, sourceResourceSha256: string;\n if (sourceDescriptor.protocolVersion === 2) {\n if (direct.resource.kind !== \"configuration\" || !direct.snapshot) throw Error(\"Resource kind must remain configuration based\");\n const generation = describeInstalledProcessGroupGeneration(first);\n reference = generation.reference;\n sourceResourceSha256 = configurationGroupSnapshot(readConfigurationSelector(first.raw, sourceDescriptor.groupPath)).sha256;\n } else {\n if (direct.resource.kind !== \"file\" || !direct.manifest) throw Error(\"Resource kind must remain file based\");\n const journal = processGroupJournalSchema.parse(normalized.journal);\n const declared = sourceDescriptor.manifests.find((m) => m.file === journal.groupManifest);\n if (!declared) throw Error(\"Unregistered original manifest\");\n const bytes = inside(first.packageRoot, declared.file),\n manifest = processGroupManifestSchema.parse(JSON.parse(bytes.toString()));\n sourceResourceSha256 = sha256(bytes);\n const contract = processGroupJournalContract(processGroupSourceIdentity(context(first).channels[1] as never), journal, manifest.profiles);\n reference = {\n directory: old.directory,\n journalId: old.journalId,\n journalContractSha256: sha256(contract),\n generationId: manifest.id,\n contractVersion: 1 as const,\n maxRecords: journal.maxRecords,\n maxBytes: journal.maxBytes,\n minFreeBytes: journal.minFreeBytes,\n profiles: manifest.profiles.map(({ processName, mappingSha256, dataGroup }) => ({ processName, mappingSha256, dataGroup })),\n };\n }\n const journal = retiredJournalReferenceSchema.parse(reference) as GenerationJournalReference;\n if (sourceResourceSha256 !== direct.resourceSha256 || hash(journal.profiles) !== hash(direct.profiles))\n throw Error(\"Direct profile resources, paths or units changed\");\n const usage = inspectGenerationJournal(journal); // Pending work is allowed at preview, never at policy switch.\n if (!Buffer.from(sourcePolicy.toString(), \"utf8\").equals(sourcePolicy)) throw Error(\"Original policy encoding cannot be retained exactly\");\n const member = (placement: typeof input.target, c: Config) => ({\n placement,\n processName: String((c.raw[\"uns\"] as Record<string, unknown>)[\"processName\"]),\n configurationSha256: hash(c.raw),\n artifactSha256: groupArtifactHash(c.packageRoot),\n });\n const policy = processGroupRetirementPolicySchema.parse({\n schemaVersion: 5,\n kind: \"uns-process-group-direct-retirement\",\n protocolVersion: 1,\n operationId,\n packageName: pkg(first).name,\n namespace,\n groupId: old.groupId,\n controllerName: owner,\n stateRoot,\n recovery: \"open\",\n journal,\n sourcePolicyJson: sourcePolicy.toString(),\n sourcePolicySha256: sha256(sourcePolicy),\n source: {\n publisher: {\n ...member(input.source.publisher, first),\n policyConfigurationSha256: sourceDescriptor.protocolVersion === 2 ? configurationResourceHash(first.raw) : hash(first.raw),\n },\n receiver: {\n ...member(input.source.receiver, configs.source.receiver),\n policyConfigurationSha256:\n sourceDescriptor.protocolVersion === 2 ? configurationResourceHash(configs.source.receiver.raw) : hash(configs.source.receiver.raw),\n },\n },\n target: {\n ...member(input.target, target),\n packageRoot: target.packageRoot,\n descriptorSha256: hash(d),\n resourceSha256: direct.resourceSha256,\n channelsSha256: channels,\n },\n });\n if (sha256(read(old.file, true)) !== policy.sourcePolicySha256) throw Error(\"Original policy changed during direct review\");\n const targetPolicy = Buffer.from(JSON.stringify(policy));\n if (targetPolicy.length > 65536) throw Error(\"Retirement policy byte budget exceeded\");\n return {\n review: {\n protocolVersion: 1 as const,\n kind: \"paired-to-direct\" as const,\n input,\n operationId,\n policyFile: old.file,\n sourcePolicySha256: sha256(sourcePolicy),\n targetPolicySha256: sha256(targetPolicy),\n journal,\n source: policy.source,\n target: policy.target,\n namespace,\n groupId: old.groupId,\n delivery: { inputPausePossible: true, exactlyOnceOutput: false, brokerReplayNotTransferred: true },\n usage,\n },\n sourcePolicy,\n targetPolicy,\n };\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import type { UpgradeConfiguration } from "./process-group-upgrade.js";
2
+ export type DirectRuntimeContext = UpgradeConfiguration & {
3
+ controllerName: string;
4
+ operationId?: string;
5
+ launchId?: string;
6
+ };
7
+ /** Startup guard, shared by host and application. An installed declaration never grants authority. */
8
+ export declare function assertProcessGroupDirectLaunch(context: DirectRuntimeContext): void;
9
+ /** PID/launch-bound observation, never authority. Start after output confirmation and input handler setup. */
10
+ export declare function trackProcessGroupDirectReadiness(context: DirectRuntimeContext, ready: () => boolean): () => void;
11
+ export declare function inspectProcessGroupDirectReadiness(directory: string, expected: {
12
+ pid: number;
13
+ launchId: string;
14
+ configurationSha256: string;
15
+ }, now?: number): boolean;
16
+ /** Preserve the managed registry in a direct process; never inherit a journal-mode launch permit. */
17
+ export declare function processGroupDirectLaunchEnvironment(operationId: string | undefined): Record<string, string>;
18
+ //# sourceMappingURL=process-group-direct-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-group-direct-runtime.d.ts","sourceRoot":"","sources":["../../src/runtime/process-group-direct-runtime.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEvE,MAAM,MAAM,oBAAoB,GAAG,oBAAoB,GAAG;IACxD,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AACF,sGAAsG;AACtG,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CA4ElF;AAED,8GAA8G;AAC9G,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,oBAAoB,EAAE,KAAK,EAAE,MAAM,OAAO,GAAG,MAAM,IAAI,CAgChH;AACD,wBAAgB,kCAAkC,CAChD,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAA;CAAE,EACxE,GAAG,SAAa,GACf,OAAO,CAuBT;AAED,qGAAqG;AACrG,wBAAgB,mCAAmC,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ3G"}
@@ -0,0 +1,154 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { z } from "zod";
5
+ import { configuredGroupProcessNames, hasProcessGroupAuthorization, parseProcessGroupRetirementPolicy } from "./process-group-authorization.js";
6
+ import { resolvedProcessGroupChannels } from "./process-group-contract.js";
7
+ import { describeDirectProcessGroup, processGroupDirectDescriptor } from "./process-group-direct-review.js";
8
+ import { inspectGenerationJournal } from "./process-group-generation.js";
9
+ import { groupArtifactHash, groupChannelsHash, configurationAuthorizationHash as hash, assertPrivateProcessGroupDirectory as privateDirectory, readProcessGroupResource as read, } from "./process-group-resources.js";
10
+ /** Startup guard, shared by host and application. An installed declaration never grants authority. */
11
+ export function assertProcessGroupDirectLaunch(context) {
12
+ if (!hasProcessGroupAuthorization())
13
+ return; // Standalone deployments without a managed journal remain supported.
14
+ const names = configuredGroupProcessNames(), name = String(context.raw["uns"]?.["processName"]);
15
+ if (!names.has(name))
16
+ return;
17
+ const d = processGroupDirectDescriptor(context.packageRoot);
18
+ if (!d)
19
+ throw Error("Retained group identity requires a reviewed direct runtime");
20
+ const root = process.env["UNS_PROCESS_GROUP_STATE_ROOT"];
21
+ const directory = process.env["UNS_PROCESS_GROUP_AUTHORIZATION_DIRECTORY"];
22
+ const single = process.env["UNS_PROCESS_GROUP_AUTHORIZATION_FILE"];
23
+ const registry = path.join(root, d.namespace, "authorizations");
24
+ privateDirectory(root);
25
+ privateDirectory(registry);
26
+ if (directory && directory !== root && directory !== registry)
27
+ throw Error("Foreign direct policy registry");
28
+ const files = new Set();
29
+ if (single)
30
+ files.add(single);
31
+ if (directory) {
32
+ const entries = fs.readdirSync(registry, { withFileTypes: true });
33
+ if (entries.length > 64)
34
+ throw Error("Direct policy budget exceeded");
35
+ for (const e of entries)
36
+ if (e.name.endsWith(".json"))
37
+ files.add(path.join(registry, e.name));
38
+ }
39
+ const policies = [...files]
40
+ .map((file) => ({ file, raw: JSON.parse(read(file, true).toString()) }))
41
+ .filter((p) => p.raw.schemaVersion === 5 && p.raw.target?.processName === name);
42
+ if (policies.length !== 1)
43
+ throw Error("Group input owners remain active or retired; reviewed direct authority required");
44
+ const { file, raw } = policies[0], p = parseProcessGroupRetirementPolicy(raw), actual = describeDirectProcessGroup(context), channels = resolvedProcessGroupChannels(context.resolved), pkg = JSON.parse(read(path.join(context.packageRoot, "package.json")).toString());
45
+ if (p.stateRoot !== root ||
46
+ p.namespace !== d.namespace ||
47
+ file !== path.join(registry, p.journal.generationId + ".json") ||
48
+ context.controllerName !== p.controllerName ||
49
+ pkg.name !== p.packageName ||
50
+ actual.groupId !== p.groupId ||
51
+ actual.processName !== name ||
52
+ actual.resourceSha256 !== p.target.resourceSha256 ||
53
+ hash(actual.profiles) !== hash(p.journal.profiles))
54
+ throw Error("Retained direct group resource or identity changed");
55
+ if (path.resolve(context.packageRoot) !== context.packageRoot ||
56
+ fs.realpathSync(context.packageRoot) !== context.packageRoot ||
57
+ path.dirname(context.instanceDirectory) !== path.join(context.packageRoot, "instances") ||
58
+ fs.realpathSync(context.instanceDirectory) !== context.instanceDirectory ||
59
+ !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(path.basename(context.instanceDirectory)))
60
+ throw Error("Canonical installed direct instance required");
61
+ const usage = inspectGenerationJournal(p.journal);
62
+ if (usage.records || usage.bytes)
63
+ throw Error("Retained input journal is not empty; direct launch blocked");
64
+ if (p.recovery === "closed")
65
+ return; // Original/profile and journal-mode launches remain fenced by schema5.
66
+ if (context.packageRoot !== p.target.packageRoot ||
67
+ pkg.version !== p.target.placement.version ||
68
+ context.instanceDirectory !== path.join(context.packageRoot, "instances", p.target.placement.instanceId) ||
69
+ fs.realpathSync(context.instanceDirectory) !== context.instanceDirectory ||
70
+ hash(context.raw) !== p.target.configurationSha256 ||
71
+ groupArtifactHash(context.packageRoot) !== p.target.artifactSha256 ||
72
+ hash(d) !== p.target.descriptorSha256 ||
73
+ groupChannelsHash(channels) !== p.target.channelsSha256 ||
74
+ channels[2].publishQueue?.enabled === true)
75
+ throw Error("Exact reviewed direct placement, configuration and artifact required");
76
+ const r = JSON.parse(read(path.join(context.instanceDirectory, "process-group-reservation.json"), true).toString());
77
+ if (!z.string().uuid().safeParse(context.launchId).success ||
78
+ context.operationId !== p.operationId ||
79
+ r.operationId !== p.operationId ||
80
+ r.role !== "target" ||
81
+ r.configurationChecksum !== p.target.configurationSha256 ||
82
+ r.lastLaunch?.launchId !== context.launchId ||
83
+ !z.string().uuid().safeParse(r.lastLaunch?.requestId).success)
84
+ throw Error("Direct target requires its exact reviewed launch reservation");
85
+ }
86
+ /** PID/launch-bound observation, never authority. Start after output confirmation and input handler setup. */
87
+ export function trackProcessGroupDirectReadiness(context, ready) {
88
+ assertProcessGroupDirectLaunch(context);
89
+ if (!context.launchId)
90
+ return () => { };
91
+ const file = path.join(context.instanceDirectory, "process-group-direct-readiness.json");
92
+ let active = true;
93
+ const publish = () => {
94
+ const bytes = JSON.stringify({
95
+ protocolVersion: 1,
96
+ pid: process.pid,
97
+ launchId: context.launchId,
98
+ configurationSha256: hash(context.raw),
99
+ ready: active && ready(),
100
+ at: Date.now(),
101
+ });
102
+ const temp = file + "." + randomUUID() + ".tmp", fd = fs.openSync(temp, "wx", 0o600);
103
+ try {
104
+ fs.writeFileSync(fd, bytes);
105
+ fs.fsyncSync(fd);
106
+ }
107
+ finally {
108
+ fs.closeSync(fd);
109
+ }
110
+ fs.renameSync(temp, file);
111
+ };
112
+ publish();
113
+ const timer = setInterval(publish, 1000);
114
+ timer.unref();
115
+ return () => {
116
+ active = false;
117
+ clearInterval(timer);
118
+ publish();
119
+ };
120
+ }
121
+ export function inspectProcessGroupDirectReadiness(directory, expected, now = Date.now()) {
122
+ try {
123
+ const r = z
124
+ .strictObject({
125
+ protocolVersion: z.literal(1),
126
+ pid: z.number().int().positive(),
127
+ launchId: z.string().uuid(),
128
+ configurationSha256: z.string().regex(/^[a-f0-9]{64}$/),
129
+ ready: z.boolean(),
130
+ at: z.number().int().positive(),
131
+ })
132
+ .parse(JSON.parse(read(path.join(directory, "process-group-direct-readiness.json"), true).toString()));
133
+ return (r.ready &&
134
+ r.pid === expected.pid &&
135
+ r.launchId === expected.launchId &&
136
+ r.configurationSha256 === expected.configurationSha256 &&
137
+ r.at <= now + 1000 &&
138
+ now - r.at <= 5000);
139
+ }
140
+ catch {
141
+ return false;
142
+ }
143
+ }
144
+ /** Preserve the managed registry in a direct process; never inherit a journal-mode launch permit. */
145
+ export function processGroupDirectLaunchEnvironment(operationId) {
146
+ return {
147
+ UNS_PROCESS_GROUP_LOCAL_PILOT: "0",
148
+ UNS_PROCESS_GROUP_AUTHORIZATION_FILE: process.env["UNS_PROCESS_GROUP_AUTHORIZATION_FILE"] ?? "",
149
+ UNS_PROCESS_GROUP_AUTHORIZATION_DIRECTORY: process.env["UNS_PROCESS_GROUP_AUTHORIZATION_DIRECTORY"] ?? "",
150
+ UNS_PROCESS_GROUP_STATE_ROOT: process.env["UNS_PROCESS_GROUP_STATE_ROOT"] ?? "",
151
+ UNS_PROCESS_GROUP_OPERATION_ID: operationId ?? "",
152
+ };
153
+ }
154
+ //# sourceMappingURL=process-group-direct-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-group-direct-runtime.js","sourceRoot":"","sources":["../../src/runtime/process-group-direct-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\n\nimport { configuredGroupProcessNames, hasProcessGroupAuthorization, parseProcessGroupRetirementPolicy } from \"./process-group-authorization.js\";\nimport { resolvedProcessGroupChannels } from \"./process-group-contract.js\";\nimport { describeDirectProcessGroup, processGroupDirectDescriptor } from \"./process-group-direct-review.js\";\nimport { type GenerationJournalReference, inspectGenerationJournal } from \"./process-group-generation.js\";\nimport {\n groupArtifactHash,\n groupChannelsHash,\n configurationAuthorizationHash as hash,\n assertPrivateProcessGroupDirectory as privateDirectory,\n readProcessGroupResource as read,\n} from \"./process-group-resources.js\";\nimport type { UpgradeConfiguration } from \"./process-group-upgrade.js\";\n\nexport type DirectRuntimeContext = UpgradeConfiguration & {\n controllerName: string;\n operationId?: string;\n launchId?: string;\n};\n/** Startup guard, shared by host and application. An installed declaration never grants authority. */\nexport function assertProcessGroupDirectLaunch(context: DirectRuntimeContext): void {\n if (!hasProcessGroupAuthorization()) return; // Standalone deployments without a managed journal remain supported.\n const names = configuredGroupProcessNames(),\n name = String((context.raw[\"uns\"] as Record<string, unknown>)?.[\"processName\"]);\n if (!names.has(name)) return;\n const d = processGroupDirectDescriptor(context.packageRoot);\n if (!d) throw Error(\"Retained group identity requires a reviewed direct runtime\");\n const root = process.env[\"UNS_PROCESS_GROUP_STATE_ROOT\"]!;\n const directory = process.env[\"UNS_PROCESS_GROUP_AUTHORIZATION_DIRECTORY\"];\n const single = process.env[\"UNS_PROCESS_GROUP_AUTHORIZATION_FILE\"];\n const registry = path.join(root, d.namespace, \"authorizations\");\n privateDirectory(root);\n privateDirectory(registry);\n if (directory && directory !== root && directory !== registry) throw Error(\"Foreign direct policy registry\");\n const files = new Set<string>();\n if (single) files.add(single);\n if (directory) {\n const entries = fs.readdirSync(registry, { withFileTypes: true });\n if (entries.length > 64) throw Error(\"Direct policy budget exceeded\");\n for (const e of entries) if (e.name.endsWith(\".json\")) files.add(path.join(registry, e.name));\n }\n const policies = [...files]\n .map((file) => ({ file, raw: JSON.parse(read(file, true).toString()) }))\n .filter((p) => p.raw.schemaVersion === 5 && p.raw.target?.processName === name);\n if (policies.length !== 1) throw Error(\"Group input owners remain active or retired; reviewed direct authority required\");\n const { file, raw } = policies[0]!,\n p = parseProcessGroupRetirementPolicy(raw),\n actual = describeDirectProcessGroup(context),\n channels = resolvedProcessGroupChannels(context.resolved),\n pkg = JSON.parse(read(path.join(context.packageRoot, \"package.json\")).toString());\n if (\n p.stateRoot !== root ||\n p.namespace !== d.namespace ||\n file !== path.join(registry, p.journal.generationId + \".json\") ||\n context.controllerName !== p.controllerName ||\n pkg.name !== p.packageName ||\n actual.groupId !== p.groupId ||\n actual.processName !== name ||\n actual.resourceSha256 !== p.target.resourceSha256 ||\n hash(actual.profiles) !== hash(p.journal.profiles)\n )\n throw Error(\"Retained direct group resource or identity changed\");\n if (\n path.resolve(context.packageRoot) !== context.packageRoot ||\n fs.realpathSync(context.packageRoot) !== context.packageRoot ||\n path.dirname(context.instanceDirectory) !== path.join(context.packageRoot, \"instances\") ||\n fs.realpathSync(context.instanceDirectory) !== context.instanceDirectory ||\n !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(path.basename(context.instanceDirectory))\n )\n throw Error(\"Canonical installed direct instance required\");\n const usage = inspectGenerationJournal(p.journal as GenerationJournalReference);\n if (usage.records || usage.bytes) throw Error(\"Retained input journal is not empty; direct launch blocked\");\n if (p.recovery === \"closed\") return; // Original/profile and journal-mode launches remain fenced by schema5.\n if (\n context.packageRoot !== p.target.packageRoot ||\n pkg.version !== p.target.placement.version ||\n context.instanceDirectory !== path.join(context.packageRoot, \"instances\", p.target.placement.instanceId) ||\n fs.realpathSync(context.instanceDirectory) !== context.instanceDirectory ||\n hash(context.raw) !== p.target.configurationSha256 ||\n groupArtifactHash(context.packageRoot) !== p.target.artifactSha256 ||\n hash(d) !== p.target.descriptorSha256 ||\n groupChannelsHash(channels) !== p.target.channelsSha256 ||\n (channels[2] as { publishQueue?: { enabled?: boolean } }).publishQueue?.enabled === true\n )\n throw Error(\"Exact reviewed direct placement, configuration and artifact required\");\n const r = JSON.parse(read(path.join(context.instanceDirectory, \"process-group-reservation.json\"), true).toString());\n if (\n !z.string().uuid().safeParse(context.launchId).success ||\n context.operationId !== p.operationId ||\n r.operationId !== p.operationId ||\n r.role !== \"target\" ||\n r.configurationChecksum !== p.target.configurationSha256 ||\n r.lastLaunch?.launchId !== context.launchId ||\n !z.string().uuid().safeParse(r.lastLaunch?.requestId).success\n )\n throw Error(\"Direct target requires its exact reviewed launch reservation\");\n}\n\n/** PID/launch-bound observation, never authority. Start after output confirmation and input handler setup. */\nexport function trackProcessGroupDirectReadiness(context: DirectRuntimeContext, ready: () => boolean): () => void {\n assertProcessGroupDirectLaunch(context);\n if (!context.launchId) return () => {};\n const file = path.join(context.instanceDirectory, \"process-group-direct-readiness.json\");\n let active = true;\n const publish = () => {\n const bytes = JSON.stringify({\n protocolVersion: 1,\n pid: process.pid,\n launchId: context.launchId,\n configurationSha256: hash(context.raw),\n ready: active && ready(),\n at: Date.now(),\n });\n const temp = file + \".\" + randomUUID() + \".tmp\",\n fd = fs.openSync(temp, \"wx\", 0o600);\n try {\n fs.writeFileSync(fd, bytes);\n fs.fsyncSync(fd);\n } finally {\n fs.closeSync(fd);\n }\n fs.renameSync(temp, file);\n };\n publish();\n const timer = setInterval(publish, 1000);\n timer.unref();\n return () => {\n active = false;\n clearInterval(timer);\n publish();\n };\n}\nexport function inspectProcessGroupDirectReadiness(\n directory: string,\n expected: { pid: number; launchId: string; configurationSha256: string },\n now = Date.now(),\n): boolean {\n try {\n const r = z\n .strictObject({\n protocolVersion: z.literal(1),\n pid: z.number().int().positive(),\n launchId: z.string().uuid(),\n configurationSha256: z.string().regex(/^[a-f0-9]{64}$/),\n ready: z.boolean(),\n at: z.number().int().positive(),\n })\n .parse(JSON.parse(read(path.join(directory, \"process-group-direct-readiness.json\"), true).toString()));\n return (\n r.ready &&\n r.pid === expected.pid &&\n r.launchId === expected.launchId &&\n r.configurationSha256 === expected.configurationSha256 &&\n r.at <= now + 1000 &&\n now - r.at <= 5000\n );\n } catch {\n return false;\n }\n}\n\n/** Preserve the managed registry in a direct process; never inherit a journal-mode launch permit. */\nexport function processGroupDirectLaunchEnvironment(operationId: string | undefined): Record<string, string> {\n return {\n UNS_PROCESS_GROUP_LOCAL_PILOT: \"0\",\n UNS_PROCESS_GROUP_AUTHORIZATION_FILE: process.env[\"UNS_PROCESS_GROUP_AUTHORIZATION_FILE\"] ?? \"\",\n UNS_PROCESS_GROUP_AUTHORIZATION_DIRECTORY: process.env[\"UNS_PROCESS_GROUP_AUTHORIZATION_DIRECTORY\"] ?? \"\",\n UNS_PROCESS_GROUP_STATE_ROOT: process.env[\"UNS_PROCESS_GROUP_STATE_ROOT\"] ?? \"\",\n UNS_PROCESS_GROUP_OPERATION_ID: operationId ?? \"\",\n };\n}\n"]}
@@ -79,6 +79,7 @@ const namespaces = rootEntries
79
79
  .sort();
80
80
  if (namespaces.length > 64) fail();
81
81
  const capturedGroups = new Set();
82
+ const retirementChecks = new Map();
82
83
  for (const namespace of namespaces) {
83
84
  if (!/^[a-z][a-z0-9-]{0,99}$/.test(namespace)) fail();
84
85
  const namespaceRoot = path.join(root, namespace),
@@ -240,9 +241,52 @@ for (const namespace of namespaces) {
240
241
  if (snapshotBytes > limits.maximumSnapshotBytes) fail();
241
242
  info[name === "admission.sqlite" ? "admissionSha256" : "ownershipSha256"] = fileHash(p);
242
243
  }
244
+ // Retired ownership is part of recovery evidence, never an automatic launch permit.
245
+ // Version2 makes an older transport fail closed instead of silently omitting it.
246
+ const policyDirectory=path.join(namespaceRoot,"authorizations"),policyFile=path.join(policyDirectory,group+".json");
247
+ let policyExists=false;
248
+ try{fs.lstatSync(policyFile);policyExists=true;}catch(e){if(e.code!=="ENOENT")throw e;}
249
+ if(policyExists){
250
+ check(policyDirectory,true);check(policyFile);
251
+ if(fs.statSync(policyFile).size>65536)fail();
252
+ const policy=fs.readFileSync(policyFile),p=JSON.parse(policy.toString());
253
+ if(p.schemaVersion===5){
254
+ if(info.usage.records!==0||info.usage.bytes!==0||p.kind!=="uns-process-group-direct-retirement"||p.protocolVersion!==1||p.stateRoot!==root||p.namespace!==namespace||
255
+ p.journal?.directory!==source||p.journal?.generationId!==group||p.journal?.journalId!==info.journalId||
256
+ p.journal?.journalContractSha256!==info.contractSha256||typeof p.sourcePolicyJson!=="string"||Buffer.byteLength(p.sourcePolicyJson)>32768||hash(p.sourcePolicyJson)!==p.sourcePolicySha256||
257
+ !["open","closed"].includes(p.recovery))fail();
258
+ fs.writeFileSync(path.join(target,"retirement-policy.json"),policy,{mode:0o600,flag:"wx"});
259
+ info.retirementPolicySha256=hash(policy);info.retirementPolicyBytes=policy.length;
260
+ snapshotBytes+=policy.length;if(snapshotBytes>limits.maximumSnapshotBytes)fail();
261
+ // Freeze this observation; a concurrent policy switch requires a new consistent capture.
262
+ if(!fs.readFileSync(policyFile).equals(policy))fail();
263
+ manifest.schemaVersion=2;
264
+ retirementChecks.set(policyFile,hash(policy));
265
+ }
266
+ }
243
267
  manifest.groups.push(info);
244
268
  }
245
269
  }
270
+ // Direct configurations no longer name the old journal. Its retained policy must
271
+ // still resolve to captured state, even after the stopped source configs are removed.
272
+ let registryFiles=0;
273
+ for(const namespace of namespaces){
274
+ const registry=path.join(root,namespace,"authorizations");
275
+ let entries;
276
+ try{check(registry,true);entries=fs.readdirSync(registry,{withFileTypes:true});}catch(e){if(e.code==="ENOENT")continue;throw e;}
277
+ if(entries.length>64||entries.some(e=>e.isSymbolicLink()))fail();
278
+ for(const entry of entries){
279
+ if(!entry.name.endsWith(".json"))continue;
280
+ if(++registryFiles>64||!entry.isFile()||!/^([a-z][a-z0-9-]{0,99})\.json$/.test(entry.name))fail();
281
+ const file=path.join(registry,entry.name);check(file);if(fs.statSync(file).size>65536)fail();
282
+ const bytes=fs.readFileSync(file),policy=JSON.parse(bytes.toString());
283
+ if(policy.schemaVersion!==5)continue;
284
+ const captured=manifest.groups.find(g=>g.namespace===namespace&&g.group===policy.journal?.generationId);
285
+ if(!captured||captured.retirementPolicySha256!==hash(bytes)||captured.journalId!==policy.journal?.journalId||
286
+ policy.namespace!==namespace||policy.stateRoot!==root||entry.name!==policy.journal.generationId+".json")fail();
287
+ }
288
+ }
289
+ for(const [file,digest] of retirementChecks){check(file);if(hash(fs.readFileSync(file))!==digest)fail();}
246
290
  const remaining = fs.statfsSync(output, { bigint: true });
247
291
  if (remaining.bavail * remaining.bsize < BigInt(snapshotBytes + 64 * 1024 * 1024)) fail();
248
292
  const manifestBytes = JSON.stringify(manifest) + "\n";
@@ -43,6 +43,7 @@ export default class MqttProxy {
43
43
  private resolveDefaultPort;
44
44
  private ensureStatusUpdateInterval;
45
45
  private ensureTransformationStatsInterval;
46
+ private lastTransportConnected;
46
47
  private emitSubscriptionReadiness;
47
48
  private subscribeToTopics;
48
49
  private buildServers;
@@ -1 +1 @@
1
- {"version":3,"file":"mqtt-proxy.d.ts","sourceRoot":"","sources":["../../src/uns-mqtt/mqtt-proxy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mqtt-proxy.d.ts","sourceRoot":"","sources":["../../src/uns-mqtt/mqtt-proxy.ts"],"names":[],"mappings":"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"}
@@ -70,7 +70,12 @@ export default class MqttProxy {
70
70
  }, 60000);
71
71
  }
72
72
  }
73
+ lastTransportConnected;
73
74
  emitSubscriptionReadiness(force = false) {
75
+ if (force || this.lastTransportConnected !== this.isConnected) {
76
+ this.lastTransportConnected = this.isConnected;
77
+ this.event.emit("mqttProxyStatus", { event: "mqtt-connected", value: this.isConnected ? 1 : 0, uom: DataSizeMeasurements.Bit, statusTopic: this.statusTopic + "mqtt-connected" });
78
+ }
74
79
  const ready = this.subscriptionReadiness.ready();
75
80
  if (!force && ready === this.lastSubscriptionReady)
76
81
  return;