@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
@@ -0,0 +1,61 @@
1
+ import { TenuoConfigurationError } from "./errors.js";
2
+ import { loadWasm, publicKeyHexFromHolderKey } from "./wasm.js";
3
+ const inspect = Symbol.for("nodejs.util.inspect.custom");
4
+ const secrets = new WeakMap();
5
+ /**
6
+ * Holder keypair. Core owns the representation; persistence is the caller's
7
+ * job (or a later Node adapter). The secret never appears in stringification,
8
+ * inspection, or JSON.
9
+ */
10
+ export class HolderIdentity {
11
+ publicKey;
12
+ constructor(holderKey) {
13
+ if (!(holderKey instanceof Uint8Array) || holderKey.length !== 32) {
14
+ throw new TenuoConfigurationError("HolderIdentity requires a 32-byte holder key");
15
+ }
16
+ loadWasm();
17
+ secrets.set(this, new Uint8Array(holderKey));
18
+ this.publicKey = {
19
+ kind: "public-key",
20
+ source: "bytes",
21
+ hex: publicKeyHexFromHolderKey(holderKey),
22
+ };
23
+ }
24
+ /** Copy of the 32-byte Ed25519 secret. */
25
+ get holderKey() {
26
+ const secret = secrets.get(this);
27
+ if (secret === undefined) {
28
+ throw new TenuoConfigurationError("identity is not bound to a holder key");
29
+ }
30
+ return new Uint8Array(secret);
31
+ }
32
+ toJSON() {
33
+ return { publicKey: this.publicKey.hex };
34
+ }
35
+ toString() {
36
+ return `TenuoIdentity(${this.publicKey.hex.slice(0, 8)}…)`;
37
+ }
38
+ [inspect]() {
39
+ return this.toJSON();
40
+ }
41
+ }
42
+ /** Import a 32-byte holder secret. */
43
+ export function identityFromKey(holderKey) {
44
+ if (!(holderKey instanceof Uint8Array) || holderKey.length !== 32) {
45
+ throw new TenuoConfigurationError("identity() requires a 32-byte holder key");
46
+ }
47
+ loadWasm();
48
+ return new HolderIdentity(holderKey);
49
+ }
50
+ /** Fresh holder identity. Uses Web Crypto; does not touch the filesystem. */
51
+ export function generateIdentity() {
52
+ return identityFromKey(randomSecret());
53
+ }
54
+ function randomSecret() {
55
+ const cryptoObj = globalThis.crypto;
56
+ if (cryptoObj === undefined || typeof cryptoObj.getRandomValues !== "function") {
57
+ throw new TenuoConfigurationError("generateIdentity() needs Web Crypto (globalThis.crypto.getRandomValues).");
58
+ }
59
+ return cryptoObj.getRandomValues(new Uint8Array(32));
60
+ }
61
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAEhE,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;AACzD,MAAM,OAAO,GAAG,IAAI,OAAO,EAA8B,CAAC;AAE1D;;;;GAIG;AACH,MAAM,OAAO,cAAc;IAChB,SAAS,CAAkB;IAEpC,YAAY,SAAqB;QAC/B,IAAI,CAAC,CAAC,SAAS,YAAY,UAAU,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;YAClE,MAAM,IAAI,uBAAuB,CAAC,8CAA8C,CAAC,CAAC;QACpF,CAAC;QACD,QAAQ,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,SAAS,GAAG;YACf,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,OAAO;YACf,GAAG,EAAE,yBAAyB,CAAC,SAAS,CAAC;SAC1C,CAAC;IACJ,CAAC;IAED,0CAA0C;IAC1C,IAAI,SAAS;QACX,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,uBAAuB,CAAC,uCAAuC,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,MAAM;QACJ,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;IAC3C,CAAC;IAED,QAAQ;QACN,OAAO,iBAAiB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;IAC7D,CAAC;IAED,CAAC,OAAO,CAAC;QACP,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;IACvB,CAAC;CACF;AAED,sCAAsC;AACtC,MAAM,UAAU,eAAe,CAAC,SAAqB;IACnD,IAAI,CAAC,CAAC,SAAS,YAAY,UAAU,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAClE,MAAM,IAAI,uBAAuB,CAAC,0CAA0C,CAAC,CAAC;IAChF,CAAC;IACD,QAAQ,EAAE,CAAC;IACX,OAAO,IAAI,cAAc,CAAC,SAAS,CAAC,CAAC;AACvC,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,gBAAgB;IAC9B,OAAO,eAAe,CAAC,YAAY,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC;IACpC,IAAI,SAAS,KAAK,SAAS,IAAI,OAAO,SAAS,CAAC,eAAe,KAAK,UAAU,EAAE,CAAC;QAC/E,MAAM,IAAI,uBAAuB,CAC/B,0EAA0E,CAC3E,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;AACvD,CAAC","sourcesContent":["import type { PublicKeyHandle } from \"./api.ts\";\nimport { TenuoConfigurationError } from \"./errors.ts\";\nimport { loadWasm, publicKeyHexFromHolderKey } from \"./wasm.ts\";\n\nconst inspect = Symbol.for(\"nodejs.util.inspect.custom\");\nconst secrets = new WeakMap<HolderIdentity, Uint8Array>();\n\n/**\n * Holder keypair. Core owns the representation; persistence is the caller's\n * job (or a later Node adapter). The secret never appears in stringification,\n * inspection, or JSON.\n */\nexport class HolderIdentity {\n readonly publicKey: PublicKeyHandle;\n\n constructor(holderKey: Uint8Array) {\n if (!(holderKey instanceof Uint8Array) || holderKey.length !== 32) {\n throw new TenuoConfigurationError(\"HolderIdentity requires a 32-byte holder key\");\n }\n loadWasm();\n secrets.set(this, new Uint8Array(holderKey));\n this.publicKey = {\n kind: \"public-key\",\n source: \"bytes\",\n hex: publicKeyHexFromHolderKey(holderKey),\n };\n }\n\n /** Copy of the 32-byte Ed25519 secret. */\n get holderKey(): Uint8Array {\n const secret = secrets.get(this);\n if (secret === undefined) {\n throw new TenuoConfigurationError(\"identity is not bound to a holder key\");\n }\n return new Uint8Array(secret);\n }\n\n toJSON(): { readonly publicKey: string } {\n return { publicKey: this.publicKey.hex };\n }\n\n toString(): string {\n return `TenuoIdentity(${this.publicKey.hex.slice(0, 8)}…)`;\n }\n\n [inspect](): { readonly publicKey: string } {\n return this.toJSON();\n }\n}\n\n/** Import a 32-byte holder secret. */\nexport function identityFromKey(holderKey: Uint8Array): HolderIdentity {\n if (!(holderKey instanceof Uint8Array) || holderKey.length !== 32) {\n throw new TenuoConfigurationError(\"identity() requires a 32-byte holder key\");\n }\n loadWasm();\n return new HolderIdentity(holderKey);\n}\n\n/** Fresh holder identity. Uses Web Crypto; does not touch the filesystem. */\nexport function generateIdentity(): HolderIdentity {\n return identityFromKey(randomSecret());\n}\n\nfunction randomSecret(): Uint8Array {\n const cryptoObj = globalThis.crypto;\n if (cryptoObj === undefined || typeof cryptoObj.getRandomValues !== \"function\") {\n throw new TenuoConfigurationError(\n \"generateIdentity() needs Web Crypto (globalThis.crypto.getRandomValues).\",\n );\n }\n return cryptoObj.getRandomValues(new Uint8Array(32));\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,13 @@
1
- export type { AllowPolicy, ApprovalRequest, ConstraintExpr, CreateTenuoOptions, Decision, DevRoot, EmailConstraint, ExactConstraint, ExecuteOptions, MaxConstraint, McpAttachOptions, McpCallParams, McpHandlerPolicy, McpJsonRpcError, McpVerifyOptions, NarrowInput, NonceStore, OneOfConstraint, PatternConstraint, ProtectedTool, PublicKeyHandle, RequireApproval, Session, SessionAllow, SessionFromWireInput, SessionInput, Tenuo, TenuoErrorCode, TenuoMcp, TenuoMcpMeta, ToolLike, WarrantPart, ToolPolicy, UnderConstraint, } from "./api.ts";
1
+ export type { ApprovalGateInspection, ApprovalRequirement, ApprovalRequirementStatus, } from "./wasm.ts";
2
+ export { approvalRequirement, evaluateApprovalGates, inspectApprovalGate } from "./wasm.ts";
3
+ export type { AllConstraint, AllowPolicy, AnyOfConstraint, ApprovalContextAttestation, ApprovalInfo, ApprovalRequest, ApprovalRequestSummary, ArgApprovalGate, CelConstraint, CidrConstraint, Clearance, ConstraintExpr, ContainsConstraint, ControlPlaneApprovalRequestV1, ControlPlaneApprovalResponseV1, CreateTenuoOptions, Decision, DevRoot, EmailConstraint, ExactConstraint, ExecuteOptions, ExplainedField, Explanation, IssueInput, IssuerKey, MaxConstraint, McpAttachOptions, McpCallParams, McpHandlerPolicy, McpJsonRpcError, McpVerifyOptions, MinConstraint, NarrowInput, NarrowOptions, NonceStore, NotConstraint, NotOneOfConstraint, OneOfConstraint, PatternConstraint, PresentedCall, ProtectedTool, PublicKeyHandle, RangeConstraint, ReceiptChainInfo, ReceiptInfo, RegexConstraint, RequireApproval, RevocationListInfo, RevocationListInput, Session, SessionAllow, SessionFromWireInput, SessionInfo, SessionInput, ShlexConstraint, SignApprovalOptions, SubsetConstraint, Tenuo, LegacyTenuoErrorCode, ProtocolDenialCode, TenuoErrorCode, TenuoMcp, TenuoMcpMeta, ToolApprovalGate, ToolLike, ToolPolicy, UnderConstraint, UrlPatternConstraint, UrlSafeConstraint, WarrantPart, WildcardConstraint, } from "./api.ts";
2
4
  export { ApprovalRequiredError, AuthorizationDeniedError, TenuoConfigurationError, TenuoError, } from "./errors.ts";
3
- export { email, exact, max, oneOf, pattern, under } from "./constraints.ts";
5
+ export { all, anyOf, cel, cidr, contains, email, exact, max, min, not, notOneOf, oneOf, pattern, range, regex, shlex, subset, under, urlPattern, urlSafe, wildcard, } from "./constraints.ts";
4
6
  export { memoryNonceStore } from "./nonce.ts";
5
7
  export { Session as SessionHandle, isSession } from "./session.ts";
8
+ export { ConnectToken, parseConnectToken } from "./connect.ts";
9
+ export type { ResolveEndpointOptions } from "./connect.ts";
10
+ export { HolderIdentity, generateIdentity, identityFromKey } from "./identity.ts";
11
+ export { Runtime } from "./runtime.ts";
12
+ export type { ReceiptsMode, RuntimeOptions, SessionWarrant } from "./runtime.ts";
6
13
  export { createTenuo } from "./client.ts";
7
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
+ export { approvalRequirement, evaluateApprovalGates, inspectApprovalGate } from "./wasm.js";
1
2
  export { ApprovalRequiredError, AuthorizationDeniedError, TenuoConfigurationError, TenuoError, } from "./errors.js";
2
- export { email, exact, max, oneOf, pattern, under } from "./constraints.js";
3
+ export { all, anyOf, cel, cidr, contains, email, exact, max, min, not, notOneOf, oneOf, pattern, range, regex, shlex, subset, under, urlPattern, urlSafe, wildcard, } from "./constraints.js";
3
4
  export { memoryNonceStore } from "./nonce.js";
4
5
  export { Session as SessionHandle, isSession } from "./session.js";
6
+ export { ConnectToken, parseConnectToken } from "./connect.js";
7
+ export { HolderIdentity, generateIdentity, identityFromKey } from "./identity.js";
8
+ export { Runtime } from "./runtime.js";
5
9
  export { createTenuo } from "./client.js";
6
10
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAqCA,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,UAAU,GACX,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEnE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AA4E5F,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,UAAU,GACX,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,GAAG,EACH,KAAK,EACL,GAAG,EACH,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,KAAK,EACL,GAAG,EACH,GAAG,EACH,GAAG,EACH,QAAQ,EACR,KAAK,EACL,OAAO,EACP,KAAK,EACL,KAAK,EACL,KAAK,EACL,MAAM,EACN,KAAK,EACL,UAAU,EACV,OAAO,EACP,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEnE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAElF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC","sourcesContent":["export type {\n ApprovalGateInspection,\n ApprovalRequirement,\n ApprovalRequirementStatus,\n} from \"./wasm.ts\";\n\nexport { approvalRequirement, evaluateApprovalGates, inspectApprovalGate } from \"./wasm.ts\";\n\nexport type {\n AllConstraint,\n AllowPolicy,\n AnyOfConstraint,\n ApprovalContextAttestation,\n ApprovalInfo,\n ApprovalRequest,\n ApprovalRequestSummary,\n ArgApprovalGate,\n CelConstraint,\n CidrConstraint,\n Clearance,\n ConstraintExpr,\n ContainsConstraint,\n ControlPlaneApprovalRequestV1,\n ControlPlaneApprovalResponseV1,\n CreateTenuoOptions,\n Decision,\n DevRoot,\n EmailConstraint,\n ExactConstraint,\n ExecuteOptions,\n ExplainedField,\n Explanation,\n IssueInput,\n IssuerKey,\n MaxConstraint,\n McpAttachOptions,\n McpCallParams,\n McpHandlerPolicy,\n McpJsonRpcError,\n McpVerifyOptions,\n MinConstraint,\n NarrowInput,\n NarrowOptions,\n NonceStore,\n NotConstraint,\n NotOneOfConstraint,\n OneOfConstraint,\n PatternConstraint,\n PresentedCall,\n ProtectedTool,\n PublicKeyHandle,\n RangeConstraint,\n ReceiptChainInfo,\n ReceiptInfo,\n RegexConstraint,\n RequireApproval,\n RevocationListInfo,\n RevocationListInput,\n Session,\n SessionAllow,\n SessionFromWireInput,\n SessionInfo,\n SessionInput,\n ShlexConstraint,\n SignApprovalOptions,\n SubsetConstraint,\n Tenuo,\n LegacyTenuoErrorCode,\n ProtocolDenialCode,\n TenuoErrorCode,\n TenuoMcp,\n TenuoMcpMeta,\n ToolApprovalGate,\n ToolLike,\n ToolPolicy,\n UnderConstraint,\n UrlPatternConstraint,\n UrlSafeConstraint,\n WarrantPart,\n WildcardConstraint,\n} from \"./api.ts\";\n\nexport {\n ApprovalRequiredError,\n AuthorizationDeniedError,\n TenuoConfigurationError,\n TenuoError,\n} from \"./errors.ts\";\n\nexport {\n all,\n anyOf,\n cel,\n cidr,\n contains,\n email,\n exact,\n max,\n min,\n not,\n notOneOf,\n oneOf,\n pattern,\n range,\n regex,\n shlex,\n subset,\n under,\n urlPattern,\n urlSafe,\n wildcard,\n} from \"./constraints.ts\";\n\nexport { memoryNonceStore } from \"./nonce.ts\";\n\nexport { Session as SessionHandle, isSession } from \"./session.ts\";\n\nexport { ConnectToken, parseConnectToken } from \"./connect.ts\";\nexport type { ResolveEndpointOptions } from \"./connect.ts\";\n\nexport { HolderIdentity, generateIdentity, identityFromKey } from \"./identity.ts\";\n\nexport { Runtime } from \"./runtime.ts\";\nexport type { ReceiptsMode, RuntimeOptions, SessionWarrant } from \"./runtime.ts\";\n\nexport { createTenuo } from \"./client.ts\";\n"]}
package/dist/mcp.d.ts CHANGED
@@ -1,4 +1,19 @@
1
- import type { TenuoMcp } from "./api.ts";
1
+ import type { McpAttachOptions, McpVerifyOptions, PresentedCall, Session as SessionContract, TenuoMcp } from "./api.ts";
2
2
  import type { WasmContext, WasmDecision } from "./wasm.ts";
3
- export declare function createMcp(context: WasmContext, decide: (decision: WasmDecision, tool: string) => void): TenuoMcp;
4
- //# sourceMappingURL=mcp.d.ts.map
3
+ export type Decide = (decision: WasmDecision, tool: string, native?: object, args?: Record<string, unknown>) => void;
4
+ /**
5
+ * Transport-agnostic half of `attach`: authorize locally, then sign
6
+ * proof-of-possession over the call. Shared by `tenuo.present()` and
7
+ * `tenuo.mcp.attach()`.
8
+ */
9
+ export declare function presentCall(context: WasmContext, decide: Decide, session: SessionContract, name: string, args: Readonly<Record<string, unknown>>, options: McpAttachOptions | undefined, label: string, host?: object): {
10
+ readonly presented: PresentedCall;
11
+ readonly wireArgs: Record<string, unknown>;
12
+ };
13
+ /**
14
+ * Transport-agnostic half of `verify`: check a presented warrant chain and
15
+ * proof-of-possession, then apply the host ceiling. Shared by
16
+ * `tenuo.verify()` and `tenuo.mcp.verify()`.
17
+ */
18
+ export declare function verifyPresented(context: WasmContext, decide: Decide, presented: PresentedCall, name: string, args: Readonly<Record<string, unknown>>, options: McpVerifyOptions | undefined, label: string, host?: object): Promise<Readonly<Record<string, unknown>>>;
19
+ export declare function createMcp(context: WasmContext, decide: Decide, host?: object): TenuoMcp;
package/dist/mcp.js CHANGED
@@ -1,50 +1,65 @@
1
- import { ApprovalRequiredError, AuthorizationDeniedError, TenuoConfigurationError, TenuoError } from "./errors.js";
1
+ import { AuthorizationDeniedError, TenuoConfigurationError, TenuoError } from "./errors.js";
2
+ import { collectReceipt, emitIsolatedReceipt } from "./receipts.js";
2
3
  import { nativeSession } from "./session.js";
3
- export function createMcp(context, decide) {
4
+ /**
5
+ * Transport-agnostic half of `attach`: authorize locally, then sign
6
+ * proof-of-possession over the call. Shared by `tenuo.present()` and
7
+ * `tenuo.mcp.attach()`.
8
+ */
9
+ export function presentCall(context, decide, session, name, args, options, label, host) {
10
+ if (options !== undefined) {
11
+ assertKnownKeys(options, ATTACH_OPTION_KEYS, `${label} options`);
12
+ }
13
+ const native = nativeSession(session);
14
+ const wireArgs = stripNulls(args);
15
+ const local = context.authorize(native, name, wireArgs, options?.approvals, undefined, options?.requestId);
16
+ emitReceipt(options?.onReceipt, local.receipt, session, host);
17
+ decide(local, name, native, wireArgs);
18
+ const signature = context.signPop(native, name, wireArgs);
19
+ const warrant = stackWire(native);
20
+ if (options?.approvals !== undefined && options.approvals.length > 0) {
21
+ return {
22
+ presented: { warrant, signature, approvals: options.approvals.map(approvalWire) },
23
+ wireArgs,
24
+ };
25
+ }
26
+ return { presented: { warrant, signature }, wireArgs };
27
+ }
28
+ /**
29
+ * Transport-agnostic half of `verify`: check a presented warrant chain and
30
+ * proof-of-possession, then apply the host ceiling. Shared by
31
+ * `tenuo.verify()` and `tenuo.mcp.verify()`.
32
+ */
33
+ export async function verifyPresented(context, decide, presented, name, args, options, label, host) {
34
+ if (options !== undefined) {
35
+ assertKnownKeys(options, VERIFY_OPTION_KEYS, `${label} options`);
36
+ }
37
+ const envelope = presentedEnvelope(presented);
38
+ if (envelope === undefined) {
39
+ throw new TenuoConfigurationError(`${label} needs { warrant, signature } from tenuo.present() or tenuo.mcp.attach()`);
40
+ }
41
+ const decision = context.authorizePresented(envelope.warrant, name, stripNulls(args), envelope.signature, envelope.approvals, options?.allow, options?.requestId);
42
+ // Rust already signed this envelope. Emit before the nonce store can
43
+ // refuse a replay — otherwise an attacker leaves no audit artifact.
44
+ emitReceipt(options?.onReceipt, decision.receipt, undefined, host);
45
+ if (decision.outcome === "allow") {
46
+ await admitPop(options?.nonceStore, envelope.signature, options?.onNonceStoreError);
47
+ }
48
+ decide(decision, name);
49
+ return plainArgs(decision.args);
50
+ }
51
+ export function createMcp(context, decide, host) {
4
52
  const mcp = {
5
53
  attach(session, name, args, options) {
6
- if (options !== undefined) {
7
- assertKnownKeys(options, ATTACH_OPTION_KEYS, "mcp.attach() options");
8
- }
9
- const native = nativeSession(session);
10
- const wireArgs = stripNulls(args);
11
- const local = context.authorize(native, name, wireArgs, options?.approvals, undefined, options?.requestId);
12
- emitReceipt(options?.onReceipt, local.receipt);
13
- decide(local, name);
14
- const signature = context.signPop(native, name, wireArgs);
15
- const warrant = stackWire(native);
16
- const tenuo = { warrant, signature };
17
- if (options?.approvals !== undefined && options.approvals.length > 0) {
18
- return {
19
- name,
20
- arguments: wireArgs,
21
- _meta: {
22
- tenuo: {
23
- ...tenuo,
24
- approvals: options.approvals.map(approvalWire),
25
- },
26
- },
27
- };
28
- }
29
- return { name, arguments: wireArgs, _meta: { tenuo } };
54
+ const { presented, wireArgs } = presentCall(context, decide, session, name, args, options, "mcp.attach()", host);
55
+ return { name, arguments: wireArgs, _meta: { tenuo: presented } };
30
56
  },
31
57
  async verify(name, args, meta, options) {
32
- if (options !== undefined) {
33
- assertKnownKeys(options, VERIFY_OPTION_KEYS, "mcp.verify() options");
34
- }
35
58
  const envelope = tenuoEnvelope(meta);
36
59
  if (envelope === undefined) {
37
60
  throw new TenuoConfigurationError("MCP call is missing _meta.tenuo. The client must call tenuo.mcp.attach().");
38
61
  }
39
- const decision = context.authorizePresented(envelope.warrant, name, stripNulls(args), envelope.signature, envelope.approvals, options?.allow, options?.requestId);
40
- // Rust already signed this envelope. Emit before the nonce store can
41
- // refuse a replay — otherwise an attacker leaves no audit artifact.
42
- emitReceipt(options?.onReceipt, decision.receipt);
43
- if (decision.outcome === "allow") {
44
- await admitPop(options?.nonceStore, envelope.signature, options?.onNonceStoreError);
45
- }
46
- decide(decision, name);
47
- return plainArgs(decision.args);
62
+ return verifyPresented(context, decide, envelope, name, args, options, "mcp.verify()", host);
48
63
  },
49
64
  handler(name, policyOrExecute, maybeExecute) {
50
65
  const policy = isHandlerPolicy(policyOrExecute) ? policyOrExecute : undefined;
@@ -85,16 +100,11 @@ function approvalWire(value) {
85
100
  }
86
101
  return Buffer.from(value).toString("base64");
87
102
  }
88
- function tenuoEnvelope(meta) {
89
- if (meta === null || typeof meta !== "object") {
90
- return undefined;
91
- }
92
- const root = meta;
93
- const block = root.tenuo ?? root._meta?.tenuo;
94
- if (block === null || typeof block !== "object") {
103
+ function presentedEnvelope(value) {
104
+ if (value === null || typeof value !== "object") {
95
105
  return undefined;
96
106
  }
97
- const tenuo = block;
107
+ const tenuo = value;
98
108
  if (typeof tenuo.warrant !== "string" || tenuo.warrant.length === 0) {
99
109
  return undefined;
100
110
  }
@@ -110,6 +120,14 @@ function tenuoEnvelope(meta) {
110
120
  ...(approvals !== undefined && approvals.length > 0 ? { approvals } : {}),
111
121
  };
112
122
  }
123
+ function tenuoEnvelope(meta) {
124
+ if (meta === null || typeof meta !== "object") {
125
+ return undefined;
126
+ }
127
+ const root = meta;
128
+ const block = root.tenuo ?? root._meta?.tenuo;
129
+ return presentedEnvelope(block);
130
+ }
113
131
  const HANDLER_POLICY_KEYS = new Set(["allow", "onReceipt", "nonceStore", "onNonceStoreError"]);
114
132
  const VERIFY_OPTION_KEYS = new Set([
115
133
  "allow",
@@ -192,19 +210,9 @@ function emitIsolated(hook, error) {
192
210
  function isThenable(value) {
193
211
  return value !== null && typeof value === "object" && "then" in value && typeof value.then === "function";
194
212
  }
195
- function emitReceipt(onReceipt, receipt) {
196
- if (onReceipt === undefined || receipt === undefined) {
197
- return;
198
- }
199
- try {
200
- const result = onReceipt(receipt);
201
- if (isThenable(result)) {
202
- void Promise.resolve(result).catch(() => undefined);
203
- }
204
- }
205
- catch {
206
- // Receipt hooks must not deny or fail the tool.
207
- }
213
+ function emitReceipt(onReceipt, receipt, session, host) {
214
+ collectReceipt(receipt, session, host);
215
+ emitIsolatedReceipt(onReceipt, receipt);
208
216
  }
209
217
  function plainArgs(value) {
210
218
  if (value instanceof Map) {
package/dist/mcp.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n McpAttachOptions,\n McpCallParams,\n McpHandlerPolicy,\n McpJsonRpcError,\n McpVerifyOptions,\n PresentedCall,\n Session as SessionContract,\n TenuoErrorCode,\n TenuoMcp,\n} from \"./api.ts\";\nimport { AuthorizationDeniedError, TenuoConfigurationError, TenuoError } from \"./errors.ts\";\nimport { collectReceipt, emitIsolatedReceipt } from \"./receipts.ts\";\nimport { nativeSession, type Session } from \"./session.ts\";\nimport type { WasmContext, WasmDecision } from \"./wasm.ts\";\n\nexport type Decide = (decision: WasmDecision, tool: string, native?: object, args?: Record<string, unknown>) => void;\n\n/**\n * Transport-agnostic half of `attach`: authorize locally, then sign\n * proof-of-possession over the call. Shared by `tenuo.present()` and\n * `tenuo.mcp.attach()`.\n */\nexport function presentCall(\n context: WasmContext,\n decide: Decide,\n session: SessionContract,\n name: string,\n args: Readonly<Record<string, unknown>>,\n options: McpAttachOptions | undefined,\n label: string,\n host?: object,\n): { readonly presented: PresentedCall; readonly wireArgs: Record<string, unknown> } {\n if (options !== undefined) {\n assertKnownKeys(options, ATTACH_OPTION_KEYS, `${label} options`);\n }\n const native = nativeSession(session as Session);\n const wireArgs = stripNulls(args);\n const local = context.authorize(\n native,\n name,\n wireArgs,\n options?.approvals,\n undefined,\n options?.requestId,\n );\n emitReceipt(options?.onReceipt, local.receipt, session, host);\n decide(local, name, native, wireArgs);\n const signature = context.signPop(native, name, wireArgs);\n const warrant = stackWire(native);\n if (options?.approvals !== undefined && options.approvals.length > 0) {\n return {\n presented: { warrant, signature, approvals: options.approvals.map(approvalWire) },\n wireArgs,\n };\n }\n return { presented: { warrant, signature }, wireArgs };\n}\n\n/**\n * Transport-agnostic half of `verify`: check a presented warrant chain and\n * proof-of-possession, then apply the host ceiling. Shared by\n * `tenuo.verify()` and `tenuo.mcp.verify()`.\n */\nexport async function verifyPresented(\n context: WasmContext,\n decide: Decide,\n presented: PresentedCall,\n name: string,\n args: Readonly<Record<string, unknown>>,\n options: McpVerifyOptions | undefined,\n label: string,\n host?: object,\n): Promise<Readonly<Record<string, unknown>>> {\n if (options !== undefined) {\n assertKnownKeys(options, VERIFY_OPTION_KEYS, `${label} options`);\n }\n const envelope = presentedEnvelope(presented);\n if (envelope === undefined) {\n throw new TenuoConfigurationError(\n `${label} needs { warrant, signature } from tenuo.present() or tenuo.mcp.attach()`,\n );\n }\n const decision = context.authorizePresented(\n envelope.warrant,\n name,\n stripNulls(args),\n envelope.signature,\n envelope.approvals,\n options?.allow,\n options?.requestId,\n );\n // Rust already signed this envelope. Emit before the nonce store can\n // refuse a replay — otherwise an attacker leaves no audit artifact.\n emitReceipt(options?.onReceipt, decision.receipt, undefined, host);\n if (decision.outcome === \"allow\") {\n await admitPop(options?.nonceStore, envelope.signature, options?.onNonceStoreError);\n }\n decide(decision, name);\n return plainArgs(decision.args);\n}\n\nexport function createMcp(context: WasmContext, decide: Decide, host?: object): TenuoMcp {\n const mcp: TenuoMcp = {\n attach(session, name, args, options) {\n const { presented, wireArgs } = presentCall(\n context,\n decide,\n session,\n name,\n args,\n options,\n \"mcp.attach()\",\n host,\n );\n return { name, arguments: wireArgs, _meta: { tenuo: presented } };\n },\n\n async verify(name, args, meta, options) {\n const envelope = tenuoEnvelope(meta);\n if (envelope === undefined) {\n throw new TenuoConfigurationError(\n \"MCP call is missing _meta.tenuo. The client must call tenuo.mcp.attach().\",\n );\n }\n return verifyPresented(context, decide, envelope, name, args, options, \"mcp.verify()\", host);\n },\n\n handler(name, policyOrExecute, maybeExecute?) {\n const policy = isHandlerPolicy(policyOrExecute) ? policyOrExecute : undefined;\n const execute = isHandlerPolicy(policyOrExecute) ? maybeExecute : policyOrExecute;\n if (typeof execute !== \"function\") {\n throw new TenuoConfigurationError(\"mcp.handler() requires an execute function\");\n }\n return async (args, extra) => {\n const authorized = await mcp.verify(name, args, extra?._meta ?? extra?.meta, {\n ...(policy?.allow !== undefined ? { allow: policy.allow } : {}),\n ...(policy?.onReceipt !== undefined ? { onReceipt: policy.onReceipt } : {}),\n ...(policy?.nonceStore !== undefined ? { nonceStore: policy.nonceStore } : {}),\n ...(policy?.onNonceStoreError !== undefined ? { onNonceStoreError: policy.onNonceStoreError } : {}),\n });\n return execute(authorized as never);\n };\n },\n\n jsonRpcError(error) {\n return jsonRpcError(error);\n },\n };\n return mcp;\n}\n\nfunction stackWire(native: object): string {\n const session = native as { toStackWire?: () => unknown };\n if (typeof session.toStackWire !== \"function\") {\n throw new TenuoConfigurationError(\"session is not bound to the WASM core\");\n }\n const wire = session.toStackWire();\n if (typeof wire !== \"string\" || wire.length === 0) {\n throw new TenuoConfigurationError(\"toStackWire() did not return a warrant stack\");\n }\n return wire;\n}\n\nfunction approvalWire(value: string | Uint8Array): string {\n if (typeof value === \"string\") {\n return value;\n }\n return Buffer.from(value).toString(\"base64\");\n}\n\nfunction presentedEnvelope(\n value: unknown,\n): { warrant: string; signature: string; approvals?: string[] } | undefined {\n if (value === null || typeof value !== \"object\") {\n return undefined;\n }\n const tenuo = value as { warrant?: unknown; signature?: unknown; approvals?: unknown };\n if (typeof tenuo.warrant !== \"string\" || tenuo.warrant.length === 0) {\n return undefined;\n }\n if (typeof tenuo.signature !== \"string\" || tenuo.signature.length === 0) {\n return undefined;\n }\n const approvals = Array.isArray(tenuo.approvals)\n ? tenuo.approvals.filter((item): item is string => typeof item === \"string\")\n : undefined;\n return {\n warrant: tenuo.warrant,\n signature: tenuo.signature,\n ...(approvals !== undefined && approvals.length > 0 ? { approvals } : {}),\n };\n}\n\nfunction tenuoEnvelope(\n meta: unknown,\n): { warrant: string; signature: string; approvals?: string[] } | undefined {\n if (meta === null || typeof meta !== \"object\") {\n return undefined;\n }\n const root = meta as { tenuo?: unknown; _meta?: unknown };\n const block = root.tenuo ?? (root._meta as { tenuo?: unknown } | undefined)?.tenuo;\n return presentedEnvelope(block);\n}\n\nconst HANDLER_POLICY_KEYS = new Set([\"allow\", \"onReceipt\", \"nonceStore\", \"onNonceStoreError\"]);\nconst VERIFY_OPTION_KEYS = new Set([\n \"allow\",\n \"onReceipt\",\n \"nonceStore\",\n \"onNonceStoreError\",\n \"requestId\",\n]);\nconst REPLAY_STORE_UNAVAILABLE = \"Replay store unavailable\";\nconst ATTACH_OPTION_KEYS = new Set([\"approvals\", \"onReceipt\", \"requestId\"]);\nconst MAX_STRIP_DEPTH = 32;\nconst MAX_STRIP_LEN = 1024;\n\nfunction assertKnownKeys(value: object, known: ReadonlySet<string>, label: string): void {\n const unknown = Object.keys(value).filter((key) => !known.has(key));\n if (unknown[0] !== undefined) {\n throw new TenuoConfigurationError(\n `${label} has unknown key '${unknown[0]}'. Use ${[...known].join(\", \")}.`,\n );\n }\n}\n\nfunction isHandlerPolicy(value: unknown): value is McpHandlerPolicy {\n if (value === null || typeof value !== \"object\" || Array.isArray(value) || typeof value === \"function\") {\n return false;\n }\n const keys = Object.keys(value);\n assertKnownKeys(value, HANDLER_POLICY_KEYS, \"mcp.handler() policy\");\n const record = value as {\n allow?: unknown;\n onReceipt?: unknown;\n nonceStore?: unknown;\n onNonceStoreError?: unknown;\n };\n const hasAllow =\n \"allow\" in record && record.allow !== null && typeof record.allow === \"object\" && !Array.isArray(record.allow);\n const hasReceipt = \"onReceipt\" in record && typeof record.onReceipt === \"function\";\n const hasNonce = \"nonceStore\" in record && record.nonceStore !== null && typeof record.nonceStore === \"object\";\n const hasStoreError = \"onNonceStoreError\" in record && typeof record.onNonceStoreError === \"function\";\n return keys.length === 0 || hasAllow || hasReceipt || hasNonce || hasStoreError;\n}\n\nasync function admitPop(\n store: { checkAndRecord(popSignature: string): boolean | Promise<boolean> } | undefined,\n signature: string,\n onNonceStoreError?: (error: unknown) => void | Promise<void>,\n): Promise<void> {\n if (store === undefined) {\n return;\n }\n let admitted: boolean | Promise<boolean>;\n try {\n admitted = store.checkAndRecord(signature);\n } catch (error) {\n throw replayStoreUnavailable(error, onNonceStoreError);\n }\n if (isThenable(admitted)) {\n try {\n admitted = await admitted;\n } catch (error) {\n throw replayStoreUnavailable(error, onNonceStoreError);\n }\n }\n if (typeof admitted !== \"boolean\") {\n throw replayStoreUnavailable(\n new TenuoConfigurationError(\"NonceStore.checkAndRecord() must return boolean or Promise<boolean>\"),\n onNonceStoreError,\n );\n }\n if (!admitted) {\n throw new AuthorizationDeniedError(\n \"TENUO_INVALID_POP\",\n \"PoP replay detected — this exact authorization token was already consumed.\",\n );\n }\n}\n\nfunction replayStoreUnavailable(\n cause: unknown,\n onNonceStoreError?: (error: unknown) => void | Promise<void>,\n): TenuoConfigurationError {\n emitIsolated(onNonceStoreError, cause);\n const error = new TenuoConfigurationError(REPLAY_STORE_UNAVAILABLE);\n if (cause !== undefined) {\n error.cause = cause;\n }\n return error;\n}\n\nfunction emitIsolated(\n hook: ((error: unknown) => void | Promise<void>) | undefined,\n error: unknown,\n): void {\n if (hook === undefined) {\n return;\n }\n try {\n const result = hook(error);\n if (isThenable(result)) {\n void Promise.resolve(result).catch(() => undefined);\n }\n } catch {\n // Isolated — must not change the public error.\n }\n}\n\nfunction isThenable(value: unknown): value is Promise<boolean> {\n return value !== null && typeof value === \"object\" && \"then\" in value && typeof value.then === \"function\";\n}\n\nfunction emitReceipt(\n onReceipt: ((receipt: string) => void | Promise<void>) | undefined,\n receipt: string | undefined,\n session?: SessionContract,\n host?: object,\n): void {\n collectReceipt(receipt, session, host);\n emitIsolatedReceipt(onReceipt, receipt);\n}\n\nfunction plainArgs(value: unknown): Record<string, unknown> {\n if (value instanceof Map) {\n return Object.fromEntries(value);\n }\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n return { ...(value as Record<string, unknown>) };\n }\n return {};\n}\n\n/** Same rule as Python `strip_none_values`: drop null so optional MCP args do not break PoP. */\nfunction stripNulls(args: Readonly<Record<string, unknown>>): Record<string, unknown> {\n const keys = Object.keys(args);\n if (keys.length > MAX_STRIP_LEN) {\n throw new TenuoConfigurationError(\"arguments exceed the TypeScript input budget\");\n }\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(args)) {\n if (value === null || value === undefined) {\n continue;\n }\n out[key] = Array.isArray(value) ? cleanList(value, 1) : value;\n }\n return out;\n}\n\nfunction cleanList(value: readonly unknown[], depth: number): unknown[] {\n if (depth > MAX_STRIP_DEPTH) {\n throw new TenuoConfigurationError(\"arguments exceed the TypeScript nesting budget\");\n }\n if (value.length > MAX_STRIP_LEN) {\n throw new TenuoConfigurationError(\"arguments exceed the TypeScript input budget\");\n }\n const cleaned: unknown[] = [];\n for (const item of value) {\n if (item === null || item === undefined) {\n continue;\n }\n cleaned.push(Array.isArray(item) ? cleanList(item, depth + 1) : item);\n }\n return cleaned;\n}\n\nfunction jsonRpcError(error: unknown): McpJsonRpcError {\n if (error instanceof TenuoError) {\n const code: TenuoErrorCode = error.code;\n const rpc = code === \"TENUO_APPROVAL_REQUIRED\" ? -32002 : code === \"TENUO_CANONICALIZATION\" ? -32602 : -32001;\n return { code: rpc, message: error.message, data: { tenuo: { code } } };\n }\n const message = error instanceof Error ? error.message : String(error);\n return { code: -32001, message };\n}\n"]}
package/dist/nonce.d.ts CHANGED
@@ -4,8 +4,13 @@ import type { NonceStore } from "./api.ts";
4
4
  * Not on by default. Does not work across processes — implement
5
5
  * `NonceStore` with an async Redis `checkAndRecord` (return
6
6
  * `Promise<boolean>`). A rejected Promise fails closed.
7
+ *
8
+ * `ttlSeconds` defaults to 180 and must be greater than zero and finite.
9
+ * Values too large to convert to milliseconds are also rejected.
10
+ *
11
+ * @throws {TenuoConfigurationError} If `ttlSeconds` is not a supported
12
+ * positive, finite duration.
7
13
  */
8
14
  export declare function memoryNonceStore(options?: {
9
15
  readonly ttlSeconds?: number;
10
16
  }): NonceStore;
11
- //# sourceMappingURL=nonce.d.ts.map
package/dist/nonce.js CHANGED
@@ -1,12 +1,23 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { TenuoConfigurationError } from "./errors.js";
2
3
  /**
3
4
  * In-process PoP replay store. Same shape as Python `NonceStore`.
4
5
  * Not on by default. Does not work across processes — implement
5
6
  * `NonceStore` with an async Redis `checkAndRecord` (return
6
7
  * `Promise<boolean>`). A rejected Promise fails closed.
8
+ *
9
+ * `ttlSeconds` defaults to 180 and must be greater than zero and finite.
10
+ * Values too large to convert to milliseconds are also rejected.
11
+ *
12
+ * @throws {TenuoConfigurationError} If `ttlSeconds` is not a supported
13
+ * positive, finite duration.
7
14
  */
8
15
  export function memoryNonceStore(options) {
9
- const ttlMs = (options?.ttlSeconds ?? 180) * 1000;
16
+ const ttlSeconds = options?.ttlSeconds ?? 180;
17
+ const ttlMs = ttlSeconds * 1000;
18
+ if (ttlSeconds <= 0 || !Number.isFinite(ttlSeconds) || !Number.isFinite(ttlMs)) {
19
+ throw new TenuoConfigurationError("memoryNonceStore() ttlSeconds must be positive, finite, and representable in milliseconds");
20
+ }
10
21
  const seen = new Map();
11
22
  return {
12
23
  checkAndRecord(popSignature) {
package/dist/nonce.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"nonce.js","sourceRoot":"","sources":["../src/nonce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAA0C;IACzE,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,UAAU,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC;IAClD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,OAAO;QACL,cAAc,CAAC,YAAoB;YACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;gBACjC,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;oBAClB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACnB,CAAC;YACH,CAAC;YACD,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACpE,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClB,OAAO,KAAK,CAAC;YACf,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,KAAK,CAAC,CAAC;YAC3B,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"nonce.js","sourceRoot":"","sources":["../src/nonce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAA0C;IACzE,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,GAAG,CAAC;IAC9C,MAAM,KAAK,GAAG,UAAU,GAAG,IAAI,CAAC;IAChC,IAAI,UAAU,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/E,MAAM,IAAI,uBAAuB,CAC/B,2FAA2F,CAC5F,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,OAAO;QACL,cAAc,CAAC,YAAoB;YACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;gBACjC,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;oBAClB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACnB,CAAC;YACH,CAAC;YACD,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACpE,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClB,OAAO,KAAK,CAAC;YACf,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,KAAK,CAAC,CAAC;YAC3B,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { NonceStore } from \"./api.ts\";\nimport { TenuoConfigurationError } from \"./errors.ts\";\n\n/**\n * In-process PoP replay store. Same shape as Python `NonceStore`.\n * Not on by default. Does not work across processes — implement\n * `NonceStore` with an async Redis `checkAndRecord` (return\n * `Promise<boolean>`). A rejected Promise fails closed.\n *\n * `ttlSeconds` defaults to 180 and must be greater than zero and finite.\n * Values too large to convert to milliseconds are also rejected.\n *\n * @throws {TenuoConfigurationError} If `ttlSeconds` is not a supported\n * positive, finite duration.\n */\nexport function memoryNonceStore(options?: { readonly ttlSeconds?: number }): NonceStore {\n const ttlSeconds = options?.ttlSeconds ?? 180;\n const ttlMs = ttlSeconds * 1000;\n if (ttlSeconds <= 0 || !Number.isFinite(ttlSeconds) || !Number.isFinite(ttlMs)) {\n throw new TenuoConfigurationError(\n \"memoryNonceStore() ttlSeconds must be positive, finite, and representable in milliseconds\",\n );\n }\n const seen = new Map<string, number>();\n return {\n checkAndRecord(popSignature: string): boolean {\n const now = Date.now();\n for (const [key, expiry] of seen) {\n if (expiry <= now) {\n seen.delete(key);\n }\n }\n const key = createHash(\"sha256\").update(popSignature).digest(\"hex\");\n if (seen.has(key)) {\n return false;\n }\n seen.set(key, now + ttlMs);\n return true;\n },\n };\n}\n"]}
@@ -0,0 +1,27 @@
1
+ import type { Session as SessionContract } from "./api.ts";
2
+ /**
3
+ * In-memory receipt buffer containing only unacknowledged receipts.
4
+ *
5
+ * Delivery: receipts are appended in emission order. `peek()` and `drain()`
6
+ * are the same non-consuming snapshot. Only `acknowledge()` removes items.
7
+ */
8
+ export declare class ReceiptCollector {
9
+ #private;
10
+ constructor(max?: number);
11
+ get overflowed(): number;
12
+ push(receipt: string): void;
13
+ peek(): string[];
14
+ drain(): string[];
15
+ acknowledge(count: number): number;
16
+ /** Remove receipts by wire identity, preserving remaining order. */
17
+ removeMatching(wires: readonly string[]): number;
18
+ }
19
+ export declare function bindSessionCollector(session: object, collector: ReceiptCollector, host?: ReceiptCollector): void;
20
+ /** Derived sessions share the parent's outbox so acknowledge frees both. */
21
+ export declare function inheritSessionCollector(parent: object, child: object): void;
22
+ export declare function bindHostCollector(host: object, collector: ReceiptCollector): void;
23
+ export declare function sessionCollector(session: object | undefined): ReceiptCollector | undefined;
24
+ export declare function hostCollector(host: object | undefined): ReceiptCollector | undefined;
25
+ export declare function linkedHostCollector(session: object | undefined): ReceiptCollector | undefined;
26
+ export declare function collectReceipt(receipt: string | undefined, session?: SessionContract, host?: object): void;
27
+ export declare function emitIsolatedReceipt(onReceipt: ((receipt: string) => void | Promise<void>) | undefined, receipt: string | undefined): void;
@@ -0,0 +1,128 @@
1
+ /**
2
+ * In-memory receipt buffer containing only unacknowledged receipts.
3
+ *
4
+ * Delivery: receipts are appended in emission order. `peek()` and `drain()`
5
+ * are the same non-consuming snapshot. Only `acknowledge()` removes items.
6
+ */
7
+ export class ReceiptCollector {
8
+ #items = [];
9
+ #max;
10
+ #overflowed = 0;
11
+ constructor(max = 10_000) {
12
+ this.#max = Number.isInteger(max) && max > 0 ? max : 10_000;
13
+ }
14
+ get overflowed() {
15
+ return this.#overflowed;
16
+ }
17
+ push(receipt) {
18
+ if (this.#items.length >= this.#max) {
19
+ this.#overflowed += 1;
20
+ return;
21
+ }
22
+ this.#items.push(receipt);
23
+ }
24
+ peek() {
25
+ return [...this.#items];
26
+ }
27
+ drain() {
28
+ return this.peek();
29
+ }
30
+ acknowledge(count) {
31
+ if (!Number.isInteger(count) || count < 0) {
32
+ return 0;
33
+ }
34
+ const n = Math.min(count, this.#items.length);
35
+ this.#items.splice(0, n);
36
+ return n;
37
+ }
38
+ /** Remove receipts by wire identity, preserving remaining order. */
39
+ removeMatching(wires) {
40
+ if (wires.length === 0) {
41
+ return 0;
42
+ }
43
+ const drop = new Set(wires);
44
+ const kept = [];
45
+ let removed = 0;
46
+ for (const item of this.#items) {
47
+ if (drop.has(item)) {
48
+ removed += 1;
49
+ }
50
+ else {
51
+ kept.push(item);
52
+ }
53
+ }
54
+ this.#items.length = 0;
55
+ this.#items.push(...kept);
56
+ return removed;
57
+ }
58
+ }
59
+ const sessionCollectors = new WeakMap();
60
+ const hostCollectors = new WeakMap();
61
+ const linkedHostCollectors = new WeakMap();
62
+ export function bindSessionCollector(session, collector, host) {
63
+ sessionCollectors.set(session, collector);
64
+ if (host !== undefined) {
65
+ linkedHostCollectors.set(session, host);
66
+ }
67
+ }
68
+ /** Derived sessions share the parent's outbox so acknowledge frees both. */
69
+ export function inheritSessionCollector(parent, child) {
70
+ const parentCollector = sessionCollectors.get(parent);
71
+ if (parentCollector !== undefined) {
72
+ sessionCollectors.set(child, parentCollector);
73
+ }
74
+ const host = linkedHostCollectors.get(parent);
75
+ if (host !== undefined) {
76
+ linkedHostCollectors.set(child, host);
77
+ }
78
+ }
79
+ export function bindHostCollector(host, collector) {
80
+ hostCollectors.set(host, collector);
81
+ }
82
+ export function sessionCollector(session) {
83
+ if (session === undefined) {
84
+ return undefined;
85
+ }
86
+ return sessionCollectors.get(session);
87
+ }
88
+ export function hostCollector(host) {
89
+ if (host === undefined) {
90
+ return undefined;
91
+ }
92
+ return hostCollectors.get(host);
93
+ }
94
+ export function linkedHostCollector(session) {
95
+ if (session === undefined) {
96
+ return undefined;
97
+ }
98
+ return linkedHostCollectors.get(session);
99
+ }
100
+ export function collectReceipt(receipt, session, host) {
101
+ if (receipt === undefined) {
102
+ return;
103
+ }
104
+ sessionCollector(session)?.push(receipt);
105
+ const linked = linkedHostCollector(session);
106
+ const hosted = hostCollector(host);
107
+ if (linked !== undefined) {
108
+ linked.push(receipt);
109
+ }
110
+ if (hosted !== undefined && hosted !== linked) {
111
+ hosted.push(receipt);
112
+ }
113
+ }
114
+ export function emitIsolatedReceipt(onReceipt, receipt) {
115
+ if (onReceipt === undefined || receipt === undefined) {
116
+ return;
117
+ }
118
+ try {
119
+ const result = onReceipt(receipt);
120
+ if (result !== null && typeof result === "object" && "then" in result && typeof result.then === "function") {
121
+ void Promise.resolve(result).catch(() => undefined);
122
+ }
123
+ }
124
+ catch {
125
+ // Explicit onReceipt remains isolated. Collectors are sync and do not use this path.
126
+ }
127
+ }
128
+ //# sourceMappingURL=receipts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipts.js","sourceRoot":"","sources":["../src/receipts.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Session as SessionContract } from \"./api.ts\";\n\n/**\n * In-memory receipt buffer containing only unacknowledged receipts.\n *\n * Delivery: receipts are appended in emission order. `peek()` and `drain()`\n * are the same non-consuming snapshot. Only `acknowledge()` removes items.\n */\nexport class ReceiptCollector {\n readonly #items: string[] = [];\n readonly #max: number;\n #overflowed = 0;\n\n constructor(max = 10_000) {\n this.#max = Number.isInteger(max) && max > 0 ? max : 10_000;\n }\n\n get overflowed(): number {\n return this.#overflowed;\n }\n\n push(receipt: string): void {\n if (this.#items.length >= this.#max) {\n this.#overflowed += 1;\n return;\n }\n this.#items.push(receipt);\n }\n\n peek(): string[] {\n return [...this.#items];\n }\n\n drain(): string[] {\n return this.peek();\n }\n\n acknowledge(count: number): number {\n if (!Number.isInteger(count) || count < 0) {\n return 0;\n }\n const n = Math.min(count, this.#items.length);\n this.#items.splice(0, n);\n return n;\n }\n\n /** Remove receipts by wire identity, preserving remaining order. */\n removeMatching(wires: readonly string[]): number {\n if (wires.length === 0) {\n return 0;\n }\n const drop = new Set(wires);\n const kept: string[] = [];\n let removed = 0;\n for (const item of this.#items) {\n if (drop.has(item)) {\n removed += 1;\n } else {\n kept.push(item);\n }\n }\n this.#items.length = 0;\n this.#items.push(...kept);\n return removed;\n }\n}\n\nconst sessionCollectors = new WeakMap<object, ReceiptCollector>();\nconst hostCollectors = new WeakMap<object, ReceiptCollector>();\nconst linkedHostCollectors = new WeakMap<object, ReceiptCollector>();\n\nexport function bindSessionCollector(\n session: object,\n collector: ReceiptCollector,\n host?: ReceiptCollector,\n): void {\n sessionCollectors.set(session, collector);\n if (host !== undefined) {\n linkedHostCollectors.set(session, host);\n }\n}\n\n/** Derived sessions share the parent's outbox so acknowledge frees both. */\nexport function inheritSessionCollector(parent: object, child: object): void {\n const parentCollector = sessionCollectors.get(parent);\n if (parentCollector !== undefined) {\n sessionCollectors.set(child, parentCollector);\n }\n const host = linkedHostCollectors.get(parent);\n if (host !== undefined) {\n linkedHostCollectors.set(child, host);\n }\n}\n\nexport function bindHostCollector(host: object, collector: ReceiptCollector): void {\n hostCollectors.set(host, collector);\n}\n\nexport function sessionCollector(session: object | undefined): ReceiptCollector | undefined {\n if (session === undefined) {\n return undefined;\n }\n return sessionCollectors.get(session);\n}\n\nexport function hostCollector(host: object | undefined): ReceiptCollector | undefined {\n if (host === undefined) {\n return undefined;\n }\n return hostCollectors.get(host);\n}\n\nexport function linkedHostCollector(session: object | undefined): ReceiptCollector | undefined {\n if (session === undefined) {\n return undefined;\n }\n return linkedHostCollectors.get(session);\n}\n\nexport function collectReceipt(\n receipt: string | undefined,\n session?: SessionContract,\n host?: object,\n): void {\n if (receipt === undefined) {\n return;\n }\n sessionCollector(session)?.push(receipt);\n const linked = linkedHostCollector(session);\n const hosted = hostCollector(host);\n if (linked !== undefined) {\n linked.push(receipt);\n }\n if (hosted !== undefined && hosted !== linked) {\n hosted.push(receipt);\n }\n}\n\nexport function emitIsolatedReceipt(\n onReceipt: ((receipt: string) => void | Promise<void>) | undefined,\n receipt: string | undefined,\n): void {\n if (onReceipt === undefined || receipt === undefined) {\n return;\n }\n try {\n const result = onReceipt(receipt);\n if (result !== null && typeof result === \"object\" && \"then\" in result && typeof result.then === \"function\") {\n void Promise.resolve(result).catch(() => undefined);\n }\n } catch {\n // Explicit onReceipt remains isolated. Collectors are sync and do not use this path.\n }\n}\n"]}