payid-rule-engine 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # rule-engine
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ bun run index.ts
13
+ ```
14
+
15
+ This project was created using `bun init` in bun v1.2.21. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./src";
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "payid-rule-engine",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "scripts": {
7
+ "build": "bun build src/sandbox.ts --outdir dist --target node"
8
+ },
9
+ "dependencies": {
10
+ "@payid/types": "*",
11
+ "@types/lodash": "^4.17.21",
12
+ "lodash": "^4.17.21"
13
+ },
14
+ "devDependencies": {
15
+ "@types/bun": "latest"
16
+ },
17
+ "peerDependencies": {
18
+ "typescript": "^5"
19
+ }
20
+ }
package/src/index.ts ADDED
@@ -0,0 +1,21 @@
1
+ import type { RuleContext, RuleResult } from "@payid/types";
2
+ import { runWasmRule } from "./sandbox";
3
+ export * from "./sandbox";
4
+ export * from "./preprocess";
5
+
6
+ /**
7
+ * Execute PAY.ID WASM rule engine.
8
+ *
9
+ * @param wasmBinary Compiled WASM binary
10
+ * @param context Rule execution context
11
+ * @param ruleConfig Rule configuration JSON
12
+ *
13
+ * @returns RuleResult (ALLOW / REJECT)
14
+ */
15
+ export async function executeRule(
16
+ wasmBinary: Buffer,
17
+ context: RuleContext,
18
+ ruleConfig: unknown
19
+ ): Promise<RuleResult> {
20
+ return runWasmRule(wasmBinary, context, ruleConfig);
21
+ }
@@ -0,0 +1,48 @@
1
+ import { validateRequiredContext } from "./validateRequires";
2
+ import { verifyAttestation } from "@payid/attestation";
3
+
4
+ export function preprocessContextV2(
5
+ context: any,
6
+ ruleConfig: any,
7
+ trustedIssuers: Set<string>
8
+ ) {
9
+ validateRequiredContext(context, ruleConfig.requires);
10
+
11
+ if (context.env) {
12
+ verifyAttestation(
13
+ { timestamp: context.env.timestamp },
14
+ context.env.proof,
15
+ trustedIssuers
16
+ );
17
+ }
18
+
19
+ if (context.state) {
20
+ verifyAttestation(
21
+ {
22
+ spentToday: context.state.spentToday,
23
+ period: context.state.period
24
+ },
25
+ context.state.proof,
26
+ trustedIssuers
27
+ );
28
+ }
29
+
30
+ if (context.oracle) {
31
+ const { proof, ...data } = context.oracle;
32
+ verifyAttestation(data, proof, trustedIssuers);
33
+ }
34
+
35
+ if (context.risk) {
36
+ verifyAttestation(
37
+ {
38
+ score: context.risk.score,
39
+ category: context.risk.category,
40
+ modelHash: context.risk.proof.modelHash
41
+ },
42
+ context.risk.proof,
43
+ trustedIssuers
44
+ );
45
+ }
46
+
47
+ return context;
48
+ }
package/src/sandbox.ts ADDED
@@ -0,0 +1,50 @@
1
+ import { WASI } from "wasi";
2
+ import type { RuleContext, RuleResult } from "@payid/types";
3
+ import { loadWasm } from "./wasm";
4
+
5
+ export async function runWasmRule(
6
+ wasmBinary: Buffer,
7
+ context: RuleContext,
8
+ config: any
9
+ ): Promise<RuleResult> {
10
+ const wasi = new WASI({ version: "preview1" });
11
+ const instance = await loadWasm(wasmBinary, wasi);
12
+
13
+ const memory = instance.exports.memory as WebAssembly.Memory;
14
+ const alloc = instance.exports.alloc as (size: number) => number;
15
+ const free = instance.exports.free as (ptr: number, size: number) => void;
16
+ const evaluate = instance.exports.evaluate as (
17
+ a: number, b: number, c: number, d: number, e: number, f: number
18
+ ) => number;
19
+
20
+ const ctxBuf = Buffer.from(JSON.stringify(context));
21
+ const cfgBuf = Buffer.from(JSON.stringify(config));
22
+ const OUT_SIZE = 2048;
23
+
24
+ const ctxPtr = alloc(ctxBuf.length);
25
+ const cfgPtr = alloc(cfgBuf.length);
26
+ const outPtr = alloc(OUT_SIZE);
27
+
28
+ try {
29
+ new Uint8Array(memory.buffer).set(ctxBuf, ctxPtr);
30
+ new Uint8Array(memory.buffer).set(cfgBuf, cfgPtr);
31
+
32
+ const rc = evaluate(
33
+ ctxPtr, ctxBuf.length,
34
+ cfgPtr, cfgBuf.length,
35
+ outPtr, OUT_SIZE
36
+ );
37
+
38
+ if (rc < 0) throw new Error(`WASM failed rc=${rc}`);
39
+
40
+ const out = Buffer.from(
41
+ new Uint8Array(memory.buffer).slice(outPtr, outPtr + rc)
42
+ );
43
+
44
+ return JSON.parse(out.toString("utf8"));
45
+ } finally {
46
+ free(ctxPtr, ctxBuf.length);
47
+ free(cfgPtr, cfgBuf.length);
48
+ free(outPtr, OUT_SIZE);
49
+ }
50
+ }
package/src/types.ts ADDED
File without changes
@@ -0,0 +1,15 @@
1
+ import { get } from "lodash";
2
+
3
+ export function validateRequiredContext(
4
+ context: any,
5
+ requires?: string[]
6
+ ) {
7
+ if (!requires) return;
8
+
9
+ for (const path of requires) {
10
+ const value = get(context, path);
11
+ if (value === undefined || value === null) {
12
+ throw new Error(`Missing required context field: ${path}`);
13
+ }
14
+ }
15
+ }
package/src/wasm.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { WASI } from "wasi";
2
+
3
+ export async function loadWasm(
4
+ binary: Buffer,
5
+ wasi: WASI
6
+ ): Promise<WebAssembly.Instance> {
7
+ const module = await WebAssembly.compile(binary);
8
+
9
+ const instance = await WebAssembly.instantiate(module, {
10
+ wasi_snapshot_preview1: wasi.wasiImport
11
+ });
12
+
13
+ wasi.start(instance);
14
+
15
+ return instance;
16
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Environment setup & latest features
4
+ "lib": ["ESNext"],
5
+ "target": "ESNext",
6
+ "module": "Preserve",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+
11
+ // Bundler mode
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "noEmit": true,
16
+
17
+ // Best practices
18
+ "strict": true,
19
+ "skipLibCheck": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "noUncheckedIndexedAccess": true,
22
+ "noImplicitOverride": true,
23
+
24
+ // Some stricter flags (disabled by default)
25
+ "noUnusedLocals": false,
26
+ "noUnusedParameters": false,
27
+ "noPropertyAccessFromIndexSignature": false
28
+ }
29
+ }