@proveanything/smartlinks 1.15.24 → 1.16.1
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/index.d.ts +1 -0
- package/dist/api/index.js +1 -0
- package/dist/api/lots.d.ts +50 -0
- package/dist/api/lots.js +114 -0
- package/dist/docs/API_SUMMARY.md +227 -1
- package/dist/docs/appConfig.md +2 -1
- package/dist/docs/lots.md +111 -0
- package/dist/index.d.ts +1 -0
- package/dist/openapi.yaml +658 -0
- package/dist/types/lots.d.ts +99 -0
- package/dist/types/lots.js +7 -0
- package/dist/types/proof.d.ts +6 -0
- package/docs/API_SUMMARY.md +227 -1
- package/docs/appConfig.md +2 -1
- package/docs/lots.md +111 -0
- package/openapi.yaml +658 -0
- package/package.json +1 -1
package/dist/api/index.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ export { order } from "./order";
|
|
|
34
34
|
export { app } from "./appObjects";
|
|
35
35
|
export { attestations } from "./attestations";
|
|
36
36
|
export { containers } from "./containers";
|
|
37
|
+
export { lots } from "./lots";
|
|
37
38
|
export { loyalty } from "./loyalty";
|
|
38
39
|
export { translations } from "./translations";
|
|
39
40
|
export { config } from "./config";
|
package/dist/api/index.js
CHANGED
|
@@ -37,6 +37,7 @@ export { order } from "./order";
|
|
|
37
37
|
export { app } from "./appObjects";
|
|
38
38
|
export { attestations } from "./attestations";
|
|
39
39
|
export { containers } from "./containers";
|
|
40
|
+
export { lots } from "./lots";
|
|
40
41
|
export { loyalty } from "./loyalty";
|
|
41
42
|
export { translations } from "./translations";
|
|
42
43
|
export { config } from "./config";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Lot, LotCreateInput, LotUpdateInput, ListLotsParams, ResolveLotResponse, ListLotProductsResponse } from "../types/lots";
|
|
2
|
+
/**
|
|
3
|
+
* Lots — collection-scoped production groupings that span one or more products.
|
|
4
|
+
* Writes and admin reads hit `/admin/collection/:cid/lots`; the `public*` reads hit
|
|
5
|
+
* `/public/collection/:cid/lots` for cross-app consumers. Admin vs public is the path
|
|
6
|
+
* prefix (auth is the ambient bearer token); there is no `admin` flag in this SDK.
|
|
7
|
+
*/
|
|
8
|
+
export declare namespace lots {
|
|
9
|
+
/** Create a lot (resolves its selector into members). */
|
|
10
|
+
function create(collectionId: string, lot: LotCreateInput): Promise<Lot>;
|
|
11
|
+
/** List lots (summary rows; `payload`/`productIds` omitted). Filter by status, search, or containing productId. */
|
|
12
|
+
function list(collectionId: string, params?: ListLotsParams): Promise<Lot[]>;
|
|
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>;
|
|
17
|
+
/** Look up a lot by its number (case-insensitive) — used by scan/resolver flows. */
|
|
18
|
+
function getByNumber(collectionId: string, lotNumber: string, opts?: {
|
|
19
|
+
includeDeleted?: boolean;
|
|
20
|
+
}): Promise<Lot>;
|
|
21
|
+
/** Update a lot. Re-resolves members if the selector changed (response then carries `diff`). */
|
|
22
|
+
function update(collectionId: string, lotId: string, lot: LotUpdateInput): Promise<Lot>;
|
|
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. */
|
|
31
|
+
function archive(collectionId: string, lotId: string): Promise<{
|
|
32
|
+
success: boolean;
|
|
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>;
|
|
36
|
+
/** Re-resolve members from the current selector; returns the lot + a member diff. */
|
|
37
|
+
function resolve(collectionId: string, lotId: string): Promise<ResolveLotResponse>;
|
|
38
|
+
/** Paginated member product summaries. */
|
|
39
|
+
function listProducts(collectionId: string, lotId: string, opts?: {
|
|
40
|
+
page?: number;
|
|
41
|
+
limit?: number;
|
|
42
|
+
}): Promise<ListLotProductsResponse>;
|
|
43
|
+
function publicList(collectionId: string, params?: ListLotsParams): Promise<Lot[]>;
|
|
44
|
+
function publicGet(collectionId: string, lotId: string): Promise<Lot>;
|
|
45
|
+
function publicGetByNumber(collectionId: string, lotNumber: string): Promise<Lot>;
|
|
46
|
+
function publicListProducts(collectionId: string, lotId: string, opts?: {
|
|
47
|
+
page?: number;
|
|
48
|
+
limit?: number;
|
|
49
|
+
}): Promise<ListLotProductsResponse>;
|
|
50
|
+
}
|
package/dist/api/lots.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// src/api/lots.ts
|
|
2
|
+
import { request, post, put, del } from "../http";
|
|
3
|
+
/**
|
|
4
|
+
* Lots — collection-scoped production groupings that span one or more products.
|
|
5
|
+
* Writes and admin reads hit `/admin/collection/:cid/lots`; the `public*` reads hit
|
|
6
|
+
* `/public/collection/:cid/lots` for cross-app consumers. Admin vs public is the path
|
|
7
|
+
* prefix (auth is the ambient bearer token); there is no `admin` flag in this SDK.
|
|
8
|
+
*/
|
|
9
|
+
export var lots;
|
|
10
|
+
(function (lots) {
|
|
11
|
+
function adminBase(collectionId) {
|
|
12
|
+
return `/admin/collection/${encodeURIComponent(collectionId)}/lots`;
|
|
13
|
+
}
|
|
14
|
+
function publicBase(collectionId) {
|
|
15
|
+
return `/public/collection/${encodeURIComponent(collectionId)}/lots`;
|
|
16
|
+
}
|
|
17
|
+
function listQuery(params = {}) {
|
|
18
|
+
const qs = new URLSearchParams();
|
|
19
|
+
if (params.status)
|
|
20
|
+
qs.append('status', params.status);
|
|
21
|
+
if (params.search)
|
|
22
|
+
qs.append('search', params.search);
|
|
23
|
+
if (params.productId)
|
|
24
|
+
qs.append('productId', params.productId);
|
|
25
|
+
if (params.includeDeleted)
|
|
26
|
+
qs.append('includeDeleted', 'true');
|
|
27
|
+
const s = qs.toString();
|
|
28
|
+
return s ? `?${s}` : '';
|
|
29
|
+
}
|
|
30
|
+
function pageQuery(opts = {}) {
|
|
31
|
+
const qs = new URLSearchParams();
|
|
32
|
+
if (opts.page)
|
|
33
|
+
qs.append('page', String(opts.page));
|
|
34
|
+
if (opts.limit)
|
|
35
|
+
qs.append('limit', String(opts.limit));
|
|
36
|
+
const s = qs.toString();
|
|
37
|
+
return s ? `?${s}` : '';
|
|
38
|
+
}
|
|
39
|
+
// ── Admin (writes + admin reads) ──
|
|
40
|
+
/** Create a lot (resolves its selector into members). */
|
|
41
|
+
async function create(collectionId, lot) {
|
|
42
|
+
return post(adminBase(collectionId), lot);
|
|
43
|
+
}
|
|
44
|
+
lots.create = create;
|
|
45
|
+
/** List lots (summary rows; `payload`/`productIds` omitted). Filter by status, search, or containing productId. */
|
|
46
|
+
async function list(collectionId, params = {}) {
|
|
47
|
+
const res = await request(`${adminBase(collectionId)}${listQuery(params)}`);
|
|
48
|
+
return res.lots;
|
|
49
|
+
}
|
|
50
|
+
lots.list = list;
|
|
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}`);
|
|
55
|
+
}
|
|
56
|
+
lots.get = get;
|
|
57
|
+
/** Look up a lot by its number (case-insensitive) — used by scan/resolver flows. */
|
|
58
|
+
async function getByNumber(collectionId, lotNumber, opts = {}) {
|
|
59
|
+
const qs = opts.includeDeleted ? '?includeDeleted=true' : '';
|
|
60
|
+
return request(`${adminBase(collectionId)}/by-number/${encodeURIComponent(lotNumber)}${qs}`);
|
|
61
|
+
}
|
|
62
|
+
lots.getByNumber = getByNumber;
|
|
63
|
+
/** Update a lot. Re-resolves members if the selector changed (response then carries `diff`). */
|
|
64
|
+
async function update(collectionId, lotId, lot) {
|
|
65
|
+
return put(`${adminBase(collectionId)}/${encodeURIComponent(lotId)}`, lot);
|
|
66
|
+
}
|
|
67
|
+
lots.update = update;
|
|
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) {
|
|
73
|
+
return del(`${adminBase(collectionId)}/${encodeURIComponent(lotId)}`);
|
|
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
|
+
}
|
|
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;
|
|
86
|
+
/** Re-resolve members from the current selector; returns the lot + a member diff. */
|
|
87
|
+
async function resolve(collectionId, lotId) {
|
|
88
|
+
return post(`${adminBase(collectionId)}/${encodeURIComponent(lotId)}/resolve`, {});
|
|
89
|
+
}
|
|
90
|
+
lots.resolve = resolve;
|
|
91
|
+
/** Paginated member product summaries. */
|
|
92
|
+
async function listProducts(collectionId, lotId, opts = {}) {
|
|
93
|
+
return request(`${adminBase(collectionId)}/${encodeURIComponent(lotId)}/products${pageQuery(opts)}`);
|
|
94
|
+
}
|
|
95
|
+
lots.listProducts = listProducts;
|
|
96
|
+
// ── Public (cross-app reads) ──
|
|
97
|
+
async function publicList(collectionId, params = {}) {
|
|
98
|
+
const res = await request(`${publicBase(collectionId)}${listQuery(params)}`);
|
|
99
|
+
return res.lots;
|
|
100
|
+
}
|
|
101
|
+
lots.publicList = publicList;
|
|
102
|
+
async function publicGet(collectionId, lotId) {
|
|
103
|
+
return request(`${publicBase(collectionId)}/${encodeURIComponent(lotId)}`);
|
|
104
|
+
}
|
|
105
|
+
lots.publicGet = publicGet;
|
|
106
|
+
async function publicGetByNumber(collectionId, lotNumber) {
|
|
107
|
+
return request(`${publicBase(collectionId)}/by-number/${encodeURIComponent(lotNumber)}`);
|
|
108
|
+
}
|
|
109
|
+
lots.publicGetByNumber = publicGetByNumber;
|
|
110
|
+
async function publicListProducts(collectionId, lotId, opts = {}) {
|
|
111
|
+
return request(`${publicBase(collectionId)}/${encodeURIComponent(lotId)}/products${pageQuery(opts)}`);
|
|
112
|
+
}
|
|
113
|
+
lots.publicListProducts = publicListProducts;
|
|
114
|
+
})(lots || (lots = {}));
|
package/dist/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.16.1 | Generated: 2026-09-01T15:57:41.258Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -35,6 +35,7 @@ For detailed guides on specific features:
|
|
|
35
35
|
- **[Proof Claiming Methods](proof-claiming-methods.md)** - All methods for claiming/registering product ownership (NFC tags, serial numbers, auto-generated claims)
|
|
36
36
|
- **[Proof Share Grants](proof-share-grants.md)** - Delegated, scoped, revocable bearer access to a single proof (read/comment/verify-owner links)
|
|
37
37
|
- **[Proof Ownership Transfer](proof-ownership-transfer.md)** - Moving a proof to a new owner: directed transfer, open release, accept/cancel, and the state machine
|
|
38
|
+
- **[Lots](lots.md)** - Collection-scoped production groupings spanning many SKUs; facet/product selectors, member resolution, and GS1 AI(10) batch-then-lot resolution
|
|
38
39
|
- **[Item Context](item-context.md)** - The `itemContext` container prop derived from a serial-proof URL or NFC tap (what item the URL points at)
|
|
39
40
|
- **[Product Facets SDK](PRODUCT_FACETS_SDK.md)** - Admin and public product facet endpoints and TypeScript interfaces
|
|
40
41
|
- **[Attestations](attestations.md)** - Append-only fact log with cryptographic chain integrity, time-series analytics, and public/owner/admin visibility
|
|
@@ -135,6 +136,7 @@ The Smartlinks SDK is organized into the following namespaces:
|
|
|
135
136
|
- **jobs** - Functions for jobs operations
|
|
136
137
|
- **journeysAnalytics** - Functions for journeysAnalytics operations
|
|
137
138
|
- **location** - Functions for location operations
|
|
139
|
+
- **lots** - Functions for lots operations
|
|
138
140
|
- **navigation** - Functions for navigation operations
|
|
139
141
|
- **order** - Functions for order operations
|
|
140
142
|
- **products** - Functions for products operations
|
|
@@ -3056,6 +3058,63 @@ interface AccountInfoResponse {
|
|
|
3056
3058
|
|
|
3057
3059
|
### authKit
|
|
3058
3060
|
|
|
3061
|
+
**AuthTelemetryEvent** (interface)
|
|
3062
|
+
```typescript
|
|
3063
|
+
interface AuthTelemetryEvent {
|
|
3064
|
+
eventId: string
|
|
3065
|
+
correlationId: string
|
|
3066
|
+
clientId: string
|
|
3067
|
+
collectionId?: string
|
|
3068
|
+
type: AuthEventType
|
|
3069
|
+
flow: AuthFlow
|
|
3070
|
+
ts: string
|
|
3071
|
+
durationMs?: number
|
|
3072
|
+
outcome?: 'success' | 'error' | 'stalled' | 'abandoned'
|
|
3073
|
+
error?: {
|
|
3074
|
+
code?: string
|
|
3075
|
+
statusCode?: number
|
|
3076
|
+
message?: string
|
|
3077
|
+
name?: string
|
|
3078
|
+
stack?: string
|
|
3079
|
+
endpoint?: string
|
|
3080
|
+
}
|
|
3081
|
+
context: {
|
|
3082
|
+
sdkVersion: string
|
|
3083
|
+
authKitVersion: string
|
|
3084
|
+
mode: 'standalone' | 'embedded' | 'proxy' | 'native'
|
|
3085
|
+
route?: string
|
|
3086
|
+
deepLinkMode?: string
|
|
3087
|
+
userAgent: string
|
|
3088
|
+
platform?: string
|
|
3089
|
+
language?: string
|
|
3090
|
+
online: boolean
|
|
3091
|
+
viewport?: { w: number; h: number }
|
|
3092
|
+
darkMode?: boolean
|
|
3093
|
+
}
|
|
3094
|
+
subject?: { uid?: string; emailHash?: string }
|
|
3095
|
+
}
|
|
3096
|
+
```
|
|
3097
|
+
|
|
3098
|
+
**TelemetryIngestResponse** (interface)
|
|
3099
|
+
```typescript
|
|
3100
|
+
interface TelemetryIngestResponse {
|
|
3101
|
+
accepted: number
|
|
3102
|
+
rejected: number
|
|
3103
|
+
rejectedIds: string[]
|
|
3104
|
+
}
|
|
3105
|
+
```
|
|
3106
|
+
|
|
3107
|
+
**AuthKitTelemetryConfig** (interface)
|
|
3108
|
+
```typescript
|
|
3109
|
+
interface AuthKitTelemetryConfig {
|
|
3110
|
+
enabled?: boolean
|
|
3111
|
+
successSampleRate?: number
|
|
3112
|
+
captureJsErrors?: boolean
|
|
3113
|
+
stallThresholdMs?: number
|
|
3114
|
+
retentionDays?: number
|
|
3115
|
+
}
|
|
3116
|
+
```
|
|
3117
|
+
|
|
3059
3118
|
**AuthKitUser** (interface)
|
|
3060
3119
|
```typescript
|
|
3061
3120
|
interface AuthKitUser {
|
|
@@ -3519,6 +3578,10 @@ interface AuthKitLockoutPolicy {
|
|
|
3519
3578
|
}
|
|
3520
3579
|
```
|
|
3521
3580
|
|
|
3581
|
+
**AuthEventType** = ``
|
|
3582
|
+
|
|
3583
|
+
**AuthFlow** = ``
|
|
3584
|
+
|
|
3522
3585
|
**RefreshErrorCode** = ``
|
|
3523
3586
|
|
|
3524
3587
|
**AuthKitErrorCode** = ``
|
|
@@ -6355,6 +6418,122 @@ interface LocationSearchResponse {
|
|
|
6355
6418
|
|
|
6356
6419
|
**LocationPayload** = `Omit<`
|
|
6357
6420
|
|
|
6421
|
+
### lots
|
|
6422
|
+
|
|
6423
|
+
**LotPayload** (interface)
|
|
6424
|
+
```typescript
|
|
6425
|
+
interface LotPayload {
|
|
6426
|
+
manufacturedAt?: string | null
|
|
6427
|
+
expiresAt?: string | null
|
|
6428
|
+
location?: string | null
|
|
6429
|
+
custom?: Record<string, any>
|
|
6430
|
+
[key: string]: any
|
|
6431
|
+
}
|
|
6432
|
+
```
|
|
6433
|
+
|
|
6434
|
+
**Lot** (interface)
|
|
6435
|
+
```typescript
|
|
6436
|
+
interface Lot {
|
|
6437
|
+
id: string
|
|
6438
|
+
collectionId: string
|
|
6439
|
+
lotNumber: string
|
|
6440
|
+
name?: string | null
|
|
6441
|
+
description?: string | null
|
|
6442
|
+
status: LotStatus
|
|
6443
|
+
selector: LotSelector
|
|
6444
|
+
payload?: LotPayload
|
|
6445
|
+
destination?: Record<string, any> | null
|
|
6446
|
+
productCount: number
|
|
6447
|
+
productIds?: string[]
|
|
6448
|
+
resolvedAt?: string | null
|
|
6449
|
+
createdBy?: string | null
|
|
6450
|
+
updatedBy?: string | null
|
|
6451
|
+
createdAt: string
|
|
6452
|
+
updatedAt: string
|
|
6453
|
+
deletedAt?: string | null
|
|
6454
|
+
}
|
|
6455
|
+
```
|
|
6456
|
+
|
|
6457
|
+
**LotCreateInput** (interface)
|
|
6458
|
+
```typescript
|
|
6459
|
+
interface LotCreateInput {
|
|
6460
|
+
lotNumber: string
|
|
6461
|
+
name?: string
|
|
6462
|
+
description?: string
|
|
6463
|
+
selector?: LotSelector
|
|
6464
|
+
payload?: LotPayload
|
|
6465
|
+
destination?: Record<string, any> | null
|
|
6466
|
+
status?: LotStatus
|
|
6467
|
+
id?: string
|
|
6468
|
+
}
|
|
6469
|
+
```
|
|
6470
|
+
|
|
6471
|
+
**ListLotsParams** (interface)
|
|
6472
|
+
```typescript
|
|
6473
|
+
interface ListLotsParams {
|
|
6474
|
+
status?: LotStatus
|
|
6475
|
+
search?: string
|
|
6476
|
+
productId?: string
|
|
6477
|
+
includeDeleted?: boolean
|
|
6478
|
+
}
|
|
6479
|
+
```
|
|
6480
|
+
|
|
6481
|
+
**ListLotsResponse** (interface)
|
|
6482
|
+
```typescript
|
|
6483
|
+
interface ListLotsResponse {
|
|
6484
|
+
lots: Lot[]
|
|
6485
|
+
}
|
|
6486
|
+
```
|
|
6487
|
+
|
|
6488
|
+
**LotMemberDiff** (interface)
|
|
6489
|
+
```typescript
|
|
6490
|
+
interface LotMemberDiff {
|
|
6491
|
+
added: string[]; removed: string[]
|
|
6492
|
+
}
|
|
6493
|
+
```
|
|
6494
|
+
|
|
6495
|
+
**ResolveLotResponse** (interface)
|
|
6496
|
+
```typescript
|
|
6497
|
+
interface ResolveLotResponse {
|
|
6498
|
+
lot: Lot; diff: LotMemberDiff
|
|
6499
|
+
}
|
|
6500
|
+
```
|
|
6501
|
+
|
|
6502
|
+
**LotProductSummary** (interface)
|
|
6503
|
+
```typescript
|
|
6504
|
+
interface LotProductSummary {
|
|
6505
|
+
id: string; name?: string; gtin?: string | null
|
|
6506
|
+
}
|
|
6507
|
+
```
|
|
6508
|
+
|
|
6509
|
+
**ListLotProductsResponse** (interface)
|
|
6510
|
+
```typescript
|
|
6511
|
+
interface ListLotProductsResponse {
|
|
6512
|
+
products: LotProductSummary[]
|
|
6513
|
+
total: number
|
|
6514
|
+
page: number
|
|
6515
|
+
limit: number
|
|
6516
|
+
}
|
|
6517
|
+
```
|
|
6518
|
+
|
|
6519
|
+
**LotResolutionResult** (interface)
|
|
6520
|
+
```typescript
|
|
6521
|
+
interface LotResolutionResult {
|
|
6522
|
+
match: 'batch' | 'lot' | 'product' | 'none'
|
|
6523
|
+
productId: string
|
|
6524
|
+
batchId: string | null
|
|
6525
|
+
lotId: string | null
|
|
6526
|
+
ai10: string | null
|
|
6527
|
+
destination?: any
|
|
6528
|
+
}
|
|
6529
|
+
```
|
|
6530
|
+
|
|
6531
|
+
**LotStatus** = `'open' | 'closed' | 'recalled' | 'archived'`
|
|
6532
|
+
|
|
6533
|
+
**LotSelector** = ``
|
|
6534
|
+
|
|
6535
|
+
**LotUpdateInput** = `Partial<LotCreateInput>`
|
|
6536
|
+
|
|
6358
6537
|
### loyalty
|
|
6359
6538
|
|
|
6360
6539
|
**LoyaltyScheme** (interface)
|
|
@@ -7329,6 +7508,9 @@ interface Proof {
|
|
|
7329
7508
|
productId: string
|
|
7330
7509
|
tokenId: string
|
|
7331
7510
|
userId: string
|
|
7511
|
+
batchId?: string | null
|
|
7512
|
+
variantId?: string | null
|
|
7513
|
+
lotId?: string | null
|
|
7332
7514
|
claimable?: boolean
|
|
7333
7515
|
virtual?: boolean
|
|
7334
7516
|
data?: Record<string, JsonValue>
|
|
@@ -9771,6 +9953,50 @@ Public: Fetch a global location by ID GET /public/location/:locationId
|
|
|
9771
9953
|
locationId: string) → `Promise<Location>`
|
|
9772
9954
|
Public: Fetch a location for a collection; returns either a collection-owned or global fallback GET /public/collection/:collectionId/location/:locationId
|
|
9773
9955
|
|
|
9956
|
+
### lots
|
|
9957
|
+
|
|
9958
|
+
**create**(collectionId: string, lot: LotCreateInput) → `Promise<Lot>`
|
|
9959
|
+
Create a lot (resolves its selector into members).
|
|
9960
|
+
|
|
9961
|
+
**list**(collectionId: string, params: ListLotsParams = {}) → `Promise<Lot[]>`
|
|
9962
|
+
List lots (summary rows; `payload`/`productIds` omitted). Filter by status, search, or containing productId.
|
|
9963
|
+
|
|
9964
|
+
**get**(collectionId: string, lotId: string, opts: { includeDeleted?: boolean } = {}) → `Promise<Lot>`
|
|
9965
|
+
Get the full lot record. Pass `{ includeDeleted: true }` to fetch a soft-deleted one.
|
|
9966
|
+
|
|
9967
|
+
**getByNumber**(collectionId: string, lotNumber: string, opts: { includeDeleted?: boolean } = {}) → `Promise<Lot>`
|
|
9968
|
+
Look up a lot by its number (case-insensitive) — used by scan/resolver flows.
|
|
9969
|
+
|
|
9970
|
+
**update**(collectionId: string, lotId: string, lot: LotUpdateInput) → `Promise<Lot>`
|
|
9971
|
+
Update a lot. Re-resolves members if the selector changed (response then carries `diff`).
|
|
9972
|
+
|
|
9973
|
+
**remove**(collectionId: string, lotId: string) → `Promise<`
|
|
9974
|
+
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}.
|
|
9975
|
+
|
|
9976
|
+
**archive**(collectionId: string, lotId: string) → `Promise<`
|
|
9977
|
+
Archive a lot — a live lifecycle state (stays visible, keeps its number). Not a delete.
|
|
9978
|
+
|
|
9979
|
+
**restore**(collectionId: string, lotId: string) → `Promise<Lot>`
|
|
9980
|
+
Restore a soft-deleted lot. Rejects (409) if a live lot now uses the same number.
|
|
9981
|
+
|
|
9982
|
+
**resolve**(collectionId: string, lotId: string) → `Promise<ResolveLotResponse>`
|
|
9983
|
+
Re-resolve members from the current selector; returns the lot + a member diff.
|
|
9984
|
+
|
|
9985
|
+
**listProducts**(collectionId: string, lotId: string, opts: { page?: number; limit?: number } = {}) → `Promise<ListLotProductsResponse>`
|
|
9986
|
+
Paginated member product summaries.
|
|
9987
|
+
|
|
9988
|
+
**publicList**(collectionId: string, params: ListLotsParams = {}) → `Promise<Lot[]>`
|
|
9989
|
+
Paginated member product summaries.
|
|
9990
|
+
|
|
9991
|
+
**publicGet**(collectionId: string, lotId: string) → `Promise<Lot>`
|
|
9992
|
+
Paginated member product summaries.
|
|
9993
|
+
|
|
9994
|
+
**publicGetByNumber**(collectionId: string, lotNumber: string) → `Promise<Lot>`
|
|
9995
|
+
Paginated member product summaries.
|
|
9996
|
+
|
|
9997
|
+
**publicListProducts**(collectionId: string, lotId: string, opts: { page?: number; limit?: number } = {}) → `Promise<ListLotProductsResponse>`
|
|
9998
|
+
Paginated member product summaries.
|
|
9999
|
+
|
|
9774
10000
|
### loyalty
|
|
9775
10001
|
|
|
9776
10002
|
Loyalty programmes built on top of collections. Configure schemes and earning rules; contacts earn points automatically via interaction events. See the [Loyalty guide](loyalty.md) for the full walkthrough.
|
package/dist/docs/appConfig.md
CHANGED
|
@@ -298,8 +298,9 @@ about:
|
|
|
298
298
|
| `hub` | The Hub module. |
|
|
299
299
|
| `portal` | QR code scan portals. |
|
|
300
300
|
| `virtualItems` | Virtual items — algorithmic per-item IDs with no persistent row (battery serials, scan-to-collect points, bulk QR sheets). Replaces the old root-level `virtualItemsEnabled` boolean, which has been removed (§8) — resolve this like any other feature flag, not as a separate config key. Independent of `itemRecordMode`. |
|
|
301
|
-
| `batches` | Batch support. Used to be the `Collection.batches` boolean; that field has been removed — this flag is now the only source of truth. |
|
|
301
|
+
| `batches` | Batch support. Used to be the `Collection.batches` boolean; that field has been removed — this flag is now the only source of truth. Also gates AI(10) **batch** resolution on a GS1 Digital Link scan (§ see `lots.md`). |
|
|
302
302
|
| `variants` | Variant support. Used to be the `Collection.variants` boolean; that field has been removed — this flag is now the only source of truth. |
|
|
303
|
+
| `lots` | Lot support — collection-scoped production groupings spanning many SKUs (see `lots.md`). Gates AI(10) **lot** resolution on a GS1 Digital Link scan. Independent of `batches`; when both are on, a scanned AI(10) value resolves batch-first (specific SKU) then lot (broad). |
|
|
303
304
|
|
|
304
305
|
Same resolution rule as any flag (§4.4) — don't read these off
|
|
305
306
|
`cfg.system.features` directly, always go through `isFeatureEnabled()`.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Lots
|
|
2
|
+
|
|
3
|
+
A **Lot** is a collection-scoped production grouping that spans one or more products
|
|
4
|
+
(SKUs) — a single identifier applied across many SKUs and/or many production runs. It's
|
|
5
|
+
the right tool when a manufacturer wants one lot number (e.g. `LOT-2026-09`) across a whole
|
|
6
|
+
range, rather than a per-product **batch** (a single run of a single product).
|
|
7
|
+
|
|
8
|
+
Lots are a first-class entity (not app records): cross-app readable, admin-written, with a
|
|
9
|
+
real lifecycle. They are **never fanned out into batches** — the lot is the single source of
|
|
10
|
+
truth for its shared data.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Concepts
|
|
15
|
+
|
|
16
|
+
- **Selector** — how member products are matched. Two modes:
|
|
17
|
+
- `{ mode: 'facets', rules: [{ key, values }] }` — AND across rules, OR within a rule's values (resolved against the facet index, so it scales to thousands of SKUs).
|
|
18
|
+
- `{ mode: 'products', productIds: [...] }` — an explicit list.
|
|
19
|
+
- **`productIds` / `productCount`** — the materialised snapshot of resolved members (re-resolved on create, on selector change, and on demand via `resolve`).
|
|
20
|
+
- **`payload`** — shared lot data (dates, supplier ref, custom fields). Lives only on the lot.
|
|
21
|
+
- **`status`** — `open` → `closed` → `recalled` → `archived`. A live lifecycle state, distinct from deletion.
|
|
22
|
+
- **`destination`** — optional lot-level redirect; wins over the product's on a lot-scoped scan.
|
|
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
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## SDK — `SL.lots.*`
|
|
40
|
+
|
|
41
|
+
Writes and admin reads hit `/admin/collection/:cid/lots`; the `public*` reads hit
|
|
42
|
+
`/public/collection/:cid/lots` for cross-app consumers (auth is the ambient bearer token —
|
|
43
|
+
there's no `admin` flag).
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { lots } from '@proveanything/smartlinks'
|
|
47
|
+
|
|
48
|
+
// Create — facet-targeted lot
|
|
49
|
+
const lot = await lots.create(collectionId, {
|
|
50
|
+
lotNumber: 'LOT-2026-09',
|
|
51
|
+
name: 'September Oak run',
|
|
52
|
+
selector: { mode: 'facets', rules: [
|
|
53
|
+
{ key: 'supplier', values: ['Acme Timber'] },
|
|
54
|
+
{ key: 'range', values: ['Oslo', 'Bergen'] },
|
|
55
|
+
]},
|
|
56
|
+
payload: { manufacturedAt: '2026-09-01', custom: { supplierBatchRef: 'ACM-7741' } },
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const list = await lots.list(collectionId, { status: 'open' })
|
|
60
|
+
const byId = await lots.get(collectionId, lot.id)
|
|
61
|
+
const byNumber = await lots.getByNumber(collectionId, 'LOT-2026-09') // case-insensitive
|
|
62
|
+
const containing = await lots.list(collectionId, { productId: 'prd_abc' }) // reverse lookup
|
|
63
|
+
const updated = await lots.update(collectionId, lot.id, { status: 'closed' })
|
|
64
|
+
const { diff } = await lots.resolve(collectionId, lot.id) // { added, removed }
|
|
65
|
+
const members = await lots.listProducts(collectionId, lot.id, { page: 1, limit: 50 })
|
|
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
|
|
71
|
+
|
|
72
|
+
// Cross-app reads
|
|
73
|
+
const publicLots = await lots.publicList(collectionId)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Exported types: `Lot`, `LotStatus`, `LotSelector`, `LotPayload`, `LotCreateInput`,
|
|
77
|
+
`LotUpdateInput`, `ListLotsParams`, `ResolveLotResponse`, `ListLotProductsResponse`,
|
|
78
|
+
`LotResolutionResult`.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## GS1 Digital Link resolution — AI(10)
|
|
83
|
+
|
|
84
|
+
GS1 gives batch and lot a **single** slot: AI(10) ("Batch or Lot Number"), in a Digital Link
|
|
85
|
+
as `/01/{gtin}/10/{value}`. A physical code carries exactly one value there, so the server
|
|
86
|
+
decides which namespace it belongs to, driven by two **feature flags** — `batches` and `lots`
|
|
87
|
+
— in the platform feature-flag system (`appConfig.system.features`), resolved the standard way
|
|
88
|
+
(`appConfiguration.isFeatureEnabled(collectionId, 'lots')`):
|
|
89
|
+
|
|
90
|
+
- Explicit `true`/`false` in `system.features` wins; otherwise **enterprise** accounts default
|
|
91
|
+
a flag on and everyone else defaults off. So AI(10) batch/lot resolution is opt-in — no
|
|
92
|
+
existing scan changes until `batches`/`lots` is enabled for the collection.
|
|
93
|
+
|
|
94
|
+
Resolution order — **batch first, then lot** (a hierarchy, not a collision):
|
|
95
|
+
|
|
96
|
+
1. **Batch** is the narrowest scope (one product). If the scanned product has a batch whose id
|
|
97
|
+
or name matches the AI(10) value, it wins — a batch is a **specific-SKU override**.
|
|
98
|
+
2. **Lot** is broad (many products). If no batch matches and the value is a lot number *and the
|
|
99
|
+
scanned product is a member*, the lot resolves.
|
|
100
|
+
3. Otherwise it resolves at the product level.
|
|
101
|
+
|
|
102
|
+
This means a range can share one lot code, and a single SKU can be given richer/overriding
|
|
103
|
+
detail by creating a batch with the **same** identifier — the batch simply takes precedence for
|
|
104
|
+
that SKU. A recalled lot (`status: 'recalled'`) still resolves so the destination page can show
|
|
105
|
+
a recall notice (a `&recall=1` context param is added).
|
|
106
|
+
|
|
107
|
+
The server returns a typed shape ({@link LotResolutionResult}); the front end renders it — clients
|
|
108
|
+
should not implement their own fallback.
|
|
109
|
+
|
|
110
|
+
See also [proof-product-data-scoping.md](proof-product-data-scoping.md) and the GS1 link
|
|
111
|
+
generator in [utils.md](utils.md) (`buildGs1DigitalLink`).
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export type { LoginResponse, VerifyTokenResponse, AccountInfoResponse, AuthLocat
|
|
|
10
10
|
export type { UserAccountRegistrationRequest, } from "./types/auth";
|
|
11
11
|
export type { CommunicationEvent, CommsQueryByUser, CommsRecipientIdsQuery, CommsRecipientsWithoutActionQuery, CommsRecipientsWithActionQuery, RecipientId, RecipientWithOutcome, LogCommunicationEventBody, LogBulkCommunicationEventsBody, AppendResult, AppendBulkResult, CommsSettings, TopicConfig, CommsSettingsGetResponse, CommsSettingsPatchBody, CommsPublicTopicsResponse, UnsubscribeQuery, UnsubscribeResponse, CommsConsentUpsertRequest, CommsPreferencesUpsertRequest, CommsSubscribeRequest, CommsSubscribeResponse, CommsSubscriptionCheckQuery, CommsSubscriptionCheckResponse, CommsListMethodsQuery, CommsListMethodsResponse, RegisterEmailMethodRequest, RegisterSmsMethodRequest, RegisterMethodResponse, SubscriptionsResolveRequest, SubscriptionsResolveResponse, } from "./types/comms";
|
|
12
12
|
export type { BatchResponse, BatchCreateRequest, BatchUpdateRequest, } from "./types/batch";
|
|
13
|
+
export type { Lot, LotStatus, LotSelector, LotPayload, LotCreateInput, LotUpdateInput, ListLotsParams, ListLotsResponse, LotMemberDiff, ResolveLotResponse, LotProductSummary, ListLotProductsResponse, LotResolutionResult, } from "./types/lots";
|
|
13
14
|
export type { VariantResponse, VariantCreateRequest, VariantUpdateRequest, } from "./types/variant";
|
|
14
15
|
export type { BroadcastSendRequest } from "./types/broadcasts";
|
|
15
16
|
export type { AppConfigOptions } from "./api/appConfiguration";
|