@codespar/sdk 0.9.0 → 0.10.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 (49) hide show
  1. package/README.md +166 -19
  2. package/dist/__tests__/base-url-resolution.test.d.ts +10 -0
  3. package/dist/__tests__/base-url-resolution.test.d.ts.map +1 -0
  4. package/dist/__tests__/base-url-resolution.test.js +57 -0
  5. package/dist/__tests__/base-url-resolution.test.js.map +1 -0
  6. package/dist/__tests__/errors.test.d.ts +16 -0
  7. package/dist/__tests__/errors.test.d.ts.map +1 -0
  8. package/dist/__tests__/errors.test.js +163 -0
  9. package/dist/__tests__/errors.test.js.map +1 -0
  10. package/dist/__tests__/forward-mocks.test.d.ts +15 -0
  11. package/dist/__tests__/forward-mocks.test.d.ts.map +1 -0
  12. package/dist/__tests__/forward-mocks.test.js +134 -0
  13. package/dist/__tests__/forward-mocks.test.js.map +1 -0
  14. package/dist/__tests__/mocks-wire-parity.test.d.ts +15 -0
  15. package/dist/__tests__/mocks-wire-parity.test.d.ts.map +1 -0
  16. package/dist/__tests__/mocks-wire-parity.test.js +71 -0
  17. package/dist/__tests__/mocks-wire-parity.test.js.map +1 -0
  18. package/dist/__tests__/testing.test.d.ts +2 -0
  19. package/dist/__tests__/testing.test.d.ts.map +1 -0
  20. package/dist/__tests__/testing.test.js +133 -0
  21. package/dist/__tests__/testing.test.js.map +1 -0
  22. package/dist/__tests__/tool-result-codes.test.d.ts +18 -0
  23. package/dist/__tests__/tool-result-codes.test.d.ts.map +1 -0
  24. package/dist/__tests__/tool-result-codes.test.js +164 -0
  25. package/dist/__tests__/tool-result-codes.test.js.map +1 -0
  26. package/dist/errors.d.ts +43 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +77 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/index.d.ts +4 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +2 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/session.d.ts.map +1 -1
  35. package/dist/session.js +80 -49
  36. package/dist/session.js.map +1 -1
  37. package/dist/testing/index.d.ts +9 -0
  38. package/dist/testing/index.d.ts.map +1 -0
  39. package/dist/testing/index.js +68 -0
  40. package/dist/testing/index.js.map +1 -0
  41. package/dist/tool-result-codes.d.ts +82 -0
  42. package/dist/tool-result-codes.d.ts.map +1 -0
  43. package/dist/tool-result-codes.js +99 -0
  44. package/dist/tool-result-codes.js.map +1 -0
  45. package/dist/types.d.ts +20 -1
  46. package/dist/types.d.ts.map +1 -1
  47. package/dist/types.js +8 -0
  48. package/dist/types.js.map +1 -1
  49. package/package.json +6 -2
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Tests for the createSession body builder's `mocks` forwarding.
3
+ *
4
+ * Asserts:
5
+ * - Wire-neutrality: a cs.create without `mocks` produces a body
6
+ * byte-identical to today's shape (R18).
7
+ * - Forwarded shape: a cs.create with `mocks` includes the field
8
+ * verbatim — no SDK-side rewriting of canonical names.
9
+ * - Empty `mocks: {}` is forwarded (the backend accepts; strict-
10
+ * mode R3a activates only on non-empty maps).
11
+ * - Double-underscore key form reaches the backend unrewritten
12
+ * so the canonical-form rejection surfaces at the right layer.
13
+ */
14
+ import { describe, it, expect, vi, afterEach } from "vitest";
15
+ import { CodeSpar } from "../index.js";
16
+ function mockSessionResponse() {
17
+ return {
18
+ ok: true,
19
+ status: 201,
20
+ text: async () => "",
21
+ json: async () => ({
22
+ id: "ses_demo",
23
+ org_id: "org_demo",
24
+ user_id: "user_demo",
25
+ servers: ["asaas"],
26
+ status: "active",
27
+ created_at: new Date().toISOString(),
28
+ closed_at: null,
29
+ }),
30
+ };
31
+ }
32
+ describe("createSession body builder forwards mocks", () => {
33
+ const originalFetch = globalThis.fetch;
34
+ afterEach(() => {
35
+ globalThis.fetch = originalFetch;
36
+ });
37
+ it("omits mocks key from the wire body when undefined (R18 wire-neutral)", async () => {
38
+ const fetchMock = vi
39
+ .fn()
40
+ .mockResolvedValueOnce(mockSessionResponse());
41
+ globalThis.fetch = fetchMock;
42
+ const cs = new CodeSpar({
43
+ apiKey: "csk_live_test",
44
+ baseUrl: "https://api.example.com",
45
+ });
46
+ await cs.create("user_demo", { servers: ["asaas"] });
47
+ const init = fetchMock.mock
48
+ .calls[0][1];
49
+ const body = JSON.parse(init.body);
50
+ expect("mocks" in body).toBe(false);
51
+ expect(body).toEqual({ servers: ["asaas"], user_id: "user_demo" });
52
+ });
53
+ it("forwards mocks verbatim when present", async () => {
54
+ const fetchMock = vi
55
+ .fn()
56
+ .mockResolvedValueOnce(mockSessionResponse());
57
+ globalThis.fetch = fetchMock;
58
+ const cs = new CodeSpar({
59
+ apiKey: "csk_live_test",
60
+ baseUrl: "https://api.example.com",
61
+ });
62
+ await cs.create("user_demo", {
63
+ servers: ["asaas"],
64
+ mocks: {
65
+ "asaas/create_payment": { id: "pay_test_42", status: "PENDING" },
66
+ },
67
+ });
68
+ const init = fetchMock.mock
69
+ .calls[0][1];
70
+ const body = JSON.parse(init.body);
71
+ expect(body.mocks).toEqual({
72
+ "asaas/create_payment": { id: "pay_test_42", status: "PENDING" },
73
+ });
74
+ });
75
+ it("accepts and forwards an empty mocks={} body", async () => {
76
+ const fetchMock = vi
77
+ .fn()
78
+ .mockResolvedValueOnce(mockSessionResponse());
79
+ globalThis.fetch = fetchMock;
80
+ const cs = new CodeSpar({
81
+ apiKey: "csk_live_test",
82
+ baseUrl: "https://api.example.com",
83
+ });
84
+ await cs.create("user_demo", { servers: ["asaas"], mocks: {} });
85
+ const init = fetchMock.mock
86
+ .calls[0][1];
87
+ const body = JSON.parse(init.body);
88
+ expect(body.mocks).toEqual({});
89
+ });
90
+ it("does NOT rewrite double-underscore keys — they reach the backend verbatim", async () => {
91
+ const fetchMock = vi
92
+ .fn()
93
+ .mockResolvedValueOnce(mockSessionResponse());
94
+ globalThis.fetch = fetchMock;
95
+ const cs = new CodeSpar({
96
+ apiKey: "csk_live_test",
97
+ baseUrl: "https://api.example.com",
98
+ });
99
+ await cs.create("user_demo", {
100
+ servers: ["asaas"],
101
+ mocks: { asaas__create_payment: { id: "pay_test_42" } },
102
+ });
103
+ const init = fetchMock.mock
104
+ .calls[0][1];
105
+ const body = JSON.parse(init.body);
106
+ const mocks = body.mocks;
107
+ expect(Object.keys(mocks)).toEqual(["asaas__create_payment"]);
108
+ });
109
+ it("matches the canonical fixture byte-for-byte when the same input lands", async () => {
110
+ // Same canonical body used by the Python parity test.
111
+ const fetchMock = vi
112
+ .fn()
113
+ .mockResolvedValueOnce(mockSessionResponse());
114
+ globalThis.fetch = fetchMock;
115
+ const cs = new CodeSpar({
116
+ apiKey: "csk_live_test",
117
+ baseUrl: "https://api.example.com",
118
+ });
119
+ await cs.create("user_demo", {
120
+ servers: ["asaas"],
121
+ mocks: {
122
+ "asaas/create_payment": { id: "pay_test_42", status: "PENDING" },
123
+ "asaas/get_payment": [
124
+ { id: "pay_test_42", status: "PENDING" },
125
+ { id: "pay_test_42", status: "CONFIRMED" },
126
+ ],
127
+ },
128
+ });
129
+ const init = fetchMock.mock
130
+ .calls[0][1];
131
+ expect(init.body).toBe('{"servers":["asaas"],"user_id":"user_demo","mocks":{"asaas/create_payment":{"id":"pay_test_42","status":"PENDING"},"asaas/get_payment":[{"id":"pay_test_42","status":"PENDING"},{"id":"pay_test_42","status":"CONFIRMED"}]}}');
132
+ });
133
+ });
134
+ //# sourceMappingURL=forward-mocks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forward-mocks.test.js","sourceRoot":"","sources":["../../src/__tests__/forward-mocks.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Wire-shape parity test for the test-mode mocks field.
3
+ *
4
+ * Asserts that the TypeScript SessionConfig type carries the optional
5
+ * `mocks` field with the right shape, and that the serialized form
6
+ * matches the canonical fixture used by the Python SDK's parallel
7
+ * test. Both languages serialize the same example to byte-identical
8
+ * JSON; any drift here is a wire-contract break.
9
+ *
10
+ * The canonical fixture lives at packages/python/tests/_fixtures/
11
+ * mocks_canonical.json — kept in sync by hand. Future contributors
12
+ * MUST update both files together when extending the example.
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=mocks-wire-parity.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mocks-wire-parity.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/mocks-wire-parity.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Wire-shape parity test for the test-mode mocks field.
3
+ *
4
+ * Asserts that the TypeScript SessionConfig type carries the optional
5
+ * `mocks` field with the right shape, and that the serialized form
6
+ * matches the canonical fixture used by the Python SDK's parallel
7
+ * test. Both languages serialize the same example to byte-identical
8
+ * JSON; any drift here is a wire-contract break.
9
+ *
10
+ * The canonical fixture lives at packages/python/tests/_fixtures/
11
+ * mocks_canonical.json — kept in sync by hand. Future contributors
12
+ * MUST update both files together when extending the example.
13
+ */
14
+ import { describe, it, expect } from "vitest";
15
+ const CANONICAL_BODY = {
16
+ servers: ["asaas"],
17
+ user_id: "user_demo",
18
+ mocks: {
19
+ "asaas/create_payment": { id: "pay_test_42", status: "PENDING" },
20
+ "asaas/get_payment": [
21
+ { id: "pay_test_42", status: "PENDING" },
22
+ { id: "pay_test_42", status: "CONFIRMED" },
23
+ ],
24
+ },
25
+ };
26
+ describe("MockObject + MockValue type aliases", () => {
27
+ it("accepts a plain dict as MockObject", () => {
28
+ const obj = { id: "pay_test_42", status: "PENDING" };
29
+ expect(obj.id).toBe("pay_test_42");
30
+ });
31
+ it("accepts a single MockObject as MockValue (static mock)", () => {
32
+ const v = { id: "pay_test_42", status: "PENDING" };
33
+ expect(v).toBeDefined();
34
+ });
35
+ it("accepts a MockObject array as MockValue (stateful mock)", () => {
36
+ const v = [
37
+ { id: "pay_test_42", status: "PENDING" },
38
+ { id: "pay_test_42", status: "CONFIRMED" },
39
+ ];
40
+ expect(Array.isArray(v)).toBe(true);
41
+ });
42
+ });
43
+ describe("CreateSessionOptions carries optional mocks field", () => {
44
+ it("accepts a SessionConfig with no mocks (wire-neutral)", () => {
45
+ const cfg = { servers: ["asaas"] };
46
+ expect(cfg.mocks).toBeUndefined();
47
+ });
48
+ it("accepts a SessionConfig with canonical mocks shape", () => {
49
+ const cfg = {
50
+ servers: ["asaas"],
51
+ mocks: {
52
+ "asaas/create_payment": { id: "pay_test_42", status: "PENDING" },
53
+ "asaas/get_payment": [
54
+ { id: "pay_test_42", status: "PENDING" },
55
+ { id: "pay_test_42", status: "CONFIRMED" },
56
+ ],
57
+ },
58
+ };
59
+ expect(cfg.mocks?.["asaas/create_payment"]).toBeDefined();
60
+ });
61
+ });
62
+ describe("Canonical body serializes to byte-identical JSON", () => {
63
+ it("matches the Python SDK fixture byte-for-byte", () => {
64
+ // The canonical body field order is preserved by the JSON.stringify
65
+ // contract used in createSession's body builder. If field ordering
66
+ // changes here, the Python side must change too.
67
+ const serialized = JSON.stringify(CANONICAL_BODY);
68
+ expect(serialized).toBe('{"servers":["asaas"],"user_id":"user_demo","mocks":{"asaas/create_payment":{"id":"pay_test_42","status":"PENDING"},"asaas/get_payment":[{"id":"pay_test_42","status":"PENDING"},{"id":"pay_test_42","status":"CONFIRMED"}]}}');
69
+ });
70
+ });
71
+ //# sourceMappingURL=mocks-wire-parity.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mocks-wire-parity.test.js","sourceRoot":"","sources":["../../src/__tests__/mocks-wire-parity.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAI9C,MAAM,cAAc,GAAG;IACrB,OAAO,EAAE,CAAC,OAAO,CAAC;IAClB,OAAO,EAAE,WAAW;IACpB,KAAK,EAAE;QACL,sBAAsB,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE;QAChE,mBAAmB,EAAE;YACnB,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE;YACxC,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE;SAC3C;KACF;CACO,CAAC;AAEX,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;IACnD,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,GAAG,GAAe,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QACjE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,GAAc,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC9D,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,GAAc;YACnB,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE;YACxC,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE;SAC3C,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,mDAAmD,EAAE,GAAG,EAAE;IACjE,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,GAAG,GAAkB,EAAE,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;QAClD,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,GAAG,GAAkB;YACzB,OAAO,EAAE,CAAC,OAAO,CAAC;YAClB,KAAK,EAAE;gBACL,sBAAsB,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE;gBAChE,mBAAmB,EAAE;oBACnB,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE;oBACxC,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE;iBAC3C;aACF;SACF,CAAC;QACF,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAChE,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,oEAAoE;QACpE,mEAAmE;QACnE,iDAAiD;QACjD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAClD,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CACrB,8NAA8N,CAC/N,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=testing.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/testing.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,133 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { fakeSession } from "../testing/index.js";
3
+ describe("@codespar/sdk/testing — exported surface", () => {
4
+ it("exports fakeSession and the ToolResult type from a single import", () => {
5
+ expect(typeof fakeSession).toBe("function");
6
+ // ToolResult is a type-only re-export; the assertion below proves it
7
+ // is usable in a value position via a typed identity function.
8
+ const passthrough = (r) => r;
9
+ const sample = {
10
+ success: true,
11
+ data: {},
12
+ error: null,
13
+ duration: 0,
14
+ server: "",
15
+ tool: "x",
16
+ };
17
+ expect(passthrough(sample)).toBe(sample);
18
+ });
19
+ });
20
+ describe("fakeSession — strict mode (default)", () => {
21
+ it("throws verbatim 'fakeSession: no response registered for tool <name>' on miss", async () => {
22
+ const session = fakeSession();
23
+ await expect(session.execute("asaas/create_payment", { value: 100 })).rejects.toThrow("fakeSession: no response registered for tool asaas/create_payment");
24
+ });
25
+ it("error message is byte-identical to the contract string", async () => {
26
+ const session = fakeSession();
27
+ let captured = null;
28
+ try {
29
+ await session.execute("foo/bar", {});
30
+ }
31
+ catch (err) {
32
+ captured = err;
33
+ }
34
+ expect(captured).toBeInstanceOf(Error);
35
+ expect(captured.message).toBe("fakeSession: no response registered for tool foo/bar");
36
+ });
37
+ });
38
+ describe("fakeSession — registered responses", () => {
39
+ it("returns the static ToolResult registered for a tool name", async () => {
40
+ const session = fakeSession({
41
+ "asaas/create_customer": {
42
+ success: true,
43
+ data: { id: "cus_test_1", name: "Maria" },
44
+ error: null,
45
+ duration: 0,
46
+ server: "asaas",
47
+ tool: "asaas/create_customer",
48
+ },
49
+ });
50
+ const result = await session.execute("asaas/create_customer", { name: "Maria" });
51
+ expect(result.success).toBe(true);
52
+ expect(result.data).toEqual({ id: "cus_test_1", name: "Maria" });
53
+ expect(result.tool).toBe("asaas/create_customer");
54
+ });
55
+ });
56
+ describe("fakeSession — per-tool function variant", () => {
57
+ it("invokes a sync response function with the call's params and returns its result", async () => {
58
+ const session = fakeSession({
59
+ "asaas/create_customer": (input) => ({
60
+ success: true,
61
+ data: { echoed: input },
62
+ error: null,
63
+ duration: 0,
64
+ server: "asaas",
65
+ tool: "asaas/create_customer",
66
+ }),
67
+ });
68
+ const result = await session.execute("asaas/create_customer", { name: "Joana" });
69
+ expect(result.data).toEqual({ echoed: { name: "Joana" } });
70
+ });
71
+ it("awaits a Promise-returning response function", async () => {
72
+ const session = fakeSession({
73
+ "asaas/create_customer": async (input) => ({
74
+ success: true,
75
+ data: { async_echoed: input },
76
+ error: null,
77
+ duration: 0,
78
+ server: "asaas",
79
+ tool: "asaas/create_customer",
80
+ }),
81
+ });
82
+ const result = await session.execute("asaas/create_customer", { name: "Joana" });
83
+ expect(result.data).toEqual({ async_echoed: { name: "Joana" } });
84
+ });
85
+ });
86
+ describe("fakeSession — lenient mode", () => {
87
+ it("returns {success:true, data:{}} for unregistered tools when lenient: true", async () => {
88
+ const session = fakeSession({}, { lenient: true });
89
+ const result = await session.execute("asaas/create_payment", { value: 100 });
90
+ expect(result.success).toBe(true);
91
+ expect(result.data).toEqual({});
92
+ expect(result.error).toBeNull();
93
+ expect(result.tool).toBe("asaas/create_payment");
94
+ });
95
+ it("does not override a registered failure response in lenient mode", async () => {
96
+ const session = fakeSession({
97
+ "asaas/create_payment": {
98
+ success: false,
99
+ data: null,
100
+ error: "boom",
101
+ duration: 0,
102
+ server: "asaas",
103
+ tool: "asaas/create_payment",
104
+ },
105
+ }, { lenient: true });
106
+ const result = await session.execute("asaas/create_payment", { value: 100 });
107
+ expect(result.success).toBe(false);
108
+ expect(result.error).toBe("boom");
109
+ });
110
+ });
111
+ describe("fakeSession — Session interface conformance", () => {
112
+ it("returns a value assignable to Session without casts", () => {
113
+ // Compile-time check: the literal annotation forces structural conformance.
114
+ // If this file compiles, the conformance check has passed.
115
+ const session = fakeSession();
116
+ expect(typeof session.execute).toBe("function");
117
+ expect(typeof session.send).toBe("function");
118
+ expect(typeof session.sendStream).toBe("function");
119
+ expect(typeof session.proxyExecute).toBe("function");
120
+ expect(typeof session.authorize).toBe("function");
121
+ expect(typeof session.connections).toBe("function");
122
+ expect(typeof session.close).toBe("function");
123
+ expect(typeof session.discover).toBe("function");
124
+ expect(typeof session.connectionWizard).toBe("function");
125
+ expect(typeof session.charge).toBe("function");
126
+ expect(typeof session.ship).toBe("function");
127
+ expect(typeof session.paymentStatus).toBe("function");
128
+ expect(typeof session.paymentStatusStream).toBe("function");
129
+ expect(typeof session.verificationStatus).toBe("function");
130
+ expect(typeof session.verificationStatusStream).toBe("function");
131
+ });
132
+ });
133
+ //# sourceMappingURL=testing.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.test.js","sourceRoot":"","sources":["../../src/__tests__/testing.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Tool-result code guard tests.
3
+ *
4
+ * Asserts:
5
+ * - Positive + negative paths per guard.
6
+ * - Sibling-field-missing fixtures — a well-formed `code` with
7
+ * missing required siblings (e.g. `rule_id` for policy_denied)
8
+ * returns false. The guard does not narrow on the discriminant
9
+ * alone.
10
+ * - Unknown-code defense-in-depth — an unknown `code` value never
11
+ * narrows positive on any guard.
12
+ * - assertExhaustiveToolResult compiles when every variant is
13
+ * handled (the test below is the compile-time witness).
14
+ * - output.code vs error_code disagreement — guards key on the
15
+ * `code` field on the payload, ignoring sibling discrepancies.
16
+ */
17
+ export {};
18
+ //# sourceMappingURL=tool-result-codes.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-result-codes.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tool-result-codes.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Tool-result code guard tests.
3
+ *
4
+ * Asserts:
5
+ * - Positive + negative paths per guard.
6
+ * - Sibling-field-missing fixtures — a well-formed `code` with
7
+ * missing required siblings (e.g. `rule_id` for policy_denied)
8
+ * returns false. The guard does not narrow on the discriminant
9
+ * alone.
10
+ * - Unknown-code defense-in-depth — an unknown `code` value never
11
+ * narrows positive on any guard.
12
+ * - assertExhaustiveToolResult compiles when every variant is
13
+ * handled (the test below is the compile-time witness).
14
+ * - output.code vs error_code disagreement — guards key on the
15
+ * `code` field on the payload, ignoring sibling discrepancies.
16
+ */
17
+ import { describe, it, expect } from "vitest";
18
+ import { TOOL_RESULT_CODES, ToolResultCode, assertExhaustiveToolResult, isApprovalRequired, isMocksEngineError, isMocksExhausted, isPolicyDenied, isToolNotMocked, } from "../tool-result-codes.js";
19
+ describe("TOOL_RESULT_CODES set", () => {
20
+ it("includes the five canonical codes", () => {
21
+ expect(TOOL_RESULT_CODES).toContain("policy_denied");
22
+ expect(TOOL_RESULT_CODES).toContain("approval_required");
23
+ expect(TOOL_RESULT_CODES).toContain("mocks_exhausted");
24
+ expect(TOOL_RESULT_CODES).toContain("mocks_engine_error");
25
+ expect(TOOL_RESULT_CODES).toContain("tool_not_mocked");
26
+ });
27
+ });
28
+ describe("isPolicyDenied", () => {
29
+ it("returns true for a well-formed policy_denied output", () => {
30
+ const out = {
31
+ code: ToolResultCode.PolicyDenied,
32
+ rule_id: "spend_cap",
33
+ message: "exceeds tenant cap",
34
+ };
35
+ expect(isPolicyDenied(out)).toBe(true);
36
+ });
37
+ it("returns false when rule_id is missing", () => {
38
+ const out = {
39
+ code: ToolResultCode.PolicyDenied,
40
+ message: "missing rule",
41
+ };
42
+ expect(isPolicyDenied(out)).toBe(false);
43
+ });
44
+ it("returns false when message is missing", () => {
45
+ const out = {
46
+ code: ToolResultCode.PolicyDenied,
47
+ rule_id: "spend_cap",
48
+ };
49
+ expect(isPolicyDenied(out)).toBe(false);
50
+ });
51
+ it("returns false on a foreign discriminant", () => {
52
+ const out = {
53
+ code: "approval_required",
54
+ rule_id: "x",
55
+ message: "y",
56
+ };
57
+ expect(isPolicyDenied(out)).toBe(false);
58
+ });
59
+ it("returns false on an unknown code (defense in depth)", () => {
60
+ const out = {
61
+ code: "totally_made_up",
62
+ rule_id: "x",
63
+ message: "y",
64
+ };
65
+ expect(isPolicyDenied(out)).toBe(false);
66
+ });
67
+ it("returns false on null/undefined/non-object", () => {
68
+ expect(isPolicyDenied(null)).toBe(false);
69
+ expect(isPolicyDenied(undefined)).toBe(false);
70
+ expect(isPolicyDenied("policy_denied")).toBe(false);
71
+ });
72
+ });
73
+ describe("isApprovalRequired", () => {
74
+ it("returns true for a well-formed approval_required output", () => {
75
+ const out = {
76
+ code: ToolResultCode.ApprovalRequired,
77
+ approval_id: "apr_abc",
78
+ expires_at: "2026-12-01T00:00:00Z",
79
+ message: "approve the transfer",
80
+ };
81
+ expect(isApprovalRequired(out)).toBe(true);
82
+ });
83
+ it("returns false when approval_id is missing", () => {
84
+ const out = {
85
+ code: ToolResultCode.ApprovalRequired,
86
+ expires_at: "2026-12-01T00:00:00Z",
87
+ message: "x",
88
+ };
89
+ expect(isApprovalRequired(out)).toBe(false);
90
+ });
91
+ it("returns false when expires_at is missing", () => {
92
+ const out = {
93
+ code: ToolResultCode.ApprovalRequired,
94
+ approval_id: "apr_abc",
95
+ message: "x",
96
+ };
97
+ expect(isApprovalRequired(out)).toBe(false);
98
+ });
99
+ it("returns false when message is missing", () => {
100
+ const out = {
101
+ code: ToolResultCode.ApprovalRequired,
102
+ approval_id: "apr_abc",
103
+ expires_at: "x",
104
+ };
105
+ expect(isApprovalRequired(out)).toBe(false);
106
+ });
107
+ });
108
+ describe("isMocksExhausted and isMocksEngineError", () => {
109
+ it("isMocksExhausted: positive + sibling-missing", () => {
110
+ expect(isMocksExhausted({ code: ToolResultCode.MocksExhausted, message: "drained" })).toBe(true);
111
+ expect(isMocksExhausted({ code: ToolResultCode.MocksExhausted })).toBe(false);
112
+ });
113
+ it("isMocksEngineError: positive + sibling-missing", () => {
114
+ expect(isMocksEngineError({
115
+ code: ToolResultCode.MocksEngineError,
116
+ message: "consume failed",
117
+ })).toBe(true);
118
+ expect(isMocksEngineError({ code: ToolResultCode.MocksEngineError })).toBe(false);
119
+ });
120
+ });
121
+ describe("isToolNotMocked", () => {
122
+ it("returns true with tool_name + message", () => {
123
+ expect(isToolNotMocked({
124
+ code: ToolResultCode.ToolNotMocked,
125
+ tool_name: "asaas/create_payment",
126
+ message: "not in mocks map",
127
+ })).toBe(true);
128
+ });
129
+ it("returns false when tool_name is missing", () => {
130
+ expect(isToolNotMocked({ code: ToolResultCode.ToolNotMocked, message: "x" })).toBe(false);
131
+ });
132
+ });
133
+ describe("assertExhaustiveToolResult", () => {
134
+ it("compiles when every code variant is handled", () => {
135
+ // The test BODY here is the compile-time witness; runtime asserts
136
+ // the unreachable-default branch throws on a hostile cast.
137
+ function describe(value) {
138
+ switch (value.code) {
139
+ case ToolResultCode.PolicyDenied:
140
+ return "denied";
141
+ case ToolResultCode.ApprovalRequired:
142
+ return "approval";
143
+ case ToolResultCode.MocksExhausted:
144
+ return "exhausted";
145
+ case ToolResultCode.MocksEngineError:
146
+ return "engine";
147
+ case ToolResultCode.ToolNotMocked:
148
+ return "not_mocked";
149
+ default:
150
+ // If a 6th code lands without this branch being updated, TS
151
+ // fails: assertExhaustiveToolResult(value) would error at
152
+ // compile time on a non-never argument.
153
+ return assertExhaustiveToolResult(value);
154
+ }
155
+ }
156
+ expect(describe({
157
+ code: ToolResultCode.PolicyDenied,
158
+ rule_id: "x",
159
+ message: "y",
160
+ })).toBe("denied");
161
+ expect(() => assertExhaustiveToolResult({ code: "rogue" })).toThrow(/tool-result-codes/i);
162
+ });
163
+ });
164
+ //# sourceMappingURL=tool-result-codes.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-result-codes.test.js","sourceRoot":"","sources":["../../src/__tests__/tool-result-codes.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Structured exception for every transport-failure path through the
3
+ * SDK. Replaces the old `throw new Error("send failed: 500 ...")`
4
+ * shape, so callers can branch on `e.code` rather than parsing
5
+ * `e.message` strings.
6
+ *
7
+ * The reserved code namespace covers the hosted-test-mode wire
8
+ * contract (tool-result codes + create-time envelope codes —
9
+ * see the README's "Reserved error codes" section). Customers
10
+ * extending CodesparApiError should prefix their own codes (e.g.
11
+ * `"myapp.policy_denied"`) to avoid collision with reserved values.
12
+ *
13
+ * `status: 0` is reserved for network errors that never reached the
14
+ * backend; the underlying `cause` carries the original `TypeError`
15
+ * or `DOMException` that `fetch` rejected with.
16
+ */
17
+ export interface CodesparApiErrorOptions {
18
+ status: number;
19
+ code?: string;
20
+ body?: unknown;
21
+ cause?: unknown;
22
+ }
23
+ export declare class CodesparApiError extends Error {
24
+ readonly status: number;
25
+ readonly code?: string;
26
+ readonly body?: unknown;
27
+ constructor(message: string, options: CodesparApiErrorOptions);
28
+ }
29
+ /**
30
+ * Build the canonical error message + extract the structured code +
31
+ * preserve the parsed body. Centralised so every transport call site
32
+ * surfaces the same shape — a customer parsing `e.message` is
33
+ * already on the deprecated path; new code branches on `e.code`.
34
+ */
35
+ export declare function throwFromResponse(response: Response, what: string): Promise<never>;
36
+ /**
37
+ * Convert a `fetch` rejection (network error, abort, DNS, TLS, etc.)
38
+ * into a CodesparApiError with `status: 0`. Preserves the underlying
39
+ * error as `cause` so callers debugging a transport failure can dig
40
+ * into the original `TypeError`.
41
+ */
42
+ export declare function networkErrorToApiError(cause: unknown, what: string): CodesparApiError;
43
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;gBAEZ,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB;CAY9D;AAkCD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,KAAK,CAAC,CAehB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAMrF"}