@xemahq/xema 0.41.0 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/edition.js +1 -1
- package/dist/commands/edition.js.map +1 -1
- package/dist/edition/verify-image-evidence.bundle.mjs +1297 -850
- package/dist/edition/verify-image-evidence.bundle.provenance.json +498 -456
- package/edition/README.md +3 -1
- package/edition/biome-content.mjs +4 -0
- package/edition/customer-edition-verbs.mjs +1 -0
- package/edition/develop-edition.mjs +22 -2
- package/edition/dispatched-runtime-components.mjs +91 -1
- package/edition/edition-protocol.mjs +36 -9
- package/edition/edition-workspace.mjs +2 -0
- package/edition/kernel-protocol-choice.mjs +239 -0
- package/edition/lib.mjs +113 -14
- package/edition/operation-grant-admission.mjs +65 -1
- package/edition/operation-requirements.mjs +18 -1
- package/edition/resolve-customer-edition.mjs +4 -3
- package/edition/resolve-distribution.mjs +16 -0
- package/edition/resolve-images.mjs +164 -20
- package/package.json +4 -4
|
@@ -40,7 +40,10 @@ import { setImmediate as yieldToEventLoop } from 'node:timers/promises';
|
|
|
40
40
|
import { assertBuildLedgerComplete } from './build-ledger-completeness.mjs';
|
|
41
41
|
import { BUILD_LEDGER_FILE, readBuildLedger } from './build-ledger.mjs';
|
|
42
42
|
import { CROSS_REPO_BUILD_INPUTS_PATH, crossRepoInputKey, resolveCrossRepoVendoredInputs } from './cross-repo-build-inputs.mjs';
|
|
43
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
resolveDispatchedRuntimeComponents,
|
|
45
|
+
UndeclaredSupplementalRuntimeComponentError,
|
|
46
|
+
} from './dispatched-runtime-components.mjs';
|
|
44
47
|
import {
|
|
45
48
|
assertCanonicalDistributionId,
|
|
46
49
|
distributionOutputPath,
|
|
@@ -58,6 +61,7 @@ import {
|
|
|
58
61
|
compareStrings,
|
|
59
62
|
hashImageBuildInputs,
|
|
60
63
|
imageInputSourceHashAlgorithm,
|
|
64
|
+
imageLockWriteSchemaVersion,
|
|
61
65
|
loadKernelDistributionSchemas,
|
|
62
66
|
parseResolvedDistributionLock,
|
|
63
67
|
readGitJsonAtCommit,
|
|
@@ -681,6 +685,28 @@ export function resolveImageStructure(
|
|
|
681
685
|
dispatchers,
|
|
682
686
|
biomeIndex,
|
|
683
687
|
)) {
|
|
688
|
+
if (dispatched.supplementalRuntimeComponentId !== undefined) {
|
|
689
|
+
// THE REFUSAL: a dispatched supplemental runtime component must be one the
|
|
690
|
+
// runtime image source index declares as a runtime-component subject.
|
|
691
|
+
// Every image lock is produced here, so this is the one place it is checked.
|
|
692
|
+
const declared = runtimeSourceIndex.supplementalSubjects.find(
|
|
693
|
+
(subject) =>
|
|
694
|
+
subject.kind === enums.RuntimeImageSubjectKind.RuntimeComponent &&
|
|
695
|
+
subject.id === dispatched.supplementalRuntimeComponentId,
|
|
696
|
+
);
|
|
697
|
+
if (declared === undefined) {
|
|
698
|
+
throw new UndeclaredSupplementalRuntimeComponentError(
|
|
699
|
+
dispatched.supplementalRuntimeComponentId,
|
|
700
|
+
dispatched.consumers,
|
|
701
|
+
`distribution "${lock.distributionId}"`,
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
addSupplementalSubject(
|
|
705
|
+
declared,
|
|
706
|
+
dispatched.consumers.map((biomeId) => ({ kind: enums.RuntimeImageOwnerKind.Biome, biomeId })),
|
|
707
|
+
);
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
684
710
|
const { target } = dispatched;
|
|
685
711
|
addSubject(subjects, {
|
|
686
712
|
kind: enums.RuntimeImageSubjectKind.RuntimeComponent,
|
|
@@ -717,6 +743,16 @@ export function resolveImageStructure(
|
|
|
717
743
|
const boundSubjects = new Set(
|
|
718
744
|
runtimeSourceIndex.platformServiceBindings.map((binding) => bindingKey(binding)),
|
|
719
745
|
);
|
|
746
|
+
// A biome's `supplemental:<id>` dispatch edge also carries the subject: the
|
|
747
|
+
// catalogue check reads the whole first-party index, not this roster, so a
|
|
748
|
+
// subject reached only by a dispatch is not "unreachable" in any edition.
|
|
749
|
+
const dispatchedSubjects = new Set(
|
|
750
|
+
biomeIndex
|
|
751
|
+
.filter((entry) => entry.source === undefined)
|
|
752
|
+
.flatMap((entry) => entry.dispatchesRuntimeComponents ?? [])
|
|
753
|
+
.filter((edge) => edge.supplementalRuntimeComponentId !== undefined)
|
|
754
|
+
.map((edge) => `${enums.RuntimeImageSubjectKind.RuntimeComponent}\0${edge.supplementalRuntimeComponentId}`),
|
|
755
|
+
);
|
|
720
756
|
const launchers = new Map(
|
|
721
757
|
supplementalSources
|
|
722
758
|
.filter((source) => source.launchedBy !== undefined)
|
|
@@ -733,11 +769,11 @@ export function resolveImageStructure(
|
|
|
733
769
|
for (const [key, supplemental] of supplementalSubjects) {
|
|
734
770
|
const launcher = launchers.get(key);
|
|
735
771
|
if (launcher === undefined) {
|
|
736
|
-
if (!boundSubjects.has(key)) {
|
|
772
|
+
if (!boundSubjects.has(key) && !dispatchedSubjects.has(key)) {
|
|
737
773
|
throw new Error(
|
|
738
|
-
`supplemental subject "${supplemental.kind}:${supplemental.id}" has neither a launchedBy
|
|
739
|
-
'platform-service binding, so no edition could ever carry it — declare what launches it ' +
|
|
740
|
-
'(runtimeImageSources.supplementalSources[].launchedBy)
|
|
774
|
+
`supplemental subject "${supplemental.kind}:${supplemental.id}" has neither a launchedBy, a ` +
|
|
775
|
+
'platform-service binding nor a biome dispatching it, so no edition could ever carry it — declare what launches it ' +
|
|
776
|
+
'(runtimeImageSources.supplementalSources[].launchedBy), bind it to a platform service or dispatch it from a biome',
|
|
741
777
|
);
|
|
742
778
|
}
|
|
743
779
|
continue;
|
|
@@ -935,6 +971,13 @@ export function editionSourceIds(lock) {
|
|
|
935
971
|
* caller can tell "this image's inputs are unknown" from any other refusal:
|
|
936
972
|
* the carried set is evidence, and with none there is no owner to derive.
|
|
937
973
|
*/
|
|
974
|
+
export class ComposedProcessWorkerError extends Error {
|
|
975
|
+
constructor(message) {
|
|
976
|
+
super(message);
|
|
977
|
+
this.name = 'ComposedProcessWorkerError';
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
938
981
|
export class ComposedProcessInputsError extends Error {
|
|
939
982
|
constructor(message) {
|
|
940
983
|
super(message);
|
|
@@ -974,16 +1017,31 @@ function composedProcessCarriage(structure, enums, repo, sourceCommit, locate) {
|
|
|
974
1017
|
const byBiome = new Map();
|
|
975
1018
|
for (const subject of structure.subjects) {
|
|
976
1019
|
if (subject.kind !== enums.RuntimeImageSubjectKind.Service || subject.repo !== repo) {continue;}
|
|
977
|
-
const servicePath =
|
|
1020
|
+
const { path: servicePath, componentKind } = subjectServiceSource(subject, sourceCommit, locate);
|
|
978
1021
|
for (const owner of subject.owners) {
|
|
979
1022
|
if (owner.kind !== enums.RuntimeImageOwnerKind.Biome) {continue;}
|
|
980
|
-
const row = byBiome.get(owner.biomeId) ??
|
|
981
|
-
|
|
1023
|
+
const row = byBiome.get(owner.biomeId) ??
|
|
1024
|
+
{ biomeId: owner.biomeId, carried: [], uncarried: [], carriedWorkers: [], packageDirs: {} };
|
|
1025
|
+
if (!carried.has(servicePath)) {
|
|
1026
|
+
row.uncarried.push(subject.id);
|
|
1027
|
+
} else if (componentKind === 'worker') {
|
|
1028
|
+
// A worker is never a member: it runs as its own Deployment.
|
|
1029
|
+
row.carriedWorkers.push(subject.id);
|
|
1030
|
+
} else {
|
|
1031
|
+
row.carried.push(subject.id);
|
|
1032
|
+
// The member's package directory IS the composed build's own input entry.
|
|
1033
|
+
row.packageDirs[subject.id] = servicePath;
|
|
1034
|
+
}
|
|
982
1035
|
byBiome.set(owner.biomeId, row);
|
|
983
1036
|
}
|
|
984
1037
|
}
|
|
985
1038
|
return [...byBiome.values()]
|
|
986
|
-
.map((row) => ({
|
|
1039
|
+
.map((row) => ({
|
|
1040
|
+
...row,
|
|
1041
|
+
carried: row.carried.sort(compareStrings),
|
|
1042
|
+
uncarried: row.uncarried.sort(compareStrings),
|
|
1043
|
+
carriedWorkers: row.carriedWorkers.sort(compareStrings),
|
|
1044
|
+
}))
|
|
987
1045
|
.sort((a, b) => compareStrings(a.biomeId, b.biomeId));
|
|
988
1046
|
}
|
|
989
1047
|
|
|
@@ -1052,8 +1110,15 @@ export function readComposedProcessDeclarations(
|
|
|
1052
1110
|
* resolve derive the same subject from the same declarations.
|
|
1053
1111
|
*
|
|
1054
1112
|
* Owners are the biomes the image CARRIES, derived from the composed build's
|
|
1055
|
-
* inputs at the sealed commit (`declaration.carriage`):
|
|
1056
|
-
* services
|
|
1113
|
+
* inputs at the sealed commit (`declaration.carriage`): every biome at least one
|
|
1114
|
+
* of whose services is a member, never every biome with a service in the
|
|
1115
|
+
* repository. The members leave the structure and are sealed on the subject
|
|
1116
|
+
* as `members[{ service, packageDir }]` — the per-service membership truth: a
|
|
1117
|
+
* service runs from the composed digest if and only if it is a row (owners
|
|
1118
|
+
* never resolve a service). The edition carries the composed subject plus the
|
|
1119
|
+
* services that are no row (the specials, which keep their own subjects even
|
|
1120
|
+
* inside an owner biome), and nothing addresses a member's own image. A worker
|
|
1121
|
+
* is never a row; an own-image worker the composed build carries is refused.
|
|
1057
1122
|
*/
|
|
1058
1123
|
export function withComposedProcessSubjects(
|
|
1059
1124
|
structure,
|
|
@@ -1064,6 +1129,9 @@ export function withComposedProcessSubjects(
|
|
|
1064
1129
|
) {
|
|
1065
1130
|
if (declarations.length === 0) {return structure;}
|
|
1066
1131
|
const subjects = new Map(structure.subjects.map((subject) => [subjectKey(subject), subject]));
|
|
1132
|
+
// A biome's members run from ONE composed image: a biome owning two composed
|
|
1133
|
+
// subjects would leave its pods two images to choose between.
|
|
1134
|
+
const composedOwnerOf = new Map();
|
|
1067
1135
|
for (const declaration of declarations) {
|
|
1068
1136
|
const services = structure.subjects.filter(
|
|
1069
1137
|
(subject) =>
|
|
@@ -1075,21 +1143,47 @@ export function withComposedProcessSubjects(
|
|
|
1075
1143
|
'biomes the image carries — refusing to guess its owners',
|
|
1076
1144
|
);
|
|
1077
1145
|
}
|
|
1078
|
-
// Owners are the biomes
|
|
1079
|
-
// with only some carried
|
|
1080
|
-
//
|
|
1146
|
+
// Owners are the biomes ANY of whose services the image carries. A biome
|
|
1147
|
+
// with only some carried is an owner too; its services the image does not
|
|
1148
|
+
// carry are specials and keep their own subjects (named here). A biome with
|
|
1149
|
+
// none carried is simply not one.
|
|
1081
1150
|
const biomeOwners = [];
|
|
1151
|
+
const members = new Set();
|
|
1152
|
+
const packageDirOf = new Map();
|
|
1082
1153
|
for (const row of declaration.carriage) {
|
|
1154
|
+
// A worker is never a member. One the composed build carries must run
|
|
1155
|
+
// from a carried sibling's image (`workerImages`, declared in the
|
|
1156
|
+
// manifest), never be dropped into the composed process or fall back.
|
|
1157
|
+
for (const worker of row.carriedWorkers ?? []) {
|
|
1158
|
+
throw new ComposedProcessWorkerError(
|
|
1159
|
+
row.carried.length === 0
|
|
1160
|
+
? `composed-process "${declaration.repo}" carries worker "${worker}" of biome "${row.biomeId}", ` +
|
|
1161
|
+
'and that biome has no carried service whose image it could run — a worker is never a ' +
|
|
1162
|
+
'composed member; carry a service of its biome or take the worker out of the composed inputs'
|
|
1163
|
+
: `composed-process "${declaration.repo}" carries worker "${worker}" of biome "${row.biomeId}" as ` +
|
|
1164
|
+
'its own oci-image — a worker is never a composed member; declare it `artifact.kind: ' +
|
|
1165
|
+
`shared-oci-image\` of a carried service (${row.carried.join(', ')}) or take it out of the composed inputs`,
|
|
1166
|
+
);
|
|
1167
|
+
}
|
|
1083
1168
|
if (row.carried.length === 0) {continue;}
|
|
1084
1169
|
if (row.uncarried.length > 0) {
|
|
1085
1170
|
onNotice(
|
|
1086
|
-
`composed-process "${declaration.repo}": biome "${row.biomeId}" is
|
|
1171
|
+
`composed-process "${declaration.repo}": biome "${row.biomeId}" is partly carried ` +
|
|
1087
1172
|
`(carried: ${row.carried.join(', ')}; not carried: ${row.uncarried.join(', ')}) — ` +
|
|
1088
|
-
'
|
|
1173
|
+
'its uncarried services keep their own subjects',
|
|
1174
|
+
);
|
|
1175
|
+
}
|
|
1176
|
+
const other = composedOwnerOf.get(row.biomeId);
|
|
1177
|
+
if (other !== undefined) {
|
|
1178
|
+
throw new Error(
|
|
1179
|
+
`biome "${row.biomeId}" is carried by the composed-process images of both "${other}" and ` +
|
|
1180
|
+
`"${declaration.repo}" — a biome is owned by exactly one composed subject`,
|
|
1089
1181
|
);
|
|
1090
|
-
continue;
|
|
1091
1182
|
}
|
|
1183
|
+
composedOwnerOf.set(row.biomeId, declaration.repo);
|
|
1092
1184
|
biomeOwners.push({ kind: enums.RuntimeImageOwnerKind.Biome, biomeId: row.biomeId });
|
|
1185
|
+
for (const id of row.carried) {members.add(id);}
|
|
1186
|
+
for (const [id, packageDir] of Object.entries(row.packageDirs ?? {})) {packageDirOf.set(id, packageDir);}
|
|
1093
1187
|
}
|
|
1094
1188
|
if (biomeOwners.length === 0) {
|
|
1095
1189
|
throw new Error(
|
|
@@ -1127,6 +1221,43 @@ export function withComposedProcessSubjects(
|
|
|
1127
1221
|
`(${[...namespaces].join(', ')}) — a composed image of one build has one`,
|
|
1128
1222
|
);
|
|
1129
1223
|
}
|
|
1224
|
+
// A MEMBER reaches its pods through this one subject (every member runs as a
|
|
1225
|
+
// group-of-one of the composed image), so it carries no subject of its own:
|
|
1226
|
+
// no `<imageRef>:<contentHash>` of its own is probed, verified or sealed. A
|
|
1227
|
+
// member is a service of this build the composed build's inputs carry
|
|
1228
|
+
// (`declaration.carriage`), every owner of which is a biome owning the
|
|
1229
|
+
// composed image. Any other service (not carried, or owned by anything but
|
|
1230
|
+
// a biome, e.g. shared with a platform service) keeps its own.
|
|
1231
|
+
const composedOwners = new Set(biomeOwners.map((owner) => owner.biomeId));
|
|
1232
|
+
const memberRows = [];
|
|
1233
|
+
for (const subject of services) {
|
|
1234
|
+
if (
|
|
1235
|
+
members.has(subject.id) &&
|
|
1236
|
+
subject.owners.length > 0 &&
|
|
1237
|
+
subject.owners.every(
|
|
1238
|
+
(owner) => owner.kind === enums.RuntimeImageOwnerKind.Biome && composedOwners.has(owner.biomeId),
|
|
1239
|
+
)
|
|
1240
|
+
) {
|
|
1241
|
+
subjects.delete(subjectKey(subject));
|
|
1242
|
+
const packageDir = packageDirOf.get(subject.id);
|
|
1243
|
+
if (packageDir === undefined) {
|
|
1244
|
+
throw new ComposedProcessInputsError(
|
|
1245
|
+
`composed-process "${declaration.repo}": member "${subject.id}" has no package directory in ` +
|
|
1246
|
+
'the composed build inputs — its shared-image workers would have nowhere to run from',
|
|
1247
|
+
);
|
|
1248
|
+
}
|
|
1249
|
+
memberRows.push({ service: subject.id, packageDir });
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
if (memberRows.length === 0) {
|
|
1253
|
+
throw new ComposedProcessInputsError(
|
|
1254
|
+
`composed-process "${declaration.repo}" has no member: every service its build carries ` +
|
|
1255
|
+
`(${[...members].sort(compareStrings).join(', ')}) is also owned by something other than a biome ` +
|
|
1256
|
+
'it owns (e.g. a platform service), so each keeps its own subject — a composed image with no ' +
|
|
1257
|
+
'member runs nothing; take it out of the edition or carry a biome-owned service',
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
memberRows.sort((a, b) => compareStrings(a.service, b.service));
|
|
1130
1261
|
const id = composedProcessSubjectId(declaration.sourceId);
|
|
1131
1262
|
addSubject(subjects, {
|
|
1132
1263
|
kind: enums.RuntimeImageSubjectKind.ComposedProcess,
|
|
@@ -1139,6 +1270,7 @@ export function withComposedProcessSubjects(
|
|
|
1139
1270
|
sourceManifestPath: declaration.sourceManifestPath,
|
|
1140
1271
|
requiredPlatforms,
|
|
1141
1272
|
owners: biomeOwners,
|
|
1273
|
+
members: memberRows,
|
|
1142
1274
|
});
|
|
1143
1275
|
}
|
|
1144
1276
|
return {
|
|
@@ -1240,11 +1372,21 @@ function sourceCommitMap(structure, locate = FIRST_PARTY_TREES) {
|
|
|
1240
1372
|
* service directory to hash the SAME build-input closure the lock names.
|
|
1241
1373
|
*/
|
|
1242
1374
|
export function subjectServicePath(subject, sourceCommit, locate = FIRST_PARTY_TREES) {
|
|
1375
|
+
return subjectServiceSource(subject, sourceCommit, locate).path;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
/**
|
|
1379
|
+
* The repository-relative source directory of a subject and the kind of the
|
|
1380
|
+
* manifest component it is built from (`worker` for a worker component,
|
|
1381
|
+
* `service` otherwise — a legacy `ships.apis[]` entry or a subject with its own
|
|
1382
|
+
* source manifest is not a worker).
|
|
1383
|
+
*/
|
|
1384
|
+
function subjectServiceSource(subject, sourceCommit, locate = FIRST_PARTY_TREES) {
|
|
1243
1385
|
const { dir: repoDirectory, base } = locate(subject.repo);
|
|
1244
1386
|
const toRepoRelative = (absolute) =>
|
|
1245
1387
|
relative(repoDirectory, absolute).split(sep).join('/') || '.';
|
|
1246
1388
|
if (subject.sourceManifestPath) {
|
|
1247
|
-
return toRepoRelative(join(base, subject.path));
|
|
1389
|
+
return { path: toRepoRelative(join(base, subject.path)), componentKind: 'service' };
|
|
1248
1390
|
}
|
|
1249
1391
|
const biomePath = toRepoRelative(join(base, subject.path));
|
|
1250
1392
|
const manifestPath =
|
|
@@ -1282,6 +1424,7 @@ export function subjectServicePath(subject, sourceCommit, locate = FIRST_PARTY_T
|
|
|
1282
1424
|
);
|
|
1283
1425
|
}
|
|
1284
1426
|
let servicePath;
|
|
1427
|
+
let componentKind = 'service';
|
|
1285
1428
|
if (v4ServiceComponents.length > 0) {
|
|
1286
1429
|
// A SERVICE is identified by `protocol.serviceName`; a WORKER has no
|
|
1287
1430
|
// service protocol and is identified by its component `key`. Matching only
|
|
@@ -1305,6 +1448,7 @@ export function subjectServicePath(subject, sourceCommit, locate = FIRST_PARTY_T
|
|
|
1305
1448
|
);
|
|
1306
1449
|
}
|
|
1307
1450
|
servicePath = component.artifact.path;
|
|
1451
|
+
componentKind = component.kind;
|
|
1308
1452
|
} else {
|
|
1309
1453
|
if (legacyApis.length === 0) {
|
|
1310
1454
|
throw new Error(
|
|
@@ -1322,7 +1466,7 @@ export function subjectServicePath(subject, sourceCommit, locate = FIRST_PARTY_T
|
|
|
1322
1466
|
}
|
|
1323
1467
|
servicePath = api.path;
|
|
1324
1468
|
}
|
|
1325
|
-
return toRepoRelative(join(base, subject.path, servicePath));
|
|
1469
|
+
return { path: toRepoRelative(join(base, subject.path, servicePath)), componentKind };
|
|
1326
1470
|
}
|
|
1327
1471
|
|
|
1328
1472
|
function assertSourceManifestParity(structure, commitByRepo, locate = FIRST_PARTY_TREES) {
|
|
@@ -1780,7 +1924,7 @@ export async function resolveImages(id, { inputs, lock, onSubjectHashed } = {})
|
|
|
1780
1924
|
const schemas = await loadKernelDistributionSchemas();
|
|
1781
1925
|
const imageLock = validateImmutableImageLock(
|
|
1782
1926
|
schemas.parseImageLock({
|
|
1783
|
-
schemaVersion:
|
|
1927
|
+
schemaVersion: imageLockWriteSchemaVersion(schemas, subjects, `distribution "${id}"`),
|
|
1784
1928
|
sourceHashAlgorithm: schemas.ImageSourceHashAlgorithm.ImageInputV2,
|
|
1785
1929
|
distributionId: id,
|
|
1786
1930
|
contractAuthority,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xemahq/xema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/xema-dev/xema-cli.git",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"@nestjs/common": "^11.1.18",
|
|
50
50
|
"@nestjs/core": "^11.1.18",
|
|
51
51
|
"@nestjs/platform-express": "^11.1.28",
|
|
52
|
-
"@xemahq/biome-sdk": "^
|
|
52
|
+
"@xemahq/biome-sdk": "^22.0.0",
|
|
53
53
|
"@xemahq/biome-supply-chain": "^0.5.0",
|
|
54
54
|
"@xemahq/distribution-source-hash": "^0.2.2",
|
|
55
55
|
"@xemahq/dsl": "^0.24.0",
|
|
56
56
|
"@xemahq/identity-client": "^0.16.0",
|
|
57
|
-
"@xemahq/contracts": "^0.
|
|
57
|
+
"@xemahq/contracts": "^0.94.0",
|
|
58
58
|
"@xemahq/kernel-state-runtime": "^0.8.0",
|
|
59
59
|
"@xemahq/license-verifier": "^0.2.0",
|
|
60
60
|
"@xemahq/service-registry-nest": "^0.12.2",
|
|
@@ -92,6 +92,6 @@
|
|
|
92
92
|
"typecheck": "tsc --noEmit"
|
|
93
93
|
},
|
|
94
94
|
"xemaRelease": {
|
|
95
|
-
"sourceDigest": "sha256:
|
|
95
|
+
"sourceDigest": "sha256:ae545509930a5b6f1215c413f3e7121b15a29d5fd3e14ab373f0910ceaa9063d"
|
|
96
96
|
}
|
|
97
97
|
}
|