@colixsystems/widget-sdk 0.287.0 → 0.288.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 +5 -1
- package/dist/contract.cjs +9 -5
- package/dist/contract.js +9 -5
- package/dist/hooks.js +7 -0
- package/dist/index.d.ts +20 -0
- package/package.json +1 -1
- package/src/contract.js +9 -5
package/README.md
CHANGED
|
@@ -90,7 +90,11 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
90
90
|
|
|
91
91
|
## Status
|
|
92
92
|
|
|
93
|
-
`v0.
|
|
93
|
+
`v0.288.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**.
|
|
94
|
+
|
|
95
|
+
### What's new in 0.288.0 (contract 1.236.0)
|
|
96
|
+
|
|
97
|
+
**A payment can pay for an order, and only the payment marks it paid.** Until now a shop widget charged the buyer and then wrote "Paid" to the order itself, so a buyer who could edit their own order could mark it paid without paying. `usePayments().requestPayment` now takes an optional `order: { table_id, record_id }`: a row the buyer may edit, in a table whose payment-status column the workspace has set (a STRING or BOOL column, one per table). The server checks it before the charge starts and refuses a missing or unreachable order (`ORDER_NOT_FOUND`), a table with no payment-status column (`ORDER_NOT_PAYABLE`) and an order that is already paid (`ORDER_ALREADY_PAID`); all three are non-retryable. Only one checkout per order can be open at a time: a second one while the first is still open is refused with `ORDER_PAYMENT_IN_PROGRESS`, which is retryable and clears when that checkout ends. When the payment settles, the server writes the column (`"PAID"`, or `true` on a BOOL; `"REFUNDED"` / `false` after a full refund); a failed or cancelled payment leaves it alone. Nothing else can write that column: every client value for it is ignored on create and update, so drop any code that sets "paid" yourself. The payment returned by `requestPayment` and `getPayment` carries `order` too, so a buyer coming back from Checkout lands on the right order. A `datastoreTemplate` column may declare `paymentStatus: true` to ship the column with the widget. Additive: a charge without `order` behaves as before.
|
|
94
98
|
|
|
95
99
|
### What's new in 0.287.0 (contract 1.235.0)
|
|
96
100
|
|
package/dist/contract.cjs
CHANGED
|
@@ -2376,9 +2376,9 @@ const HOOKS = [
|
|
|
2376
2376
|
signature: "usePayments()",
|
|
2377
2377
|
returnShape: {
|
|
2378
2378
|
requestPayment:
|
|
2379
|
-
"({ amount_cents, currency?, description, kind, return_path? }) => Promise<{ id, status }> // kind is REQUIRED: \"physical\" | \"service\" | \"digital\" — what is sold; a digital charge is refused in an iOS/Android build (DIGITAL_SALE_NEEDS_STORE_BILLING); host opens hosted Checkout; rejects with PaymentError { code, message, retryable } — render the message when retryable is false, never \"try again\"",
|
|
2379
|
+
"({ amount_cents, currency?, description, kind, return_path?, order? }) => Promise<{ id, status, order }> // kind is REQUIRED: \"physical\" | \"service\" | \"digital\" — what is sold; a digital charge is refused in an iOS/Android build (DIGITAL_SALE_NEEDS_STORE_BILLING); order: { table_id, record_id } — the order row this pays for, in a table with a payment-status column; the SERVER marks it paid when the payment settles, so never write \"paid\" yourself (refused: ORDER_NOT_FOUND, ORDER_NOT_PAYABLE, ORDER_ALREADY_PAID; ORDER_PAYMENT_IN_PROGRESS is retryable while another checkout for the order is open); host opens hosted Checkout; rejects with PaymentError { code, message, retryable } — render the message when retryable is false, never \"try again\"",
|
|
2380
2380
|
getPayment:
|
|
2381
|
-
"(paymentId) => Promise<{ id, status, amount_cents, currency, description }>",
|
|
2381
|
+
"(paymentId) => Promise<{ id, status, amount_cents, currency, description, order }> // order: { table_id, record_id } | null — read it after returning from Checkout",
|
|
2382
2382
|
},
|
|
2383
2383
|
requiredContextSlice: ["payments.requestPayment"],
|
|
2384
2384
|
scopes: ["payments.charge:appUser"],
|
|
@@ -4170,7 +4170,7 @@ const MANIFEST_SCHEMA = {
|
|
|
4170
4170
|
type: "object",
|
|
4171
4171
|
required: false,
|
|
4172
4172
|
description:
|
|
4173
|
-
"Optional. Tables the widget needs, seeded into the workspace at install time. Authors wire them into the widget's `tableRef` properties via the Properties Panel — the SDK does not auto-bind. Limits: 100 tables, 200 columns per table, 100 sample rows per table and 20000 sample cells across the whole template (each row counts the keys it sets, and at least one, summed over every table). RELATION columns address siblings by `targetSuffix` (any table in the same array, in any order; tables may relate to each other both ways). Tables persist across uninstalls. A `tableRef` property may also carry `sharedTable: true`, declaring that the table is the APP'S OWN — the author picks an existing table and the widget seeds nothing for it. That is the correct shape for a widget that reads data it does not own (a chart, a metric, a manager view over another widget's table). `sharedTable` exempts the property from needing a seeded table at publish (`manifest.requiredTableRefsHaveTemplate`) WITHOUT making it optional: the author must still bind one, and the host still refuses to place the widget unbound. Use it instead of dropping `required` — a widget that silently renders an empty tile is the defect it looks like a fix for. sc-7530: a table may also declare `roleGrants` — group-scoped access named SYMBOLICALLY, because a group id belongs to the workspace that installs the widget and could never travel in the manifest. Declare the audiences once at template level as `roles: [{ key, label, description? }]` (key is lowercase kebab, max 32 roles), then per table `roleGrants: [{ role, canRead?, canWrite?, canDelete? }]`. The installing workspace binds each role to one of its own user groups (or has one created) during the install consent step, so a permission model where an admin group does everything and signed-in users only read survives the trip between workspaces. Use `publicGrant` for the two id-less audiences (everyone / any signed-in user) and `roleGrants` for anything that names a group. A role nobody binds simply writes no grant — it never fails the install. sc-7557: a column may declare `encrypted: true` — its values are stored AES-256-GCM encrypted at rest under a per-workspace subkey. The widget still reads and writes PLAINTEXT (the platform encrypts on write, decrypts for end users); studio users see `🔒` instead, and the column cannot be searched, filtered or sorted on. Sample `rows` you seed for it are encrypted the same way. Not valid on `RELATION` — its value is a foreign key the backend must resolve — and publishing one is rejected. An `inheritAcl` RELATION column may add `inheritAclReadOnly: true` — rows then inherit READ access only, so members of the parent read every child and may add children, but change or delete only the rows they created (pair with `grantCreatorPermissions`). A column may declare `defaultValue`, written when a create omits it: `@currentUser` on USER, `@now` on DATE / DATETIME, `@uuid` on UUID (a new random id per row), or a literal of the column's own type (none on FILE, RELATION or USER_GROUP — ids belong to the installing workspace). `defaultLocked: true` on an `@currentUser` / `@now` / `@uuid` default makes the server always stamp it and ignore any client value on create and update, so an author column cannot be forged. `immutable: true` makes a column write-once: a create sets it as usual and any value sent for it on update is ignored (not valid on a MANY_TO_MANY relation). A table may declare `presence: true` so the people who share a row see which of each other are online (useOnlineMembers); it takes effect only while the workspace records user activity, and an upgrade that declares it turns it on for the existing table. A table whose rows people join and leave through per-record grants (conversations) may declare `deleteWhenLastMemberLeaves: true`: when a signed-in member giving up their own grant leaves a row with no grant and no table-wide grant lets anyone read it, the row and every row a CASCADE relation ties to it (including rows deleted earlier) are deleted for good. A row that never had a grant (a seeded sample row) is never deleted this way, and a revoke made in the Studio never deletes. An upgrade that declares it turns it on for the existing table. A ONE_TO_ONE / ONE_TO_MANY RELATION may declare `latestVia: \"<relation column on its target that points back>\"` (onDelete left at SET_NULL; that relation must have inheritAcl and be immutable): the server keeps it at the newest row of the target table that points back at this row. A column may declare `copyOf: { via, column }`: the server keeps it equal to `column` on the row the latest-row column `via` points at (same type, or text into text, cut to 140 characters in a STRING column; a copy of an encrypted column must be encrypted, and a copy cannot inheritAcl). Both are written only by the server, in the same write as the related row; a client value is ignored. A table may declare `constraints`, checked on every write for every client and refused as CONSTRAINT_VIOLATION: `unique` ({ columns, partitionColumns?, unlessRelated?: { relation, column } } — waived for rows whose related row has that yes/no column set), `no-overlap` ({ startColumn, endColumn, partitionColumns? }), `related-open` ({ relation, closedColumn } — no row is added, changed or removed while the related row's column is filled) and `related-index` ({ column, relation, listColumn } — the number must be a position in the related row's list). An upgrade adds a declared constraint to an existing table without judging the rows already in it.",
|
|
4173
|
+
"Optional. Tables the widget needs, seeded into the workspace at install time. Authors wire them into the widget's `tableRef` properties via the Properties Panel — the SDK does not auto-bind. Limits: 100 tables, 200 columns per table, 100 sample rows per table and 20000 sample cells across the whole template (each row counts the keys it sets, and at least one, summed over every table). RELATION columns address siblings by `targetSuffix` (any table in the same array, in any order; tables may relate to each other both ways). Tables persist across uninstalls. A `tableRef` property may also carry `sharedTable: true`, declaring that the table is the APP'S OWN — the author picks an existing table and the widget seeds nothing for it. That is the correct shape for a widget that reads data it does not own (a chart, a metric, a manager view over another widget's table). `sharedTable` exempts the property from needing a seeded table at publish (`manifest.requiredTableRefsHaveTemplate`) WITHOUT making it optional: the author must still bind one, and the host still refuses to place the widget unbound. Use it instead of dropping `required` — a widget that silently renders an empty tile is the defect it looks like a fix for. sc-7530: a table may also declare `roleGrants` — group-scoped access named SYMBOLICALLY, because a group id belongs to the workspace that installs the widget and could never travel in the manifest. Declare the audiences once at template level as `roles: [{ key, label, description? }]` (key is lowercase kebab, max 32 roles), then per table `roleGrants: [{ role, canRead?, canWrite?, canDelete? }]`. The installing workspace binds each role to one of its own user groups (or has one created) during the install consent step, so a permission model where an admin group does everything and signed-in users only read survives the trip between workspaces. Use `publicGrant` for the two id-less audiences (everyone / any signed-in user) and `roleGrants` for anything that names a group. A role nobody binds simply writes no grant — it never fails the install. sc-7557: a column may declare `encrypted: true` — its values are stored AES-256-GCM encrypted at rest under a per-workspace subkey. The widget still reads and writes PLAINTEXT (the platform encrypts on write, decrypts for end users); studio users see `🔒` instead, and the column cannot be searched, filtered or sorted on. Sample `rows` you seed for it are encrypted the same way. Not valid on `RELATION` — its value is a foreign key the backend must resolve — and publishing one is rejected. An `inheritAcl` RELATION column may add `inheritAclReadOnly: true` — rows then inherit READ access only, so members of the parent read every child and may add children, but change or delete only the rows they created (pair with `grantCreatorPermissions`). A column may declare `defaultValue`, written when a create omits it: `@currentUser` on USER, `@now` on DATE / DATETIME, `@uuid` on UUID (a new random id per row), or a literal of the column's own type (none on FILE, RELATION or USER_GROUP — ids belong to the installing workspace). `defaultLocked: true` on an `@currentUser` / `@now` / `@uuid` default makes the server always stamp it and ignore any client value on create and update, so an author column cannot be forged. `immutable: true` makes a column write-once: a create sets it as usual and any value sent for it on update is ignored (not valid on a MANY_TO_MANY relation). `paymentStatus: true` makes a STRING or BOOL column the table's payment status (at most one per table; not required, encrypted, immutable or defaulting to paid): a settled `requestPayment({ order: { table_id, record_id } })` for one of its rows writes it (`PAID`, or `true` on a BOOL; `REFUNDED` / `false` after a full refund), and every client value for it is ignored, so a buyer cannot mark their own order paid. A table may declare `presence: true` so the people who share a row see which of each other are online (useOnlineMembers); it takes effect only while the workspace records user activity, and an upgrade that declares it turns it on for the existing table. A table whose rows people join and leave through per-record grants (conversations) may declare `deleteWhenLastMemberLeaves: true`: when a signed-in member giving up their own grant leaves a row with no grant and no table-wide grant lets anyone read it, the row and every row a CASCADE relation ties to it (including rows deleted earlier) are deleted for good. A row that never had a grant (a seeded sample row) is never deleted this way, and a revoke made in the Studio never deletes. An upgrade that declares it turns it on for the existing table. A ONE_TO_ONE / ONE_TO_MANY RELATION may declare `latestVia: \"<relation column on its target that points back>\"` (onDelete left at SET_NULL; that relation must have inheritAcl and be immutable): the server keeps it at the newest row of the target table that points back at this row. A column may declare `copyOf: { via, column }`: the server keeps it equal to `column` on the row the latest-row column `via` points at (same type, or text into text, cut to 140 characters in a STRING column; a copy of an encrypted column must be encrypted, and a copy cannot inheritAcl). Both are written only by the server, in the same write as the related row; a client value is ignored. A table may declare `constraints`, checked on every write for every client and refused as CONSTRAINT_VIOLATION: `unique` ({ columns, partitionColumns?, unlessRelated?: { relation, column } } — waived for rows whose related row has that yes/no column set), `no-overlap` ({ startColumn, endColumn, partitionColumns? }), `related-open` ({ relation, closedColumn } — no row is added, changed or removed while the related row's column is filled) and `related-index` ({ column, relation, listColumn } — the number must be a position in the related row's list). An upgrade adds a declared constraint to an existing table without judging the rows already in it.",
|
|
4174
4174
|
},
|
|
4175
4175
|
translations: {
|
|
4176
4176
|
type: "object",
|
|
@@ -4471,7 +4471,7 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
4471
4471
|
},
|
|
4472
4472
|
payments: {
|
|
4473
4473
|
description:
|
|
4474
|
-
"Injected @colixsystems/payments-client instance (REQ-BILL-07-WIDGETPAY). { requestPayment(body) -> Promise<{ id, status }>, getPayment(id) -> Promise<payment>, listAccessPlans() -> Promise<{ data, meta }>, purchaseAccessPlan({ plan_id, return_path? }) -> Promise<{ plan_id, status }>, cancelAccessPlan(planId) -> Promise<{ plan_id, renews, access_ends_at }>, getAppSubscription() -> Promise<{ active, renews, access_ends_at }>, cancelAppSubscription() -> Promise<{ active, renews, access_ends_at }> }; wire is snake_case (amount_cents, return_path). Backs usePayments(), useAccessPlans() and useAppSubscription(); 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.",
|
|
4474
|
+
"Injected @colixsystems/payments-client instance (REQ-BILL-07-WIDGETPAY). { requestPayment(body) -> Promise<{ id, status }>, getPayment(id) -> Promise<payment>, listAccessPlans() -> Promise<{ data, meta }>, purchaseAccessPlan({ plan_id, return_path? }) -> Promise<{ plan_id, status }>, cancelAccessPlan(planId) -> Promise<{ plan_id, renews, access_ends_at }>, getAppSubscription() -> Promise<{ active, renews, access_ends_at }>, cancelAppSubscription() -> Promise<{ active, renews, access_ends_at }> }; wire is snake_case (amount_cents, return_path, order). Backs usePayments(), useAccessPlans() and useAppSubscription(); 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.",
|
|
4475
4475
|
required: true,
|
|
4476
4476
|
fields: {
|
|
4477
4477
|
requestPayment: "function",
|
|
@@ -6745,7 +6745,11 @@ const CONTRACT = deepFreeze({
|
|
|
6745
6745
|
// 1.235.0: additive (sc-15342) — `useAppSubscription()`, and the payments
|
|
6746
6746
|
// slice gains `getAppSubscription` / `cancelAppSubscription`: a paid
|
|
6747
6747
|
// app's subscriber cancels their own subscription.
|
|
6748
|
-
|
|
6748
|
+
// 1.236.0: additive (sc-15358) — `requestPayment` takes an optional
|
|
6749
|
+
// `order: { table_id, record_id }` the server marks paid on settlement,
|
|
6750
|
+
// a template column may declare `paymentStatus: true`, and four new
|
|
6751
|
+
// PaymentError codes.
|
|
6752
|
+
version: "1.236.0",
|
|
6749
6753
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
6750
6754
|
hooks: HOOKS,
|
|
6751
6755
|
primitives: PRIMITIVES,
|
package/dist/contract.js
CHANGED
|
@@ -2372,9 +2372,9 @@ const HOOKS = [
|
|
|
2372
2372
|
signature: "usePayments()",
|
|
2373
2373
|
returnShape: {
|
|
2374
2374
|
requestPayment:
|
|
2375
|
-
"({ amount_cents, currency?, description, kind, return_path? }) => Promise<{ id, status }> // kind is REQUIRED: \"physical\" | \"service\" | \"digital\" — what is sold; a digital charge is refused in an iOS/Android build (DIGITAL_SALE_NEEDS_STORE_BILLING); host opens hosted Checkout; rejects with PaymentError { code, message, retryable } — render the message when retryable is false, never \"try again\"",
|
|
2375
|
+
"({ amount_cents, currency?, description, kind, return_path?, order? }) => Promise<{ id, status, order }> // kind is REQUIRED: \"physical\" | \"service\" | \"digital\" — what is sold; a digital charge is refused in an iOS/Android build (DIGITAL_SALE_NEEDS_STORE_BILLING); order: { table_id, record_id } — the order row this pays for, in a table with a payment-status column; the SERVER marks it paid when the payment settles, so never write \"paid\" yourself (refused: ORDER_NOT_FOUND, ORDER_NOT_PAYABLE, ORDER_ALREADY_PAID; ORDER_PAYMENT_IN_PROGRESS is retryable while another checkout for the order is open); host opens hosted Checkout; rejects with PaymentError { code, message, retryable } — render the message when retryable is false, never \"try again\"",
|
|
2376
2376
|
getPayment:
|
|
2377
|
-
"(paymentId) => Promise<{ id, status, amount_cents, currency, description }>",
|
|
2377
|
+
"(paymentId) => Promise<{ id, status, amount_cents, currency, description, order }> // order: { table_id, record_id } | null — read it after returning from Checkout",
|
|
2378
2378
|
},
|
|
2379
2379
|
requiredContextSlice: ["payments.requestPayment"],
|
|
2380
2380
|
scopes: ["payments.charge:appUser"],
|
|
@@ -4166,7 +4166,7 @@ const MANIFEST_SCHEMA = {
|
|
|
4166
4166
|
type: "object",
|
|
4167
4167
|
required: false,
|
|
4168
4168
|
description:
|
|
4169
|
-
"Optional. Tables the widget needs, seeded into the workspace at install time. Authors wire them into the widget's `tableRef` properties via the Properties Panel — the SDK does not auto-bind. Limits: 100 tables, 200 columns per table, 100 sample rows per table and 20000 sample cells across the whole template (each row counts the keys it sets, and at least one, summed over every table). RELATION columns address siblings by `targetSuffix` (any table in the same array, in any order; tables may relate to each other both ways). Tables persist across uninstalls. A `tableRef` property may also carry `sharedTable: true`, declaring that the table is the APP'S OWN — the author picks an existing table and the widget seeds nothing for it. That is the correct shape for a widget that reads data it does not own (a chart, a metric, a manager view over another widget's table). `sharedTable` exempts the property from needing a seeded table at publish (`manifest.requiredTableRefsHaveTemplate`) WITHOUT making it optional: the author must still bind one, and the host still refuses to place the widget unbound. Use it instead of dropping `required` — a widget that silently renders an empty tile is the defect it looks like a fix for. sc-7530: a table may also declare `roleGrants` — group-scoped access named SYMBOLICALLY, because a group id belongs to the workspace that installs the widget and could never travel in the manifest. Declare the audiences once at template level as `roles: [{ key, label, description? }]` (key is lowercase kebab, max 32 roles), then per table `roleGrants: [{ role, canRead?, canWrite?, canDelete? }]`. The installing workspace binds each role to one of its own user groups (or has one created) during the install consent step, so a permission model where an admin group does everything and signed-in users only read survives the trip between workspaces. Use `publicGrant` for the two id-less audiences (everyone / any signed-in user) and `roleGrants` for anything that names a group. A role nobody binds simply writes no grant — it never fails the install. sc-7557: a column may declare `encrypted: true` — its values are stored AES-256-GCM encrypted at rest under a per-workspace subkey. The widget still reads and writes PLAINTEXT (the platform encrypts on write, decrypts for end users); studio users see `🔒` instead, and the column cannot be searched, filtered or sorted on. Sample `rows` you seed for it are encrypted the same way. Not valid on `RELATION` — its value is a foreign key the backend must resolve — and publishing one is rejected. An `inheritAcl` RELATION column may add `inheritAclReadOnly: true` — rows then inherit READ access only, so members of the parent read every child and may add children, but change or delete only the rows they created (pair with `grantCreatorPermissions`). A column may declare `defaultValue`, written when a create omits it: `@currentUser` on USER, `@now` on DATE / DATETIME, `@uuid` on UUID (a new random id per row), or a literal of the column's own type (none on FILE, RELATION or USER_GROUP — ids belong to the installing workspace). `defaultLocked: true` on an `@currentUser` / `@now` / `@uuid` default makes the server always stamp it and ignore any client value on create and update, so an author column cannot be forged. `immutable: true` makes a column write-once: a create sets it as usual and any value sent for it on update is ignored (not valid on a MANY_TO_MANY relation). A table may declare `presence: true` so the people who share a row see which of each other are online (useOnlineMembers); it takes effect only while the workspace records user activity, and an upgrade that declares it turns it on for the existing table. A table whose rows people join and leave through per-record grants (conversations) may declare `deleteWhenLastMemberLeaves: true`: when a signed-in member giving up their own grant leaves a row with no grant and no table-wide grant lets anyone read it, the row and every row a CASCADE relation ties to it (including rows deleted earlier) are deleted for good. A row that never had a grant (a seeded sample row) is never deleted this way, and a revoke made in the Studio never deletes. An upgrade that declares it turns it on for the existing table. A ONE_TO_ONE / ONE_TO_MANY RELATION may declare `latestVia: \"<relation column on its target that points back>\"` (onDelete left at SET_NULL; that relation must have inheritAcl and be immutable): the server keeps it at the newest row of the target table that points back at this row. A column may declare `copyOf: { via, column }`: the server keeps it equal to `column` on the row the latest-row column `via` points at (same type, or text into text, cut to 140 characters in a STRING column; a copy of an encrypted column must be encrypted, and a copy cannot inheritAcl). Both are written only by the server, in the same write as the related row; a client value is ignored. A table may declare `constraints`, checked on every write for every client and refused as CONSTRAINT_VIOLATION: `unique` ({ columns, partitionColumns?, unlessRelated?: { relation, column } } — waived for rows whose related row has that yes/no column set), `no-overlap` ({ startColumn, endColumn, partitionColumns? }), `related-open` ({ relation, closedColumn } — no row is added, changed or removed while the related row's column is filled) and `related-index` ({ column, relation, listColumn } — the number must be a position in the related row's list). An upgrade adds a declared constraint to an existing table without judging the rows already in it.",
|
|
4169
|
+
"Optional. Tables the widget needs, seeded into the workspace at install time. Authors wire them into the widget's `tableRef` properties via the Properties Panel — the SDK does not auto-bind. Limits: 100 tables, 200 columns per table, 100 sample rows per table and 20000 sample cells across the whole template (each row counts the keys it sets, and at least one, summed over every table). RELATION columns address siblings by `targetSuffix` (any table in the same array, in any order; tables may relate to each other both ways). Tables persist across uninstalls. A `tableRef` property may also carry `sharedTable: true`, declaring that the table is the APP'S OWN — the author picks an existing table and the widget seeds nothing for it. That is the correct shape for a widget that reads data it does not own (a chart, a metric, a manager view over another widget's table). `sharedTable` exempts the property from needing a seeded table at publish (`manifest.requiredTableRefsHaveTemplate`) WITHOUT making it optional: the author must still bind one, and the host still refuses to place the widget unbound. Use it instead of dropping `required` — a widget that silently renders an empty tile is the defect it looks like a fix for. sc-7530: a table may also declare `roleGrants` — group-scoped access named SYMBOLICALLY, because a group id belongs to the workspace that installs the widget and could never travel in the manifest. Declare the audiences once at template level as `roles: [{ key, label, description? }]` (key is lowercase kebab, max 32 roles), then per table `roleGrants: [{ role, canRead?, canWrite?, canDelete? }]`. The installing workspace binds each role to one of its own user groups (or has one created) during the install consent step, so a permission model where an admin group does everything and signed-in users only read survives the trip between workspaces. Use `publicGrant` for the two id-less audiences (everyone / any signed-in user) and `roleGrants` for anything that names a group. A role nobody binds simply writes no grant — it never fails the install. sc-7557: a column may declare `encrypted: true` — its values are stored AES-256-GCM encrypted at rest under a per-workspace subkey. The widget still reads and writes PLAINTEXT (the platform encrypts on write, decrypts for end users); studio users see `🔒` instead, and the column cannot be searched, filtered or sorted on. Sample `rows` you seed for it are encrypted the same way. Not valid on `RELATION` — its value is a foreign key the backend must resolve — and publishing one is rejected. An `inheritAcl` RELATION column may add `inheritAclReadOnly: true` — rows then inherit READ access only, so members of the parent read every child and may add children, but change or delete only the rows they created (pair with `grantCreatorPermissions`). A column may declare `defaultValue`, written when a create omits it: `@currentUser` on USER, `@now` on DATE / DATETIME, `@uuid` on UUID (a new random id per row), or a literal of the column's own type (none on FILE, RELATION or USER_GROUP — ids belong to the installing workspace). `defaultLocked: true` on an `@currentUser` / `@now` / `@uuid` default makes the server always stamp it and ignore any client value on create and update, so an author column cannot be forged. `immutable: true` makes a column write-once: a create sets it as usual and any value sent for it on update is ignored (not valid on a MANY_TO_MANY relation). `paymentStatus: true` makes a STRING or BOOL column the table's payment status (at most one per table; not required, encrypted, immutable or defaulting to paid): a settled `requestPayment({ order: { table_id, record_id } })` for one of its rows writes it (`PAID`, or `true` on a BOOL; `REFUNDED` / `false` after a full refund), and every client value for it is ignored, so a buyer cannot mark their own order paid. A table may declare `presence: true` so the people who share a row see which of each other are online (useOnlineMembers); it takes effect only while the workspace records user activity, and an upgrade that declares it turns it on for the existing table. A table whose rows people join and leave through per-record grants (conversations) may declare `deleteWhenLastMemberLeaves: true`: when a signed-in member giving up their own grant leaves a row with no grant and no table-wide grant lets anyone read it, the row and every row a CASCADE relation ties to it (including rows deleted earlier) are deleted for good. A row that never had a grant (a seeded sample row) is never deleted this way, and a revoke made in the Studio never deletes. An upgrade that declares it turns it on for the existing table. A ONE_TO_ONE / ONE_TO_MANY RELATION may declare `latestVia: \"<relation column on its target that points back>\"` (onDelete left at SET_NULL; that relation must have inheritAcl and be immutable): the server keeps it at the newest row of the target table that points back at this row. A column may declare `copyOf: { via, column }`: the server keeps it equal to `column` on the row the latest-row column `via` points at (same type, or text into text, cut to 140 characters in a STRING column; a copy of an encrypted column must be encrypted, and a copy cannot inheritAcl). Both are written only by the server, in the same write as the related row; a client value is ignored. A table may declare `constraints`, checked on every write for every client and refused as CONSTRAINT_VIOLATION: `unique` ({ columns, partitionColumns?, unlessRelated?: { relation, column } } — waived for rows whose related row has that yes/no column set), `no-overlap` ({ startColumn, endColumn, partitionColumns? }), `related-open` ({ relation, closedColumn } — no row is added, changed or removed while the related row's column is filled) and `related-index` ({ column, relation, listColumn } — the number must be a position in the related row's list). An upgrade adds a declared constraint to an existing table without judging the rows already in it.",
|
|
4170
4170
|
},
|
|
4171
4171
|
translations: {
|
|
4172
4172
|
type: "object",
|
|
@@ -4467,7 +4467,7 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
4467
4467
|
},
|
|
4468
4468
|
payments: {
|
|
4469
4469
|
description:
|
|
4470
|
-
"Injected @colixsystems/payments-client instance (REQ-BILL-07-WIDGETPAY). { requestPayment(body) -> Promise<{ id, status }>, getPayment(id) -> Promise<payment>, listAccessPlans() -> Promise<{ data, meta }>, purchaseAccessPlan({ plan_id, return_path? }) -> Promise<{ plan_id, status }>, cancelAccessPlan(planId) -> Promise<{ plan_id, renews, access_ends_at }>, getAppSubscription() -> Promise<{ active, renews, access_ends_at }>, cancelAppSubscription() -> Promise<{ active, renews, access_ends_at }> }; wire is snake_case (amount_cents, return_path). Backs usePayments(), useAccessPlans() and useAppSubscription(); 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.",
|
|
4470
|
+
"Injected @colixsystems/payments-client instance (REQ-BILL-07-WIDGETPAY). { requestPayment(body) -> Promise<{ id, status }>, getPayment(id) -> Promise<payment>, listAccessPlans() -> Promise<{ data, meta }>, purchaseAccessPlan({ plan_id, return_path? }) -> Promise<{ plan_id, status }>, cancelAccessPlan(planId) -> Promise<{ plan_id, renews, access_ends_at }>, getAppSubscription() -> Promise<{ active, renews, access_ends_at }>, cancelAppSubscription() -> Promise<{ active, renews, access_ends_at }> }; wire is snake_case (amount_cents, return_path, order). Backs usePayments(), useAccessPlans() and useAppSubscription(); 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.",
|
|
4471
4471
|
required: true,
|
|
4472
4472
|
fields: {
|
|
4473
4473
|
requestPayment: "function",
|
|
@@ -6741,7 +6741,11 @@ const CONTRACT = deepFreeze({
|
|
|
6741
6741
|
// 1.235.0: additive (sc-15342) — `useAppSubscription()`, and the payments
|
|
6742
6742
|
// slice gains `getAppSubscription` / `cancelAppSubscription`: a paid
|
|
6743
6743
|
// app's subscriber cancels their own subscription.
|
|
6744
|
-
|
|
6744
|
+
// 1.236.0: additive (sc-15358) — `requestPayment` takes an optional
|
|
6745
|
+
// `order: { table_id, record_id }` the server marks paid on settlement,
|
|
6746
|
+
// a template column may declare `paymentStatus: true`, and four new
|
|
6747
|
+
// PaymentError codes.
|
|
6748
|
+
version: "1.236.0",
|
|
6745
6749
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
6746
6750
|
hooks: HOOKS,
|
|
6747
6751
|
primitives: PRIMITIVES,
|
package/dist/hooks.js
CHANGED
|
@@ -6893,6 +6893,9 @@ const NON_RETRYABLE_PAYMENT_CODES = new Set([
|
|
|
6893
6893
|
"FORBIDDEN",
|
|
6894
6894
|
"INVALID_AMOUNT",
|
|
6895
6895
|
"NOT_FOUND",
|
|
6896
|
+
"ORDER_ALREADY_PAID",
|
|
6897
|
+
"ORDER_NOT_FOUND",
|
|
6898
|
+
"ORDER_NOT_PAYABLE",
|
|
6896
6899
|
"PAYMENTS_DISABLED",
|
|
6897
6900
|
"PAYMENTS_SCOPE_NOT_GRANTED",
|
|
6898
6901
|
"PAYMENTS_UNAVAILABLE",
|
|
@@ -6920,6 +6923,10 @@ const NON_RETRYABLE_PAYMENT_CODES = new Set([
|
|
|
6920
6923
|
* - "CHARGE_KIND_NOT_ENABLED" — this workspace cannot sell that kind yet
|
|
6921
6924
|
* - "DIGITAL_SALE_NEEDS_STORE_BILLING" — a digital sale from an iOS / Android
|
|
6922
6925
|
* build: store policy requires store billing
|
|
6926
|
+
* - "ORDER_NOT_FOUND" / "ORDER_NOT_PAYABLE" / "ORDER_ALREADY_PAID" — the
|
|
6927
|
+
* `order` is not one this user can pay for
|
|
6928
|
+
* - "ORDER_PAYMENT_IN_PROGRESS" — another checkout for the order is open
|
|
6929
|
+
* (retryable: it clears when that one ends)
|
|
6923
6930
|
* - "CONNECT_NOT_READY" / "PAYMENTS_DISABLED" — provider not ready
|
|
6924
6931
|
* - "DECLINED" — the charge was declined
|
|
6925
6932
|
* - "INTERNAL" — anything else
|
package/dist/index.d.ts
CHANGED
|
@@ -1538,6 +1538,20 @@ export interface PaymentRequest {
|
|
|
1538
1538
|
* to the current page, so the user lands back where they started.
|
|
1539
1539
|
*/
|
|
1540
1540
|
return_path?: string;
|
|
1541
|
+
/**
|
|
1542
|
+
* The order this charge pays for: a row the user may edit, in a table with
|
|
1543
|
+
* a payment-status column. When the payment settles the server sets that
|
|
1544
|
+
* column, so never write "paid" yourself; the platform ignores it anyway.
|
|
1545
|
+
* Refused with ORDER_NOT_FOUND, ORDER_NOT_PAYABLE or ORDER_ALREADY_PAID, and
|
|
1546
|
+
* with the retryable ORDER_PAYMENT_IN_PROGRESS while another checkout is open.
|
|
1547
|
+
*/
|
|
1548
|
+
order?: PaymentOrder;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
/** A row of a table with a payment-status column, by the ids a widget holds. */
|
|
1552
|
+
export interface PaymentOrder {
|
|
1553
|
+
table_id: string;
|
|
1554
|
+
record_id: string;
|
|
1541
1555
|
}
|
|
1542
1556
|
|
|
1543
1557
|
export interface PaymentResult {
|
|
@@ -1547,6 +1561,8 @@ export interface PaymentResult {
|
|
|
1547
1561
|
currency?: string;
|
|
1548
1562
|
description?: string;
|
|
1549
1563
|
kind?: "physical" | "service" | "digital" | null;
|
|
1564
|
+
/** The order the charge pays for, or null. Read it after returning from Checkout. */
|
|
1565
|
+
order?: PaymentOrder | null;
|
|
1550
1566
|
}
|
|
1551
1567
|
|
|
1552
1568
|
export interface PaymentsApi {
|
|
@@ -1658,6 +1674,10 @@ export class PaymentError extends Error {
|
|
|
1658
1674
|
| "CHARGE_KIND_REQUIRED"
|
|
1659
1675
|
| "CHARGE_KIND_NOT_ENABLED"
|
|
1660
1676
|
| "DIGITAL_SALE_NEEDS_STORE_BILLING"
|
|
1677
|
+
| "ORDER_NOT_FOUND"
|
|
1678
|
+
| "ORDER_NOT_PAYABLE"
|
|
1679
|
+
| "ORDER_ALREADY_PAID"
|
|
1680
|
+
| "ORDER_PAYMENT_IN_PROGRESS"
|
|
1661
1681
|
| "PAYMENTS_DISABLED"
|
|
1662
1682
|
| "DECLINED"
|
|
1663
1683
|
| "FORBIDDEN"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.288.0",
|
|
4
4
|
"description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
|
|
5
5
|
"homepage": "https://github.com/Colix-AB/AppStudio",
|
|
6
6
|
"type": "module",
|
package/src/contract.js
CHANGED
|
@@ -2372,9 +2372,9 @@ const HOOKS = [
|
|
|
2372
2372
|
signature: "usePayments()",
|
|
2373
2373
|
returnShape: {
|
|
2374
2374
|
requestPayment:
|
|
2375
|
-
"({ amount_cents, currency?, description, kind, return_path? }) => Promise<{ id, status }> // kind is REQUIRED: \"physical\" | \"service\" | \"digital\" — what is sold; a digital charge is refused in an iOS/Android build (DIGITAL_SALE_NEEDS_STORE_BILLING); host opens hosted Checkout; rejects with PaymentError { code, message, retryable } — render the message when retryable is false, never \"try again\"",
|
|
2375
|
+
"({ amount_cents, currency?, description, kind, return_path?, order? }) => Promise<{ id, status, order }> // kind is REQUIRED: \"physical\" | \"service\" | \"digital\" — what is sold; a digital charge is refused in an iOS/Android build (DIGITAL_SALE_NEEDS_STORE_BILLING); order: { table_id, record_id } — the order row this pays for, in a table with a payment-status column; the SERVER marks it paid when the payment settles, so never write \"paid\" yourself (refused: ORDER_NOT_FOUND, ORDER_NOT_PAYABLE, ORDER_ALREADY_PAID; ORDER_PAYMENT_IN_PROGRESS is retryable while another checkout for the order is open); host opens hosted Checkout; rejects with PaymentError { code, message, retryable } — render the message when retryable is false, never \"try again\"",
|
|
2376
2376
|
getPayment:
|
|
2377
|
-
"(paymentId) => Promise<{ id, status, amount_cents, currency, description }>",
|
|
2377
|
+
"(paymentId) => Promise<{ id, status, amount_cents, currency, description, order }> // order: { table_id, record_id } | null — read it after returning from Checkout",
|
|
2378
2378
|
},
|
|
2379
2379
|
requiredContextSlice: ["payments.requestPayment"],
|
|
2380
2380
|
scopes: ["payments.charge:appUser"],
|
|
@@ -4166,7 +4166,7 @@ const MANIFEST_SCHEMA = {
|
|
|
4166
4166
|
type: "object",
|
|
4167
4167
|
required: false,
|
|
4168
4168
|
description:
|
|
4169
|
-
"Optional. Tables the widget needs, seeded into the workspace at install time. Authors wire them into the widget's `tableRef` properties via the Properties Panel — the SDK does not auto-bind. Limits: 100 tables, 200 columns per table, 100 sample rows per table and 20000 sample cells across the whole template (each row counts the keys it sets, and at least one, summed over every table). RELATION columns address siblings by `targetSuffix` (any table in the same array, in any order; tables may relate to each other both ways). Tables persist across uninstalls. A `tableRef` property may also carry `sharedTable: true`, declaring that the table is the APP'S OWN — the author picks an existing table and the widget seeds nothing for it. That is the correct shape for a widget that reads data it does not own (a chart, a metric, a manager view over another widget's table). `sharedTable` exempts the property from needing a seeded table at publish (`manifest.requiredTableRefsHaveTemplate`) WITHOUT making it optional: the author must still bind one, and the host still refuses to place the widget unbound. Use it instead of dropping `required` — a widget that silently renders an empty tile is the defect it looks like a fix for. sc-7530: a table may also declare `roleGrants` — group-scoped access named SYMBOLICALLY, because a group id belongs to the workspace that installs the widget and could never travel in the manifest. Declare the audiences once at template level as `roles: [{ key, label, description? }]` (key is lowercase kebab, max 32 roles), then per table `roleGrants: [{ role, canRead?, canWrite?, canDelete? }]`. The installing workspace binds each role to one of its own user groups (or has one created) during the install consent step, so a permission model where an admin group does everything and signed-in users only read survives the trip between workspaces. Use `publicGrant` for the two id-less audiences (everyone / any signed-in user) and `roleGrants` for anything that names a group. A role nobody binds simply writes no grant — it never fails the install. sc-7557: a column may declare `encrypted: true` — its values are stored AES-256-GCM encrypted at rest under a per-workspace subkey. The widget still reads and writes PLAINTEXT (the platform encrypts on write, decrypts for end users); studio users see `🔒` instead, and the column cannot be searched, filtered or sorted on. Sample `rows` you seed for it are encrypted the same way. Not valid on `RELATION` — its value is a foreign key the backend must resolve — and publishing one is rejected. An `inheritAcl` RELATION column may add `inheritAclReadOnly: true` — rows then inherit READ access only, so members of the parent read every child and may add children, but change or delete only the rows they created (pair with `grantCreatorPermissions`). A column may declare `defaultValue`, written when a create omits it: `@currentUser` on USER, `@now` on DATE / DATETIME, `@uuid` on UUID (a new random id per row), or a literal of the column's own type (none on FILE, RELATION or USER_GROUP — ids belong to the installing workspace). `defaultLocked: true` on an `@currentUser` / `@now` / `@uuid` default makes the server always stamp it and ignore any client value on create and update, so an author column cannot be forged. `immutable: true` makes a column write-once: a create sets it as usual and any value sent for it on update is ignored (not valid on a MANY_TO_MANY relation). A table may declare `presence: true` so the people who share a row see which of each other are online (useOnlineMembers); it takes effect only while the workspace records user activity, and an upgrade that declares it turns it on for the existing table. A table whose rows people join and leave through per-record grants (conversations) may declare `deleteWhenLastMemberLeaves: true`: when a signed-in member giving up their own grant leaves a row with no grant and no table-wide grant lets anyone read it, the row and every row a CASCADE relation ties to it (including rows deleted earlier) are deleted for good. A row that never had a grant (a seeded sample row) is never deleted this way, and a revoke made in the Studio never deletes. An upgrade that declares it turns it on for the existing table. A ONE_TO_ONE / ONE_TO_MANY RELATION may declare `latestVia: \"<relation column on its target that points back>\"` (onDelete left at SET_NULL; that relation must have inheritAcl and be immutable): the server keeps it at the newest row of the target table that points back at this row. A column may declare `copyOf: { via, column }`: the server keeps it equal to `column` on the row the latest-row column `via` points at (same type, or text into text, cut to 140 characters in a STRING column; a copy of an encrypted column must be encrypted, and a copy cannot inheritAcl). Both are written only by the server, in the same write as the related row; a client value is ignored. A table may declare `constraints`, checked on every write for every client and refused as CONSTRAINT_VIOLATION: `unique` ({ columns, partitionColumns?, unlessRelated?: { relation, column } } — waived for rows whose related row has that yes/no column set), `no-overlap` ({ startColumn, endColumn, partitionColumns? }), `related-open` ({ relation, closedColumn } — no row is added, changed or removed while the related row's column is filled) and `related-index` ({ column, relation, listColumn } — the number must be a position in the related row's list). An upgrade adds a declared constraint to an existing table without judging the rows already in it.",
|
|
4169
|
+
"Optional. Tables the widget needs, seeded into the workspace at install time. Authors wire them into the widget's `tableRef` properties via the Properties Panel — the SDK does not auto-bind. Limits: 100 tables, 200 columns per table, 100 sample rows per table and 20000 sample cells across the whole template (each row counts the keys it sets, and at least one, summed over every table). RELATION columns address siblings by `targetSuffix` (any table in the same array, in any order; tables may relate to each other both ways). Tables persist across uninstalls. A `tableRef` property may also carry `sharedTable: true`, declaring that the table is the APP'S OWN — the author picks an existing table and the widget seeds nothing for it. That is the correct shape for a widget that reads data it does not own (a chart, a metric, a manager view over another widget's table). `sharedTable` exempts the property from needing a seeded table at publish (`manifest.requiredTableRefsHaveTemplate`) WITHOUT making it optional: the author must still bind one, and the host still refuses to place the widget unbound. Use it instead of dropping `required` — a widget that silently renders an empty tile is the defect it looks like a fix for. sc-7530: a table may also declare `roleGrants` — group-scoped access named SYMBOLICALLY, because a group id belongs to the workspace that installs the widget and could never travel in the manifest. Declare the audiences once at template level as `roles: [{ key, label, description? }]` (key is lowercase kebab, max 32 roles), then per table `roleGrants: [{ role, canRead?, canWrite?, canDelete? }]`. The installing workspace binds each role to one of its own user groups (or has one created) during the install consent step, so a permission model where an admin group does everything and signed-in users only read survives the trip between workspaces. Use `publicGrant` for the two id-less audiences (everyone / any signed-in user) and `roleGrants` for anything that names a group. A role nobody binds simply writes no grant — it never fails the install. sc-7557: a column may declare `encrypted: true` — its values are stored AES-256-GCM encrypted at rest under a per-workspace subkey. The widget still reads and writes PLAINTEXT (the platform encrypts on write, decrypts for end users); studio users see `🔒` instead, and the column cannot be searched, filtered or sorted on. Sample `rows` you seed for it are encrypted the same way. Not valid on `RELATION` — its value is a foreign key the backend must resolve — and publishing one is rejected. An `inheritAcl` RELATION column may add `inheritAclReadOnly: true` — rows then inherit READ access only, so members of the parent read every child and may add children, but change or delete only the rows they created (pair with `grantCreatorPermissions`). A column may declare `defaultValue`, written when a create omits it: `@currentUser` on USER, `@now` on DATE / DATETIME, `@uuid` on UUID (a new random id per row), or a literal of the column's own type (none on FILE, RELATION or USER_GROUP — ids belong to the installing workspace). `defaultLocked: true` on an `@currentUser` / `@now` / `@uuid` default makes the server always stamp it and ignore any client value on create and update, so an author column cannot be forged. `immutable: true` makes a column write-once: a create sets it as usual and any value sent for it on update is ignored (not valid on a MANY_TO_MANY relation). `paymentStatus: true` makes a STRING or BOOL column the table's payment status (at most one per table; not required, encrypted, immutable or defaulting to paid): a settled `requestPayment({ order: { table_id, record_id } })` for one of its rows writes it (`PAID`, or `true` on a BOOL; `REFUNDED` / `false` after a full refund), and every client value for it is ignored, so a buyer cannot mark their own order paid. A table may declare `presence: true` so the people who share a row see which of each other are online (useOnlineMembers); it takes effect only while the workspace records user activity, and an upgrade that declares it turns it on for the existing table. A table whose rows people join and leave through per-record grants (conversations) may declare `deleteWhenLastMemberLeaves: true`: when a signed-in member giving up their own grant leaves a row with no grant and no table-wide grant lets anyone read it, the row and every row a CASCADE relation ties to it (including rows deleted earlier) are deleted for good. A row that never had a grant (a seeded sample row) is never deleted this way, and a revoke made in the Studio never deletes. An upgrade that declares it turns it on for the existing table. A ONE_TO_ONE / ONE_TO_MANY RELATION may declare `latestVia: \"<relation column on its target that points back>\"` (onDelete left at SET_NULL; that relation must have inheritAcl and be immutable): the server keeps it at the newest row of the target table that points back at this row. A column may declare `copyOf: { via, column }`: the server keeps it equal to `column` on the row the latest-row column `via` points at (same type, or text into text, cut to 140 characters in a STRING column; a copy of an encrypted column must be encrypted, and a copy cannot inheritAcl). Both are written only by the server, in the same write as the related row; a client value is ignored. A table may declare `constraints`, checked on every write for every client and refused as CONSTRAINT_VIOLATION: `unique` ({ columns, partitionColumns?, unlessRelated?: { relation, column } } — waived for rows whose related row has that yes/no column set), `no-overlap` ({ startColumn, endColumn, partitionColumns? }), `related-open` ({ relation, closedColumn } — no row is added, changed or removed while the related row's column is filled) and `related-index` ({ column, relation, listColumn } — the number must be a position in the related row's list). An upgrade adds a declared constraint to an existing table without judging the rows already in it.",
|
|
4170
4170
|
},
|
|
4171
4171
|
translations: {
|
|
4172
4172
|
type: "object",
|
|
@@ -4467,7 +4467,7 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
4467
4467
|
},
|
|
4468
4468
|
payments: {
|
|
4469
4469
|
description:
|
|
4470
|
-
"Injected @colixsystems/payments-client instance (REQ-BILL-07-WIDGETPAY). { requestPayment(body) -> Promise<{ id, status }>, getPayment(id) -> Promise<payment>, listAccessPlans() -> Promise<{ data, meta }>, purchaseAccessPlan({ plan_id, return_path? }) -> Promise<{ plan_id, status }>, cancelAccessPlan(planId) -> Promise<{ plan_id, renews, access_ends_at }>, getAppSubscription() -> Promise<{ active, renews, access_ends_at }>, cancelAppSubscription() -> Promise<{ active, renews, access_ends_at }> }; wire is snake_case (amount_cents, return_path). Backs usePayments(), useAccessPlans() and useAppSubscription(); 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.",
|
|
4470
|
+
"Injected @colixsystems/payments-client instance (REQ-BILL-07-WIDGETPAY). { requestPayment(body) -> Promise<{ id, status }>, getPayment(id) -> Promise<payment>, listAccessPlans() -> Promise<{ data, meta }>, purchaseAccessPlan({ plan_id, return_path? }) -> Promise<{ plan_id, status }>, cancelAccessPlan(planId) -> Promise<{ plan_id, renews, access_ends_at }>, getAppSubscription() -> Promise<{ active, renews, access_ends_at }>, cancelAppSubscription() -> Promise<{ active, renews, access_ends_at }> }; wire is snake_case (amount_cents, return_path, order). Backs usePayments(), useAccessPlans() and useAppSubscription(); 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.",
|
|
4471
4471
|
required: true,
|
|
4472
4472
|
fields: {
|
|
4473
4473
|
requestPayment: "function",
|
|
@@ -6741,7 +6741,11 @@ const CONTRACT = deepFreeze({
|
|
|
6741
6741
|
// 1.235.0: additive (sc-15342) — `useAppSubscription()`, and the payments
|
|
6742
6742
|
// slice gains `getAppSubscription` / `cancelAppSubscription`: a paid
|
|
6743
6743
|
// app's subscriber cancels their own subscription.
|
|
6744
|
-
|
|
6744
|
+
// 1.236.0: additive (sc-15358) — `requestPayment` takes an optional
|
|
6745
|
+
// `order: { table_id, record_id }` the server marks paid on settlement,
|
|
6746
|
+
// a template column may declare `paymentStatus: true`, and four new
|
|
6747
|
+
// PaymentError codes.
|
|
6748
|
+
version: "1.236.0",
|
|
6745
6749
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
6746
6750
|
hooks: HOOKS,
|
|
6747
6751
|
primitives: PRIMITIVES,
|