ega-v9 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +163 -0
- package/dist/index.mjs +27 -0
- package/package.json +14 -4
package/dist/index.js
CHANGED
|
@@ -6,6 +6,163 @@ exports.replay = replay;
|
|
|
6
6
|
exports.provenance = provenance;
|
|
7
7
|
exports.contain = contain;
|
|
8
8
|
const crypto_1 = require("crypto");
|
|
9
|
+
class EGAInputValidationError extends TypeError {
|
|
10
|
+
constructor(args) {
|
|
11
|
+
super(`[${args.code}] ${args.message}`);
|
|
12
|
+
this.name = "EGAInputValidationError";
|
|
13
|
+
this.code = args.code;
|
|
14
|
+
this.field = args.field;
|
|
15
|
+
this.expected = args.expected;
|
|
16
|
+
this.receivedType = describeInputType(args.value);
|
|
17
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function describeInputType(value) {
|
|
21
|
+
if (value === null) {
|
|
22
|
+
return "null";
|
|
23
|
+
}
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
return "array";
|
|
26
|
+
}
|
|
27
|
+
return typeof value;
|
|
28
|
+
}
|
|
29
|
+
function isPlainObject(value) {
|
|
30
|
+
if (value === null ||
|
|
31
|
+
typeof value !== "object" ||
|
|
32
|
+
Array.isArray(value)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
const prototype = Object.getPrototypeOf(value);
|
|
36
|
+
return (prototype === Object.prototype ||
|
|
37
|
+
prototype === null);
|
|
38
|
+
}
|
|
39
|
+
function assertStandaloneInput(input, functionName) {
|
|
40
|
+
if (input === undefined) {
|
|
41
|
+
throw new EGAInputValidationError({
|
|
42
|
+
code: "EGA_INPUT_REQUIRED",
|
|
43
|
+
message: `${functionName} input is required. Pass a defined execution value.`,
|
|
44
|
+
value: input,
|
|
45
|
+
field: "input",
|
|
46
|
+
expected: "defined value"
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function validateEGAOptions(options) {
|
|
51
|
+
if (!isPlainObject(options)) {
|
|
52
|
+
throw new EGAInputValidationError({
|
|
53
|
+
code: "EGA_OPTIONS_TYPE",
|
|
54
|
+
message: "EGA.init options must be a plain object.",
|
|
55
|
+
value: options,
|
|
56
|
+
field: "options",
|
|
57
|
+
expected: "plain object"
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (options.appName !== undefined &&
|
|
61
|
+
(typeof options.appName !== "string" ||
|
|
62
|
+
options.appName.trim().length === 0)) {
|
|
63
|
+
throw new EGAInputValidationError({
|
|
64
|
+
code: typeof options.appName === "string"
|
|
65
|
+
? "EGA_OPTION_VALUE"
|
|
66
|
+
: "EGA_OPTION_TYPE",
|
|
67
|
+
message: "options.appName must be a non-empty string.",
|
|
68
|
+
value: options.appName,
|
|
69
|
+
field: "options.appName",
|
|
70
|
+
expected: "non-empty string"
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (options.trustLevel !== undefined &&
|
|
74
|
+
options.trustLevel !== "supported" &&
|
|
75
|
+
options.trustLevel !== "verified") {
|
|
76
|
+
throw new EGAInputValidationError({
|
|
77
|
+
code: "EGA_OPTION_VALUE",
|
|
78
|
+
message: 'options.trustLevel must be "supported" or "verified".',
|
|
79
|
+
value: options.trustLevel,
|
|
80
|
+
field: "options.trustLevel",
|
|
81
|
+
expected: '"supported" | "verified"'
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
for (const field of [
|
|
85
|
+
"telemetry",
|
|
86
|
+
"failClosed"
|
|
87
|
+
]) {
|
|
88
|
+
const value = options[field];
|
|
89
|
+
if (value !== undefined &&
|
|
90
|
+
typeof value !== "boolean") {
|
|
91
|
+
throw new EGAInputValidationError({
|
|
92
|
+
code: "EGA_OPTION_TYPE",
|
|
93
|
+
message: `options.${field} must be a boolean.`,
|
|
94
|
+
value,
|
|
95
|
+
field: `options.${field}`,
|
|
96
|
+
expected: "boolean"
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (options.policyId !== undefined &&
|
|
101
|
+
(typeof options.policyId !== "string" ||
|
|
102
|
+
options.policyId.trim().length === 0)) {
|
|
103
|
+
throw new EGAInputValidationError({
|
|
104
|
+
code: typeof options.policyId === "string"
|
|
105
|
+
? "EGA_OPTION_VALUE"
|
|
106
|
+
: "EGA_OPTION_TYPE",
|
|
107
|
+
message: "options.policyId must be a non-empty string.",
|
|
108
|
+
value: options.policyId,
|
|
109
|
+
field: "options.policyId",
|
|
110
|
+
expected: "non-empty string"
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (options.approvalThreshold !== undefined) {
|
|
114
|
+
if (typeof options.approvalThreshold !==
|
|
115
|
+
"number" ||
|
|
116
|
+
!Number.isFinite(options.approvalThreshold)) {
|
|
117
|
+
throw new EGAInputValidationError({
|
|
118
|
+
code: "EGA_OPTION_TYPE",
|
|
119
|
+
message: "options.approvalThreshold must be a finite number.",
|
|
120
|
+
value: options.approvalThreshold,
|
|
121
|
+
field: "options.approvalThreshold",
|
|
122
|
+
expected: "finite number from 0 to 100"
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
if (options.approvalThreshold < 0 ||
|
|
126
|
+
options.approvalThreshold > 100) {
|
|
127
|
+
throw new EGAInputValidationError({
|
|
128
|
+
code: "EGA_OPTION_RANGE",
|
|
129
|
+
message: "options.approvalThreshold must be between 0 and 100.",
|
|
130
|
+
value: options.approvalThreshold,
|
|
131
|
+
field: "options.approvalThreshold",
|
|
132
|
+
expected: "number from 0 to 100"
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function validateGuardInvocation(req, res, next) {
|
|
138
|
+
if (!isPlainObject(req)) {
|
|
139
|
+
throw new EGAInputValidationError({
|
|
140
|
+
code: "EGA_GUARD_REQUEST_REQUIRED",
|
|
141
|
+
message: "EGA guard requires a request object.",
|
|
142
|
+
value: req,
|
|
143
|
+
field: "req",
|
|
144
|
+
expected: "request object"
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (!isPlainObject(res)) {
|
|
148
|
+
throw new EGAInputValidationError({
|
|
149
|
+
code: "EGA_GUARD_RESPONSE_REQUIRED",
|
|
150
|
+
message: "EGA guard requires a response object.",
|
|
151
|
+
value: res,
|
|
152
|
+
field: "res",
|
|
153
|
+
expected: "response object"
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (typeof next !== "function") {
|
|
157
|
+
throw new EGAInputValidationError({
|
|
158
|
+
code: "EGA_GUARD_NEXT_REQUIRED",
|
|
159
|
+
message: "EGA guard requires a next callback.",
|
|
160
|
+
value: next,
|
|
161
|
+
field: "next",
|
|
162
|
+
expected: "function"
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
9
166
|
class EGA {
|
|
10
167
|
constructor(options = {}) {
|
|
11
168
|
this.eventLog = [];
|
|
@@ -20,10 +177,12 @@ class EGA {
|
|
|
20
177
|
};
|
|
21
178
|
}
|
|
22
179
|
static init(options = {}) {
|
|
180
|
+
validateEGAOptions(options);
|
|
23
181
|
return new EGA(options);
|
|
24
182
|
}
|
|
25
183
|
guard() {
|
|
26
184
|
return (req, res, next) => {
|
|
185
|
+
validateGuardInvocation(req, res, next);
|
|
27
186
|
const requestId = (0, crypto_1.randomUUID)();
|
|
28
187
|
const clientIdentity = buildAnonymousClientIdentity(req, this.options.appName);
|
|
29
188
|
const licenseState = evaluateLicenseState(req);
|
|
@@ -621,6 +780,7 @@ function stableStringify(input) {
|
|
|
621
780
|
}).join(",")}}`;
|
|
622
781
|
}
|
|
623
782
|
function verifyExecution(input) {
|
|
783
|
+
assertStandaloneInput(input, "verifyExecution");
|
|
624
784
|
const ega = EGA.init();
|
|
625
785
|
const replayRoot = ega.replayRoot(input);
|
|
626
786
|
const businessMetrics = collectBusinessMetrics(input);
|
|
@@ -680,12 +840,15 @@ function verifyExecution(input) {
|
|
|
680
840
|
};
|
|
681
841
|
}
|
|
682
842
|
function replay(input) {
|
|
843
|
+
assertStandaloneInput(input, "replay");
|
|
683
844
|
return verifyExecution(input);
|
|
684
845
|
}
|
|
685
846
|
function provenance(input) {
|
|
847
|
+
assertStandaloneInput(input, "provenance");
|
|
686
848
|
return verifyExecution(input);
|
|
687
849
|
}
|
|
688
850
|
function contain(input) {
|
|
851
|
+
assertStandaloneInput(input, "contain");
|
|
689
852
|
return verifyExecution(input);
|
|
690
853
|
}
|
|
691
854
|
function guardLatencyMicroseconds(startedAt) {
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict compatibility wrapper";
|
|
2
|
+
|
|
3
|
+
import commonJsModule from "./index.js";
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
EGA,
|
|
7
|
+
contain,
|
|
8
|
+
ega,
|
|
9
|
+
provenance,
|
|
10
|
+
replay,
|
|
11
|
+
verifyExecution,
|
|
12
|
+
} = commonJsModule;
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
EGA,
|
|
16
|
+
contain,
|
|
17
|
+
ega,
|
|
18
|
+
provenance,
|
|
19
|
+
replay,
|
|
20
|
+
verifyExecution,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
* Preserve the historical Node.js ESM-to-CommonJS default-import
|
|
25
|
+
* compatibility behavior.
|
|
26
|
+
*/
|
|
27
|
+
export default commonJsModule;
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ega-v9",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "EGA V9 TypeScript SDK for replay, provenance, containment, and SCORP LOCK governance.",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
9
|
"README.md",
|
|
10
10
|
"LICENSE"
|
|
11
11
|
],
|
|
12
12
|
"scripts": {
|
|
13
|
-
"build": "tsc",
|
|
13
|
+
"build": "tsc && node scripts/generate-esm-wrapper.cjs",
|
|
14
14
|
"test": "npm run build && node ../../scripts/testing/run-v1-test-suite.cjs",
|
|
15
15
|
"dev": "tsc --watch"
|
|
16
16
|
},
|
|
@@ -35,5 +35,15 @@
|
|
|
35
35
|
"homepage": "https://github.com/paibyun9/EGA-V9#readme",
|
|
36
36
|
"bugs": {
|
|
37
37
|
"url": "https://github.com/paibyun9/EGA-V9/issues"
|
|
38
|
+
},
|
|
39
|
+
"module": "./dist/index.mjs",
|
|
40
|
+
"exports": {
|
|
41
|
+
".": {
|
|
42
|
+
"types": "./dist/index.d.ts",
|
|
43
|
+
"import": "./dist/index.mjs",
|
|
44
|
+
"require": "./dist/index.js",
|
|
45
|
+
"default": "./dist/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./package.json": "./package.json"
|
|
38
48
|
}
|
|
39
49
|
}
|