@proveanything/smartlinks 1.15.24 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -0
- package/dist/api/lots.d.ts +37 -0
- package/dist/api/lots.js +97 -0
- package/dist/docs/API_SUMMARY.md +158 -1
- package/dist/docs/appConfig.md +2 -1
- package/dist/docs/lots.md +94 -0
- package/dist/index.d.ts +1 -0
- package/dist/openapi.yaml +506 -0
- package/dist/types/lots.d.ts +95 -0
- package/dist/types/lots.js +7 -0
- package/dist/types/proof.d.ts +6 -0
- package/docs/API_SUMMARY.md +158 -1
- package/docs/appConfig.md +2 -1
- package/docs/lots.md +94 -0
- package/openapi.yaml +506 -0
- package/package.json +1 -1
package/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.16.0 | Generated: 2026-09-01T12:28:06.435Z
|
|
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
|
|
@@ -6355,6 +6357,120 @@ interface LocationSearchResponse {
|
|
|
6355
6357
|
|
|
6356
6358
|
**LocationPayload** = `Omit<`
|
|
6357
6359
|
|
|
6360
|
+
### lots
|
|
6361
|
+
|
|
6362
|
+
**LotPayload** (interface)
|
|
6363
|
+
```typescript
|
|
6364
|
+
interface LotPayload {
|
|
6365
|
+
manufacturedAt?: string | null
|
|
6366
|
+
expiresAt?: string | null
|
|
6367
|
+
location?: string | null
|
|
6368
|
+
custom?: Record<string, any>
|
|
6369
|
+
[key: string]: any
|
|
6370
|
+
}
|
|
6371
|
+
```
|
|
6372
|
+
|
|
6373
|
+
**Lot** (interface)
|
|
6374
|
+
```typescript
|
|
6375
|
+
interface Lot {
|
|
6376
|
+
id: string
|
|
6377
|
+
collectionId: string
|
|
6378
|
+
lotNumber: string
|
|
6379
|
+
name?: string | null
|
|
6380
|
+
description?: string | null
|
|
6381
|
+
status: LotStatus
|
|
6382
|
+
selector: LotSelector
|
|
6383
|
+
payload?: LotPayload
|
|
6384
|
+
destination?: Record<string, any> | null
|
|
6385
|
+
productCount: number
|
|
6386
|
+
productIds?: string[]
|
|
6387
|
+
resolvedAt?: string | null
|
|
6388
|
+
createdBy?: string | null
|
|
6389
|
+
updatedBy?: string | null
|
|
6390
|
+
createdAt: string
|
|
6391
|
+
updatedAt: string
|
|
6392
|
+
}
|
|
6393
|
+
```
|
|
6394
|
+
|
|
6395
|
+
**LotCreateInput** (interface)
|
|
6396
|
+
```typescript
|
|
6397
|
+
interface LotCreateInput {
|
|
6398
|
+
lotNumber: string
|
|
6399
|
+
name?: string
|
|
6400
|
+
description?: string
|
|
6401
|
+
selector?: LotSelector
|
|
6402
|
+
payload?: LotPayload
|
|
6403
|
+
destination?: Record<string, any> | null
|
|
6404
|
+
status?: LotStatus
|
|
6405
|
+
id?: string
|
|
6406
|
+
}
|
|
6407
|
+
```
|
|
6408
|
+
|
|
6409
|
+
**ListLotsParams** (interface)
|
|
6410
|
+
```typescript
|
|
6411
|
+
interface ListLotsParams {
|
|
6412
|
+
status?: LotStatus
|
|
6413
|
+
search?: string
|
|
6414
|
+
productId?: string
|
|
6415
|
+
}
|
|
6416
|
+
```
|
|
6417
|
+
|
|
6418
|
+
**ListLotsResponse** (interface)
|
|
6419
|
+
```typescript
|
|
6420
|
+
interface ListLotsResponse {
|
|
6421
|
+
lots: Lot[]
|
|
6422
|
+
}
|
|
6423
|
+
```
|
|
6424
|
+
|
|
6425
|
+
**LotMemberDiff** (interface)
|
|
6426
|
+
```typescript
|
|
6427
|
+
interface LotMemberDiff {
|
|
6428
|
+
added: string[]; removed: string[]
|
|
6429
|
+
}
|
|
6430
|
+
```
|
|
6431
|
+
|
|
6432
|
+
**ResolveLotResponse** (interface)
|
|
6433
|
+
```typescript
|
|
6434
|
+
interface ResolveLotResponse {
|
|
6435
|
+
lot: Lot; diff: LotMemberDiff
|
|
6436
|
+
}
|
|
6437
|
+
```
|
|
6438
|
+
|
|
6439
|
+
**LotProductSummary** (interface)
|
|
6440
|
+
```typescript
|
|
6441
|
+
interface LotProductSummary {
|
|
6442
|
+
id: string; name?: string; gtin?: string | null
|
|
6443
|
+
}
|
|
6444
|
+
```
|
|
6445
|
+
|
|
6446
|
+
**ListLotProductsResponse** (interface)
|
|
6447
|
+
```typescript
|
|
6448
|
+
interface ListLotProductsResponse {
|
|
6449
|
+
products: LotProductSummary[]
|
|
6450
|
+
total: number
|
|
6451
|
+
page: number
|
|
6452
|
+
limit: number
|
|
6453
|
+
}
|
|
6454
|
+
```
|
|
6455
|
+
|
|
6456
|
+
**LotResolutionResult** (interface)
|
|
6457
|
+
```typescript
|
|
6458
|
+
interface LotResolutionResult {
|
|
6459
|
+
match: 'batch' | 'lot' | 'product' | 'none'
|
|
6460
|
+
productId: string
|
|
6461
|
+
batchId: string | null
|
|
6462
|
+
lotId: string | null
|
|
6463
|
+
ai10: string | null
|
|
6464
|
+
destination?: any
|
|
6465
|
+
}
|
|
6466
|
+
```
|
|
6467
|
+
|
|
6468
|
+
**LotStatus** = `'open' | 'closed' | 'recalled' | 'archived'`
|
|
6469
|
+
|
|
6470
|
+
**LotSelector** = ``
|
|
6471
|
+
|
|
6472
|
+
**LotUpdateInput** = `Partial<LotCreateInput>`
|
|
6473
|
+
|
|
6358
6474
|
### loyalty
|
|
6359
6475
|
|
|
6360
6476
|
**LoyaltyScheme** (interface)
|
|
@@ -7329,6 +7445,9 @@ interface Proof {
|
|
|
7329
7445
|
productId: string
|
|
7330
7446
|
tokenId: string
|
|
7331
7447
|
userId: string
|
|
7448
|
+
batchId?: string | null
|
|
7449
|
+
variantId?: string | null
|
|
7450
|
+
lotId?: string | null
|
|
7332
7451
|
claimable?: boolean
|
|
7333
7452
|
virtual?: boolean
|
|
7334
7453
|
data?: Record<string, JsonValue>
|
|
@@ -9771,6 +9890,44 @@ Public: Fetch a global location by ID GET /public/location/:locationId
|
|
|
9771
9890
|
locationId: string) → `Promise<Location>`
|
|
9772
9891
|
Public: Fetch a location for a collection; returns either a collection-owned or global fallback GET /public/collection/:collectionId/location/:locationId
|
|
9773
9892
|
|
|
9893
|
+
### lots
|
|
9894
|
+
|
|
9895
|
+
**create**(collectionId: string, lot: LotCreateInput) → `Promise<Lot>`
|
|
9896
|
+
Create a lot (resolves its selector into members).
|
|
9897
|
+
|
|
9898
|
+
**list**(collectionId: string, params: ListLotsParams = {}) → `Promise<Lot[]>`
|
|
9899
|
+
List lots (summary rows; `payload`/`productIds` omitted). Filter by status, search, or containing productId.
|
|
9900
|
+
|
|
9901
|
+
**get**(collectionId: string, lotId: string) → `Promise<Lot>`
|
|
9902
|
+
Get the full lot record.
|
|
9903
|
+
|
|
9904
|
+
**getByNumber**(collectionId: string, lotNumber: string) → `Promise<Lot>`
|
|
9905
|
+
Look up a lot by its number (case-insensitive) — used by scan/resolver flows.
|
|
9906
|
+
|
|
9907
|
+
**update**(collectionId: string, lotId: string, lot: LotUpdateInput) → `Promise<Lot>`
|
|
9908
|
+
Update a lot. Re-resolves members if the selector changed (response then carries `diff`).
|
|
9909
|
+
|
|
9910
|
+
**archive**(collectionId: string, lotId: string) → `Promise<`
|
|
9911
|
+
Soft-archive a lot (never deletes members).
|
|
9912
|
+
|
|
9913
|
+
**resolve**(collectionId: string, lotId: string) → `Promise<ResolveLotResponse>`
|
|
9914
|
+
Re-resolve members from the current selector; returns the lot + a member diff.
|
|
9915
|
+
|
|
9916
|
+
**listProducts**(collectionId: string, lotId: string, opts: { page?: number; limit?: number } = {}) → `Promise<ListLotProductsResponse>`
|
|
9917
|
+
Paginated member product summaries.
|
|
9918
|
+
|
|
9919
|
+
**publicList**(collectionId: string, params: ListLotsParams = {}) → `Promise<Lot[]>`
|
|
9920
|
+
Paginated member product summaries.
|
|
9921
|
+
|
|
9922
|
+
**publicGet**(collectionId: string, lotId: string) → `Promise<Lot>`
|
|
9923
|
+
Paginated member product summaries.
|
|
9924
|
+
|
|
9925
|
+
**publicGetByNumber**(collectionId: string, lotNumber: string) → `Promise<Lot>`
|
|
9926
|
+
Paginated member product summaries.
|
|
9927
|
+
|
|
9928
|
+
**publicListProducts**(collectionId: string, lotId: string, opts: { page?: number; limit?: number } = {}) → `Promise<ListLotProductsResponse>`
|
|
9929
|
+
Paginated member product summaries.
|
|
9930
|
+
|
|
9774
9931
|
### loyalty
|
|
9775
9932
|
|
|
9776
9933
|
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/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()`.
|
package/docs/lots.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
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`. Archiving never deletes anything.
|
|
22
|
+
- **`destination`** — optional lot-level redirect; wins over the product's on a lot-scoped scan.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## SDK — `SL.lots.*`
|
|
27
|
+
|
|
28
|
+
Writes and admin reads hit `/admin/collection/:cid/lots`; the `public*` reads hit
|
|
29
|
+
`/public/collection/:cid/lots` for cross-app consumers (auth is the ambient bearer token —
|
|
30
|
+
there's no `admin` flag).
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { lots } from '@proveanything/smartlinks'
|
|
34
|
+
|
|
35
|
+
// Create — facet-targeted lot
|
|
36
|
+
const lot = await lots.create(collectionId, {
|
|
37
|
+
lotNumber: 'LOT-2026-09',
|
|
38
|
+
name: 'September Oak run',
|
|
39
|
+
selector: { mode: 'facets', rules: [
|
|
40
|
+
{ key: 'supplier', values: ['Acme Timber'] },
|
|
41
|
+
{ key: 'range', values: ['Oslo', 'Bergen'] },
|
|
42
|
+
]},
|
|
43
|
+
payload: { manufacturedAt: '2026-09-01', custom: { supplierBatchRef: 'ACM-7741' } },
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const list = await lots.list(collectionId, { status: 'open' })
|
|
47
|
+
const byId = await lots.get(collectionId, lot.id)
|
|
48
|
+
const byNumber = await lots.getByNumber(collectionId, 'LOT-2026-09') // case-insensitive
|
|
49
|
+
const containing = await lots.list(collectionId, { productId: 'prd_abc' }) // reverse lookup
|
|
50
|
+
const updated = await lots.update(collectionId, lot.id, { status: 'closed' })
|
|
51
|
+
const { diff } = await lots.resolve(collectionId, lot.id) // { added, removed }
|
|
52
|
+
const members = await lots.listProducts(collectionId, lot.id, { page: 1, limit: 50 })
|
|
53
|
+
await lots.archive(collectionId, lot.id)
|
|
54
|
+
|
|
55
|
+
// Cross-app reads
|
|
56
|
+
const publicLots = await lots.publicList(collectionId)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Exported types: `Lot`, `LotStatus`, `LotSelector`, `LotPayload`, `LotCreateInput`,
|
|
60
|
+
`LotUpdateInput`, `ListLotsParams`, `ResolveLotResponse`, `ListLotProductsResponse`,
|
|
61
|
+
`LotResolutionResult`.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## GS1 Digital Link resolution — AI(10)
|
|
66
|
+
|
|
67
|
+
GS1 gives batch and lot a **single** slot: AI(10) ("Batch or Lot Number"), in a Digital Link
|
|
68
|
+
as `/01/{gtin}/10/{value}`. A physical code carries exactly one value there, so the server
|
|
69
|
+
decides which namespace it belongs to, driven by two **feature flags** — `batches` and `lots`
|
|
70
|
+
— in the platform feature-flag system (`appConfig.system.features`), resolved the standard way
|
|
71
|
+
(`appConfiguration.isFeatureEnabled(collectionId, 'lots')`):
|
|
72
|
+
|
|
73
|
+
- Explicit `true`/`false` in `system.features` wins; otherwise **enterprise** accounts default
|
|
74
|
+
a flag on and everyone else defaults off. So AI(10) batch/lot resolution is opt-in — no
|
|
75
|
+
existing scan changes until `batches`/`lots` is enabled for the collection.
|
|
76
|
+
|
|
77
|
+
Resolution order — **batch first, then lot** (a hierarchy, not a collision):
|
|
78
|
+
|
|
79
|
+
1. **Batch** is the narrowest scope (one product). If the scanned product has a batch whose id
|
|
80
|
+
or name matches the AI(10) value, it wins — a batch is a **specific-SKU override**.
|
|
81
|
+
2. **Lot** is broad (many products). If no batch matches and the value is a lot number *and the
|
|
82
|
+
scanned product is a member*, the lot resolves.
|
|
83
|
+
3. Otherwise it resolves at the product level.
|
|
84
|
+
|
|
85
|
+
This means a range can share one lot code, and a single SKU can be given richer/overriding
|
|
86
|
+
detail by creating a batch with the **same** identifier — the batch simply takes precedence for
|
|
87
|
+
that SKU. A recalled lot (`status: 'recalled'`) still resolves so the destination page can show
|
|
88
|
+
a recall notice (a `&recall=1` context param is added).
|
|
89
|
+
|
|
90
|
+
The server returns a typed shape ({@link LotResolutionResult}); the front end renders it — clients
|
|
91
|
+
should not implement their own fallback.
|
|
92
|
+
|
|
93
|
+
See also [proof-product-data-scoping.md](proof-product-data-scoping.md) and the GS1 link
|
|
94
|
+
generator in [utils.md](utils.md) (`buildGs1DigitalLink`).
|