@proveanything/smartlinks 1.7.1 → 1.7.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.
@@ -1,139 +1,141 @@
1
- import { CreateTagRequest, CreateTagResponse, CreateTagsBatchRequest, CreateTagsBatchResponse, UpdateTagRequest, UpdateTagResponse, DeleteTagResponse, GetTagResponse, ListTagsRequest, ListTagsResponse, PublicGetTagRequest, PublicGetTagResponse, PublicBatchLookupRequest, PublicBatchLookupResponse, PublicBatchLookupQueryRequest, PublicBatchLookupQueryResponse, ReverseTagLookupParams, ReverseTagLookupResponse } from "../types/tags";
1
+ import type { TagIndexEntry, CreateTagRequest, CreateTagResponse, BatchCreateTagRequest, BatchCreateResult, UpdateTagRequest, UpdateTagResponse, DeleteTagResponse, GetTagResponse, ListTagsRequest, ListTagsResponse, LookupTagsRequest, LookupTagsQueryRequest, TagLookupResponse, PublicGetTagResponse, ByRefRequest, ByRefResponse, ReverseTagLookupParams, ReverseTagLookupResponse } from "../types/tags";
2
2
  /**
3
3
  * Tag Management API
4
4
  *
5
- * Create mappings between physical tags (NFC tags, QR codes, etc.) and digital proofs.
6
- * Supports automatic serial number generation, batch operations, and public lookups.
5
+ * Manages mappings between physical tag identifiers (NFC UIDs, QR codes, barcodes,
6
+ * etc.) and products, proofs, or any polymorphic object in the platform.
7
+ *
8
+ * ### Two-tier architecture
9
+ * - **Per-org shard** (`tags` table) — full tag data; used for all collection-scoped
10
+ * queries.
11
+ * - **Shared shard** (`tag_index` table) — `tagId → collectionId` routing only; used
12
+ * when the collection is not yet known.
13
+ *
14
+ * 99% of callers will know the collection and should use collection-scoped endpoints
15
+ * directly. Use `resolveTag` only when you have a raw `tagId` and no collection context.
7
16
  */
8
17
  export declare namespace tags {
9
18
  /**
10
- * Create a single tag mapping.
11
- * If proofId is not provided, automatically generates a serial number.
19
+ * Create a single tag mapping (admin).
20
+ *
21
+ * If `productId` is set without `proofId`, a serial number is auto-generated
22
+ * unless `useSerialNumber: true` is explicitly passed.
23
+ * `refType` and `refId` can be set independently of or alongside product/proof.
12
24
  *
13
- * @param collectionId - Identifier of the parent collection
14
- * @param data - Tag creation data
15
- * @returns Promise resolving to a CreateTagResponse object
16
- * @throws ErrorResponse if the request fails
25
+ * @param collectionId - Collection context
26
+ * @param data - Tag creation payload; `tagId` is required
27
+ * @returns The created tag (`wasUpdated: true` when `force=true` triggered an update)
17
28
  *
18
29
  * @example
19
30
  * ```typescript
20
31
  * // Auto-generate serial number
21
32
  * const tag = await tags.create('coll_123', {
22
- * tagId: 'TAG001',
33
+ * tagId: 'NFC-001',
23
34
  * productId: 'prod_456',
24
- * variantId: 'var_789'
35
+ * batchId: 'batch_2026_01',
25
36
  * })
26
37
  *
27
- * // Use explicit proof ID
38
+ * // Explicit proof + polymorphic ref
28
39
  * const tag2 = await tags.create('coll_123', {
29
- * tagId: 'TAG002',
30
- * productId: 'prod_456',
31
- * proofId: 'proof_explicit_123'
40
+ * tagId: 'NFC-002',
41
+ * refType: 'container',
42
+ * refId: 'container-uuid',
32
43
  * })
33
44
  * ```
34
45
  */
35
46
  function create(collectionId: string, data: CreateTagRequest): Promise<CreateTagResponse>;
36
47
  /**
37
- * Create multiple tag mappings efficiently in a batch operation.
38
- * By default, auto-generates serial numbers for all tags without explicit proofId.
39
- * Tags are grouped by product/variant/batch and serial numbers are generated in
40
- * a single transaction per group for optimal performance.
48
+ * Batch-create tags (admin).
41
49
  *
42
- * @param collectionId - Identifier of the parent collection
43
- * @param data - Batch creation data
44
- * @returns Promise resolving to a CreateTagsBatchResponse with summary and results
45
- * @throws ErrorResponse if the request fails
50
+ * Tags with `productId` but no `proofId` automatically get serial numbers.
51
+ * Serial number generation is grouped by `(productId, variantId, batchId)` for
52
+ * efficiency. Partial success is possible — check `results` for individual outcomes.
53
+ *
54
+ * @param collectionId - Collection context
55
+ * @param data - Batch payload; `force` applies to all tags in the batch
56
+ * @returns `BatchCreateResult` with summary and per-tag outcomes
46
57
  *
47
58
  * @example
48
59
  * ```typescript
49
60
  * const result = await tags.createBatch('coll_123', {
50
61
  * tags: [
51
- * { tagId: 'TAG001', productId: 'prod_456', variantId: 'var_789' },
52
- * { tagId: 'TAG002', productId: 'prod_456', variantId: 'var_789' },
53
- * { tagId: 'TAG003', productId: 'prod_456', batchId: 'batch_100' }
54
- * ]
62
+ * { tagId: 'NFC-001', productId: 'prod_456', batchId: 'batch_2026_01' },
63
+ * { tagId: 'NFC-002', productId: 'prod_456', batchId: 'batch_2026_01' },
64
+ * ],
55
65
  * })
56
- *
57
- * console.log(`Created: ${result.summary.created}, Failed: ${result.summary.failed}`)
66
+ * console.log(`Created: ${result.summary.created}, Conflicts: ${result.summary.conflicts}`)
58
67
  * ```
59
68
  */
60
- function createBatch(collectionId: string, data: CreateTagsBatchRequest): Promise<CreateTagsBatchResponse>;
69
+ function createBatch(collectionId: string, data: BatchCreateTagRequest): Promise<BatchCreateResult>;
61
70
  /**
62
- * Update an existing tag mapping.
63
- *
64
- * @param collectionId - Identifier of the parent collection
65
- * @param tagId - Unique tag identifier
66
- * @param data - Update data (only include fields to update)
67
- * @returns Promise resolving to an UpdateTagResponse object
68
- * @throws ErrorResponse if the request fails
71
+ * Get a single tag by `tagId` (admin).
69
72
  *
70
- * @example
71
- * ```typescript
72
- * const updated = await tags.update('coll_123', 'TAG001', {
73
- * variantId: 'var_999',
74
- * metadata: { notes: 'Updated variant' }
75
- * })
76
- * ```
73
+ * @param collectionId - Collection context
74
+ * @param tagId - Physical tag identifier
75
+ * @returns Full `Tag` record
77
76
  */
78
- function update(collectionId: string, tagId: string, data: UpdateTagRequest): Promise<UpdateTagResponse>;
77
+ function get(collectionId: string, tagId: string): Promise<GetTagResponse>;
79
78
  /**
80
- * Delete a tag mapping.
79
+ * Update a tag (admin).
81
80
  *
82
- * @param collectionId - Identifier of the parent collection
83
- * @param tagId - Unique tag identifier
84
- * @returns Promise resolving to a DeleteTagResponse object
85
- * @throws ErrorResponse if the request fails
81
+ * Partial update — only provided fields are changed. `metadata` is
82
+ * deep-merged with the existing value. Pass `refType: null, refId: null`
83
+ * to clear the polymorphic ref.
84
+ *
85
+ * @param collectionId - Collection context
86
+ * @param tagId - Physical tag identifier
87
+ * @param data - Fields to update
88
+ * @returns Updated `Tag`
86
89
  *
87
90
  * @example
88
91
  * ```typescript
89
- * await tags.remove('coll_123', 'TAG001')
92
+ * const updated = await tags.update('coll_123', 'NFC-001', {
93
+ * variantId: 'var_premium',
94
+ * metadata: { notes: 'Updated to premium variant' },
95
+ * })
96
+ *
97
+ * // Clear polymorphic ref
98
+ * await tags.update('coll_123', 'NFC-001', { refType: null, refId: null })
90
99
  * ```
91
100
  */
92
- function remove(collectionId: string, tagId: string): Promise<DeleteTagResponse>;
101
+ function update(collectionId: string, tagId: string, data: UpdateTagRequest): Promise<UpdateTagResponse>;
93
102
  /**
94
- * Get a single tag mapping by tagId.
103
+ * Delete a tag (admin).
95
104
  *
96
- * @param collectionId - Identifier of the parent collection
97
- * @param tagId - Unique tag identifier
98
- * @returns Promise resolving to a GetTagResponse object
99
- * @throws ErrorResponse if the request fails
105
+ * Permanently removes the tag from the per-org shard and the shared index.
100
106
  *
101
- * @example
102
- * ```typescript
103
- * const tag = await tags.get('coll_123', 'TAG001')
104
- * ```
107
+ * @param collectionId - Collection context
108
+ * @param tagId - Physical tag identifier
109
+ * @returns `{ success: true }`
105
110
  */
106
- function get(collectionId: string, tagId: string): Promise<GetTagResponse>;
111
+ function remove(collectionId: string, tagId: string): Promise<DeleteTagResponse>;
107
112
  /**
108
- * List all tags for a collection with optional filters and pagination.
113
+ * List tags with optional filters and pagination (admin).
109
114
  *
110
- * @param collectionId - Identifier of the parent collection
111
- * @param params - Optional query parameters for filtering and pagination
112
- * @returns Promise resolving to a ListTagsResponse object
113
- * @throws ErrorResponse if the request fails
115
+ * @param collectionId - Collection context
116
+ * @param params - Optional filter and pagination params
117
+ * @returns `{ tags: Tag[], limit: number, offset: number }`
114
118
  *
115
119
  * @example
116
120
  * ```typescript
117
- * // List all tags
118
- * const all = await tags.list('coll_123')
121
+ * // All tags for a product
122
+ * const { tags: list } = await tags.list('coll_123', { productId: 'prod_456' })
119
123
  *
120
- * // List with filters
121
- * const filtered = await tags.list('coll_123', {
122
- * productId: 'prod_456',
123
- * variantId: 'var_789',
124
- * limit: 50,
125
- * offset: 0
124
+ * // All tags linked to a container
125
+ * const { tags: linked } = await tags.list('coll_123', {
126
+ * refType: 'container',
127
+ * refId: 'container-uuid',
126
128
  * })
127
129
  * ```
128
130
  */
129
131
  function list(collectionId: string, params?: ListTagsRequest): Promise<ListTagsResponse>;
130
132
  /**
131
- * Reverse lookup find all tags linked to a given app object (admin).
133
+ * Reverse lookup — find all tags linked to a given object (admin).
132
134
  *
133
- * Uses a global cross-shard index keyed on `(orgId, refType, refId)`, so it
134
- * is safe to call without knowing which collection the object belongs to.
135
+ * Uses a compound index on `(orgId, refType, refId)` on the per-org shard.
136
+ * No embed support on the admin side.
135
137
  *
136
- * @param collectionId - Collection context (used for auth scope)
138
+ * @param collectionId - Collection context
137
139
  * @param params - `refType` and `refId` are required
138
140
  * @returns `{ tags: Tag[] }`
139
141
  *
@@ -147,86 +149,112 @@ export declare namespace tags {
147
149
  */
148
150
  function byRef(collectionId: string, params: ReverseTagLookupParams): Promise<ReverseTagLookupResponse>;
149
151
  /**
150
- * Public lookup of a single tag by tagId (global).
151
- * Optionally embed related collection, product, or proof data.
152
- * No authentication required.
152
+ * Global tag resolve — returns `{ tagId, collectionId }` only.
153
+ *
154
+ * Use this **only** when you have a raw `tagId` and do not yet know which
155
+ * collection it belongs to. Queries the shared `tag_index` shard.
156
+ * Once `collectionId` is resolved, call `publicGetByCollection` for full data.
157
+ *
158
+ * > The global `/public/tags/by-ref` endpoint has been removed.
159
+ * > Use the collection-scoped `publicByRef` instead.
153
160
  *
154
- * @param tagId - Unique tag identifier (globally unique)
155
- * @param params - Optional parameters (embed)
156
- * @returns Promise resolving to a PublicGetTagResponse with optional embedded data
157
- * @throws ErrorResponse if the request fails
161
+ * @param tagId - Physical tag identifier
162
+ * @returns `{ tagId, collectionId }` — routing info only, no full tag data
158
163
  *
159
164
  * @example
160
165
  * ```typescript
161
- * // Simple lookup
162
- * const result = await tags.getTag('TAG001')
166
+ * // Step 1: resolve collection
167
+ * const { collectionId } = await tags.resolveTag('NFC-001')
163
168
  *
164
- * // With embedded data
165
- * const withData = await tags.getTag('TAG001', {
166
- * embed: 'collection,product,proof'
167
- * })
168
- * console.log(withData.tag, withData.collection, withData.product, withData.proof)
169
+ * // Step 2: full lookup with embedded data
170
+ * const { tag, embedded } = await tags.publicGetByCollection(
171
+ * collectionId, 'NFC-001', 'product,proof'
172
+ * )
169
173
  * ```
170
174
  */
171
- function getTag(tagId: string, params?: PublicGetTagRequest): Promise<PublicGetTagResponse>;
175
+ function resolveTag(tagId: string): Promise<TagIndexEntry>;
172
176
  /**
173
- * Backward-compat: Public lookup with collectionId parameter (ignored).
174
- * Calls global route under /public/tags/:tagId.
177
+ * Single tag lookup with optional embedded data (public).
178
+ *
179
+ * `GET /public/collection/:collectionId/tags/:tagId?embed=product,proof,container,ref`
180
+ *
181
+ * Supported `embed` values: `'product'`, `'proof'`, `'container'`, `'ref'`
182
+ * (`'collection'` is not supported — the collection is already known from the URL).
183
+ *
184
+ * @param collectionId - Collection context
185
+ * @param tagId - Physical tag identifier
186
+ * @param embed - Optional comma-separated embed string
187
+ * @returns `{ tag: Tag, embedded: TagEmbedded }`
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * const { tag, embedded } = await tags.publicGetByCollection(
192
+ * 'coll_123', 'NFC-001', 'product,proof'
193
+ * )
194
+ * const product = embedded.products?.[tag.productId!]
195
+ * const proof = embedded.proofs?.[tag.proofId!]
196
+ * ```
175
197
  */
176
- function publicGet(_collectionId: string, tagId: string, params?: PublicGetTagRequest): Promise<PublicGetTagResponse>;
198
+ function publicGetByCollection(collectionId: string, tagId: string, embed?: string): Promise<PublicGetTagResponse>;
177
199
  /**
178
- * Public batch lookup of multiple tags in a single request (POST).
179
- * Only returns tags from the specified collection.
180
- * Optionally embed related data. Related data is deduplicated and batch-fetched.
181
- * No authentication required.
200
+ * Batch tag lookup via POST (public).
201
+ *
202
+ * `POST /public/collection/:collectionId/tags/lookup`
182
203
  *
183
- * @param collectionId - Identifier of the collection to search within
184
- * @param data - Request containing array of tagIds and optional embed parameter
185
- * @returns Promise resolving to PublicBatchLookupResponse with deduplicated related data
186
- * @throws ErrorResponse if the request fails
204
+ * Tags not belonging to this collection are filtered out silently.
205
+ * Returns deduplicated embedded objects alongside the tag array.
206
+ *
207
+ * @param collectionId - Collection context
208
+ * @param data - `{ tagIds: string[], embed?: string }`
209
+ * @returns `{ count: number, tags: Tag[], embedded: TagEmbedded }`
187
210
  *
188
211
  * @example
189
212
  * ```typescript
190
- * const result = await tags.publicBatchLookup('coll_123', {
191
- * tagIds: ['TAG001', 'TAG002', 'TAG003'],
192
- * embed: 'collection,product'
213
+ * const { count, tags: list, embedded } = await tags.lookupTags('coll_123', {
214
+ * tagIds: ['NFC-001', 'NFC-002', 'NFC-003'],
215
+ * embed: 'product,proof',
193
216
  * })
194
- *
195
- * // Access tags and deduplicated collections/products
196
- * console.log(result.tags['TAG001'])
197
- * console.log(result.collections)
198
- * console.log(result.products)
199
217
  * ```
200
218
  */
201
- function lookupTags(data: PublicBatchLookupRequest): Promise<PublicBatchLookupResponse>;
219
+ function lookupTags(collectionId: string, data: LookupTagsRequest): Promise<TagLookupResponse>;
202
220
  /**
203
- * Backward-compat: Public batch lookup with collectionId parameter (ignored).
204
- * Calls global route under /public/tags/lookup.
221
+ * Batch tag lookup via GET (public).
222
+ *
223
+ * `GET /public/collection/:collectionId/tags/lookup?tagIds=NFC-001,NFC-002&embed=product`
224
+ *
225
+ * @param collectionId - Collection context
226
+ * @param params - `tagIds` is comma-separated; `embed` is optional
227
+ * @returns `{ count: number, tags: Tag[], embedded: TagEmbedded }`
205
228
  */
206
- function publicBatchLookup(_collectionId: string, data: PublicBatchLookupRequest): Promise<PublicBatchLookupResponse>;
229
+ function lookupTagsQuery(collectionId: string, params: LookupTagsQueryRequest): Promise<TagLookupResponse>;
207
230
  /**
208
- * Public batch lookup of multiple tags using query parameters (GET).
209
- * Only returns tags from the specified collection.
210
- * Alternative to publicBatchLookup for simple GET requests.
211
- * No authentication required.
231
+ * Reverse lookup by ref via GET (public).
232
+ *
233
+ * `GET /public/collection/:collectionId/tags/by-ref?refType=container&refId=<uuid>&embed=ref`
212
234
  *
213
- * @param collectionId - Identifier of the collection to search within
214
- * @param params - Query parameters with comma-separated tagIds and optional embed
215
- * @returns Promise resolving to PublicBatchLookupQueryResponse
216
- * @throws ErrorResponse if the request fails
235
+ * @param collectionId - Collection context
236
+ * @param params - `refType` and `refId` are required; `embed` is optional
237
+ * @returns `{ tags: Tag[], embedded: TagEmbedded }`
217
238
  *
218
239
  * @example
219
240
  * ```typescript
220
- * const result = await tags.publicBatchLookupQuery('coll_123', {
221
- * tagIds: 'TAG001,TAG002,TAG003',
222
- * embed: 'collection'
241
+ * const { tags: linked, embedded } = await tags.publicByRef('coll_123', {
242
+ * refType: 'container',
243
+ * refId: 'container-uuid',
244
+ * embed: 'container',
223
245
  * })
246
+ * const container = embedded.containers?.[containerId]
224
247
  * ```
225
248
  */
226
- function lookupTagsQuery(params: PublicBatchLookupQueryRequest): Promise<PublicBatchLookupQueryResponse>;
249
+ function publicByRef(collectionId: string, params: ReverseTagLookupParams): Promise<ByRefResponse>;
227
250
  /**
228
- * Backward-compat: Public batch lookup (GET) with collectionId parameter (ignored).
229
- * Calls global route under /public/tags/lookup.
251
+ * Reverse lookup by ref via POST (public).
252
+ *
253
+ * `POST /public/collection/:collectionId/tags/by-ref`
254
+ *
255
+ * @param collectionId - Collection context
256
+ * @param data - `{ refType, refId, embed? }`
257
+ * @returns `{ tags: Tag[], embedded: TagEmbedded }`
230
258
  */
231
- function publicBatchLookupQuery(_collectionId: string, params: PublicBatchLookupQueryRequest): Promise<PublicBatchLookupQueryResponse>;
259
+ function publicByRefPost(collectionId: string, data: ByRefRequest): Promise<ByRefResponse>;
232
260
  }