@codespar/sdk 0.9.0 → 0.10.1

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 +182 -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__/shop.test.d.ts +17 -0
  19. package/dist/__tests__/shop.test.d.ts.map +1 -0
  20. package/dist/__tests__/shop.test.js +213 -0
  21. package/dist/__tests__/shop.test.js.map +1 -0
  22. package/dist/__tests__/testing.test.d.ts +2 -0
  23. package/dist/__tests__/testing.test.d.ts.map +1 -0
  24. package/dist/__tests__/testing.test.js +133 -0
  25. package/dist/__tests__/testing.test.js.map +1 -0
  26. package/dist/__tests__/tool-result-codes.test.d.ts +18 -0
  27. package/dist/__tests__/tool-result-codes.test.d.ts.map +1 -0
  28. package/dist/__tests__/tool-result-codes.test.js +164 -0
  29. package/dist/__tests__/tool-result-codes.test.js.map +1 -0
  30. package/dist/errors.d.ts +43 -0
  31. package/dist/errors.d.ts.map +1 -0
  32. package/dist/errors.js +77 -0
  33. package/dist/errors.js.map +1 -0
  34. package/dist/index.d.ts +4 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +2 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/session.d.ts.map +1 -1
  39. package/dist/session.js +128 -49
  40. package/dist/session.js.map +1 -1
  41. package/dist/testing/index.d.ts +9 -0
  42. package/dist/testing/index.d.ts.map +1 -0
  43. package/dist/testing/index.js +97 -0
  44. package/dist/testing/index.js.map +1 -0
  45. package/dist/tool-result-codes.d.ts +82 -0
  46. package/dist/tool-result-codes.d.ts.map +1 -0
  47. package/dist/tool-result-codes.js +99 -0
  48. package/dist/tool-result-codes.js.map +1 -0
  49. package/dist/types.d.ts +20 -1
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/types.js +8 -0
  52. package/dist/types.js.map +1 -1
  53. package/package.json +6 -2
package/README.md CHANGED
@@ -2,19 +2,38 @@
2
2
 
3
3
  Commerce SDK for AI agents — sessions, managed auth, Complete Loop orchestration for Latin American commercial APIs.
4
4
 
5
- ## What's new in 0.5.0
5
+ ## What's new in 0.9.0
6
6
 
7
- Typed wrappers for the F3.M2 meta-tool router:
7
+ Eight new typed methods on `Session`, grouped by capability:
8
8
 
9
- - `session.discover(query, options?)` find the right tool for a free-form use case (`codespar_discover`).
10
- - `session.connectionWizard(options)` — surface the connect deep-link when a needed server is disconnected (`codespar_manage_connections`). Credentials never travel through this method.
11
- - `session.paymentStatus(toolCallId)` — correlate webhook settlement back to the originating `codespar_pay` call via the response idempotency key.
9
+ **Meta-tool wrappers**neutral input shape, typed payload back, same wire as `session.execute(...)`:
12
10
 
13
- All three call into the same managed runtime as `session.execute(...)`; the wrappers just give you the typed payload shape without hand-rolling the meta-tool envelope.
11
+ - `session.charge(args)` INBOUND charges (`codespar_charge`). Buyer pays merchant. Pix BRL via Asaas / MP / iugu / Stone; card USD via Stripe. Distinct from `codespar_pay` (outbound transfers).
12
+ - `session.ship(args)` — shipping (`codespar_ship`). One typed entry into Melhor Envio's 3 rails (`action: "label" | "quote" | "track"`).
13
+ - `session.shop(args)` — buy-side shopping (`codespar_shop`). Catalog search → async checkout → Pix mint (`action: "search" | "checkout" | "checkout_status"`). Discriminated `ShopArgs`/`ShopResult` give the action-correct result type. Checkout is async: start, then poll `checkout_status` until `ready_for_payment` (carries `pix_copia_e_cola`) or `canceled`. Settle the returned Pix via a separate payment tool — settlement and governance are out of this contract. Full spec: [`docs/codespar-shop-contract.md`](../../docs/codespar-shop-contract.md).
14
14
 
15
- ### Crypto + KYC meta-tools (raw `execute()` only)
15
+ **Async settlement** `codespar_charge` / `codespar_pay` return synchronously, but real settlement lands via webhook:
16
16
 
17
- Two newer meta-tools `codespar_crypto_pay` (USDC/USDT/BTC across mainnet + L2s) and `codespar_kyc` (Persona / Sift / etc identity + risk verification) are callable today via raw `session.execute(...)`. Typed SDK wrappers will land in a future release once at least 2 transforms per meta-tool are live in prod.
17
+ - `session.paymentStatus(toolCallId)` poll the latest known status (pending succeeded / failed / refunded). Correlates via the response idempotency_key provider external_reference.
18
+ - `session.paymentStatusStream(toolCallId, { onUpdate?, signal? })` — SSE variant. Snapshot on open, an envelope per state change, heartbeat every 15s, auto-closes 5s after a terminal state. `signal` aborts from the caller side.
19
+
20
+ **Async verification** — `codespar_kyc` returns the inquiry id; the buyer finishes the hosted flow off-platform:
21
+
22
+ - `session.verificationStatus(toolCallId)` — poll the disposition (pending → approved / rejected / review / expired).
23
+ - `session.verificationStatusStream(toolCallId, { onUpdate?, signal? })` — SSE variant. Same lifecycle as `paymentStatusStream`.
24
+
25
+ **Tool discovery + connection wizard** (already in 0.4.0, restated for completeness):
26
+
27
+ - `session.discover(query, options?)` — semantic + lexical tool search across the catalog (`codespar_discover`, pgvector + pg_trgm).
28
+ - `session.connectionWizard(options)` — connect deep-link backend (`codespar_manage_connections`). Credentials never travel through this method.
29
+
30
+ All wrappers call into the same runtime as `session.execute(...)`; you get typed payloads instead of hand-rolling the meta-tool envelope.
31
+
32
+ > **The typed meta-tool facades (`shop()`, `charge()`, `ship()`, …) are clients, not implementations.** Each is a thin wrapper over `execute("codespar_<tool>", args)` and requires a runtime that **implements** that meta-tool (a registered implementation behind the contract). Against a self-hosted runtime with no registered implementation, the call returns `Tool not registered`. The contract + the typed facade ship here MIT; the implementation is registered by the runtime you point `baseUrl` at.
33
+
34
+ ### Crypto + KYC meta-tools
35
+
36
+ `codespar_crypto_pay` (Coinbase Commerce + Bitso + UnblockPay + Foxbit) and `codespar_kyc` (Persona, Sift, Konduto, Truora) are routable today. The verification half now has a typed wrapper (`session.verificationStatus` / `verificationStatusStream`); a `session.cryptoPay(...)` typed wrapper is not in 0.9.0 — call via raw `session.execute("codespar_crypto_pay", {...})` for now.
18
37
 
19
38
  ```typescript
20
39
  // Crypto: receive a USDC payment via Coinbase Commerce hosted checkout
@@ -26,12 +45,26 @@ const charge = await session.execute("codespar_crypto_pay", {
26
45
  });
27
46
  // charge.output.hosted_url → redirect buyer here
28
47
 
29
- // KYC: kick off a Persona identity verification
48
+ // Crypto: send a USDC payout to an external wallet (UnblockPay stablecoin-payout)
49
+ const payout = await session.execute("codespar_crypto_pay", {
50
+ rail: "stablecoin-payout",
51
+ amount: 100,
52
+ currency: "USDC",
53
+ direction: "send",
54
+ counterparty: {
55
+ address: "0xRecipientWalletAddress...",
56
+ country: "MX", // ISO 3166-1 alpha-2 — required when direction is "send"
57
+ },
58
+ });
59
+ // payout.output.id / .status → poll via session.paymentStatus(payout.tool_call_id)
60
+
61
+ // KYC: kick off a Persona identity verification, then poll typed
30
62
  const inquiry = await session.execute("codespar_kyc", {
31
63
  buyer: { email: "alice@example.com", first_name: "Alice", last_name: "Smith" },
32
64
  check_type: "identity",
33
65
  });
34
- // inquiry.output.verification_id poll for completion
66
+ const v = await session.verificationStatus(inquiry.tool_call_id);
67
+ // ^^ approved | rejected | review | expired | pending
35
68
  ```
36
69
 
37
70
  ## Install
@@ -57,9 +90,10 @@ const session = await cs.create("user_123", {
57
90
  const result = await session.send("Charge R$150 via Pix and issue the NF-e");
58
91
 
59
92
  // Direct tool execution
60
- const charge = await session.execute("ZOOP_CREATE_CHARGE", {
61
- amount: 150.0,
62
- payment_type: "pix",
93
+ const charge = await session.execute("asaas/create_payment", {
94
+ customer: "cus_xxx",
95
+ billingType: "PIX",
96
+ value: 150,
63
97
  });
64
98
 
65
99
  // Complete Loop — tools, findTools, and loop are free functions
@@ -70,10 +104,10 @@ const payments = await findTools(session, "payment");
70
104
 
71
105
  const result = await loop(session, {
72
106
  steps: [
73
- { tool: "ZOOP_CREATE_CHARGE", params: { amount: 150, payment_type: "pix" } },
74
- { tool: "NUVEMFISCAL_EMITIR_NFE", params: (prev) => ({ chargeId: prev[0].data }) },
75
- { tool: "MELHORENVIO_GENERATE_LABEL", params: {} },
76
- { tool: "ZAPI_SEND_MESSAGE", params: { text: "Your order is on the way!" } },
107
+ { tool: "codespar_charge", params: { amount: 150, currency: "BRL", method: "pix", buyer: { name, document: cpf } } },
108
+ { tool: "codespar_invoice", params: (prev) => ({ rail: "nfe", company_id, payment_id: prev[0].data.id }) },
109
+ { tool: "codespar_ship", params: { action: "label", origin, destination, items } },
110
+ { tool: "codespar_notify", params: { recipient: phone, message: "Your order is on the way!" } },
77
111
  ],
78
112
  onStepComplete: (step, r) => console.log(`✓ ${step.tool}`),
79
113
  retryPolicy: { maxRetries: 3, backoff: "exponential" },
@@ -87,7 +121,7 @@ const result = await loop(session, {
87
121
  | Option | Type | Default | Description |
88
122
  |--------|------|---------|-------------|
89
123
  | `apiKey` | `string` | `CODESPAR_API_KEY` env | Your API key |
90
- | `baseUrl` | `string` | `https://api.codespar.dev` | API base URL |
124
+ | `baseUrl` | `string` | `CODESPAR_BASE_URL` env, else `https://api.codespar.dev` | API base URL. Set `CODESPAR_BASE_URL=http://localhost:8000` to point the SDK at a [local OSS runtime](https://github.com/codespar/codespar); the managed backend is the default. |
91
125
  | `managed` | `boolean` | `true` | Enable managed billing/logging |
92
126
  | `projectId` | `string` | — | Optional `prj_<16alphanum>`. Client-wide default project; sent as `x-codespar-project`. Falls back to the org's default project when omitted. |
93
127
 
@@ -99,6 +133,7 @@ const result = await loop(session, {
99
133
  | `preset` | `string` | `"brazilian"`, `"mexican"`, `"argentinian"`, `"colombian"`, `"all"` |
100
134
  | `manageConnections.waitForConnections` | `boolean` | Block until all servers connected |
101
135
  | `projectId` | `string` | Optional `prj_<16alphanum>`. Overrides the client-level `projectId`; falls back to the org's default project when both are unset. |
136
+ | `mocks` | `Record<string, MockValue>` | Optional test-mode mocks. See [Test-mode mocks](#test-mode-mocks). |
102
137
 
103
138
  ### Session methods
104
139
 
@@ -112,7 +147,12 @@ const result = await loop(session, {
112
147
  | `session.connections()` | List connected servers |
113
148
  | `session.discover(query, options?)` | Tool search via `codespar_discover` (typed) |
114
149
  | `session.connectionWizard(options)` | Connect deep-link via `codespar_manage_connections` (typed) |
115
- | `session.paymentStatus(toolCallId)` | Async settlement status for a `codespar_pay` call |
150
+ | `session.charge(args)` | Inbound charge via `codespar_charge` (typed) — buyer pays merchant |
151
+ | `session.ship(args)` | Shipping via `codespar_ship` (typed) — `action: "label" \| "quote" \| "track"` |
152
+ | `session.paymentStatus(toolCallId)` | Async settlement status for a `codespar_charge` / `codespar_pay` call |
153
+ | `session.paymentStatusStream(toolCallId, opts)` | SSE variant of `paymentStatus`; resolves on terminal |
154
+ | `session.verificationStatus(toolCallId)` | Async KYC disposition for a `codespar_kyc` call |
155
+ | `session.verificationStatusStream(toolCallId, opts)` | SSE variant of `verificationStatus`; resolves on terminal |
116
156
  | `session.mcp` | MCP transport URL and headers (when using managed runtime) |
117
157
  | `session.close()` | Close session |
118
158
 
@@ -167,6 +207,129 @@ const session = await cs.create("user_123", {
167
207
 
168
208
  Precedence: `sessionConfig.projectId` > `clientConfig.projectId` > backend's org default. Format is validated at construction via Zod (`/^prj_[A-Za-z0-9]{16}$/`) so typos fail fast. See the [Projects concept doc](https://docs.codespar.dev/concepts/projects) for the full tenancy model.
169
209
 
210
+ ## Test-mode mocks
211
+
212
+ Skip live providers in tests by passing a `mocks` map to `cs.create`. Keys are canonical tool names in slash form (`asaas/create_payment`, `melhor-envio/calculate_shipping`, …). Values are either a single object — used as the response on every matching call — or an array of objects consumed in order, returning `mocks_exhausted` once the list drains.
213
+
214
+ ```typescript
215
+ import { CodeSpar } from "@codespar/sdk";
216
+
217
+ const cs = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });
218
+
219
+ const session = await cs.create("user_test", {
220
+ servers: ["asaas"],
221
+ mocks: {
222
+ "asaas/create_payment": { id: "pay_test", status: "PENDING" },
223
+ },
224
+ });
225
+
226
+ const result = await session.execute("asaas/create_payment", { value: 100 });
227
+ // result.data === { id: "pay_test", status: "PENDING" }
228
+ ```
229
+
230
+ Pass an array for stateful mocks:
231
+
232
+ ```typescript
233
+ mocks: {
234
+ "asaas/create_payment": [
235
+ { id: "pay_1", status: "PENDING" },
236
+ { id: "pay_1", status: "RECEIVED" },
237
+ ],
238
+ }
239
+ ```
240
+
241
+ Mocks live behind the managed backend's test-mode gate — a `csk_test_*` API key against a `test`-environment project. Live keys against the same map return `mocks_not_permitted`. The SDK forwards keys verbatim; if you send the OSS double-underscore form (`asaas__create_payment`) the backend rejects with `mocks_invalid` rather than the SDK silently rewriting.
242
+
243
+ The OSS runtime accepts the same `mocks` shape on its session API (see [codespar/codespar#113](https://github.com/codespar/codespar/pull/113)), so the same test fixtures work whether you point at `api.codespar.dev` or a self-hosted instance via `CODESPAR_BASE_URL`. Self-hosted runtimes must additionally set `CODESPAR_TEST_MODE_ENABLED=true` on the server process; without it, the SDK receives `mocks_not_permitted` / HTTP 501 instead of fixture responses.
244
+
245
+ Storage shape differs by runtime — the wire contract does not. The managed backend persists mocks and per-tool consume counters; sessions and their fixtures survive restarts and multi-replica deployments. The OSS runtime holds both in process memory; they are scoped to the HTTP-session process and are lost on restart, and channel-bridge sessions (WhatsApp, Slack, Telegram, Discord) cannot carry mocks under the OSS shape. Response envelopes, status codes, sibling fields, and gate ordering are byte-identical between runtimes regardless. See [the test-mode concept doc](https://docs.codespar.dev/concepts/test-mode) for the full per-runtime split.
246
+
247
+ Test mode is a property of the runtime, not the session. On the managed backend it's `project.environment === 'test'`; on a self-hosted OSS runtime it's `CODESPAR_TEST_MODE_ENABLED=true` on the server process. When the runtime is in test mode, every external tool call your code or LLM dispatches must match a declared mock — unmatched calls return `tool_not_mocked` (HTTP 422 on the catalog-routed `/execute` path; a `tool_result` block on the chat-loop) and no upstream provider runs. The envelope covers three failure modes: the `mocks` map has no entry for the canonical name, the session was created with no `mocks` field, or the canonical name has an unknown server prefix. A session that doesn't declare `mocks` can't dispatch any tools in test mode; declare the mocks the test will exercise, or run the same code against a live-mode runtime where the real providers handle dispatch. Built-in metadata tools — `codespar_list_tools` on OSS, `codespar_discover` and `codespar_manage_connections` on the managed backend — bypass this gate.
248
+
249
+ ### Type aliases
250
+
251
+ `MockObject` (`Record<string, unknown>`) and `MockValue` (`MockObject | MockObject[]`) ship from `@codespar/types` and re-export through `@codespar/sdk`. Use them when you want to define mock fixtures separately from the `create` call site.
252
+
253
+ ```typescript
254
+ import type { MockValue } from "@codespar/sdk";
255
+
256
+ const fixtures: Record<string, MockValue> = {
257
+ "asaas/create_payment": { id: "pay_test", status: "PENDING" },
258
+ };
259
+ ```
260
+
261
+ ## Typed errors
262
+
263
+ Every transport failure from `createSession`, `proxyExecute`, `send`, `sendStream`, `paymentStatus(Stream)`, `verificationStatus(Stream)`, and `authorize` throws a `CodesparApiError` with a structured `code` field. The old `e.message.includes("foo")` pattern is gone — branch on `e.code` instead.
264
+
265
+ ```typescript
266
+ import { CodesparApiError } from "@codespar/sdk";
267
+
268
+ try {
269
+ await cs.create("user_test", { mocks: { "asaas/create_payment": {} } });
270
+ } catch (err) {
271
+ if (err instanceof CodesparApiError) {
272
+ if (err.code === "mocks_not_permitted") {
273
+ // Live key against a mocks map. Swap to csk_test_*.
274
+ } else if (err.code === "mocks_invalid") {
275
+ // Backend rejected a tool-name key. Check the slash form.
276
+ } else if (err.status === 0) {
277
+ // Network never reached the backend; err.cause has the fetch rejection.
278
+ }
279
+ throw err;
280
+ }
281
+ }
282
+ ```
283
+
284
+ `session.execute` keeps its returns-vs-throws asymmetry: tool failures come back as `ToolResult.success === false` with the body on `error`. Only transport-level failures throw.
285
+
286
+ ### Tool-result guards
287
+
288
+ The five reserved tool-result codes (`policy_denied`, `approval_required`, `mocks_exhausted`, `mocks_engine_error`, `tool_not_mocked`) ship typed guards plus an exhaustive-match helper. Guards run against any `unknown` payload — both `ToolResult.data` from `session.execute` and `ToolCallRecord.output` from `send` / `sendStream`. Each guard checks the `code` discriminant AND the variant's required sibling fields, so a malformed payload returns false rather than narrowing positive on the code alone.
289
+
290
+ ```typescript
291
+ import {
292
+ isApprovalRequired,
293
+ isMocksEngineError,
294
+ isMocksExhausted,
295
+ isPolicyDenied,
296
+ isToolNotMocked,
297
+ assertExhaustiveToolResult,
298
+ ToolResultCode,
299
+ } from "@codespar/sdk";
300
+
301
+ const result = await session.execute("asaas/create_payment", { value: 100 });
302
+
303
+ if (isPolicyDenied(result.data)) {
304
+ console.warn(`blocked by ${result.data.rule_id}: ${result.data.message}`);
305
+ } else if (isApprovalRequired(result.data)) {
306
+ console.log(`needs approval ${result.data.approval_id} by ${result.data.expires_at}`);
307
+ } else if (isMocksExhausted(result.data)) {
308
+ // Stateful mock array drained — pad it or extend the test.
309
+ } else if (isMocksEngineError(result.data)) {
310
+ // Backend-side mocks engine failure; usually a malformed fixture.
311
+ } else if (isToolNotMocked(result.data)) {
312
+ console.warn(`no mock for ${result.data.tool_name}`);
313
+ }
314
+ ```
315
+
316
+ The same guards apply inside a `sendStream` loop against `event.toolCall.output`.
317
+
318
+ When a `switch` over `ToolResultCode` covers every variant, call `assertExhaustiveToolResult` in the default branch. TypeScript fails to compile if a sixth code lands without a matching arm.
319
+
320
+ ```typescript
321
+ function handle(outcome: ToolResultOutcome): string {
322
+ switch (outcome.code) {
323
+ case ToolResultCode.PolicyDenied: return outcome.rule_id;
324
+ case ToolResultCode.ApprovalRequired: return outcome.approval_id;
325
+ case ToolResultCode.MocksExhausted: return "exhausted";
326
+ case ToolResultCode.MocksEngineError: return "engine";
327
+ case ToolResultCode.ToolNotMocked: return outcome.tool_name;
328
+ default: return assertExhaustiveToolResult(outcome);
329
+ }
330
+ }
331
+ ```
332
+
170
333
  ## Need more?
171
334
 
172
335
  Need governance, budget limits, and audit trails for agent payments? **[CodeSpar Enterprise](https://codespar.dev/enterprise)** adds policy engine, payment routing, and compliance templates on top of these MCP servers.
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `CODESPAR_BASE_URL` env-var resolution for the TS client.
3
+ *
4
+ * The constructor cascade is: explicit `baseUrl` option, then the
5
+ * `CODESPAR_BASE_URL` env var, then the production default. The env
6
+ * var lets a caller point the same client wiring at a local OSS
7
+ * runtime or at `api.codespar.dev` without rebuilding the call sites.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=base-url-resolution.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-url-resolution.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/base-url-resolution.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * `CODESPAR_BASE_URL` env-var resolution for the TS client.
3
+ *
4
+ * The constructor cascade is: explicit `baseUrl` option, then the
5
+ * `CODESPAR_BASE_URL` env var, then the production default. The env
6
+ * var lets a caller point the same client wiring at a local OSS
7
+ * runtime or at `api.codespar.dev` without rebuilding the call sites.
8
+ */
9
+ import { describe, it, expect } from "vitest";
10
+ import { CodeSpar } from "../index.js";
11
+ describe("CODESPAR_BASE_URL env-var fallback", () => {
12
+ it("uses CODESPAR_BASE_URL when no explicit baseUrl is passed", () => {
13
+ const prevBase = process.env.CODESPAR_BASE_URL;
14
+ const prevKey = process.env.CODESPAR_API_KEY;
15
+ process.env.CODESPAR_BASE_URL = "https://oss.codespar.local";
16
+ process.env.CODESPAR_API_KEY = "csk_live_test";
17
+ try {
18
+ const cs = new CodeSpar();
19
+ // baseUrl is private; the smoke test is that construction
20
+ // succeeds and the default does NOT override an env override.
21
+ // The behavior is exercised via createSession's URL prefix in
22
+ // the integration tests.
23
+ expect(cs).toBeDefined();
24
+ }
25
+ finally {
26
+ if (prevBase === undefined)
27
+ delete process.env.CODESPAR_BASE_URL;
28
+ else
29
+ process.env.CODESPAR_BASE_URL = prevBase;
30
+ if (prevKey === undefined)
31
+ delete process.env.CODESPAR_API_KEY;
32
+ else
33
+ process.env.CODESPAR_API_KEY = prevKey;
34
+ }
35
+ });
36
+ it("explicit baseUrl wins over CODESPAR_BASE_URL env var", () => {
37
+ const prev = process.env.CODESPAR_BASE_URL;
38
+ process.env.CODESPAR_BASE_URL = "https://oss.codespar.local";
39
+ try {
40
+ const cs = new CodeSpar({
41
+ apiKey: "csk_live_x",
42
+ baseUrl: "https://override.example.com",
43
+ });
44
+ // Smoke — construction succeeds with both set. The wire-level
45
+ // behavior is covered by createSession tests that fetch-mock
46
+ // the URL prefix directly.
47
+ expect(cs).toBeDefined();
48
+ }
49
+ finally {
50
+ if (prev === undefined)
51
+ delete process.env.CODESPAR_BASE_URL;
52
+ else
53
+ process.env.CODESPAR_BASE_URL = prev;
54
+ }
55
+ });
56
+ });
57
+ //# sourceMappingURL=base-url-resolution.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-url-resolution.test.js","sourceRoot":"","sources":["../../src/__tests__/base-url-resolution.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAC/C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,4BAA4B,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,eAAe,CAAC;QAC/C,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC1B,0DAA0D;YAC1D,8DAA8D;YAC9D,8DAA8D;YAC9D,yBAAyB;YACzB,MAAM,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAC3B,CAAC;gBAAS,CAAC;YACT,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;;gBAC5D,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,QAAQ,CAAC;YAC9C,IAAI,OAAO,KAAK,SAAS;gBAAE,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;;gBAC1D,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,OAAO,CAAC;QAC9C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,4BAA4B,CAAC;QAC7D,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC;gBACtB,MAAM,EAAE,YAAY;gBACpB,OAAO,EAAE,8BAA8B;aACxC,CAAC,CAAC;YACH,8DAA8D;YAC9D,6DAA6D;YAC7D,2BAA2B;YAC3B,MAAM,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAC3B,CAAC;gBAAS,CAAC;YACT,IAAI,IAAI,KAAK,SAAS;gBAAE,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;;gBACxD,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Tests for CodesparApiError + the throwFromResponse helper that
3
+ * collapses all transport-failure throw sites in session.ts.
4
+ *
5
+ * Asserts:
6
+ * - Every transport throw site surfaces a CodesparApiError (not
7
+ * a plain Error) carrying status + code + body.
8
+ * - Network errors wrap fetch rejections into CodesparApiError
9
+ * with status: 0 and preserve the underlying cause.
10
+ * - The session.execute non-ok branch is untouched — it still
11
+ * returns ToolResult.success === false rather than throwing.
12
+ * - instanceof CodesparApiError works across realms (prototype
13
+ * chain is restored via Object.setPrototypeOf).
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=errors.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/errors.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Tests for CodesparApiError + the throwFromResponse helper that
3
+ * collapses all transport-failure throw sites in session.ts.
4
+ *
5
+ * Asserts:
6
+ * - Every transport throw site surfaces a CodesparApiError (not
7
+ * a plain Error) carrying status + code + body.
8
+ * - Network errors wrap fetch rejections into CodesparApiError
9
+ * with status: 0 and preserve the underlying cause.
10
+ * - The session.execute non-ok branch is untouched — it still
11
+ * returns ToolResult.success === false rather than throwing.
12
+ * - instanceof CodesparApiError works across realms (prototype
13
+ * chain is restored via Object.setPrototypeOf).
14
+ */
15
+ import { describe, it, expect, vi, afterEach } from "vitest";
16
+ import { CodesparApiError } from "../errors.js";
17
+ import { CodeSpar } from "../index.js";
18
+ describe("CodesparApiError", () => {
19
+ it("constructs with status + message", () => {
20
+ const err = new CodesparApiError("boom", { status: 500 });
21
+ expect(err.status).toBe(500);
22
+ expect(err.message).toBe("boom");
23
+ expect(err.code).toBeUndefined();
24
+ expect(err.body).toBeUndefined();
25
+ });
26
+ it("carries the structured code + body + cause", () => {
27
+ const cause = new Error("underlying");
28
+ const err = new CodesparApiError("boom", {
29
+ status: 403,
30
+ code: "mocks_not_permitted",
31
+ body: { error: "mocks_not_permitted", message: "test mode key required" },
32
+ cause,
33
+ });
34
+ expect(err.status).toBe(403);
35
+ expect(err.code).toBe("mocks_not_permitted");
36
+ expect(err.body).toEqual({
37
+ error: "mocks_not_permitted",
38
+ message: "test mode key required",
39
+ });
40
+ expect(err.cause).toBe(cause);
41
+ });
42
+ it("instanceof CodesparApiError works after prototype-chain repair", () => {
43
+ const err = new CodesparApiError("x", { status: 1 });
44
+ expect(err instanceof CodesparApiError).toBe(true);
45
+ expect(err instanceof Error).toBe(true);
46
+ expect(err.name).toBe("CodesparApiError");
47
+ });
48
+ });
49
+ describe("session transport-failure call sites throw CodesparApiError", () => {
50
+ const originalFetch = globalThis.fetch;
51
+ afterEach(() => {
52
+ globalThis.fetch = originalFetch;
53
+ });
54
+ it("createSession throws CodesparApiError on 4xx with structured body", async () => {
55
+ globalThis.fetch = vi.fn().mockResolvedValue({
56
+ ok: false,
57
+ status: 403,
58
+ text: async () => JSON.stringify({
59
+ error: "mocks_not_permitted",
60
+ message: "csk_test_* key required",
61
+ }),
62
+ });
63
+ const cs = new CodeSpar({
64
+ apiKey: "csk_live_test",
65
+ baseUrl: "https://api.example.com",
66
+ });
67
+ try {
68
+ await cs.create("user_42");
69
+ expect.fail("expected createSession to throw");
70
+ }
71
+ catch (err) {
72
+ expect(err).toBeInstanceOf(CodesparApiError);
73
+ const apiErr = err;
74
+ expect(apiErr.status).toBe(403);
75
+ expect(apiErr.code).toBe("mocks_not_permitted");
76
+ }
77
+ });
78
+ it("createSession wraps fetch rejection as CodesparApiError status 0", async () => {
79
+ const underlying = new TypeError("Network failure");
80
+ globalThis.fetch = vi
81
+ .fn()
82
+ .mockRejectedValue(underlying);
83
+ const cs = new CodeSpar({
84
+ apiKey: "csk_live_test",
85
+ baseUrl: "https://api.example.com",
86
+ });
87
+ try {
88
+ await cs.create("user_42");
89
+ expect.fail("expected createSession to throw");
90
+ }
91
+ catch (err) {
92
+ expect(err).toBeInstanceOf(CodesparApiError);
93
+ const apiErr = err;
94
+ expect(apiErr.status).toBe(0);
95
+ expect(apiErr.cause).toBe(underlying);
96
+ }
97
+ });
98
+ it("send throws CodesparApiError on 5xx", async () => {
99
+ const sessionCreate = {
100
+ ok: true,
101
+ status: 201,
102
+ text: async () => "",
103
+ json: async () => ({
104
+ id: "ses_err",
105
+ org_id: "o",
106
+ user_id: "u",
107
+ servers: [],
108
+ status: "active",
109
+ created_at: new Date().toISOString(),
110
+ closed_at: null,
111
+ }),
112
+ };
113
+ const sendFail = {
114
+ ok: false,
115
+ status: 502,
116
+ text: async () => JSON.stringify({ code: "upstream_unavailable" }),
117
+ };
118
+ globalThis.fetch = vi
119
+ .fn()
120
+ .mockResolvedValueOnce(sessionCreate)
121
+ .mockResolvedValueOnce(sendFail);
122
+ const cs = new CodeSpar({
123
+ apiKey: "csk_live_test",
124
+ baseUrl: "https://api.example.com",
125
+ });
126
+ const session = await cs.create("u");
127
+ await expect(session.send("hi")).rejects.toBeInstanceOf(CodesparApiError);
128
+ });
129
+ it("session.execute does NOT throw on non-ok — returns ToolResult.success=false", async () => {
130
+ const sessionCreate = {
131
+ ok: true,
132
+ status: 201,
133
+ text: async () => "",
134
+ json: async () => ({
135
+ id: "ses_ok",
136
+ org_id: "o",
137
+ user_id: "u",
138
+ servers: [],
139
+ status: "active",
140
+ created_at: new Date().toISOString(),
141
+ closed_at: null,
142
+ }),
143
+ };
144
+ const execFail = {
145
+ ok: false,
146
+ status: 422,
147
+ text: async () => "validation failed",
148
+ };
149
+ globalThis.fetch = vi
150
+ .fn()
151
+ .mockResolvedValueOnce(sessionCreate)
152
+ .mockResolvedValueOnce(execFail);
153
+ const cs = new CodeSpar({
154
+ apiKey: "csk_live_test",
155
+ baseUrl: "https://api.example.com",
156
+ });
157
+ const session = await cs.create("u");
158
+ const result = await session.execute("asaas/create_payment", {});
159
+ expect(result.success).toBe(false);
160
+ expect(result.error).toContain("422");
161
+ });
162
+ });
163
+ //# sourceMappingURL=errors.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.js","sourceRoot":"","sources":["../../src/__tests__/errors.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
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
+ export {};
15
+ //# sourceMappingURL=forward-mocks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forward-mocks.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/forward-mocks.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}