cope-sdk 0.0.1-reserved.0 → 0.1.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/CHANGELOG.md +84 -0
- package/README.md +1085 -2
- package/dist/handler-CRAsln_7.d.cts +55 -0
- package/dist/handler-CRAsln_7.d.ts +55 -0
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +576 -0
- package/dist/index.d.ts +576 -0
- package/dist/index.global.js +3 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/node.cjs +1345 -0
- package/dist/mcp/node.cjs.map +1 -0
- package/dist/mcp/node.d.cts +15 -0
- package/dist/mcp/node.d.ts +15 -0
- package/dist/mcp/node.js +1323 -0
- package/dist/mcp/node.js.map +1 -0
- package/dist/mcp.cjs +1336 -0
- package/dist/mcp.cjs.map +1 -0
- package/dist/mcp.d.cts +6 -0
- package/dist/mcp.d.ts +6 -0
- package/dist/mcp.js +1313 -0
- package/dist/mcp.js.map +1 -0
- package/package.json +69 -6
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `cope-sdk` are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
`cope-sdk` is the new-architecture copy of `@copecart/sdk` 0.3.0 (`svcs/cart-sdk`, whose changelog holds the history
|
|
9
|
+
before the copy). `@copecart/sdk` is unchanged and keeps serving the pages that already load it.
|
|
10
|
+
|
|
11
|
+
## [Unreleased] — 0.1.0
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`cope-sdk/mcp`**: an MCP endpoint a store mounts on its own server so a buyer's AI agent can look up products,
|
|
16
|
+
build a cart and get a checkout URL (`createCopeMcpHandler`, `generateCartRefKey`; `createCopeMcpNodeHandler` from
|
|
17
|
+
`cope-sdk/mcp/node`). Server-only; needs `@modelcontextprotocol/server` and `zod` as peers, plus
|
|
18
|
+
`@modelcontextprotocol/node` for the Node entry. The browser build does not include it.
|
|
19
|
+
- **Ids in request paths are URL-encoded**, so an id such as `../promo_code` cannot aim a request carrying the cart
|
|
20
|
+
secret at another route.
|
|
21
|
+
- **`persistence: 'none'`** keeps the cart only in memory, for a server that serves many buyers from one process; the
|
|
22
|
+
default stays `'localStorage'`; a server needs one client per buyer. **`cart: { id, secret }`** acts on a cart whose
|
|
23
|
+
credentials the caller holds, and never touches stored carts.
|
|
24
|
+
- **`checkout(cartId, payload, { idempotencyKey })`**: a repeated call with the same key and payload returns the
|
|
25
|
+
checkout already created instead of `cart_not_active` (409 `idempotency_conflict` while the first call is still
|
|
26
|
+
in flight).
|
|
27
|
+
- **`CopeApiError.retryAfter`**: the server's `Retry-After`, in seconds, or null.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **Published as `cope-sdk`**, not `@copecart/sdk`.
|
|
32
|
+
- **MIT-licensed** (`@copecart/sdk` was `UNLICENSED`), so merchants may use, modify and redistribute it in their
|
|
33
|
+
own sites.
|
|
34
|
+
- **Default `baseUrl` is `https://app.cope.com`.** Requests go to `https://app.cope.com/api/cart/v1/...`, the checkout
|
|
35
|
+
block cope-edge serves; the old default `https://app.cope.com/gateway/cart_api` pointed at the old estate's gateway,
|
|
36
|
+
which the new estate does not have. The hosted checkout origin (the `checkoutBaseUrl` default) stays `app.cope.com`.
|
|
37
|
+
- **`baseUrl` must be an origin.** A value with a path, such as `@copecart/sdk`'s documented
|
|
38
|
+
`https://app.cope.com/gateway/cart_api`, throws `CopeError('Invalid baseUrl...')` instead of 404ing on every call.
|
|
39
|
+
- **The cart is stored under `cope_sdk_cart`**, not `cope_cart`, so `cope-sdk` never reads or clears a cart
|
|
40
|
+
`@copecart/sdk` stored on the same page.
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- **`cope-sdk/mcp` failed every `create_cart` and `get_cart` against the real cart API** (staging, 2026-09-26). cope-core
|
|
45
|
+
answers `POST /carts` without `lines` or `buyer_identity`, and reprice and the promo-code routes without
|
|
46
|
+
`buyer_identity`; the MCP projection read both unconditionally and answered `internal_error`. `createCart` now
|
|
47
|
+
returns `lines: []` and `buyer_identity: null` (a new cart has neither), `Cart.buyer_identity` is optional (absent
|
|
48
|
+
where the response does not report it), and the MCP result leaves `buyer` out rather than claiming none.
|
|
49
|
+
- **`Cart.promo_code` never existed.** cope-core sends `applied_promo_code`, an object with the code and the discount;
|
|
50
|
+
the type now says so, and the MCP result's `promoCode` reads it.
|
|
51
|
+
- **`get_product` quoted plan prices 100 times too low.** The cart API's plan amounts are display strings in major
|
|
52
|
+
units despite their `_cents` names (`"999.00"`); the MCP projection read them as minor units. It converts them now,
|
|
53
|
+
so `firstPaymentMinorUnits` matches what the cart charges.
|
|
54
|
+
- **A refused promo code was never recognised.** The cart API answers 422 with the validator's reason (`not_found`,
|
|
55
|
+
`expired`, `exhausted`, ...), never `invalid_promo_code`; `ApiErrorCode` lists the real reasons, and
|
|
56
|
+
`apply_promo_code` answers `promo_code_not_accepted` with the API's code as `reason`.
|
|
57
|
+
- The MCP tests' cart API fake had the same four shapes wrong, which is why they passed; it now follows
|
|
58
|
+
`CartBlueprint` and `PaymentPlanBlueprint`.
|
|
59
|
+
|
|
60
|
+
- **Promo codes 404ed.** `applyPromoCode` and `removePromoCode` sent `POST`/`DELETE /carts/:id/promo-codes`; the cart
|
|
61
|
+
API has only ever drawn `/carts/:id/promo_code` (singular, underscore). They now send `promo_code`. The old unit tests
|
|
62
|
+
asserted the wrong path, so they agreed with the bug; `tests/edge-route-agreement.test.ts` now checks every request
|
|
63
|
+
the SDK sends against cope-edge's own route table.
|
|
64
|
+
- **The docs promised an unbounded prefilled replay.** A replay returns the stored handoff only within the cart API's
|
|
65
|
+
24-hour idempotency TTL; after it the same `externalReference` creates a new cart and checkout. README and the
|
|
66
|
+
`externalReference` doc comment now say so (plan 30 W2-16).
|
|
67
|
+
- **`cart_id_mismatch` was documented as 422.** The cart API answers it with 403.
|
|
68
|
+
- **Two external references could share an Idempotency-Key.** The prefilled key replaced characters outside
|
|
69
|
+
`[A-Za-z0-9._:-]` with `-` and cut at 120, so `INV/2026/1` and `INV-2026-1` collided and the second checkout got
|
|
70
|
+
422 `idempotency_body_mismatch` for 24 hours. A safe reference of up to 120 characters keeps its readable key
|
|
71
|
+
(`prefilled:<reference>:cart`); any other is SHA-256'd whole (`prefilled#<hex>:cart`).
|
|
72
|
+
- **Errors cope-edge answers itself surfaced as `unknown`.** Edge's checkout-block refusals (413 `payload_too_large`,
|
|
73
|
+
429 `rate_limited`, 502 `upstream_unavailable`, 504 `gateway_timeout`) use `{error, request_id}`, not core's
|
|
74
|
+
`{errors: [...]}`. `CopeApiError.code` now carries edge's code with a readable `message`, and `requestId` falls back to the
|
|
75
|
+
body's `request_id` (plan 30 W2-47). An `error` that is prose rather than a code becomes `code: 'unknown'`.
|
|
76
|
+
- **A cart write could be applied twice.** `createCart`, `addLine`, `reprice` and `applyPromoCode` were resent after a
|
|
77
|
+
5xx, a timeout or a network error, but the cart API deduplicates none of them — so a write edge timed out on (504
|
|
78
|
+
`gateway_timeout`) but core committed was applied again. Only GETs and `createPrefilledCheckout`, which the server
|
|
79
|
+
does deduplicate, are resent after an ambiguous failure; a 429 is still retried everywhere it was, because it is
|
|
80
|
+
refused before processing.
|
|
81
|
+
- **`baseUrl` validation let a query, fragment or credentials through**, and a malformed URL threw a bare `TypeError`.
|
|
82
|
+
It must now equal its own origin, and anything else throws `CopeError`.
|
|
83
|
+
- **Typecheck failed on a fresh install.** The iframe timer ids were typed `ReturnType<typeof window.setInterval>`,
|
|
84
|
+
which resolves to Node's `Timeout` once `@types/node` is present; they are typed as the DOM's `number`.
|