halfcode-compiler.xnl 0.2.8 → 0.2.9
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/dist/authoring-runtime.d.ts +163 -1
- package/dist/authoring-runtime.js +2 -2
- package/dist/effective-content-identities-CSVFi-N5.d.ts +14 -0
- package/dist/effective-content-identities-DV5fTr5Q.js +118 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/resource-core-C0Fj-VJA.d.ts +29 -0
- package/dist/resource-core.d.ts +2 -1
- package/dist/resource-core.js +17 -132
- package/dist/src-3MZLm339.js +588 -0
- package/dist/testing.js +1 -1
- package/package.json +6 -2
- package/dist/resource-core-C8IonwKw.d.ts +0 -41
- package/dist/src-B87eJQat.js +0 -39
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
import "./src-D3qSzGFn.js";
|
|
2
|
+
import { t as resolveEffectiveResourceContentIdentities } from "./effective-content-identities-DV5fTr5Q.js";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
|
+
//#region ../runtime-authoring/src/resource-authoring.ts
|
|
6
|
+
const RESOURCE_AUTHORING_SCHEMA_VERSION = "halfcode.resource-authoring/v1";
|
|
7
|
+
var ResourceAuthoringError = class extends Error {
|
|
8
|
+
code;
|
|
9
|
+
cause;
|
|
10
|
+
constructor(code, message, cause) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.cause = cause;
|
|
14
|
+
this.name = "ResourceAuthoringError";
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
/** Derives the content-sensitive revision used by planning and CAS from canonical projections. */
|
|
18
|
+
function deriveResourceAuthoringRegistryRevision(input) {
|
|
19
|
+
let identities;
|
|
20
|
+
try {
|
|
21
|
+
identities = resolveEffectiveResourceContentIdentities(input);
|
|
22
|
+
} catch (cause) {
|
|
23
|
+
throw new ResourceAuthoringError("RESOURCE_AUTHORING_REFRESH_INVALID", "Registry revision requires authentic canonical registry and layer projections.", cause);
|
|
24
|
+
}
|
|
25
|
+
return digestValue({
|
|
26
|
+
compositionRevision: input.registry.compositionRevision,
|
|
27
|
+
resources: [...identities.entries()].map(([resourceId, value]) => ({
|
|
28
|
+
resourceId,
|
|
29
|
+
contentDigest: value.contentDigest
|
|
30
|
+
})).sort((left, right) => compareCodeUnits(left.resourceId, right.resourceId))
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function planResourceAuthoring(runtime, input, _config) {
|
|
34
|
+
const proposal = normalizeProposal(input);
|
|
35
|
+
const planning = normalizePlanningAuthority(runtime.planningAuthority);
|
|
36
|
+
if (proposal.expected.registryRevision !== planning.registryRevision) fail("RESOURCE_AUTHORING_EXPECTED_STATE_INVALID", "Proposal registry revision does not match the planning authority.");
|
|
37
|
+
if (proposal.operation === "create" !== (proposal.expected.state === "absent")) fail("RESOURCE_AUTHORING_EXPECTED_STATE_INVALID", "Create requires absent state and update requires present state.");
|
|
38
|
+
const kindDefinition = planning.kindDefinitions.find((item) => item.kind === proposal.kind);
|
|
39
|
+
if (!kindDefinition) fail("RESOURCE_AUTHORING_KIND_UNKNOWN", `Kind '${proposal.kind}' is not registered.`);
|
|
40
|
+
if (!kindDefinition.supportedApiVersions.includes(proposal.apiVersion)) fail("RESOURCE_AUTHORING_API_VERSION_UNSUPPORTED", `Kind '${proposal.kind}' does not support '${proposal.apiVersion}'.`);
|
|
41
|
+
if (!kindDefinition.sourceShapes.includes(proposal.sourceShape)) fail("RESOURCE_AUTHORING_SOURCE_SHAPE_UNSUPPORTED", `Kind '${proposal.kind}' does not support '${proposal.sourceShape}'.`);
|
|
42
|
+
const catalog = planning.catalogs.find((item) => item.catalogId === proposal.catalogId);
|
|
43
|
+
if (!catalog) fail("RESOURCE_AUTHORING_CATALOG_UNKNOWN", `Catalog '${proposal.catalogId}' is not registered.`);
|
|
44
|
+
if (catalog.resourceKind !== proposal.kind || catalog.sourceShape !== proposal.sourceShape) fail("RESOURCE_AUTHORING_CATALOG_MISMATCH", `Catalog '${catalog.catalogId}' does not admit the proposal Kind and source shape.`);
|
|
45
|
+
assertCatalogTarget(catalog, proposal.documentUri);
|
|
46
|
+
let inspection;
|
|
47
|
+
try {
|
|
48
|
+
inspection = normalizeInspection(runtime.inspectAuthority({
|
|
49
|
+
documentUri: proposal.documentUri,
|
|
50
|
+
sourceShape: proposal.sourceShape,
|
|
51
|
+
authorityText: proposal.authorityText
|
|
52
|
+
}));
|
|
53
|
+
} catch (cause) {
|
|
54
|
+
if (cause instanceof ResourceAuthoringError) throw cause;
|
|
55
|
+
throw new ResourceAuthoringError("RESOURCE_AUTHORING_AUTHORITY_INVALID", "Authority inspection failed.", cause);
|
|
56
|
+
}
|
|
57
|
+
if (inspection.documentUri !== proposal.documentUri) fail("RESOURCE_AUTHORING_AUTHORITY_INVALID", "Authority inspection changed the logical document URI.");
|
|
58
|
+
if (kindDefinition.documentCardinality === "one" && inspection.resources.length !== 1) fail("RESOURCE_AUTHORING_AUTHORITY_INVALID", `Kind '${proposal.kind}' requires one resource root per authority document.`);
|
|
59
|
+
if (inspection.resources.length === 0) fail("RESOURCE_AUTHORING_AUTHORITY_INVALID", "Authority document contains no resource roots.");
|
|
60
|
+
const resourceIds = /* @__PURE__ */ new Set();
|
|
61
|
+
for (const resource of inspection.resources) {
|
|
62
|
+
if (resourceIds.has(resource.resourceId)) fail("RESOURCE_AUTHORING_AUTHORITY_INVALID", "Authority document repeats a resource identity.");
|
|
63
|
+
resourceIds.add(resource.resourceId);
|
|
64
|
+
if (resource.kind !== proposal.kind || resource.apiVersion !== proposal.apiVersion) fail("RESOURCE_AUTHORING_AUTHORITY_INVALID", "Every authority root must match the proposed Kind and apiVersion.");
|
|
65
|
+
}
|
|
66
|
+
if (!resourceIds.has(proposal.resourceId)) fail("RESOURCE_AUTHORING_AUTHORITY_INVALID", `Authority document does not contain target '${proposal.resourceId}'.`);
|
|
67
|
+
const authorityDigest = digestText(proposal.authorityText);
|
|
68
|
+
if (proposal.expected.state === "present" && proposal.expected.authorityDigest === authorityDigest) fail("RESOURCE_AUTHORING_EXPECTED_STATE_INVALID", "Update authority must differ from the expected current authority.");
|
|
69
|
+
const unsigned = {
|
|
70
|
+
schemaVersion: RESOURCE_AUTHORING_SCHEMA_VERSION,
|
|
71
|
+
proposal,
|
|
72
|
+
kindDefinition,
|
|
73
|
+
catalog,
|
|
74
|
+
resources: inspection.resources,
|
|
75
|
+
authorityDigest
|
|
76
|
+
};
|
|
77
|
+
return deepFreeze({
|
|
78
|
+
...unsigned,
|
|
79
|
+
planDigest: digestValue(unsigned)
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async function applyResourceAuthoring(runtime, input, config) {
|
|
83
|
+
const plan = normalizePlan(input);
|
|
84
|
+
let replanned;
|
|
85
|
+
try {
|
|
86
|
+
replanned = planResourceAuthoring(runtime, plan.proposal, config);
|
|
87
|
+
} catch (cause) {
|
|
88
|
+
throw new ResourceAuthoringError("RESOURCE_AUTHORING_PLAN_FORGED", "Resource authoring plan is not admitted by the trusted planning authority.", cause);
|
|
89
|
+
}
|
|
90
|
+
if (canonicalJson(plan) !== canonicalJson(replanned)) fail("RESOURCE_AUTHORING_PLAN_FORGED", "Resource authoring plan does not match trusted planning inputs.");
|
|
91
|
+
let replay;
|
|
92
|
+
try {
|
|
93
|
+
replay = await runtime.transaction.loadReceipt(plan.planDigest);
|
|
94
|
+
} catch (cause) {
|
|
95
|
+
throw new ResourceAuthoringError("RESOURCE_AUTHORING_COMMIT_INVALID", "Durable receipt lookup failed.", cause);
|
|
96
|
+
}
|
|
97
|
+
if (replay) return verifyReceipt(replay, plan);
|
|
98
|
+
let prepared;
|
|
99
|
+
let phase = "prepare";
|
|
100
|
+
try {
|
|
101
|
+
prepared = normalizePrepared(await runtime.transaction.prepare({
|
|
102
|
+
planDigest: plan.planDigest,
|
|
103
|
+
operation: plan.proposal.operation,
|
|
104
|
+
documentUri: plan.proposal.documentUri,
|
|
105
|
+
expected: plan.proposal.expected,
|
|
106
|
+
authorityDigest: plan.authorityDigest,
|
|
107
|
+
authorityText: plan.proposal.authorityText
|
|
108
|
+
}));
|
|
109
|
+
verifyPrepared(prepared, plan);
|
|
110
|
+
phase = "refresh";
|
|
111
|
+
const candidate = await runtime.transaction.refreshCandidate({
|
|
112
|
+
transactionId: prepared.transactionId,
|
|
113
|
+
planDigest: plan.planDigest
|
|
114
|
+
});
|
|
115
|
+
const receipt = verifyCandidate(candidate, prepared, plan);
|
|
116
|
+
phase = "commit";
|
|
117
|
+
return verifyReceipt(await runtime.transaction.commit({
|
|
118
|
+
transactionId: prepared.transactionId,
|
|
119
|
+
candidateId: candidate.candidateId,
|
|
120
|
+
receipt
|
|
121
|
+
}), plan, receipt);
|
|
122
|
+
} catch (cause) {
|
|
123
|
+
const recovered = await runtime.transaction.loadReceipt(plan.planDigest).catch(() => void 0);
|
|
124
|
+
if (recovered) return verifyReceipt(recovered, plan);
|
|
125
|
+
if (prepared) try {
|
|
126
|
+
await runtime.transaction.rollback({
|
|
127
|
+
transactionId: prepared.transactionId,
|
|
128
|
+
planDigest: plan.planDigest
|
|
129
|
+
});
|
|
130
|
+
} catch (rollbackCause) {
|
|
131
|
+
throw new ResourceAuthoringError("RESOURCE_AUTHORING_ROLLBACK_FAILED", "Resource authoring rollback failed before a durable receipt was found.", {
|
|
132
|
+
cause,
|
|
133
|
+
rollbackCause
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (cause instanceof ResourceAuthoringError) throw cause;
|
|
137
|
+
throw new ResourceAuthoringError(phase === "prepare" ? "RESOURCE_AUTHORING_PREPARE_INVALID" : phase === "refresh" ? "RESOURCE_AUTHORING_REFRESH_INVALID" : "RESOURCE_AUTHORING_COMMIT_INVALID", `Resource authoring ${phase} failed.`, cause);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function verifyPrepared(prepared, plan) {
|
|
141
|
+
const before = plan.proposal.expected.state === "present" ? plan.proposal.expected.authorityDigest : null;
|
|
142
|
+
if (prepared.planDigest !== plan.planDigest || prepared.authorityDigestBefore !== before || prepared.registryRevisionBefore !== plan.proposal.expected.registryRevision) fail("RESOURCE_AUTHORING_PREPARE_INVALID", "Prepared write does not match the exact CAS expectation.");
|
|
143
|
+
}
|
|
144
|
+
function verifyCandidate(candidate, prepared, plan) {
|
|
145
|
+
if (!candidate || typeof candidate !== "object" || candidate.transactionId !== prepared.transactionId || !nonEmptyString(candidate.candidateId) || !nonEmptyString(candidate.targetLayerId) || candidate.tree !== candidate.layers.find((layer) => layer.id === candidate.targetLayerId)?.tree) fail("RESOURCE_AUTHORING_REFRESH_INVALID", "Candidate refresh does not bind the prepared transaction and target layer.");
|
|
146
|
+
let identities;
|
|
147
|
+
try {
|
|
148
|
+
identities = resolveEffectiveResourceContentIdentities({
|
|
149
|
+
registry: candidate.registry,
|
|
150
|
+
layers: candidate.layers
|
|
151
|
+
});
|
|
152
|
+
} catch (cause) {
|
|
153
|
+
throw new ResourceAuthoringError("RESOURCE_AUTHORING_REFRESH_INVALID", "Candidate refresh is not an authentic canonical projection.", cause);
|
|
154
|
+
}
|
|
155
|
+
const target = candidate.registry.byId.get(plan.proposal.resourceId);
|
|
156
|
+
const identity = identities.get(plan.proposal.resourceId);
|
|
157
|
+
const resource = target?.resource;
|
|
158
|
+
const origin = target?.effectiveOrigin;
|
|
159
|
+
if (!resource || !identity || !origin || target.kind !== plan.proposal.kind || resource.metadata.apiVersion !== plan.proposal.apiVersion || resource.sourceShape !== plan.proposal.sourceShape || resource.documentUri !== plan.proposal.documentUri || identity.authorityDigest !== plan.authorityDigest || origin.layerId !== candidate.targetLayerId || origin.documentUri !== plan.proposal.documentUri) fail("RESOURCE_AUTHORING_REFRESH_INVALID", "Candidate refresh does not project the planned effective resource and authority.");
|
|
160
|
+
const actualRoots = recordsAtDocument(candidate.tree, plan.proposal.documentUri).map((record) => ({
|
|
161
|
+
resourceId: record.resourceId,
|
|
162
|
+
kind: record.kind,
|
|
163
|
+
apiVersion: record.metadata.apiVersion
|
|
164
|
+
})).sort(compareInspectedRoots);
|
|
165
|
+
const plannedRoots = [...plan.resources].sort(compareInspectedRoots);
|
|
166
|
+
if (canonicalJson(actualRoots) !== canonicalJson(plannedRoots)) fail("RESOURCE_AUTHORING_REFRESH_INVALID", "Candidate refresh changed the whole authority-document resource set.");
|
|
167
|
+
for (const root of plannedRoots) {
|
|
168
|
+
const rootIdentity = candidate.tree.contentIdentities.get(root.resourceId);
|
|
169
|
+
if (!rootIdentity || rootIdentity.authorityDigest !== plan.authorityDigest) fail("RESOURCE_AUTHORING_REFRESH_INVALID", "Candidate refresh does not bind every authority root to the planned bytes.");
|
|
170
|
+
}
|
|
171
|
+
const registryRevisionAfter = deriveResourceAuthoringRegistryRevision({
|
|
172
|
+
registry: candidate.registry,
|
|
173
|
+
layers: candidate.layers
|
|
174
|
+
});
|
|
175
|
+
if (registryRevisionAfter === prepared.registryRevisionBefore) fail("RESOURCE_AUTHORING_REFRESH_INVALID", "Candidate refresh did not change the content-sensitive registry revision.");
|
|
176
|
+
const unsignedReceipt = {
|
|
177
|
+
schemaVersion: RESOURCE_AUTHORING_SCHEMA_VERSION,
|
|
178
|
+
planDigest: plan.planDigest,
|
|
179
|
+
transactionId: prepared.transactionId,
|
|
180
|
+
operation: plan.proposal.operation,
|
|
181
|
+
catalogId: plan.proposal.catalogId,
|
|
182
|
+
resourceId: plan.proposal.resourceId,
|
|
183
|
+
kind: plan.proposal.kind,
|
|
184
|
+
apiVersion: plan.proposal.apiVersion,
|
|
185
|
+
sourceShape: plan.proposal.sourceShape,
|
|
186
|
+
documentUri: plan.proposal.documentUri,
|
|
187
|
+
authorityDigestBefore: prepared.authorityDigestBefore,
|
|
188
|
+
authorityDigestAfter: plan.authorityDigest,
|
|
189
|
+
registryRevisionBefore: prepared.registryRevisionBefore,
|
|
190
|
+
registryRevisionAfter,
|
|
191
|
+
contentDigest: identity.contentDigest,
|
|
192
|
+
effectiveOrigin: {
|
|
193
|
+
layerId: origin.layerId,
|
|
194
|
+
layerIndex: origin.layerIndex,
|
|
195
|
+
packageId: origin.packageId,
|
|
196
|
+
documentUri: origin.documentUri,
|
|
197
|
+
...origin.logicalPath === void 0 ? {} : { logicalPath: origin.logicalPath }
|
|
198
|
+
},
|
|
199
|
+
authorityResourceIds: plannedRoots.map((item) => item.resourceId)
|
|
200
|
+
};
|
|
201
|
+
return deepFreeze({
|
|
202
|
+
...unsignedReceipt,
|
|
203
|
+
receiptDigest: digestValue(unsignedReceipt)
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
function verifyReceipt(value, plan, expected) {
|
|
207
|
+
const receipt = normalizeReceipt(value);
|
|
208
|
+
const authorityDigestBefore = plan.proposal.expected.state === "present" ? plan.proposal.expected.authorityDigest : null;
|
|
209
|
+
if (receipt.planDigest !== plan.planDigest || receipt.operation !== plan.proposal.operation || receipt.catalogId !== plan.proposal.catalogId || receipt.resourceId !== plan.proposal.resourceId || receipt.kind !== plan.proposal.kind || receipt.apiVersion !== plan.proposal.apiVersion || receipt.sourceShape !== plan.proposal.sourceShape || receipt.documentUri !== plan.proposal.documentUri || receipt.authorityDigestBefore !== authorityDigestBefore || receipt.authorityDigestAfter !== plan.authorityDigest || receipt.registryRevisionBefore !== plan.proposal.expected.registryRevision || receipt.registryRevisionAfter === receipt.registryRevisionBefore || receipt.effectiveOrigin.documentUri !== plan.proposal.documentUri || canonicalJson(receipt.authorityResourceIds) !== canonicalJson(plan.resources.map((item) => item.resourceId).sort(compareCodeUnits)) || expected && canonicalJson(receipt) !== canonicalJson(expected)) fail("RESOURCE_AUTHORING_COMMIT_INVALID", "Durable receipt does not match the exact accepted plan and refresh projection.");
|
|
210
|
+
return receipt;
|
|
211
|
+
}
|
|
212
|
+
function normalizeProposal(value) {
|
|
213
|
+
const input = ownRecord(value, [
|
|
214
|
+
"schemaVersion",
|
|
215
|
+
"operation",
|
|
216
|
+
"catalogId",
|
|
217
|
+
"resourceId",
|
|
218
|
+
"kind",
|
|
219
|
+
"apiVersion",
|
|
220
|
+
"sourceShape",
|
|
221
|
+
"documentUri",
|
|
222
|
+
"authorityText",
|
|
223
|
+
"expected"
|
|
224
|
+
], "proposal");
|
|
225
|
+
if (input.schemaVersion !== "halfcode.resource-authoring/v1") invalid("proposal.schemaVersion");
|
|
226
|
+
if (input.operation !== "create" && input.operation !== "update") invalid("proposal.operation");
|
|
227
|
+
if (input.sourceShape !== "single-file") fail("RESOURCE_AUTHORING_SOURCE_SHAPE_UNSUPPORTED", "The initial authoring transaction supports only single-file authority.");
|
|
228
|
+
const documentUri = normalizeDocumentUri(input.documentUri, "proposal.documentUri");
|
|
229
|
+
const authorityText = requiredString(input.authorityText, "proposal.authorityText", true);
|
|
230
|
+
const expectedInput = ownRecord(input.expected, input.operation === "create" ? ["state", "registryRevision"] : [
|
|
231
|
+
"state",
|
|
232
|
+
"authorityDigest",
|
|
233
|
+
"registryRevision"
|
|
234
|
+
], "proposal.expected");
|
|
235
|
+
const registryRevision = digestString(expectedInput.registryRevision, "proposal.expected.registryRevision");
|
|
236
|
+
const expected = input.operation === "create" ? (() => {
|
|
237
|
+
if (expectedInput.state !== "absent") invalid("proposal.expected.state");
|
|
238
|
+
return {
|
|
239
|
+
state: "absent",
|
|
240
|
+
registryRevision
|
|
241
|
+
};
|
|
242
|
+
})() : (() => {
|
|
243
|
+
if (expectedInput.state !== "present") invalid("proposal.expected.state");
|
|
244
|
+
return {
|
|
245
|
+
state: "present",
|
|
246
|
+
authorityDigest: digestString(expectedInput.authorityDigest, "proposal.expected.authorityDigest"),
|
|
247
|
+
registryRevision
|
|
248
|
+
};
|
|
249
|
+
})();
|
|
250
|
+
return deepFreeze({
|
|
251
|
+
schemaVersion: RESOURCE_AUTHORING_SCHEMA_VERSION,
|
|
252
|
+
operation: input.operation,
|
|
253
|
+
catalogId: requiredString(input.catalogId, "proposal.catalogId"),
|
|
254
|
+
resourceId: requiredString(input.resourceId, "proposal.resourceId"),
|
|
255
|
+
kind: requiredString(input.kind, "proposal.kind"),
|
|
256
|
+
apiVersion: requiredString(input.apiVersion, "proposal.apiVersion"),
|
|
257
|
+
sourceShape: "single-file",
|
|
258
|
+
documentUri,
|
|
259
|
+
authorityText,
|
|
260
|
+
expected
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
function normalizePlanningAuthority(value) {
|
|
264
|
+
const input = ownRecord(value, [
|
|
265
|
+
"registryRevision",
|
|
266
|
+
"kindDefinitions",
|
|
267
|
+
"catalogs"
|
|
268
|
+
], "planning");
|
|
269
|
+
const registryRevision = digestString(input.registryRevision, "planning.registryRevision");
|
|
270
|
+
const kindDefinitions = ownArray(input.kindDefinitions, "planning.kindDefinitions").map((item, index) => {
|
|
271
|
+
const record = ownRecord(item, [
|
|
272
|
+
"kind",
|
|
273
|
+
"supportedApiVersions",
|
|
274
|
+
"sourceShapes",
|
|
275
|
+
"documentCardinality"
|
|
276
|
+
], `planning.kindDefinitions[${index}]`);
|
|
277
|
+
const sourceShapes = ownArray(record.sourceShapes, `planning.kindDefinitions[${index}].sourceShapes`).map((shape) => {
|
|
278
|
+
if (shape !== "single-file") fail("RESOURCE_AUTHORING_SOURCE_SHAPE_UNSUPPORTED", "Planning authority contains an unsupported source shape.");
|
|
279
|
+
return shape;
|
|
280
|
+
});
|
|
281
|
+
if (record.documentCardinality !== "one" && record.documentCardinality !== "many") invalid(`planning.kindDefinitions[${index}].documentCardinality`);
|
|
282
|
+
return deepFreeze({
|
|
283
|
+
kind: requiredString(record.kind, `planning.kindDefinitions[${index}].kind`),
|
|
284
|
+
supportedApiVersions: [...uniqueStrings(record.supportedApiVersions, `planning.kindDefinitions[${index}].supportedApiVersions`)].sort(compareCodeUnits),
|
|
285
|
+
sourceShapes: sourceShapes.sort(compareCodeUnits),
|
|
286
|
+
documentCardinality: record.documentCardinality
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
const catalogs = ownArray(input.catalogs, "planning.catalogs").map((item, index) => {
|
|
290
|
+
const record = ownRecordOptional(item, [
|
|
291
|
+
"catalogId",
|
|
292
|
+
"resourceKind",
|
|
293
|
+
"sourceShape",
|
|
294
|
+
"rootUri"
|
|
295
|
+
], ["entry"], `planning.catalogs[${index}]`);
|
|
296
|
+
if (record.sourceShape !== "single-file") fail("RESOURCE_AUTHORING_SOURCE_SHAPE_UNSUPPORTED", "Planning catalog contains an unsupported source shape.");
|
|
297
|
+
const entry = record.entry === void 0 ? void 0 : plainEntry(record.entry, `planning.catalogs[${index}].entry`);
|
|
298
|
+
return deepFreeze({
|
|
299
|
+
catalogId: requiredString(record.catalogId, `planning.catalogs[${index}].catalogId`),
|
|
300
|
+
resourceKind: requiredString(record.resourceKind, `planning.catalogs[${index}].resourceKind`),
|
|
301
|
+
sourceShape: "single-file",
|
|
302
|
+
rootUri: normalizeDirectoryUri(record.rootUri, `planning.catalogs[${index}].rootUri`),
|
|
303
|
+
...entry === void 0 ? {} : { entry }
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
requireUnique(kindDefinitions.map((item) => item.kind), "planning Kind");
|
|
307
|
+
requireUnique(catalogs.map((item) => item.catalogId), "planning catalog");
|
|
308
|
+
return deepFreeze({
|
|
309
|
+
registryRevision,
|
|
310
|
+
kindDefinitions,
|
|
311
|
+
catalogs
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
function normalizeInspection(value) {
|
|
315
|
+
const input = ownRecord(value, ["documentUri", "resources"], "authorityInspection");
|
|
316
|
+
const resources = ownArray(input.resources, "authorityInspection.resources").map((item, index) => {
|
|
317
|
+
const record = ownRecord(item, [
|
|
318
|
+
"resourceId",
|
|
319
|
+
"kind",
|
|
320
|
+
"apiVersion"
|
|
321
|
+
], `authorityInspection.resources[${index}]`);
|
|
322
|
+
return deepFreeze({
|
|
323
|
+
resourceId: requiredString(record.resourceId, `authorityInspection.resources[${index}].resourceId`),
|
|
324
|
+
kind: requiredString(record.kind, `authorityInspection.resources[${index}].kind`),
|
|
325
|
+
apiVersion: requiredString(record.apiVersion, `authorityInspection.resources[${index}].apiVersion`)
|
|
326
|
+
});
|
|
327
|
+
}).sort(compareInspectedRoots);
|
|
328
|
+
return deepFreeze({
|
|
329
|
+
documentUri: normalizeDocumentUri(input.documentUri, "authorityInspection.documentUri"),
|
|
330
|
+
resources
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
function normalizePlan(value) {
|
|
334
|
+
const input = ownRecord(value, [
|
|
335
|
+
"schemaVersion",
|
|
336
|
+
"proposal",
|
|
337
|
+
"kindDefinition",
|
|
338
|
+
"catalog",
|
|
339
|
+
"resources",
|
|
340
|
+
"authorityDigest",
|
|
341
|
+
"planDigest"
|
|
342
|
+
], "plan");
|
|
343
|
+
if (input.schemaVersion !== "halfcode.resource-authoring/v1") invalid("plan.schemaVersion");
|
|
344
|
+
const proposal = normalizeProposal(input.proposal);
|
|
345
|
+
const authority = normalizePlanningAuthority({
|
|
346
|
+
registryRevision: proposal.expected.registryRevision,
|
|
347
|
+
kindDefinitions: [input.kindDefinition],
|
|
348
|
+
catalogs: [input.catalog]
|
|
349
|
+
});
|
|
350
|
+
const unsigned = {
|
|
351
|
+
schemaVersion: RESOURCE_AUTHORING_SCHEMA_VERSION,
|
|
352
|
+
proposal,
|
|
353
|
+
kindDefinition: authority.kindDefinitions[0],
|
|
354
|
+
catalog: authority.catalogs[0],
|
|
355
|
+
resources: normalizeInspection({
|
|
356
|
+
documentUri: proposal.documentUri,
|
|
357
|
+
resources: input.resources
|
|
358
|
+
}).resources,
|
|
359
|
+
authorityDigest: digestString(input.authorityDigest, "plan.authorityDigest")
|
|
360
|
+
};
|
|
361
|
+
const planDigest = digestString(input.planDigest, "plan.planDigest");
|
|
362
|
+
if (digestValue(unsigned) !== planDigest) fail("RESOURCE_AUTHORING_PLAN_FORGED", "Resource authoring plan digest is invalid.");
|
|
363
|
+
return deepFreeze({
|
|
364
|
+
...unsigned,
|
|
365
|
+
planDigest
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
function normalizePrepared(value) {
|
|
369
|
+
const input = ownRecord(value, [
|
|
370
|
+
"transactionId",
|
|
371
|
+
"planDigest",
|
|
372
|
+
"authorityDigestBefore",
|
|
373
|
+
"registryRevisionBefore"
|
|
374
|
+
], "prepared");
|
|
375
|
+
return deepFreeze({
|
|
376
|
+
transactionId: requiredString(input.transactionId, "prepared.transactionId"),
|
|
377
|
+
planDigest: digestString(input.planDigest, "prepared.planDigest"),
|
|
378
|
+
authorityDigestBefore: input.authorityDigestBefore === null ? null : digestString(input.authorityDigestBefore, "prepared.authorityDigestBefore"),
|
|
379
|
+
registryRevisionBefore: digestString(input.registryRevisionBefore, "prepared.registryRevisionBefore")
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
function normalizeReceipt(value) {
|
|
383
|
+
const input = ownRecord(value, [
|
|
384
|
+
"schemaVersion",
|
|
385
|
+
"planDigest",
|
|
386
|
+
"transactionId",
|
|
387
|
+
"operation",
|
|
388
|
+
"catalogId",
|
|
389
|
+
"resourceId",
|
|
390
|
+
"kind",
|
|
391
|
+
"apiVersion",
|
|
392
|
+
"sourceShape",
|
|
393
|
+
"documentUri",
|
|
394
|
+
"authorityDigestBefore",
|
|
395
|
+
"authorityDigestAfter",
|
|
396
|
+
"registryRevisionBefore",
|
|
397
|
+
"registryRevisionAfter",
|
|
398
|
+
"contentDigest",
|
|
399
|
+
"effectiveOrigin",
|
|
400
|
+
"authorityResourceIds",
|
|
401
|
+
"receiptDigest"
|
|
402
|
+
], "receipt");
|
|
403
|
+
if (input.schemaVersion !== "halfcode.resource-authoring/v1") invalid("receipt.schemaVersion");
|
|
404
|
+
if (input.operation !== "create" && input.operation !== "update") invalid("receipt.operation");
|
|
405
|
+
if (input.sourceShape !== "single-file") invalid("receipt.sourceShape");
|
|
406
|
+
const origin = ownRecordOptional(input.effectiveOrigin, [
|
|
407
|
+
"layerId",
|
|
408
|
+
"layerIndex",
|
|
409
|
+
"packageId",
|
|
410
|
+
"documentUri"
|
|
411
|
+
], ["logicalPath"], "receipt.effectiveOrigin");
|
|
412
|
+
if (!Number.isSafeInteger(origin.layerIndex) || Number(origin.layerIndex) < 0) invalid("receipt.effectiveOrigin.layerIndex");
|
|
413
|
+
const unsignedReceipt = {
|
|
414
|
+
schemaVersion: RESOURCE_AUTHORING_SCHEMA_VERSION,
|
|
415
|
+
planDigest: digestString(input.planDigest, "receipt.planDigest"),
|
|
416
|
+
transactionId: requiredString(input.transactionId, "receipt.transactionId"),
|
|
417
|
+
operation: input.operation,
|
|
418
|
+
catalogId: requiredString(input.catalogId, "receipt.catalogId"),
|
|
419
|
+
resourceId: requiredString(input.resourceId, "receipt.resourceId"),
|
|
420
|
+
kind: requiredString(input.kind, "receipt.kind"),
|
|
421
|
+
apiVersion: requiredString(input.apiVersion, "receipt.apiVersion"),
|
|
422
|
+
sourceShape: "single-file",
|
|
423
|
+
documentUri: normalizeDocumentUri(input.documentUri, "receipt.documentUri"),
|
|
424
|
+
authorityDigestBefore: input.authorityDigestBefore === null ? null : digestString(input.authorityDigestBefore, "receipt.authorityDigestBefore"),
|
|
425
|
+
authorityDigestAfter: digestString(input.authorityDigestAfter, "receipt.authorityDigestAfter"),
|
|
426
|
+
registryRevisionBefore: digestString(input.registryRevisionBefore, "receipt.registryRevisionBefore"),
|
|
427
|
+
registryRevisionAfter: digestString(input.registryRevisionAfter, "receipt.registryRevisionAfter"),
|
|
428
|
+
contentDigest: digestString(input.contentDigest, "receipt.contentDigest"),
|
|
429
|
+
effectiveOrigin: {
|
|
430
|
+
layerId: requiredString(origin.layerId, "receipt.effectiveOrigin.layerId"),
|
|
431
|
+
layerIndex: Number(origin.layerIndex),
|
|
432
|
+
packageId: requiredString(origin.packageId, "receipt.effectiveOrigin.packageId"),
|
|
433
|
+
documentUri: normalizeDocumentUri(origin.documentUri, "receipt.effectiveOrigin.documentUri"),
|
|
434
|
+
...origin.logicalPath === void 0 ? {} : { logicalPath: safeLogicalPath(origin.logicalPath, "receipt.effectiveOrigin.logicalPath") }
|
|
435
|
+
},
|
|
436
|
+
authorityResourceIds: [...uniqueStrings(input.authorityResourceIds, "receipt.authorityResourceIds")].sort(compareCodeUnits)
|
|
437
|
+
};
|
|
438
|
+
const receiptDigest = digestString(input.receiptDigest, "receipt.receiptDigest");
|
|
439
|
+
if (digestValue(unsignedReceipt) !== receiptDigest) fail("RESOURCE_AUTHORING_COMMIT_INVALID", "Durable receipt content digest is invalid.");
|
|
440
|
+
return deepFreeze({
|
|
441
|
+
...unsignedReceipt,
|
|
442
|
+
receiptDigest
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
function assertCatalogTarget(catalog, documentUri) {
|
|
446
|
+
const relative = documentUri.slice(catalog.rootUri.length);
|
|
447
|
+
if (!documentUri.startsWith(catalog.rootUri) || relative.length === 0 || relative.includes("/")) fail("RESOURCE_AUTHORING_CATALOG_MISMATCH", `Target '${documentUri}' is not a direct member of catalog '${catalog.catalogId}'.`);
|
|
448
|
+
if (catalog.entry !== void 0 && relative !== catalog.entry) fail("RESOURCE_AUTHORING_CATALOG_MISMATCH", `Catalog '${catalog.catalogId}' admits only '${catalog.entry}'.`);
|
|
449
|
+
}
|
|
450
|
+
function recordsAtDocument(tree, documentUri) {
|
|
451
|
+
return [...tree.registry.byKind.values()].flatMap((records) => [...records]).filter((record) => record.documentUri === documentUri);
|
|
452
|
+
}
|
|
453
|
+
function compareInspectedRoots(left, right) {
|
|
454
|
+
return compareCodeUnits(left.resourceId, right.resourceId) || compareCodeUnits(left.kind, right.kind) || compareCodeUnits(left.apiVersion, right.apiVersion);
|
|
455
|
+
}
|
|
456
|
+
function compareCodeUnits(left, right) {
|
|
457
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
458
|
+
}
|
|
459
|
+
function digestText(value) {
|
|
460
|
+
return `sha256:${createHash("sha256").update(value, "utf8").digest("hex")}`;
|
|
461
|
+
}
|
|
462
|
+
function digestValue(value) {
|
|
463
|
+
return digestText(canonicalJson(value));
|
|
464
|
+
}
|
|
465
|
+
function canonicalJson(value) {
|
|
466
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
|
|
467
|
+
if (typeof value === "number" && Number.isFinite(value)) return JSON.stringify(value);
|
|
468
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
469
|
+
if (value && typeof value === "object") return `{${Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => compareCodeUnits(left, right)).map(([key, item]) => `${JSON.stringify(key)}:${canonicalJson(item)}`).join(",")}}`;
|
|
470
|
+
invalid("canonical value");
|
|
471
|
+
}
|
|
472
|
+
function deepFreeze(value) {
|
|
473
|
+
if (!value || typeof value !== "object" || Object.isFrozen(value)) return value;
|
|
474
|
+
for (const item of Object.values(value)) deepFreeze(item);
|
|
475
|
+
return Object.freeze(value);
|
|
476
|
+
}
|
|
477
|
+
function ownRecord(value, keys, location) {
|
|
478
|
+
return ownRecordOptional(value, keys, [], location);
|
|
479
|
+
}
|
|
480
|
+
function ownRecordOptional(value, required, optional, location) {
|
|
481
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null || Object.getOwnPropertySymbols(value).length > 0) invalid(location);
|
|
482
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
483
|
+
const actual = Object.keys(descriptors).filter((key) => descriptors[key].enumerable).sort(compareCodeUnits);
|
|
484
|
+
const allowed = [...required, ...optional];
|
|
485
|
+
if (required.some((key) => !actual.includes(key)) || actual.some((key) => !allowed.includes(key))) invalid(location);
|
|
486
|
+
const output = {};
|
|
487
|
+
for (const key of actual) {
|
|
488
|
+
const descriptor = descriptors[key];
|
|
489
|
+
if (!("value" in descriptor)) invalid(`${location}.${key}`);
|
|
490
|
+
output[key] = descriptor.value;
|
|
491
|
+
}
|
|
492
|
+
return output;
|
|
493
|
+
}
|
|
494
|
+
function ownArray(value, location) {
|
|
495
|
+
if (!Array.isArray(value) || Object.getOwnPropertySymbols(value).length > 0) invalid(location);
|
|
496
|
+
for (let index = 0; index < value.length; index += 1) if (!Object.prototype.hasOwnProperty.call(value, index)) invalid(location);
|
|
497
|
+
return value;
|
|
498
|
+
}
|
|
499
|
+
function requiredString(value, location, allowWhitespace = false) {
|
|
500
|
+
if (typeof value !== "string" || value.length === 0 || !allowWhitespace && value.trim() !== value) invalid(location);
|
|
501
|
+
return value;
|
|
502
|
+
}
|
|
503
|
+
function nonEmptyString(value) {
|
|
504
|
+
return typeof value === "string" && value.length > 0;
|
|
505
|
+
}
|
|
506
|
+
function digestString(value, location) {
|
|
507
|
+
const text = requiredString(value, location);
|
|
508
|
+
if (!/^sha256:[0-9a-f]{64}$/u.test(text)) invalid(location);
|
|
509
|
+
return text;
|
|
510
|
+
}
|
|
511
|
+
function normalizeDocumentUri(value, location) {
|
|
512
|
+
const text = requiredString(value, location);
|
|
513
|
+
const logicalPath = text.startsWith("vfs://@/") ? text.slice(8) : "";
|
|
514
|
+
if (!isSafeAuthoringPath(logicalPath) || !/\.(?:xnl|md)$/u.test(logicalPath)) fail("RESOURCE_AUTHORING_TARGET_UNSAFE", `${location} must be a containment-safe XNL or Markdown VFS document URI.`);
|
|
515
|
+
return text;
|
|
516
|
+
}
|
|
517
|
+
function normalizeDirectoryUri(value, location) {
|
|
518
|
+
const text = requiredString(value, location);
|
|
519
|
+
if (!isSafeAuthoringPath(text.startsWith("vfs://@/") && text.endsWith("/") ? text.slice(8, -1) : "")) fail("RESOURCE_AUTHORING_TARGET_UNSAFE", `${location} must be a containment-safe VFS directory URI ending in '/'.`);
|
|
520
|
+
return text;
|
|
521
|
+
}
|
|
522
|
+
function plainEntry(value, location) {
|
|
523
|
+
const text = requiredString(value, location);
|
|
524
|
+
if (!isSafeAuthoringPath(text) || text.includes("/") || !/\.(?:xnl|md)$/u.test(text)) invalid(location);
|
|
525
|
+
return text;
|
|
526
|
+
}
|
|
527
|
+
function safeLogicalPath(value, location) {
|
|
528
|
+
const text = requiredString(value, location);
|
|
529
|
+
if (!isSafeAuthoringPath(text)) invalid(location);
|
|
530
|
+
return text;
|
|
531
|
+
}
|
|
532
|
+
function isSafeAuthoringPath(value) {
|
|
533
|
+
if (value.length === 0 || value.startsWith("/") || value.includes("\\") || value.includes("%") || /[\u0000-\u001f\u007f-\u009f]/u.test(value) || /[\ud800-\udfff]/u.test(value)) return false;
|
|
534
|
+
return value.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
|
|
535
|
+
}
|
|
536
|
+
function uniqueStrings(value, location) {
|
|
537
|
+
const items = ownArray(value, location).map((item, index) => requiredString(item, `${location}[${index}]`));
|
|
538
|
+
requireUnique(items, location);
|
|
539
|
+
return Object.freeze([...items]);
|
|
540
|
+
}
|
|
541
|
+
function requireUnique(values, location) {
|
|
542
|
+
if (new Set(values).size !== values.length) invalid(`${location} identities`);
|
|
543
|
+
}
|
|
544
|
+
function invalid(location) {
|
|
545
|
+
throw new ResourceAuthoringError("RESOURCE_AUTHORING_INPUT_INVALID", `${location} is invalid or not closed own-data.`);
|
|
546
|
+
}
|
|
547
|
+
function fail(code, message) {
|
|
548
|
+
throw new ResourceAuthoringError(code, message);
|
|
549
|
+
}
|
|
550
|
+
//#endregion
|
|
551
|
+
//#region ../runtime-authoring/src/index.ts
|
|
552
|
+
const runtimeScope = new AsyncLocalStorage();
|
|
553
|
+
function runWithRuntime(runtime, callback) {
|
|
554
|
+
return runtimeScope.run(runtime, callback);
|
|
555
|
+
}
|
|
556
|
+
function currentRuntime() {
|
|
557
|
+
const runtime = runtimeScope.getStore();
|
|
558
|
+
if (!runtime) throw new Error("No authoring runtime is active in the current async scope");
|
|
559
|
+
return runtime;
|
|
560
|
+
}
|
|
561
|
+
function createAuthoringBindings(runtime = currentRuntime()) {
|
|
562
|
+
return {
|
|
563
|
+
runtime,
|
|
564
|
+
logger: runtime.effects.logger,
|
|
565
|
+
invokeEffect: (effectFqn, input) => runtime.effects.invoke(effectFqn, input)
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
const logger = {
|
|
569
|
+
info(message, fields) {
|
|
570
|
+
currentRuntime().effects.logger.info(message, fields);
|
|
571
|
+
},
|
|
572
|
+
warn(message, fields) {
|
|
573
|
+
currentRuntime().effects.logger.warn(message, fields);
|
|
574
|
+
},
|
|
575
|
+
error(message, fields) {
|
|
576
|
+
currentRuntime().effects.logger.error(message, fields);
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
function invokeEffect(effectFqn, input) {
|
|
580
|
+
return currentRuntime().effects.invoke(effectFqn, input);
|
|
581
|
+
}
|
|
582
|
+
const runtimeAuthoringPackage = {
|
|
583
|
+
role: "framework",
|
|
584
|
+
area: "runtime-authoring",
|
|
585
|
+
owns: "target-neutral deterministic-code runtime and effect boundary"
|
|
586
|
+
};
|
|
587
|
+
//#endregion
|
|
588
|
+
export { runWithRuntime as a, ResourceAuthoringError as c, planResourceAuthoring as d, logger as i, applyResourceAuthoring as l, currentRuntime as n, runtimeAuthoringPackage as o, invokeEffect as r, RESOURCE_AUTHORING_SCHEMA_VERSION as s, createAuthoringBindings as t, deriveResourceAuthoringRegistryRevision as u };
|
package/dist/testing.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "halfcode-compiler.xnl",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "Compile XNL-described applications into runtime-ready skill capsules.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -70,5 +70,9 @@
|
|
|
70
70
|
"halfcode-compiler-runtime-testing": "workspace:*",
|
|
71
71
|
"halfcode-compiler-skill-capsule": "workspace:*",
|
|
72
72
|
"tsdown": "0.22.14"
|
|
73
|
-
}
|
|
73
|
+
},
|
|
74
|
+
"main": "index.js",
|
|
75
|
+
"keywords": [],
|
|
76
|
+
"author": "",
|
|
77
|
+
"license": "ISC"
|
|
74
78
|
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { I as EffectiveResourceRegistry, O as ResourceDigestContribution, T as ResourceContentIdentity, n as LoadedResourceTree, o as ResourceDiagnostic } from "./index-CDIT65pI.js";
|
|
2
|
-
//#region ../resource-core/src/composition-error.d.ts
|
|
3
|
-
declare class ResourceCompositionError extends Error {
|
|
4
|
-
readonly diagnostics: readonly ResourceDiagnostic[];
|
|
5
|
-
constructor(diagnostics: readonly ResourceDiagnostic[]);
|
|
6
|
-
}
|
|
7
|
-
//#endregion
|
|
8
|
-
//#region ../resource-core/src/effective-content-identities.d.ts
|
|
9
|
-
interface ResourceLayerContentIdentityInput {
|
|
10
|
-
readonly id: string;
|
|
11
|
-
readonly tree: LoadedResourceTree;
|
|
12
|
-
}
|
|
13
|
-
interface ResolveEffectiveResourceContentIdentitiesInput {
|
|
14
|
-
readonly registry: EffectiveResourceRegistry;
|
|
15
|
-
readonly layers: readonly ResourceLayerContentIdentityInput[];
|
|
16
|
-
readonly contributions?: ReadonlyMap<string, readonly ResourceDigestContribution[]>;
|
|
17
|
-
}
|
|
18
|
-
declare function resolveEffectiveResourceContentIdentities(input: ResolveEffectiveResourceContentIdentitiesInput): ReadonlyMap<string, ResourceContentIdentity>;
|
|
19
|
-
//#endregion
|
|
20
|
-
//#region ../resource-core/src/resource-material.d.ts
|
|
21
|
-
interface ReadResourceMaterialInput {
|
|
22
|
-
readonly tree: LoadedResourceTree;
|
|
23
|
-
readonly rootDir: string;
|
|
24
|
-
readonly resourceId: string;
|
|
25
|
-
readonly uri: string;
|
|
26
|
-
}
|
|
27
|
-
interface ResourceMaterial {
|
|
28
|
-
readonly resourceId: string;
|
|
29
|
-
readonly uri: string;
|
|
30
|
-
readonly sourceUri: string;
|
|
31
|
-
readonly digest: string;
|
|
32
|
-
readonly contribution: ResourceDigestContribution;
|
|
33
|
-
bytes(): Uint8Array;
|
|
34
|
-
}
|
|
35
|
-
declare class ResourceMaterialError extends Error {
|
|
36
|
-
readonly diagnostics: readonly ResourceDiagnostic[];
|
|
37
|
-
constructor(diagnostics: readonly ResourceDiagnostic[]);
|
|
38
|
-
}
|
|
39
|
-
declare function readResourceMaterial(input: ReadResourceMaterialInput): Promise<ResourceMaterial>;
|
|
40
|
-
//#endregion
|
|
41
|
-
export { ResolveEffectiveResourceContentIdentitiesInput as a, ResourceCompositionError as c, readResourceMaterial as i, ResourceMaterial as n, ResourceLayerContentIdentityInput as o, ResourceMaterialError as r, resolveEffectiveResourceContentIdentities as s, ReadResourceMaterialInput as t };
|