@proveanything/smartlinks 1.9.16 → 1.9.19

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.
@@ -1,4 +1,4 @@
1
- import type { AppCase, CreateCaseInput, UpdateCaseInput, AppendHistoryInput, CaseSummaryRequest, CaseSummaryResponse, CaseListQueryParams, AppThread, CreateThreadInput, UpdateThreadInput, ReplyInput, ThreadListQueryParams, AppRecord, CreateRecordInput, UpdateRecordInput, RecordListQueryParams, PaginatedResponse, AggregateRequest, AggregateResponse, RelatedResponse } from '../types/appObjects';
1
+ import type { AppCase, CreateCaseInput, UpdateCaseInput, AppendHistoryInput, CaseSummaryRequest, CaseSummaryResponse, CaseListQueryParams, AppThread, CreateThreadInput, UpdateThreadInput, ReplyInput, ThreadListQueryParams, AppRecord, CreateRecordInput, CreateRecordResponse, UpdateRecordInput, RecordListQueryParams, PaginatedResponse, AggregateRequest, AggregateResponse, RelatedResponse } from '../types/appObjects';
2
2
  export declare namespace app {
3
3
  namespace cases {
4
4
  /**
@@ -95,8 +95,15 @@ export declare namespace app {
95
95
  /**
96
96
  * Create a new record
97
97
  * POST /records
98
+ *
99
+ * When called on the public endpoint (admin = false) with an anonymous
100
+ * caller, and the app's `publicCreate.records.anonymous.edit.editToken`
101
+ * policy is enabled, the response includes a one-time `editToken` string.
102
+ * Store it immediately — it is never returned again.
103
+ *
104
+ * @see {@link updateWithToken} — use the edit token for a follow-up amendment
98
105
  */
99
- function create(collectionId: string, appId: string, input: CreateRecordInput, admin?: boolean): Promise<AppRecord>;
106
+ function create(collectionId: string, appId: string, input: CreateRecordInput, admin?: boolean): Promise<CreateRecordResponse>;
100
107
  /**
101
108
  * List records with optional query parameters
102
109
  * GET /records
@@ -113,6 +120,53 @@ export declare namespace app {
113
120
  * Admin can update any field, public (owner) can only update data and owner
114
121
  */
115
122
  function update(collectionId: string, appId: string, recordId: string, input: UpdateRecordInput, admin?: boolean): Promise<AppRecord>;
123
+ /**
124
+ * Amend the `data` zone of a record using an anonymous edit token.
125
+ * PATCH /records/:recordId (public endpoint, no auth)
126
+ *
127
+ * This is the follow-up call after an anonymous `create()` that returned an
128
+ * `editToken`. Present the token via `X-Edit-Token` — the server validates
129
+ * it with a constant-time comparison and, if `windowMinutes` is configured
130
+ * in the policy, checks that the token has not expired.
131
+ *
132
+ * **Scope:** only the `data` zone may be modified via this path.
133
+ * `owner`, `admin`, `status`, `visibility`, and indexed fields are
134
+ * immutable to anonymous token holders.
135
+ *
136
+ * @param collectionId - Collection the record belongs to
137
+ * @param appId - App the record belongs to
138
+ * @param recordId - ID of the record to amend
139
+ * @param data - New (full replacement) value for the `data` zone
140
+ * @param editToken - Token received from the original `create()` response
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * const record = await app.records.create(collectionId, appId, {
145
+ * recordType: 'payment',
146
+ * visibility: 'public',
147
+ * data: { amount: 9900, currency: 'USD' },
148
+ * })
149
+ * const { editToken } = record // store this immediately!
150
+ *
151
+ * // Later, once the payment gateway confirms:
152
+ * const updated = await app.records.updateWithToken(
153
+ * collectionId,
154
+ * appId,
155
+ * record.id,
156
+ * { amount: 9900, currency: 'USD', transactionId: 'txn_abc123' },
157
+ * editToken,
158
+ * )
159
+ * ```
160
+ *
161
+ * ### Error codes
162
+ * | HTTP | `errorCode` | Meaning |
163
+ * |------|-----------------------|---------------------------------------------------|
164
+ * | 401 | `UNAUTHORIZED` | No auth token and no `X-Edit-Token` header |
165
+ * | 403 | `FORBIDDEN` | Policy not enabled, or token does not match |
166
+ * | 403 | `EDIT_WINDOW_EXPIRED` | `windowMinutes` elapsed since record creation |
167
+ * | 404 | `NOT_FOUND` | Record does not exist |
168
+ */
169
+ function updateWithToken(collectionId: string, appId: string, recordId: string, data: Record<string, unknown>, editToken: string): Promise<AppRecord>;
116
170
  /**
117
171
  * Soft delete a record
118
172
  * DELETE /records/:recordId
@@ -187,6 +187,13 @@ export var app;
187
187
  /**
188
188
  * Create a new record
189
189
  * POST /records
190
+ *
191
+ * When called on the public endpoint (admin = false) with an anonymous
192
+ * caller, and the app's `publicCreate.records.anonymous.edit.editToken`
193
+ * policy is enabled, the response includes a one-time `editToken` string.
194
+ * Store it immediately — it is never returned again.
195
+ *
196
+ * @see {@link updateWithToken} — use the edit token for a follow-up amendment
190
197
  */
191
198
  async function create(collectionId, appId, input, admin = false) {
192
199
  const path = basePath(collectionId, appId, admin);
@@ -222,6 +229,57 @@ export var app;
222
229
  return patch(path, input);
223
230
  }
224
231
  records.update = update;
232
+ /**
233
+ * Amend the `data` zone of a record using an anonymous edit token.
234
+ * PATCH /records/:recordId (public endpoint, no auth)
235
+ *
236
+ * This is the follow-up call after an anonymous `create()` that returned an
237
+ * `editToken`. Present the token via `X-Edit-Token` — the server validates
238
+ * it with a constant-time comparison and, if `windowMinutes` is configured
239
+ * in the policy, checks that the token has not expired.
240
+ *
241
+ * **Scope:** only the `data` zone may be modified via this path.
242
+ * `owner`, `admin`, `status`, `visibility`, and indexed fields are
243
+ * immutable to anonymous token holders.
244
+ *
245
+ * @param collectionId - Collection the record belongs to
246
+ * @param appId - App the record belongs to
247
+ * @param recordId - ID of the record to amend
248
+ * @param data - New (full replacement) value for the `data` zone
249
+ * @param editToken - Token received from the original `create()` response
250
+ *
251
+ * @example
252
+ * ```ts
253
+ * const record = await app.records.create(collectionId, appId, {
254
+ * recordType: 'payment',
255
+ * visibility: 'public',
256
+ * data: { amount: 9900, currency: 'USD' },
257
+ * })
258
+ * const { editToken } = record // store this immediately!
259
+ *
260
+ * // Later, once the payment gateway confirms:
261
+ * const updated = await app.records.updateWithToken(
262
+ * collectionId,
263
+ * appId,
264
+ * record.id,
265
+ * { amount: 9900, currency: 'USD', transactionId: 'txn_abc123' },
266
+ * editToken,
267
+ * )
268
+ * ```
269
+ *
270
+ * ### Error codes
271
+ * | HTTP | `errorCode` | Meaning |
272
+ * |------|-----------------------|---------------------------------------------------|
273
+ * | 401 | `UNAUTHORIZED` | No auth token and no `X-Edit-Token` header |
274
+ * | 403 | `FORBIDDEN` | Policy not enabled, or token does not match |
275
+ * | 403 | `EDIT_WINDOW_EXPIRED` | `windowMinutes` elapsed since record creation |
276
+ * | 404 | `NOT_FOUND` | Record does not exist |
277
+ */
278
+ async function updateWithToken(collectionId, appId, recordId, data, editToken) {
279
+ const path = `${basePath(collectionId, appId, false)}/${encodeURIComponent(recordId)}`;
280
+ return patch(path, { data }, { 'X-Edit-Token': editToken });
281
+ }
282
+ records.updateWithToken = updateWithToken;
225
283
  /**
226
284
  * Soft delete a record
227
285
  * DELETE /records/:recordId
@@ -25,12 +25,12 @@ export var authKit;
25
25
  authKit.googleLogin = googleLogin;
26
26
  /** Send a magic link email to the user (public). */
27
27
  async function sendMagicLink(clientId, data) {
28
- return post(`/authkit/${encodeURIComponent(clientId)}/magic-link/send`, data);
28
+ return post(`/authkit/${encodeURIComponent(clientId)}/auth/magic-link/send`, data);
29
29
  }
30
30
  authKit.sendMagicLink = sendMagicLink;
31
31
  /** Verify a magic link token and authenticate/create the user (public). */
32
32
  async function verifyMagicLink(clientId, token) {
33
- const res = await post(`/authkit/${encodeURIComponent(clientId)}/magic-link/verify`, { token });
33
+ const res = await post(`/authkit/${encodeURIComponent(clientId)}/auth/magic-link/verify`, { token });
34
34
  if (res.token)
35
35
  setBearerToken(res.token);
36
36
  return res;
package/dist/api/http.js CHANGED
@@ -23,6 +23,10 @@
23
23
  // { collectionId, productId, appId, data }
24
24
  // )
25
25
  import { request as _get, post as _post, put as _put, patch as _patch, del as _del, } from '../http';
26
+ /** Ensure the path always starts with `/` so it concatenates correctly with baseURL. */
27
+ function normalizePath(path) {
28
+ return path.startsWith('/') ? path : `/${path}`;
29
+ }
26
30
  export var http;
27
31
  (function (http) {
28
32
  /**
@@ -36,7 +40,7 @@ export var http;
36
40
  * const fields = await http.get<FieldDefinition[]>('/public/config/fields')
37
41
  */
38
42
  async function get(path) {
39
- return _get(path);
43
+ return _get(normalizePath(path));
40
44
  }
41
45
  http.get = get;
42
46
  /**
@@ -56,7 +60,7 @@ export var http;
56
60
  * })
57
61
  */
58
62
  async function post(path, body) {
59
- return _post(path, body);
63
+ return _post(normalizePath(path), body);
60
64
  }
61
65
  http.post = post;
62
66
  /**
@@ -68,7 +72,7 @@ export var http;
68
72
  * @throws {SmartlinksApiError} on non-2xx responses
69
73
  */
70
74
  async function put(path, body) {
71
- return _put(path, body);
75
+ return _put(normalizePath(path), body);
72
76
  }
73
77
  http.put = put;
74
78
  /**
@@ -80,7 +84,7 @@ export var http;
80
84
  * @throws {SmartlinksApiError} on non-2xx responses
81
85
  */
82
86
  async function patch(path, body) {
83
- return _patch(path, body);
87
+ return _patch(normalizePath(path), body);
84
88
  }
85
89
  http.patch = patch;
86
90
  /**
@@ -91,7 +95,7 @@ export var http;
91
95
  * @throws {SmartlinksApiError} on non-2xx responses
92
96
  */
93
97
  async function del(path) {
94
- return _del(path);
98
+ return _del(normalizePath(path));
95
99
  }
96
100
  http.del = del;
97
101
  })(http || (http = {}));
@@ -0,0 +1,77 @@
1
+ import type { SmartLinksWidgetProps } from '../types';
2
+ /**
3
+ * Props for a SmartLinks container component.
4
+ *
5
+ * Extends {@link SmartLinksWidgetProps} with container-specific additions.
6
+ *
7
+ * ## Rendering modes
8
+ *
9
+ * Containers run in two modes, and props are the sole source of context in
10
+ * both:
11
+ *
12
+ * | Mode | How context arrives |
13
+ * |-------------------|--------------------------------------------------------|
14
+ * | Direct component | All props are passed directly by the parent platform |
15
+ * | Iframe fallback | Core params arrive via URL; `PublicPage` reads them |
16
+ * from search params when the equivalent prop is absent |
17
+ *
18
+ * ## Deep-link parameters (`dlParams`) in container mode
19
+ *
20
+ * When the parent platform resolves a deep link (e.g. from a scanned QR code,
21
+ * NFC tap, or shared URL), it **decodes** the link's `dlParams` payload and
22
+ * forwards each parameter as an explicit React prop — it does **not** append
23
+ * them to the browser URL.
24
+ *
25
+ * App-specific params (e.g. `preselectedAmount`, `voucherId`, `campaignSlug`)
26
+ * should therefore be declared as optional props directly on this interface.
27
+ * The parent guarantees that any param present in the `dlParams` payload will
28
+ * arrive as the corresponding named prop.
29
+ *
30
+ * ### PublicPage priority order
31
+ *
32
+ * `PublicPage` (and pages derived from it) **must** resolve app-specific params
33
+ * in the following priority order so the component works correctly in both
34
+ * rendering modes:
35
+ *
36
+ * ```
37
+ * 1. Prop value (set by parent in container / direct-component mode)
38
+ * 2. React Router search param (useSearchParams) in MemoryRouter
39
+ * 3. Raw URL search param (window.location) — iframe-mode fallback
40
+ * ```
41
+ *
42
+ * Example hook:
43
+ *
44
+ * ```ts
45
+ * function usePreselectedAmount(
46
+ * propValue: string | undefined,
47
+ * ): string | undefined {
48
+ * const [searchParams] = useSearchParams()
49
+ * return (
50
+ * propValue ??
51
+ * searchParams.get('preselectedAmount') ??
52
+ * new URLSearchParams(window.location.search).get('preselectedAmount') ??
53
+ * undefined
54
+ * )
55
+ * }
56
+ * ```
57
+ *
58
+ * @see docs/smartlinks/routing-guide.md — full pattern documentation
59
+ * @see docs/containers.md — container architecture overview
60
+ */
61
+ export interface SmartLinksContainerProps extends SmartLinksWidgetProps {
62
+ /**
63
+ * Optional CSS class applied to the outermost wrapper element rendered by
64
+ * the framework around this container.
65
+ */
66
+ className?: string;
67
+ /**
68
+ * Initial route path to navigate to inside the container's MemoryRouter.
69
+ *
70
+ * The framework sets the MemoryRouter's `initialEntries` from this value
71
+ * when present. Useful for deep links that target a specific page within
72
+ * the container (e.g. `'/loyalty/redeem'`).
73
+ *
74
+ * In iframe mode the equivalent is the `pageId` URL search parameter.
75
+ */
76
+ initialPath?: string;
77
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.9.16 | Generated: 2026-04-13T17:25:57.673Z
3
+ Version: 1.9.19 | Generated: 2026-04-16T12:41:11.180Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -1957,22 +1957,51 @@ interface RelatedResponse {
1957
1957
  **PublicCreatePolicy** (interface)
1958
1958
  ```typescript
1959
1959
  interface PublicCreatePolicy {
1960
- cases?: PublicCreateRule
1961
- threads?: PublicCreateRule
1962
- records?: PublicCreateRule
1960
+ cases?: PublicCreateObjectRule
1961
+ threads?: PublicCreateObjectRule
1962
+ records?: PublicCreateObjectRule
1963
1963
  }
1964
1964
  ```
1965
1965
 
1966
- **PublicCreateRule** (interface)
1966
+ **PublicCreateObjectRule** (interface)
1967
1967
  ```typescript
1968
- interface PublicCreateRule {
1969
- allow: {
1970
- anonymous?: boolean
1971
- authenticated?: boolean
1972
- }
1968
+ interface PublicCreateObjectRule {
1969
+ anonymous?: PublicCreateBranch
1970
+ authenticated?: PublicCreateBranch
1971
+ }
1972
+ ```
1973
+
1974
+ **PublicCreateBranch** (interface)
1975
+ ```typescript
1976
+ interface PublicCreateBranch {
1977
+ allow: boolean
1978
+ * Field values merged **over** the caller's request body before writing.
1979
+ * Use this to lock down `visibility` and `status` regardless of what the
1980
+ * client sends.
1973
1981
  enforce?: {
1974
- anonymous?: Partial<CreateCaseInput | CreateThreadInput | CreateRecordInput>
1975
- authenticated?: Partial<CreateCaseInput | CreateThreadInput | CreateRecordInput>
1982
+ visibility?: 'public' | 'owner' | 'admin'
1983
+ status?: string
1984
+ }
1985
+ * Anonymous edit-token configuration.
1986
+ * **Records only** — ignored for cases and threads.
1987
+ *
1988
+ * When `editToken: true`, the server generates a one-time 256-bit hex token
1989
+ * on anonymous record creation, stores it in `admin.editToken` (never
1990
+ * exposed to public / owner responses), and returns it **once** in the
1991
+ * creation response under the `editToken` key.
1992
+ *
1993
+ * The client can then pass that token as the `X-Edit-Token` header on
1994
+ * `PATCH /records/:recordId` to amend the `data` zone without
1995
+ * authentication.
1996
+ *
1997
+ * @see {@link CreateRecordResponse} — creation response shape
1998
+ * @see {@link records.updateWithToken} — SDK method for the amendment call
1999
+ edit?: {
2000
+ editToken: boolean
2001
+ * Optional expiry window in minutes from `createdAt`.
2002
+ * After this many minutes the token is rejected with HTTP 403
2003
+ * `EDIT_WINDOW_EXPIRED`. Omit for no expiry.
2004
+ windowMinutes?: number
1976
2005
  }
1977
2006
  }
1978
2007
  ```
@@ -6654,6 +6683,46 @@ interface TranslationUpdateRequest {
6654
6683
 
6655
6684
  **VariantUpdateRequest** = `any`
6656
6685
 
6686
+ ### widgets
6687
+
6688
+ **NavigationRequest** (interface)
6689
+ ```typescript
6690
+ interface NavigationRequest {
6691
+ appId: string
6692
+ deepLink?: string
6693
+ params?: Record<string, string>
6694
+ productId?: string
6695
+ proofId?: string
6696
+ }
6697
+ ```
6698
+
6699
+ **SmartLinksWidgetProps** (interface)
6700
+ ```typescript
6701
+ interface SmartLinksWidgetProps {
6702
+ collectionId: string
6703
+ appId: string
6704
+ productId?: string
6705
+ proofId?: string
6706
+ user?: {
6707
+ id?: string
6708
+ email?: string
6709
+ name?: string
6710
+ admin?: boolean
6711
+ }
6712
+ * Pre-initialised SmartLinks SDK instance provided by the parent platform.
6713
+ * At runtime this is `typeof import('@proveanything/smartlinks')`.
6714
+ SL: Record<string, unknown>
6715
+ * Navigation callback. Emit a `NavigationRequest` to ask the parent
6716
+ * platform to navigate to another app. A legacy plain-string path is also
6717
+ * accepted for backward compatibility.
6718
+ onNavigate?: (request: NavigationRequest | string) => void
6719
+ publicPortalUrl?: string
6720
+ size?: 'compact' | 'standard' | 'large'
6721
+ lang?: string
6722
+ translations?: Record<string, string>
6723
+ }
6724
+ ```
6725
+
6657
6726
  ### appConfiguration (api)
6658
6727
 
6659
6728
  **AppConfigOptions** (type)
@@ -7024,8 +7093,8 @@ General-purpose structured app objects. Use these when a simple scoped data item
7024
7093
  **create**(collectionId: string,
7025
7094
  appId: string,
7026
7095
  input: CreateRecordInput,
7027
- admin: boolean = false) → `Promise<AppRecord>`
7028
- Create a new record POST /records
7096
+ admin: boolean = false) → `Promise<CreateRecordResponse>`
7097
+ Create a new record POST /records When called on the public endpoint (admin = false) with an anonymous caller, and the app's `publicCreate.records.anonymous.edit.editToken` policy is enabled, the response includes a one-time `editToken` string. Store it immediately — it is never returned again.
7029
7098
 
7030
7099
  **list**(collectionId: string,
7031
7100
  appId: string,
@@ -7046,6 +7115,13 @@ Get a single record by ID GET /records/:recordId
7046
7115
  admin: boolean = false) → `Promise<AppRecord>`
7047
7116
  Update a record PATCH /records/:recordId Admin can update any field, public (owner) can only update data and owner
7048
7117
 
7118
+ **updateWithToken**(collectionId: string,
7119
+ appId: string,
7120
+ recordId: string,
7121
+ data: Record<string, unknown>,
7122
+ editToken: string) → `Promise<AppRecord>`
7123
+ Amend the `data` zone of a record using an anonymous edit token. PATCH /records/:recordId (public endpoint, no auth) This is the follow-up call after an anonymous `create()` that returned an `editToken`. Present the token via `X-Edit-Token` — the server validates it with a constant-time comparison and, if `windowMinutes` is configured in the policy, checks that the token has not expired. **Scope:** only the `data` zone may be modified via this path. `owner`, `admin`, `status`, `visibility`, and indexed fields are immutable to anonymous token holders. ```ts const record = await app.records.create(collectionId, appId, { recordType: 'payment', visibility: 'public', data: { amount: 9900, currency: 'USD' }, }) const { editToken } = record // store this immediately! // Later, once the payment gateway confirms: const updated = await app.records.updateWithToken( collectionId, appId, record.id, { amount: 9900, currency: 'USD', transactionId: 'txn_abc123' }, editToken, ) ``` ### Error codes | HTTP | `errorCode` | Meaning | |------|-----------------------|---------------------------------------------------| | 401 | `UNAUTHORIZED` | No auth token and no `X-Edit-Token` header | | 403 | `FORBIDDEN` | Policy not enabled, or token does not match | | 403 | `EDIT_WINDOW_EXPIRED` | `windowMinutes` elapsed since record creation | | 404 | `NOT_FOUND` | Record does not exist |
7124
+
7049
7125
  **remove**(collectionId: string,
7050
7126
  appId: string,
7051
7127
  recordId: string,