@01.software/sdk 0.70.1 → 0.72.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 (70) hide show
  1. package/CHANGELOG.md +143 -0
  2. package/MIGRATION.md +28 -0
  3. package/README.md +253 -11
  4. package/dist/client.cjs +396 -26
  5. package/dist/client.cjs.map +1 -1
  6. package/dist/client.d.cts +7 -6
  7. package/dist/client.d.ts +7 -6
  8. package/dist/client.js +396 -26
  9. package/dist/client.js.map +1 -1
  10. package/dist/{collection-client-BHLStm1K.d.cts → collection-client-B3CnqMDQ.d.cts} +14 -18
  11. package/dist/{collection-client-B1FSJ24_.d.ts → collection-client-uOgS_1bC.d.ts} +14 -18
  12. package/dist/{const-ty8u0TDI.d.ts → const-BJBK7jBl.d.ts} +1 -1
  13. package/dist/{const-BfQfV-rr.d.cts → const-_ZfJjRQG.d.cts} +1 -1
  14. package/dist/embedded-admin/server.cjs +117 -2
  15. package/dist/embedded-admin/server.cjs.map +1 -1
  16. package/dist/embedded-admin/server.d.cts +30 -2
  17. package/dist/embedded-admin/server.d.ts +30 -2
  18. package/dist/embedded-admin/server.js +117 -2
  19. package/dist/embedded-admin/server.js.map +1 -1
  20. package/dist/embedded-admin.cjs +135 -7
  21. package/dist/embedded-admin.cjs.map +1 -1
  22. package/dist/embedded-admin.d.cts +35 -2
  23. package/dist/embedded-admin.d.ts +35 -2
  24. package/dist/embedded-admin.js +135 -7
  25. package/dist/embedded-admin.js.map +1 -1
  26. package/dist/errors.cjs +2 -0
  27. package/dist/errors.cjs.map +1 -1
  28. package/dist/errors.d.cts +3 -3
  29. package/dist/errors.d.ts +3 -3
  30. package/dist/errors.js +2 -0
  31. package/dist/errors.js.map +1 -1
  32. package/dist/{index-DnKgjPGM.d.ts → index-CBaP4q8r.d.ts} +3 -3
  33. package/dist/{index-CX6si6YC.d.cts → index-CI_LFWiG.d.cts} +3 -3
  34. package/dist/index.cjs +396 -26
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +24 -9
  37. package/dist/index.d.ts +24 -9
  38. package/dist/index.js +396 -26
  39. package/dist/index.js.map +1 -1
  40. package/dist/{payload-types-DTAaWKrp.d.cts → payload-types-BRg8Yary.d.cts} +262 -177
  41. package/dist/{payload-types-DTAaWKrp.d.ts → payload-types-BRg8Yary.d.ts} +262 -177
  42. package/dist/query.cjs +20 -0
  43. package/dist/query.cjs.map +1 -1
  44. package/dist/query.d.cts +5 -5
  45. package/dist/query.d.ts +5 -5
  46. package/dist/query.js +20 -0
  47. package/dist/query.js.map +1 -1
  48. package/dist/realtime.d.cts +2 -2
  49. package/dist/realtime.d.ts +2 -2
  50. package/dist/server.cjs +459 -46
  51. package/dist/server.cjs.map +1 -1
  52. package/dist/server.d.cts +10 -8
  53. package/dist/server.d.ts +10 -8
  54. package/dist/server.js +459 -46
  55. package/dist/server.js.map +1 -1
  56. package/dist/storefront-cache.cjs +2 -0
  57. package/dist/storefront-cache.cjs.map +1 -1
  58. package/dist/storefront-cache.js +2 -0
  59. package/dist/storefront-cache.js.map +1 -1
  60. package/dist/{types-DdlhpNVv.d.ts → types-Cmnxxvuv.d.ts} +238 -21
  61. package/dist/{types-Bzgf4mTo.d.cts → types-CnkJQUez.d.cts} +238 -21
  62. package/dist/{types-DX8Z44yQ.d.ts → types-DLjSqL0P.d.ts} +2 -2
  63. package/dist/{types-CpSiyJud.d.cts → types-FyklqLAk.d.cts} +2 -2
  64. package/dist/ui/form.d.cts +1 -1
  65. package/dist/ui/form.d.ts +1 -1
  66. package/dist/ui/video.d.cts +1 -1
  67. package/dist/ui/video.d.ts +1 -1
  68. package/dist/webhook.d.cts +5 -5
  69. package/dist/webhook.d.ts +5 -5
  70. package/package.json +2 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,148 @@
1
1
  # @01.software/sdk
2
2
 
3
+ ## 0.72.1
4
+
5
+ ### Patch Changes
6
+
7
+ - bbcdc03: Clarify generated event occurrence identity and community comment-setting descriptions in operator-facing wording. Types, field access, and response shapes are unchanged.
8
+ - 327779c: Clarify generated JSDoc for event admission sale windows and usage rate card effective windows after adding date and time pickers in the Admin Panel. Stored instants, SDK runtime behavior, and public API shape remain unchanged.
9
+ - 2075d27: Clarify the generated event registration-list description with operator-facing wording. Types, field access, and response shapes are unchanged.
10
+ - 2990468: Correct the generated event `externalSource` description comment: provider, source ID, and URL can all appear in public read responses. Field access and response shapes are unchanged.
11
+ - 055671d: Clarify generated commerce field descriptions in operator-facing wording. Types, field access, and response shapes are unchanged.
12
+ - 5581c60: Clarify generated event field descriptions for admission quantity limits, attendee privacy, and public API visibility.
13
+ - 5138b42: Clarify generated customer and membership field descriptions without changing field keys or types.
14
+ - 269db8b: Refresh generated Payload type descriptions for workspace and platform operator guidance.
15
+ - 9ec8504: Update generated type description comments without changing request or response shapes. The server applies the calendar timezone when a non-duplicate event create omits timezone.
16
+ - 15e5dc6: Restore privacy, entitlement lifecycle and validation, usage aggregation, and webhook idempotency details in generated field descriptions.
17
+ - 1c23d29: Document the membership delegated billing connection in generated payment credential types.
18
+ - 3b47cff: Clarify generated Product `markets` JSDoc: new products without markets receive the active default market if one exists, and removing every market from an existing product excludes it from market catalogs. Runtime behavior and public API shape remain unchanged.
19
+
20
+ ## 0.72.0
21
+
22
+ ### Minor Changes
23
+
24
+ - 756ca0b: Document the owner-approved multi-currency reporting correction for server-only
25
+ customer `lifetimeValue`: retain `number | null`, sum only a verified single
26
+ currency, and return `null` for mixed or unavailable currencies (zero orders
27
+ remain `0`). No new SDK field or webhook envelope is introduced and persisted
28
+ webhook bytes are unchanged. This minor records the public behavior correction
29
+ under [the #7859 owner decision](https://github.com/01-office/01-software/issues/7859#issuecomment-6540676116),
30
+ even though the generated property type is unchanged.
31
+ - 181d5ee: **Additive response arms (0.x minor).** `server.commerce.cancelOrder()` can now
32
+ return the registered managed Toss outcome (ADR 0073). When the paid order was
33
+ captured through a Console payment connection, Console refunds it after the
34
+ local cancel commits and the response carries
35
+ `managedRefund: { outcome: 'completed' | 'convergence_pending' | 'operator_required' }`
36
+ with `providerRefunded` and the refunded amount, never `refundPending`. Do not
37
+ run a storefront or BFF provider refund for these responses: retries read or
38
+ resume the same Console refund. An exhaustive check over `CancelOrderResponse`
39
+ needs the two new arms (`CancelOrderManagedCommittedResponse`,
40
+ `CancelOrderManagedAlreadyCanceledResponse`).
41
+
42
+ Import both response arms and `ManagedCancelRefundOutcome` as types from
43
+ `@01.software/sdk`, alongside `CancelOrderResponse`.
44
+
45
+ Custom bridge, legacy, PortOne, and credit-funded orders keep the existing
46
+ `refundPending` handoff unchanged.
47
+
48
+ - cf8e6d5: **BREAKING (0.x minor).** Prepare strict readers for the reserved `'stripe'`
49
+ managed provider before the server can emit it.
50
+ `CheckoutPaymentSessionRef['provider']` widens to
51
+ `'toss' | 'portone' | 'stripe'`, so an exhaustive `switch` over it needs a
52
+ `'stripe'` case. Earlier SDK versions reject a `'stripe'` reference as an
53
+ invalid canonical response; upgrade every consumer that reads Checkouts before
54
+ Stripe becomes available.
55
+
56
+ Checkout references accept `provider: 'stripe'`. PaymentSession methods
57
+ (`create`, `createPortOne`, `retrieve`, `retrievePortOne`, `cancel`,
58
+ `cancelPortOne` and server `confirm`) reject a Stripe session after validating
59
+ it completely, including the strict Stripe Payment Element action
60
+ (`stripe_payment_element` with `clientSecret`, `publishableKey` and a
61
+ credential-free HTTPS or loopback `returnUrl`), and report a generic invalid response with
62
+ `details.expected` and `details.actual`. Partial or unknown action fields are
63
+ rejected. Stripe is not available yet and the SDK adds no Stripe PaymentSession
64
+ method. Toss, PortOne and custom bridge behavior, including custom provider
65
+ names, is unchanged.
66
+
67
+ ### Patch Changes
68
+
69
+ - 88bee51: Clarify the generated admission type price-reference guidance: the reference is optional when saving and required for sales. The generated field type and public API behavior are unchanged.
70
+ - 9f326b5: Synchronize generated collection and calendar field descriptions with neutral Console copy for workspace menu display names. Type shapes, runtime behavior, and API titles are unchanged.
71
+ - 1d03497: Clarify the generated documentation for membership payment results that were not applied at the time they were received.
72
+ - 931d8a0: Clarify generated Discount type descriptions for code usage counts, pending checkout reservations, and unsupported allocation repair guidance.
73
+ - 1a6e310: Restore the read-only note in the generated Discount `usesCount` type description.
74
+ - 2f4989e: Synchronize generated EventRegistration types with the reordered registration fields (status, attendance, and quantity now come first). Only property order changes; SDK runtime behavior, collection buckets, request inputs, and public responses remain unchanged. Separately, Console now reads `event-occurrences` newest `startsAt` first when a request omits `sort`; pass `sort` explicitly if you depend on a specific order.
75
+ - 4db606a: Clarify the generated membership plan description comment to reflect its inclusion in public query responses for active plans. Field access and response shapes are unchanged.
76
+ - b43cb9c: Synchronize generated Order and Checkout types with the internal Checkout `source` field and the internal `in_person` Order source value. SDK runtime behavior, collection buckets, request inputs, and public responses remain unchanged.
77
+ - ba3ffc2: Synchronize generated FulfillmentOrder and Fulfillment types with the internal, access-closed `method` field. SDK runtime behavior, collection buckets, request inputs, and public responses remain unchanged.
78
+ - c246a93: Clarify generated Customer field descriptions for linked sign-in providers and password change times. Types and runtime behavior are unchanged.
79
+ - 6b9d1ab: Use neutral short-summary comments in generated Payload types without prescribing where tenant apps display descriptions.
80
+ - 8ae95f0: Give the SDK declaration build a bounded 4 GiB heap so release preparation can complete on hosted runners.
81
+ - 2be5e90: Remove unused package-local prerelease publishing commands. Package publication continues through the owner-dispatched trusted publishing workflow.
82
+ - f776ca2: Clarify the generated Return field descriptions for return details, cancellation actors, refund receipts, and original shipping refunds.
83
+ - e1ba296: Synchronize generated PaymentSession types with the private, nullable Standard long-tail detection history field. SDK runtime behavior, collection buckets, and public projections remain unchanged.
84
+ - 9159e72: Clarify the generated customer type documentation for server-recorded hosted consent history. Runtime behavior and public type shapes are unchanged.
85
+ - 9a92a2d: Update generated collection descriptions to match the Console coupon navigation and explain checkout discounts and redemption coupon definitions. Public types and runtime behavior are unchanged.
86
+
87
+ ## 0.71.0
88
+
89
+ ### Minor Changes
90
+
91
+ - b8af85e: Expose `shipping_address_required` as a typed commerce error reason when Checkout creation rejects shippable lines without a valid request or stored Cart address.
92
+ - e48864c: Add an optional `locale` (`en` or `ko`) to server collection `create()`, `update()`, and `updateMany()`, sent as Payload's `locale` query parameter, so workspaces that enable only `ko` (the Korean onboarding default) can write localized collections. Calls without `locale` send the same request as before. Raw collection errors now expose a Payload `errors[0].data.code` (or `.reason`) as `SDKError.apiReason` when the body has no top-level reason, so `getSDKErrorReason()` identifies `content_locale_not_enabled`; error classes, `code`, and retry behavior are unchanged.
93
+ - d65f43d: Add explicitly negotiated embedded admin collection actions with signed execution context, fixed deadlines and a claim-only durable receiver verification contract. Preserve v1 settings helpers and add CLI action configuration with omission-preserves semantics.
94
+ - 0ded572: Add binding-scoped, default-off embedded admin downloads. Configure with
95
+ `--allow-downloads` to opt in; full configure without it resets downloads to
96
+ false on supporting servers. Omit the request field when no download option is
97
+ supplied for released-server compatibility; `--no-allow-downloads` explicitly
98
+ sends false. Normalize legacy configuration/readback to false while retaining the
99
+ version-1 receiver protocol and PAT-only management boundary.
100
+ - 96360d8: Add the server-only membership subscribe intent termination operation.
101
+ - 0d0d8ec: **BREAKING (0.x minor), TypeScript types only.** Prepare strict Cart, Checkout
102
+ and Order response readers for the complete pickup response shapes while
103
+ continuing to accept the released server shapes. `PublicCart`,
104
+ `PublicCheckout`, `ServerCheckout`, `CheckoutListItem` and `PublicOrder` become
105
+ unions of both shapes; narrow with `'deliveryMethod' in resource`. Because
106
+ `PublicCart` and `PublicOrder` were object types, an `interface` extending them
107
+ (TS2312) or a `class` implementing them (TS2422) no longer compiles. Use an
108
+ intersection type alias (`type AppOrder = PublicOrder & { ... }`), or extend or
109
+ implement one generation selected with `Exclude`/`Extract` on
110
+ `{ deliveryMethod: unknown }`; a class cannot implement the intersection, which
111
+ is still a union. Runtime response acceptance only widens.
112
+
113
+ Partial field sets, incomplete pickup projections and unknown fields are
114
+ rejected, including in envelopes and list entries. Existing response fields,
115
+ inputs, method signatures, money, source, PortOne action and credit funding
116
+ semantics are unchanged; no pickup commands, inputs or reasons are added and
117
+ servers do not emit the new fields yet. The later server default-response
118
+ cutover (#7760) is a separate breaking semantic contract change that older
119
+ strict SDKs reject; its Changeset records the actual first published compatible
120
+ SDK and support floor from `docs/packages/sdk-pickup-response-rollout.md`.
121
+
122
+ - 57519f0: Add server-only template credit grant, revoke and account readback, customer balance and history reads, and optional Checkout credit input. Checkout funding uses an exact versioned Accept opt-in while legacy responses remain compatible. Missing funding remains unknown, and credit requests never fall back to non-credit checkout.
123
+
124
+ Allow an omitted Return refund capture ID only for an original full-credit Order with zero frozen provider payable. Mixed Orders still require the original capture identity, including credit-only refund remainders; existing server money and credential authority remains unchanged.
125
+
126
+ Preserve the ordinary refund missing-capture-ID 400 response, reject missing and foreign grant Customers identically, keep account reads from advancing mutation revisions, and return retryable 503 for unavailable Checkout funding readback.
127
+
128
+ ### Patch Changes
129
+
130
+ - a8a2312: Preserve the current in-memory access and refresh token pair when cloning a
131
+ `persist: false` client with `withMarket()`, including sessions established by
132
+ login, rotated sessions, and cleared credentials.
133
+ - 4f1fa0a: Synchronize generated Cart, Checkout, and Order types with the internal, access-closed `deliveryMethod` field. SDK runtime behavior, collection buckets, request inputs, and public responses remain unchanged.
134
+ - eb636d1: Refresh generated commerce field descriptions for returns, carts, and checkouts.
135
+ - dd223b8: Document once-per-customer/plan Membership trials, preserved intent snapshots,
136
+ and paid preparation confirmation before tenant PSP execution. No SDK runtime,
137
+ export, or wire shape changes.
138
+ - bc0f481: Synchronize generated PaymentSession and PaymentEventInbox types with two private, nullable payment detection history fields. SDK runtime behavior, collection buckets, and public projections remain unchanged.
139
+ - b61a4b0: Synchronize generated PaymentRefundAttempt types and field selectors with the internal `not_sent_rejected` status and the private, write-once `returnRejection` proof (`gate` and `rejectedAt`). SDK runtime behavior, collection buckets, and public projections remain unchanged.
140
+ - c65e931: Synchronize the optional tenant workspace management IP policy in generated
141
+ Payload types. This does not add an SDK method or expose the policy to public
142
+ or service-key callers.
143
+ - 590e41e: Sync generated Tenant types with collection-specific Admin Panel export policy settings.
144
+ - 750a403: Clarify generated Customer order-count documentation: pending orders contribute, while canceled, refunded, returned, test and trashed orders do not.
145
+
3
146
  ## 0.70.1
4
147
 
5
148
  ### Patch Changes
package/MIGRATION.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @01.software/sdk Migration Notes
2
2
 
3
+ ## Pickup response compatibility preparation (#7756)
4
+
5
+ This SDK reads both the released and the complete final Cart, Checkout and Order
6
+ responses; servers still return the released shape and pickup remains
7
+ unavailable. `PublicCart`, `PublicCheckout`, `ServerCheckout`,
8
+ `CheckoutListItem` and `PublicOrder` are unions of the two shapes. The new
9
+ fields arrive only as a complete set per resource, so narrow with
10
+ `'deliveryMethod' in resource` before reading them. Partial sets, incomplete
11
+ pickup projections and unknown fields fail closed, also in envelopes and lists.
12
+ No field is synthesized for released servers. Existing `amounts`, Cart
13
+ `estimatedTotalMinor` (still excluding shipping), PortOne action negotiation and
14
+ credit funding semantics are unchanged.
15
+
16
+ This is a `BREAKING (0.x minor)` change for TypeScript types only; runtime
17
+ response acceptance only widens. `PublicCart` and `PublicOrder` were object
18
+ types, so an `interface` extending them (TS2312) or a `class` implementing them
19
+ (TS2422) no longer compiles. Use an intersection type alias
20
+ (`type AppOrder = PublicOrder & { ... }`), or select one generation with
21
+ `Exclude<PublicOrder, { deliveryMethod: unknown }>` (released) /
22
+ `Extract<PublicOrder, { deliveryMethod: unknown }>` (cutover) before extending
23
+ or implementing it. The intersection is still a union, so a class must
24
+ implement a selected generation.
25
+ `PublicCheckout` was already a union. The later server cutover (#7760) is a
26
+ separate breaking contract change for older strict SDKs: upgrade to this SDK or
27
+ later before it. See the
28
+ [response matrix and pending publication record](../../../docs/packages/sdk-pickup-response-rollout.md)
29
+ for the exact field sets, version/support-floor placeholders and cutover gate.
30
+
3
31
  ## Product media compatibility shim retirement (#721)
4
32
 
5
33
  This is a `BREAKING (0.x minor)` change. The ADR 0025 one-release compatibility
package/README.md CHANGED
@@ -17,7 +17,7 @@ pnpm add @01.software/sdk
17
17
  - React Query integration (both Client and ServerClient)
18
18
  - Mutation hooks (useCreate, useUpdate, useRemove) with automatic cache invalidation
19
19
  - Customer auth hooks (useCustomerMe, useCustomerLogin, etc.) with cache management
20
- - Automatic retry with exponential backoff (non-retryable: 400, 401, 403, 404, 409, 422)
20
+ - Automatic failure retries for safe methods (`GET`, `HEAD`, `OPTIONS`) after network/timeout failures and retry-eligible HTTP failures (defaults: 408/500/502/503/504), within the SDK's bounded retry budget and with bounded backoff (exponential by default). GET already retries; avoid stacking an outer retry loop. A rate-limit 429 is terminal (`RateLimitError`; usage-quota 429 remains `UsageLimitError`). Unsafe mutations are not automatically retried after these failures.
21
21
  - Webhook handling with HMAC-SHA256 signature verification
22
22
  - Sub-path imports (`./server`, `./webhook`, `./realtime`, `./storefront-cache`, `./ui/*`) for tree-shaking
23
23
  - Type-safe read-only `collections.from()` for Client (compile-time write prevention)
@@ -151,6 +151,30 @@ CLI (`01 embedded-app configure`) with a user-scoped PAT. Binding management is
151
151
  an operator control-plane action and is intentionally not exposed as a public
152
152
  SDK mutation facade. A tenant API key (`sk01_`) is rejected.
153
153
 
154
+ Collection-list actions use the additive `receiveEmbeddedAdminExecution` browser
155
+ helper and `verifyEmbeddedAdminExecution` server helper. Pin `frameUrl` and pass
156
+ the actual action/collection/selected IDs/execution ID/deadline as `execution`.
157
+ The verifier requires a claim-only `consumeExecution` callback backed by shared
158
+ durable atomic storage, retained through `expiresAt+60`. It performs no business
159
+ effects. False/throw/timeout/uncertain commit fails closed; verification also
160
+ checks a fresh trusted clock after consume. Start effects only after successful
161
+ return and apply app-owned business idempotency/transaction policy. Repeating an
162
+ action is a new execution, not a retry of its business result.
163
+
164
+ V2 explicitly negotiates `collection-actions` and has a purpose-specific audience
165
+ (`urn:01-software:embedded-admin-execution:` plus the app origin); it cannot be
166
+ verified as v1 identity. Its immutable 60-second prepare deadline is unchanged by
167
+ reload or mint. V1 settings and helpers remain supported. These are context
168
+ proofs, not delegated mutation authority or an exactly-once business service.
169
+ Binding configuration adds optional `allowDownloads` for source compatibility;
170
+ normalization always returns a boolean and defaults missing values to false.
171
+ Downloads require explicit admin opt-in (`01 embedded-app configure
172
+ --allow-downloads`). Full configure without the flag resets false, even after
173
+ an opt-in. The receiver version-1 wire protocol remains unchanged. The setting
174
+ grants an iframe capability; the app owns file encryption and password handling.
175
+ Policy observation may replace/remove the frame, but cannot recall files,
176
+ delivered data, or app-local sessions.
177
+
154
178
  Loopback HTTP is disabled by default. Only non-production fixtures may set
155
179
  `allowLoopbackHttp: true` on the receiver and verifier options.
156
180
 
@@ -771,19 +795,42 @@ const prepared = await server.memberships.subscribe({
771
795
  })
772
796
 
773
797
  if (prepared.status === 'incomplete') {
774
- const expiresAt = Date.parse(prepared.firstCharge.expiresAt)
775
- if (!Number.isFinite(expiresAt) || Date.now() >= expiresAt) {
776
- throw new Error('First charge instruction expired or invalid')
798
+ // Show amount, currency and periodStart and obtain explicit paid consent.
799
+ if (await tenantPsp.confirm(prepared.firstCharge)) {
800
+ // The customer confirmation may outlast the preparation.
801
+ const expiresAt = Date.parse(prepared.firstCharge.expiresAt)
802
+ if (!Number.isFinite(expiresAt) || Date.now() >= expiresAt) {
803
+ throw new Error('First charge instruction expired or invalid')
804
+ }
805
+ await tenantPsp.charge({
806
+ idempotencyKey: prepared.firstCharge.idempotencyKey,
807
+ amount: prepared.firstCharge.amount,
808
+ currency: prepared.firstCharge.currency,
809
+ })
810
+ // Post the PSP outcome to Console's existing signed charge-result webhook.
777
811
  }
778
- await tenantPsp.charge({
779
- idempotencyKey: prepared.firstCharge.idempotencyKey,
780
- amount: prepared.firstCharge.amount,
781
- currency: prepared.firstCharge.currency,
782
- })
783
- // Post the PSP outcome to Console's existing signed charge-result webhook.
784
812
  }
785
813
  ```
786
814
 
815
+ A customer receives a trial once per plan within the same tenant. Started
816
+ positive-snapshot trials, including cancelled or archived ones, consume it;
817
+ started legacy rows with null/absent snapshots conservatively consume it too.
818
+ Unstarted failed/cancelled setups and paid-only zero snapshots do not. A catalog
819
+ trial badge does not promise customer eligibility. A recipient's new intent
820
+ returns the existing paid preparation, or `409 conflict` without lifecycle
821
+ writes if no active delegated billing connection exists. Present its amount,
822
+ currency and `periodStart`, keep the selected billing cycle visible, and obtain
823
+ customer confirmation before PSP execution; no `periodEnd` is returned.
824
+ Implement `tenantPsp.confirm` in your app's checkout flow. A refusal must result
825
+ in no PSP call. Console preparation does not establish payment or consent.
826
+ A completed trial replay keeps its cached result. Existing payload and live
827
+ duplicate checks run first; another live Membership returns
828
+ `409 duplicate_subscription`. An unfinished trial replay that passes those
829
+ checks returns `409 idempotency_conflict` after another intent received the trial,
830
+ without lifecycle writes, and preserves its snapshot. Use a new confirmed paid
831
+ intent instead. Uncompleted setups expire through the existing sweeper; the
832
+ Membership and charge evidence remain retained.
833
+
787
834
  `subscribeIntentKey` is sent as `X-Idempotency-Key`; it is not part of the JSON
788
835
  body. A paid response is `incomplete` and contains the immutable first-charge
789
836
  instruction. The tenant charges its PSP with `firstCharge.idempotencyKey`, then
@@ -798,6 +845,18 @@ activate the Membership, so the tenant handles any refund outside this API. Repl
798
845
  the same plan, price, customer reference, and idempotency key while the first
799
846
  charge is pending. A replay after settlement or `expiresAt` returns `409`
800
847
  instead of a payment instruction.
848
+ Server applications can explicitly end a signup intent with
849
+ `server.memberships.endSubscribeIntent({ customerId, subscribeIntentKey })`.
850
+ Use the same tenant, customer, and intent key as the original subscribe. The
851
+ key must contain 1–512 visible ASCII characters without whitespace; use an
852
+ opaque random value without personal data. `ended` fences future creation for
853
+ that intent; `existing` means the existing operation needs recovery. This call
854
+ requires an `sk01_` key with membership write scope and does not cancel, alter,
855
+ or charge an existing membership. An unsupported endpoint, transport error, or
856
+ malformed response does not establish termination. A later subscribe blocked by
857
+ the fence returns `409 intent_ended`; terminal-row replay may instead return its
858
+ existing conflict.
859
+
801
860
  `memberships.me()` and browser `memberships.cancel()` require the customer JWT
802
861
  configured on the client. Refund webhook `refundedAmount` values are cumulative
803
862
  charge totals, not per-event deltas.
@@ -900,6 +959,12 @@ Refund and refund-line-item collection reads remain server-only. Their public
900
959
  types and native reads omit private funding fields, including populated refund
901
960
  relationships. Generated storage types do not grant access to those fields.
902
961
 
962
+ Server-only customer documents and customer-update webhooks retain
963
+ `lifetimeValue?: number | null`. The scalar sums original order totals only
964
+ for one verified registry currency with a numeric exponent; mixed or unavailable
965
+ currencies yield `null`, and no contributing orders yield `0`. Currency bucket
966
+ fields are not added. Existing webhook bodies and replay bytes stay unchanged.
967
+
903
968
  ### `depth` — how deep to populate relationship fields
904
969
 
905
970
  `depth` is the primary control for populating relationships like `category`, `images`, `brand`. Browser publishable-key raw collection reads are constrained to `depth: 0` with `joins: false` and no `populate`; relationship-rich storefront reads should use shaped helpers such as `commerce.product.detail()` / `listingPage()`, or a `createServerClient()` raw query when server credentials are appropriate. Browser SDK raw reads add those safe defaults automatically and reject relationship-expanded raw read options before making a request.
@@ -1149,6 +1214,37 @@ await server.collections.from('articles').updateMany(where, data)
1149
1214
  await server.collections.from('articles').removeMany(where)
1150
1215
  ```
1151
1216
 
1217
+ Collection writes (`create`, `update`, `updateMany`) accept an optional
1218
+ `locale` (`en` or `ko`) that selects the content locale localized fields are
1219
+ written in; it is sent as Payload's `locale` query parameter. Omitting it keeps
1220
+ the request unchanged, and the server writes the platform default locale
1221
+ (`en`). A write has no locale rewrite, so a workspace without `en` enabled (the
1222
+ Korean onboarding default enables only `ko`) rejects an omitted or disabled
1223
+ write locale with HTTP 400 and `apiReason` `content_locale_not_enabled`.
1224
+
1225
+ ```typescript
1226
+ import { getSDKErrorReason, isSDKError } from '@01.software/sdk/errors'
1227
+ import { createServerClient } from '@01.software/sdk/server'
1228
+
1229
+ const server = createServerClient({ publishableKey, secretKey })
1230
+
1231
+ try {
1232
+ const { doc } = await server.collections
1233
+ .from('articles')
1234
+ .create({ title: '공지' }, { locale: 'ko' })
1235
+ await server.collections
1236
+ .from('articles')
1237
+ .update(doc.id, { title: '수정된 공지' }, { locale: 'ko' })
1238
+ } catch (error) {
1239
+ if (
1240
+ isSDKError(error) &&
1241
+ getSDKErrorReason(error) === 'content_locale_not_enabled'
1242
+ ) {
1243
+ // Retry with a locale that is enabled for this workspace.
1244
+ }
1245
+ }
1246
+ ```
1247
+
1152
1248
  Collection `find`, `count`, `updateMany`, and `removeMany` share filter validation.
1153
1249
  `equals: null` and `not_equals: null` retain their null meaning through Payload
1154
1250
  REST, including text fields; null-containing filters use Payload's native JSON
@@ -1533,10 +1629,24 @@ Cart add/update/remove/clear/discount/attribute mutations additionally require
1533
1629
  the last observed `cart.revision` as `expectedRevision`. A
1534
1630
  `cart_revision_conflict` means refetch the Cart and start a new logical mutation
1535
1631
  with a new idempotency key. Cart merge requires the key but not a single revision
1536
- because it atomically resolves two current Cart states.
1632
+ because it atomically resolves two current Cart states. Merging a Cart the
1633
+ customer already owns returns `resolution: 'unchanged'` and writes nothing, so
1634
+ the revision you last observed stays valid for the next mutation. Because it
1635
+ writes nothing, such a merge does not count as Cart activity for stale-Cart
1636
+ cleanup.
1537
1637
  Treat a replayed Cart result as an operation receipt: never replace a newer
1538
1638
  cached Cart with a lower `revision`; retrieve when response ordering is unclear.
1539
1639
 
1640
+ Shipping Checkout creation requires a request `shippingAddress` or a valid
1641
+ stored Cart address whenever any line has `requiresShipping !== false`.
1642
+ `recipientName`, `phone`, `postalCode`, `address`, and `detailAddress` must be nonblank after trimming. Otherwise,
1643
+ Console returns HTTP 400 with the typed `shipping_address_required` reason;
1644
+ non-shipping-only Carts may omit the address. Request addresses take precedence.
1645
+
1646
+ After `shipping_address_required`, adding an address to the same idempotency key
1647
+ changes the request fingerprint and returns `409 idempotency_conflict`. Start a
1648
+ new logical Checkout with a valid address and a new `idempotencyKey`.
1649
+
1540
1650
  ```typescript
1541
1651
  import { createCommerceIdempotencyKey } from '@01.software/sdk'
1542
1652
  import { isCommerceSDKError } from '@01.software/sdk/errors'
@@ -1679,6 +1789,16 @@ authoritative API response or signed webhook, then report the exact captured
1679
1789
  identity and Money. The create response is intentionally limited to
1680
1790
  `{ id, provider, providerSessionId, money }`.
1681
1791
 
1792
+ The closed managed provider vocabulary is `'toss' | 'portone' | 'stripe'`.
1793
+ `'stripe'` is reserved so that consumers upgrade before the server can emit it:
1794
+ Checkout references accept `provider: 'stripe'`, while the PaymentSession
1795
+ methods (`create`, `createPortOne`, `retrieve`, `retrievePortOne`, `cancel`,
1796
+ `cancelPortOne`, and server `confirm`) reject a Stripe session after validating
1797
+ it completely, with a generic invalid-response error carrying
1798
+ `details.expected` and `details.actual`. Stripe is not available yet, and the
1799
+ SDK has no Stripe PaymentSession method. Custom bridge provider names are a
1800
+ separate namespace and are unaffected.
1801
+
1682
1802
  Custom bridge sessions intentionally remain `null` in
1683
1803
  `checkout.paymentState.activePaymentSession`: Checkout exposes only managed
1684
1804
  adapters from its closed provider vocabulary. Persist the `providerSessionId`
@@ -1826,6 +1946,16 @@ Do not infer the external lane from a defaulted `sessionOrigin`, an
1826
1946
  captures must use Console's refund operation; `resolveCancelRefund` remains
1827
1947
  only for the two external-drain rows above.
1828
1948
 
1949
+ For a registered managed Toss capture without customer credit, `cancelOrder()`
1950
+ no longer returns `refundPending`: Console refunds the payment after the local
1951
+ cancel commits and returns `managedRefund.outcome`. `completed` means the
1952
+ provider refund and the cancel refund ledger are committed;
1953
+ `convergence_pending` means Console still owns the refund and continues it;
1954
+ `operator_required` means it needs operator review in Console. Treat all three
1955
+ as a committed cancellation and never start a provider refund from your
1956
+ storefront or BFF. A retry reads or resumes the same Console refund. Registered
1957
+ PortOne and credit-funded managed orders still return the pending marker.
1958
+
1829
1959
  Managed ownership follows the captured Transaction's exact tenant-bound
1830
1960
  PaymentSession and historical registered account. Order/provider/environment
1831
1961
  drift remains Console-owned corruption. Unresolved or cross-tenant identity
@@ -2527,6 +2657,12 @@ try {
2527
2657
 
2528
2658
  Error classes: `SDKError`, `ApiError`, `NetworkError`, `ValidationError`, `ConfigError`, `TimeoutError`
2529
2659
 
2660
+ Raw collection failures keep Payload's native body. When Payload reports a
2661
+ machine code as `errors[0].data.code` (or `.reason`) and the body has no
2662
+ top-level `reason`, the SDK exposes it as `SDKError.apiReason`, so
2663
+ `getSDKErrorReason()` returns codes such as `content_locale_not_enabled` without
2664
+ reading `details.body`. The typed error class and `code` stay status-based.
2665
+
2530
2666
  A customer-token `401 token_expired` permits at most one configured token
2531
2667
  refresh. After a successful refresh, GET/HEAD/OPTIONS may be resent once
2532
2668
  independently of the transient retry budget, including `retry.maxRetries: 0`
@@ -2680,3 +2816,109 @@ Reuse the same sourceNamespace/sourceRef and identical issue input on an unknown
2680
2816
  The staff app server must verify the staff member and Customer before redeeming: voucherId is not a bearer capability. `actorRef` is app-attested evidence, never a platform-verified staff identity or an authorization input. Use opaque references without personal data in sourceRef and actorRef. Definitions snapshot name, description and expiry at issue; later edits do not change issued vouchers. Voucher history survives Customer erasure and blocks tenant hard deletion. Referenced definitions must be archived.
2681
2817
 
2682
2818
  Product purchase quantity policies are enforced by Console at Cart ingress and Checkout creation. A product's optional `maxQuantityPerCustomer` combines all variants, committed Orders minus completed Returns, and open Checkouts. Limited products require a verified Customer; delegated server purchases use the existing `customerToken`. Handle `409 purchase_limit_exceeded` by its scalar `details.productId`, `maxQuantityPerCustomer` and `remainingQuantity`; guests receive `product_not_eligible`. See the [Commerce guide](https://docs.01.software/en/commerce).
2819
+
2820
+ ## Customer credits
2821
+
2822
+ In Console → Customer credits, a `tenant-admin` configures the default validity
2823
+ (1–1825 days), redemption cap (1–100%), and immutable fixed or bounded grant
2824
+ templates. Other tenant roles can read configuration and customer history.
2825
+ Archiving a template stops new grants; it preserves existing grant snapshots.
2826
+ Credit settings start disabled. Turning them off blocks new grants and credit
2827
+ reservations while preserving existing consumption, release, refund restoration,
2828
+ expiry, revocation and reads. This switch does not bypass ecommerce entitlement.
2829
+
2830
+ Use a trusted tenant server with `sk01_` credentials for
2831
+ `server.credits.grant`, `getGrant`, `getAccount` and `revoke`. Grants and revocations
2832
+ require write scope; reads require read scope. Browser clients expose only
2833
+ `client.credits.mine()` and `client.credits.history({ page })` using the logged-in
2834
+ Customer session and publishable key. These pages contain at most 50 entries;
2835
+ balances and history amounts are decimal strings in KRW, including aggregates
2836
+ larger than JavaScript's safe integer range. Do not convert such aggregates to
2837
+ `Number`. Buckets distinguish original expiry from the one-time restoration
2838
+ grace period. A grace period lasts 168 hours and is never renewed.
2839
+
2840
+ ### Monthly grant recipe for an annual member
2841
+
2842
+ The tenant owns its scheduler, membership eligibility and cancellation policy.
2843
+ Before running this function, verify that the member qualifies for the selected
2844
+ calendar month. An annual payment alone does not cause future monthly grants.
2845
+
2846
+ ```ts
2847
+ import { createServerClient } from '@01.software/sdk/server'
2848
+
2849
+ type CreditServer = ReturnType<typeof createServerClient>
2850
+
2851
+ export async function grantMembershipMonth(
2852
+ server: CreditServer,
2853
+ input: {
2854
+ customerId: string
2855
+ fixedTemplateId: string
2856
+ membershipId: string
2857
+ month: string
2858
+ },
2859
+ ) {
2860
+ const source = {
2861
+ sourceNamespace: 'membership-month',
2862
+ sourceRef: `${input.membershipId}:${input.month}`, // month: YYYY-MM in the tenant's calendar
2863
+ }
2864
+ await server.credits.grant({
2865
+ ...source,
2866
+ customerId: input.customerId,
2867
+ templateId: input.fixedTemplateId,
2868
+ })
2869
+ return server.credits.getGrant(source)
2870
+ }
2871
+
2872
+ export async function revokeMembershipMonth(
2873
+ server: CreditServer,
2874
+ input: { membershipId: string; month: string },
2875
+ ) {
2876
+ return server.credits.revoke({
2877
+ sourceNamespace: 'membership-month',
2878
+ sourceRef: `${input.membershipId}:${input.month}`,
2879
+ })
2880
+ }
2881
+ ```
2882
+
2883
+ Run missed eligible months with their original month identity; retry an uncertain
2884
+ request with exactly the same template, customer and source identity. Matching
2885
+ replay has one grant effect, even after configuration changes; changing that
2886
+ identity's payload conflicts. Fixed templates reject `amount`; bounded templates
2887
+ require an exact positive integer `amount` within their maximum. Revocation
2888
+ reports `revoked`, `pending` and `spent` separately, never creates debt, and routes
2889
+ later release or restoration to revoked funds. Deciding whether a membership
2890
+ cancellation or refund warrants revocation remains the tenant's responsibility.
2891
+ There is no platform cron, campaign engine, cash loading, transfer or cash-out.
2892
+
2893
+ ### Apply credit to the current Commerce Checkout
2894
+
2895
+ Pass an exact positive safe-integer `creditAmount` with the existing Checkout
2896
+ create request and its original idempotency key. Credit needs verified Customer
2897
+ proof, active ecommerce, enabled credit settings, available balance and cap
2898
+ admission. No browser balance or Accept header is payment authority.
2899
+
2900
+ The SDK opts into `application/vnd.01software.credit-funding.v1+json` for successful
2901
+ Checkout create/detail/query. Only this entire Accept value (trimmed,
2902
+ case-insensitive) opts in; lists, wildcards and parameters do not. The selected
2903
+ response uses that Content-Type and `Cache-Control: private, no-store`; errors
2904
+ retain their ordinary JSON type. The public `funding` object contains only
2905
+ `creditAmount` and `providerPayableAmount`. Show purchase total
2906
+ (`checkout.amounts.totalMinor`) separately from these credit and PG amounts.
2907
+ Full-credit placement needs no PaymentSession; mixed payment charges the frozen
2908
+ provider-payable amount. Refunds retain the original purchase split and restore
2909
+ only their attributed credit leg.
2910
+
2911
+ Old servers reject the new credit input before business writes. The SDK never
2912
+ strips it, changes it to zero, probes a separate endpoint or retries without
2913
+ credit. A response without `funding` remains a legacy response with unknown
2914
+ funding support, not proof of zero credit. Missing or inconsistent funding after
2915
+ a credit create is an uncertain result: retrieve the Checkout or retry the exact
2916
+ same request with the original idempotency key. Never fall back to a full PG charge.
2917
+
2918
+ For `server.commerce.orders.returnWithRefund`, omit `pgPaymentId` only if the
2919
+ original Order's frozen `provider_payable` is zero (a full-credit Order). A mixed
2920
+ Order requires its original capture identity even when the current refund has
2921
+ zero provider amount and restores credit only. A full-credit Order rejects any
2922
+ `pgPaymentId` or `paymentKey`; never invent an identifier. Explicit blank values
2923
+ remain invalid. Orders without credit funding retain `400/validation_failed`
2924
+ when `pgPaymentId` is omitted. Refund amount, credential, tenant and ecommerce authority remain unchanged.