@nekzus/liop 1.2.0-alpha.10 → 1.2.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 CHANGED
@@ -301,7 +301,7 @@ const server = new LiopServer(info, {
301
301
  The following shows a complete Logic-Injection-on-Origin execution cycle (handled internally by the SDK):
302
302
 
303
303
  ```
304
- 1. LLM generates JavaScript analysis code wrapped in ---BEGIN_LOGIC--- / ---END_LOGIC--- boundaries
304
+ 1. LLM generates JavaScript analysis code wrapped in @LIOP / @END boundaries
305
305
  2. LiopServer receives the payload via tools/call (JSON-RPC or direct)
306
306
  3. Guardian AST inspects for sandbox escapes (zero-time heuristic analysis)
307
307
  4. Code executes inside a V8 isolate with CPU fuel limits (no Node.js globals)
@@ -4,7 +4,7 @@ import crypto from "node:crypto";
4
4
  * proxy logic embeds a full envelope inside JSON strings; `^` per line would
5
5
  * incorrectly treat that as the document root and desync ImageID vs the worker.
6
6
  */
7
- const TOP_LEVEL_ENVELOPE = /^\s*LIOP_MAGIC:0x00FF\s*\n?\s*MANIFEST:\{[\s\S]*?\}\s*\n?\s*---BEGIN_LOGIC---\n?([\s\S]*?)\n?---END_LOGIC---\s*$/;
7
+ const TOP_LEVEL_ENVELOPE = /^\s*@LIOP\{[^}]+\}\n?([\s\S]*?)\n?@END\s*$/;
8
8
  export function normalizeLogicSource(logicUtf8) {
9
9
  const match = logicUtf8.match(TOP_LEVEL_ENVELOPE);
10
10
  if (match?.[1] !== undefined) {
@@ -0,0 +1,14 @@
1
+ export declare enum ErrorCode {
2
+ CapabilityViolation = "CapabilityViolation",
3
+ SandboxEscape = "SandboxEscape",
4
+ PiiLeak = "PiiLeak",
5
+ InvalidIntent = "InvalidIntent",
6
+ Throttled = "Throttled",
7
+ ZkVerificationFailed = "ZkVerificationFailed",
8
+ MeshUnavailable = "MeshUnavailable",
9
+ ConnectionFailed = "ConnectionFailed"
10
+ }
11
+ export declare class LiopError extends Error {
12
+ readonly code: ErrorCode;
13
+ constructor(code: ErrorCode, message: string);
14
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,19 @@
1
+ export var ErrorCode;
2
+ (function (ErrorCode) {
3
+ ErrorCode["CapabilityViolation"] = "CapabilityViolation";
4
+ ErrorCode["SandboxEscape"] = "SandboxEscape";
5
+ ErrorCode["PiiLeak"] = "PiiLeak";
6
+ ErrorCode["InvalidIntent"] = "InvalidIntent";
7
+ ErrorCode["Throttled"] = "Throttled";
8
+ ErrorCode["ZkVerificationFailed"] = "ZkVerificationFailed";
9
+ ErrorCode["MeshUnavailable"] = "MeshUnavailable";
10
+ ErrorCode["ConnectionFailed"] = "ConnectionFailed";
11
+ })(ErrorCode || (ErrorCode = {}));
12
+ export class LiopError extends Error {
13
+ code;
14
+ constructor(code, message) {
15
+ super(message);
16
+ this.name = "LiopError";
17
+ this.code = code;
18
+ }
19
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from "./bridge/index.js";
2
2
  export * from "./client/index.js";
3
3
  export * from "./economy/index.js";
4
+ export * from "./errors.js";
4
5
  export * from "./gateway/hybrid.js";
5
6
  export * from "./mesh/node.js";
6
7
  export * from "./prompts/adapters.js";
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from "./bridge/index.js";
2
2
  export * from "./client/index.js";
3
3
  export * from "./economy/index.js";
4
+ export * from "./errors.js";
4
5
  export * from "./gateway/hybrid.js";
5
6
  export * from "./mesh/node.js";
6
7
  export * from "./prompts/adapters.js";
@@ -101,36 +101,65 @@ export class WasiSandbox {
101
101
  else {
102
102
  // Path B: Hardened V8 Isolate Fallback
103
103
  // Uses node:vm with zero-prototype objects to prevent prototype pollution escapes.
104
+ // biome-ignore lint/suspicious/noExplicitAny: Required for Sandbox global poisoning
104
105
  const sandboxEnv = Object.create(null); // Isolated global object
105
106
  const env = { records, ...inputs };
107
+ // Explicitly poison Node.js escape vectors in the context
108
+ sandboxEnv.require = undefined;
109
+ sandboxEnv.process = undefined;
110
+ sandboxEnv.global = undefined;
111
+ sandboxEnv.globalThis = undefined;
112
+ sandboxEnv.Buffer = undefined;
113
+ sandboxEnv.setTimeout = undefined;
114
+ sandboxEnv.setInterval = undefined;
115
+ sandboxEnv.setImmediate = undefined;
116
+ sandboxEnv.queueMicrotask = undefined;
117
+ sandboxEnv.eval = undefined;
118
+ sandboxEnv.Function = undefined;
106
119
  // Inject strictly monitored globals
107
120
  sandboxEnv.records = JSON.parse(JSON.stringify(records)); // Deep copy safety
108
121
  sandboxEnv.env = JSON.parse(JSON.stringify(env));
109
122
  for (const [key, value] of Object.entries(inputs)) {
110
123
  sandboxEnv[key] = JSON.parse(JSON.stringify(value));
111
124
  }
125
+ // Freeze the sandbox context to prevent mutation (SEC-GAP-1)
126
+ // biome-ignore lint/suspicious/noExplicitAny: Required for recursive deep freeze of unknown data
127
+ const deepFreeze = (obj) => {
128
+ if (obj && typeof obj === "object" && !Object.isFrozen(obj)) {
129
+ Object.freeze(obj);
130
+ for (const key of Object.keys(obj)) {
131
+ deepFreeze(obj[key]);
132
+ }
133
+ }
134
+ return obj;
135
+ };
136
+ deepFreeze(sandboxEnv.records);
137
+ deepFreeze(sandboxEnv.env);
138
+ // Prevent property addition/modification on global scope
139
+ for (const key of Object.keys(sandboxEnv)) {
140
+ Object.defineProperty(sandboxEnv, key, {
141
+ writable: false,
142
+ configurable: false,
143
+ });
144
+ }
112
145
  // LIOP Execution Wrapper
113
- // Supports two code patterns:
114
- // 1. Explicit entry point: function liop_main(env) { ... }
115
- // 2. Bare return logic: const x = env.records; return { total: x.length };
146
+ // Host-side logic transformation to avoid 'new Function' in sandbox
147
+ let processedLogic = String(compiledLogic);
148
+ if (/^\s*return\s/m.test(processedLogic) ||
149
+ !processedLogic.includes("function liop_main")) {
150
+ if (!processedLogic.includes("function liop_main")) {
151
+ processedLogic = `function liop_main(env) {\n${processedLogic}\n}`;
152
+ }
153
+ }
116
154
  const scriptCode = `
117
155
  (function() {
118
156
  try {
119
- ${compiledLogic}
157
+ ${processedLogic}
120
158
  if (typeof liop_main === 'function') {
121
159
  return liop_main(env);
122
160
  }
123
161
  return "ERR_NO_ENTRY_POINT";
124
162
  } catch(e) {
125
- if (e instanceof SyntaxError && /Illegal return statement/i.test(e.message)) {
126
- // Bare-return pattern: wrap the logic as a function body
127
- try {
128
- const __liop_fn = new Function('env', 'records', ${JSON.stringify(String(compiledLogic))});
129
- return __liop_fn(env, env.records);
130
- } catch(e2) {
131
- return "LogicError: " + e2.message;
132
- }
133
- }
134
163
  return "LogicError: " + e.message;
135
164
  }
136
165
  })();
@@ -24,6 +24,12 @@ export interface LiopServerOptions {
24
24
  executionTypes?: string[];
25
25
  };
26
26
  }
27
+ export interface AggregationPolicy {
28
+ /** Maximum number of object-type array elements allowed (default: 10) */
29
+ maxOutputRows?: number;
30
+ /** Allow arrays containing only primitive values (default: true) */
31
+ allowPrimitiveArrays?: boolean;
32
+ }
27
33
  export interface LogicExecutionPolicy {
28
34
  /**
29
35
  * Validate the business payload returned by sandbox logic (post-execution).
@@ -33,7 +39,7 @@ export interface LogicExecutionPolicy {
33
39
  /**
34
40
  * Enforce aggregation-first heuristics (preflight + post-check).
35
41
  */
36
- enforceAggregationFirst?: boolean;
42
+ enforceAggregationFirst?: boolean | AggregationPolicy;
37
43
  /**
38
44
  * Optional additional deny patterns checked against extracted logic source.
39
45
  */
@@ -58,7 +64,6 @@ export declare class LiopServer {
58
64
  private rpcServer;
59
65
  private boundPort;
60
66
  private sessions;
61
- private static readonly LIOP_LOGIC_REGEX;
62
67
  private static readonly LIOP_COMPACT_REGEX;
63
68
  private extractLogic;
64
69
  private parseUnknownJson;
@@ -40,14 +40,9 @@ export class LiopServer {
40
40
  rpcServer = null;
41
41
  boundPort = null;
42
42
  sessions = new Map();
43
- static LIOP_LOGIC_REGEX = /\s*LIOP_MAGIC:0x00FF\s*\n?\s*MANIFEST:(?<manifest>\{[\s\S]*?\})\s*\n?\s*---BEGIN_LOGIC---\n?(?<logic>[\s\S]*?)\n?---END_LOGIC---/m;
44
43
  // Compact envelope: @LIOP{target,name}\n<code>\n@END
45
44
  static LIOP_COMPACT_REGEX = /@LIOP\{(?<target>[^,}]+)(?:,(?<name>[^}]*))?\}\n(?<logic>[\s\S]*?)\n@END/m;
46
45
  extractLogic(payload) {
47
- const match = payload.match(LiopServer.LIOP_LOGIC_REGEX);
48
- if (match?.groups?.logic)
49
- return match.groups.logic.trim();
50
- // Compact envelope fallback — same execution, fewer tokens
51
46
  const compact = payload.match(LiopServer.LIOP_COMPACT_REGEX);
52
47
  return compact?.groups?.logic ? compact.groups.logic.trim() : null;
53
48
  }
@@ -101,7 +96,7 @@ export class LiopServer {
101
96
  }
102
97
  }
103
98
  if (policy.enforceAggregationFirst &&
104
- this.violatesAggregationFirstPolicy(this.unwrapForAggregationPolicyScan(parsed))) {
99
+ this.violatesAggregationFirstPolicy(this.unwrapForAggregationPolicyScan(parsed), policy.enforceAggregationFirst)) {
105
100
  return "Aggregation-First Policy Violation: row-level export blocked. HINT: Use .reduce() to produce a flat {key:value} object. Do NOT use .map() to create arrays of objects.";
106
101
  }
107
102
  return null;
@@ -147,13 +142,13 @@ export class LiopServer {
147
142
  const joined = texts.length === 1 ? texts[0] : texts.join("\n");
148
143
  return this.unwrapForAggregationPolicyScan(joined);
149
144
  }
150
- violatesAggregationFirstPolicy(input) {
145
+ violatesAggregationFirstPolicy(input, policyObj) {
151
146
  if (typeof input === "string") {
152
147
  const trimmed = input.trim();
153
148
  if ((trimmed.startsWith("{") && trimmed.endsWith("}")) ||
154
149
  (trimmed.startsWith("[") && trimmed.endsWith("]"))) {
155
150
  try {
156
- return this.violatesAggregationFirstPolicy(JSON.parse(trimmed));
151
+ return this.violatesAggregationFirstPolicy(JSON.parse(trimmed), policyObj);
157
152
  }
158
153
  catch {
159
154
  return false;
@@ -162,14 +157,32 @@ export class LiopServer {
162
157
  return false;
163
158
  }
164
159
  if (Array.isArray(input)) {
165
- if (input.length > 0 && input.every((item) => typeof item === "object")) {
166
- // Treat tabular row export as non-aggregated leakage risk.
167
- return true;
160
+ const maxRows = typeof policyObj === "object" &&
161
+ typeof policyObj.maxOutputRows === "number"
162
+ ? policyObj.maxOutputRows
163
+ : 10;
164
+ const allowPrimitives = typeof policyObj === "object" &&
165
+ typeof policyObj.allowPrimitiveArrays === "boolean"
166
+ ? policyObj.allowPrimitiveArrays
167
+ : true;
168
+ if (input.length > 0 &&
169
+ input.every((item) => typeof item === "object" && item !== null)) {
170
+ // Treat tabular row export as non-aggregated leakage risk if above threshold.
171
+ if (input.length > maxRows) {
172
+ return true;
173
+ }
174
+ return input.some((item) => this.violatesAggregationFirstPolicy(item, policyObj));
175
+ }
176
+ if (input.length > 0 &&
177
+ input.every((item) => typeof item !== "object" || item === null)) {
178
+ if (!allowPrimitives)
179
+ return true;
180
+ return false;
168
181
  }
169
- return input.some((item) => this.violatesAggregationFirstPolicy(item));
182
+ return input.some((item) => this.violatesAggregationFirstPolicy(item, policyObj));
170
183
  }
171
184
  if (input && typeof input === "object") {
172
- return Object.values(input).some((value) => this.violatesAggregationFirstPolicy(value));
185
+ return Object.values(input).some((value) => this.violatesAggregationFirstPolicy(value, policyObj));
173
186
  }
174
187
  return false;
175
188
  }
@@ -242,20 +255,13 @@ export class LiopServer {
242
255
  "LIOP v1 Envelope Specification",
243
256
  "================================",
244
257
  "",
245
- "FORMATS (both accepted):",
258
+ "FORMAT:",
246
259
  "",
247
- "Compact:",
260
+ "Compact Envelope:",
248
261
  " @LIOP{wasi_v1,TaskName}",
249
262
  " <JavaScript code>",
250
263
  " @END",
251
264
  "",
252
- "Standard:",
253
- " LIOP_MAGIC:0x00FF",
254
- ' MANIFEST:{"target":"wasi_v1","name":"TaskName","integrity_checks":true}',
255
- " ---BEGIN_LOGIC---",
256
- " <JavaScript code>",
257
- " ---END_LOGIC---",
258
- "",
259
265
  "RUNTIME ENVIRONMENT:",
260
266
  "- env.records: Array of data objects from the origin",
261
267
  "- Must use 'return' to output results",
@@ -406,7 +412,7 @@ export class LiopServer {
406
412
  content: [
407
413
  {
408
414
  type: "text",
409
- text: 'Error: Malformed payload. Missing LIOP_MAGIC, MANIFEST, or boundaries.\nYou MUST wrap your logic exactly like this:\n\nLIOP_MAGIC:0x00FF\nMANIFEST:{"target":"wasi_v1","name":"DynamicAudit","integrity_checks":true}\n---BEGIN_LOGIC---\n// Your JS code here\n---END_LOGIC---',
415
+ text: "Error: Malformed payload. Missing @LIOP boundary.\\nYou MUST wrap your logic exactly like this:\\n\\n@LIOP{wasi_v1,DynamicAudit}\\n// Your JS code here\\n@END",
410
416
  },
411
417
  ],
412
418
  isError: true,
@@ -509,13 +515,11 @@ Your objective is to perform secure Logic-on-Origin injections. You must process
509
515
  INDUSTRIAL CONSTRAINTS & PROTOCOL RULES:
510
516
  1. DATA PRIVACY: NEVER attempt to export Personally Identifiable Information (PII). The LIOP Egress Shield will block any response containing raw IDs, names, or addresses.
511
517
  2. AGGREGATION FIRST: Always prefer returning counts, averages, or anonymized summaries.
512
- 3. PAYLOAD ENCAPSULATION: Your JavaScript payloads MUST strictly adhere to the LIOPv1 Envelope. DO NOT include markdown backticks or leading text inside the 'payload' argument.
518
+ 3. PAYLOAD ENCAPSULATION: Your JavaScript payloads MUST strictly adhere to the Compact Envelope. DO NOT include markdown backticks or leading text inside the 'payload' argument.
513
519
  Structure:
514
- LIOP_MAGIC:0x00FF
515
- MANIFEST:{"target":"wasi_v1","name":"AnalysisTask","integrity_checks":true}
516
- ---BEGIN_LOGIC---
520
+ @LIOP{wasi_v1,AnalysisTask}
517
521
  // Your JS Code Here
518
- ---END_LOGIC---
522
+ @END
519
523
  4. RUNTIME SCOPE: The execution environment provides a global 'env' object. Use 'env.records' to access the target dataset.
520
524
  5. LOCALIZATION: Format all JSON response keys in the language used by the user in their query (e.g., use Spanish keys if the query is in Spanish).
521
525
  6. SCHEMA RIGIDITY: Only use fields defined in the 'Data Dictionary'. Usage of non-existent fields will trigger a sandbox runtime exception.${this.activeSchema
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nekzus/liop",
3
- "version": "1.2.0-alpha.10",
3
+ "version": "1.2.0",
4
4
  "description": "Official SDK for Logic-Injection-on-Origin Protocol (LIOP). Deploy Logic-on-Origin with WebAssembly at gRPC speed and bidirectional MCP compatibility.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",