@xemahq/xema 0.47.0 → 0.48.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/edition/README.md CHANGED
@@ -143,7 +143,7 @@ The edition library builds, validates and verifies evidence statements; it never
143
143
 
144
144
  ## Kernel protocol and pins
145
145
 
146
- The CLI is coupled to the kernel's edition protocol, not to the kernel package. `@xemahq/contracts` exports the protocol identity as data (`dist/edition-protocol/edition-protocol.json`: `{contentDigest, provisional, version}`). This CLI supports protocols v9 to v16 and v19 to v26 (the versions the kernel declared and contracts published), each pinned to its digest and vendored (v10 to v26 grow the kernel source closure only; a data root whose pinned kernel speaks v8 stays on CLI 0.41.x, v5 on 0.33.x) and REFUSES an identity with `provisional: true`; every loader that executes the kernel, `xema edition check` first, and the evidence verifier compare only that identity and refuse an unsupported one, naming the supported and the declared versions. A protocol change needs a CLI release first; only then does the data root repin its kernel authority.
146
+ The CLI is coupled to the kernel's edition protocol, not to the kernel package. `@xemahq/contracts` exports the protocol identity as data (`dist/edition-protocol/edition-protocol.json`: `{contentDigest, provisional, version}`). This CLI supports protocols v28, v30 and v31 (no published kernel declares v29; a CLI lists a protocol only while every kernel published under it exports what the CLI imports; v27 and older kernels lack `serviceImageSubjects`, so a data root whose pinned kernel speaks v27 or older stays on an earlier CLI), pinned to its digest and vendored, and REFUSES an identity with `provisional: true`; every loader that executes the kernel, `xema edition check` first, and the evidence verifier compare only that identity and refuse an unsupported one, naming the supported and the declared versions. A protocol change needs a CLI release first; only then does the data root repin its kernel authority.
147
147
 
148
148
  A develop edition does not take the kernel's develop head blindly: `xema edition develop choose-kernel --kernel <package dir> [--kernel-pin <40-hex>] --out <file>` reads the declared protocol of each commit on the checkout's first-parent history (from source, unbuilt) and chooses the newest one this CLI supports. It writes `{chosenSha, headSha, held, reason}` (`reason`: `head-supported` | `head-ahead` | `explicit-pin`; `held` is `head-ahead`), and when held prints `kernel held at v<N> (<sha12>), head at v<M> (<sha12>): raise the CLI` (stdout only, never persisted). The head is the checkout's `refs/remotes/origin/develop` (a full-history checkout). An explicit pin wins but is still checked, and must be on that head's first-parent history (`not-on-develop` otherwise); when no commit is supported it refuses (`EditionProtocolMismatchError`, `no-supported-commit`; the walk ends at the first commit with no declaration file) and never falls back to the head; a declaration that exists but does not parse, at the head or any walked commit, is refused by name (`unparseable`), never skipped. `freeze-graph` applies the same check to `--kernel-sha`.
149
149
 
@@ -758,8 +758,11 @@ export const REPIN_CONTRACT_AUTHORITY_FOLLOW_UPS = Object.freeze([
758
758
  * states (`kernelCommit`, required; HEAD must equal it), and write it back.
759
759
  *
760
760
  * The document is read as raw strict JSON and the field replaced BEFORE it is
761
- * parsed: the kernel's schema refuses an index whose authority `sourcePaths`
762
- * differ from the bundled constant, so a stale index cannot be parsed first.
761
+ * parsed, so a stale index cannot block its own repair (the wire schema
762
+ * checks the shape of `sourcePaths` only, from contracts 0.110.3).
763
+ * The new authority's `sourcePaths` are the set the stated commit declares,
764
+ * and `buildTrustedKernelContractAuthority` requires this CLI's bundled set to
765
+ * equal it: a repin is trusted generation at HEAD.
763
766
  * Every repository pin and subject is kept byte for byte. Repository coverage
764
767
  * is not asserted: this repin produces no pin, and requiring coverage would
765
768
  * make a stale index unrepairable.
@@ -28,27 +28,14 @@ import { realpathSync } from 'node:fs';
28
28
 
29
29
  import { readBoundedNoFollowFile } from './no-follow-file.mjs';
30
30
 
31
- /** The edition protocols this library interprets: version -> content digest. v10..v28 grow the kernel
32
- * source closure only (entry subpaths and hashing unchanged), so one library speaks every row. */
31
+ /** The edition protocols this library interprets: version -> content digest. A protocol is listed only
32
+ * while every kernel published under it exports what this library imports (`kernel-export-coverage.test.mjs`):
33
+ * v27 and older kernels lack `serviceImageSubjects` (first exported by the v28 kernel), so they are not listed.
34
+ * No published kernel declares v29 (0.110.2 is v28, 0.110.3 is v30, 0.111.0 is v31), so v29 is not listed either. */
33
35
  export const SUPPORTED_EDITION_PROTOCOLS = Object.freeze([
34
- Object.freeze({ version: 9, contentDigest: '7cd6d760e7e7caaec3634a08c739debbdeeeaac4f1bad6791246a12f4f248e37' }),
35
- Object.freeze({ version: 10, contentDigest: '660129065650a8300f7c0ad54f957b4d43507e1a44e093c9812d2b1bbf143104' }),
36
- Object.freeze({ version: 11, contentDigest: '600451d2253c470c7d21bafe87260dfc3bfd43b6ad3eee2ef4d8b1f7ad08eb6e' }),
37
- Object.freeze({ version: 12, contentDigest: 'cff51ea06b6ba7d95d02dcd6305b6a55061b428da48ae74dcbff8a5c8107ce41' }),
38
- Object.freeze({ version: 13, contentDigest: '5f69fe73d1dea1650ef1757204a53ccd4030ade78bfa91959c2d01c937fc0e16' }),
39
- Object.freeze({ version: 14, contentDigest: '403b6a491b5922df1a423ba8a2d6ae3d3900bb1caff4e8c0caa48de90a47eb9b' }),
40
- Object.freeze({ version: 15, contentDigest: 'c66191703abfd9b532d8b6c15476bede2a5752af5bea5032e839fb9d6303a2d1' }),
41
- Object.freeze({ version: 16, contentDigest: '2e65c280a399304ebb438e4e9829bcb4688f36a3c6a5e8b35b679cf69c689f55' }),
42
- Object.freeze({ version: 19, contentDigest: '66dab3dcf18c3a587f073808cc91165cc513eabb237b35439ff6cfe2b312b127' }),
43
- Object.freeze({ version: 20, contentDigest: '22c0e4ba6ee2771e91516ea78806117b5e3e60b76e085b9a9b98e993c1de79f8' }),
44
- Object.freeze({ version: 21, contentDigest: 'f6364cf4830dcd15f82fb316ec9c0f0c11ffbe45262d97d8621242117d02f2b8' }),
45
- Object.freeze({ version: 22, contentDigest: '566a0c37ee8b25c22bb9a5979190508e479c87593790b4a9e481ab1db8f7bcd1' }),
46
- Object.freeze({ version: 23, contentDigest: '96735bd71236b4d0a2cef8a59c4a8d4f6919c6b5e54654c4b2b01e22b9880e04' }),
47
- Object.freeze({ version: 24, contentDigest: '6ae70f55db789f95e194f623525b30ffedc21478ec17d246336b9a2783b6c0db' }),
48
- Object.freeze({ version: 25, contentDigest: '79916e652836c7f6c31a7284c083c4f11249c6f21ef0b1bf79efc9dc23684d4a' }),
49
- Object.freeze({ version: 26, contentDigest: '8d1dcfca5c59ff7b5eee6ea84fec3d9d62a48f3260f4ddb27b6665c25056f968' }),
50
- Object.freeze({ version: 27, contentDigest: 'd4807f6464508c1abb32f7de9754f2e1f12cd7f2be5fbf939b6a5175c01dd90b' }),
51
36
  Object.freeze({ version: 28, contentDigest: 'f7795478b1bfe9a41bcbea9efe496011fcd209a56c90294029a08801e84cf92c' }),
37
+ Object.freeze({ version: 30, contentDigest: '91e3cdff255778b5aa94b64ca9316d031be549ead2267a9a9311ff06d4f1db2c' }),
38
+ Object.freeze({ version: 31, contentDigest: 'b2026847fdd202e7b9e05815cdc2c9819b60be7007c789cc5b5f291c9c682fdd' }),
52
39
  ]);
53
40
 
54
41
  /** Where a kernel package publishes its identity and its contract, package-relative. */
@@ -4,6 +4,11 @@ import { join } from 'node:path';
4
4
 
5
5
  import { kernelRepoDir } from './edition-workspace.mjs';
6
6
  import { COMMIT_PATTERN } from './evidence-grammars.mjs';
7
+ import {
8
+ assertSourcePathsEqualSet,
9
+ KERNEL_CONTRACT_SOURCE_PATH_SET_FILE,
10
+ parseKernelContractSourcePathSet,
11
+ } from './kernel-contract-source-path-set.mjs';
7
12
 
8
13
  const GIT_ENV = Object.freeze({
9
14
  GIT_CONFIG_NOSYSTEM: '1',
@@ -171,6 +176,28 @@ function gitBlobsAtCommit(repositoryDirectory, sourceCommit, paths) {
171
176
  return sources;
172
177
  }
173
178
 
179
+ /**
180
+ * The source-path set the kernel declares AT `sourceCommit`, read from that
181
+ * commit's own declaration blob: the same tree the digest is recomputed from,
182
+ * never the list of the contracts version this CLI bundles.
183
+ */
184
+ export function sourcePathSetAtCommit(repositoryDirectory, sourceCommit) {
185
+ const [declaration] = gitBlobsAtCommit(repositoryDirectory, sourceCommit, [
186
+ KERNEL_CONTRACT_SOURCE_PATH_SET_FILE,
187
+ ]);
188
+ return parseKernelContractSourcePathSet(declaration.blob.toString('utf8'), sourceCommit);
189
+ }
190
+
191
+ /**
192
+ * Refuses `sourcePaths` unless they equal the source-path set at `sourceCommit`
193
+ * (KernelContractSourcePathSetMismatchError names the missing and extra paths).
194
+ * The wire schema checks shape only; this is the check that the set means
195
+ * something.
196
+ */
197
+ export function assertSourcePathsMatchCommit(repositoryDirectory, sourceCommit, sourcePaths) {
198
+ assertSourcePathsEqualSet(sourcePaths, sourcePathSetAtCommit(repositoryDirectory, sourceCommit), sourceCommit);
199
+ }
200
+
174
201
  function exactAuthorityJson(value) {
175
202
  return JSON.stringify(value);
176
203
  }
@@ -194,11 +221,12 @@ export async function readKernelContractAuthorityAtCommit({
194
221
  }
195
222
  exactOrigin(repositoryDirectory, schemas);
196
223
  assertCommitExists(repositoryDirectory, sourceCommit);
197
- const sources = gitBlobsAtCommit(
198
- repositoryDirectory,
199
- sourceCommit,
200
- schemas.XEMA_KERNEL_CONTRACT_SOURCE_PATHS,
201
- );
224
+ // The set is the commit's own (XEMA-2010): an authority at a commit whose
225
+ // contracts declare 446 paths is read, digested and stamped over those 446,
226
+ // whatever this CLI bundles. The digest's validateSources checks shape only
227
+ // (contracts 0.110.3 and later).
228
+ const sourcePaths = sourcePathSetAtCommit(repositoryDirectory, sourceCommit);
229
+ const sources = gitBlobsAtCommit(repositoryDirectory, sourceCommit, sourcePaths);
202
230
  const contentDigest =
203
231
  await schemas.computeKernelContractAuthorityContentDigest(sources);
204
232
  return {
@@ -206,7 +234,7 @@ export async function readKernelContractAuthorityAtCommit({
206
234
  generatorIdentity: schemas.XEMA_KERNEL_CONTRACT_AUTHORITY_GENERATOR,
207
235
  repositoryUrl: schemas.XEMA_KERNEL_CONTRACT_REPOSITORY_URL,
208
236
  sourceCommit,
209
- sourcePaths: [...schemas.XEMA_KERNEL_CONTRACT_SOURCE_PATHS],
237
+ sourcePaths,
210
238
  contentHashAlgorithm:
211
239
  schemas.KernelContractContentHashAlgorithm.LengthFramedGitPathModeBlobV1,
212
240
  contentDigest,
@@ -254,14 +282,11 @@ export function assertExactCleanKernelContractCheckout({
254
282
  const path = record.slice(record.indexOf('\t') + 1);
255
283
  indexByPath.set(path, [...(indexByPath.get(path) ?? []), record]);
256
284
  }
285
+ const sourcePaths = sourcePathSetAtCommit(repositoryDirectory, sourceCommit);
257
286
  const committed = new Map(
258
- gitBlobsAtCommit(
259
- repositoryDirectory,
260
- sourceCommit,
261
- schemas.XEMA_KERNEL_CONTRACT_SOURCE_PATHS,
262
- ).map((source) => [source.path, source]),
287
+ gitBlobsAtCommit(repositoryDirectory, sourceCommit, sourcePaths).map((source) => [source.path, source]),
263
288
  );
264
- for (const path of schemas.XEMA_KERNEL_CONTRACT_SOURCE_PATHS) {
289
+ for (const path of sourcePaths) {
265
290
  const indexRecords = indexByPath.get(path) ?? [];
266
291
  const indexMatch =
267
292
  indexRecords.length === 1
@@ -323,6 +348,16 @@ export async function buildTrustedKernelContractAuthority({
323
348
  sourceCommit,
324
349
  schemas,
325
350
  });
351
+ // Trusted generation at HEAD ONLY: a NEW pin is minted by a CLI whose bundled
352
+ // contracts declare exactly the set at that commit, so the CLI that writes
353
+ // the pin understands every source it binds. Reading or validating an
354
+ // existing pin never makes this comparison.
355
+ assertSourcePathsEqualSet(
356
+ schemas.XEMA_KERNEL_CONTRACT_SOURCE_PATHS,
357
+ sourcePathSetAtCommit(repositoryDirectory, sourceCommit),
358
+ sourceCommit,
359
+ "this CLI's bundled kernel contract source paths",
360
+ );
326
361
  const authority = await readKernelContractAuthorityAtCommit({
327
362
  repositoryDirectory,
328
363
  sourceCommit,
@@ -401,12 +436,19 @@ async function assessAuthorityLineage({ authority, repositoryDirectory, schemas
401
436
  return { head, changedPaths: [] };
402
437
  }
403
438
 
404
- const changedPaths = [];
405
- const pinned = gitBlobRecordsAtCommit(repositoryDirectory, authority.sourceCommit, authority.sourcePaths);
406
- const current = gitBlobRecordsAtCommit(repositoryDirectory, head, authority.sourcePaths);
407
- for (const [index, path] of authority.sourcePaths.entries()) {
408
- if (pinned[index].objectId !== current[index].objectId) {changedPaths.push(path);}
409
- }
439
+ // The two commits may declare different sets: a path added or dropped since
440
+ // the pin has moved as surely as one whose blob changed.
441
+ const pinnedTree = gitTreeAtCommit(repositoryDirectory, authority.sourceCommit);
442
+ const currentTree = gitTreeAtCommit(repositoryDirectory, head);
443
+ const pinnedSet = new Set(authority.sourcePaths);
444
+ const currentSet = new Set(atHead.sourcePaths);
445
+ const changedPaths = [...new Set([...pinnedSet, ...currentSet])]
446
+ .sort()
447
+ .filter(
448
+ (path) =>
449
+ pinnedSet.has(path) !== currentSet.has(path) ||
450
+ pinnedTree.get(path)?.objectId !== currentTree.get(path)?.objectId,
451
+ );
410
452
  return { head, changedPaths };
411
453
  }
412
454
 
@@ -451,6 +493,8 @@ export async function validateKernelContractAuthorityFromGit({
451
493
  schemas,
452
494
  });
453
495
  }
496
+ assertCommitExists(repositoryDirectory, authority.sourceCommit);
497
+ assertSourcePathsMatchCommit(repositoryDirectory, authority.sourceCommit, authority.sourcePaths);
454
498
  const expected = await readKernelContractAuthorityAtCommit({
455
499
  repositoryDirectory,
456
500
  sourceCommit: authority.sourceCommit,
@@ -0,0 +1,94 @@
1
+ /**
2
+ * The kernel contract authority's source-path set, as the kernel commit itself
3
+ * declares it. The set belongs to the commit an authority is pinned at, never
4
+ * to the contracts package the CLI happens to bundle: a bundled constant is the
5
+ * set of ONE contracts version, and comparing a pin made under another version
6
+ * against it is the cross-version defect this check replaces.
7
+ */
8
+
9
+ /** The file in the kernel repository that declares the source-path set. */
10
+ export const KERNEL_CONTRACT_SOURCE_PATH_SET_FILE =
11
+ 'packages/kernel/kernel-contracts/src/distribution/lib/kernel-contract-source-paths.ts';
12
+
13
+ const DECLARATION_START = 'export const XEMA_KERNEL_CONTRACT_SOURCE_PATHS = Object.freeze([';
14
+ const DECLARATION_END = '] as const);';
15
+ const PATH_LINE_PATTERN = /^ {2}'([^'\\\s]+)',$/;
16
+
17
+ /**
18
+ * A source-path list is not the source-path set at `sourceCommit`. `subject`
19
+ * names the list that was compared: a pinned authority's `sourcePaths`, or the
20
+ * set the CLI's bundled contracts declare (trusted generation only).
21
+ */
22
+ export class KernelContractSourcePathSetMismatchError extends Error {
23
+ constructor({ sourceCommit, missing, extra, subject = 'kernel contract authority sourcePaths' }) {
24
+ super(
25
+ `${subject} are not the source-path set at ${sourceCommit}: ` +
26
+ `${missing.length} missing (${missing.join(', ') || 'none'}), ` +
27
+ `${extra.length} extra (${extra.join(', ') || 'none'})`,
28
+ );
29
+ this.name = 'KernelContractSourcePathSetMismatchError';
30
+ this.sourceCommit = sourceCommit;
31
+ this.missing = missing;
32
+ this.extra = extra;
33
+ }
34
+ }
35
+
36
+ /**
37
+ * The ordered path list declared by the text of
38
+ * {@link KERNEL_CONTRACT_SOURCE_PATH_SET_FILE}. Refuses any other shape, a list
39
+ * that is empty, not strictly ascending (which also makes it unique), or that
40
+ * does not name the declaration file itself: the declaration is one of the
41
+ * digested sources, so the digest commits to the set it was taken over.
42
+ */
43
+ export function parseKernelContractSourcePathSet(text, sourceCommit) {
44
+ const lines = text.split('\n');
45
+ const start = lines.indexOf(DECLARATION_START);
46
+ const end = lines.indexOf(DECLARATION_END, start + 1);
47
+ if (start === -1 || end === -1) {
48
+ throw new Error(
49
+ `${KERNEL_CONTRACT_SOURCE_PATH_SET_FILE} at ${sourceCommit} does not declare XEMA_KERNEL_CONTRACT_SOURCE_PATHS in the expected form`,
50
+ );
51
+ }
52
+ const paths = lines.slice(start + 1, end).map((line) => {
53
+ const match = PATH_LINE_PATTERN.exec(line);
54
+ if (!match || match[1].split('/').some((segment) => segment === '' || segment === '.' || segment === '..')) {
55
+ throw new Error(
56
+ `${KERNEL_CONTRACT_SOURCE_PATH_SET_FILE} at ${sourceCommit} has a line that is not one quoted relative path: ${JSON.stringify(line)}`,
57
+ );
58
+ }
59
+ return match[1];
60
+ });
61
+ if (paths.length === 0) {
62
+ throw new Error(`${KERNEL_CONTRACT_SOURCE_PATH_SET_FILE} at ${sourceCommit} declares no source paths`);
63
+ }
64
+ for (let index = 1; index < paths.length; index += 1) {
65
+ if (!(paths[index - 1] < paths[index])) {
66
+ throw new Error(
67
+ `${KERNEL_CONTRACT_SOURCE_PATH_SET_FILE} at ${sourceCommit} is not in strictly ascending order at ${JSON.stringify(paths[index])}`,
68
+ );
69
+ }
70
+ }
71
+ if (!paths.includes(KERNEL_CONTRACT_SOURCE_PATH_SET_FILE)) {
72
+ throw new Error(
73
+ `${KERNEL_CONTRACT_SOURCE_PATH_SET_FILE} at ${sourceCommit} does not declare itself, so the digest would not commit to the set`,
74
+ );
75
+ }
76
+ return paths;
77
+ }
78
+
79
+ /**
80
+ * Refuses `sourcePaths` unless it equals `expected`, the set at `sourceCommit`
81
+ * (same paths, same order); names the paths `sourcePaths` lacks (missing) and
82
+ * the ones it has beyond the set (extra).
83
+ */
84
+ export function assertSourcePathsEqualSet(sourcePaths, expected, sourceCommit, subject = undefined) {
85
+ const have = new Set(sourcePaths);
86
+ const want = new Set(expected);
87
+ const missing = expected.filter((path) => !have.has(path));
88
+ const extra = sourcePaths.filter((path) => !want.has(path));
89
+ const sameOrder =
90
+ sourcePaths.length === expected.length && sourcePaths.every((path, index) => path === expected[index]);
91
+ if (missing.length > 0 || extra.length > 0 || !sameOrder) {
92
+ throw new KernelContractSourcePathSetMismatchError({ sourceCommit, missing, extra, subject });
93
+ }
94
+ }
@@ -204,7 +204,8 @@ export function writeInvalidReferrerReport(skipped) {
204
204
  * `getBlob` verifies every digest again, independently of the manifest.
205
205
  * An artifact that is not valid evidence under `expectedAuthorityCommit`
206
206
  * (a manifest that is not the exact subject's, RAW statements stating another authority commit, a
207
- * failed strict parse) is refused with `InvalidEvidenceReferrerError`; a
207
+ * failed strict parse, a statement whose contract authority is not exactly
208
+ * `expectedContractAuthority`, which is required) is refused with `InvalidEvidenceReferrerError`; a
208
209
  * registry that cannot answer, or bytes that do not match their digests
209
210
  * (`EvidenceIntegrityError`, a tampering signal), still throw.
210
211
  */
@@ -215,8 +216,12 @@ export async function readImageSourceEvidenceArtifact({
215
216
  artifactDigest,
216
217
  schemas,
217
218
  expectedAuthorityCommit,
219
+ expectedContractAuthority,
218
220
  }) {
219
221
  assertExpectedAuthorityCommit(expectedAuthorityCommit);
222
+ if (!expectedContractAuthority) {
223
+ throw new Error('the expected kernel contract authority is required');
224
+ }
220
225
  const fetched = await client.getManifestByDigest(repository, artifactDigest);
221
226
  const invalid = (error) =>
222
227
  new InvalidEvidenceReferrerError({
@@ -264,6 +269,14 @@ export async function readImageSourceEvidenceArtifact({
264
269
  subjectDigest,
265
270
  schemas,
266
271
  });
272
+ // The wire schema checks the shape of an authority's sourcePaths only
273
+ // (contracts 0.110.3), so a statement naming the expected commit with
274
+ // another path set or digest parses: it is not evidence under the pin.
275
+ for (const record of evidence.records) {
276
+ if (canonicalJson(record.statement.predicate.contractAuthority) !== canonicalJson(expectedContractAuthority)) {
277
+ throw new Error(`${record.key} statement's kernel contract authority is not exactly the expected one at ${expectedAuthorityCommit}`);
278
+ }
279
+ }
267
280
  return { ...evidence, artifactDigest, created };
268
281
  } catch (error) {
269
282
  if (error instanceof InvalidEvidenceReferrerError || error instanceof EvidenceIntegrityError) {
@@ -327,6 +340,7 @@ export async function resolveImageSourceEvidenceReferrer({
327
340
  artifactDigest: descriptor.digest,
328
341
  schemas,
329
342
  expectedAuthorityCommit,
343
+ expectedContractAuthority,
330
344
  }),
331
345
  );
332
346
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xemahq/xema",
3
- "version": "0.47.0",
3
+ "version": "0.48.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/xema-dev/xema-cli.git",
@@ -54,7 +54,7 @@
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.110.2",
57
+ "@xemahq/contracts": "^0.111.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:7c50b1499876697b28ff4a9c5cc2d1517bc1cfca2a9ccf9c019411b6e3b0edcd"
95
+ "sourceDigest": "sha256:5f6bd75aa0d1bdc9a141a6f9f31be0957f7a8e5aa967695362db0ced936cac5a"
96
96
  }
97
97
  }