@tiangong-lca/cli 0.1.9 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +10 -5
  2. package/assets/runtime/cli-runtime-descriptor.schema.json +138 -0
  3. package/assets/runtime/cli-runtime-expectation.schema.json +38 -0
  4. package/assets/runtime/runtime-bootstrap-lock.schema.json +254 -0
  5. package/assets/runtime/runtime-command-result.schema.json +95 -0
  6. package/assets/runtime/runtime-manifest.schema.json +383 -0
  7. package/dist/src/cli.js +5 -1
  8. package/dist/src/cli.js.map +1 -1
  9. package/dist/src/lib/dataset-import-lca.js +2 -2
  10. package/dist/src/lib/dataset-import-lca.js.map +1 -1
  11. package/dist/src/lib/runtime/archive-writer.d.ts +7 -0
  12. package/dist/src/lib/runtime/archive-writer.js +89 -0
  13. package/dist/src/lib/runtime/archive-writer.js.map +1 -0
  14. package/dist/src/lib/runtime/archive.d.ts +2 -0
  15. package/dist/src/lib/runtime/archive.js +122 -0
  16. package/dist/src/lib/runtime/archive.js.map +1 -0
  17. package/dist/src/lib/runtime/command.d.ts +8 -0
  18. package/dist/src/lib/runtime/command.js +57 -0
  19. package/dist/src/lib/runtime/command.js.map +1 -0
  20. package/dist/src/lib/runtime/descriptor.d.ts +11 -0
  21. package/dist/src/lib/runtime/descriptor.js +126 -0
  22. package/dist/src/lib/runtime/descriptor.js.map +1 -0
  23. package/dist/src/lib/runtime/download.d.ts +9 -0
  24. package/dist/src/lib/runtime/download.js +118 -0
  25. package/dist/src/lib/runtime/download.js.map +1 -0
  26. package/dist/src/lib/runtime/exec-command.d.ts +7 -0
  27. package/dist/src/lib/runtime/exec-command.js +86 -0
  28. package/dist/src/lib/runtime/exec-command.js.map +1 -0
  29. package/dist/src/lib/runtime/execute.d.ts +12 -0
  30. package/dist/src/lib/runtime/execute.js +132 -0
  31. package/dist/src/lib/runtime/execute.js.map +1 -0
  32. package/dist/src/lib/runtime/files.d.ts +7 -0
  33. package/dist/src/lib/runtime/files.js +91 -0
  34. package/dist/src/lib/runtime/files.js.map +1 -0
  35. package/dist/src/lib/runtime/host-context-protocol.d.ts +20 -0
  36. package/dist/src/lib/runtime/host-context-protocol.js +83 -0
  37. package/dist/src/lib/runtime/host-context-protocol.js.map +1 -0
  38. package/dist/src/lib/runtime/host-context-server.d.ts +6 -0
  39. package/dist/src/lib/runtime/host-context-server.js +81 -0
  40. package/dist/src/lib/runtime/host-context-server.js.map +1 -0
  41. package/dist/src/lib/runtime/host-context.d.ts +23 -0
  42. package/dist/src/lib/runtime/host-context.js +122 -0
  43. package/dist/src/lib/runtime/host-context.js.map +1 -0
  44. package/dist/src/lib/runtime/host.d.ts +8 -0
  45. package/dist/src/lib/runtime/host.js +37 -0
  46. package/dist/src/lib/runtime/host.js.map +1 -0
  47. package/dist/src/lib/runtime/leases.d.ts +12 -0
  48. package/dist/src/lib/runtime/leases.js +72 -0
  49. package/dist/src/lib/runtime/leases.js.map +1 -0
  50. package/dist/src/lib/runtime/managed-command.d.ts +6 -0
  51. package/dist/src/lib/runtime/managed-command.js +99 -0
  52. package/dist/src/lib/runtime/managed-command.js.map +1 -0
  53. package/dist/src/lib/runtime/manager.d.ts +33 -0
  54. package/dist/src/lib/runtime/manager.js +196 -0
  55. package/dist/src/lib/runtime/manager.js.map +1 -0
  56. package/dist/src/lib/runtime/manifest-types.d.ts +82 -0
  57. package/dist/src/lib/runtime/manifest-types.js +5 -0
  58. package/dist/src/lib/runtime/manifest-types.js.map +1 -0
  59. package/dist/src/lib/runtime/manifest-values.d.ts +15 -0
  60. package/dist/src/lib/runtime/manifest-values.js +124 -0
  61. package/dist/src/lib/runtime/manifest-values.js.map +1 -0
  62. package/dist/src/lib/runtime/manifest.d.ts +8 -0
  63. package/dist/src/lib/runtime/manifest.js +239 -0
  64. package/dist/src/lib/runtime/manifest.js.map +1 -0
  65. package/dist/src/lib/runtime/process.d.ts +4 -0
  66. package/dist/src/lib/runtime/process.js +69 -0
  67. package/dist/src/lib/runtime/process.js.map +1 -0
  68. package/dist/src/lib/runtime/storage.d.ts +8 -0
  69. package/dist/src/lib/runtime/storage.js +142 -0
  70. package/dist/src/lib/runtime/storage.js.map +1 -0
  71. package/dist/src/lib/runtime/types.d.ts +45 -0
  72. package/dist/src/lib/runtime/types.js +9 -0
  73. package/dist/src/lib/runtime/types.js.map +1 -0
  74. package/dist/src/lib/runtime/work-directory.d.ts +2 -0
  75. package/dist/src/lib/runtime/work-directory.js +16 -0
  76. package/dist/src/lib/runtime/work-directory.js.map +1 -0
  77. package/dist/src/main.js +13 -1
  78. package/dist/src/main.js.map +1 -1
  79. package/dist/src/runtime.d.ts +16 -0
  80. package/dist/src/runtime.js +23 -0
  81. package/dist/src/runtime.js.map +1 -0
  82. package/package.json +5 -1
@@ -0,0 +1,124 @@
1
+ import { runtimeError } from './files.js';
2
+ import { RUNTIME_PLATFORMS } from './types.js';
3
+ export function record(value, label) {
4
+ if (!value || typeof value !== 'object' || Array.isArray(value))
5
+ invalid(label);
6
+ return value;
7
+ }
8
+ export function invalid(label) {
9
+ return runtimeError('RUNTIME_MANIFEST_INVALID', `Runtime manifest has invalid ${label}.`);
10
+ }
11
+ export function exact(value, keys, label) {
12
+ if (Object.keys(value).length !== keys.length || keys.some((key) => !Object.hasOwn(value, key)))
13
+ invalid(label);
14
+ }
15
+ export function text(value, label, max = 256) {
16
+ if (typeof value !== 'string' ||
17
+ !value ||
18
+ value.length > max ||
19
+ value.split('').some((char) => char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127))
20
+ invalid(label);
21
+ return value;
22
+ }
23
+ export function id(value) {
24
+ const result = text(value, 'identifier', 64);
25
+ if (!/^[a-z0-9][a-z0-9._-]*$/u.test(result) || result === '.' || result === '..')
26
+ invalid('identifier');
27
+ return result;
28
+ }
29
+ export function version(value) {
30
+ const result = text(value, 'version', 40);
31
+ if (!/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(result))
32
+ invalid('exact stable version');
33
+ return result;
34
+ }
35
+ export function sha(value) {
36
+ const result = text(value, 'SHA-256', 64);
37
+ if (!/^[0-9a-f]{64}$/u.test(result))
38
+ invalid('SHA-256');
39
+ return result;
40
+ }
41
+ export function integer(value, max, minimum = 0) {
42
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < minimum || value > max)
43
+ invalid('bounded integer');
44
+ return value;
45
+ }
46
+ export function array(value, max, minimum = 0) {
47
+ if (!Array.isArray(value) || value.length > max || value.length < minimum)
48
+ invalid('bounded array');
49
+ return value;
50
+ }
51
+ export function platform(value) {
52
+ if (!RUNTIME_PLATFORMS.includes(value))
53
+ invalid('platform');
54
+ return value;
55
+ }
56
+ export function relativeFile(value) {
57
+ const result = text(value, 'portable file path', 255);
58
+ if (Buffer.byteLength(result) > 255 ||
59
+ result.includes('\\') ||
60
+ result.includes(':') ||
61
+ result.startsWith('/') ||
62
+ result
63
+ .split('/')
64
+ .some((part) => !part ||
65
+ part === '.' ||
66
+ part === '..' ||
67
+ /^(?:\.env(?:\..*)?|\.git|\.npmrc|\.ssh)$/iu.test(part) ||
68
+ /[. ]$/u.test(part) ||
69
+ /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(part)))
70
+ invalid('portable file path');
71
+ const segments = result.split('/');
72
+ if (segments.length > 32 ||
73
+ Buffer.byteLength(segments.at(-1)) > 100 ||
74
+ (Buffer.byteLength(result) > 100 &&
75
+ !segments
76
+ .slice(0, -1)
77
+ .some((_, i) => Buffer.byteLength(segments.slice(0, i + 1).join('/')) <= 155 &&
78
+ Buffer.byteLength(segments.slice(i + 1).join('/')) <= 100)))
79
+ invalid('USTAR path');
80
+ return result;
81
+ }
82
+ export function unique(values, label) {
83
+ if (new Set(values).size !== values.length)
84
+ invalid(`duplicate ${label}`);
85
+ }
86
+ export function distributionUrl(value, redirected = false) {
87
+ const input = text(value, 'distribution URL', 4096);
88
+ let url;
89
+ try {
90
+ url = new URL(input);
91
+ }
92
+ catch {
93
+ invalid('distribution URL');
94
+ }
95
+ if (url.protocol !== 'https:' || url.username || url.password || url.hash || url.port)
96
+ invalid('distribution URL');
97
+ const primary = ['github.com', 'nodejs.org', 'registry.npmjs.org'];
98
+ const redirects = ['release-assets.githubusercontent.com', 'objects.githubusercontent.com'];
99
+ if (!primary.includes(url.hostname) && !(redirected && redirects.includes(url.hostname)))
100
+ invalid('distribution origin');
101
+ if (!redirected) {
102
+ if (url.search || /\/(?:latest|heads)(?:\/|$)/u.test(url.pathname))
103
+ invalid('immutable distribution URL');
104
+ if (url.hostname === 'github.com' &&
105
+ !/^\/[^/]+\/[^/]+\/releases\/download\/[^/]+\/[^/]+$/u.test(url.pathname))
106
+ invalid('release asset URL');
107
+ if (url.hostname === 'nodejs.org' &&
108
+ !/^\/dist\/v[0-9]+\.[0-9]+\.[0-9]+\/[^/]+$/u.test(url.pathname))
109
+ invalid('Node release URL');
110
+ if (url.hostname === 'registry.npmjs.org' &&
111
+ !/\/-\/[^/]+-[0-9]+\.[0-9]+\.[0-9]+\.tgz$/u.test(url.pathname))
112
+ invalid('registry tarball URL');
113
+ }
114
+ return url.href;
115
+ }
116
+ export function deepFreeze(value) {
117
+ if (value && typeof value === 'object' && !Object.isFrozen(value)) {
118
+ for (const item of Object.values(value))
119
+ deepFreeze(item);
120
+ Object.freeze(value);
121
+ }
122
+ return value;
123
+ }
124
+ //# sourceMappingURL=manifest-values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest-values.js","sourceRoot":"","sources":["../../../../src/lib/runtime/manifest-values.ts"],"names":[],"mappings":"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","sourcesContent":["import { runtimeError } from './files.js';\nimport { RUNTIME_PLATFORMS, type RuntimePlatform } from './types.js';\n\nexport function record(value: unknown, label: string): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) invalid(label);\n return value as Record<string, unknown>;\n}\nexport function invalid(label: string): never {\n return runtimeError('RUNTIME_MANIFEST_INVALID', `Runtime manifest has invalid ${label}.`);\n}\nexport function exact(\n value: Record<string, unknown>,\n keys: readonly string[],\n label: string,\n): void {\n if (Object.keys(value).length !== keys.length || keys.some((key) => !Object.hasOwn(value, key)))\n invalid(label);\n}\nexport function text(value: unknown, label: string, max = 256): string {\n if (\n typeof value !== 'string' ||\n !value ||\n value.length > max ||\n value.split('').some((char) => char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127)\n )\n invalid(label);\n return value;\n}\nexport function id(value: unknown): string {\n const result = text(value, 'identifier', 64);\n if (!/^[a-z0-9][a-z0-9._-]*$/u.test(result) || result === '.' || result === '..')\n invalid('identifier');\n return result;\n}\nexport function version(value: unknown): string {\n const result = text(value, 'version', 40);\n if (!/^(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*)$/u.test(result))\n invalid('exact stable version');\n return result;\n}\nexport function sha(value: unknown): string {\n const result = text(value, 'SHA-256', 64);\n if (!/^[0-9a-f]{64}$/u.test(result)) invalid('SHA-256');\n return result;\n}\nexport function integer(value: unknown, max: number, minimum = 0): number {\n if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < minimum || value > max)\n invalid('bounded integer');\n return value;\n}\nexport function array(value: unknown, max: number, minimum = 0): unknown[] {\n if (!Array.isArray(value) || value.length > max || value.length < minimum)\n invalid('bounded array');\n return value;\n}\nexport function platform(value: unknown): RuntimePlatform {\n if (!RUNTIME_PLATFORMS.includes(value as RuntimePlatform)) invalid('platform');\n return value as RuntimePlatform;\n}\nexport function relativeFile(value: unknown): string {\n const result = text(value, 'portable file path', 255);\n if (\n Buffer.byteLength(result) > 255 ||\n result.includes('\\\\') ||\n result.includes(':') ||\n result.startsWith('/') ||\n result\n .split('/')\n .some(\n (part) =>\n !part ||\n part === '.' ||\n part === '..' ||\n /^(?:\\.env(?:\\..*)?|\\.git|\\.npmrc|\\.ssh)$/iu.test(part) ||\n /[. ]$/u.test(part) ||\n /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\\.|$)/iu.test(part),\n )\n )\n invalid('portable file path');\n const segments = result.split('/');\n if (\n segments.length > 32 ||\n Buffer.byteLength(segments.at(-1)!) > 100 ||\n (Buffer.byteLength(result) > 100 &&\n !segments\n .slice(0, -1)\n .some(\n (_, i) =>\n Buffer.byteLength(segments.slice(0, i + 1).join('/')) <= 155 &&\n Buffer.byteLength(segments.slice(i + 1).join('/')) <= 100,\n ))\n )\n invalid('USTAR path');\n return result;\n}\nexport function unique(values: readonly string[], label: string): void {\n if (new Set(values).size !== values.length) invalid(`duplicate ${label}`);\n}\nexport function distributionUrl(value: unknown, redirected = false): string {\n const input = text(value, 'distribution URL', 4096);\n let url: URL;\n try {\n url = new URL(input);\n } catch {\n invalid('distribution URL');\n }\n if (url.protocol !== 'https:' || url.username || url.password || url.hash || url.port)\n invalid('distribution URL');\n const primary = ['github.com', 'nodejs.org', 'registry.npmjs.org'];\n const redirects = ['release-assets.githubusercontent.com', 'objects.githubusercontent.com'];\n if (!primary.includes(url.hostname) && !(redirected && redirects.includes(url.hostname)))\n invalid('distribution origin');\n if (!redirected) {\n if (url.search || /\\/(?:latest|heads)(?:\\/|$)/u.test(url.pathname))\n invalid('immutable distribution URL');\n if (\n url.hostname === 'github.com' &&\n !/^\\/[^/]+\\/[^/]+\\/releases\\/download\\/[^/]+\\/[^/]+$/u.test(url.pathname)\n )\n invalid('release asset URL');\n if (\n url.hostname === 'nodejs.org' &&\n !/^\\/dist\\/v[0-9]+\\.[0-9]+\\.[0-9]+\\/[^/]+$/u.test(url.pathname)\n )\n invalid('Node release URL');\n if (\n url.hostname === 'registry.npmjs.org' &&\n !/\\/-\\/[^/]+-[0-9]+\\.[0-9]+\\.[0-9]+\\.tgz$/u.test(url.pathname)\n )\n invalid('registry tarball URL');\n }\n return url.href;\n}\nexport function deepFreeze<T>(value: T): T {\n if (value && typeof value === 'object' && !Object.isFrozen(value)) {\n for (const item of Object.values(value)) deepFreeze(item);\n Object.freeze(value);\n }\n return value;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type { RuntimeComponent, RuntimeManifest, TrustedRuntimeManifest, WorkspaceCompatibility } from './manifest-types.js';
2
+ export declare function parseRuntimeManifest(value: unknown): RuntimeManifest;
3
+ export declare function trustRuntimeManifest(bytes: Uint8Array, expectedSha256: string): TrustedRuntimeManifest;
4
+ export declare function loadTrustedRuntimeManifest(file: string, expectedSha256: string): TrustedRuntimeManifest;
5
+ export declare function assertTrustedManifest(value: TrustedRuntimeManifest): void;
6
+ export declare function copyTrustedRuntimeManifestBytes(value: TrustedRuntimeManifest): Buffer;
7
+ export declare function componentKey(value: RuntimeComponent): string;
8
+ export declare function assertWorkspaceCompatibility(value: TrustedRuntimeManifest, request: WorkspaceCompatibility, access: 'read' | 'write'): void;
@@ -0,0 +1,239 @@
1
+ import fs from 'node:fs';
2
+ import { createHash } from 'node:crypto';
3
+ import { contentHash, runtimeError } from './files.js';
4
+ import { array, deepFreeze, distributionUrl, exact, id, integer, invalid, platform, record, relativeFile, sha, text, unique, version, } from './manifest-values.js';
5
+ import { RUNTIME_ARCHIVE_FORMAT, RUNTIME_BOOTSTRAP_PROTOCOL, RUNTIME_MANIFEST_SCHEMA, RUNTIME_HOST_CONTEXT_PROTOCOL, } from './manifest-types.js';
6
+ const trusted = new WeakMap();
7
+ function compatibility(value) {
8
+ const result = array(value, 32).map((item) => {
9
+ const entry = record(item, 'workspace compatibility');
10
+ exact(entry, ['schema', 'features'], 'workspace compatibility');
11
+ const features = array(entry.features, 64).map((value) => text(value, 'workspace feature', 128));
12
+ unique(features, 'workspace feature');
13
+ return { schema: text(entry.schema, 'workspace schema', 128), features };
14
+ });
15
+ unique(result.map((entry) => entry.schema), 'workspace schema');
16
+ return result;
17
+ }
18
+ function component(value) {
19
+ const item = record(value, 'component');
20
+ exact(item, [
21
+ 'id',
22
+ 'version',
23
+ 'platform',
24
+ 'archive',
25
+ 'files',
26
+ 'content_sha256',
27
+ 'production_lock',
28
+ 'sbom',
29
+ 'licenses',
30
+ 'provenance',
31
+ 'protocols',
32
+ 'asset_fingerprints',
33
+ ], 'component');
34
+ const archive = record(item.archive, 'archive');
35
+ exact(archive, ['format', 'url', 'bytes', 'sha256'], 'archive');
36
+ if (archive.format !== RUNTIME_ARCHIVE_FORMAT)
37
+ invalid('archive format');
38
+ let total = 0;
39
+ const files = array(item.files, 50_000, 1).map((value) => {
40
+ const file = record(value, 'component file');
41
+ exact(file, ['path', 'bytes', 'sha256', 'mode'], 'component file');
42
+ if (file.mode !== 420 && file.mode !== 493)
43
+ invalid('file mode');
44
+ const bytes = integer(file.bytes, 512 * 1024 * 1024);
45
+ total += bytes;
46
+ return { path: relativeFile(file.path), bytes, sha256: sha(file.sha256), mode: file.mode };
47
+ });
48
+ if (total > 2 * 1024 * 1024 * 1024)
49
+ invalid('unpacked size');
50
+ const paths = files.map((file) => file.path);
51
+ unique(paths.map((path) => path.toLowerCase()), 'case-folded file path');
52
+ if (JSON.stringify(paths) !== JSON.stringify([...paths].sort()))
53
+ invalid('file order');
54
+ const pathSet = new Set(paths.map((path) => path.toLowerCase()));
55
+ for (const file of paths) {
56
+ const parts = file.split('/');
57
+ for (let i = 1; i < parts.length; i++)
58
+ if (pathSet.has(parts.slice(0, i).join('/').toLowerCase()))
59
+ invalid('file/directory collision');
60
+ }
61
+ const content = sha(item.content_sha256);
62
+ if (content !== contentHash(files))
63
+ invalid('component content SHA-256');
64
+ const requiredFile = (value) => {
65
+ const file = relativeFile(value);
66
+ if (!paths.includes(file))
67
+ invalid('metadata file reference');
68
+ return file;
69
+ };
70
+ const licenses = array(item.licenses, 64, 1).map(requiredFile), provenance = array(item.provenance, 64, 1).map(requiredFile);
71
+ unique(licenses, 'license');
72
+ unique(provenance, 'provenance');
73
+ const protocols = array(item.protocols, 32, 1).map((value) => text(value, 'component protocol', 128));
74
+ unique(protocols, 'protocol');
75
+ const fingerprints = record(item.asset_fingerprints, 'asset fingerprints');
76
+ if (Object.keys(fingerprints).length > 64)
77
+ invalid('fingerprint count');
78
+ const asset_fingerprints = Object.fromEntries(Object.entries(fingerprints).map(([key, value]) => [id(key), sha(value)]));
79
+ return {
80
+ id: id(item.id),
81
+ version: version(item.version),
82
+ platform: platform(item.platform),
83
+ archive: {
84
+ format: RUNTIME_ARCHIVE_FORMAT,
85
+ url: distributionUrl(archive.url),
86
+ bytes: integer(archive.bytes, 512 * 1024 * 1024, 1),
87
+ sha256: sha(archive.sha256),
88
+ },
89
+ files,
90
+ content_sha256: content,
91
+ production_lock: requiredFile(item.production_lock),
92
+ sbom: requiredFile(item.sbom),
93
+ licenses,
94
+ provenance,
95
+ protocols,
96
+ asset_fingerprints,
97
+ };
98
+ }
99
+ function componentPath(value, components, target, executable = false) {
100
+ const entry = record(value, 'component path');
101
+ exact(entry, ['component', 'path'], 'component path');
102
+ const componentId = id(entry.component), file = relativeFile(entry.path);
103
+ const owner = components.find((item) => item.platform === target && item.id === componentId);
104
+ const fact = owner?.files.find((item) => item.path === file);
105
+ if (!fact || (executable && fact.mode !== 493))
106
+ invalid('launch file reference');
107
+ return { component: componentId, path: file };
108
+ }
109
+ export function parseRuntimeManifest(value) {
110
+ const item = record(value, 'manifest');
111
+ exact(item, [
112
+ 'schema',
113
+ 'bootstrap_protocol',
114
+ 'product',
115
+ 'minimum_hosts',
116
+ 'workspace',
117
+ 'components',
118
+ 'launches',
119
+ ], 'manifest');
120
+ if (item.schema !== RUNTIME_MANIFEST_SCHEMA ||
121
+ item.bootstrap_protocol !== RUNTIME_BOOTSTRAP_PROTOCOL)
122
+ invalid('manifest protocol version');
123
+ const product = record(item.product, 'product');
124
+ exact(product, ['id', 'version'], 'product');
125
+ const workspace = record(item.workspace, 'workspace');
126
+ exact(workspace, ['read', 'write'], 'workspace');
127
+ const read = compatibility(workspace.read), write = compatibility(workspace.write);
128
+ for (const entry of write)
129
+ if (!read.some((candidate) => candidate.schema === entry.schema &&
130
+ entry.features.every((feature) => candidate.features.includes(feature))))
131
+ invalid('write compatibility outside read support');
132
+ const components = array(item.components, 128, 1).map(component);
133
+ unique(components.map((item) => `${item.platform}:${item.id}`), 'platform component');
134
+ const minimum = record(item.minimum_hosts, 'minimum hosts');
135
+ const minimum_hosts = Object.fromEntries(Object.entries(minimum).map(([key, value]) => {
136
+ const target = platform(key), host = record(value, 'minimum host');
137
+ exact(host, ['os_release', 'glibc'], 'minimum host');
138
+ if ((target.startsWith('linux-') && typeof host.glibc !== 'string') ||
139
+ (!target.startsWith('linux-') && host.glibc !== null))
140
+ invalid('host ABI');
141
+ const glibc = host.glibc === null ? null : text(host.glibc, 'glibc version', 40);
142
+ if (glibc !== null && !/^[0-9]+\.[0-9]+$/u.test(glibc))
143
+ invalid('glibc version');
144
+ return [target, { os_release: version(host.os_release), glibc }];
145
+ }));
146
+ const supported = [...new Set(components.map((item) => item.platform))].sort();
147
+ if (JSON.stringify(Object.keys(minimum_hosts).sort()) !== JSON.stringify(supported))
148
+ invalid('host/component platform coverage');
149
+ const launches = array(item.launches, 64, 1).map((value) => {
150
+ const launch = record(value, 'launch');
151
+ const hasContext = Object.hasOwn(launch, 'context_protocol');
152
+ exact(launch, [
153
+ 'id',
154
+ 'platform',
155
+ 'executable',
156
+ 'environment',
157
+ 'argv',
158
+ ...(hasContext ? ['context_protocol'] : []),
159
+ ], 'launch');
160
+ if (hasContext && launch.context_protocol !== RUNTIME_HOST_CONTEXT_PROTOCOL)
161
+ invalid('host context protocol');
162
+ if (launch.environment !== 'isolated' && launch.environment !== 'cli-auth')
163
+ invalid('launch environment');
164
+ const target = platform(launch.platform);
165
+ const argv = array(launch.argv, 32).map((value) => {
166
+ const arg = record(value, 'launch argument');
167
+ if (Object.hasOwn(arg, 'literal')) {
168
+ exact(arg, ['literal'], 'literal argument');
169
+ return { literal: text(arg.literal, 'literal argument', 4096) };
170
+ }
171
+ return componentPath(arg, components, target);
172
+ });
173
+ return {
174
+ id: id(launch.id),
175
+ platform: target,
176
+ executable: componentPath(launch.executable, components, target, true),
177
+ environment: launch.environment,
178
+ ...(hasContext ? { context_protocol: RUNTIME_HOST_CONTEXT_PROTOCOL } : {}),
179
+ argv,
180
+ };
181
+ });
182
+ unique(launches.map((item) => `${item.platform}:${item.id}`), 'platform launch');
183
+ for (const target of supported)
184
+ if (!launches.some((launch) => launch.platform === target))
185
+ invalid('platform launch coverage');
186
+ return deepFreeze({
187
+ schema: RUNTIME_MANIFEST_SCHEMA,
188
+ bootstrap_protocol: RUNTIME_BOOTSTRAP_PROTOCOL,
189
+ product: { id: id(product.id), version: version(product.version) },
190
+ minimum_hosts,
191
+ workspace: { read, write },
192
+ components,
193
+ launches,
194
+ });
195
+ }
196
+ export function trustRuntimeManifest(bytes, expectedSha256) {
197
+ sha(expectedSha256);
198
+ if (bytes.byteLength > 32 * 1024 * 1024)
199
+ runtimeError('RUNTIME_MANIFEST_INTEGRITY', 'Runtime manifest bytes do not match the independent trust anchor.');
200
+ const snapshot = Buffer.from(bytes);
201
+ if (createHash('sha256').update(snapshot).digest('hex') !== expectedSha256)
202
+ runtimeError('RUNTIME_MANIFEST_INTEGRITY', 'Runtime manifest bytes do not match the independent trust anchor.');
203
+ let value;
204
+ try {
205
+ value = JSON.parse(snapshot.toString('utf8'));
206
+ }
207
+ catch {
208
+ invalid('JSON');
209
+ }
210
+ const result = Object.freeze({ sha256: expectedSha256, manifest: parseRuntimeManifest(value) });
211
+ trusted.set(result, snapshot);
212
+ return result;
213
+ }
214
+ export function loadTrustedRuntimeManifest(file, expectedSha256) {
215
+ const stat = fs.lstatSync(file);
216
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 32 * 1024 * 1024)
217
+ runtimeError('RUNTIME_MANIFEST_FILE', 'Runtime manifest must be a bounded regular file.');
218
+ return trustRuntimeManifest(fs.readFileSync(file), expectedSha256);
219
+ }
220
+ export function assertTrustedManifest(value) {
221
+ if (!value || !trusted.has(value))
222
+ runtimeError('RUNTIME_MANIFEST_UNTRUSTED', 'Supply a manifest verified against an independent trusted digest.');
223
+ }
224
+ export function copyTrustedRuntimeManifestBytes(value) {
225
+ const bytes = trusted.get(value);
226
+ if (!bytes)
227
+ runtimeError('RUNTIME_MANIFEST_UNTRUSTED', 'Supply a manifest verified against an independent trusted digest.');
228
+ return Buffer.from(bytes);
229
+ }
230
+ export function componentKey(value) {
231
+ return contentHash(value);
232
+ }
233
+ export function assertWorkspaceCompatibility(value, request, access) {
234
+ assertTrustedManifest(value);
235
+ const support = value.manifest.workspace[access]?.find((entry) => entry.schema === request.schema);
236
+ if (!support || !request.features.every((feature) => support.features.includes(feature)))
237
+ runtimeError('RUNTIME_WORKSPACE_INCOMPATIBLE', 'The selected runtime does not support the requested workspace access/schema/features.');
238
+ }
239
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../../src/lib/runtime/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { contentHash, runtimeError } from './files.js';\nimport {\n array,\n deepFreeze,\n distributionUrl,\n exact,\n id,\n integer,\n invalid,\n platform,\n record,\n relativeFile,\n sha,\n text,\n unique,\n version,\n} from './manifest-values.js';\nimport {\n RUNTIME_ARCHIVE_FORMAT,\n RUNTIME_BOOTSTRAP_PROTOCOL,\n RUNTIME_MANIFEST_SCHEMA,\n RUNTIME_HOST_CONTEXT_PROTOCOL,\n} from './manifest-types.js';\nimport type {\n ComponentFile,\n ComponentPath,\n RuntimeComponent,\n RuntimeLaunch,\n RuntimeManifest,\n TrustedRuntimeManifest,\n WorkspaceCompatibility,\n} from './manifest-types.js';\nconst trusted = new WeakMap<object, Buffer>();\n\nfunction compatibility(value: unknown): WorkspaceCompatibility[] {\n const result = array(value, 32).map((item) => {\n const entry = record(item, 'workspace compatibility');\n exact(entry, ['schema', 'features'], 'workspace compatibility');\n const features = array(entry.features, 64).map((value) =>\n text(value, 'workspace feature', 128),\n );\n unique(features, 'workspace feature');\n return { schema: text(entry.schema, 'workspace schema', 128), features };\n });\n unique(\n result.map((entry) => entry.schema),\n 'workspace schema',\n );\n return result;\n}\nfunction component(value: unknown): RuntimeComponent {\n const item = record(value, 'component');\n exact(\n item,\n [\n 'id',\n 'version',\n 'platform',\n 'archive',\n 'files',\n 'content_sha256',\n 'production_lock',\n 'sbom',\n 'licenses',\n 'provenance',\n 'protocols',\n 'asset_fingerprints',\n ],\n 'component',\n );\n const archive = record(item.archive, 'archive');\n exact(archive, ['format', 'url', 'bytes', 'sha256'], 'archive');\n if (archive.format !== RUNTIME_ARCHIVE_FORMAT) invalid('archive format');\n let total = 0;\n const files: ComponentFile[] = array(item.files, 50_000, 1).map((value) => {\n const file = record(value, 'component file');\n exact(file, ['path', 'bytes', 'sha256', 'mode'], 'component file');\n if (file.mode !== 420 && file.mode !== 493) invalid('file mode');\n const bytes = integer(file.bytes, 512 * 1024 * 1024);\n total += bytes;\n return { path: relativeFile(file.path), bytes, sha256: sha(file.sha256), mode: file.mode };\n });\n if (total > 2 * 1024 * 1024 * 1024) invalid('unpacked size');\n const paths = files.map((file) => file.path);\n unique(\n paths.map((path) => path.toLowerCase()),\n 'case-folded file path',\n );\n if (JSON.stringify(paths) !== JSON.stringify([...paths].sort())) invalid('file order');\n const pathSet = new Set(paths.map((path) => path.toLowerCase()));\n for (const file of paths) {\n const parts = file.split('/');\n for (let i = 1; i < parts.length; i++)\n if (pathSet.has(parts.slice(0, i).join('/').toLowerCase()))\n invalid('file/directory collision');\n }\n const content = sha(item.content_sha256);\n if (content !== contentHash(files)) invalid('component content SHA-256');\n const requiredFile = (value: unknown) => {\n const file = relativeFile(value);\n if (!paths.includes(file)) invalid('metadata file reference');\n return file;\n };\n const licenses = array(item.licenses, 64, 1).map(requiredFile),\n provenance = array(item.provenance, 64, 1).map(requiredFile);\n unique(licenses, 'license');\n unique(provenance, 'provenance');\n const protocols = array(item.protocols, 32, 1).map((value) =>\n text(value, 'component protocol', 128),\n );\n unique(protocols, 'protocol');\n const fingerprints = record(item.asset_fingerprints, 'asset fingerprints');\n if (Object.keys(fingerprints).length > 64) invalid('fingerprint count');\n const asset_fingerprints = Object.fromEntries(\n Object.entries(fingerprints).map(([key, value]) => [id(key), sha(value)]),\n );\n return {\n id: id(item.id),\n version: version(item.version),\n platform: platform(item.platform),\n archive: {\n format: RUNTIME_ARCHIVE_FORMAT,\n url: distributionUrl(archive.url),\n bytes: integer(archive.bytes, 512 * 1024 * 1024, 1),\n sha256: sha(archive.sha256),\n },\n files,\n content_sha256: content,\n production_lock: requiredFile(item.production_lock),\n sbom: requiredFile(item.sbom),\n licenses,\n provenance,\n protocols,\n asset_fingerprints,\n };\n}\nfunction componentPath(\n value: unknown,\n components: readonly RuntimeComponent[],\n target: string,\n executable = false,\n): ComponentPath {\n const entry = record(value, 'component path');\n exact(entry, ['component', 'path'], 'component path');\n const componentId = id(entry.component),\n file = relativeFile(entry.path);\n const owner = components.find((item) => item.platform === target && item.id === componentId);\n const fact = owner?.files.find((item) => item.path === file);\n if (!fact || (executable && fact.mode !== 493)) invalid('launch file reference');\n return { component: componentId, path: file };\n}\nexport function parseRuntimeManifest(value: unknown): RuntimeManifest {\n const item = record(value, 'manifest');\n exact(\n item,\n [\n 'schema',\n 'bootstrap_protocol',\n 'product',\n 'minimum_hosts',\n 'workspace',\n 'components',\n 'launches',\n ],\n 'manifest',\n );\n if (\n item.schema !== RUNTIME_MANIFEST_SCHEMA ||\n item.bootstrap_protocol !== RUNTIME_BOOTSTRAP_PROTOCOL\n )\n invalid('manifest protocol version');\n const product = record(item.product, 'product');\n exact(product, ['id', 'version'], 'product');\n const workspace = record(item.workspace, 'workspace');\n exact(workspace, ['read', 'write'], 'workspace');\n const read = compatibility(workspace.read),\n write = compatibility(workspace.write);\n for (const entry of write)\n if (\n !read.some(\n (candidate) =>\n candidate.schema === entry.schema &&\n entry.features.every((feature) => candidate.features.includes(feature)),\n )\n )\n invalid('write compatibility outside read support');\n const components = array(item.components, 128, 1).map(component);\n unique(\n components.map((item) => `${item.platform}:${item.id}`),\n 'platform component',\n );\n const minimum = record(item.minimum_hosts, 'minimum hosts');\n const minimum_hosts = Object.fromEntries(\n Object.entries(minimum).map(([key, value]) => {\n const target = platform(key),\n host = record(value, 'minimum host');\n exact(host, ['os_release', 'glibc'], 'minimum host');\n if (\n (target.startsWith('linux-') && typeof host.glibc !== 'string') ||\n (!target.startsWith('linux-') && host.glibc !== null)\n )\n invalid('host ABI');\n const glibc = host.glibc === null ? null : text(host.glibc, 'glibc version', 40);\n if (glibc !== null && !/^[0-9]+\\.[0-9]+$/u.test(glibc)) invalid('glibc version');\n return [target, { os_release: version(host.os_release), glibc }];\n }),\n );\n const supported = [...new Set(components.map((item) => item.platform))].sort();\n if (JSON.stringify(Object.keys(minimum_hosts).sort()) !== JSON.stringify(supported))\n invalid('host/component platform coverage');\n const launches: RuntimeLaunch[] = array(item.launches, 64, 1).map((value) => {\n const launch = record(value, 'launch');\n const hasContext = Object.hasOwn(launch, 'context_protocol');\n exact(\n launch,\n [\n 'id',\n 'platform',\n 'executable',\n 'environment',\n 'argv',\n ...(hasContext ? ['context_protocol'] : []),\n ],\n 'launch',\n );\n if (hasContext && launch.context_protocol !== RUNTIME_HOST_CONTEXT_PROTOCOL)\n invalid('host context protocol');\n if (launch.environment !== 'isolated' && launch.environment !== 'cli-auth')\n invalid('launch environment');\n const target = platform(launch.platform);\n const argv = array(launch.argv, 32).map((value) => {\n const arg = record(value, 'launch argument');\n if (Object.hasOwn(arg, 'literal')) {\n exact(arg, ['literal'], 'literal argument');\n return { literal: text(arg.literal, 'literal argument', 4096) };\n }\n return componentPath(arg, components, target);\n });\n return {\n id: id(launch.id),\n platform: target,\n executable: componentPath(launch.executable, components, target, true),\n environment: launch.environment,\n ...(hasContext ? { context_protocol: RUNTIME_HOST_CONTEXT_PROTOCOL } : {}),\n argv,\n };\n });\n unique(\n launches.map((item) => `${item.platform}:${item.id}`),\n 'platform launch',\n );\n for (const target of supported)\n if (!launches.some((launch) => launch.platform === target)) invalid('platform launch coverage');\n return deepFreeze({\n schema: RUNTIME_MANIFEST_SCHEMA,\n bootstrap_protocol: RUNTIME_BOOTSTRAP_PROTOCOL,\n product: { id: id(product.id), version: version(product.version) },\n minimum_hosts,\n workspace: { read, write },\n components,\n launches,\n });\n}\nexport function trustRuntimeManifest(\n bytes: Uint8Array,\n expectedSha256: string,\n): TrustedRuntimeManifest {\n sha(expectedSha256);\n if (bytes.byteLength > 32 * 1024 * 1024)\n runtimeError(\n 'RUNTIME_MANIFEST_INTEGRITY',\n 'Runtime manifest bytes do not match the independent trust anchor.',\n );\n const snapshot = Buffer.from(bytes);\n if (createHash('sha256').update(snapshot).digest('hex') !== expectedSha256)\n runtimeError(\n 'RUNTIME_MANIFEST_INTEGRITY',\n 'Runtime manifest bytes do not match the independent trust anchor.',\n );\n let value: unknown;\n try {\n value = JSON.parse(snapshot.toString('utf8'));\n } catch {\n invalid('JSON');\n }\n const result = Object.freeze({ sha256: expectedSha256, manifest: parseRuntimeManifest(value) });\n trusted.set(result, snapshot);\n return result;\n}\nexport function loadTrustedRuntimeManifest(\n file: string,\n expectedSha256: string,\n): TrustedRuntimeManifest {\n const stat = fs.lstatSync(file);\n if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 32 * 1024 * 1024)\n runtimeError('RUNTIME_MANIFEST_FILE', 'Runtime manifest must be a bounded regular file.');\n return trustRuntimeManifest(fs.readFileSync(file), expectedSha256);\n}\nexport function assertTrustedManifest(value: TrustedRuntimeManifest): void {\n if (!value || !trusted.has(value))\n runtimeError(\n 'RUNTIME_MANIFEST_UNTRUSTED',\n 'Supply a manifest verified against an independent trusted digest.',\n );\n}\nexport function copyTrustedRuntimeManifestBytes(value: TrustedRuntimeManifest): Buffer {\n const bytes = trusted.get(value);\n if (!bytes)\n runtimeError(\n 'RUNTIME_MANIFEST_UNTRUSTED',\n 'Supply a manifest verified against an independent trusted digest.',\n );\n return Buffer.from(bytes);\n}\nexport function componentKey(value: RuntimeComponent): string {\n return contentHash(value);\n}\nexport function assertWorkspaceCompatibility(\n value: TrustedRuntimeManifest,\n request: WorkspaceCompatibility,\n access: 'read' | 'write',\n): void {\n assertTrustedManifest(value);\n const support = value.manifest.workspace[access]?.find(\n (entry) => entry.schema === request.schema,\n );\n if (!support || !request.features.every((feature) => support.features.includes(feature)))\n runtimeError(\n 'RUNTIME_WORKSPACE_INCOMPATIBLE',\n 'The selected runtime does not support the requested workspace access/schema/features.',\n );\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { FoundryCommandSpecAsyncSpawnOptions, FoundryCommandSpecSpawnResult } from '../../command-spec.js';
2
+ import type { RuntimeHostContext } from './manifest-types.js';
3
+ /** Resolve only after close, including cancellation and output overflow, so callers retain component leases. */
4
+ export declare function spawnRuntimeProcess(executable: string, argv: readonly string[], options: FoundryCommandSpecAsyncSpawnOptions, context?: RuntimeHostContext): Promise<FoundryCommandSpecSpawnResult>;
@@ -0,0 +1,69 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { serveRuntimeHostContext } from './host-context-server.js';
3
+ /** Resolve only after close, including cancellation and output overflow, so callers retain component leases. */
4
+ export function spawnRuntimeProcess(executable, argv, options, context) {
5
+ return new Promise((resolve) => {
6
+ const child = spawn(executable, [...argv], {
7
+ cwd: options.cwd,
8
+ env: options.env,
9
+ shell: false,
10
+ windowsHide: true,
11
+ stdio: ['ignore', 'pipe', 'pipe', ...(context ? ['ipc'] : [])],
12
+ });
13
+ const stdout = [], stderr = [];
14
+ let bytes = 0;
15
+ let error;
16
+ let force;
17
+ let hostSession;
18
+ const stop = () => {
19
+ hostSession?.finish();
20
+ child.kill('SIGTERM');
21
+ force ??= setTimeout(() => child.kill('SIGKILL'), 3000);
22
+ };
23
+ const abort = () => {
24
+ error = new Error('Runtime execution was interrupted.');
25
+ stop();
26
+ };
27
+ if (context)
28
+ child.once('spawn', () => {
29
+ if (error)
30
+ return;
31
+ hostSession = serveRuntimeHostContext(child, context, (failure) => {
32
+ error ??= failure;
33
+ stop();
34
+ });
35
+ });
36
+ options.signal.addEventListener('abort', abort, { once: true });
37
+ if (options.signal.aborted)
38
+ abort();
39
+ const capture = (target, chunk) => {
40
+ bytes += chunk.length;
41
+ if (bytes > (options.maxBuffer ?? 16 * 1024 * 1024)) {
42
+ error = new Error('Runtime output exceeded its bound.');
43
+ stop();
44
+ return;
45
+ }
46
+ target.push(chunk);
47
+ };
48
+ child.stdout.on('data', (chunk) => capture(stdout, chunk));
49
+ child.stderr.on('data', (chunk) => capture(stderr, chunk));
50
+ child.once('error', (value) => {
51
+ error = value;
52
+ });
53
+ child.once('close', (status, signal) => {
54
+ const contextError = hostSession?.finish();
55
+ error ??= contextError;
56
+ if (force)
57
+ clearTimeout(force);
58
+ options.signal.removeEventListener('abort', abort);
59
+ resolve({
60
+ stdout: Buffer.concat(stdout).toString('utf8'),
61
+ stderr: Buffer.concat(stderr).toString('utf8'),
62
+ status,
63
+ signal,
64
+ ...(error ? { error } : {}),
65
+ });
66
+ });
67
+ });
68
+ }
69
+ //# sourceMappingURL=process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.js","sourceRoot":"","sources":["../../../../src/lib/runtime/process.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'node:child_process';\nimport type {\n FoundryCommandSpecAsyncSpawnOptions,\n FoundryCommandSpecSpawnResult,\n} from '../../command-spec.js';\nimport type { RuntimeHostContext } from './manifest-types.js';\nimport { serveRuntimeHostContext } from './host-context-server.js';\n\n/** Resolve only after close, including cancellation and output overflow, so callers retain component leases. */\nexport function spawnRuntimeProcess(\n executable: string,\n argv: readonly string[],\n options: FoundryCommandSpecAsyncSpawnOptions,\n context?: RuntimeHostContext,\n): Promise<FoundryCommandSpecSpawnResult> {\n return new Promise((resolve) => {\n const child = spawn(executable, [...argv], {\n cwd: options.cwd,\n env: options.env,\n shell: false,\n windowsHide: true,\n stdio: ['ignore', 'pipe', 'pipe', ...(context ? ['ipc' as const] : [])],\n });\n const stdout: Buffer[] = [],\n stderr: Buffer[] = [];\n let bytes = 0;\n let error: Error | undefined;\n let force: NodeJS.Timeout | undefined;\n let hostSession: ReturnType<typeof serveRuntimeHostContext> | undefined;\n const stop = () => {\n hostSession?.finish();\n child.kill('SIGTERM');\n force ??= setTimeout(() => child.kill('SIGKILL'), 3000);\n };\n const abort = () => {\n error = new Error('Runtime execution was interrupted.');\n stop();\n };\n if (context)\n child.once('spawn', () => {\n if (error) return;\n hostSession = serveRuntimeHostContext(child, context, (failure) => {\n error ??= failure;\n stop();\n });\n });\n options.signal.addEventListener('abort', abort, { once: true });\n if (options.signal.aborted) abort();\n const capture = (target: Buffer[], chunk: Buffer) => {\n bytes += chunk.length;\n if (bytes > (options.maxBuffer ?? 16 * 1024 * 1024)) {\n error = new Error('Runtime output exceeded its bound.');\n stop();\n return;\n }\n target.push(chunk);\n };\n child.stdout!.on('data', (chunk: Buffer) => capture(stdout, chunk));\n child.stderr!.on('data', (chunk: Buffer) => capture(stderr, chunk));\n child.once('error', (value) => {\n error = value;\n });\n child.once('close', (status, signal) => {\n const contextError = hostSession?.finish();\n error ??= contextError;\n if (force) clearTimeout(force);\n options.signal.removeEventListener('abort', abort);\n resolve({\n stdout: Buffer.concat(stdout).toString('utf8'),\n stderr: Buffer.concat(stderr).toString('utf8'),\n status,\n signal,\n ...(error ? { error } : {}),\n });\n });\n });\n}\n"]}
@@ -0,0 +1,8 @@
1
+ export declare function defaultRuntimeCache(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): string;
2
+ export declare function canonicalCacheRoot(value: string): string;
3
+ export declare function cachePath(root: string, relative: string): string;
4
+ export declare function writeAll(fd: number, bytes: Uint8Array): void;
5
+ export declare function writeOnce(root: string, relative: string, bytes: Uint8Array): void;
6
+ export declare function openRuntimeCache(value: string, create: boolean): string;
7
+ export declare function readCacheJson(root: string, relative: string, limit?: number): unknown;
8
+ export declare function ensureRuntimeCache(value: string): Promise<string>;