@codespar/sdk 0.3.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.
- package/README.md +191 -9
- package/dist/__tests__/base-url-resolution.test.d.ts +10 -0
- package/dist/__tests__/base-url-resolution.test.d.ts.map +1 -0
- package/dist/__tests__/base-url-resolution.test.js +57 -0
- package/dist/__tests__/base-url-resolution.test.js.map +1 -0
- package/dist/__tests__/errors.test.d.ts +16 -0
- package/dist/__tests__/errors.test.d.ts.map +1 -0
- package/dist/__tests__/errors.test.js +163 -0
- package/dist/__tests__/errors.test.js.map +1 -0
- package/dist/__tests__/forward-mocks.test.d.ts +15 -0
- package/dist/__tests__/forward-mocks.test.d.ts.map +1 -0
- package/dist/__tests__/forward-mocks.test.js +134 -0
- package/dist/__tests__/forward-mocks.test.js.map +1 -0
- package/dist/__tests__/mocks-wire-parity.test.d.ts +15 -0
- package/dist/__tests__/mocks-wire-parity.test.d.ts.map +1 -0
- package/dist/__tests__/mocks-wire-parity.test.js +71 -0
- package/dist/__tests__/mocks-wire-parity.test.js.map +1 -0
- package/dist/__tests__/testing.test.d.ts +2 -0
- package/dist/__tests__/testing.test.d.ts.map +1 -0
- package/dist/__tests__/testing.test.js +133 -0
- package/dist/__tests__/testing.test.js.map +1 -0
- package/dist/__tests__/tool-result-codes.test.d.ts +18 -0
- package/dist/__tests__/tool-result-codes.test.d.ts.map +1 -0
- package/dist/__tests__/tool-result-codes.test.js +164 -0
- package/dist/__tests__/tool-result-codes.test.js.map +1 -0
- package/dist/errors.d.ts +43 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +77 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +237 -35
- package/dist/session.js.map +1 -1
- package/dist/testing/index.d.ts +9 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +68 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/tool-result-codes.d.ts +82 -0
- package/dist/tool-result-codes.d.ts.map +1 -0
- package/dist/tool-result-codes.js +99 -0
- package/dist/tool-result-codes.js.map +1 -0
- package/dist/types.d.ts +20 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -2,6 +2,55 @@
|
|
|
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.9.0
|
|
6
|
+
|
|
7
|
+
Eight new typed methods on `Session`, grouped by capability:
|
|
8
|
+
|
|
9
|
+
**Meta-tool wrappers** — neutral input shape, typed payload back, same wire as `session.execute(...)`:
|
|
10
|
+
|
|
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
|
+
|
|
14
|
+
**Async settlement** — `codespar_charge` / `codespar_pay` return synchronously, but real settlement lands via webhook:
|
|
15
|
+
|
|
16
|
+
- `session.paymentStatus(toolCallId)` — poll the latest known status (pending → succeeded / failed / refunded). Correlates via the response idempotency_key ↔ provider external_reference.
|
|
17
|
+
- `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.
|
|
18
|
+
|
|
19
|
+
**Async verification** — `codespar_kyc` returns the inquiry id; the buyer finishes the hosted flow off-platform:
|
|
20
|
+
|
|
21
|
+
- `session.verificationStatus(toolCallId)` — poll the disposition (pending → approved / rejected / review / expired).
|
|
22
|
+
- `session.verificationStatusStream(toolCallId, { onUpdate?, signal? })` — SSE variant. Same lifecycle as `paymentStatusStream`.
|
|
23
|
+
|
|
24
|
+
**Tool discovery + connection wizard** (already in 0.4.0, restated for completeness):
|
|
25
|
+
|
|
26
|
+
- `session.discover(query, options?)` — semantic + lexical tool search across the catalog (`codespar_discover`, pgvector + pg_trgm).
|
|
27
|
+
- `session.connectionWizard(options)` — connect deep-link backend (`codespar_manage_connections`). Credentials never travel through this method.
|
|
28
|
+
|
|
29
|
+
All wrappers call into the same managed runtime as `session.execute(...)`; you get typed payloads instead of hand-rolling the meta-tool envelope.
|
|
30
|
+
|
|
31
|
+
### Crypto + KYC meta-tools
|
|
32
|
+
|
|
33
|
+
`codespar_crypto_pay` (Coinbase Commerce + Bitso) 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.
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// Crypto: receive a USDC payment via Coinbase Commerce hosted checkout
|
|
37
|
+
const charge = await session.execute("codespar_crypto_pay", {
|
|
38
|
+
amount: 29.9,
|
|
39
|
+
currency: "USDC",
|
|
40
|
+
direction: "receive",
|
|
41
|
+
description: "Order #42",
|
|
42
|
+
});
|
|
43
|
+
// charge.output.hosted_url → redirect buyer here
|
|
44
|
+
|
|
45
|
+
// KYC: kick off a Persona identity verification, then poll typed
|
|
46
|
+
const inquiry = await session.execute("codespar_kyc", {
|
|
47
|
+
buyer: { email: "alice@example.com", first_name: "Alice", last_name: "Smith" },
|
|
48
|
+
check_type: "identity",
|
|
49
|
+
});
|
|
50
|
+
const v = await session.verificationStatus(inquiry.tool_call_id);
|
|
51
|
+
// ^^ approved | rejected | review | expired | pending
|
|
52
|
+
```
|
|
53
|
+
|
|
5
54
|
## Install
|
|
6
55
|
|
|
7
56
|
```bash
|
|
@@ -25,9 +74,10 @@ const session = await cs.create("user_123", {
|
|
|
25
74
|
const result = await session.send("Charge R$150 via Pix and issue the NF-e");
|
|
26
75
|
|
|
27
76
|
// Direct tool execution
|
|
28
|
-
const charge = await session.execute("
|
|
29
|
-
|
|
30
|
-
|
|
77
|
+
const charge = await session.execute("asaas/create_payment", {
|
|
78
|
+
customer: "cus_xxx",
|
|
79
|
+
billingType: "PIX",
|
|
80
|
+
value: 150,
|
|
31
81
|
});
|
|
32
82
|
|
|
33
83
|
// Complete Loop — tools, findTools, and loop are free functions
|
|
@@ -38,10 +88,10 @@ const payments = await findTools(session, "payment");
|
|
|
38
88
|
|
|
39
89
|
const result = await loop(session, {
|
|
40
90
|
steps: [
|
|
41
|
-
{ tool: "
|
|
42
|
-
{ tool: "
|
|
43
|
-
{ tool: "
|
|
44
|
-
{ tool: "
|
|
91
|
+
{ tool: "codespar_charge", params: { amount: 150, currency: "BRL", method: "pix", buyer: { name, document: cpf } } },
|
|
92
|
+
{ tool: "codespar_invoice", params: (prev) => ({ rail: "nfe", company_id, payment_id: prev[0].data.id }) },
|
|
93
|
+
{ tool: "codespar_ship", params: { action: "label", origin, destination, items } },
|
|
94
|
+
{ tool: "codespar_notify", params: { recipient: phone, message: "Your order is on the way!" } },
|
|
45
95
|
],
|
|
46
96
|
onStepComplete: (step, r) => console.log(`✓ ${step.tool}`),
|
|
47
97
|
retryPolicy: { maxRetries: 3, backoff: "exponential" },
|
|
@@ -55,7 +105,7 @@ const result = await loop(session, {
|
|
|
55
105
|
| Option | Type | Default | Description |
|
|
56
106
|
|--------|------|---------|-------------|
|
|
57
107
|
| `apiKey` | `string` | `CODESPAR_API_KEY` env | Your API key |
|
|
58
|
-
| `baseUrl` | `string` | `https://api.codespar.dev` | API base URL |
|
|
108
|
+
| `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. |
|
|
59
109
|
| `managed` | `boolean` | `true` | Enable managed billing/logging |
|
|
60
110
|
| `projectId` | `string` | — | Optional `prj_<16alphanum>`. Client-wide default project; sent as `x-codespar-project`. Falls back to the org's default project when omitted. |
|
|
61
111
|
|
|
@@ -67,6 +117,7 @@ const result = await loop(session, {
|
|
|
67
117
|
| `preset` | `string` | `"brazilian"`, `"mexican"`, `"argentinian"`, `"colombian"`, `"all"` |
|
|
68
118
|
| `manageConnections.waitForConnections` | `boolean` | Block until all servers connected |
|
|
69
119
|
| `projectId` | `string` | Optional `prj_<16alphanum>`. Overrides the client-level `projectId`; falls back to the org's default project when both are unset. |
|
|
120
|
+
| `mocks` | `Record<string, MockValue>` | Optional test-mode mocks. See [Test-mode mocks](#test-mode-mocks). |
|
|
70
121
|
|
|
71
122
|
### Session methods
|
|
72
123
|
|
|
@@ -78,6 +129,14 @@ const result = await loop(session, {
|
|
|
78
129
|
| `session.authorize(serverId)` | Start OAuth flow for a server |
|
|
79
130
|
| `session.proxyExecute(request)` | Proxy a raw HTTP call through the session |
|
|
80
131
|
| `session.connections()` | List connected servers |
|
|
132
|
+
| `session.discover(query, options?)` | Tool search via `codespar_discover` (typed) |
|
|
133
|
+
| `session.connectionWizard(options)` | Connect deep-link via `codespar_manage_connections` (typed) |
|
|
134
|
+
| `session.charge(args)` | Inbound charge via `codespar_charge` (typed) — buyer pays merchant |
|
|
135
|
+
| `session.ship(args)` | Shipping via `codespar_ship` (typed) — `action: "label" \| "quote" \| "track"` |
|
|
136
|
+
| `session.paymentStatus(toolCallId)` | Async settlement status for a `codespar_charge` / `codespar_pay` call |
|
|
137
|
+
| `session.paymentStatusStream(toolCallId, opts)` | SSE variant of `paymentStatus`; resolves on terminal |
|
|
138
|
+
| `session.verificationStatus(toolCallId)` | Async KYC disposition for a `codespar_kyc` call |
|
|
139
|
+
| `session.verificationStatusStream(toolCallId, opts)` | SSE variant of `verificationStatus`; resolves on terminal |
|
|
81
140
|
| `session.mcp` | MCP transport URL and headers (when using managed runtime) |
|
|
82
141
|
| `session.close()` | Close session |
|
|
83
142
|
|
|
@@ -132,9 +191,132 @@ const session = await cs.create("user_123", {
|
|
|
132
191
|
|
|
133
192
|
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.
|
|
134
193
|
|
|
194
|
+
## Test-mode mocks
|
|
195
|
+
|
|
196
|
+
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.
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { CodeSpar } from "@codespar/sdk";
|
|
200
|
+
|
|
201
|
+
const cs = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });
|
|
202
|
+
|
|
203
|
+
const session = await cs.create("user_test", {
|
|
204
|
+
servers: ["asaas"],
|
|
205
|
+
mocks: {
|
|
206
|
+
"asaas/create_payment": { id: "pay_test", status: "PENDING" },
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const result = await session.execute("asaas/create_payment", { value: 100 });
|
|
211
|
+
// result.data === { id: "pay_test", status: "PENDING" }
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Pass an array for stateful mocks:
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
mocks: {
|
|
218
|
+
"asaas/create_payment": [
|
|
219
|
+
{ id: "pay_1", status: "PENDING" },
|
|
220
|
+
{ id: "pay_1", status: "RECEIVED" },
|
|
221
|
+
],
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
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.
|
|
226
|
+
|
|
227
|
+
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.
|
|
228
|
+
|
|
229
|
+
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.
|
|
230
|
+
|
|
231
|
+
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.
|
|
232
|
+
|
|
233
|
+
### Type aliases
|
|
234
|
+
|
|
235
|
+
`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.
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
import type { MockValue } from "@codespar/sdk";
|
|
239
|
+
|
|
240
|
+
const fixtures: Record<string, MockValue> = {
|
|
241
|
+
"asaas/create_payment": { id: "pay_test", status: "PENDING" },
|
|
242
|
+
};
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Typed errors
|
|
246
|
+
|
|
247
|
+
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.
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
import { CodesparApiError } from "@codespar/sdk";
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
await cs.create("user_test", { mocks: { "asaas/create_payment": {} } });
|
|
254
|
+
} catch (err) {
|
|
255
|
+
if (err instanceof CodesparApiError) {
|
|
256
|
+
if (err.code === "mocks_not_permitted") {
|
|
257
|
+
// Live key against a mocks map. Swap to csk_test_*.
|
|
258
|
+
} else if (err.code === "mocks_invalid") {
|
|
259
|
+
// Backend rejected a tool-name key. Check the slash form.
|
|
260
|
+
} else if (err.status === 0) {
|
|
261
|
+
// Network never reached the backend; err.cause has the fetch rejection.
|
|
262
|
+
}
|
|
263
|
+
throw err;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
`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.
|
|
269
|
+
|
|
270
|
+
### Tool-result guards
|
|
271
|
+
|
|
272
|
+
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.
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import {
|
|
276
|
+
isApprovalRequired,
|
|
277
|
+
isMocksEngineError,
|
|
278
|
+
isMocksExhausted,
|
|
279
|
+
isPolicyDenied,
|
|
280
|
+
isToolNotMocked,
|
|
281
|
+
assertExhaustiveToolResult,
|
|
282
|
+
ToolResultCode,
|
|
283
|
+
} from "@codespar/sdk";
|
|
284
|
+
|
|
285
|
+
const result = await session.execute("asaas/create_payment", { value: 100 });
|
|
286
|
+
|
|
287
|
+
if (isPolicyDenied(result.data)) {
|
|
288
|
+
console.warn(`blocked by ${result.data.rule_id}: ${result.data.message}`);
|
|
289
|
+
} else if (isApprovalRequired(result.data)) {
|
|
290
|
+
console.log(`needs approval ${result.data.approval_id} by ${result.data.expires_at}`);
|
|
291
|
+
} else if (isMocksExhausted(result.data)) {
|
|
292
|
+
// Stateful mock array drained — pad it or extend the test.
|
|
293
|
+
} else if (isMocksEngineError(result.data)) {
|
|
294
|
+
// Backend-side mocks engine failure; usually a malformed fixture.
|
|
295
|
+
} else if (isToolNotMocked(result.data)) {
|
|
296
|
+
console.warn(`no mock for ${result.data.tool_name}`);
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
The same guards apply inside a `sendStream` loop against `event.toolCall.output`.
|
|
301
|
+
|
|
302
|
+
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.
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
function handle(outcome: ToolResultOutcome): string {
|
|
306
|
+
switch (outcome.code) {
|
|
307
|
+
case ToolResultCode.PolicyDenied: return outcome.rule_id;
|
|
308
|
+
case ToolResultCode.ApprovalRequired: return outcome.approval_id;
|
|
309
|
+
case ToolResultCode.MocksExhausted: return "exhausted";
|
|
310
|
+
case ToolResultCode.MocksEngineError: return "engine";
|
|
311
|
+
case ToolResultCode.ToolNotMocked: return outcome.tool_name;
|
|
312
|
+
default: return assertExhaustiveToolResult(outcome);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
135
317
|
## Need more?
|
|
136
318
|
|
|
137
|
-
|
|
319
|
+
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.
|
|
138
320
|
|
|
139
321
|
## License
|
|
140
322
|
|
|
@@ -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"}
|