@tenuo/core 0.2.4-beta.0 → 0.3.0-beta.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.
Files changed (53) hide show
  1. package/README.md +49 -5
  2. package/dist/api.d.ts +416 -17
  3. package/dist/api.js.map +1 -1
  4. package/dist/client.d.ts +59 -2
  5. package/dist/client.js +700 -70
  6. package/dist/client.js.map +1 -1
  7. package/dist/connect.d.ts +53 -0
  8. package/dist/connect.js +177 -0
  9. package/dist/connect.js.map +1 -0
  10. package/dist/constraints.d.ts +54 -3
  11. package/dist/constraints.js +154 -6
  12. package/dist/constraints.js.map +1 -1
  13. package/dist/errors.d.ts +8 -3
  14. package/dist/errors.js +10 -1
  15. package/dist/errors.js.map +1 -1
  16. package/dist/generated/tenuo_wasm.d.ts +136 -7
  17. package/dist/generated/tenuo_wasm.js +398 -9
  18. package/dist/generated/tenuo_wasm_bg.wasm +0 -0
  19. package/dist/generated/tenuo_wasm_bg.wasm.d.ts +40 -22
  20. package/dist/identity.d.ts +25 -0
  21. package/dist/identity.js +61 -0
  22. package/dist/identity.js.map +1 -0
  23. package/dist/index.d.ts +9 -3
  24. package/dist/index.js +5 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/mcp.d.ts +18 -3
  27. package/dist/mcp.js +67 -59
  28. package/dist/mcp.js.map +1 -1
  29. package/dist/nonce.d.ts +6 -1
  30. package/dist/nonce.js +12 -1
  31. package/dist/nonce.js.map +1 -1
  32. package/dist/receipts.d.ts +27 -0
  33. package/dist/receipts.js +128 -0
  34. package/dist/receipts.js.map +1 -0
  35. package/dist/runtime.d.ts +51 -0
  36. package/dist/runtime.js +102 -0
  37. package/dist/runtime.js.map +1 -0
  38. package/dist/session.d.ts +9 -2
  39. package/dist/session.js +56 -0
  40. package/dist/session.js.map +1 -1
  41. package/dist/wasm.d.ts +207 -5
  42. package/dist/wasm.js +62 -4
  43. package/dist/wasm.js.map +1 -1
  44. package/package.json +3 -2
  45. package/dist/api.d.ts.map +0 -1
  46. package/dist/client.d.ts.map +0 -1
  47. package/dist/constraints.d.ts.map +0 -1
  48. package/dist/errors.d.ts.map +0 -1
  49. package/dist/index.d.ts.map +0 -1
  50. package/dist/mcp.d.ts.map +0 -1
  51. package/dist/nonce.d.ts.map +0 -1
  52. package/dist/session.d.ts.map +0 -1
  53. package/dist/wasm.d.ts.map +0 -1
@@ -1,32 +1,180 @@
1
+ import { TenuoConfigurationError } from "./errors.js";
2
+ /**
3
+ * Constraint builders. These produce plain marker objects; every one is
4
+ * evaluated by the Rust core, never in TypeScript. The set matches the
5
+ * Python SDK and the core `Constraint` enum one for one. Builders that
6
+ * validate their input throw `TenuoConfigurationError` at the call site.
7
+ * Deeper checks, such as regex syntax, run in the core when `session()`
8
+ * compiles the policy. Nothing here makes an authorization decision.
9
+ */
1
10
  /** Directory prefix. Evaluated in core as Subpath — not a string prefix check in TS. */
2
- export function under(root) {
11
+ export function under(root, options) {
3
12
  if (!root.startsWith("/")) {
4
- throw new Error("tenuo.under() expects an absolute path (start with /)");
13
+ throw new TenuoConfigurationError("tenuo.under() expects an absolute path (start with /)");
5
14
  }
6
- return { kind: "under", root };
15
+ const out = {
16
+ kind: "under",
17
+ root,
18
+ };
19
+ if (options?.caseSensitive !== undefined) {
20
+ out.caseSensitive = options.caseSensitive;
21
+ }
22
+ if (options?.allowEqual !== undefined) {
23
+ out.allowEqual = options.allowEqual;
24
+ }
25
+ return out;
7
26
  }
8
27
  export function email(options) {
9
28
  return { kind: "email", domain: options.domain };
10
29
  }
11
30
  export function max(value) {
12
31
  if (!Number.isFinite(value)) {
13
- throw new Error("tenuo.max() requires a finite number");
32
+ throw new TenuoConfigurationError("tenuo.max() requires a finite number");
14
33
  }
15
34
  return { kind: "max", value };
16
35
  }
36
+ export function min(value) {
37
+ if (!Number.isFinite(value)) {
38
+ throw new TenuoConfigurationError("tenuo.min() requires a finite number");
39
+ }
40
+ return { kind: "min", value };
41
+ }
42
+ /** Numeric interval. Bounds are inclusive unless `minExclusive` / `maxExclusive`. */
43
+ export function range(options) {
44
+ if (options.min === undefined && options.max === undefined) {
45
+ throw new TenuoConfigurationError("tenuo.range() requires min, max, or both");
46
+ }
47
+ for (const bound of [options.min, options.max]) {
48
+ if (bound !== undefined && !Number.isFinite(bound)) {
49
+ throw new TenuoConfigurationError("tenuo.range() bounds must be finite numbers");
50
+ }
51
+ }
52
+ if (options.min !== undefined && options.max !== undefined && options.min > options.max) {
53
+ throw new TenuoConfigurationError("tenuo.range() min must not exceed max");
54
+ }
55
+ const out = { kind: "range" };
56
+ if (options.min !== undefined) {
57
+ out.min = options.min;
58
+ }
59
+ if (options.max !== undefined) {
60
+ out.max = options.max;
61
+ }
62
+ if (options.minExclusive === true) {
63
+ out.minExclusive = true;
64
+ }
65
+ if (options.maxExclusive === true) {
66
+ out.maxExclusive = true;
67
+ }
68
+ return out;
69
+ }
17
70
  export function oneOf(values) {
18
71
  if (values.length === 0) {
19
- throw new Error("tenuo.oneOf() requires at least one value");
72
+ throw new TenuoConfigurationError("tenuo.oneOf() requires at least one value");
20
73
  }
21
74
  return { kind: "oneOf", values };
22
75
  }
76
+ /** Any value except these. */
77
+ export function notOneOf(values) {
78
+ if (values.length === 0) {
79
+ throw new TenuoConfigurationError("tenuo.notOneOf() requires at least one value");
80
+ }
81
+ return { kind: "notOneOf", values };
82
+ }
23
83
  export function pattern(pattern) {
24
84
  if (pattern.length === 0) {
25
- throw new Error("tenuo.pattern() requires a non-empty pattern");
85
+ throw new TenuoConfigurationError("tenuo.pattern() requires a non-empty pattern");
26
86
  }
27
87
  return { kind: "pattern", pattern };
28
88
  }
89
+ /** Regular expression, compiled and evaluated in core. */
90
+ export function regex(source) {
91
+ if (source.length === 0) {
92
+ throw new TenuoConfigurationError("tenuo.regex() requires a non-empty expression");
93
+ }
94
+ return { kind: "regex", source };
95
+ }
29
96
  export function exact(value) {
30
97
  return { kind: "exact", value };
31
98
  }
99
+ /** Any value at all. Name it in a zero-trust policy to allow an argument without constraining it. */
100
+ export function wildcard() {
101
+ return { kind: "wildcard" };
102
+ }
103
+ /** IP address inside a network, e.g. `cidr("10.0.0.0/8")`. */
104
+ export function cidr(network) {
105
+ if (!network.includes("/")) {
106
+ throw new TenuoConfigurationError("tenuo.cidr() expects CIDR notation like 10.0.0.0/8");
107
+ }
108
+ return { kind: "cidr", network };
109
+ }
110
+ /** URL glob, e.g. `urlPattern("https://*.example.com/api/*")`. Parsed as a URL, not a string. */
111
+ export function urlPattern(pattern) {
112
+ if (pattern.length === 0) {
113
+ throw new TenuoConfigurationError("tenuo.urlPattern() requires a non-empty pattern");
114
+ }
115
+ return { kind: "urlPattern", pattern };
116
+ }
117
+ /**
118
+ * SSRF-aware URL check: http/https only by default, private and link-local
119
+ * hosts rejected, optional allow and deny domain lists (`*.example.com`).
120
+ */
121
+ export function urlSafe(options) {
122
+ const out = { kind: "urlSafe" };
123
+ if (options?.schemes !== undefined) {
124
+ out.schemes = options.schemes;
125
+ }
126
+ if (options?.allowDomains !== undefined) {
127
+ out.allowDomains = options.allowDomains;
128
+ }
129
+ if (options?.denyDomains !== undefined) {
130
+ out.denyDomains = options.denyDomains;
131
+ }
132
+ return out;
133
+ }
134
+ /** Shell command whose first word must be one of `allow`. Parsed with shell quoting rules in core. */
135
+ export function shlex(allow) {
136
+ if (allow.length === 0) {
137
+ throw new TenuoConfigurationError("tenuo.shlex() requires at least one allowed command");
138
+ }
139
+ return { kind: "shlex", allow };
140
+ }
141
+ /** List argument that must include every one of these values. */
142
+ export function contains(values) {
143
+ if (values.length === 0) {
144
+ throw new TenuoConfigurationError("tenuo.contains() requires at least one value");
145
+ }
146
+ return { kind: "contains", values };
147
+ }
148
+ /** List argument whose every element must be one of these values. */
149
+ export function subset(values) {
150
+ if (values.length === 0) {
151
+ throw new TenuoConfigurationError("tenuo.subset() requires at least one value");
152
+ }
153
+ return { kind: "subset", values };
154
+ }
155
+ /** Satisfied when at least one inner constraint is. */
156
+ export function anyOf(constraints) {
157
+ if (constraints.length === 0) {
158
+ throw new TenuoConfigurationError("tenuo.anyOf() requires at least one constraint");
159
+ }
160
+ return { kind: "anyOf", constraints };
161
+ }
162
+ /** Satisfied only when every inner constraint is. */
163
+ export function all(constraints) {
164
+ if (constraints.length === 0) {
165
+ throw new TenuoConfigurationError("tenuo.all() requires at least one constraint");
166
+ }
167
+ return { kind: "all", constraints };
168
+ }
169
+ /** Satisfied when the inner constraint is not. Delegation cannot narrow a `not`; prefer `notOneOf`. */
170
+ export function not(constraint) {
171
+ return { kind: "not", constraint };
172
+ }
173
+ /** Common Expression Language predicate over the argument value, evaluated in core. */
174
+ export function cel(expression) {
175
+ if (expression.trim().length === 0) {
176
+ throw new TenuoConfigurationError("tenuo.cel() requires a non-empty expression");
177
+ }
178
+ return { kind: "cel", expression };
179
+ }
32
180
  //# sourceMappingURL=constraints.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constraints.js","sourceRoot":"","sources":["../src/constraints.ts"],"names":[],"mappings":"AASA,wFAAwF;AACxF,MAAM,UAAU,KAAK,CAAC,IAAY;IAChC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,OAA2B;IAC/C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,KAAa;IAC/B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,MAAyB;IAC7C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,KAAgC;IACpD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"constraints.js","sourceRoot":"","sources":["../src/constraints.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AllConstraint,\n AnyOfConstraint,\n CelConstraint,\n CidrConstraint,\n ConstraintExpr,\n ContainsConstraint,\n EmailConstraint,\n ExactConstraint,\n MaxConstraint,\n MinConstraint,\n NotConstraint,\n NotOneOfConstraint,\n OneOfConstraint,\n PatternConstraint,\n RangeConstraint,\n RegexConstraint,\n ShlexConstraint,\n SubsetConstraint,\n UnderConstraint,\n UrlPatternConstraint,\n UrlSafeConstraint,\n WildcardConstraint,\n} from \"./api.ts\";\nimport { TenuoConfigurationError } from \"./errors.ts\";\n\n/**\n * Constraint builders. These produce plain marker objects; every one is\n * evaluated by the Rust core, never in TypeScript. The set matches the\n * Python SDK and the core `Constraint` enum one for one. Builders that\n * validate their input throw `TenuoConfigurationError` at the call site.\n * Deeper checks, such as regex syntax, run in the core when `session()`\n * compiles the policy. Nothing here makes an authorization decision.\n */\n\n/** Directory prefix. Evaluated in core as Subpath — not a string prefix check in TS. */\nexport function under(\n root: string,\n options?: { readonly caseSensitive?: boolean; readonly allowEqual?: boolean },\n): UnderConstraint {\n if (!root.startsWith(\"/\")) {\n throw new TenuoConfigurationError(\"tenuo.under() expects an absolute path (start with /)\");\n }\n const out: { kind: \"under\"; root: string; caseSensitive?: boolean; allowEqual?: boolean } = {\n kind: \"under\",\n root,\n };\n if (options?.caseSensitive !== undefined) {\n out.caseSensitive = options.caseSensitive;\n }\n if (options?.allowEqual !== undefined) {\n out.allowEqual = options.allowEqual;\n }\n return out;\n}\n\nexport function email(options: { domain: string }): EmailConstraint {\n return { kind: \"email\", domain: options.domain };\n}\n\nexport function max(value: number): MaxConstraint {\n if (!Number.isFinite(value)) {\n throw new TenuoConfigurationError(\"tenuo.max() requires a finite number\");\n }\n return { kind: \"max\", value };\n}\n\nexport function min(value: number): MinConstraint {\n if (!Number.isFinite(value)) {\n throw new TenuoConfigurationError(\"tenuo.min() requires a finite number\");\n }\n return { kind: \"min\", value };\n}\n\n/** Numeric interval. Bounds are inclusive unless `minExclusive` / `maxExclusive`. */\nexport function range(options: {\n readonly min?: number;\n readonly max?: number;\n readonly minExclusive?: boolean;\n readonly maxExclusive?: boolean;\n}): RangeConstraint {\n if (options.min === undefined && options.max === undefined) {\n throw new TenuoConfigurationError(\"tenuo.range() requires min, max, or both\");\n }\n for (const bound of [options.min, options.max]) {\n if (bound !== undefined && !Number.isFinite(bound)) {\n throw new TenuoConfigurationError(\"tenuo.range() bounds must be finite numbers\");\n }\n }\n if (options.min !== undefined && options.max !== undefined && options.min > options.max) {\n throw new TenuoConfigurationError(\"tenuo.range() min must not exceed max\");\n }\n const out: {\n kind: \"range\";\n min?: number;\n max?: number;\n minExclusive?: boolean;\n maxExclusive?: boolean;\n } = { kind: \"range\" };\n if (options.min !== undefined) {\n out.min = options.min;\n }\n if (options.max !== undefined) {\n out.max = options.max;\n }\n if (options.minExclusive === true) {\n out.minExclusive = true;\n }\n if (options.maxExclusive === true) {\n out.maxExclusive = true;\n }\n return out;\n}\n\nexport function oneOf(values: readonly string[]): OneOfConstraint {\n if (values.length === 0) {\n throw new TenuoConfigurationError(\"tenuo.oneOf() requires at least one value\");\n }\n return { kind: \"oneOf\", values };\n}\n\n/** Any value except these. */\nexport function notOneOf(values: readonly string[]): NotOneOfConstraint {\n if (values.length === 0) {\n throw new TenuoConfigurationError(\"tenuo.notOneOf() requires at least one value\");\n }\n return { kind: \"notOneOf\", values };\n}\n\nexport function pattern(pattern: string): PatternConstraint {\n if (pattern.length === 0) {\n throw new TenuoConfigurationError(\"tenuo.pattern() requires a non-empty pattern\");\n }\n return { kind: \"pattern\", pattern };\n}\n\n/** Regular expression, compiled and evaluated in core. */\nexport function regex(source: string): RegexConstraint {\n if (source.length === 0) {\n throw new TenuoConfigurationError(\"tenuo.regex() requires a non-empty expression\");\n }\n return { kind: \"regex\", source };\n}\n\nexport function exact(value: string | number | boolean): ExactConstraint {\n return { kind: \"exact\", value };\n}\n\n/** Any value at all. Name it in a zero-trust policy to allow an argument without constraining it. */\nexport function wildcard(): WildcardConstraint {\n return { kind: \"wildcard\" };\n}\n\n/** IP address inside a network, e.g. `cidr(\"10.0.0.0/8\")`. */\nexport function cidr(network: string): CidrConstraint {\n if (!network.includes(\"/\")) {\n throw new TenuoConfigurationError(\"tenuo.cidr() expects CIDR notation like 10.0.0.0/8\");\n }\n return { kind: \"cidr\", network };\n}\n\n/** URL glob, e.g. `urlPattern(\"https://*.example.com/api/*\")`. Parsed as a URL, not a string. */\nexport function urlPattern(pattern: string): UrlPatternConstraint {\n if (pattern.length === 0) {\n throw new TenuoConfigurationError(\"tenuo.urlPattern() requires a non-empty pattern\");\n }\n return { kind: \"urlPattern\", pattern };\n}\n\n/**\n * SSRF-aware URL check: http/https only by default, private and link-local\n * hosts rejected, optional allow and deny domain lists (`*.example.com`).\n */\nexport function urlSafe(options?: {\n readonly schemes?: readonly string[];\n readonly allowDomains?: readonly string[];\n readonly denyDomains?: readonly string[];\n}): UrlSafeConstraint {\n const out: {\n kind: \"urlSafe\";\n schemes?: readonly string[];\n allowDomains?: readonly string[];\n denyDomains?: readonly string[];\n } = { kind: \"urlSafe\" };\n if (options?.schemes !== undefined) {\n out.schemes = options.schemes;\n }\n if (options?.allowDomains !== undefined) {\n out.allowDomains = options.allowDomains;\n }\n if (options?.denyDomains !== undefined) {\n out.denyDomains = options.denyDomains;\n }\n return out;\n}\n\n/** Shell command whose first word must be one of `allow`. Parsed with shell quoting rules in core. */\nexport function shlex(allow: readonly string[]): ShlexConstraint {\n if (allow.length === 0) {\n throw new TenuoConfigurationError(\"tenuo.shlex() requires at least one allowed command\");\n }\n return { kind: \"shlex\", allow };\n}\n\n/** List argument that must include every one of these values. */\nexport function contains(values: readonly (string | number | boolean)[]): ContainsConstraint {\n if (values.length === 0) {\n throw new TenuoConfigurationError(\"tenuo.contains() requires at least one value\");\n }\n return { kind: \"contains\", values };\n}\n\n/** List argument whose every element must be one of these values. */\nexport function subset(values: readonly (string | number | boolean)[]): SubsetConstraint {\n if (values.length === 0) {\n throw new TenuoConfigurationError(\"tenuo.subset() requires at least one value\");\n }\n return { kind: \"subset\", values };\n}\n\n/** Satisfied when at least one inner constraint is. */\nexport function anyOf(constraints: readonly ConstraintExpr[]): AnyOfConstraint {\n if (constraints.length === 0) {\n throw new TenuoConfigurationError(\"tenuo.anyOf() requires at least one constraint\");\n }\n return { kind: \"anyOf\", constraints };\n}\n\n/** Satisfied only when every inner constraint is. */\nexport function all(constraints: readonly ConstraintExpr[]): AllConstraint {\n if (constraints.length === 0) {\n throw new TenuoConfigurationError(\"tenuo.all() requires at least one constraint\");\n }\n return { kind: \"all\", constraints };\n}\n\n/** Satisfied when the inner constraint is not. Delegation cannot narrow a `not`; prefer `notOneOf`. */\nexport function not(constraint: ConstraintExpr): NotConstraint {\n return { kind: \"not\", constraint };\n}\n\n/** Common Expression Language predicate over the argument value, evaluated in core. */\nexport function cel(expression: string): CelConstraint {\n if (expression.trim().length === 0) {\n throw new TenuoConfigurationError(\"tenuo.cel() requires a non-empty expression\");\n }\n return { kind: \"cel\", expression };\n}\n"]}
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { TenuoErrorCode } from "./api.ts";
1
+ import type { ApprovalRequest, TenuoErrorCode } from "./api.ts";
2
2
  export declare class TenuoError extends Error {
3
3
  readonly code: TenuoErrorCode;
4
4
  constructor(code: TenuoErrorCode, message: string);
@@ -14,6 +14,11 @@ export declare class ApprovalRequiredError extends TenuoError {
14
14
  readonly tool: string;
15
15
  readonly required: number;
16
16
  readonly received: number;
17
- constructor(tool: string, required: number, received: number, message?: string);
17
+ /**
18
+ * What to send to an approval service, when the SDK had the session at
19
+ * hand. Absent on the server-side verify path, where only the caller can
20
+ * build it.
21
+ */
22
+ readonly request?: ApprovalRequest;
23
+ constructor(tool: string, required: number, received: number, message?: string, request?: ApprovalRequest);
18
24
  }
19
- //# sourceMappingURL=errors.d.ts.map
package/dist/errors.js CHANGED
@@ -26,12 +26,21 @@ export class ApprovalRequiredError extends TenuoError {
26
26
  tool;
27
27
  required;
28
28
  received;
29
- constructor(tool, required, received, message) {
29
+ /**
30
+ * What to send to an approval service, when the SDK had the session at
31
+ * hand. Absent on the server-side verify path, where only the caller can
32
+ * build it.
33
+ */
34
+ request;
35
+ constructor(tool, required, received, message, request) {
30
36
  super("TENUO_APPROVAL_REQUIRED", message ?? `Approval required for ${tool}`);
31
37
  this.name = "ApprovalRequiredError";
32
38
  this.tool = tool;
33
39
  this.required = required;
34
40
  this.received = received;
41
+ if (request !== undefined) {
42
+ this.request = request;
43
+ }
35
44
  }
36
45
  }
37
46
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,IAAI,CAAiB;IAE9B,YAAY,IAAoB,EAAE,OAAe;QAC/C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,UAAU;IACrD,YAAY,OAAe,EAAE,OAAuB,qBAAqB;QACvE,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED,MAAM,OAAO,wBAAyB,SAAQ,UAAU;IAC7C,KAAK,CAAU;IAExB,YAAY,IAAoB,EAAE,OAAe,EAAE,KAAc;QAC/D,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,CAAC;IACH,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,UAAU;IAC1C,IAAI,CAAS;IACb,QAAQ,CAAS;IACjB,QAAQ,CAAS;IAE1B,YAAY,IAAY,EAAE,QAAgB,EAAE,QAAgB,EAAE,OAAgB;QAC5E,KAAK,CAAC,yBAAyB,EAAE,OAAO,IAAI,yBAAyB,IAAI,EAAE,CAAC,CAAC;QAC7E,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,IAAI,CAAiB;IAE9B,YAAY,IAAoB,EAAE,OAAe;QAC/C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,UAAU;IACrD,YAAY,OAAe,EAAE,OAAuB,qBAAqB;QACvE,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED,MAAM,OAAO,wBAAyB,SAAQ,UAAU;IAC7C,KAAK,CAAU;IAExB,YAAY,IAAoB,EAAE,OAAe,EAAE,KAAc;QAC/D,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,CAAC;IACH,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,UAAU;IAC1C,IAAI,CAAS;IACb,QAAQ,CAAS;IACjB,QAAQ,CAAS;IAC1B;;;;OAIG;IACM,OAAO,CAAmB;IAEnC,YAAY,IAAY,EAAE,QAAgB,EAAE,QAAgB,EAAE,OAAgB,EAAE,OAAyB;QACvG,KAAK,CAAC,yBAAyB,EAAE,OAAO,IAAI,yBAAyB,IAAI,EAAE,CAAC,CAAC;QAC7E,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACzB,CAAC;IACH,CAAC;CACF","sourcesContent":["import type { ApprovalRequest, TenuoErrorCode } from \"./api.ts\";\n\nexport class TenuoError extends Error {\n readonly code: TenuoErrorCode;\n\n constructor(code: TenuoErrorCode, message: string) {\n super(message);\n this.name = \"TenuoError\";\n this.code = code;\n }\n}\n\nexport class TenuoConfigurationError extends TenuoError {\n constructor(message: string, code: TenuoErrorCode = \"TENUO_CONFIGURATION\") {\n super(code, message);\n this.name = \"TenuoConfigurationError\";\n }\n}\n\nexport class AuthorizationDeniedError extends TenuoError {\n readonly field?: string;\n\n constructor(code: TenuoErrorCode, message: string, field?: string) {\n super(code, message);\n this.name = \"AuthorizationDeniedError\";\n if (field !== undefined) {\n this.field = field;\n }\n }\n}\n\nexport class ApprovalRequiredError extends TenuoError {\n readonly tool: string;\n readonly required: number;\n readonly received: number;\n /**\n * What to send to an approval service, when the SDK had the session at\n * hand. Absent on the server-side verify path, where only the caller can\n * build it.\n */\n readonly request?: ApprovalRequest;\n\n constructor(tool: string, required: number, received: number, message?: string, request?: ApprovalRequest) {\n super(\"TENUO_APPROVAL_REQUIRED\", message ?? `Approval required for ${tool}`);\n this.name = \"ApprovalRequiredError\";\n this.tool = tool;\n this.required = required;\n this.received = received;\n if (request !== undefined) {\n this.request = request;\n }\n }\n}\n"]}
@@ -8,6 +8,17 @@
8
8
  export class SdkContext {
9
9
  free(): void;
10
10
  [Symbol.dispose](): void;
11
+ /**
12
+ * Signed statement from this session's holder that it is the one asking
13
+ * for `tool(args)`. Carried inside a control-plane approval request so
14
+ * the approver can tell a genuine request from a forged one.
15
+ */
16
+ approvalContextAttestation(session: SdkSession, tool: string, args_json: any): any;
17
+ /**
18
+ * Everything an approval service needs to present `tool(args)` to a
19
+ * human and mint a matching `SignedApproval`. Not a signed artifact.
20
+ */
21
+ approvalRequest(session: SdkSession, tool: string, args_json: any): any;
11
22
  /**
12
23
  * Sign PoP and authorize in one call. Never returns allow without a core allow.
13
24
  *
@@ -26,10 +37,36 @@ export class SdkContext {
26
37
  * Null/undefined: no extra ceiling. Empty object: open.
27
38
  */
28
39
  authorizePresented(warrants: any, tool: string, args_json: any, pop: string, approvals: any, tool_allow: any, request_id?: string | null): any;
40
+ /**
41
+ * Explain what the leaf would decide for `tool(args)`, field by field.
42
+ * No proof-of-possession is signed, so this works on any session,
43
+ * including one issued to another holder.
44
+ */
45
+ explain(session: SdkSession, tool: string, args_json: any): any;
46
+ /**
47
+ * Issuer context from a stable 32-byte Ed25519 secret. Its own public
48
+ * key is trusted; `extra_roots` (hex) are trusted as well, so one
49
+ * process can verify chains from several control planes.
50
+ */
51
+ static fromIssuerSecret(secret: Uint8Array, extra_roots: any): SdkContext;
29
52
  /**
30
53
  * Authorizer-only context. `mint()` fails; import a session from the wire.
31
54
  */
32
55
  static fromTrustedRoots(roots: any): SdkContext;
56
+ /**
57
+ * Issue an execution session from an issuer session. The issuer
58
+ * session's holder signs; core checks the tools against
59
+ * `issuableTools`, constraints against `constraintBounds`, clearance,
60
+ * and issue depth. No control-plane key is involved.
61
+ */
62
+ issue(issuer: SdkSession, options: any): SdkSession;
63
+ /**
64
+ * Public key of the local issuer, hex. Verifier-only contexts have none.
65
+ *
66
+ * This is what other processes put in `trustedRoots` to accept warrants
67
+ * this context mints. It is a public key: sharing it grants nothing.
68
+ */
69
+ issuerPublicKey(): string;
33
70
  /**
34
71
  * Load a published SignedRevocationList. The SRL must be signed by a trusted root.
35
72
  */
@@ -40,12 +77,33 @@ export class SdkContext {
40
77
  *
41
78
  * `require_approval` is optional:
42
79
  * `{ "approvers": ["hex..."], "min": 2, "tools": ["transfer"] }`
80
+ *
81
+ * `holder_hex` binds the warrant to another agent's public key. The
82
+ * returned session then has no holder secret: export it with `toWire()`
83
+ * and let that agent import it. Omit it to mint a local session with a
84
+ * fresh holder key.
85
+ *
86
+ * `max_depth` caps how many times the authority may be delegated below
87
+ * the root (0 = terminal). Omit for the protocol maximum.
88
+ */
89
+ mint(allow_json: any, ttl_seconds: number, require_approval: any, holder_hex?: string | null, max_depth?: number | null): SdkSession;
90
+ /**
91
+ * `mint()` with every option the protocol offers: kind, clearance,
92
+ * session and agent ids, approval gates with messages and per-argument
93
+ * triggers, and issuer-warrant fields. Keys are camelCase; unknown keys
94
+ * are rejected.
43
95
  */
44
- mint(allow_json: any, ttl_seconds: number, require_approval: any): SdkSession;
96
+ mintExtended(options: any): SdkSession;
45
97
  /**
46
- * Attenuate the leaf. The current holder signs; the same holder keeps the child.
98
+ * Attenuate the leaf. The current holder signs.
99
+ *
100
+ * Without `options.holder` the same holder keeps the child. With it, the
101
+ * child is bound to that public key: this is delegation to another agent,
102
+ * and the returned session carries no holder secret (see `SdkSession`).
103
+ * Core rejects any child that is not within its parent — tools,
104
+ * constraints, lifetime, and depth — before a token exists.
47
105
  */
48
- narrow(session: SdkSession, allow_json: any): SdkSession;
106
+ narrow(session: SdkSession, allow_json: any, options: any): SdkSession;
49
107
  constructor();
50
108
  /**
51
109
  * Holder PoP only. Does not authorize. Used to fill `_meta.tenuo.signature`.
@@ -55,10 +113,25 @@ export class SdkContext {
55
113
  * Test / host seam. Signs an SRL with the local issuer. Does not load it.
56
114
  */
57
115
  signRevocationList(ids: any): string;
116
+ /**
117
+ * Sign a revocation list with this context's issuer key. Load it with
118
+ * `loadRevocationList` anywhere this issuer is a trusted root.
119
+ */
120
+ signRevocationListVersioned(ids: any, version?: number | null): string;
121
+ /**
122
+ * Sign verifier receipts with this 32-byte holder secret instead of an
123
+ * ephemeral key. Used by the TypeScript `Runtime`.
124
+ */
125
+ withReceiptSigner(secret: Uint8Array): SdkContext;
58
126
  }
59
127
 
60
128
  /**
61
129
  * Opaque warrant chain (root first) + leaf holder key. Not JSON-serializable from JS.
130
+ *
131
+ * `holder` is `None` when the leaf was issued or delegated to another agent's
132
+ * key. Such a session can be exported with `toWire()` and handed over, but it
133
+ * cannot sign proof-of-possession here; the holder imports it with
134
+ * `SdkSession.fromWire` and its own secret.
62
135
  */
63
136
  export class SdkSession {
64
137
  private constructor();
@@ -69,6 +142,11 @@ export class SdkSession {
69
142
  * Not a PoP. MCP replay uses the PoP signature, not this key.
70
143
  */
71
144
  dedupKey(tool: string, args_json: any): string;
145
+ /**
146
+ * Public view of the leaf: holder public key, depth, ceiling, lifetime,
147
+ * tools. Never the holder secret.
148
+ */
149
+ describe(): any;
72
150
  /**
73
151
  * Test / interop seam. Not on the public TypeScript Session type.
74
152
  */
@@ -99,6 +177,16 @@ export class SdkSession {
99
177
  warrantIds(): any;
100
178
  }
101
179
 
180
+ /**
181
+ * Typed preflight of a warrant's approval gates for `(tool, args)`.
182
+ *
183
+ * Returns `{ status: "not_gated"|"exempt"|"required"|"denied", tool, kind?,
184
+ * argument?, arguments, message?, code?, reason?, error? }`. Parse errors
185
+ * fail closed with `status: "required"` and `error` set (no fabricated
186
+ * `kind`). `denied` means the warrant's constraints refuse the call.
187
+ */
188
+ export function approval_requirement(warrant_b64: string, tool: string, args_json: any): any;
189
+
102
190
  export function check_access(warrant_b64: string, tool: string, args_json: any, trusted_root_hex: string, dry_run: boolean): any;
103
191
 
104
192
  /**
@@ -175,6 +263,9 @@ export function decode_warrant(base64_warrant: string): any;
175
263
  * Returns `{ approval_required: true/false, tool, error }`.
176
264
  * This reads `extensions["tenuo.approval_gates"]` from the warrant, parses it,
177
265
  * and runs the gate evaluation logic from tenuo-core.
266
+ *
267
+ * Malformed warrants, gate maps, or arguments fail closed (`approval_required: true`).
268
+ * Prefer `approval_requirement` when the caller must distinguish exemptions.
178
269
  */
179
270
  export function evaluate_approval_gates(warrant_b64: string, tool: string, args_json: any): any;
180
271
 
@@ -186,25 +277,58 @@ export function generate_keypair(): any;
186
277
  export function init_panic_hook(): void;
187
278
 
188
279
  /**
189
- * Parse a `TENUO_CONNECT_TOKEN` string into its component fields.
280
+ * Inspect how a warrant gates `tool`, without evaluating arguments.
190
281
  *
191
- * The token is a base64url-encoded JSON blob: `{ v, e, k, a?, t? }`.
192
- * This WASM binding keeps the parsing canonical so TypeScript doesn't need
193
- * to duplicate the decode logic.
282
+ * Returns `{ kind: "none"|"whole_tool"|"conditional", tool, arguments, message?, error? }`.
283
+ * Parse errors fail closed with `kind: "unknown"` and `error` set so callers
284
+ * cannot treat a malformed map as ungated.
285
+ */
286
+ export function inspect_approval_gate(warrant_b64: string, tool: string): any;
287
+
288
+ /**
289
+ * Parse a complete `tenuo_ct_…` token into its component fields.
290
+ *
291
+ * Accepts padded and unpadded Base64URL. Version must be 1; omitted `v`
292
+ * is an error. Trailing `/v1` is stripped from `e`.
293
+ * Registration-token aliases: `t`, `r`, `registration_token`.
194
294
  *
195
295
  * Returns `{ endpoint, apiKey, agentId?, registrationToken?, error? }`.
196
296
  */
197
297
  export function parse_connect_token(token: string): any;
198
298
 
299
+ /**
300
+ * Decode and check an approval envelope. Not authorization.
301
+ */
302
+ export function sdkInspectApproval(envelope: string): any;
303
+
199
304
  export function sdkInspectParts(payload_hex: string, signature_hex: string): any;
200
305
 
306
+ /**
307
+ * Decode a signed revocation list without loading it.
308
+ */
309
+ export function sdkInspectRevocationList(wire: string): any;
310
+
201
311
  export function sdkInspectWarrant(wire: string): any;
202
312
 
313
+ export function sdkProtocolLimits(): any;
314
+
315
+ /**
316
+ * Public key (hex) for a 32-byte Ed25519 holder secret. What an agent hands
317
+ * to whoever will issue or delegate a warrant to it.
318
+ */
319
+ export function sdkPublicKeyFromHolderKey(holder_secret: Uint8Array): string;
320
+
203
321
  /**
204
322
  * Test / host seam. Signs a SignedApproval envelope; does not authorize.
205
323
  */
206
324
  export function sdkSignApproval(session: SdkSession, tool: string, args_json: any, approver_secret: Uint8Array, external_id: string, as_of?: number | null): string;
207
325
 
326
+ /**
327
+ * Sign an approval for a request hash. The approver never needs the
328
+ * warrant or the holder key; the hash already commits to both.
329
+ */
330
+ export function sdkSignApprovalForRequest(request_hash_hex: string, approver_secret: Uint8Array, external_id: string, ttl_seconds?: number | null, warrant_expires_at?: number | null): string;
331
+
208
332
  /**
209
333
  * Test seam. Signs the published generator envelope (not the in-memory SRL codec).
210
334
  */
@@ -215,6 +339,11 @@ export function sdkSignPublishedRevocationList(ids: any, version: number, issuer
215
339
  */
216
340
  export function sdkSignRevocationList(ids: any, issuer_secret: Uint8Array): string;
217
341
 
342
+ /**
343
+ * Sign a revocation list with an explicit issuer secret (control-plane path).
344
+ */
345
+ export function sdkSignRevocationListVersioned(ids: any, version: number | null | undefined, issuer_secret: Uint8Array): string;
346
+
218
347
  /**
219
348
  * Signature authenticity only. Not authorization.
220
349
  */