@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.
- package/__documentations/2026-08-18-artifact-compiler.md +44 -0
- package/build/_modules/artifact-compiler/_enums/artifact-compile-outcome.type-enum.d.ts +6 -0
- package/build/_modules/artifact-compiler/_enums/artifact-compile-outcome.type-enum.d.ts.map +1 -0
- package/build/_modules/artifact-compiler/_enums/artifact-compile-outcome.type-enum.js +10 -0
- package/build/_modules/artifact-compiler/_enums/artifact-compile-outcome.type-enum.js.map +1 -0
- package/build/_modules/artifact-compiler/_enums/artifact-compile-stage.type-enum.d.ts +9 -0
- package/build/_modules/artifact-compiler/_enums/artifact-compile-stage.type-enum.d.ts.map +1 -0
- package/build/_modules/artifact-compiler/_enums/artifact-compile-stage.type-enum.js +13 -0
- package/build/_modules/artifact-compiler/_enums/artifact-compile-stage.type-enum.js.map +1 -0
- package/build/_modules/artifact-compiler/_enums/artifact-retry-class.type-enum.d.ts +7 -0
- package/build/_modules/artifact-compiler/_enums/artifact-retry-class.type-enum.d.ts.map +1 -0
- package/build/_modules/artifact-compiler/_enums/artifact-retry-class.type-enum.js +11 -0
- package/build/_modules/artifact-compiler/_enums/artifact-retry-class.type-enum.js.map +1 -0
- package/build/_modules/artifact-compiler/_models/artifact-compile.interface.d.ts +33 -0
- package/build/_modules/artifact-compiler/_models/artifact-compile.interface.d.ts.map +1 -0
- package/build/_modules/artifact-compiler/_models/artifact-compile.interface.js +3 -0
- package/build/_modules/artifact-compiler/_models/artifact-compile.interface.js.map +1 -0
- package/build/_modules/artifact-compiler/artifact-compiler.control-service.d.ts +37 -0
- package/build/_modules/artifact-compiler/artifact-compiler.control-service.d.ts.map +1 -0
- package/build/_modules/artifact-compiler/artifact-compiler.control-service.js +274 -0
- package/build/_modules/artifact-compiler/artifact-compiler.control-service.js.map +1 -0
- package/build/_modules/artifact-compiler/index.d.ts +6 -0
- package/build/_modules/artifact-compiler/index.d.ts.map +1 -0
- package/build/_modules/artifact-compiler/index.js +12 -0
- package/build/_modules/artifact-compiler/index.js.map +1 -0
- package/package.json +15 -2
- package/pnpm-workspace.yaml +4 -3
- package/src/_modules/artifact-compiler/_enums/artifact-compile-outcome.type-enum.ts +5 -0
- package/src/_modules/artifact-compiler/_enums/artifact-compile-stage.type-enum.ts +8 -0
- package/src/_modules/artifact-compiler/_enums/artifact-retry-class.type-enum.ts +6 -0
- package/src/_modules/artifact-compiler/_models/artifact-compile.interface.ts +35 -0
- package/src/_modules/artifact-compiler/artifact-compiler.control-service.spec.ts +151 -0
- package/src/_modules/artifact-compiler/artifact-compiler.control-service.ts +356 -0
- 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 @@
|
|
|
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 @@
|
|
|
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.
|
|
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
|
}
|
package/pnpm-workspace.yaml
CHANGED
|
@@ -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';
|