@kungfu-tech/buildchain 4.0.2-alpha.30 → 4.0.2-alpha.32
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/architecture/agent-change-map.md +4 -1
- package/architecture/maintainability-debt.json +90 -58
- package/architecture/maintainability-policy.json +22 -23
- package/architecture/v4-architecture-constitution.md +23 -20
- package/architecture/v4-partial-mutation-recovery-qualification.json +4 -1
- package/architecture/v4-provider-operation-journal-contract.json +5 -2
- package/architecture/v4-release-activation-shadow-domain.json +5 -2
- package/architecture/v4-release-topology.json +17 -2
- package/architecture/v4-rust-wasm-production-authority.json +57 -0
- package/architecture/v4-stable-publication-fence.json +5 -2
- package/dist/site/buildchain-contract.json +5 -5
- package/dist/site/buildchain-site.json +44 -8
- package/dist/site/capability-registry.json +1 -1
- package/dist/site/kfd-claims.json +17 -5
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +1 -1
- package/dist/site/node-api-registry.json +27 -27
- package/dist/site/page-registry.json +39 -3
- package/dist/site/public-surface-audit.json +7 -3
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/site-manifest.json +5 -5
- package/dist/site/workflow-registry.json +4 -4
- package/docs/node-api-reference.md +60 -60
- package/docs/v4-rust-wasm-production-authority.md +58 -0
- package/package.json +5 -3
- package/packages/core/buildchain-v4-domain.wasm +0 -0
- package/packages/core/dev-delivery-candidate-identity.js +48 -11
- package/packages/core/release-tail-provider-plane.js +68 -1048
- package/packages/core/v4-canonical-contracts.js +9 -75
- package/packages/core/v4-domain-wasm-artifact.js +7 -0
- package/packages/core/v4-domain-wasm.js +216 -0
- package/packages/core/v4-partial-mutation-recovery-qualification.js +9 -386
- package/packages/core/v4-product-publication.js +18 -384
- package/packages/core/v4-provider-operation-journal.js +18 -487
- package/packages/core/v4-provider-readback-idempotency.js +12 -97
- package/packages/core/v4-release-activation-shadow.js +13 -500
- package/packages/core/v4-release-invocation.js +28 -389
- package/packages/core/v4-stable-publication-fence.js +13 -342
- package/scripts/build-v4-domain-wasm.mjs +189 -0
- package/scripts/check-action-bundles.mjs +12 -2
- package/scripts/check-v4-release-topology.mjs +50 -25
- package/scripts/copy-v4-domain-wasm.mjs +14 -0
- package/scripts/dev-delivery-warrant.mjs +7 -3
- package/scripts/generate-v4-universal-workflow-facades.mjs +8 -3
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
v4CanonicalBytes,
|
|
4
|
-
v4ContentRoot,
|
|
5
|
-
validateV4Root,
|
|
6
|
-
} from "./v4-canonical-contracts.js";
|
|
1
|
+
import { V4ContractFault } from "./v4-canonical-contracts.js";
|
|
2
|
+
import { V4DomainWasmFault, invokeV4DomainWasm } from "./v4-domain-wasm.js";
|
|
7
3
|
|
|
8
4
|
export const V4_RELEASE_INVOCATION_CONTRACT =
|
|
9
5
|
"kungfu-buildchain-v4-release-invocation/v1";
|
|
@@ -16,235 +12,25 @@ export const V4_RELEASE_RECEIPT_CONTRACT =
|
|
|
16
12
|
export const V4_RELEASE_PROVIDER_CONTRACT =
|
|
17
13
|
"kungfu-buildchain-release-tail-provider/v1";
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
]);
|
|
29
|
-
const EXECUTION_MODES = new Set(["fresh", "resume"]);
|
|
30
|
-
const COMPARISON_STATES = new Set(["identical", "ahead", "behind", "diverged"]);
|
|
31
|
-
|
|
32
|
-
function fault(code, path, message) {
|
|
33
|
-
throw new V4ContractFault(code, path, message);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function exactKeys(value, keys, path) {
|
|
37
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
38
|
-
fault("invalid-release-invocation", path, `${path} must be an object`);
|
|
39
|
-
const actual = Object.keys(value).sort();
|
|
40
|
-
const expected = [...keys].sort();
|
|
41
|
-
if (
|
|
42
|
-
actual.length !== expected.length ||
|
|
43
|
-
actual.some((key, index) => key !== expected[index])
|
|
44
|
-
)
|
|
45
|
-
fault(
|
|
46
|
-
"invalid-release-invocation-shape",
|
|
47
|
-
path,
|
|
48
|
-
`${path} keys are not canonical`,
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function sha(value, path, nullable = false) {
|
|
53
|
-
if (nullable && value === null) return value;
|
|
54
|
-
if (typeof value !== "string" || !SHA_PATTERN.test(value))
|
|
55
|
-
fault("invalid-release-sha", path, `${path} must be an exact Git SHA`);
|
|
56
|
-
return value;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function text(value, path) {
|
|
60
|
-
if (
|
|
61
|
-
typeof value !== "string" ||
|
|
62
|
-
value.length === 0 ||
|
|
63
|
-
/[^\x20-\x7e]/u.test(value)
|
|
64
|
-
)
|
|
65
|
-
fault("invalid-release-text", path, `${path} must be printable ASCII`);
|
|
66
|
-
return value;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function validatePublisher(value) {
|
|
70
|
-
exactKeys(
|
|
71
|
-
value,
|
|
72
|
-
["repository", "workflow", "workflowSha", "job"],
|
|
73
|
-
"$/publisher",
|
|
74
|
-
);
|
|
75
|
-
if (
|
|
76
|
-
value.repository !== "kungfu-systems/buildchain" ||
|
|
77
|
-
value.workflow !== ".github/workflows/.release-candidate-promote.yml" ||
|
|
78
|
-
value.job !== "apply"
|
|
79
|
-
)
|
|
80
|
-
fault(
|
|
81
|
-
"invalid-publisher-identity",
|
|
82
|
-
"$/publisher",
|
|
83
|
-
"publisher identity is not the canonical v4 APPLY job",
|
|
84
|
-
);
|
|
85
|
-
sha(value.workflowSha, "$/publisher/workflowSha");
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function validateRuntime(value) {
|
|
89
|
-
exactKeys(value, ["repository", "commit", "tree"], "$/runtime");
|
|
90
|
-
if (value.repository !== "kungfu-systems/buildchain")
|
|
91
|
-
fault(
|
|
92
|
-
"invalid-runtime-identity",
|
|
93
|
-
"$/runtime/repository",
|
|
94
|
-
"runtime repository is not canonical",
|
|
95
|
-
);
|
|
96
|
-
sha(value.commit, "$/runtime/commit");
|
|
97
|
-
sha(value.tree, "$/runtime/tree");
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function validateCandidate(value) {
|
|
101
|
-
exactKeys(value, ["repository", "commit", "tree", "version"], "$/candidate");
|
|
102
|
-
text(value.repository, "$/candidate/repository");
|
|
103
|
-
sha(value.commit, "$/candidate/commit");
|
|
104
|
-
sha(value.tree, "$/candidate/tree");
|
|
105
|
-
text(value.version, "$/candidate/version");
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function validateTarget(value) {
|
|
109
|
-
exactKeys(value, ["channel", "tag", "expectedOldSha"], "$/target");
|
|
110
|
-
if (
|
|
111
|
-
!["alpha", "stable"].includes(value.channel) ||
|
|
112
|
-
!TAG_PATTERN.test(value.tag)
|
|
113
|
-
)
|
|
114
|
-
fault(
|
|
115
|
-
"invalid-release-target",
|
|
116
|
-
"$/target",
|
|
117
|
-
"release channel and exact tag are not canonical",
|
|
118
|
-
);
|
|
119
|
-
sha(value.expectedOldSha, "$/target/expectedOldSha", true);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function validateAuthority(value) {
|
|
123
|
-
exactKeys(
|
|
124
|
-
value,
|
|
125
|
-
["policyRoot", "qualificationRoot", "warrantRoot"],
|
|
126
|
-
"$/authority",
|
|
127
|
-
);
|
|
128
|
-
for (const name of ["policyRoot", "qualificationRoot", "warrantRoot"])
|
|
129
|
-
validateV4Root(value[name], `$/authority/${name}`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function validateProvider(value, candidate) {
|
|
133
|
-
exactKeys(value, ["adapter", "contract", "repository"], "$/provider");
|
|
134
|
-
if (
|
|
135
|
-
value.adapter !== "built-in-provider-plane" ||
|
|
136
|
-
value.contract !== V4_RELEASE_PROVIDER_CONTRACT ||
|
|
137
|
-
value.repository !== candidate.repository
|
|
138
|
-
)
|
|
139
|
-
fault(
|
|
140
|
-
"invalid-release-provider",
|
|
141
|
-
"$/provider",
|
|
142
|
-
"provider identity must bind the built-in Provider Plane and candidate repository",
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function validateParent(value) {
|
|
147
|
-
exactKeys(
|
|
148
|
-
value,
|
|
149
|
-
["invocationRoot", "transactionRoot", "receiptRoot"],
|
|
150
|
-
"$/parent",
|
|
151
|
-
);
|
|
152
|
-
const roots = [
|
|
153
|
-
value.invocationRoot,
|
|
154
|
-
value.transactionRoot,
|
|
155
|
-
value.receiptRoot,
|
|
156
|
-
];
|
|
157
|
-
if (roots.every((root) => root === null)) return;
|
|
158
|
-
if (roots.some((root) => root === null))
|
|
159
|
-
fault(
|
|
160
|
-
"invalid-release-parent-lineage",
|
|
161
|
-
"$/parent",
|
|
162
|
-
"parent lineage roots must be either all null or all present",
|
|
163
|
-
);
|
|
164
|
-
roots.forEach((root, index) =>
|
|
165
|
-
validateV4Root(
|
|
166
|
-
root,
|
|
167
|
-
`$/parent/${["invocationRoot", "transactionRoot", "receiptRoot"][index]}`,
|
|
168
|
-
),
|
|
169
|
-
);
|
|
15
|
+
function invoke(operation, payload) {
|
|
16
|
+
try {
|
|
17
|
+
return invokeV4DomainWasm(operation, payload);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (error instanceof V4DomainWasmFault) {
|
|
20
|
+
throw new V4ContractFault(error.code, error.path, error.message);
|
|
21
|
+
}
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
170
24
|
}
|
|
171
25
|
|
|
172
26
|
export function createV4ReleaseInvocation(value) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
[
|
|
176
|
-
"schema",
|
|
177
|
-
"publisher",
|
|
178
|
-
"runtime",
|
|
179
|
-
"candidate",
|
|
180
|
-
"target",
|
|
181
|
-
"authority",
|
|
182
|
-
"provider",
|
|
183
|
-
"parent",
|
|
184
|
-
],
|
|
185
|
-
"$",
|
|
186
|
-
);
|
|
187
|
-
if (value.schema !== V4_RELEASE_INVOCATION_CONTRACT)
|
|
188
|
-
fault(
|
|
189
|
-
"invalid-release-invocation",
|
|
190
|
-
"$/schema",
|
|
191
|
-
"unsupported invocation schema",
|
|
192
|
-
);
|
|
193
|
-
validatePublisher(value.publisher);
|
|
194
|
-
validateRuntime(value.runtime);
|
|
195
|
-
validateCandidate(value.candidate);
|
|
196
|
-
validateTarget(value.target);
|
|
197
|
-
validateAuthority(value.authority);
|
|
198
|
-
validateProvider(value.provider, value.candidate);
|
|
199
|
-
validateParent(value.parent);
|
|
200
|
-
v4CanonicalBytes(value);
|
|
201
|
-
const roots = {
|
|
202
|
-
publisherRoot: v4ContentRoot(
|
|
203
|
-
"release-invocation-publisher",
|
|
204
|
-
value.publisher,
|
|
205
|
-
),
|
|
206
|
-
runtimeRoot: v4ContentRoot("release-invocation-runtime", value.runtime),
|
|
207
|
-
candidateRoot: v4ContentRoot(
|
|
208
|
-
"release-invocation-candidate",
|
|
209
|
-
value.candidate,
|
|
210
|
-
),
|
|
211
|
-
targetRoot: v4ContentRoot("release-invocation-target", value.target),
|
|
212
|
-
authorityRoot: v4ContentRoot(
|
|
213
|
-
"release-invocation-authority",
|
|
214
|
-
value.authority,
|
|
215
|
-
),
|
|
216
|
-
providerRoot: v4ContentRoot("release-invocation-provider", value.provider),
|
|
217
|
-
parentRoot: v4ContentRoot("release-invocation-parent", value.parent),
|
|
218
|
-
};
|
|
219
|
-
const invocationRoot = v4ContentRoot("release-invocation", {
|
|
220
|
-
schema: V4_RELEASE_INVOCATION_CONTRACT,
|
|
221
|
-
...roots,
|
|
222
|
-
});
|
|
223
|
-
return { invocation: value, roots: { ...roots, invocationRoot } };
|
|
27
|
+
const projected = invoke("release-invocation", value);
|
|
28
|
+
return { ...projected, invocation: value };
|
|
224
29
|
}
|
|
225
30
|
|
|
226
31
|
export function adaptV4ReleaseInvocation(value) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
fault(
|
|
230
|
-
"invalid-release-adapter",
|
|
231
|
-
"$adapter/schema",
|
|
232
|
-
"unsupported adapter schema",
|
|
233
|
-
);
|
|
234
|
-
exactKeys(value.route, ["surface", "execution"], "$adapter/route");
|
|
235
|
-
if (!ROUTE_SURFACES.has(value.route.surface))
|
|
236
|
-
fault(
|
|
237
|
-
"invalid-release-adapter",
|
|
238
|
-
"$adapter/route/surface",
|
|
239
|
-
"unsupported route surface",
|
|
240
|
-
);
|
|
241
|
-
if (!EXECUTION_MODES.has(value.route.execution))
|
|
242
|
-
fault(
|
|
243
|
-
"invalid-release-adapter",
|
|
244
|
-
"$adapter/route/execution",
|
|
245
|
-
"unsupported execution mode",
|
|
246
|
-
);
|
|
247
|
-
return createV4ReleaseInvocation(value.invocation);
|
|
32
|
+
const projected = invoke("release-invocation-adapter", value);
|
|
33
|
+
return { ...projected, invocation: value.invocation };
|
|
248
34
|
}
|
|
249
35
|
|
|
250
36
|
export function planV4ReleaseRoute({
|
|
@@ -256,170 +42,23 @@ export function planV4ReleaseRoute({
|
|
|
256
42
|
dryRun = false,
|
|
257
43
|
resume = false,
|
|
258
44
|
}) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
/^release\/v[0-9]+\/v[0-9]+\.[0-9]+$/u.test(targetRef) ||
|
|
271
|
-
["publish-gate/major", "major-gate"].includes(targetRef);
|
|
272
|
-
if (!alphaLane && !stableLane)
|
|
273
|
-
fault(
|
|
274
|
-
"invalid-release-route",
|
|
275
|
-
"$route/targetRef",
|
|
276
|
-
"source lane is not a supported v4 release lane",
|
|
277
|
-
);
|
|
278
|
-
const derivedChannel = alphaLane ? "alpha" : "stable";
|
|
279
|
-
const normalizedRequested =
|
|
280
|
-
requestedChannel === "alpha"
|
|
281
|
-
? "alpha"
|
|
282
|
-
: ["release", "stable", "major"].includes(requestedChannel)
|
|
283
|
-
? "stable"
|
|
284
|
-
: requestedChannel === ""
|
|
285
|
-
? derivedChannel
|
|
286
|
-
: "";
|
|
287
|
-
if (!normalizedRequested || normalizedRequested !== derivedChannel)
|
|
288
|
-
fault(
|
|
289
|
-
"invalid-release-route",
|
|
290
|
-
"$route/channel",
|
|
291
|
-
"requested channel does not match the source lane",
|
|
292
|
-
);
|
|
293
|
-
let decision = resume ? "Resume" : "Fresh";
|
|
294
|
-
let reason = resume ? "resume" : "fresh";
|
|
295
|
-
if (comparisonStatus === "ahead" && !resume && !dryRun) {
|
|
296
|
-
decision = "NoOp";
|
|
297
|
-
reason = "source-advanced";
|
|
298
|
-
} else if (
|
|
299
|
-
requestedSha !== observedSha &&
|
|
300
|
-
!(resume && comparisonStatus === "ahead") &&
|
|
301
|
-
!(dryRun && comparisonStatus === "ahead")
|
|
302
|
-
) {
|
|
303
|
-
decision = "Blocked";
|
|
304
|
-
reason = `source-${comparisonStatus}`;
|
|
305
|
-
}
|
|
306
|
-
return Object.freeze({
|
|
307
|
-
decision,
|
|
308
|
-
reason,
|
|
309
|
-
channel: normalizedRequested,
|
|
310
|
-
targetRef,
|
|
311
|
-
requestedSha,
|
|
312
|
-
observedSha,
|
|
313
|
-
});
|
|
45
|
+
return Object.freeze(
|
|
46
|
+
invoke("release-route", {
|
|
47
|
+
requestedSha,
|
|
48
|
+
observedSha,
|
|
49
|
+
comparisonStatus,
|
|
50
|
+
requestedChannel,
|
|
51
|
+
targetRef,
|
|
52
|
+
dryRun,
|
|
53
|
+
resume,
|
|
54
|
+
}),
|
|
55
|
+
);
|
|
314
56
|
}
|
|
315
57
|
|
|
316
58
|
export function createV4ReleaseTransaction(value) {
|
|
317
|
-
|
|
318
|
-
value,
|
|
319
|
-
[
|
|
320
|
-
"invocationRoot",
|
|
321
|
-
"publisherRoot",
|
|
322
|
-
"runtimeRoot",
|
|
323
|
-
"providerRoot",
|
|
324
|
-
"parentRoot",
|
|
325
|
-
],
|
|
326
|
-
"$transaction",
|
|
327
|
-
);
|
|
328
|
-
for (const name of [
|
|
329
|
-
"invocationRoot",
|
|
330
|
-
"publisherRoot",
|
|
331
|
-
"runtimeRoot",
|
|
332
|
-
"providerRoot",
|
|
333
|
-
"parentRoot",
|
|
334
|
-
])
|
|
335
|
-
validateV4Root(value[name], `$transaction/${name}`);
|
|
336
|
-
const transaction = {
|
|
337
|
-
schema: V4_RELEASE_TRANSACTION_CONTRACT,
|
|
338
|
-
invocationRoot: value.invocationRoot,
|
|
339
|
-
publisherRoot: value.publisherRoot,
|
|
340
|
-
runtimeRoot: value.runtimeRoot,
|
|
341
|
-
providerRoot: value.providerRoot,
|
|
342
|
-
parentRoot: value.parentRoot,
|
|
343
|
-
phases: ["QUALIFY", "APPLY", "SETTLE"],
|
|
344
|
-
writer: "canonical-v4-apply",
|
|
345
|
-
};
|
|
346
|
-
return {
|
|
347
|
-
transaction,
|
|
348
|
-
transactionRoot: v4ContentRoot("release-transaction", transaction),
|
|
349
|
-
};
|
|
59
|
+
return invoke("release-transaction", value);
|
|
350
60
|
}
|
|
351
61
|
|
|
352
62
|
export function createV4ReleaseReceipt(value) {
|
|
353
|
-
|
|
354
|
-
value,
|
|
355
|
-
[
|
|
356
|
-
"schema",
|
|
357
|
-
"transactionRoot",
|
|
358
|
-
"outcome",
|
|
359
|
-
"releasePassportRoot",
|
|
360
|
-
"providerTransactionRoot",
|
|
361
|
-
"providerStateRoot",
|
|
362
|
-
"providerReceiptRoots",
|
|
363
|
-
],
|
|
364
|
-
"$receipt",
|
|
365
|
-
);
|
|
366
|
-
if (value.schema !== V4_RELEASE_RECEIPT_CONTRACT)
|
|
367
|
-
fault(
|
|
368
|
-
"invalid-release-receipt",
|
|
369
|
-
"$receipt/schema",
|
|
370
|
-
"unsupported receipt schema",
|
|
371
|
-
);
|
|
372
|
-
validateV4Root(value.transactionRoot, "$receipt/transactionRoot");
|
|
373
|
-
if (!["complete", "blocked"].includes(value.outcome))
|
|
374
|
-
fault(
|
|
375
|
-
"invalid-release-receipt",
|
|
376
|
-
"$receipt/outcome",
|
|
377
|
-
"unsupported receipt outcome",
|
|
378
|
-
);
|
|
379
|
-
for (const name of [
|
|
380
|
-
"releasePassportRoot",
|
|
381
|
-
"providerTransactionRoot",
|
|
382
|
-
"providerStateRoot",
|
|
383
|
-
]) {
|
|
384
|
-
if (value[name] !== null) validateV4Root(value[name], `$receipt/${name}`);
|
|
385
|
-
}
|
|
386
|
-
if (!Array.isArray(value.providerReceiptRoots))
|
|
387
|
-
fault(
|
|
388
|
-
"invalid-release-receipt",
|
|
389
|
-
"$receipt/providerReceiptRoots",
|
|
390
|
-
"receipt roots must be an array",
|
|
391
|
-
);
|
|
392
|
-
value.providerReceiptRoots.forEach((root, index) =>
|
|
393
|
-
validateV4Root(root, `$receipt/providerReceiptRoots/${index}`),
|
|
394
|
-
);
|
|
395
|
-
const canonicalRoots = [...new Set(value.providerReceiptRoots)].sort();
|
|
396
|
-
if (
|
|
397
|
-
canonicalRoots.length !== value.providerReceiptRoots.length ||
|
|
398
|
-
canonicalRoots.some(
|
|
399
|
-
(root, index) => root !== value.providerReceiptRoots[index],
|
|
400
|
-
)
|
|
401
|
-
)
|
|
402
|
-
fault(
|
|
403
|
-
"invalid-release-receipt",
|
|
404
|
-
"$receipt/providerReceiptRoots",
|
|
405
|
-
"provider receipt roots must be sorted and unique",
|
|
406
|
-
);
|
|
407
|
-
if (
|
|
408
|
-
value.outcome === "complete" &&
|
|
409
|
-
[
|
|
410
|
-
value.releasePassportRoot,
|
|
411
|
-
value.providerTransactionRoot,
|
|
412
|
-
value.providerStateRoot,
|
|
413
|
-
].some((root) => root === null)
|
|
414
|
-
)
|
|
415
|
-
fault(
|
|
416
|
-
"invalid-release-receipt",
|
|
417
|
-
"$receipt/outcome",
|
|
418
|
-
"complete receipt requires every terminal root",
|
|
419
|
-
);
|
|
420
|
-
v4CanonicalBytes(value);
|
|
421
|
-
return {
|
|
422
|
-
receipt: value,
|
|
423
|
-
receiptRoot: v4ContentRoot("release-receipt", value),
|
|
424
|
-
};
|
|
63
|
+
return invoke("release-receipt", value);
|
|
425
64
|
}
|