@colixsystems/widget-sdk 0.61.0 → 0.62.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 CHANGED
@@ -53,7 +53,15 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
53
53
 
54
54
  ## Status
55
55
 
56
- `v0.60.0` — pre-publish. The package surface (types, function names, export paths) is the v1 contract; runtime behaviour for some hooks is stubbed (each hook documents what's wired and what isn't). It is **not yet published to npm**.
56
+ `v0.62.0` — pre-publish. The package surface (types, function names, export paths) is the v1 contract; runtime behaviour for some hooks is stubbed (each hook documents what's wired and what isn't). It is **not yet published to npm**.
57
+
58
+ ### What's new in 0.62.0
59
+
60
+ **`usePayments()` — the host owns the hosted-checkout redirect, and the documented contract is corrected to snake_case (sc-3290).** Two things that had drifted are now aligned with the runtime:
61
+
62
+ - **The host opens Checkout; the widget never does.** When a hosted-checkout provider (Mollie) is active, `requestPayment(...)` now makes the host open Checkout itself — a **same-tab** redirect on web, the **in-app browser** on native (the identical model the paid-signup flow uses). The result no longer carries a `checkout_url`, and widgets must **not** call `Linking.openURL(...)` for payments: `react-native-web`'s `Linking.openURL` opens a `_blank`, `noopener` tab, which left the app user stranded on an orphan tab after paying. `return_path` now defaults to the current page, so the web return lands the user back where they started. Confirm completion from server-authoritative state (the Mollie webhook flips your datastore record) or by polling `getPayment(id)`.
63
+ - **`PaymentRequest` / `PaymentResult` types are snake_case.** The TypeScript types and the `CONTRACT` return-shape strings described `amountCents` / `checkoutUrl` (plus a `metadata` field the client never forwarded), but the wire — and the runtime client — have always been snake_case. They now read `amount_cents`, `currency?`, `description`, `return_path?` in, `{ id, status, amount_cents, ... }` out. A TS widget that passed `amountCents` was silently sending `undefined`; update to `amount_cents`.
64
+ - No `CONTRACT.version` change — the `ctx.payments` context shape (`{ requestPayment, getPayment }`) is unchanged; only its documented request/return shape and the host-owned redirect behaviour changed.
57
65
 
58
66
  ### What's new in 0.60.0
59
67
 
@@ -394,6 +402,8 @@ The "split-implementation + vetted package list" pivot.
394
402
 
395
403
  ### What's new in 0.9.0
396
404
 
405
+ > **Superseded in 0.62.0** — the wire was always snake_case (`amount_cents`, `return_path`), never the camelCase shown below, and the HOST now opens hosted Checkout itself (the widget does not). See the 0.62.0 entry for the current contract.
406
+
397
407
  - **`usePayments()` — incoming app-user payments.** Returns `{ requestPayment, getPayment }`. `requestPayment({ amountCents, currency?, description, metadata?, returnPath? })` triggers a one-time charge from the signed-in app user and resolves to `{ id, status, checkoutUrl? }`: when `checkoutUrl` is present the widget opens it (web: navigate; native: `expo-web-browser`) — the user pays in the provider's **hosted checkout**; when absent (the platform's built-in **mock** provider, the default until a real provider is configured) the charge auto-confirms (`status: "PAID"`). `getPayment(id)` polls the terminal status. Backed by a new `WidgetContext.payments` slice and gated by the new `payments.charge:appUser` scope. **No card data ever touches the widget** — never collect card fields yourself. The charge settles to the workspace owner; the amount is bounded by a platform per-charge cap. Rejections are a structured `PaymentError` (also a new named export) with a stable `.code`.
398
408
  - **`CONTRACT.version` → `1.2.0`** (additive: one new hook, one new context slice, one new scope, one new error class). No existing export changed signature.
399
409
 
package/dist/contract.cjs CHANGED
@@ -469,9 +469,9 @@ const HOOKS = [
469
469
  signature: "usePayments()",
470
470
  returnShape: {
471
471
  requestPayment:
472
- "({ amountCents, currency?, description, metadata? }) => Promise<{ id, status, checkoutUrl? }> // rejects with PaymentError",
472
+ "({ amount_cents, currency?, description, return_path? }) => Promise<{ id, status }> // host opens hosted Checkout; rejects with PaymentError",
473
473
  getPayment:
474
- "(paymentId) => Promise<{ id, status, amountCents, currency, description }>",
474
+ "(paymentId) => Promise<{ id, status, amount_cents, currency, description }>",
475
475
  },
476
476
  requiredContextSlice: ["payments.requestPayment"],
477
477
  scopes: ["payments.charge:appUser"],
@@ -1119,7 +1119,7 @@ const WIDGET_CONTEXT_SHAPE = {
1119
1119
  },
1120
1120
  payments: {
1121
1121
  description:
1122
- "Injected @colixsystems/payments-client instance (REQ-BILL-07-WIDGETPAY). { requestPayment(body) -> Promise<{ id, status, checkoutUrl? }>, getPayment(id) -> Promise<payment> }. Backs usePayments(); requires the payments.charge:appUser scope. The host opens hosted Checkout (or auto-confirms under the mock provider); the charge settles to the workspace owner.",
1122
+ "Injected @colixsystems/payments-client instance (REQ-BILL-07-WIDGETPAY). { requestPayment(body) -> Promise<{ id, status }>, getPayment(id) -> Promise<payment> }; wire is snake_case (amount_cents, return_path). Backs usePayments(); requires the payments.charge:appUser scope. The host opens hosted Checkout itself — same-tab on web, in-app browser on native (or auto-confirms under the mock provider); the charge settles to the workspace owner.",
1123
1123
  required: true,
1124
1124
  fields: { requestPayment: "function", getPayment: "function" },
1125
1125
  },
package/dist/contract.js CHANGED
@@ -469,9 +469,9 @@ const HOOKS = [
469
469
  signature: "usePayments()",
470
470
  returnShape: {
471
471
  requestPayment:
472
- "({ amountCents, currency?, description, metadata? }) => Promise<{ id, status, checkoutUrl? }> // rejects with PaymentError",
472
+ "({ amount_cents, currency?, description, return_path? }) => Promise<{ id, status }> // host opens hosted Checkout; rejects with PaymentError",
473
473
  getPayment:
474
- "(paymentId) => Promise<{ id, status, amountCents, currency, description }>",
474
+ "(paymentId) => Promise<{ id, status, amount_cents, currency, description }>",
475
475
  },
476
476
  requiredContextSlice: ["payments.requestPayment"],
477
477
  scopes: ["payments.charge:appUser"],
@@ -1119,7 +1119,7 @@ const WIDGET_CONTEXT_SHAPE = {
1119
1119
  },
1120
1120
  payments: {
1121
1121
  description:
1122
- "Injected @colixsystems/payments-client instance (REQ-BILL-07-WIDGETPAY). { requestPayment(body) -> Promise<{ id, status, checkoutUrl? }>, getPayment(id) -> Promise<payment> }. Backs usePayments(); requires the payments.charge:appUser scope. The host opens hosted Checkout (or auto-confirms under the mock provider); the charge settles to the workspace owner.",
1122
+ "Injected @colixsystems/payments-client instance (REQ-BILL-07-WIDGETPAY). { requestPayment(body) -> Promise<{ id, status }>, getPayment(id) -> Promise<payment> }; wire is snake_case (amount_cents, return_path). Backs usePayments(); requires the payments.charge:appUser scope. The host opens hosted Checkout itself — same-tab on web, in-app browser on native (or auto-confirms under the mock provider); the charge settles to the workspace owner.",
1123
1123
  required: true,
1124
1124
  fields: { requestPayment: "function", getPayment: "function" },
1125
1125
  },
package/dist/hooks.js CHANGED
@@ -2813,20 +2813,26 @@ function toPaymentError(err) {
2813
2813
 
2814
2814
  /**
2815
2815
  * Incoming app-user payments (REQ-BILL-07-WIDGETPAY). Returns
2816
- * `{ requestPayment, getPayment }`.
2817
- *
2818
- * requestPayment({ amountCents, currency?, description, metadata? })
2819
- * → Promise<{ id, status, checkoutUrl?, ... }>. The host either
2820
- * auto-confirms (mock provider, `status: "PAID"`, no redirect) or
2821
- * returns a hosted-checkout `checkoutUrl` the widget should open
2822
- * (Mollie provider, `status: "PENDING"`). Rejects with a
2823
- * `PaymentError`.
2816
+ * `{ requestPayment, getPayment }`. The wire is snake_case (REQ-GEN-09) —
2817
+ * pass and read snake_case keys VERBATIM.
2818
+ *
2819
+ * requestPayment({ amount_cents, currency?, description, return_path? })
2820
+ * Promise<{ id, status, ... }>. When a hosted-checkout provider
2821
+ * (Mollie) is active the HOST opens Checkout for you — a same-tab
2822
+ * redirect on web, the in-app browser on native — so you do NOT open
2823
+ * anything yourself (no `Linking.openURL`, no `checkout_url` to
2824
+ * handle). The mock provider auto-confirms (`status: "PAID"`, no
2825
+ * redirect). Rejects with a `PaymentError`.
2824
2826
  * getPayment(paymentId) → Promise<payment> — poll the terminal status.
2825
2827
  *
2826
- * Requires the `payments.charge:appUser` scope in the manifest's
2827
- * `requestedScopes`. The charge settles to the workspace owner; the app
2828
- * user confirms the amount in hosted Checkout. No card data touches the
2829
- * widget never collect card fields yourself.
2828
+ * Because the web redirect reloads the app on return, confirm completion
2829
+ * from server-authoritative state (the Mollie webhook flips the charge /
2830
+ * your datastore record) re-read your bound record on mount, or poll
2831
+ * `getPayment(id)` after the mock/native flow resolves. Requires the
2832
+ * `payments.charge:appUser` scope in the manifest's `requestedScopes`. The
2833
+ * charge settles to the workspace owner; the app user confirms the amount
2834
+ * in hosted Checkout. No card data touches the widget — never collect card
2835
+ * fields yourself.
2830
2836
  */
2831
2837
  export function usePayments() {
2832
2838
  const ctx = useWidgetContextOrThrow("usePayments");
package/dist/index.d.ts CHANGED
@@ -614,32 +614,27 @@ export function useDirectory(query?: DirectoryQuery): DirectoryResult;
614
614
  export function useWidgetEvent(name: string): (payload?: unknown) => void;
615
615
 
616
616
  /**
617
- * Arguments for `usePayments().requestPayment(...)`. `amountCents` is the
618
- * charge in the currency's minor unit; the app user confirms it in hosted
619
- * Checkout. `metadata` is an optional flat map carried through for the
620
- * widget's own reconciliation (never used to derive the amount).
617
+ * Arguments for `usePayments().requestPayment(...)`. snake_case VERBATIM
618
+ * this is the wire contract (REQ-GEN-09). `amount_cents` is the charge in the
619
+ * currency's minor unit; the app user confirms it in hosted Checkout.
621
620
  */
622
621
  export interface PaymentRequest {
623
- amountCents: number;
622
+ amount_cents: number;
624
623
  currency?: string;
625
624
  description: string;
626
- metadata?: Record<string, string>;
627
- /** Site-relative path to return to after Checkout (e.g. "/cart"). */
628
- returnPath?: string;
625
+ /**
626
+ * Site-relative path to return to after Checkout (e.g. "/cart"). Defaults
627
+ * to the current page, so the user lands back where they started.
628
+ */
629
+ return_path?: string;
629
630
  }
630
631
 
631
632
  export interface PaymentResult {
632
633
  id: string;
633
634
  status: "PENDING" | "PAID" | "FAILED" | "REFUNDED" | "CANCELLED";
634
- amountCents?: number;
635
+ amount_cents?: number;
635
636
  currency?: string;
636
637
  description?: string;
637
- /**
638
- * Present (Mollie provider) when the app user must complete a hosted
639
- * checkout: the widget should open this URL. Absent under the mock
640
- * provider, where the charge auto-confirms (`status: "PAID"`).
641
- */
642
- checkoutUrl?: string | null;
643
638
  }
644
639
 
645
640
  export interface PaymentsApi {
@@ -649,8 +644,12 @@ export interface PaymentsApi {
649
644
 
650
645
  /**
651
646
  * Incoming app-user payments (REQ-BILL-07-WIDGETPAY). Requires the
652
- * `payments.charge:appUser` scope in the widget manifest. The charge
653
- * settles to the workspace owner; no card data touches the widget.
647
+ * `payments.charge:appUser` scope in the widget manifest. When a hosted-
648
+ * checkout provider is active the HOST opens Checkout for you (a same-tab
649
+ * redirect on web, the in-app browser on native) — you never open a URL and
650
+ * never collect card data. Confirm completion from server state (the webhook
651
+ * flips your record) or poll `getPayment(id)`. The charge settles to the
652
+ * workspace owner.
654
653
  */
655
654
  export function usePayments(): PaymentsApi;
656
655
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colixsystems/widget-sdk",
3
- "version": "0.61.0",
3
+ "version": "0.62.0",
4
4
  "description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",