@colixsystems/widget-sdk 0.180.1 → 0.181.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 +24 -5
- package/dist/contract.cjs +18 -5
- package/dist/contract.js +18 -5
- package/dist/index.d.ts +20 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ The data layer lives in **four separate domain-client packages**, each instantia
|
|
|
59
59
|
| **DIRECTORY** (`ctx.directory`) | `useDirectory(query)` (optional: query) | `{ users, loading, error, refetch }` | `directory.users.list` — `directory.read:users` |
|
|
60
60
|
| **DIRECTORY** | `useUsers(query)` (optional: query) | `{ users, loading, error, refetch, invite, deactivate, reactivate, remove, sendPasswordReset }` | `directory.users.*` — `users.read:*` plus the `users.read` (or `users.write`) capability, else `FORBIDDEN` (edits, incl. `sendPasswordReset()`, also `users.write:*`; `remove()` also `users.delete:*`) |
|
|
61
61
|
| **DIRECTORY** | `useGroups(query)` (optional: query) | `{ groups, loading, error, refetch, create, remove, addMember, removeMember }` | `directory.groups.*` — `groups.read:*` (mutations also `groups.write:*`) |
|
|
62
|
-
| **DIRECTORY** | `useInvites(query)` (optional: query) | `{ invites, loading, error, refetch, resend, revoke }` | `directory.invites.*` — `users.write:*` + the SystemAcl `users.write` capability (the whole invite surface, list included). `query` is `{ status?, limit?, offset? }` with `status` ∈ `pending \| accepted \| revoked \| expired \| all` (endpoint default `all`). |
|
|
62
|
+
| **DIRECTORY** | `useInvites(query)` (optional: query) | `{ invites, loading, error, refetch, resend, revoke }` | `directory.invites.*` — `users.write:*` + the SystemAcl `users.write` capability (the whole invite surface, list included). `query` is `{ status?, q?, app_user_id?, limit?, offset? }` with `status` ∈ `pending \| accepted \| revoked \| expired \| open \| all` (endpoint default `all`; `open` = `pending` or `expired`); `q` matches the invite's name or email, `app_user_id` returns the invites reserving that user id. |
|
|
63
63
|
| **DIRECTORY** | `useBankIdLink()` | `{ linked, available, status, qr, message, startLink, refresh, cancel, unlink, refetchStatus, … }` | `directory.bankid.*` — no scope (JWT-gated self-service) |
|
|
64
64
|
| **FILESTORE** (`ctx.filestore`) | `usePdfExport({ spaceType, folderId })` (optional: spaceType, folderId) | `{ openPdf, opening, canOpenPdf, exportToPdf, exporting, error, lastExported }` | `ctx.filestore.files.renderPdf` + `ctx.device.pdfViewer`, `ctx.filestore.files.exportPdf` — `files.write:*`. `openPdf(html, { fileName? })` renders the HTML to a PDF server-side and OPENS it (web: PDF tab; native: print / share sheet) without saving. `exportToPdf(html, { fileName?, folderId? })` renders it and saves it as a file (`application/pdf`). Same server-side renderer on web + native. |
|
|
65
65
|
| **PAYMENTS** (`ctx.payments`) | `usePayments()` | `{ requestPayment, getPayment }` | `ctx.payments.*` — `payments.charge:appUser`. Rejects with `PaymentError { code, message, retryable }`; when `retryable` is `false` show `message` and drop the retry. Charges are accepted ONLY in the currency the workspace sells in — omit `currency` and the platform applies it (a disagreeing literal is a publish-blocking `payment-currency` finding). |
|
|
@@ -74,7 +74,18 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
74
74
|
|
|
75
75
|
## Status
|
|
76
76
|
|
|
77
|
-
`v0.
|
|
77
|
+
`v0.181.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**.
|
|
78
|
+
|
|
79
|
+
### What's new in 0.181.0 (contract 1.142.0)
|
|
80
|
+
|
|
81
|
+
**A `USER` column can point at someone who has been invited but has not joined yet.** Every invite now reserves the id its invitee's user account will have, so a record can be assigned to that person straight away and nothing needs rewriting when they accept.
|
|
82
|
+
|
|
83
|
+
- **`useInvites()` rows carry `app_user_id`** — that reserved id. The `resend()` result carries it too.
|
|
84
|
+
- **`useInvites(query)` takes two more optional keys.** `q` is a case-insensitive substring match on the invite's name or email. `app_user_id` returns only the invites reserving that id, which is how a member-admin widget resolves the person behind a `USER` value before they have joined; an id no invite reserves returns no rows.
|
|
85
|
+
- **`status: 'open'`** is every invite that is neither accepted nor revoked — `pending` or `expired`. A re-invite keeps the reserved id, so `useInvites({ app_user_id, status: 'open' })` is the one invite that still reserves it.
|
|
86
|
+
- **A `USER` column has a third read shape.** A user of the workspace still reads as `{ id, name, email }` and an id that names nobody as `{ id, name: null }`. An invited person who has not joined reads as `{ id, name, invited: true }` — **with no `email`**, so render `name` and treat `email` as optional. Once they accept, the same id reads as an ordinary user and `invited` is gone.
|
|
87
|
+
|
|
88
|
+
Additive: no existing field changed shape, and the scope is unchanged (`users.write:*` plus the `users.write` capability for the whole invite surface).
|
|
78
89
|
|
|
79
90
|
### What's new in 0.180.1 (contract 1.141.0 — unchanged)
|
|
80
91
|
|
|
@@ -2114,9 +2125,17 @@ function PendingInvites() {
|
|
|
2114
2125
|
}
|
|
2115
2126
|
```
|
|
2116
2127
|
|
|
2117
|
-
Rows are snake_case: `{ id, email, name, group_ids, status, expires_at,
|
|
2118
|
-
revoked_at, created_at }`. Trust the server-computed `status` rather than
|
|
2119
|
-
`expires_at` against the device clock.
|
|
2128
|
+
Rows are snake_case: `{ id, app_user_id, email, name, group_ids, status, expires_at,
|
|
2129
|
+
accepted_at, revoked_at, created_at }`. Trust the server-computed `status` rather than
|
|
2130
|
+
comparing `expires_at` against the device clock.
|
|
2131
|
+
|
|
2132
|
+
`query` also takes `q` (a case-insensitive substring match on the invite's name or
|
|
2133
|
+
email) and `app_user_id`. Each row's `app_user_id` is the id the invitee's user account
|
|
2134
|
+
will have once they accept. A `USER` column may hold that id before the person has
|
|
2135
|
+
joined — it then reads back as `{ id, name, invited: true }`, with no `email` — and
|
|
2136
|
+
`useInvites({ app_user_id: value.id, status: 'open', limit: 1 })` returns the invite
|
|
2137
|
+
behind it. `status: 'open'` is every invite that is neither accepted nor revoked
|
|
2138
|
+
(`pending` or `expired`); a re-invite keeps the id, so without it earlier invites match too.
|
|
2120
2139
|
|
|
2121
2140
|
**The gate is `users.write`, not `users.read`.** A pending invite exposes the email of
|
|
2122
2141
|
someone who is not a member yet, so the backend gates the entire invite surface —
|
package/dist/contract.cjs
CHANGED
|
@@ -1787,9 +1787,18 @@ const HOOKS = [
|
|
|
1787
1787
|
"returns the { data, meta } envelope verbatim — the hook unwraps " +
|
|
1788
1788
|
"res.data; rows are snake_case (email, status, expires_at, …) and " +
|
|
1789
1789
|
"status is the server-computed pending/accepted/revoked/expired " +
|
|
1790
|
-
"value. query is { status?, limit?, offset? } passed
|
|
1791
|
-
"endpoint defaults to status 'all', so pass
|
|
1792
|
-
"for the usual outstanding-invite list
|
|
1790
|
+
"value. query is { status?, q?, app_user_id?, limit?, offset? } passed " +
|
|
1791
|
+
"verbatim; the endpoint defaults to status 'all', so pass " +
|
|
1792
|
+
"{ status: 'pending' } for the usual outstanding-invite list; " +
|
|
1793
|
+
"status 'open' is every invite neither accepted nor revoked (pending " +
|
|
1794
|
+
"or expired). q is a " +
|
|
1795
|
+
"case-insensitive substring match on the invite's name or email. " +
|
|
1796
|
+
"Each row's app_user_id is the id the invitee's user account will " +
|
|
1797
|
+
"have once they accept; a USER column may already hold it, and " +
|
|
1798
|
+
"{ app_user_id, status: 'open' } returns the invite behind such an id " +
|
|
1799
|
+
"(a re-invite keeps the id, so without the status earlier invites " +
|
|
1800
|
+
"match too; an id no invite reserves returns no rows). The WHOLE " +
|
|
1801
|
+
"invite surface — " +
|
|
1793
1802
|
"list included — is gated on users.write:* plus the users.write " +
|
|
1794
1803
|
"SystemAcl capability, because a pending invite exposes the email of " +
|
|
1795
1804
|
"someone who is not a member yet; a users.read-only caller cannot see " +
|
|
@@ -1799,7 +1808,7 @@ const HOOKS = [
|
|
|
1799
1808
|
"refetch on success.",
|
|
1800
1809
|
returnShape: {
|
|
1801
1810
|
invites:
|
|
1802
|
-
"Array<{ id, email, name, group_ids, status, expires_at, accepted_at, revoked_at, created_at }> // snake_case rows; unwrapped from { data, meta }",
|
|
1811
|
+
"Array<{ id, app_user_id, email, name, group_ids, status, expires_at, accepted_at, revoked_at, created_at }> // snake_case rows; unwrapped from { data, meta }",
|
|
1803
1812
|
loading: "boolean",
|
|
1804
1813
|
error: "DirectoryError | null // { code, message, retryable }",
|
|
1805
1814
|
refetch: "() => Promise<void>",
|
|
@@ -4767,7 +4776,11 @@ const CONTRACT = deepFreeze({
|
|
|
4767
4776
|
// 1.141.0: additive (sc-9346) — inside a section that paints its own fill,
|
|
4768
4777
|
// `theme.colors.backdrop` is that fill, and `<Button>` re-inks a variant
|
|
4769
4778
|
// colour that cannot be read against it by the rule its text follows.
|
|
4770
|
-
|
|
4779
|
+
// 1.142.0: additive (sc-9713) — `useInvites(query)` takes `q`,
|
|
4780
|
+
// `app_user_id` and `status: "open"`, and each invite row carries
|
|
4781
|
+
// `app_user_id`: the id the invitee's user account will have once they
|
|
4782
|
+
// accept.
|
|
4783
|
+
version: "1.142.0",
|
|
4771
4784
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
4772
4785
|
hooks: HOOKS,
|
|
4773
4786
|
primitives: PRIMITIVES,
|
package/dist/contract.js
CHANGED
|
@@ -1787,9 +1787,18 @@ const HOOKS = [
|
|
|
1787
1787
|
"returns the { data, meta } envelope verbatim — the hook unwraps " +
|
|
1788
1788
|
"res.data; rows are snake_case (email, status, expires_at, …) and " +
|
|
1789
1789
|
"status is the server-computed pending/accepted/revoked/expired " +
|
|
1790
|
-
"value. query is { status?, limit?, offset? } passed
|
|
1791
|
-
"endpoint defaults to status 'all', so pass
|
|
1792
|
-
"for the usual outstanding-invite list
|
|
1790
|
+
"value. query is { status?, q?, app_user_id?, limit?, offset? } passed " +
|
|
1791
|
+
"verbatim; the endpoint defaults to status 'all', so pass " +
|
|
1792
|
+
"{ status: 'pending' } for the usual outstanding-invite list; " +
|
|
1793
|
+
"status 'open' is every invite neither accepted nor revoked (pending " +
|
|
1794
|
+
"or expired). q is a " +
|
|
1795
|
+
"case-insensitive substring match on the invite's name or email. " +
|
|
1796
|
+
"Each row's app_user_id is the id the invitee's user account will " +
|
|
1797
|
+
"have once they accept; a USER column may already hold it, and " +
|
|
1798
|
+
"{ app_user_id, status: 'open' } returns the invite behind such an id " +
|
|
1799
|
+
"(a re-invite keeps the id, so without the status earlier invites " +
|
|
1800
|
+
"match too; an id no invite reserves returns no rows). The WHOLE " +
|
|
1801
|
+
"invite surface — " +
|
|
1793
1802
|
"list included — is gated on users.write:* plus the users.write " +
|
|
1794
1803
|
"SystemAcl capability, because a pending invite exposes the email of " +
|
|
1795
1804
|
"someone who is not a member yet; a users.read-only caller cannot see " +
|
|
@@ -1799,7 +1808,7 @@ const HOOKS = [
|
|
|
1799
1808
|
"refetch on success.",
|
|
1800
1809
|
returnShape: {
|
|
1801
1810
|
invites:
|
|
1802
|
-
"Array<{ id, email, name, group_ids, status, expires_at, accepted_at, revoked_at, created_at }> // snake_case rows; unwrapped from { data, meta }",
|
|
1811
|
+
"Array<{ id, app_user_id, email, name, group_ids, status, expires_at, accepted_at, revoked_at, created_at }> // snake_case rows; unwrapped from { data, meta }",
|
|
1803
1812
|
loading: "boolean",
|
|
1804
1813
|
error: "DirectoryError | null // { code, message, retryable }",
|
|
1805
1814
|
refetch: "() => Promise<void>",
|
|
@@ -4763,7 +4772,11 @@ const CONTRACT = deepFreeze({
|
|
|
4763
4772
|
// 1.141.0: additive (sc-9346) — inside a section that paints its own fill,
|
|
4764
4773
|
// `theme.colors.backdrop` is that fill, and `<Button>` re-inks a variant
|
|
4765
4774
|
// colour that cannot be read against it by the rule its text follows.
|
|
4766
|
-
|
|
4775
|
+
// 1.142.0: additive (sc-9713) — `useInvites(query)` takes `q`,
|
|
4776
|
+
// `app_user_id` and `status: "open"`, and each invite row carries
|
|
4777
|
+
// `app_user_id`: the id the invitee's user account will have once they
|
|
4778
|
+
// accept.
|
|
4779
|
+
version: "1.142.0",
|
|
4767
4780
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
4768
4781
|
hooks: HOOKS,
|
|
4769
4782
|
primitives: PRIMITIVES,
|
package/dist/index.d.ts
CHANGED
|
@@ -2185,6 +2185,12 @@ export type AppUserInviteStatus =
|
|
|
2185
2185
|
|
|
2186
2186
|
export interface AppUserInviteRow {
|
|
2187
2187
|
id: string;
|
|
2188
|
+
/**
|
|
2189
|
+
* The id the invitee's user account will have once they accept. On every
|
|
2190
|
+
* `useInvites()` row and the `resend()` result; `useUsers().invite()` does
|
|
2191
|
+
* not return it.
|
|
2192
|
+
*/
|
|
2193
|
+
app_user_id?: string;
|
|
2188
2194
|
email: string;
|
|
2189
2195
|
/** Server-computed lifecycle value — prefer it over re-deriving expiry. */
|
|
2190
2196
|
status: AppUserInviteStatus;
|
|
@@ -2258,8 +2264,20 @@ export function useGroups(query?: GroupsQuery): GroupsApi;
|
|
|
2258
2264
|
// sc-5097 — pending AppUser invite administration.
|
|
2259
2265
|
|
|
2260
2266
|
export interface InvitesQuery {
|
|
2261
|
-
/**
|
|
2262
|
-
|
|
2267
|
+
/**
|
|
2268
|
+
* Defaults to "all" server-side; pass "pending" for outstanding invites.
|
|
2269
|
+
* "open" is "pending" or "expired": neither accepted nor revoked.
|
|
2270
|
+
*/
|
|
2271
|
+
status?: AppUserInviteStatus | "open" | "all";
|
|
2272
|
+
/** Case-insensitive substring match on the invite's name or email. */
|
|
2273
|
+
q?: string;
|
|
2274
|
+
/**
|
|
2275
|
+
* Only the invites reserving this user id (a row's `app_user_id`) — resolves
|
|
2276
|
+
* the person behind an id a USER column holds before they have joined. A
|
|
2277
|
+
* re-invite keeps the id, so add `status: "open"` for the one that still
|
|
2278
|
+
* reserves it. An id no invite reserves returns no rows.
|
|
2279
|
+
*/
|
|
2280
|
+
app_user_id?: string;
|
|
2263
2281
|
limit?: number;
|
|
2264
2282
|
offset?: number;
|
|
2265
2283
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.181.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",
|