@proveanything/smartlinks 1.16.0 → 1.16.2
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/dist/api/lots.d.ts +17 -4
- package/dist/api/lots.js +24 -7
- package/dist/api/proof.d.ts +22 -1
- package/dist/api/proof.js +25 -0
- package/dist/docs/API_SUMMARY.md +75 -17
- package/dist/docs/lots.md +19 -2
- package/dist/docs/proof-product-data-scoping.md +5 -2
- package/dist/openapi.yaml +137 -4
- package/dist/types/batch.d.ts +18 -7
- package/dist/types/lots.d.ts +4 -0
- package/dist/types/proof.d.ts +26 -1
- package/dist/types/variant.d.ts +26 -5
- package/dist/utils/paths.js +3 -7
- package/docs/API_SUMMARY.md +75 -17
- package/docs/lots.md +19 -2
- package/docs/proof-product-data-scoping.md +5 -2
- package/openapi.yaml +137 -4
- package/package.json +1 -1
package/dist/api/lots.d.ts
CHANGED
|
@@ -10,16 +10,29 @@ export declare namespace lots {
|
|
|
10
10
|
function create(collectionId: string, lot: LotCreateInput): Promise<Lot>;
|
|
11
11
|
/** List lots (summary rows; `payload`/`productIds` omitted). Filter by status, search, or containing productId. */
|
|
12
12
|
function list(collectionId: string, params?: ListLotsParams): Promise<Lot[]>;
|
|
13
|
-
/** Get the full lot record. */
|
|
14
|
-
function get(collectionId: string, lotId: string
|
|
13
|
+
/** Get the full lot record. Pass `{ includeDeleted: true }` to fetch a soft-deleted one. */
|
|
14
|
+
function get(collectionId: string, lotId: string, opts?: {
|
|
15
|
+
includeDeleted?: boolean;
|
|
16
|
+
}): Promise<Lot>;
|
|
15
17
|
/** Look up a lot by its number (case-insensitive) — used by scan/resolver flows. */
|
|
16
|
-
function getByNumber(collectionId: string, lotNumber: string
|
|
18
|
+
function getByNumber(collectionId: string, lotNumber: string, opts?: {
|
|
19
|
+
includeDeleted?: boolean;
|
|
20
|
+
}): Promise<Lot>;
|
|
17
21
|
/** Update a lot. Re-resolves members if the selector changed (response then carries `diff`). */
|
|
18
22
|
function update(collectionId: string, lotId: string, lot: LotUpdateInput): Promise<Lot>;
|
|
19
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Soft-delete a lot — recoverable, and frees its `lotNumber` for reuse. Distinct from
|
|
25
|
+
* {@link archive}. Hidden from reads unless `{ includeDeleted: true }`; undo with {@link restore}.
|
|
26
|
+
*/
|
|
27
|
+
function remove(collectionId: string, lotId: string): Promise<{
|
|
28
|
+
success: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
/** Archive a lot — a live lifecycle state (stays visible, keeps its number). Not a delete. */
|
|
20
31
|
function archive(collectionId: string, lotId: string): Promise<{
|
|
21
32
|
success: boolean;
|
|
22
33
|
}>;
|
|
34
|
+
/** Restore a soft-deleted lot. Rejects (409) if a live lot now uses the same number. */
|
|
35
|
+
function restore(collectionId: string, lotId: string): Promise<Lot>;
|
|
23
36
|
/** Re-resolve members from the current selector; returns the lot + a member diff. */
|
|
24
37
|
function resolve(collectionId: string, lotId: string): Promise<ResolveLotResponse>;
|
|
25
38
|
/** Paginated member product summaries. */
|
package/dist/api/lots.js
CHANGED
|
@@ -22,6 +22,8 @@ export var lots;
|
|
|
22
22
|
qs.append('search', params.search);
|
|
23
23
|
if (params.productId)
|
|
24
24
|
qs.append('productId', params.productId);
|
|
25
|
+
if (params.includeDeleted)
|
|
26
|
+
qs.append('includeDeleted', 'true');
|
|
25
27
|
const s = qs.toString();
|
|
26
28
|
return s ? `?${s}` : '';
|
|
27
29
|
}
|
|
@@ -46,14 +48,16 @@ export var lots;
|
|
|
46
48
|
return res.lots;
|
|
47
49
|
}
|
|
48
50
|
lots.list = list;
|
|
49
|
-
/** Get the full lot record. */
|
|
50
|
-
async function get(collectionId, lotId) {
|
|
51
|
-
|
|
51
|
+
/** Get the full lot record. Pass `{ includeDeleted: true }` to fetch a soft-deleted one. */
|
|
52
|
+
async function get(collectionId, lotId, opts = {}) {
|
|
53
|
+
const qs = opts.includeDeleted ? '?includeDeleted=true' : '';
|
|
54
|
+
return request(`${adminBase(collectionId)}/${encodeURIComponent(lotId)}${qs}`);
|
|
52
55
|
}
|
|
53
56
|
lots.get = get;
|
|
54
57
|
/** Look up a lot by its number (case-insensitive) — used by scan/resolver flows. */
|
|
55
|
-
async function getByNumber(collectionId, lotNumber) {
|
|
56
|
-
|
|
58
|
+
async function getByNumber(collectionId, lotNumber, opts = {}) {
|
|
59
|
+
const qs = opts.includeDeleted ? '?includeDeleted=true' : '';
|
|
60
|
+
return request(`${adminBase(collectionId)}/by-number/${encodeURIComponent(lotNumber)}${qs}`);
|
|
57
61
|
}
|
|
58
62
|
lots.getByNumber = getByNumber;
|
|
59
63
|
/** Update a lot. Re-resolves members if the selector changed (response then carries `diff`). */
|
|
@@ -61,11 +65,24 @@ export var lots;
|
|
|
61
65
|
return put(`${adminBase(collectionId)}/${encodeURIComponent(lotId)}`, lot);
|
|
62
66
|
}
|
|
63
67
|
lots.update = update;
|
|
64
|
-
/**
|
|
65
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Soft-delete a lot — recoverable, and frees its `lotNumber` for reuse. Distinct from
|
|
70
|
+
* {@link archive}. Hidden from reads unless `{ includeDeleted: true }`; undo with {@link restore}.
|
|
71
|
+
*/
|
|
72
|
+
async function remove(collectionId, lotId) {
|
|
66
73
|
return del(`${adminBase(collectionId)}/${encodeURIComponent(lotId)}`);
|
|
67
74
|
}
|
|
75
|
+
lots.remove = remove;
|
|
76
|
+
/** Archive a lot — a live lifecycle state (stays visible, keeps its number). Not a delete. */
|
|
77
|
+
async function archive(collectionId, lotId) {
|
|
78
|
+
return post(`${adminBase(collectionId)}/${encodeURIComponent(lotId)}/archive`, {});
|
|
79
|
+
}
|
|
68
80
|
lots.archive = archive;
|
|
81
|
+
/** Restore a soft-deleted lot. Rejects (409) if a live lot now uses the same number. */
|
|
82
|
+
async function restore(collectionId, lotId) {
|
|
83
|
+
return post(`${adminBase(collectionId)}/${encodeURIComponent(lotId)}/restore`, {});
|
|
84
|
+
}
|
|
85
|
+
lots.restore = restore;
|
|
69
86
|
/** Re-resolve members from the current selector; returns the lot + a member diff. */
|
|
70
87
|
async function resolve(collectionId, lotId) {
|
|
71
88
|
return post(`${adminBase(collectionId)}/${encodeURIComponent(lotId)}/resolve`, {});
|
package/dist/api/proof.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ProofResponse, ProofCreateRequest, ProofUpdateRequest, ProofClaimRequest, ProofGrant, CreateGrantOptions, RedeemGrantOptions, RedeemGrantResult, ProofTransfer, TransferProofOptions, TransferProofResult } from "../types/proof";
|
|
1
|
+
import { ProofResponse, ProofCreateRequest, ProofUpdateRequest, ProofValuesUpdateRequest, ProofClaimRequest, ProofGrant, CreateGrantOptions, RedeemGrantOptions, RedeemGrantResult, ProofTransfer, TransferProofOptions, TransferProofResult } from "../types/proof";
|
|
2
2
|
export declare namespace proof {
|
|
3
3
|
/**
|
|
4
4
|
* Retrieves a single Proof by Collection ID, Product ID, and Proof ID.
|
|
@@ -42,6 +42,27 @@ export declare namespace proof {
|
|
|
42
42
|
* Object zones deep-merge, so you can change one field without wiping the rest.
|
|
43
43
|
*/
|
|
44
44
|
function update(collectionId: string, productId: string, proofId: string, values: ProofUpdateRequest): Promise<ProofResponse>;
|
|
45
|
+
/**
|
|
46
|
+
* Owner self-service update of a proof's owner-writable data.
|
|
47
|
+
* PUT /public/collection/:collectionId/product/:productId/proof/:proofId/values
|
|
48
|
+
*
|
|
49
|
+
* The public counterpart to admin `update` — the current OWNER (or a collection
|
|
50
|
+
* admin) editing their own proof, no admin credentials required. Only owner-writable
|
|
51
|
+
* zones are honoured (see {@link ProofValuesUpdateRequest}):
|
|
52
|
+
* ```ts
|
|
53
|
+
* proof.updateValues(collectionId, productId, proofId, {
|
|
54
|
+
* colour: 'blue', // → proof.values.colour (public)
|
|
55
|
+
* owner: { warranty: '2y' }, // → proof.values.owner (owner-scoped)
|
|
56
|
+
* personal: { nickname: 'Bo' }, // → proof.values.personal[callerUid] (private, own slot only)
|
|
57
|
+
* })
|
|
58
|
+
* ```
|
|
59
|
+
* `personal` always targets the caller's OWN slot — you cannot write another
|
|
60
|
+
* user's personal data, even as an admin. Object zones deep-merge (owner/personal
|
|
61
|
+
* merge field-by-field), so you can change one field without wiping the rest.
|
|
62
|
+
* Business-only zones (`data`/`admin`/`private`) are not writable here — use the
|
|
63
|
+
* admin `update` for those.
|
|
64
|
+
*/
|
|
65
|
+
function updateValues(collectionId: string, productId: string, proofId: string, values: ProofValuesUpdateRequest): Promise<ProofResponse>;
|
|
45
66
|
/**
|
|
46
67
|
* Claim a proof for a product using a proof ID (serial number, NFC tag, etc.).
|
|
47
68
|
* PUT /public/collection/:collectionId/product/:productId/proof/:proofId/claim
|
package/dist/api/proof.js
CHANGED
|
@@ -64,6 +64,31 @@ export var proof;
|
|
|
64
64
|
return put(path, values);
|
|
65
65
|
}
|
|
66
66
|
proof.update = update;
|
|
67
|
+
/**
|
|
68
|
+
* Owner self-service update of a proof's owner-writable data.
|
|
69
|
+
* PUT /public/collection/:collectionId/product/:productId/proof/:proofId/values
|
|
70
|
+
*
|
|
71
|
+
* The public counterpart to admin `update` — the current OWNER (or a collection
|
|
72
|
+
* admin) editing their own proof, no admin credentials required. Only owner-writable
|
|
73
|
+
* zones are honoured (see {@link ProofValuesUpdateRequest}):
|
|
74
|
+
* ```ts
|
|
75
|
+
* proof.updateValues(collectionId, productId, proofId, {
|
|
76
|
+
* colour: 'blue', // → proof.values.colour (public)
|
|
77
|
+
* owner: { warranty: '2y' }, // → proof.values.owner (owner-scoped)
|
|
78
|
+
* personal: { nickname: 'Bo' }, // → proof.values.personal[callerUid] (private, own slot only)
|
|
79
|
+
* })
|
|
80
|
+
* ```
|
|
81
|
+
* `personal` always targets the caller's OWN slot — you cannot write another
|
|
82
|
+
* user's personal data, even as an admin. Object zones deep-merge (owner/personal
|
|
83
|
+
* merge field-by-field), so you can change one field without wiping the rest.
|
|
84
|
+
* Business-only zones (`data`/`admin`/`private`) are not writable here — use the
|
|
85
|
+
* admin `update` for those.
|
|
86
|
+
*/
|
|
87
|
+
async function updateValues(collectionId, productId, proofId, values) {
|
|
88
|
+
const path = `/public/collection/${encodeURIComponent(collectionId)}/product/${encodeURIComponent(productId)}/proof/${encodeURIComponent(proofId)}/values`;
|
|
89
|
+
return put(path, values);
|
|
90
|
+
}
|
|
91
|
+
proof.updateValues = updateValues;
|
|
67
92
|
/**
|
|
68
93
|
* Claim a proof for a product using a proof ID (serial number, NFC tag, etc.).
|
|
69
94
|
* PUT /public/collection/:collectionId/product/:productId/proof/:proofId/claim
|
package/dist/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.16.
|
|
3
|
+
Version: 1.16.2 | Generated: 2026-09-05T10:46:06.239Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -3549,20 +3549,25 @@ interface FirebaseTimestamp {
|
|
|
3549
3549
|
```typescript
|
|
3550
3550
|
interface BatchResponse {
|
|
3551
3551
|
id: string // Batch ID
|
|
3552
|
-
name?: string
|
|
3553
|
-
expiryDate?:
|
|
3554
|
-
productId?: string // Product ID
|
|
3552
|
+
name?: string | null // Batch name
|
|
3553
|
+
expiryDate?: string | null
|
|
3554
|
+
productId?: string // Product ID
|
|
3555
3555
|
collectionId?: string // Collection ID
|
|
3556
|
-
|
|
3556
|
+
createdAt?: string // ISO 8601
|
|
3557
|
+
updatedAt?: string // ISO 8601
|
|
3558
|
+
deleted?: boolean
|
|
3559
|
+
deletedAt?: string // ISO 8601
|
|
3560
|
+
admin?: Record<string, any>
|
|
3561
|
+
[key: string]: any // Additional (schemaless) batch fields
|
|
3557
3562
|
}
|
|
3558
3563
|
```
|
|
3559
3564
|
|
|
3560
3565
|
**BatchCreateRequest** (interface)
|
|
3561
3566
|
```typescript
|
|
3562
3567
|
interface BatchCreateRequest {
|
|
3563
|
-
id
|
|
3564
|
-
name?: string
|
|
3565
|
-
expiryDate?: FirebaseTimestamp | string
|
|
3568
|
+
id?: string
|
|
3569
|
+
name?: string
|
|
3570
|
+
expiryDate?: FirebaseTimestamp | string | Date
|
|
3566
3571
|
[key: string]: any // Additional batch fields
|
|
3567
3572
|
}
|
|
3568
3573
|
```
|
|
@@ -3570,8 +3575,8 @@ interface BatchCreateRequest {
|
|
|
3570
3575
|
**BatchUpdateRequest** (interface)
|
|
3571
3576
|
```typescript
|
|
3572
3577
|
interface BatchUpdateRequest {
|
|
3573
|
-
name?: string
|
|
3574
|
-
expiryDate?: FirebaseTimestamp | string
|
|
3578
|
+
name?: string
|
|
3579
|
+
expiryDate?: FirebaseTimestamp | string | Date
|
|
3575
3580
|
[key: string]: any // Additional batch fields
|
|
3576
3581
|
}
|
|
3577
3582
|
```
|
|
@@ -6389,6 +6394,7 @@ interface Lot {
|
|
|
6389
6394
|
updatedBy?: string | null
|
|
6390
6395
|
createdAt: string
|
|
6391
6396
|
updatedAt: string
|
|
6397
|
+
deletedAt?: string | null
|
|
6392
6398
|
}
|
|
6393
6399
|
```
|
|
6394
6400
|
|
|
@@ -6412,6 +6418,7 @@ interface ListLotsParams {
|
|
|
6412
6418
|
status?: LotStatus
|
|
6413
6419
|
search?: string
|
|
6414
6420
|
productId?: string
|
|
6421
|
+
includeDeleted?: boolean
|
|
6415
6422
|
}
|
|
6416
6423
|
```
|
|
6417
6424
|
|
|
@@ -7431,6 +7438,9 @@ interface ProductFieldsConfig {
|
|
|
7431
7438
|
```typescript
|
|
7432
7439
|
interface ProofValues {
|
|
7433
7440
|
[key: string]: JsonValue | Record<string, JsonValue> | Record<string, Record<string, JsonValue>> | undefined
|
|
7441
|
+
* Owner-scoped: read/write by business + current owner; transfers with ownership.
|
|
7442
|
+
* Read exception: while the proof is `claimable`, this bag is also readable by everyone
|
|
7443
|
+
* (so a prospective claimer sees pre-set owner data); it reverts to owner-only once claimed.
|
|
7434
7444
|
owner?: Record<string, JsonValue>
|
|
7435
7445
|
personal?: Record<string, Record<string, JsonValue>>
|
|
7436
7446
|
}
|
|
@@ -7489,6 +7499,15 @@ interface ProofCreateRequest {
|
|
|
7489
7499
|
}
|
|
7490
7500
|
```
|
|
7491
7501
|
|
|
7502
|
+
**ProofValuesUpdateRequest** (interface)
|
|
7503
|
+
```typescript
|
|
7504
|
+
interface ProofValuesUpdateRequest {
|
|
7505
|
+
[key: string]: JsonValue | Record<string, JsonValue> | undefined
|
|
7506
|
+
owner?: Record<string, JsonValue>
|
|
7507
|
+
personal?: Record<string, JsonValue>
|
|
7508
|
+
}
|
|
7509
|
+
```
|
|
7510
|
+
|
|
7492
7511
|
**ProofFieldsConfig** (interface)
|
|
7493
7512
|
```typescript
|
|
7494
7513
|
interface ProofFieldsConfig {
|
|
@@ -8151,11 +8170,38 @@ interface TranslationUpdateRequest {
|
|
|
8151
8170
|
|
|
8152
8171
|
### variant
|
|
8153
8172
|
|
|
8154
|
-
**VariantResponse**
|
|
8173
|
+
**VariantResponse** (interface)
|
|
8174
|
+
```typescript
|
|
8175
|
+
interface VariantResponse {
|
|
8176
|
+
id: string
|
|
8177
|
+
name?: string | null
|
|
8178
|
+
productId?: string
|
|
8179
|
+
collectionId?: string
|
|
8180
|
+
createdAt?: string // ISO 8601
|
|
8181
|
+
updatedAt?: string // ISO 8601
|
|
8182
|
+
deleted?: boolean
|
|
8183
|
+
deletedAt?: string // ISO 8601
|
|
8184
|
+
admin?: Record<string, any>
|
|
8185
|
+
[key: string]: any // Additional (schemaless) variant fields
|
|
8186
|
+
}
|
|
8187
|
+
```
|
|
8155
8188
|
|
|
8156
|
-
**VariantCreateRequest**
|
|
8189
|
+
**VariantCreateRequest** (interface)
|
|
8190
|
+
```typescript
|
|
8191
|
+
interface VariantCreateRequest {
|
|
8192
|
+
id?: string
|
|
8193
|
+
name?: string
|
|
8194
|
+
[key: string]: any
|
|
8195
|
+
}
|
|
8196
|
+
```
|
|
8157
8197
|
|
|
8158
|
-
**VariantUpdateRequest**
|
|
8198
|
+
**VariantUpdateRequest** (interface)
|
|
8199
|
+
```typescript
|
|
8200
|
+
interface VariantUpdateRequest {
|
|
8201
|
+
name?: string
|
|
8202
|
+
[key: string]: any
|
|
8203
|
+
}
|
|
8204
|
+
```
|
|
8159
8205
|
|
|
8160
8206
|
### widgets
|
|
8161
8207
|
|
|
@@ -9898,17 +9944,23 @@ Create a lot (resolves its selector into members).
|
|
|
9898
9944
|
**list**(collectionId: string, params: ListLotsParams = {}) → `Promise<Lot[]>`
|
|
9899
9945
|
List lots (summary rows; `payload`/`productIds` omitted). Filter by status, search, or containing productId.
|
|
9900
9946
|
|
|
9901
|
-
**get**(collectionId: string, lotId: string) → `Promise<Lot>`
|
|
9902
|
-
Get the full lot record.
|
|
9947
|
+
**get**(collectionId: string, lotId: string, opts: { includeDeleted?: boolean } = {}) → `Promise<Lot>`
|
|
9948
|
+
Get the full lot record. Pass `{ includeDeleted: true }` to fetch a soft-deleted one.
|
|
9903
9949
|
|
|
9904
|
-
**getByNumber**(collectionId: string, lotNumber: string) → `Promise<Lot>`
|
|
9950
|
+
**getByNumber**(collectionId: string, lotNumber: string, opts: { includeDeleted?: boolean } = {}) → `Promise<Lot>`
|
|
9905
9951
|
Look up a lot by its number (case-insensitive) — used by scan/resolver flows.
|
|
9906
9952
|
|
|
9907
9953
|
**update**(collectionId: string, lotId: string, lot: LotUpdateInput) → `Promise<Lot>`
|
|
9908
9954
|
Update a lot. Re-resolves members if the selector changed (response then carries `diff`).
|
|
9909
9955
|
|
|
9956
|
+
**remove**(collectionId: string, lotId: string) → `Promise<`
|
|
9957
|
+
Soft-delete a lot — recoverable, and frees its `lotNumber` for reuse. Distinct from {@link archive}. Hidden from reads unless `{ includeDeleted: true }`; undo with {@link restore}.
|
|
9958
|
+
|
|
9910
9959
|
**archive**(collectionId: string, lotId: string) → `Promise<`
|
|
9911
|
-
|
|
9960
|
+
Archive a lot — a live lifecycle state (stays visible, keeps its number). Not a delete.
|
|
9961
|
+
|
|
9962
|
+
**restore**(collectionId: string, lotId: string) → `Promise<Lot>`
|
|
9963
|
+
Restore a soft-deleted lot. Rejects (409) if a live lot now uses the same number.
|
|
9912
9964
|
|
|
9913
9965
|
**resolve**(collectionId: string, lotId: string) → `Promise<ResolveLotResponse>`
|
|
9914
9966
|
Re-resolve members from the current selector; returns the lot + a member diff.
|
|
@@ -10301,6 +10353,12 @@ Create a proof for a product (admin only). POST /admin/collection/:collectionId/
|
|
|
10301
10353
|
values: ProofUpdateRequest) → `Promise<ProofResponse>`
|
|
10302
10354
|
Update a proof for a product (admin only). PUT /admin/collection/:collectionId/product/:productId/proof/:proofId Pass the fields to change **at the root**, keyed by zone (see {@link ProofWrite}): ```ts proof.update(collectionId, productId, proofId, { data: { serialNo: 1002 }, // → proof.data (admin-only writable) values: { colour: 'blue' }, // → proof.values }) ``` Object zones deep-merge, so you can change one field without wiping the rest.
|
|
10303
10355
|
|
|
10356
|
+
**updateValues**(collectionId: string,
|
|
10357
|
+
productId: string,
|
|
10358
|
+
proofId: string,
|
|
10359
|
+
values: ProofValuesUpdateRequest) → `Promise<ProofResponse>`
|
|
10360
|
+
Owner self-service update of a proof's owner-writable data. PUT /public/collection/:collectionId/product/:productId/proof/:proofId/values The public counterpart to admin `update` — the current OWNER (or a collection admin) editing their own proof, no admin credentials required. Only owner-writable zones are honoured (see {@link ProofValuesUpdateRequest}): ```ts proof.updateValues(collectionId, productId, proofId, { colour: 'blue', // → proof.values.colour (public) owner: { warranty: '2y' }, // → proof.values.owner (owner-scoped) personal: { nickname: 'Bo' }, // → proof.values.personal[callerUid] (private, own slot only) }) ``` `personal` always targets the caller's OWN slot — you cannot write another user's personal data, even as an admin. Object zones deep-merge (owner/personal merge field-by-field), so you can change one field without wiping the rest. Business-only zones (`data`/`admin`/`private`) are not writable here — use the admin `update` for those.
|
|
10361
|
+
|
|
10304
10362
|
**claim**(collectionId: string,
|
|
10305
10363
|
productId: string,
|
|
10306
10364
|
proofId: string,
|
package/dist/docs/lots.md
CHANGED
|
@@ -18,9 +18,22 @@ truth for its shared data.
|
|
|
18
18
|
- `{ mode: 'products', productIds: [...] }` — an explicit list.
|
|
19
19
|
- **`productIds` / `productCount`** — the materialised snapshot of resolved members (re-resolved on create, on selector change, and on demand via `resolve`).
|
|
20
20
|
- **`payload`** — shared lot data (dates, supplier ref, custom fields). Lives only on the lot.
|
|
21
|
-
- **`status`** — `open` → `closed` → `recalled` → `archived`.
|
|
21
|
+
- **`status`** — `open` → `closed` → `recalled` → `archived`. A live lifecycle state, distinct from deletion.
|
|
22
22
|
- **`destination`** — optional lot-level redirect; wins over the product's on a lot-scoped scan.
|
|
23
23
|
|
|
24
|
+
### Archive vs delete
|
|
25
|
+
|
|
26
|
+
Two separate ideas — mirroring the platform's `deletedAt` convention:
|
|
27
|
+
|
|
28
|
+
| | `archive` (`status: 'archived'`) | `remove` (soft-delete, `deletedAt`) |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| Record | stays **live** & visible | **hidden** from reads unless `includeDeleted: true` |
|
|
31
|
+
| `lotNumber` | **stays reserved** | **freed** for reuse by a new lot |
|
|
32
|
+
| AI(10) scan | not resolved (excluded) | not resolved |
|
|
33
|
+
| Reversible | change status back | `restore` (409 if the number was taken by a live lot) |
|
|
34
|
+
|
|
35
|
+
Nothing is ever hard-deleted (joins/history stay intact). Use **archive** for "this run is done, keep it around"; use **remove** for "this was a mistake, and I want the number back."
|
|
36
|
+
|
|
24
37
|
---
|
|
25
38
|
|
|
26
39
|
## SDK — `SL.lots.*`
|
|
@@ -50,7 +63,11 @@ const containing = await lots.list(collectionId, { productId: 'prd_abc' }) // r
|
|
|
50
63
|
const updated = await lots.update(collectionId, lot.id, { status: 'closed' })
|
|
51
64
|
const { diff } = await lots.resolve(collectionId, lot.id) // { added, removed }
|
|
52
65
|
const members = await lots.listProducts(collectionId, lot.id, { page: 1, limit: 50 })
|
|
53
|
-
|
|
66
|
+
|
|
67
|
+
await lots.archive(collectionId, lot.id) // live, keeps its number
|
|
68
|
+
await lots.remove(collectionId, lot.id) // soft-delete, frees the number
|
|
69
|
+
const withDeleted = await lots.list(collectionId, { includeDeleted: true })
|
|
70
|
+
const restored = await lots.restore(collectionId, lot.id) // undo a soft-delete
|
|
54
71
|
|
|
55
72
|
// Cross-app reads
|
|
56
73
|
const publicLots = await lots.publicList(collectionId)
|
|
@@ -37,7 +37,8 @@ proof.admin = { … } // BUSINESS-ONLY → read: business, write: b
|
|
|
37
37
|
proof.values = { // consumer bag — owner + business-writable
|
|
38
38
|
<anyKey>: …, // PUBLIC → read: everyone,
|
|
39
39
|
// write: business + current owner
|
|
40
|
-
owner: { … }, // OWNER-SCOPED → read: business + current owner
|
|
40
|
+
owner: { … }, // OWNER-SCOPED → read: business + current owner
|
|
41
|
+
// (also everyone while `claimable`, see below),
|
|
41
42
|
// write: business + current owner,
|
|
42
43
|
// transfers with ownership
|
|
43
44
|
personal: { // PER-USER → read/write: only the specific user,
|
|
@@ -75,10 +76,12 @@ The field-config editor and SDK write helpers MUST reject attempts to create top
|
|
|
75
76
|
| `proof.data.*` | ✅ | ✅ | ✅ | ✅ |
|
|
76
77
|
| `proof.admin.*` | ❌ | ❌ | ❌ | ✅ |
|
|
77
78
|
| `proof.values.<publicKey>` | ✅ | ✅ | ✅ | ✅ |
|
|
78
|
-
| `proof.values.owner.*` |
|
|
79
|
+
| `proof.values.owner.*` | ❌ † | ❌ † | ✅ | ✅ |
|
|
79
80
|
| `proof.values.personal[me].*` | ❌ | ✅ (own slot only) | ✅ (own slot) | ❌ (see note) |
|
|
80
81
|
| `proof.values.personal[other].*` | ❌ | ❌ | ❌ | ❌ (see note) |
|
|
81
82
|
|
|
83
|
+
> **† Claimable exception (`proof.values.owner.*`):** while a proof is **claimable** (`proof.claimable === true` *or* `proof.values.claimable === true`), its `owner` bag is returned to **everyone** — public/anonymous and authenticated non-owners included — so a prospective claimer can see pre-set owner data before claiming. Once the proof is claimed (`claimable` flips off) it reverts to owner-only (unless re-marked claimable). This is **read-only** exposure — write authority is unchanged (still owner + business). Implication: don't put anything in `values.owner` on a claimable proof that shouldn't be visible before it's claimed.
|
|
84
|
+
>
|
|
82
85
|
> **Note on `personal`:** the default rule is that `personal` slots are readable *only* by the user whose `userId` matches the slot key — not even business admins. If the platform ever needs an admin-visible variant, it should be a separate mechanism, not a relaxation of this rule.
|
|
83
86
|
|
|
84
87
|
## Who writes what (authority matrix)
|
package/dist/openapi.yaml
CHANGED
|
@@ -4996,6 +4996,38 @@ paths:
|
|
|
4996
4996
|
description: Unauthorized
|
|
4997
4997
|
404:
|
|
4998
4998
|
description: Not found
|
|
4999
|
+
/admin/collection/{collectionId}/lots/{lotId}/restore:
|
|
5000
|
+
post:
|
|
5001
|
+
tags:
|
|
5002
|
+
- lots
|
|
5003
|
+
summary: Restore a soft-deleted lot.
|
|
5004
|
+
operationId: lots_restore
|
|
5005
|
+
security:
|
|
5006
|
+
- bearerAuth: []
|
|
5007
|
+
parameters:
|
|
5008
|
+
- name: collectionId
|
|
5009
|
+
in: path
|
|
5010
|
+
required: true
|
|
5011
|
+
schema:
|
|
5012
|
+
type: string
|
|
5013
|
+
- name: lotId
|
|
5014
|
+
in: path
|
|
5015
|
+
required: true
|
|
5016
|
+
schema:
|
|
5017
|
+
type: string
|
|
5018
|
+
responses:
|
|
5019
|
+
200:
|
|
5020
|
+
description: Success
|
|
5021
|
+
content:
|
|
5022
|
+
application/json:
|
|
5023
|
+
schema:
|
|
5024
|
+
$ref: "#/components/schemas/Lot"
|
|
5025
|
+
400:
|
|
5026
|
+
description: Bad request
|
|
5027
|
+
401:
|
|
5028
|
+
description: Unauthorized
|
|
5029
|
+
404:
|
|
5030
|
+
description: Not found
|
|
4999
5031
|
/admin/collection/{collectionId}/lots{params}:
|
|
5000
5032
|
get:
|
|
5001
5033
|
tags:
|
|
@@ -12611,6 +12643,48 @@ paths:
|
|
|
12611
12643
|
description: Unauthorized
|
|
12612
12644
|
404:
|
|
12613
12645
|
description: Not found
|
|
12646
|
+
/public/collection/{collectionId}/product/{productId}/proof/{proofId}/values:
|
|
12647
|
+
put:
|
|
12648
|
+
tags:
|
|
12649
|
+
- proof
|
|
12650
|
+
summary: proof.updateValues
|
|
12651
|
+
operationId: proof_updateValues
|
|
12652
|
+
security: []
|
|
12653
|
+
parameters:
|
|
12654
|
+
- name: collectionId
|
|
12655
|
+
in: path
|
|
12656
|
+
required: true
|
|
12657
|
+
schema:
|
|
12658
|
+
type: string
|
|
12659
|
+
- name: productId
|
|
12660
|
+
in: path
|
|
12661
|
+
required: true
|
|
12662
|
+
schema:
|
|
12663
|
+
type: string
|
|
12664
|
+
- name: proofId
|
|
12665
|
+
in: path
|
|
12666
|
+
required: true
|
|
12667
|
+
schema:
|
|
12668
|
+
type: string
|
|
12669
|
+
responses:
|
|
12670
|
+
200:
|
|
12671
|
+
description: Success
|
|
12672
|
+
content:
|
|
12673
|
+
application/json:
|
|
12674
|
+
schema:
|
|
12675
|
+
$ref: "#/components/schemas/ProofResponse"
|
|
12676
|
+
400:
|
|
12677
|
+
description: Bad request
|
|
12678
|
+
401:
|
|
12679
|
+
description: Unauthorized
|
|
12680
|
+
404:
|
|
12681
|
+
description: Not found
|
|
12682
|
+
requestBody:
|
|
12683
|
+
required: true
|
|
12684
|
+
content:
|
|
12685
|
+
application/json:
|
|
12686
|
+
schema:
|
|
12687
|
+
$ref: "#/components/schemas/ProofValuesUpdateRequest"
|
|
12614
12688
|
/public/collection/{collectionId}/products/{productId}/createClaim:
|
|
12615
12689
|
post:
|
|
12616
12690
|
tags:
|
|
@@ -19810,12 +19884,22 @@ components:
|
|
|
19810
19884
|
name:
|
|
19811
19885
|
type: string
|
|
19812
19886
|
expiryDate:
|
|
19813
|
-
type:
|
|
19814
|
-
additionalProperties: true
|
|
19887
|
+
type: string
|
|
19815
19888
|
productId:
|
|
19816
19889
|
type: string
|
|
19817
19890
|
collectionId:
|
|
19818
19891
|
type: string
|
|
19892
|
+
createdAt:
|
|
19893
|
+
type: string
|
|
19894
|
+
updatedAt:
|
|
19895
|
+
type: string
|
|
19896
|
+
deleted:
|
|
19897
|
+
type: boolean
|
|
19898
|
+
deletedAt:
|
|
19899
|
+
type: string
|
|
19900
|
+
admin:
|
|
19901
|
+
type: object
|
|
19902
|
+
additionalProperties: true
|
|
19819
19903
|
required:
|
|
19820
19904
|
- id
|
|
19821
19905
|
BatchCreateRequest:
|
|
@@ -19828,8 +19912,6 @@ components:
|
|
|
19828
19912
|
expiryDate:
|
|
19829
19913
|
type: object
|
|
19830
19914
|
additionalProperties: true
|
|
19831
|
-
required:
|
|
19832
|
-
- id
|
|
19833
19915
|
BatchUpdateRequest:
|
|
19834
19916
|
type: object
|
|
19835
19917
|
properties:
|
|
@@ -23737,6 +23819,8 @@ components:
|
|
|
23737
23819
|
type: string
|
|
23738
23820
|
updatedAt:
|
|
23739
23821
|
type: string
|
|
23822
|
+
deletedAt:
|
|
23823
|
+
type: string
|
|
23740
23824
|
required:
|
|
23741
23825
|
- id
|
|
23742
23826
|
- collectionId
|
|
@@ -23777,6 +23861,8 @@ components:
|
|
|
23777
23861
|
type: string
|
|
23778
23862
|
productId:
|
|
23779
23863
|
type: string
|
|
23864
|
+
includeDeleted:
|
|
23865
|
+
type: boolean
|
|
23780
23866
|
ListLotsResponse:
|
|
23781
23867
|
type: object
|
|
23782
23868
|
properties:
|
|
@@ -25620,6 +25706,17 @@ components:
|
|
|
25620
25706
|
type: object
|
|
25621
25707
|
additionalProperties:
|
|
25622
25708
|
$ref: "#/components/schemas/JsonValue"
|
|
25709
|
+
ProofValuesUpdateRequest:
|
|
25710
|
+
type: object
|
|
25711
|
+
properties:
|
|
25712
|
+
owner:
|
|
25713
|
+
type: object
|
|
25714
|
+
additionalProperties:
|
|
25715
|
+
$ref: "#/components/schemas/JsonValue"
|
|
25716
|
+
personal:
|
|
25717
|
+
type: object
|
|
25718
|
+
additionalProperties:
|
|
25719
|
+
$ref: "#/components/schemas/JsonValue"
|
|
25623
25720
|
ProofFieldsConfig:
|
|
25624
25721
|
type: object
|
|
25625
25722
|
properties:
|
|
@@ -26654,6 +26751,42 @@ components:
|
|
|
26654
26751
|
metadata:
|
|
26655
26752
|
type: object
|
|
26656
26753
|
additionalProperties: true
|
|
26754
|
+
VariantResponse:
|
|
26755
|
+
type: object
|
|
26756
|
+
properties:
|
|
26757
|
+
id:
|
|
26758
|
+
type: string
|
|
26759
|
+
name:
|
|
26760
|
+
type: string
|
|
26761
|
+
productId:
|
|
26762
|
+
type: string
|
|
26763
|
+
collectionId:
|
|
26764
|
+
type: string
|
|
26765
|
+
createdAt:
|
|
26766
|
+
type: string
|
|
26767
|
+
updatedAt:
|
|
26768
|
+
type: string
|
|
26769
|
+
deleted:
|
|
26770
|
+
type: boolean
|
|
26771
|
+
deletedAt:
|
|
26772
|
+
type: string
|
|
26773
|
+
admin:
|
|
26774
|
+
type: object
|
|
26775
|
+
additionalProperties: true
|
|
26776
|
+
required:
|
|
26777
|
+
- id
|
|
26778
|
+
VariantCreateRequest:
|
|
26779
|
+
type: object
|
|
26780
|
+
properties:
|
|
26781
|
+
id:
|
|
26782
|
+
type: string
|
|
26783
|
+
name:
|
|
26784
|
+
type: string
|
|
26785
|
+
VariantUpdateRequest:
|
|
26786
|
+
type: object
|
|
26787
|
+
properties:
|
|
26788
|
+
name:
|
|
26789
|
+
type: string
|
|
26657
26790
|
NavigationRequest:
|
|
26658
26791
|
type: object
|
|
26659
26792
|
properties:
|
package/dist/types/batch.d.ts
CHANGED
|
@@ -1,28 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* @deprecated Batches moved to Postgres — dates now come back as ISO 8601 strings, never
|
|
3
|
+
* Firestore Timestamp objects. Kept only so request bodies can still pass a legacy value.
|
|
3
4
|
*/
|
|
4
5
|
export interface FirebaseTimestamp {
|
|
5
6
|
seconds: number;
|
|
6
7
|
nanoseconds?: number;
|
|
7
8
|
}
|
|
8
9
|
/**
|
|
9
|
-
* Represents a Batch object.
|
|
10
|
+
* Represents a Batch object. Dates are **ISO 8601 strings**.
|
|
10
11
|
*/
|
|
11
12
|
export interface BatchResponse {
|
|
12
13
|
id: string;
|
|
13
|
-
name?: string;
|
|
14
|
-
|
|
14
|
+
name?: string | null;
|
|
15
|
+
/** ISO 8601 date-time (was a Firebase Timestamp; now normalised to a string). */
|
|
16
|
+
expiryDate?: string | null;
|
|
15
17
|
productId?: string;
|
|
16
18
|
collectionId?: string;
|
|
19
|
+
createdAt?: string;
|
|
20
|
+
updatedAt?: string;
|
|
21
|
+
/** Present only on soft-deleted batches. */
|
|
22
|
+
deleted?: boolean;
|
|
23
|
+
deletedAt?: string;
|
|
24
|
+
/** Admin-only zone (e.g. `lastSerialId`). Returned on admin reads only — never on public reads. */
|
|
25
|
+
admin?: Record<string, any>;
|
|
17
26
|
[key: string]: any;
|
|
18
27
|
}
|
|
19
28
|
/**
|
|
20
29
|
* Request payload for creating a new batch.
|
|
21
30
|
*/
|
|
22
31
|
export interface BatchCreateRequest {
|
|
23
|
-
id
|
|
32
|
+
/** @deprecated Ignored — the server generates the batch id. */
|
|
33
|
+
id?: string;
|
|
24
34
|
name?: string;
|
|
25
|
-
|
|
35
|
+
/** A `Date`, ISO 8601 string, or legacy Firebase Timestamp — all accepted. */
|
|
36
|
+
expiryDate?: FirebaseTimestamp | string | Date;
|
|
26
37
|
[key: string]: any;
|
|
27
38
|
}
|
|
28
39
|
/**
|
|
@@ -30,7 +41,7 @@ export interface BatchCreateRequest {
|
|
|
30
41
|
*/
|
|
31
42
|
export interface BatchUpdateRequest {
|
|
32
43
|
name?: string;
|
|
33
|
-
expiryDate?: FirebaseTimestamp | string;
|
|
44
|
+
expiryDate?: FirebaseTimestamp | string | Date;
|
|
34
45
|
[key: string]: any;
|
|
35
46
|
}
|
|
36
47
|
/**
|
package/dist/types/lots.d.ts
CHANGED
|
@@ -39,6 +39,8 @@ export interface Lot {
|
|
|
39
39
|
updatedBy?: string | null;
|
|
40
40
|
createdAt: string;
|
|
41
41
|
updatedAt: string;
|
|
42
|
+
/** Soft-delete timestamp (recoverable). `null` for live lots. Distinct from `status:'archived'`. */
|
|
43
|
+
deletedAt?: string | null;
|
|
42
44
|
}
|
|
43
45
|
export interface LotCreateInput {
|
|
44
46
|
lotNumber: string;
|
|
@@ -57,6 +59,8 @@ export interface ListLotsParams {
|
|
|
57
59
|
search?: string;
|
|
58
60
|
/** Reverse lookup — lots containing this product id. */
|
|
59
61
|
productId?: string;
|
|
62
|
+
/** Admin only: include soft-deleted lots (default false). */
|
|
63
|
+
includeDeleted?: boolean;
|
|
60
64
|
}
|
|
61
65
|
export interface ListLotsResponse {
|
|
62
66
|
lots: Lot[];
|
package/dist/types/proof.d.ts
CHANGED
|
@@ -7,7 +7,11 @@ import { JsonValue, ScopedFieldDef } from './product';
|
|
|
7
7
|
*/
|
|
8
8
|
export interface ProofValues {
|
|
9
9
|
[key: string]: JsonValue | Record<string, JsonValue> | Record<string, Record<string, JsonValue>> | undefined;
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Owner-scoped: read/write by business + current owner; transfers with ownership.
|
|
12
|
+
* Read exception: while the proof is `claimable`, this bag is also readable by everyone
|
|
13
|
+
* (so a prospective claimer sees pre-set owner data); it reverts to owner-only once claimed.
|
|
14
|
+
*/
|
|
11
15
|
owner?: Record<string, JsonValue>;
|
|
12
16
|
/** Per-user: read/write only by the matching userId; not visible to the next owner, not even business admins. */
|
|
13
17
|
personal?: Record<string, Record<string, JsonValue>>;
|
|
@@ -111,6 +115,27 @@ export interface ProofCreateRequest {
|
|
|
111
115
|
export type ProofUpdateRequest = Partial<ProofWrite> & {
|
|
112
116
|
proof?: ProofWrite;
|
|
113
117
|
};
|
|
118
|
+
/**
|
|
119
|
+
* Body for the owner self-service values write (`proof.updateValues`), the
|
|
120
|
+
* public counterpart to the admin `update`. The caller must be the current
|
|
121
|
+
* owner (or a collection admin). Only owner-writable zones are honoured:
|
|
122
|
+
*
|
|
123
|
+
* - flat keys → `proof.values.<key>` (public data)
|
|
124
|
+
* - `owner` → merged into `proof.values.owner` (owner-scoped)
|
|
125
|
+
* - `personal` → merged into `proof.values.personal[callerUid]` — the
|
|
126
|
+
* caller's OWN private slot only, never another user's
|
|
127
|
+
* (owner-only, non-transferring; not even admins can
|
|
128
|
+
* write someone else's slot)
|
|
129
|
+
*
|
|
130
|
+
* `private` / `proof` sub-keys are business-only and are ignored here.
|
|
131
|
+
*/
|
|
132
|
+
export interface ProofValuesUpdateRequest {
|
|
133
|
+
[key: string]: JsonValue | Record<string, JsonValue> | undefined;
|
|
134
|
+
/** Owner-scoped data, merged into `proof.values.owner`. */
|
|
135
|
+
owner?: Record<string, JsonValue>;
|
|
136
|
+
/** The caller's own private slot, merged into `proof.values.personal[callerUid]`. */
|
|
137
|
+
personal?: Record<string, JsonValue>;
|
|
138
|
+
}
|
|
114
139
|
export type ProofClaimRequest = Record<string, any>;
|
|
115
140
|
/**
|
|
116
141
|
* `'public'` (default, omitted) reads/writes `proof.values[key]`.
|
package/dist/types/variant.d.ts
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Represents a Variant object.
|
|
2
|
+
* Represents a Variant object. Dates are ISO 8601 strings (Postgres-backed).
|
|
3
3
|
*/
|
|
4
|
-
export
|
|
4
|
+
export interface VariantResponse {
|
|
5
|
+
id: string;
|
|
6
|
+
name?: string | null;
|
|
7
|
+
productId?: string;
|
|
8
|
+
collectionId?: string;
|
|
9
|
+
createdAt?: string;
|
|
10
|
+
updatedAt?: string;
|
|
11
|
+
/** Present only on soft-deleted variants. */
|
|
12
|
+
deleted?: boolean;
|
|
13
|
+
deletedAt?: string;
|
|
14
|
+
/** Admin-only zone (e.g. `lastSerialId`). Admin reads only — never on public reads. */
|
|
15
|
+
admin?: Record<string, any>;
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
}
|
|
5
18
|
/**
|
|
6
19
|
* Request payload for creating a new variant.
|
|
7
20
|
*/
|
|
8
|
-
export
|
|
21
|
+
export interface VariantCreateRequest {
|
|
22
|
+
/** @deprecated Ignored — the server generates the variant id. (Use PUT with an id to choose one.) */
|
|
23
|
+
id?: string;
|
|
24
|
+
name?: string;
|
|
25
|
+
[key: string]: any;
|
|
26
|
+
}
|
|
9
27
|
/**
|
|
10
|
-
* Request payload for updating
|
|
28
|
+
* Request payload for updating a variant. PUT with a new id creates it (upsert).
|
|
11
29
|
*/
|
|
12
|
-
export
|
|
30
|
+
export interface VariantUpdateRequest {
|
|
31
|
+
name?: string;
|
|
32
|
+
[key: string]: any;
|
|
33
|
+
}
|
package/dist/utils/paths.js
CHANGED
|
@@ -110,13 +110,9 @@ export function buildPortalPath(params) {
|
|
|
110
110
|
// Batch object - extract id and expiryDate
|
|
111
111
|
extractedBatchId = batch.id;
|
|
112
112
|
if (batch.expiryDate) {
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
expiryDate = batch.expiryDate;
|
|
119
|
-
}
|
|
113
|
+
// Now an ISO string, but stay defensive about a legacy Firebase Timestamp object.
|
|
114
|
+
const exp = batch.expiryDate;
|
|
115
|
+
expiryDate = (exp && typeof exp === 'object' && 'seconds' in exp) ? new Date(exp.seconds * 1000) : exp;
|
|
120
116
|
}
|
|
121
117
|
}
|
|
122
118
|
else if (batchId) {
|
package/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.16.
|
|
3
|
+
Version: 1.16.2 | Generated: 2026-09-05T10:46:06.239Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -3549,20 +3549,25 @@ interface FirebaseTimestamp {
|
|
|
3549
3549
|
```typescript
|
|
3550
3550
|
interface BatchResponse {
|
|
3551
3551
|
id: string // Batch ID
|
|
3552
|
-
name?: string
|
|
3553
|
-
expiryDate?:
|
|
3554
|
-
productId?: string // Product ID
|
|
3552
|
+
name?: string | null // Batch name
|
|
3553
|
+
expiryDate?: string | null
|
|
3554
|
+
productId?: string // Product ID
|
|
3555
3555
|
collectionId?: string // Collection ID
|
|
3556
|
-
|
|
3556
|
+
createdAt?: string // ISO 8601
|
|
3557
|
+
updatedAt?: string // ISO 8601
|
|
3558
|
+
deleted?: boolean
|
|
3559
|
+
deletedAt?: string // ISO 8601
|
|
3560
|
+
admin?: Record<string, any>
|
|
3561
|
+
[key: string]: any // Additional (schemaless) batch fields
|
|
3557
3562
|
}
|
|
3558
3563
|
```
|
|
3559
3564
|
|
|
3560
3565
|
**BatchCreateRequest** (interface)
|
|
3561
3566
|
```typescript
|
|
3562
3567
|
interface BatchCreateRequest {
|
|
3563
|
-
id
|
|
3564
|
-
name?: string
|
|
3565
|
-
expiryDate?: FirebaseTimestamp | string
|
|
3568
|
+
id?: string
|
|
3569
|
+
name?: string
|
|
3570
|
+
expiryDate?: FirebaseTimestamp | string | Date
|
|
3566
3571
|
[key: string]: any // Additional batch fields
|
|
3567
3572
|
}
|
|
3568
3573
|
```
|
|
@@ -3570,8 +3575,8 @@ interface BatchCreateRequest {
|
|
|
3570
3575
|
**BatchUpdateRequest** (interface)
|
|
3571
3576
|
```typescript
|
|
3572
3577
|
interface BatchUpdateRequest {
|
|
3573
|
-
name?: string
|
|
3574
|
-
expiryDate?: FirebaseTimestamp | string
|
|
3578
|
+
name?: string
|
|
3579
|
+
expiryDate?: FirebaseTimestamp | string | Date
|
|
3575
3580
|
[key: string]: any // Additional batch fields
|
|
3576
3581
|
}
|
|
3577
3582
|
```
|
|
@@ -6389,6 +6394,7 @@ interface Lot {
|
|
|
6389
6394
|
updatedBy?: string | null
|
|
6390
6395
|
createdAt: string
|
|
6391
6396
|
updatedAt: string
|
|
6397
|
+
deletedAt?: string | null
|
|
6392
6398
|
}
|
|
6393
6399
|
```
|
|
6394
6400
|
|
|
@@ -6412,6 +6418,7 @@ interface ListLotsParams {
|
|
|
6412
6418
|
status?: LotStatus
|
|
6413
6419
|
search?: string
|
|
6414
6420
|
productId?: string
|
|
6421
|
+
includeDeleted?: boolean
|
|
6415
6422
|
}
|
|
6416
6423
|
```
|
|
6417
6424
|
|
|
@@ -7431,6 +7438,9 @@ interface ProductFieldsConfig {
|
|
|
7431
7438
|
```typescript
|
|
7432
7439
|
interface ProofValues {
|
|
7433
7440
|
[key: string]: JsonValue | Record<string, JsonValue> | Record<string, Record<string, JsonValue>> | undefined
|
|
7441
|
+
* Owner-scoped: read/write by business + current owner; transfers with ownership.
|
|
7442
|
+
* Read exception: while the proof is `claimable`, this bag is also readable by everyone
|
|
7443
|
+
* (so a prospective claimer sees pre-set owner data); it reverts to owner-only once claimed.
|
|
7434
7444
|
owner?: Record<string, JsonValue>
|
|
7435
7445
|
personal?: Record<string, Record<string, JsonValue>>
|
|
7436
7446
|
}
|
|
@@ -7489,6 +7499,15 @@ interface ProofCreateRequest {
|
|
|
7489
7499
|
}
|
|
7490
7500
|
```
|
|
7491
7501
|
|
|
7502
|
+
**ProofValuesUpdateRequest** (interface)
|
|
7503
|
+
```typescript
|
|
7504
|
+
interface ProofValuesUpdateRequest {
|
|
7505
|
+
[key: string]: JsonValue | Record<string, JsonValue> | undefined
|
|
7506
|
+
owner?: Record<string, JsonValue>
|
|
7507
|
+
personal?: Record<string, JsonValue>
|
|
7508
|
+
}
|
|
7509
|
+
```
|
|
7510
|
+
|
|
7492
7511
|
**ProofFieldsConfig** (interface)
|
|
7493
7512
|
```typescript
|
|
7494
7513
|
interface ProofFieldsConfig {
|
|
@@ -8151,11 +8170,38 @@ interface TranslationUpdateRequest {
|
|
|
8151
8170
|
|
|
8152
8171
|
### variant
|
|
8153
8172
|
|
|
8154
|
-
**VariantResponse**
|
|
8173
|
+
**VariantResponse** (interface)
|
|
8174
|
+
```typescript
|
|
8175
|
+
interface VariantResponse {
|
|
8176
|
+
id: string
|
|
8177
|
+
name?: string | null
|
|
8178
|
+
productId?: string
|
|
8179
|
+
collectionId?: string
|
|
8180
|
+
createdAt?: string // ISO 8601
|
|
8181
|
+
updatedAt?: string // ISO 8601
|
|
8182
|
+
deleted?: boolean
|
|
8183
|
+
deletedAt?: string // ISO 8601
|
|
8184
|
+
admin?: Record<string, any>
|
|
8185
|
+
[key: string]: any // Additional (schemaless) variant fields
|
|
8186
|
+
}
|
|
8187
|
+
```
|
|
8155
8188
|
|
|
8156
|
-
**VariantCreateRequest**
|
|
8189
|
+
**VariantCreateRequest** (interface)
|
|
8190
|
+
```typescript
|
|
8191
|
+
interface VariantCreateRequest {
|
|
8192
|
+
id?: string
|
|
8193
|
+
name?: string
|
|
8194
|
+
[key: string]: any
|
|
8195
|
+
}
|
|
8196
|
+
```
|
|
8157
8197
|
|
|
8158
|
-
**VariantUpdateRequest**
|
|
8198
|
+
**VariantUpdateRequest** (interface)
|
|
8199
|
+
```typescript
|
|
8200
|
+
interface VariantUpdateRequest {
|
|
8201
|
+
name?: string
|
|
8202
|
+
[key: string]: any
|
|
8203
|
+
}
|
|
8204
|
+
```
|
|
8159
8205
|
|
|
8160
8206
|
### widgets
|
|
8161
8207
|
|
|
@@ -9898,17 +9944,23 @@ Create a lot (resolves its selector into members).
|
|
|
9898
9944
|
**list**(collectionId: string, params: ListLotsParams = {}) → `Promise<Lot[]>`
|
|
9899
9945
|
List lots (summary rows; `payload`/`productIds` omitted). Filter by status, search, or containing productId.
|
|
9900
9946
|
|
|
9901
|
-
**get**(collectionId: string, lotId: string) → `Promise<Lot>`
|
|
9902
|
-
Get the full lot record.
|
|
9947
|
+
**get**(collectionId: string, lotId: string, opts: { includeDeleted?: boolean } = {}) → `Promise<Lot>`
|
|
9948
|
+
Get the full lot record. Pass `{ includeDeleted: true }` to fetch a soft-deleted one.
|
|
9903
9949
|
|
|
9904
|
-
**getByNumber**(collectionId: string, lotNumber: string) → `Promise<Lot>`
|
|
9950
|
+
**getByNumber**(collectionId: string, lotNumber: string, opts: { includeDeleted?: boolean } = {}) → `Promise<Lot>`
|
|
9905
9951
|
Look up a lot by its number (case-insensitive) — used by scan/resolver flows.
|
|
9906
9952
|
|
|
9907
9953
|
**update**(collectionId: string, lotId: string, lot: LotUpdateInput) → `Promise<Lot>`
|
|
9908
9954
|
Update a lot. Re-resolves members if the selector changed (response then carries `diff`).
|
|
9909
9955
|
|
|
9956
|
+
**remove**(collectionId: string, lotId: string) → `Promise<`
|
|
9957
|
+
Soft-delete a lot — recoverable, and frees its `lotNumber` for reuse. Distinct from {@link archive}. Hidden from reads unless `{ includeDeleted: true }`; undo with {@link restore}.
|
|
9958
|
+
|
|
9910
9959
|
**archive**(collectionId: string, lotId: string) → `Promise<`
|
|
9911
|
-
|
|
9960
|
+
Archive a lot — a live lifecycle state (stays visible, keeps its number). Not a delete.
|
|
9961
|
+
|
|
9962
|
+
**restore**(collectionId: string, lotId: string) → `Promise<Lot>`
|
|
9963
|
+
Restore a soft-deleted lot. Rejects (409) if a live lot now uses the same number.
|
|
9912
9964
|
|
|
9913
9965
|
**resolve**(collectionId: string, lotId: string) → `Promise<ResolveLotResponse>`
|
|
9914
9966
|
Re-resolve members from the current selector; returns the lot + a member diff.
|
|
@@ -10301,6 +10353,12 @@ Create a proof for a product (admin only). POST /admin/collection/:collectionId/
|
|
|
10301
10353
|
values: ProofUpdateRequest) → `Promise<ProofResponse>`
|
|
10302
10354
|
Update a proof for a product (admin only). PUT /admin/collection/:collectionId/product/:productId/proof/:proofId Pass the fields to change **at the root**, keyed by zone (see {@link ProofWrite}): ```ts proof.update(collectionId, productId, proofId, { data: { serialNo: 1002 }, // → proof.data (admin-only writable) values: { colour: 'blue' }, // → proof.values }) ``` Object zones deep-merge, so you can change one field without wiping the rest.
|
|
10303
10355
|
|
|
10356
|
+
**updateValues**(collectionId: string,
|
|
10357
|
+
productId: string,
|
|
10358
|
+
proofId: string,
|
|
10359
|
+
values: ProofValuesUpdateRequest) → `Promise<ProofResponse>`
|
|
10360
|
+
Owner self-service update of a proof's owner-writable data. PUT /public/collection/:collectionId/product/:productId/proof/:proofId/values The public counterpart to admin `update` — the current OWNER (or a collection admin) editing their own proof, no admin credentials required. Only owner-writable zones are honoured (see {@link ProofValuesUpdateRequest}): ```ts proof.updateValues(collectionId, productId, proofId, { colour: 'blue', // → proof.values.colour (public) owner: { warranty: '2y' }, // → proof.values.owner (owner-scoped) personal: { nickname: 'Bo' }, // → proof.values.personal[callerUid] (private, own slot only) }) ``` `personal` always targets the caller's OWN slot — you cannot write another user's personal data, even as an admin. Object zones deep-merge (owner/personal merge field-by-field), so you can change one field without wiping the rest. Business-only zones (`data`/`admin`/`private`) are not writable here — use the admin `update` for those.
|
|
10361
|
+
|
|
10304
10362
|
**claim**(collectionId: string,
|
|
10305
10363
|
productId: string,
|
|
10306
10364
|
proofId: string,
|
package/docs/lots.md
CHANGED
|
@@ -18,9 +18,22 @@ truth for its shared data.
|
|
|
18
18
|
- `{ mode: 'products', productIds: [...] }` — an explicit list.
|
|
19
19
|
- **`productIds` / `productCount`** — the materialised snapshot of resolved members (re-resolved on create, on selector change, and on demand via `resolve`).
|
|
20
20
|
- **`payload`** — shared lot data (dates, supplier ref, custom fields). Lives only on the lot.
|
|
21
|
-
- **`status`** — `open` → `closed` → `recalled` → `archived`.
|
|
21
|
+
- **`status`** — `open` → `closed` → `recalled` → `archived`. A live lifecycle state, distinct from deletion.
|
|
22
22
|
- **`destination`** — optional lot-level redirect; wins over the product's on a lot-scoped scan.
|
|
23
23
|
|
|
24
|
+
### Archive vs delete
|
|
25
|
+
|
|
26
|
+
Two separate ideas — mirroring the platform's `deletedAt` convention:
|
|
27
|
+
|
|
28
|
+
| | `archive` (`status: 'archived'`) | `remove` (soft-delete, `deletedAt`) |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| Record | stays **live** & visible | **hidden** from reads unless `includeDeleted: true` |
|
|
31
|
+
| `lotNumber` | **stays reserved** | **freed** for reuse by a new lot |
|
|
32
|
+
| AI(10) scan | not resolved (excluded) | not resolved |
|
|
33
|
+
| Reversible | change status back | `restore` (409 if the number was taken by a live lot) |
|
|
34
|
+
|
|
35
|
+
Nothing is ever hard-deleted (joins/history stay intact). Use **archive** for "this run is done, keep it around"; use **remove** for "this was a mistake, and I want the number back."
|
|
36
|
+
|
|
24
37
|
---
|
|
25
38
|
|
|
26
39
|
## SDK — `SL.lots.*`
|
|
@@ -50,7 +63,11 @@ const containing = await lots.list(collectionId, { productId: 'prd_abc' }) // r
|
|
|
50
63
|
const updated = await lots.update(collectionId, lot.id, { status: 'closed' })
|
|
51
64
|
const { diff } = await lots.resolve(collectionId, lot.id) // { added, removed }
|
|
52
65
|
const members = await lots.listProducts(collectionId, lot.id, { page: 1, limit: 50 })
|
|
53
|
-
|
|
66
|
+
|
|
67
|
+
await lots.archive(collectionId, lot.id) // live, keeps its number
|
|
68
|
+
await lots.remove(collectionId, lot.id) // soft-delete, frees the number
|
|
69
|
+
const withDeleted = await lots.list(collectionId, { includeDeleted: true })
|
|
70
|
+
const restored = await lots.restore(collectionId, lot.id) // undo a soft-delete
|
|
54
71
|
|
|
55
72
|
// Cross-app reads
|
|
56
73
|
const publicLots = await lots.publicList(collectionId)
|
|
@@ -37,7 +37,8 @@ proof.admin = { … } // BUSINESS-ONLY → read: business, write: b
|
|
|
37
37
|
proof.values = { // consumer bag — owner + business-writable
|
|
38
38
|
<anyKey>: …, // PUBLIC → read: everyone,
|
|
39
39
|
// write: business + current owner
|
|
40
|
-
owner: { … }, // OWNER-SCOPED → read: business + current owner
|
|
40
|
+
owner: { … }, // OWNER-SCOPED → read: business + current owner
|
|
41
|
+
// (also everyone while `claimable`, see below),
|
|
41
42
|
// write: business + current owner,
|
|
42
43
|
// transfers with ownership
|
|
43
44
|
personal: { // PER-USER → read/write: only the specific user,
|
|
@@ -75,10 +76,12 @@ The field-config editor and SDK write helpers MUST reject attempts to create top
|
|
|
75
76
|
| `proof.data.*` | ✅ | ✅ | ✅ | ✅ |
|
|
76
77
|
| `proof.admin.*` | ❌ | ❌ | ❌ | ✅ |
|
|
77
78
|
| `proof.values.<publicKey>` | ✅ | ✅ | ✅ | ✅ |
|
|
78
|
-
| `proof.values.owner.*` |
|
|
79
|
+
| `proof.values.owner.*` | ❌ † | ❌ † | ✅ | ✅ |
|
|
79
80
|
| `proof.values.personal[me].*` | ❌ | ✅ (own slot only) | ✅ (own slot) | ❌ (see note) |
|
|
80
81
|
| `proof.values.personal[other].*` | ❌ | ❌ | ❌ | ❌ (see note) |
|
|
81
82
|
|
|
83
|
+
> **† Claimable exception (`proof.values.owner.*`):** while a proof is **claimable** (`proof.claimable === true` *or* `proof.values.claimable === true`), its `owner` bag is returned to **everyone** — public/anonymous and authenticated non-owners included — so a prospective claimer can see pre-set owner data before claiming. Once the proof is claimed (`claimable` flips off) it reverts to owner-only (unless re-marked claimable). This is **read-only** exposure — write authority is unchanged (still owner + business). Implication: don't put anything in `values.owner` on a claimable proof that shouldn't be visible before it's claimed.
|
|
84
|
+
>
|
|
82
85
|
> **Note on `personal`:** the default rule is that `personal` slots are readable *only* by the user whose `userId` matches the slot key — not even business admins. If the platform ever needs an admin-visible variant, it should be a separate mechanism, not a relaxation of this rule.
|
|
83
86
|
|
|
84
87
|
## Who writes what (authority matrix)
|
package/openapi.yaml
CHANGED
|
@@ -4996,6 +4996,38 @@ paths:
|
|
|
4996
4996
|
description: Unauthorized
|
|
4997
4997
|
404:
|
|
4998
4998
|
description: Not found
|
|
4999
|
+
/admin/collection/{collectionId}/lots/{lotId}/restore:
|
|
5000
|
+
post:
|
|
5001
|
+
tags:
|
|
5002
|
+
- lots
|
|
5003
|
+
summary: Restore a soft-deleted lot.
|
|
5004
|
+
operationId: lots_restore
|
|
5005
|
+
security:
|
|
5006
|
+
- bearerAuth: []
|
|
5007
|
+
parameters:
|
|
5008
|
+
- name: collectionId
|
|
5009
|
+
in: path
|
|
5010
|
+
required: true
|
|
5011
|
+
schema:
|
|
5012
|
+
type: string
|
|
5013
|
+
- name: lotId
|
|
5014
|
+
in: path
|
|
5015
|
+
required: true
|
|
5016
|
+
schema:
|
|
5017
|
+
type: string
|
|
5018
|
+
responses:
|
|
5019
|
+
200:
|
|
5020
|
+
description: Success
|
|
5021
|
+
content:
|
|
5022
|
+
application/json:
|
|
5023
|
+
schema:
|
|
5024
|
+
$ref: "#/components/schemas/Lot"
|
|
5025
|
+
400:
|
|
5026
|
+
description: Bad request
|
|
5027
|
+
401:
|
|
5028
|
+
description: Unauthorized
|
|
5029
|
+
404:
|
|
5030
|
+
description: Not found
|
|
4999
5031
|
/admin/collection/{collectionId}/lots{params}:
|
|
5000
5032
|
get:
|
|
5001
5033
|
tags:
|
|
@@ -12611,6 +12643,48 @@ paths:
|
|
|
12611
12643
|
description: Unauthorized
|
|
12612
12644
|
404:
|
|
12613
12645
|
description: Not found
|
|
12646
|
+
/public/collection/{collectionId}/product/{productId}/proof/{proofId}/values:
|
|
12647
|
+
put:
|
|
12648
|
+
tags:
|
|
12649
|
+
- proof
|
|
12650
|
+
summary: proof.updateValues
|
|
12651
|
+
operationId: proof_updateValues
|
|
12652
|
+
security: []
|
|
12653
|
+
parameters:
|
|
12654
|
+
- name: collectionId
|
|
12655
|
+
in: path
|
|
12656
|
+
required: true
|
|
12657
|
+
schema:
|
|
12658
|
+
type: string
|
|
12659
|
+
- name: productId
|
|
12660
|
+
in: path
|
|
12661
|
+
required: true
|
|
12662
|
+
schema:
|
|
12663
|
+
type: string
|
|
12664
|
+
- name: proofId
|
|
12665
|
+
in: path
|
|
12666
|
+
required: true
|
|
12667
|
+
schema:
|
|
12668
|
+
type: string
|
|
12669
|
+
responses:
|
|
12670
|
+
200:
|
|
12671
|
+
description: Success
|
|
12672
|
+
content:
|
|
12673
|
+
application/json:
|
|
12674
|
+
schema:
|
|
12675
|
+
$ref: "#/components/schemas/ProofResponse"
|
|
12676
|
+
400:
|
|
12677
|
+
description: Bad request
|
|
12678
|
+
401:
|
|
12679
|
+
description: Unauthorized
|
|
12680
|
+
404:
|
|
12681
|
+
description: Not found
|
|
12682
|
+
requestBody:
|
|
12683
|
+
required: true
|
|
12684
|
+
content:
|
|
12685
|
+
application/json:
|
|
12686
|
+
schema:
|
|
12687
|
+
$ref: "#/components/schemas/ProofValuesUpdateRequest"
|
|
12614
12688
|
/public/collection/{collectionId}/products/{productId}/createClaim:
|
|
12615
12689
|
post:
|
|
12616
12690
|
tags:
|
|
@@ -19810,12 +19884,22 @@ components:
|
|
|
19810
19884
|
name:
|
|
19811
19885
|
type: string
|
|
19812
19886
|
expiryDate:
|
|
19813
|
-
type:
|
|
19814
|
-
additionalProperties: true
|
|
19887
|
+
type: string
|
|
19815
19888
|
productId:
|
|
19816
19889
|
type: string
|
|
19817
19890
|
collectionId:
|
|
19818
19891
|
type: string
|
|
19892
|
+
createdAt:
|
|
19893
|
+
type: string
|
|
19894
|
+
updatedAt:
|
|
19895
|
+
type: string
|
|
19896
|
+
deleted:
|
|
19897
|
+
type: boolean
|
|
19898
|
+
deletedAt:
|
|
19899
|
+
type: string
|
|
19900
|
+
admin:
|
|
19901
|
+
type: object
|
|
19902
|
+
additionalProperties: true
|
|
19819
19903
|
required:
|
|
19820
19904
|
- id
|
|
19821
19905
|
BatchCreateRequest:
|
|
@@ -19828,8 +19912,6 @@ components:
|
|
|
19828
19912
|
expiryDate:
|
|
19829
19913
|
type: object
|
|
19830
19914
|
additionalProperties: true
|
|
19831
|
-
required:
|
|
19832
|
-
- id
|
|
19833
19915
|
BatchUpdateRequest:
|
|
19834
19916
|
type: object
|
|
19835
19917
|
properties:
|
|
@@ -23737,6 +23819,8 @@ components:
|
|
|
23737
23819
|
type: string
|
|
23738
23820
|
updatedAt:
|
|
23739
23821
|
type: string
|
|
23822
|
+
deletedAt:
|
|
23823
|
+
type: string
|
|
23740
23824
|
required:
|
|
23741
23825
|
- id
|
|
23742
23826
|
- collectionId
|
|
@@ -23777,6 +23861,8 @@ components:
|
|
|
23777
23861
|
type: string
|
|
23778
23862
|
productId:
|
|
23779
23863
|
type: string
|
|
23864
|
+
includeDeleted:
|
|
23865
|
+
type: boolean
|
|
23780
23866
|
ListLotsResponse:
|
|
23781
23867
|
type: object
|
|
23782
23868
|
properties:
|
|
@@ -25620,6 +25706,17 @@ components:
|
|
|
25620
25706
|
type: object
|
|
25621
25707
|
additionalProperties:
|
|
25622
25708
|
$ref: "#/components/schemas/JsonValue"
|
|
25709
|
+
ProofValuesUpdateRequest:
|
|
25710
|
+
type: object
|
|
25711
|
+
properties:
|
|
25712
|
+
owner:
|
|
25713
|
+
type: object
|
|
25714
|
+
additionalProperties:
|
|
25715
|
+
$ref: "#/components/schemas/JsonValue"
|
|
25716
|
+
personal:
|
|
25717
|
+
type: object
|
|
25718
|
+
additionalProperties:
|
|
25719
|
+
$ref: "#/components/schemas/JsonValue"
|
|
25623
25720
|
ProofFieldsConfig:
|
|
25624
25721
|
type: object
|
|
25625
25722
|
properties:
|
|
@@ -26654,6 +26751,42 @@ components:
|
|
|
26654
26751
|
metadata:
|
|
26655
26752
|
type: object
|
|
26656
26753
|
additionalProperties: true
|
|
26754
|
+
VariantResponse:
|
|
26755
|
+
type: object
|
|
26756
|
+
properties:
|
|
26757
|
+
id:
|
|
26758
|
+
type: string
|
|
26759
|
+
name:
|
|
26760
|
+
type: string
|
|
26761
|
+
productId:
|
|
26762
|
+
type: string
|
|
26763
|
+
collectionId:
|
|
26764
|
+
type: string
|
|
26765
|
+
createdAt:
|
|
26766
|
+
type: string
|
|
26767
|
+
updatedAt:
|
|
26768
|
+
type: string
|
|
26769
|
+
deleted:
|
|
26770
|
+
type: boolean
|
|
26771
|
+
deletedAt:
|
|
26772
|
+
type: string
|
|
26773
|
+
admin:
|
|
26774
|
+
type: object
|
|
26775
|
+
additionalProperties: true
|
|
26776
|
+
required:
|
|
26777
|
+
- id
|
|
26778
|
+
VariantCreateRequest:
|
|
26779
|
+
type: object
|
|
26780
|
+
properties:
|
|
26781
|
+
id:
|
|
26782
|
+
type: string
|
|
26783
|
+
name:
|
|
26784
|
+
type: string
|
|
26785
|
+
VariantUpdateRequest:
|
|
26786
|
+
type: object
|
|
26787
|
+
properties:
|
|
26788
|
+
name:
|
|
26789
|
+
type: string
|
|
26657
26790
|
NavigationRequest:
|
|
26658
26791
|
type: object
|
|
26659
26792
|
properties:
|