@futdevpro/nts-dynamo 1.15.142 → 1.15.144

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 (34) hide show
  1. package/__documentations/2026-08-18-artifact-compiler.md +44 -0
  2. package/build/_modules/artifact-compiler/_enums/artifact-compile-outcome.type-enum.d.ts +6 -0
  3. package/build/_modules/artifact-compiler/_enums/artifact-compile-outcome.type-enum.d.ts.map +1 -0
  4. package/build/_modules/artifact-compiler/_enums/artifact-compile-outcome.type-enum.js +10 -0
  5. package/build/_modules/artifact-compiler/_enums/artifact-compile-outcome.type-enum.js.map +1 -0
  6. package/build/_modules/artifact-compiler/_enums/artifact-compile-stage.type-enum.d.ts +9 -0
  7. package/build/_modules/artifact-compiler/_enums/artifact-compile-stage.type-enum.d.ts.map +1 -0
  8. package/build/_modules/artifact-compiler/_enums/artifact-compile-stage.type-enum.js +13 -0
  9. package/build/_modules/artifact-compiler/_enums/artifact-compile-stage.type-enum.js.map +1 -0
  10. package/build/_modules/artifact-compiler/_enums/artifact-retry-class.type-enum.d.ts +7 -0
  11. package/build/_modules/artifact-compiler/_enums/artifact-retry-class.type-enum.d.ts.map +1 -0
  12. package/build/_modules/artifact-compiler/_enums/artifact-retry-class.type-enum.js +11 -0
  13. package/build/_modules/artifact-compiler/_enums/artifact-retry-class.type-enum.js.map +1 -0
  14. package/build/_modules/artifact-compiler/_models/artifact-compile.interface.d.ts +33 -0
  15. package/build/_modules/artifact-compiler/_models/artifact-compile.interface.d.ts.map +1 -0
  16. package/build/_modules/artifact-compiler/_models/artifact-compile.interface.js +3 -0
  17. package/build/_modules/artifact-compiler/_models/artifact-compile.interface.js.map +1 -0
  18. package/build/_modules/artifact-compiler/artifact-compiler.control-service.d.ts +37 -0
  19. package/build/_modules/artifact-compiler/artifact-compiler.control-service.d.ts.map +1 -0
  20. package/build/_modules/artifact-compiler/artifact-compiler.control-service.js +274 -0
  21. package/build/_modules/artifact-compiler/artifact-compiler.control-service.js.map +1 -0
  22. package/build/_modules/artifact-compiler/index.d.ts +6 -0
  23. package/build/_modules/artifact-compiler/index.d.ts.map +1 -0
  24. package/build/_modules/artifact-compiler/index.js +12 -0
  25. package/build/_modules/artifact-compiler/index.js.map +1 -0
  26. package/package.json +15 -2
  27. package/pnpm-workspace.yaml +4 -3
  28. package/src/_modules/artifact-compiler/_enums/artifact-compile-outcome.type-enum.ts +5 -0
  29. package/src/_modules/artifact-compiler/_enums/artifact-compile-stage.type-enum.ts +8 -0
  30. package/src/_modules/artifact-compiler/_enums/artifact-retry-class.type-enum.ts +6 -0
  31. package/src/_modules/artifact-compiler/_models/artifact-compile.interface.ts +35 -0
  32. package/src/_modules/artifact-compiler/artifact-compiler.control-service.spec.ts +151 -0
  33. package/src/_modules/artifact-compiler/artifact-compiler.control-service.ts +356 -0
  34. package/src/_modules/artifact-compiler/index.ts +9 -0
@@ -0,0 +1,44 @@
1
+ # Dynamo NTS in-memory artifact compiler
2
+
3
+ **Contract:** `dynts-artifact-compiler/1`
4
+
5
+ **Release candidate:** `@futdevpro/nts-dynamo@1.15.144`
6
+
7
+ ## Purpose
8
+
9
+ The artifact compiler turns one already policy-validated TypeScript program into a self-contained JavaScript bundle
10
+ for a classic browser Worker. It is a shared build capability, not a sandbox, an authorization layer or a source
11
+ policy validator. Consumers must validate source before compilation and execute the output inside an independently
12
+ enforced runtime boundary.
13
+
14
+ ## Guarantees
15
+
16
+ - source is supplied through an in-memory virtual entry;
17
+ - output uses the asynchronous esbuild API with `bundle:true`, `platform:'browser'`, `format:'iife'` and
18
+ `write:false`;
19
+ - no sourcemap, embedded source content, legal comment file, plugin supplied by the caller or filesystem output;
20
+ - the TypeScript AST is traversed before bundling, so unused imports cannot disappear through tree-shaking before
21
+ policy evaluation;
22
+ - only caller-allowlisted static package roots resolve from the supplied absolute dependency directory;
23
+ - relative, absolute, re-export, import-equals, `require()` and dynamic `import()` module loads fail closed;
24
+ - transitive modules resolve only through the installed dependency graph;
25
+ - source and output byte limits, allowlist cardinality, package names and path fields have absolute Bedrock
26
+ ceilings;
27
+ - success returns exactly one JavaScript output with SHA-256 metadata;
28
+ - errors return stable codes and optional line/column only, never esbuild message text, source excerpt or path.
29
+
30
+ The output is deterministic for the same source, settings, installed lock graph, platform and compiler version. The
31
+ consumer must therefore version and checksum the compiler version and dependency lock together with the bundle.
32
+
33
+ ## Security boundary
34
+
35
+ esbuild's own documentation explicitly states that esbuild is not a sandbox. This module never executes generated
36
+ code, and successful compilation must not be interpreted as permission to run it. Direct relative/absolute, Node,
37
+ HTTP or non-allowlisted imports fail because only package roots in `allowedPackages` can resolve from the virtual
38
+ entry. Trusted allowed packages may resolve their own installed transitive graph.
39
+
40
+ ## Verification
41
+
42
+ The eight focused Bedrock specs cover deterministic output, a real bundled dependency, non-allowlisted imports,
43
+ all supported static and dynamic module-load syntax, content-free syntax diagnostics, invalid request contracts and
44
+ source/output budgets. Company Toolmaker is the first direct consumer under `BFR-CTM-007`.
@@ -0,0 +1,6 @@
1
+ /** Terminal result of one deterministic in-memory artifact compilation. */
2
+ export declare enum DyNTS_ArtifactCompileOutcome_Type {
3
+ compiled = "compiled",
4
+ rejected = "rejected"
5
+ }
6
+ //# sourceMappingURL=artifact-compile-outcome.type-enum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-compile-outcome.type-enum.d.ts","sourceRoot":"","sources":["../../../../src/_modules/artifact-compiler/_enums/artifact-compile-outcome.type-enum.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,oBAAY,iCAAiC;IAC3C,QAAQ,aAAa;IACrB,QAAQ,aAAa;CACtB"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyNTS_ArtifactCompileOutcome_Type = void 0;
4
+ /** Terminal result of one deterministic in-memory artifact compilation. */
5
+ var DyNTS_ArtifactCompileOutcome_Type;
6
+ (function (DyNTS_ArtifactCompileOutcome_Type) {
7
+ DyNTS_ArtifactCompileOutcome_Type["compiled"] = "compiled";
8
+ DyNTS_ArtifactCompileOutcome_Type["rejected"] = "rejected";
9
+ })(DyNTS_ArtifactCompileOutcome_Type || (exports.DyNTS_ArtifactCompileOutcome_Type = DyNTS_ArtifactCompileOutcome_Type = {}));
10
+ //# sourceMappingURL=artifact-compile-outcome.type-enum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-compile-outcome.type-enum.js","sourceRoot":"","sources":["../../../../src/_modules/artifact-compiler/_enums/artifact-compile-outcome.type-enum.ts"],"names":[],"mappings":";;;AAAA,2EAA2E;AAC3E,IAAY,iCAGX;AAHD,WAAY,iCAAiC;IAC3C,0DAAqB,CAAA;IACrB,0DAAqB,CAAA;AACvB,CAAC,EAHW,iCAAiC,iDAAjC,iCAAiC,QAG5C"}
@@ -0,0 +1,9 @@
1
+ /** Content-free stage identifiers for artifact compiler findings. */
2
+ export declare enum DyNTS_ArtifactCompileStage_Type {
3
+ request = "request",
4
+ sourcePolicy = "source-policy",
5
+ resolve = "resolve",
6
+ compile = "compile",
7
+ output = "output"
8
+ }
9
+ //# sourceMappingURL=artifact-compile-stage.type-enum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-compile-stage.type-enum.d.ts","sourceRoot":"","sources":["../../../../src/_modules/artifact-compiler/_enums/artifact-compile-stage.type-enum.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,oBAAY,+BAA+B;IACzC,OAAO,YAAY;IACnB,YAAY,kBAAkB;IAC9B,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,MAAM,WAAW;CAClB"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyNTS_ArtifactCompileStage_Type = void 0;
4
+ /** Content-free stage identifiers for artifact compiler findings. */
5
+ var DyNTS_ArtifactCompileStage_Type;
6
+ (function (DyNTS_ArtifactCompileStage_Type) {
7
+ DyNTS_ArtifactCompileStage_Type["request"] = "request";
8
+ DyNTS_ArtifactCompileStage_Type["sourcePolicy"] = "source-policy";
9
+ DyNTS_ArtifactCompileStage_Type["resolve"] = "resolve";
10
+ DyNTS_ArtifactCompileStage_Type["compile"] = "compile";
11
+ DyNTS_ArtifactCompileStage_Type["output"] = "output";
12
+ })(DyNTS_ArtifactCompileStage_Type || (exports.DyNTS_ArtifactCompileStage_Type = DyNTS_ArtifactCompileStage_Type = {}));
13
+ //# sourceMappingURL=artifact-compile-stage.type-enum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-compile-stage.type-enum.js","sourceRoot":"","sources":["../../../../src/_modules/artifact-compiler/_enums/artifact-compile-stage.type-enum.ts"],"names":[],"mappings":";;;AAAA,qEAAqE;AACrE,IAAY,+BAMX;AAND,WAAY,+BAA+B;IACzC,sDAAmB,CAAA;IACnB,iEAA8B,CAAA;IAC9B,sDAAmB,CAAA;IACnB,sDAAmB,CAAA;IACnB,oDAAiB,CAAA;AACnB,CAAC,EANW,+BAA+B,+CAA/B,+BAA+B,QAM1C"}
@@ -0,0 +1,7 @@
1
+ /** Stable remediation classification for artifact compiler findings. */
2
+ export declare enum DyNTS_ArtifactRetryClass_Type {
3
+ agentFixable = "agent-fixable",
4
+ deterministicToolFixable = "deterministic-tool-fixable",
5
+ terminal = "terminal"
6
+ }
7
+ //# sourceMappingURL=artifact-retry-class.type-enum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-retry-class.type-enum.d.ts","sourceRoot":"","sources":["../../../../src/_modules/artifact-compiler/_enums/artifact-retry-class.type-enum.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,oBAAY,6BAA6B;IACvC,YAAY,kBAAkB;IAC9B,wBAAwB,+BAA+B;IACvD,QAAQ,aAAa;CACtB"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyNTS_ArtifactRetryClass_Type = void 0;
4
+ /** Stable remediation classification for artifact compiler findings. */
5
+ var DyNTS_ArtifactRetryClass_Type;
6
+ (function (DyNTS_ArtifactRetryClass_Type) {
7
+ DyNTS_ArtifactRetryClass_Type["agentFixable"] = "agent-fixable";
8
+ DyNTS_ArtifactRetryClass_Type["deterministicToolFixable"] = "deterministic-tool-fixable";
9
+ DyNTS_ArtifactRetryClass_Type["terminal"] = "terminal";
10
+ })(DyNTS_ArtifactRetryClass_Type || (exports.DyNTS_ArtifactRetryClass_Type = DyNTS_ArtifactRetryClass_Type = {}));
11
+ //# sourceMappingURL=artifact-retry-class.type-enum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-retry-class.type-enum.js","sourceRoot":"","sources":["../../../../src/_modules/artifact-compiler/_enums/artifact-retry-class.type-enum.ts"],"names":[],"mappings":";;;AAAA,wEAAwE;AACxE,IAAY,6BAIX;AAJD,WAAY,6BAA6B;IACvC,+DAA8B,CAAA;IAC9B,wFAAuD,CAAA;IACvD,sDAAqB,CAAA;AACvB,CAAC,EAJW,6BAA6B,6CAA7B,6BAA6B,QAIxC"}
@@ -0,0 +1,33 @@
1
+ import { DyNTS_ArtifactCompileOutcome_Type } from '../_enums/artifact-compile-outcome.type-enum';
2
+ import { DyNTS_ArtifactCompileStage_Type } from '../_enums/artifact-compile-stage.type-enum';
3
+ import { DyNTS_ArtifactRetryClass_Type } from '../_enums/artifact-retry-class.type-enum';
4
+ /** Versioned input for the deterministic TypeScript-to-browser bundle compiler. */
5
+ export interface DyNTS_ArtifactCompileRequest_Interface {
6
+ contractVersion: 'dynts-artifact-compiler/1';
7
+ source: string;
8
+ sourceFileName: string;
9
+ resolveDirectory: string;
10
+ allowedPackages: string[];
11
+ maxSourceBytes: number;
12
+ maxOutputBytes: number;
13
+ }
14
+ /** Content-free compiler finding. Source text and dependency paths are deliberately excluded. */
15
+ export interface DyNTS_ArtifactCompileFinding_Interface {
16
+ code: string;
17
+ stage: DyNTS_ArtifactCompileStage_Type;
18
+ line: number | null;
19
+ column: number | null;
20
+ retryClass: DyNTS_ArtifactRetryClass_Type;
21
+ }
22
+ /** One self-contained JavaScript output or a fail-closed, content-free rejection. */
23
+ export interface DyNTS_ArtifactCompileResult_Interface {
24
+ contractVersion: 'dynts-artifact-compiler/1';
25
+ outcome: DyNTS_ArtifactCompileOutcome_Type;
26
+ code: string;
27
+ sourceChecksum: string;
28
+ bundleChecksum: string;
29
+ outputBytes: number;
30
+ bundleSource: string | null;
31
+ findings: DyNTS_ArtifactCompileFinding_Interface[];
32
+ }
33
+ //# sourceMappingURL=artifact-compile.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-compile.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/artifact-compiler/_models/artifact-compile.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iCAAiC,EAAE,MAAM,8CAA8C,CAAC;AACjG,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AAEzF,mFAAmF;AACnF,MAAM,WAAW,sCAAsC;IACrD,eAAe,EAAE,2BAA2B,CAAC;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,iGAAiG;AACjG,MAAM,WAAW,sCAAsC;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,+BAA+B,CAAC;IACvC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,6BAA6B,CAAC;CAC3C;AAED,qFAAqF;AACrF,MAAM,WAAW,qCAAqC;IACpD,eAAe,EAAE,2BAA2B,CAAC;IAC7C,OAAO,EAAE,iCAAiC,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,sCAAsC,EAAE,CAAC;CACpD"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=artifact-compile.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-compile.interface.js","sourceRoot":"","sources":["../../../../src/_modules/artifact-compiler/_models/artifact-compile.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import { DyNTS_ArtifactCompileRequest_Interface, DyNTS_ArtifactCompileResult_Interface } from './_models/artifact-compile.interface';
2
+ /**
3
+ * Deterministically bundles one in-memory TypeScript program for a classic browser Worker.
4
+ * This compiler is not a sandbox: consumers must validate source policy before compilation and execute the result
5
+ * inside a separately enforced runtime boundary.
6
+ */
7
+ export declare class DyNTS_ArtifactCompiler_ControlService {
8
+ static readonly contractVersion: 'dynts-artifact-compiler/1';
9
+ private readonly absoluteMaxSourceBytes;
10
+ private readonly absoluteMaxOutputBytes;
11
+ private readonly absoluteMaxAllowedPackages;
12
+ private readonly absoluteMaxPackageNameLength;
13
+ private readonly absoluteMaxSourceFileNameLength;
14
+ private readonly absoluteMaxResolveDirectoryLength;
15
+ private readonly packageNamePattern;
16
+ private readonly sourceFileNamePattern;
17
+ /** Compiles without writing source, sourcemaps, metadata or output files to disk. */
18
+ compile(request: DyNTS_ArtifactCompileRequest_Interface): Promise<DyNTS_ArtifactCompileResult_Interface>;
19
+ private validateRequest;
20
+ private buildOptions;
21
+ /**
22
+ * Validates every syntactic import before esbuild can tree-shake it. The plugin below is a second resolution gate,
23
+ * but it cannot be the only policy boundary because unused imports need not reach package resolution.
24
+ */
25
+ private validateDirectImports;
26
+ private moduleName;
27
+ private isDynamicModuleLoad;
28
+ private importFinding;
29
+ private allowlistedEntryPlugin;
30
+ private buildFindings;
31
+ private isBuildFailure;
32
+ private genericBuildFinding;
33
+ private rejected;
34
+ private packageRoot;
35
+ private checksum;
36
+ }
37
+ //# sourceMappingURL=artifact-compiler.control-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-compiler.control-service.d.ts","sourceRoot":"","sources":["../../../src/_modules/artifact-compiler/artifact-compiler.control-service.ts"],"names":[],"mappings":"AAqBA,OAAO,EAEL,sCAAsC,EACtC,qCAAqC,EACtC,MAAM,sCAAsC,CAAC;AAE9C;;;;GAIG;AACH,qBAAa,qCAAqC;IAChD,gBAAuB,eAAe,EAAE,2BAA2B,CAA+B;IAClG,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAqB;IAC5D,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAsB;IAC7D,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAc;IACzD,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAe;IAC5D,OAAO,CAAC,QAAQ,CAAC,+BAA+B,CAAe;IAC/D,OAAO,CAAC,QAAQ,CAAC,iCAAiC,CAAiB;IACnE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CACwC;IAC3E,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAwC;IAE9E,qFAAqF;IACxE,OAAO,CAClB,OAAO,EAAE,sCAAsC,GAC9C,OAAO,CAAC,qCAAqC,CAAC;IAwDjD,OAAO,CAAC,eAAe;IA2CvB,OAAO,CAAC,YAAY;IAuBpB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAyC7B,OAAO,CAAC,UAAU;IAgBlB,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,sBAAsB;IAmC9B,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,QAAQ;IAiBhB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,QAAQ;CAGjB"}
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyNTS_ArtifactCompiler_ControlService = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const node_crypto_1 = require("node:crypto");
6
+ const node_path_1 = tslib_1.__importDefault(require("node:path"));
7
+ const esbuild_1 = require("esbuild");
8
+ const typescript_1 = tslib_1.__importDefault(require("typescript"));
9
+ const artifact_compile_outcome_type_enum_1 = require("./_enums/artifact-compile-outcome.type-enum");
10
+ const artifact_compile_stage_type_enum_1 = require("./_enums/artifact-compile-stage.type-enum");
11
+ const artifact_retry_class_type_enum_1 = require("./_enums/artifact-retry-class.type-enum");
12
+ /**
13
+ * Deterministically bundles one in-memory TypeScript program for a classic browser Worker.
14
+ * This compiler is not a sandbox: consumers must validate source policy before compilation and execute the result
15
+ * inside a separately enforced runtime boundary.
16
+ */
17
+ class DyNTS_ArtifactCompiler_ControlService {
18
+ static contractVersion = 'dynts-artifact-compiler/1';
19
+ absoluteMaxSourceBytes = 1_048_576;
20
+ absoluteMaxOutputBytes = 16_777_216;
21
+ absoluteMaxAllowedPackages = 64;
22
+ absoluteMaxPackageNameLength = 128;
23
+ absoluteMaxSourceFileNameLength = 128;
24
+ absoluteMaxResolveDirectoryLength = 1_024;
25
+ packageNamePattern = /^(?:@[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*|[a-z0-9][a-z0-9._-]*)$/;
26
+ sourceFileNamePattern = /^[a-z0-9][a-z0-9._-]*\.ts$/;
27
+ /** Compiles without writing source, sourcemaps, metadata or output files to disk. */
28
+ async compile(request) {
29
+ const sourceChecksum = this.checksum(typeof request?.source === 'string' ? request.source : '');
30
+ const requestFinding = this.validateRequest(request);
31
+ if (requestFinding) {
32
+ return this.rejected(sourceChecksum, 'DYNTS|ARTIFACT_COMPILER|REQUEST_INVALID', [requestFinding]);
33
+ }
34
+ const importFinding = this.validateDirectImports(request);
35
+ if (importFinding) {
36
+ return this.rejected(sourceChecksum, 'DYNTS|ARTIFACT_COMPILER|IMPORT_REJECTED', [importFinding]);
37
+ }
38
+ try {
39
+ const result = await (0, esbuild_1.build)(this.buildOptions(request));
40
+ const outputFiles = result.outputFiles ?? [];
41
+ if (outputFiles.length !== 1 || !outputFiles[0].path.endsWith('.js')) {
42
+ return this.rejected(sourceChecksum, 'DYNTS|ARTIFACT_COMPILER|OUTPUT_INVALID', [{
43
+ code: 'DYNTS|ARTIFACT_COMPILER|OUTPUT_COUNT',
44
+ stage: artifact_compile_stage_type_enum_1.DyNTS_ArtifactCompileStage_Type.output,
45
+ line: null,
46
+ column: null,
47
+ retryClass: artifact_retry_class_type_enum_1.DyNTS_ArtifactRetryClass_Type.deterministicToolFixable,
48
+ }]);
49
+ }
50
+ const bundleSource = outputFiles[0].text;
51
+ const outputBytes = Buffer.byteLength(bundleSource, 'utf8');
52
+ if (!outputBytes || outputBytes > request.maxOutputBytes) {
53
+ return this.rejected(sourceChecksum, 'DYNTS|ARTIFACT_COMPILER|OUTPUT_LIMIT', [{
54
+ code: 'DYNTS|ARTIFACT_COMPILER|OUTPUT_SIZE',
55
+ stage: artifact_compile_stage_type_enum_1.DyNTS_ArtifactCompileStage_Type.output,
56
+ line: null,
57
+ column: null,
58
+ retryClass: artifact_retry_class_type_enum_1.DyNTS_ArtifactRetryClass_Type.agentFixable,
59
+ }]);
60
+ }
61
+ return {
62
+ contractVersion: DyNTS_ArtifactCompiler_ControlService.contractVersion,
63
+ outcome: artifact_compile_outcome_type_enum_1.DyNTS_ArtifactCompileOutcome_Type.compiled,
64
+ code: 'DYNTS|ARTIFACT_COMPILER|COMPILED',
65
+ sourceChecksum: sourceChecksum,
66
+ bundleChecksum: this.checksum(bundleSource),
67
+ outputBytes: outputBytes,
68
+ bundleSource: bundleSource,
69
+ findings: [],
70
+ };
71
+ }
72
+ catch (error) {
73
+ return this.rejected(sourceChecksum, 'DYNTS|ARTIFACT_COMPILER|BUILD_FAILED', this.buildFindings(error));
74
+ }
75
+ }
76
+ validateRequest(request) {
77
+ const sourceBytes = typeof request?.source === 'string'
78
+ ? Buffer.byteLength(request.source, 'utf8')
79
+ : 0;
80
+ const allowedPackages = Array.isArray(request?.allowedPackages) ? request.allowedPackages : [];
81
+ const uniquePackages = new Set(allowedPackages);
82
+ const isPackageSetValid = allowedPackages.length <= this.absoluteMaxAllowedPackages
83
+ && uniquePackages.size === allowedPackages.length
84
+ && allowedPackages.every((packageName) => packageName.length <= this.absoluteMaxPackageNameLength
85
+ && this.packageNamePattern.test(packageName));
86
+ if (request?.contractVersion !== DyNTS_ArtifactCompiler_ControlService.contractVersion
87
+ || !sourceBytes
88
+ || !Number.isInteger(request.maxSourceBytes)
89
+ || request.maxSourceBytes < 1
90
+ || request.maxSourceBytes > this.absoluteMaxSourceBytes
91
+ || sourceBytes > request.maxSourceBytes
92
+ || !Number.isInteger(request.maxOutputBytes)
93
+ || request.maxOutputBytes < 1
94
+ || request.maxOutputBytes > this.absoluteMaxOutputBytes
95
+ || typeof request.sourceFileName !== 'string'
96
+ || request.sourceFileName.length > this.absoluteMaxSourceFileNameLength
97
+ || !this.sourceFileNamePattern.test(request.sourceFileName)
98
+ || typeof request.resolveDirectory !== 'string'
99
+ || request.resolveDirectory.length > this.absoluteMaxResolveDirectoryLength
100
+ || !node_path_1.default.isAbsolute(request.resolveDirectory)
101
+ || !isPackageSetValid) {
102
+ return {
103
+ code: 'DYNTS|ARTIFACT_COMPILER|REQUEST_CONTRACT',
104
+ stage: artifact_compile_stage_type_enum_1.DyNTS_ArtifactCompileStage_Type.request,
105
+ line: null,
106
+ column: null,
107
+ retryClass: artifact_retry_class_type_enum_1.DyNTS_ArtifactRetryClass_Type.deterministicToolFixable,
108
+ };
109
+ }
110
+ return null;
111
+ }
112
+ buildOptions(request) {
113
+ return {
114
+ absWorkingDir: request.resolveDirectory,
115
+ bundle: true,
116
+ charset: 'utf8',
117
+ conditions: ['browser', 'default'],
118
+ entryPoints: ['dynts-entry:candidate'],
119
+ format: 'iife',
120
+ legalComments: 'none',
121
+ logLevel: 'silent',
122
+ mainFields: ['browser', 'module', 'main'],
123
+ metafile: false,
124
+ minify: true,
125
+ outdir: 'dynts-in-memory-output',
126
+ platform: 'browser',
127
+ plugins: [this.allowlistedEntryPlugin(request)],
128
+ sourcemap: false,
129
+ target: ['es2022'],
130
+ treeShaking: true,
131
+ write: false,
132
+ };
133
+ }
134
+ /**
135
+ * Validates every syntactic import before esbuild can tree-shake it. The plugin below is a second resolution gate,
136
+ * but it cannot be the only policy boundary because unused imports need not reach package resolution.
137
+ */
138
+ validateDirectImports(request) {
139
+ const sourceFile = typescript_1.default.createSourceFile(request.sourceFileName, request.source, typescript_1.default.ScriptTarget.ES2022, true, typescript_1.default.ScriptKind.TS);
140
+ const allowedPackages = new Set(request.allowedPackages);
141
+ let finding = null;
142
+ /** Traverses the parsed source once and stops at the first forbidden module load. */
143
+ const inspectNode = (node) => {
144
+ if (finding) {
145
+ return;
146
+ }
147
+ const moduleName = this.moduleName(node);
148
+ if (moduleName !== null && !allowedPackages.has(this.packageRoot(moduleName))) {
149
+ finding = this.importFinding(sourceFile, node);
150
+ return;
151
+ }
152
+ if (this.isDynamicModuleLoad(node)) {
153
+ finding = this.importFinding(sourceFile, node);
154
+ return;
155
+ }
156
+ typescript_1.default.forEachChild(node, inspectNode);
157
+ };
158
+ inspectNode(sourceFile);
159
+ return finding;
160
+ }
161
+ moduleName(node) {
162
+ if ((typescript_1.default.isImportDeclaration(node) || typescript_1.default.isExportDeclaration(node)) && node.moduleSpecifier) {
163
+ return typescript_1.default.isStringLiteral(node.moduleSpecifier) ? node.moduleSpecifier.text : '';
164
+ }
165
+ if (typescript_1.default.isImportEqualsDeclaration(node)
166
+ && typescript_1.default.isExternalModuleReference(node.moduleReference)
167
+ && node.moduleReference.expression) {
168
+ return typescript_1.default.isStringLiteral(node.moduleReference.expression) ? node.moduleReference.expression.text : '';
169
+ }
170
+ return null;
171
+ }
172
+ isDynamicModuleLoad(node) {
173
+ return typescript_1.default.isCallExpression(node)
174
+ && (node.expression.kind === typescript_1.default.SyntaxKind.ImportKeyword
175
+ || (typescript_1.default.isIdentifier(node.expression) && node.expression.text === 'require'));
176
+ }
177
+ importFinding(sourceFile, node) {
178
+ const location = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
179
+ return {
180
+ code: 'DYNTS|ARTIFACT_COMPILER|IMPORT_NOT_ALLOWED',
181
+ stage: artifact_compile_stage_type_enum_1.DyNTS_ArtifactCompileStage_Type.sourcePolicy,
182
+ line: location.line + 1,
183
+ column: location.character + 1,
184
+ retryClass: artifact_retry_class_type_enum_1.DyNTS_ArtifactRetryClass_Type.terminal,
185
+ };
186
+ }
187
+ allowlistedEntryPlugin(request) {
188
+ const allowedPackages = new Set(request.allowedPackages);
189
+ return {
190
+ name: 'dynts-allowlisted-in-memory-entry',
191
+ setup: (pluginBuild) => {
192
+ pluginBuild.onResolve({ filter: /^dynts-entry:candidate$/ }, () => ({
193
+ path: 'candidate',
194
+ namespace: 'dynts-entry',
195
+ }));
196
+ pluginBuild.onLoad({ filter: /^candidate$/, namespace: 'dynts-entry' }, () => ({
197
+ contents: request.source,
198
+ loader: 'ts',
199
+ resolveDir: request.resolveDirectory,
200
+ }));
201
+ pluginBuild.onResolve({ filter: /.*/, namespace: 'dynts-entry' }, async (args) => {
202
+ if (!allowedPackages.has(this.packageRoot(args.path))) {
203
+ return {
204
+ errors: [{ text: 'DYNTS|ARTIFACT_COMPILER|IMPORT_NOT_ALLOWED' }],
205
+ };
206
+ }
207
+ return pluginBuild.resolve(args.path, {
208
+ importer: args.importer,
209
+ kind: args.kind,
210
+ namespace: 'file',
211
+ resolveDir: request.resolveDirectory,
212
+ });
213
+ });
214
+ },
215
+ };
216
+ }
217
+ buildFindings(error) {
218
+ if (!this.isBuildFailure(error)) {
219
+ return [this.genericBuildFinding()];
220
+ }
221
+ const findings = error.errors.map((message) => ({
222
+ code: message.text === 'DYNTS|ARTIFACT_COMPILER|IMPORT_NOT_ALLOWED'
223
+ ? message.text
224
+ : 'DYNTS|ARTIFACT_COMPILER|COMPILE_ERROR',
225
+ stage: message.text === 'DYNTS|ARTIFACT_COMPILER|IMPORT_NOT_ALLOWED'
226
+ ? artifact_compile_stage_type_enum_1.DyNTS_ArtifactCompileStage_Type.resolve
227
+ : artifact_compile_stage_type_enum_1.DyNTS_ArtifactCompileStage_Type.compile,
228
+ line: message.location?.line ?? null,
229
+ column: message.location ? message.location.column + 1 : null,
230
+ retryClass: message.text === 'DYNTS|ARTIFACT_COMPILER|IMPORT_NOT_ALLOWED'
231
+ ? artifact_retry_class_type_enum_1.DyNTS_ArtifactRetryClass_Type.terminal
232
+ : artifact_retry_class_type_enum_1.DyNTS_ArtifactRetryClass_Type.agentFixable,
233
+ }));
234
+ return findings.length ? findings : [this.genericBuildFinding()];
235
+ }
236
+ isBuildFailure(error) {
237
+ if (!error || typeof error !== 'object') {
238
+ return false;
239
+ }
240
+ return 'errors' in error && Array.isArray(error.errors);
241
+ }
242
+ genericBuildFinding() {
243
+ return {
244
+ code: 'DYNTS|ARTIFACT_COMPILER|COMPILE_ERROR',
245
+ stage: artifact_compile_stage_type_enum_1.DyNTS_ArtifactCompileStage_Type.compile,
246
+ line: null,
247
+ column: null,
248
+ retryClass: artifact_retry_class_type_enum_1.DyNTS_ArtifactRetryClass_Type.agentFixable,
249
+ };
250
+ }
251
+ rejected(sourceChecksum, code, findings) {
252
+ return {
253
+ contractVersion: DyNTS_ArtifactCompiler_ControlService.contractVersion,
254
+ outcome: artifact_compile_outcome_type_enum_1.DyNTS_ArtifactCompileOutcome_Type.rejected,
255
+ code: code,
256
+ sourceChecksum: sourceChecksum,
257
+ bundleChecksum: '',
258
+ outputBytes: 0,
259
+ bundleSource: null,
260
+ findings: findings,
261
+ };
262
+ }
263
+ packageRoot(moduleName) {
264
+ if (moduleName.startsWith('@')) {
265
+ return moduleName.split('/').slice(0, 2).join('/');
266
+ }
267
+ return moduleName.split('/')[0];
268
+ }
269
+ checksum(value) {
270
+ return (0, node_crypto_1.createHash)('sha256').update(value, 'utf8').digest('hex');
271
+ }
272
+ }
273
+ exports.DyNTS_ArtifactCompiler_ControlService = DyNTS_ArtifactCompiler_ControlService;
274
+ //# sourceMappingURL=artifact-compiler.control-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-compiler.control-service.js","sourceRoot":"","sources":["../../../src/_modules/artifact-compiler/artifact-compiler.control-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { DyNTS_ArtifactCompiler_ControlService } from './artifact-compiler.control-service';
2
+ export { DyNTS_ArtifactCompileOutcome_Type } from './_enums/artifact-compile-outcome.type-enum';
3
+ export { DyNTS_ArtifactCompileStage_Type } from './_enums/artifact-compile-stage.type-enum';
4
+ export { DyNTS_ArtifactRetryClass_Type } from './_enums/artifact-retry-class.type-enum';
5
+ export { DyNTS_ArtifactCompileFinding_Interface, DyNTS_ArtifactCompileRequest_Interface, DyNTS_ArtifactCompileResult_Interface } from './_models/artifact-compile.interface';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/_modules/artifact-compiler/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qCAAqC,EAAE,MAAM,qCAAqC,CAAC;AAC5F,OAAO,EAAE,iCAAiC,EAAE,MAAM,6CAA6C,CAAC;AAChG,OAAO,EAAE,+BAA+B,EAAE,MAAM,2CAA2C,CAAC;AAC5F,OAAO,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AACxF,OAAO,EACL,sCAAsC,EACtC,sCAAsC,EACtC,qCAAqC,EACtC,MAAM,sCAAsC,CAAC"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyNTS_ArtifactRetryClass_Type = exports.DyNTS_ArtifactCompileStage_Type = exports.DyNTS_ArtifactCompileOutcome_Type = exports.DyNTS_ArtifactCompiler_ControlService = void 0;
4
+ var artifact_compiler_control_service_1 = require("./artifact-compiler.control-service");
5
+ Object.defineProperty(exports, "DyNTS_ArtifactCompiler_ControlService", { enumerable: true, get: function () { return artifact_compiler_control_service_1.DyNTS_ArtifactCompiler_ControlService; } });
6
+ var artifact_compile_outcome_type_enum_1 = require("./_enums/artifact-compile-outcome.type-enum");
7
+ Object.defineProperty(exports, "DyNTS_ArtifactCompileOutcome_Type", { enumerable: true, get: function () { return artifact_compile_outcome_type_enum_1.DyNTS_ArtifactCompileOutcome_Type; } });
8
+ var artifact_compile_stage_type_enum_1 = require("./_enums/artifact-compile-stage.type-enum");
9
+ Object.defineProperty(exports, "DyNTS_ArtifactCompileStage_Type", { enumerable: true, get: function () { return artifact_compile_stage_type_enum_1.DyNTS_ArtifactCompileStage_Type; } });
10
+ var artifact_retry_class_type_enum_1 = require("./_enums/artifact-retry-class.type-enum");
11
+ Object.defineProperty(exports, "DyNTS_ArtifactRetryClass_Type", { enumerable: true, get: function () { return artifact_retry_class_type_enum_1.DyNTS_ArtifactRetryClass_Type; } });
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/_modules/artifact-compiler/index.ts"],"names":[],"mappings":";;;AAAA,yFAA4F;AAAnF,0JAAA,qCAAqC,OAAA;AAC9C,kGAAgG;AAAvF,uJAAA,iCAAiC,OAAA;AAC1C,8FAA4F;AAAnF,mJAAA,+BAA+B,OAAA;AACxC,0FAAwF;AAA/E,+IAAA,6BAA6B,OAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@futdevpro/nts-dynamo",
3
- "version": "01.15.142",
3
+ "version": "01.15.144",
4
4
  "description": "Dynamic NodeTS (NodeJS-Typescript), MongoDB Backend System Framework by Future Development Program Ltd.",
5
5
  "DyBu_settings": {
6
6
  "packageType": "server-package",
@@ -224,6 +224,12 @@
224
224
  "types": "./build/_modules/privacy-lifecycle/index.d.ts",
225
225
  "typings": "./build/_modules/privacy-lifecycle/index.d.ts"
226
226
  },
227
+ "./artifact-compiler": {
228
+ "default": "./build/_modules/artifact-compiler/index.js",
229
+ "module": "./build/_modules/artifact-compiler/index.js",
230
+ "types": "./build/_modules/artifact-compiler/index.d.ts",
231
+ "typings": "./build/_modules/artifact-compiler/index.d.ts"
232
+ },
227
233
  "./oauth2": {
228
234
  "default": "./build/_modules/oauth2/index.js",
229
235
  "module": "./build/_modules/oauth2/index.js",
@@ -356,6 +362,9 @@
356
362
  "privacy-lifecycle": [
357
363
  "build/_modules/privacy-lifecycle/index.d.ts"
358
364
  ],
365
+ "artifact-compiler": [
366
+ "build/_modules/artifact-compiler/index.d.ts"
367
+ ],
359
368
  "oauth2": [
360
369
  "build/_modules/oauth2/index.d.ts"
361
370
  ],
@@ -392,6 +401,10 @@
392
401
  "@futdevpro/fsm-dynamo": "file:../tgz-collection/dynamo-fsm/futdevpro-fsm-dynamo-01.15.8.tgz",
393
402
  "empty": ""
394
403
  },
404
+ "dependencies": {
405
+ "esbuild": "0.28.2",
406
+ "typescript": "5.5.4"
407
+ },
395
408
  "peerDependencies": {
396
409
  "@anthropic-ai/sdk": "~0.39.0",
397
410
  "@modelcontextprotocol/sdk": "~1.29.0",
@@ -441,6 +454,7 @@
441
454
  "@types/better-sqlite3": "~7.6.13",
442
455
  "better-sqlite3": "~12.4.1",
443
456
  "crypto-js": "~4.2.0",
457
+ "decimal.js": "10.6.0",
444
458
  "discord.js": "~14.24.2",
445
459
  "eslint": "^9.34.0",
446
460
  "eslint-plugin-import": "^2.29.0",
@@ -456,7 +470,6 @@
456
470
  "socket.io": "~4.8.1",
457
471
  "socket.io-client": "~4.8.1",
458
472
  "tslib": "~2.6.2",
459
- "typescript": "~5.5.4",
460
473
  "husky": "^9.1.7"
461
474
  }
462
475
  }
@@ -1,5 +1,6 @@
1
- allowBuilds:
2
- '@discordjs/opus': false
3
- better-sqlite3: true
1
+ allowBuilds:
2
+ '@discordjs/opus': false
3
+ better-sqlite3: true
4
+ esbuild: true
4
5
  minimumReleaseAgeExclude:
5
6
  - '@futdevpro/*'
@@ -0,0 +1,5 @@
1
+ /** Terminal result of one deterministic in-memory artifact compilation. */
2
+ export enum DyNTS_ArtifactCompileOutcome_Type {
3
+ compiled = 'compiled',
4
+ rejected = 'rejected',
5
+ }
@@ -0,0 +1,8 @@
1
+ /** Content-free stage identifiers for artifact compiler findings. */
2
+ export enum DyNTS_ArtifactCompileStage_Type {
3
+ request = 'request',
4
+ sourcePolicy = 'source-policy',
5
+ resolve = 'resolve',
6
+ compile = 'compile',
7
+ output = 'output',
8
+ }
@@ -0,0 +1,6 @@
1
+ /** Stable remediation classification for artifact compiler findings. */
2
+ export enum DyNTS_ArtifactRetryClass_Type {
3
+ agentFixable = 'agent-fixable',
4
+ deterministicToolFixable = 'deterministic-tool-fixable',
5
+ terminal = 'terminal',
6
+ }
@@ -0,0 +1,35 @@
1
+ import { DyNTS_ArtifactCompileOutcome_Type } from '../_enums/artifact-compile-outcome.type-enum';
2
+ import { DyNTS_ArtifactCompileStage_Type } from '../_enums/artifact-compile-stage.type-enum';
3
+ import { DyNTS_ArtifactRetryClass_Type } from '../_enums/artifact-retry-class.type-enum';
4
+
5
+ /** Versioned input for the deterministic TypeScript-to-browser bundle compiler. */
6
+ export interface DyNTS_ArtifactCompileRequest_Interface {
7
+ contractVersion: 'dynts-artifact-compiler/1';
8
+ source: string;
9
+ sourceFileName: string;
10
+ resolveDirectory: string;
11
+ allowedPackages: string[];
12
+ maxSourceBytes: number;
13
+ maxOutputBytes: number;
14
+ }
15
+
16
+ /** Content-free compiler finding. Source text and dependency paths are deliberately excluded. */
17
+ export interface DyNTS_ArtifactCompileFinding_Interface {
18
+ code: string;
19
+ stage: DyNTS_ArtifactCompileStage_Type;
20
+ line: number | null;
21
+ column: number | null;
22
+ retryClass: DyNTS_ArtifactRetryClass_Type;
23
+ }
24
+
25
+ /** One self-contained JavaScript output or a fail-closed, content-free rejection. */
26
+ export interface DyNTS_ArtifactCompileResult_Interface {
27
+ contractVersion: 'dynts-artifact-compiler/1';
28
+ outcome: DyNTS_ArtifactCompileOutcome_Type;
29
+ code: string;
30
+ sourceChecksum: string;
31
+ bundleChecksum: string;
32
+ outputBytes: number;
33
+ bundleSource: string | null;
34
+ findings: DyNTS_ArtifactCompileFinding_Interface[];
35
+ }
@@ -0,0 +1,151 @@
1
+ import path from 'node:path';
2
+
3
+ import { DyNTS_ArtifactCompileOutcome_Type } from './_enums/artifact-compile-outcome.type-enum';
4
+ import {
5
+ DyNTS_ArtifactCompileRequest_Interface,
6
+ DyNTS_ArtifactCompileResult_Interface
7
+ } from './_models/artifact-compile.interface';
8
+ import { DyNTS_ArtifactCompiler_ControlService } from './artifact-compiler.control-service';
9
+
10
+ describe('| DyNTS_ArtifactCompiler_ControlService', (): void => {
11
+ const compiler_CS: DyNTS_ArtifactCompiler_ControlService = new DyNTS_ArtifactCompiler_ControlService();
12
+
13
+ it('| emits one deterministic self-contained classic-worker bundle without filesystem output', async (
14
+ ): Promise<void> => {
15
+ const request: DyNTS_ArtifactCompileRequest_Interface = buildRequest(workerSource());
16
+ const first: DyNTS_ArtifactCompileResult_Interface = await compiler_CS.compile(request);
17
+ const second: DyNTS_ArtifactCompileResult_Interface = await compiler_CS.compile(request);
18
+
19
+ expect(first.outcome).toBe(DyNTS_ArtifactCompileOutcome_Type.compiled);
20
+ expect(first.bundleSource).toContain('self.onmessage');
21
+ expect(first.bundleSource).not.toContain('sourceMappingURL');
22
+ expect(first.bundleSource).not.toContain('dynts-in-memory-output');
23
+ expect(first.bundleChecksum).toMatch(/^[a-f0-9]{64}$/);
24
+ expect(first.outputBytes).toBeGreaterThan(0);
25
+ expect(second).toEqual(first);
26
+ });
27
+
28
+ it('| bundles an explicitly allowed installed package into the output', async (): Promise<void> => {
29
+ const source: string = `import Decimal from 'decimal.js';
30
+ self.onmessage = (): void => {
31
+ const value: string = new Decimal(1).plus(2).toString();
32
+ const output: ArrayBuffer = new TextEncoder().encode(value).buffer;
33
+ self.postMessage({ type: 'complete', output: output }, [ output ]);
34
+ };`;
35
+ const request: DyNTS_ArtifactCompileRequest_Interface = buildRequest(source);
36
+
37
+ request.allowedPackages = [ 'decimal.js' ];
38
+
39
+ const result: DyNTS_ArtifactCompileResult_Interface = await compiler_CS.compile(request);
40
+
41
+ expect(result.outcome).toBe(DyNTS_ArtifactCompileOutcome_Type.compiled);
42
+ expect(result.bundleSource).not.toContain('from\'decimal.js\'');
43
+ expect(result.outputBytes).toBeGreaterThan(1_000);
44
+ });
45
+
46
+ it('| rejects non-allowlisted direct imports without reflecting the source canary', async (): Promise<void> => {
47
+ const canary: string = 'SOURCE-CANARY-MUST-NOT-RETURN';
48
+ const request: DyNTS_ArtifactCompileRequest_Interface = buildRequest(
49
+ `import fs from 'node:fs';\nconst secret = '${canary}';\n${workerSource()}`
50
+ );
51
+ const result: DyNTS_ArtifactCompileResult_Interface = await compiler_CS.compile(request);
52
+
53
+ expect(result.outcome).toBe(DyNTS_ArtifactCompileOutcome_Type.rejected);
54
+ expect(result.findings[0].code).toBe('DYNTS|ARTIFACT_COMPILER|IMPORT_NOT_ALLOWED');
55
+ expect(JSON.stringify(result)).not.toContain(canary);
56
+ expect(result.bundleSource).toBeNull();
57
+ });
58
+
59
+ it('| rejects re-exports, import-equals, require and dynamic import syntax before bundling', async (
60
+ ): Promise<void> => {
61
+ const sources: string[] = [
62
+ 'export { readFile } from \'node:fs\';',
63
+ 'import fs = require(\'node:fs\');',
64
+ 'const fs = require(\'node:fs\');',
65
+ 'void import(\'decimal.js\');',
66
+ ];
67
+
68
+ for (const source of sources) {
69
+ const result: DyNTS_ArtifactCompileResult_Interface = await compiler_CS.compile(buildRequest(source));
70
+
71
+ expect(result.code).toBe('DYNTS|ARTIFACT_COMPILER|IMPORT_REJECTED');
72
+ expect(result.findings[0].stage).toBe('source-policy');
73
+ }
74
+ });
75
+
76
+ it('| returns content-free compile diagnostics for invalid TypeScript', async (): Promise<void> => {
77
+ const canary: string = 'INVALID-CANARY-MUST-NOT-RETURN';
78
+ const result: DyNTS_ArtifactCompileResult_Interface = await compiler_CS.compile(
79
+ buildRequest(`const ${canary}: = ;`)
80
+ );
81
+
82
+ expect(result.outcome).toBe(DyNTS_ArtifactCompileOutcome_Type.rejected);
83
+ expect(result.findings[0].code).toBe('DYNTS|ARTIFACT_COMPILER|COMPILE_ERROR');
84
+ expect(result.findings[0].line).toBe(1);
85
+ expect(JSON.stringify(result)).not.toContain(canary);
86
+ });
87
+
88
+ it('| rejects invalid contracts, duplicate packages and unsafe resolve inputs', async (): Promise<void> => {
89
+ const request: DyNTS_ArtifactCompileRequest_Interface = buildRequest(workerSource());
90
+
91
+ request.allowedPackages = [ 'decimal.js', 'decimal.js' ];
92
+ request.resolveDirectory = 'relative/path';
93
+ request.maxOutputBytes = 20_000_000;
94
+
95
+ const result: DyNTS_ArtifactCompileResult_Interface = await compiler_CS.compile(request);
96
+
97
+ expect(result.code).toBe('DYNTS|ARTIFACT_COMPILER|REQUEST_INVALID');
98
+ expect(result.findings[0].stage).toBe('request');
99
+ });
100
+
101
+ it('| bounds allowlist cardinality and request path lengths', async (): Promise<void> => {
102
+ const packageLimited: DyNTS_ArtifactCompileRequest_Interface = buildRequest(workerSource());
103
+ const pathLimited: DyNTS_ArtifactCompileRequest_Interface = buildRequest(workerSource());
104
+
105
+ packageLimited.allowedPackages = Array.from({ length: 65 }, (_value: unknown, index: number): string =>
106
+ `package-${index}`);
107
+ pathLimited.sourceFileName = `${'a'.repeat(128)}.ts`;
108
+
109
+ const packageResult: DyNTS_ArtifactCompileResult_Interface = await compiler_CS.compile(packageLimited);
110
+ const pathResult: DyNTS_ArtifactCompileResult_Interface = await compiler_CS.compile(pathLimited);
111
+
112
+ expect(packageResult.code).toBe('DYNTS|ARTIFACT_COMPILER|REQUEST_INVALID');
113
+ expect(pathResult.code).toBe('DYNTS|ARTIFACT_COMPILER|REQUEST_INVALID');
114
+ });
115
+
116
+ it('| enforces source and output byte budgets before returning bundle content', async (): Promise<void> => {
117
+ const sourceLimited: DyNTS_ArtifactCompileRequest_Interface = buildRequest(workerSource());
118
+ const outputLimited: DyNTS_ArtifactCompileRequest_Interface = buildRequest(workerSource());
119
+
120
+ sourceLimited.maxSourceBytes = 1;
121
+ outputLimited.maxOutputBytes = 1;
122
+
123
+ const sourceResult: DyNTS_ArtifactCompileResult_Interface = await compiler_CS.compile(sourceLimited);
124
+ const outputResult: DyNTS_ArtifactCompileResult_Interface = await compiler_CS.compile(outputLimited);
125
+
126
+ expect(sourceResult.code).toBe('DYNTS|ARTIFACT_COMPILER|REQUEST_INVALID');
127
+ expect(outputResult.code).toBe('DYNTS|ARTIFACT_COMPILER|OUTPUT_LIMIT');
128
+ expect(outputResult.bundleSource).toBeNull();
129
+ });
130
+
131
+ /** Builds a valid request resolved against this package's installed dependencies. */
132
+ function buildRequest(source: string): DyNTS_ArtifactCompileRequest_Interface {
133
+ return {
134
+ contractVersion: 'dynts-artifact-compiler/1',
135
+ source: source,
136
+ sourceFileName: 'candidate.ts',
137
+ resolveDirectory: path.resolve(process.cwd()),
138
+ allowedPackages: [],
139
+ maxSourceBytes: 512_000,
140
+ maxOutputBytes: 8_000_000,
141
+ };
142
+ }
143
+
144
+ /** Returns a minimal classic Worker contract. */
145
+ function workerSource(): string {
146
+ return `self.onmessage = (event: MessageEvent<{ input: ArrayBuffer }>): void => {
147
+ const output: ArrayBuffer = event.data.input;
148
+ self.postMessage({ type: 'complete', output: output }, [ output ]);
149
+ };`;
150
+ }
151
+ });
@@ -0,0 +1,356 @@
1
+ import { createHash } from 'node:crypto';
2
+ import path from 'node:path';
3
+
4
+ import {
5
+ BuildFailure,
6
+ BuildOptions,
7
+ BuildResult,
8
+ Message,
9
+ OnLoadResult,
10
+ OnResolveArgs,
11
+ OnResolveResult,
12
+ OutputFile,
13
+ Plugin,
14
+ PluginBuild,
15
+ build
16
+ } from 'esbuild';
17
+ import ts from 'typescript';
18
+
19
+ import { DyNTS_ArtifactCompileOutcome_Type } from './_enums/artifact-compile-outcome.type-enum';
20
+ import { DyNTS_ArtifactCompileStage_Type } from './_enums/artifact-compile-stage.type-enum';
21
+ import { DyNTS_ArtifactRetryClass_Type } from './_enums/artifact-retry-class.type-enum';
22
+ import {
23
+ DyNTS_ArtifactCompileFinding_Interface,
24
+ DyNTS_ArtifactCompileRequest_Interface,
25
+ DyNTS_ArtifactCompileResult_Interface
26
+ } from './_models/artifact-compile.interface';
27
+
28
+ /**
29
+ * Deterministically bundles one in-memory TypeScript program for a classic browser Worker.
30
+ * This compiler is not a sandbox: consumers must validate source policy before compilation and execute the result
31
+ * inside a separately enforced runtime boundary.
32
+ */
33
+ export class DyNTS_ArtifactCompiler_ControlService {
34
+ public static readonly contractVersion: 'dynts-artifact-compiler/1' = 'dynts-artifact-compiler/1';
35
+ private readonly absoluteMaxSourceBytes: number = 1_048_576;
36
+ private readonly absoluteMaxOutputBytes: number = 16_777_216;
37
+ private readonly absoluteMaxAllowedPackages: number = 64;
38
+ private readonly absoluteMaxPackageNameLength: number = 128;
39
+ private readonly absoluteMaxSourceFileNameLength: number = 128;
40
+ private readonly absoluteMaxResolveDirectoryLength: number = 1_024;
41
+ private readonly packageNamePattern: RegExp =
42
+ /^(?:@[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*|[a-z0-9][a-z0-9._-]*)$/;
43
+ private readonly sourceFileNamePattern: RegExp = /^[a-z0-9][a-z0-9._-]*\.ts$/;
44
+
45
+ /** Compiles without writing source, sourcemaps, metadata or output files to disk. */
46
+ public async compile(
47
+ request: DyNTS_ArtifactCompileRequest_Interface
48
+ ): Promise<DyNTS_ArtifactCompileResult_Interface> {
49
+ const sourceChecksum: string = this.checksum(typeof request?.source === 'string' ? request.source : '');
50
+ const requestFinding: DyNTS_ArtifactCompileFinding_Interface | null = this.validateRequest(request);
51
+
52
+ if (requestFinding) {
53
+ return this.rejected(sourceChecksum, 'DYNTS|ARTIFACT_COMPILER|REQUEST_INVALID', [ requestFinding ]);
54
+ }
55
+
56
+ const importFinding: DyNTS_ArtifactCompileFinding_Interface | null = this.validateDirectImports(request);
57
+
58
+ if (importFinding) {
59
+ return this.rejected(sourceChecksum, 'DYNTS|ARTIFACT_COMPILER|IMPORT_REJECTED', [ importFinding ]);
60
+ }
61
+
62
+ try {
63
+ const result: BuildResult = await build(this.buildOptions(request));
64
+ const outputFiles: OutputFile[] = result.outputFiles ?? [];
65
+
66
+ if (outputFiles.length !== 1 || !outputFiles[0].path.endsWith('.js')) {
67
+ return this.rejected(sourceChecksum, 'DYNTS|ARTIFACT_COMPILER|OUTPUT_INVALID', [{
68
+ code: 'DYNTS|ARTIFACT_COMPILER|OUTPUT_COUNT',
69
+ stage: DyNTS_ArtifactCompileStage_Type.output,
70
+ line: null,
71
+ column: null,
72
+ retryClass: DyNTS_ArtifactRetryClass_Type.deterministicToolFixable,
73
+ }]);
74
+ }
75
+
76
+ const bundleSource: string = outputFiles[0].text;
77
+ const outputBytes: number = Buffer.byteLength(bundleSource, 'utf8');
78
+
79
+ if (!outputBytes || outputBytes > request.maxOutputBytes) {
80
+ return this.rejected(sourceChecksum, 'DYNTS|ARTIFACT_COMPILER|OUTPUT_LIMIT', [{
81
+ code: 'DYNTS|ARTIFACT_COMPILER|OUTPUT_SIZE',
82
+ stage: DyNTS_ArtifactCompileStage_Type.output,
83
+ line: null,
84
+ column: null,
85
+ retryClass: DyNTS_ArtifactRetryClass_Type.agentFixable,
86
+ }]);
87
+ }
88
+
89
+ return {
90
+ contractVersion: DyNTS_ArtifactCompiler_ControlService.contractVersion,
91
+ outcome: DyNTS_ArtifactCompileOutcome_Type.compiled,
92
+ code: 'DYNTS|ARTIFACT_COMPILER|COMPILED',
93
+ sourceChecksum: sourceChecksum,
94
+ bundleChecksum: this.checksum(bundleSource),
95
+ outputBytes: outputBytes,
96
+ bundleSource: bundleSource,
97
+ findings: [],
98
+ };
99
+ } catch (error: unknown) {
100
+ return this.rejected(sourceChecksum, 'DYNTS|ARTIFACT_COMPILER|BUILD_FAILED', this.buildFindings(error));
101
+ }
102
+ }
103
+
104
+ private validateRequest(
105
+ request: DyNTS_ArtifactCompileRequest_Interface
106
+ ): DyNTS_ArtifactCompileFinding_Interface | null {
107
+ const sourceBytes: number = typeof request?.source === 'string'
108
+ ? Buffer.byteLength(request.source, 'utf8')
109
+ : 0;
110
+ const allowedPackages: string[] = Array.isArray(request?.allowedPackages) ? request.allowedPackages : [];
111
+ const uniquePackages: Set<string> = new Set<string>(allowedPackages);
112
+ const isPackageSetValid: boolean = allowedPackages.length <= this.absoluteMaxAllowedPackages
113
+ && uniquePackages.size === allowedPackages.length
114
+ && allowedPackages.every((packageName: string): boolean => packageName.length <= this.absoluteMaxPackageNameLength
115
+ && this.packageNamePattern.test(packageName));
116
+
117
+ if (
118
+ request?.contractVersion !== DyNTS_ArtifactCompiler_ControlService.contractVersion
119
+ || !sourceBytes
120
+ || !Number.isInteger(request.maxSourceBytes)
121
+ || request.maxSourceBytes < 1
122
+ || request.maxSourceBytes > this.absoluteMaxSourceBytes
123
+ || sourceBytes > request.maxSourceBytes
124
+ || !Number.isInteger(request.maxOutputBytes)
125
+ || request.maxOutputBytes < 1
126
+ || request.maxOutputBytes > this.absoluteMaxOutputBytes
127
+ || typeof request.sourceFileName !== 'string'
128
+ || request.sourceFileName.length > this.absoluteMaxSourceFileNameLength
129
+ || !this.sourceFileNamePattern.test(request.sourceFileName)
130
+ || typeof request.resolveDirectory !== 'string'
131
+ || request.resolveDirectory.length > this.absoluteMaxResolveDirectoryLength
132
+ || !path.isAbsolute(request.resolveDirectory)
133
+ || !isPackageSetValid
134
+ ) {
135
+ return {
136
+ code: 'DYNTS|ARTIFACT_COMPILER|REQUEST_CONTRACT',
137
+ stage: DyNTS_ArtifactCompileStage_Type.request,
138
+ line: null,
139
+ column: null,
140
+ retryClass: DyNTS_ArtifactRetryClass_Type.deterministicToolFixable,
141
+ };
142
+ }
143
+
144
+ return null;
145
+ }
146
+
147
+ private buildOptions(request: DyNTS_ArtifactCompileRequest_Interface): BuildOptions {
148
+ return {
149
+ absWorkingDir: request.resolveDirectory,
150
+ bundle: true,
151
+ charset: 'utf8',
152
+ conditions: [ 'browser', 'default' ],
153
+ entryPoints: [ 'dynts-entry:candidate' ],
154
+ format: 'iife',
155
+ legalComments: 'none',
156
+ logLevel: 'silent',
157
+ mainFields: [ 'browser', 'module', 'main' ],
158
+ metafile: false,
159
+ minify: true,
160
+ outdir: 'dynts-in-memory-output',
161
+ platform: 'browser',
162
+ plugins: [ this.allowlistedEntryPlugin(request) ],
163
+ sourcemap: false,
164
+ target: [ 'es2022' ],
165
+ treeShaking: true,
166
+ write: false,
167
+ };
168
+ }
169
+
170
+ /**
171
+ * Validates every syntactic import before esbuild can tree-shake it. The plugin below is a second resolution gate,
172
+ * but it cannot be the only policy boundary because unused imports need not reach package resolution.
173
+ */
174
+ private validateDirectImports(
175
+ request: DyNTS_ArtifactCompileRequest_Interface
176
+ ): DyNTS_ArtifactCompileFinding_Interface | null {
177
+ const sourceFile: ts.SourceFile = ts.createSourceFile(
178
+ request.sourceFileName,
179
+ request.source,
180
+ ts.ScriptTarget.ES2022,
181
+ true,
182
+ ts.ScriptKind.TS
183
+ );
184
+ const allowedPackages: ReadonlySet<string> = new Set<string>(request.allowedPackages);
185
+ let finding: DyNTS_ArtifactCompileFinding_Interface | null = null;
186
+
187
+ /** Traverses the parsed source once and stops at the first forbidden module load. */
188
+ const inspectNode: (node: ts.Node) => void = (node: ts.Node): void => {
189
+ if (finding) {
190
+ return;
191
+ }
192
+
193
+ const moduleName: string | null = this.moduleName(node);
194
+
195
+ if (moduleName !== null && !allowedPackages.has(this.packageRoot(moduleName))) {
196
+ finding = this.importFinding(sourceFile, node);
197
+
198
+ return;
199
+ }
200
+
201
+ if (this.isDynamicModuleLoad(node)) {
202
+ finding = this.importFinding(sourceFile, node);
203
+
204
+ return;
205
+ }
206
+
207
+ ts.forEachChild(node, inspectNode);
208
+ };
209
+
210
+ inspectNode(sourceFile);
211
+
212
+ return finding;
213
+ }
214
+
215
+ private moduleName(node: ts.Node): string | null {
216
+ if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) && node.moduleSpecifier) {
217
+ return ts.isStringLiteral(node.moduleSpecifier) ? node.moduleSpecifier.text : '';
218
+ }
219
+
220
+ if (
221
+ ts.isImportEqualsDeclaration(node)
222
+ && ts.isExternalModuleReference(node.moduleReference)
223
+ && node.moduleReference.expression
224
+ ) {
225
+ return ts.isStringLiteral(node.moduleReference.expression) ? node.moduleReference.expression.text : '';
226
+ }
227
+
228
+ return null;
229
+ }
230
+
231
+ private isDynamicModuleLoad(node: ts.Node): boolean {
232
+ return ts.isCallExpression(node)
233
+ && (node.expression.kind === ts.SyntaxKind.ImportKeyword
234
+ || (ts.isIdentifier(node.expression) && node.expression.text === 'require'));
235
+ }
236
+
237
+ private importFinding(
238
+ sourceFile: ts.SourceFile,
239
+ node: ts.Node
240
+ ): DyNTS_ArtifactCompileFinding_Interface {
241
+ const location: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
242
+
243
+ return {
244
+ code: 'DYNTS|ARTIFACT_COMPILER|IMPORT_NOT_ALLOWED',
245
+ stage: DyNTS_ArtifactCompileStage_Type.sourcePolicy,
246
+ line: location.line + 1,
247
+ column: location.character + 1,
248
+ retryClass: DyNTS_ArtifactRetryClass_Type.terminal,
249
+ };
250
+ }
251
+
252
+ private allowlistedEntryPlugin(request: DyNTS_ArtifactCompileRequest_Interface): Plugin {
253
+ const allowedPackages: ReadonlySet<string> = new Set<string>(request.allowedPackages);
254
+
255
+ return {
256
+ name: 'dynts-allowlisted-in-memory-entry',
257
+ setup: (pluginBuild: PluginBuild): void => {
258
+ pluginBuild.onResolve({ filter: /^dynts-entry:candidate$/ }, (): OnResolveResult => ({
259
+ path: 'candidate',
260
+ namespace: 'dynts-entry',
261
+ }));
262
+ pluginBuild.onLoad({ filter: /^candidate$/, namespace: 'dynts-entry' }, (): OnLoadResult => ({
263
+ contents: request.source,
264
+ loader: 'ts',
265
+ resolveDir: request.resolveDirectory,
266
+ }));
267
+ pluginBuild.onResolve({ filter: /.*/, namespace: 'dynts-entry' }, async (
268
+ args: OnResolveArgs
269
+ ): Promise<OnResolveResult> => {
270
+ if (!allowedPackages.has(this.packageRoot(args.path))) {
271
+ return {
272
+ errors: [{ text: 'DYNTS|ARTIFACT_COMPILER|IMPORT_NOT_ALLOWED' }],
273
+ };
274
+ }
275
+
276
+ return pluginBuild.resolve(args.path, {
277
+ importer: args.importer,
278
+ kind: args.kind,
279
+ namespace: 'file',
280
+ resolveDir: request.resolveDirectory,
281
+ });
282
+ });
283
+ },
284
+ };
285
+ }
286
+
287
+ private buildFindings(error: unknown): DyNTS_ArtifactCompileFinding_Interface[] {
288
+ if (!this.isBuildFailure(error)) {
289
+ return [ this.genericBuildFinding() ];
290
+ }
291
+
292
+ const findings: DyNTS_ArtifactCompileFinding_Interface[] = error.errors.map((message: Message):
293
+ DyNTS_ArtifactCompileFinding_Interface => ({
294
+ code: message.text === 'DYNTS|ARTIFACT_COMPILER|IMPORT_NOT_ALLOWED'
295
+ ? message.text
296
+ : 'DYNTS|ARTIFACT_COMPILER|COMPILE_ERROR',
297
+ stage: message.text === 'DYNTS|ARTIFACT_COMPILER|IMPORT_NOT_ALLOWED'
298
+ ? DyNTS_ArtifactCompileStage_Type.resolve
299
+ : DyNTS_ArtifactCompileStage_Type.compile,
300
+ line: message.location?.line ?? null,
301
+ column: message.location ? message.location.column + 1 : null,
302
+ retryClass: message.text === 'DYNTS|ARTIFACT_COMPILER|IMPORT_NOT_ALLOWED'
303
+ ? DyNTS_ArtifactRetryClass_Type.terminal
304
+ : DyNTS_ArtifactRetryClass_Type.agentFixable,
305
+ }));
306
+
307
+ return findings.length ? findings : [ this.genericBuildFinding() ];
308
+ }
309
+
310
+ private isBuildFailure(error: unknown): error is BuildFailure {
311
+ if (!error || typeof error !== 'object') {
312
+ return false;
313
+ }
314
+
315
+ return 'errors' in error && Array.isArray(error.errors);
316
+ }
317
+
318
+ private genericBuildFinding(): DyNTS_ArtifactCompileFinding_Interface {
319
+ return {
320
+ code: 'DYNTS|ARTIFACT_COMPILER|COMPILE_ERROR',
321
+ stage: DyNTS_ArtifactCompileStage_Type.compile,
322
+ line: null,
323
+ column: null,
324
+ retryClass: DyNTS_ArtifactRetryClass_Type.agentFixable,
325
+ };
326
+ }
327
+
328
+ private rejected(
329
+ sourceChecksum: string,
330
+ code: string,
331
+ findings: DyNTS_ArtifactCompileFinding_Interface[]
332
+ ): DyNTS_ArtifactCompileResult_Interface {
333
+ return {
334
+ contractVersion: DyNTS_ArtifactCompiler_ControlService.contractVersion,
335
+ outcome: DyNTS_ArtifactCompileOutcome_Type.rejected,
336
+ code: code,
337
+ sourceChecksum: sourceChecksum,
338
+ bundleChecksum: '',
339
+ outputBytes: 0,
340
+ bundleSource: null,
341
+ findings: findings,
342
+ };
343
+ }
344
+
345
+ private packageRoot(moduleName: string): string {
346
+ if (moduleName.startsWith('@')) {
347
+ return moduleName.split('/').slice(0, 2).join('/');
348
+ }
349
+
350
+ return moduleName.split('/')[0];
351
+ }
352
+
353
+ private checksum(value: string): string {
354
+ return createHash('sha256').update(value, 'utf8').digest('hex');
355
+ }
356
+ }
@@ -0,0 +1,9 @@
1
+ export { DyNTS_ArtifactCompiler_ControlService } from './artifact-compiler.control-service';
2
+ export { DyNTS_ArtifactCompileOutcome_Type } from './_enums/artifact-compile-outcome.type-enum';
3
+ export { DyNTS_ArtifactCompileStage_Type } from './_enums/artifact-compile-stage.type-enum';
4
+ export { DyNTS_ArtifactRetryClass_Type } from './_enums/artifact-retry-class.type-enum';
5
+ export {
6
+ DyNTS_ArtifactCompileFinding_Interface,
7
+ DyNTS_ArtifactCompileRequest_Interface,
8
+ DyNTS_ArtifactCompileResult_Interface
9
+ } from './_models/artifact-compile.interface';