@proveanything/smartlinks 2.1.15 → 2.1.17
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/claimSet.d.ts +9 -1
- package/dist/api/claimSet.js +15 -0
- package/dist/api/errors.d.ts +10 -0
- package/dist/api/errors.js +17 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -0
- package/dist/api/partner.d.ts +7 -1
- package/dist/api/partner.js +9 -0
- package/dist/docs/API_SUMMARY.md +140 -9
- package/dist/docs/app-objects.md +23 -0
- package/dist/docs/server-functions.md +88 -0
- package/dist/docs/tag-ranges.md +29 -0
- package/dist/openapi.yaml +309 -1
- package/dist/testing/index.d.ts +16 -0
- package/dist/testing/index.js +123 -1
- package/dist/types/appManifest.d.ts +87 -0
- package/dist/types/appObjects.d.ts +22 -1
- package/dist/types/claimSet.d.ts +61 -8
- package/dist/types/clientLog.d.ts +46 -0
- package/dist/types/clientLog.js +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/docs/API_SUMMARY.md +140 -9
- package/docs/app-objects.md +23 -0
- package/docs/server-functions.md +88 -0
- package/docs/tag-ranges.md +29 -0
- package/openapi.yaml +309 -1
- package/package.json +1 -1
package/dist/api/claimSet.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ClaimSetScope, ClaimSetRange, CreateClaimSetRangeRequest, UpdateClaimSetRangeRequest, ClaimSetRangeTagsPage, ClaimSetRangeTag, ClaimSetRangeNextTag, ImportClaimSetRangeUidsRequest, ImportClaimSetRangeUidsResponse, AssignClaimSetRangeRequest, AssignClaimSetRangeResponse, ClaimSetRangeFile, UpdateClaimDataRequest, AssignClaimsRequest, CreateClaimSetTagRequest, CreateClaimSetTagResponse, CreateClaimSetRequest, ImportClaimSetTagsRequest, ImportClaimSetTagsResponse } from "../types/index.js";
|
|
1
|
+
import { ClaimSetScope, ClaimSetRange, CreateClaimSetRangeRequest, UpdateClaimSetRangeRequest, ClaimSetRangeTagsPage, ClaimSetRangeTag, ClaimSetRangeNextTag, ImportClaimSetRangeUidsRequest, ImportClaimSetRangeUidsResponse, AssignClaimSetRangeRequest, AddClaimSetRangeMemberRequest, AddClaimSetRangeMemberResponse, CloseClaimSetRangeResponse, AssignClaimSetRangeResponse, ClaimSetRangeFile, UpdateClaimDataRequest, AssignClaimsRequest, CreateClaimSetTagRequest, CreateClaimSetTagResponse, CreateClaimSetRequest, ImportClaimSetTagsRequest, ImportClaimSetTagsResponse } from "../types/index.js";
|
|
2
2
|
export declare namespace claimSet {
|
|
3
3
|
/**
|
|
4
4
|
* Get all claim sets.
|
|
@@ -106,6 +106,14 @@ export declare namespace claimSet {
|
|
|
106
106
|
function update(scope: ClaimSetScope, claimSetId: string, rangeId: string, params: UpdateClaimSetRangeRequest): Promise<ClaimSetRange>;
|
|
107
107
|
/** Finish minting a range that was interrupted. */
|
|
108
108
|
function resume(scope: ClaimSetScope, claimSetId: string, rangeId: string): Promise<ClaimSetRange>;
|
|
109
|
+
/** Close an open range: it becomes a range with the quantity it reached (removed if nothing was minted). */
|
|
110
|
+
function close(scope: ClaimSetScope, claimSetId: string, rangeId: string): Promise<CloseClaimSetRangeResponse>;
|
|
111
|
+
/** Put an existing tag of the set into a group (by code or chip UID), assigning it if a collection is given. */
|
|
112
|
+
function addMember(scope: ClaimSetScope, claimSetId: string, groupId: string, params: AddClaimSetRangeMemberRequest): Promise<AddClaimSetRangeMemberResponse>;
|
|
113
|
+
/** Take a tag out of a group. Its assignment is left as it is. */
|
|
114
|
+
function removeMember(scope: ClaimSetScope, claimSetId: string, groupId: string, code: string): Promise<{
|
|
115
|
+
range: ClaimSetRange;
|
|
116
|
+
}>;
|
|
109
117
|
/** The range's tags in index order, a page at a time (keys: owners/admins only). */
|
|
110
118
|
function tags(scope: ClaimSetScope, claimSetId: string, rangeId: string, options?: {
|
|
111
119
|
from?: number;
|
package/dist/api/claimSet.js
CHANGED
|
@@ -190,6 +190,21 @@ export var claimSet;
|
|
|
190
190
|
return post(`${rangesBase(scope, claimSetId)}/${encodeURIComponent(rangeId)}/resume`, {});
|
|
191
191
|
}
|
|
192
192
|
ranges.resume = resume;
|
|
193
|
+
/** Close an open range: it becomes a range with the quantity it reached (removed if nothing was minted). */
|
|
194
|
+
async function close(scope, claimSetId, rangeId) {
|
|
195
|
+
return post(`${rangesBase(scope, claimSetId)}/${encodeURIComponent(rangeId)}/close`, {});
|
|
196
|
+
}
|
|
197
|
+
ranges.close = close;
|
|
198
|
+
/** Put an existing tag of the set into a group (by code or chip UID), assigning it if a collection is given. */
|
|
199
|
+
async function addMember(scope, claimSetId, groupId, params) {
|
|
200
|
+
return post(`${rangesBase(scope, claimSetId)}/${encodeURIComponent(groupId)}/members`, params);
|
|
201
|
+
}
|
|
202
|
+
ranges.addMember = addMember;
|
|
203
|
+
/** Take a tag out of a group. Its assignment is left as it is. */
|
|
204
|
+
async function removeMember(scope, claimSetId, groupId, code) {
|
|
205
|
+
return del(`${rangesBase(scope, claimSetId)}/${encodeURIComponent(groupId)}/members/${encodeURIComponent(code)}`);
|
|
206
|
+
}
|
|
207
|
+
ranges.removeMember = removeMember;
|
|
193
208
|
/** The range's tags in index order, a page at a time (keys: owners/admins only). */
|
|
194
209
|
async function tags(scope, claimSetId, rangeId, options = {}) {
|
|
195
210
|
const q = new URLSearchParams();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ClientErrorReport } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Report an error an app saw, into the platform's one error log (the same BigQuery error-events table the
|
|
4
|
+
* server writes to). Best effort: never throws into the flow that failed.
|
|
5
|
+
*/
|
|
6
|
+
export declare namespace errors {
|
|
7
|
+
function report(event: ClientErrorReport): Promise<{
|
|
8
|
+
kept: boolean;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { post } from "../http.js";
|
|
2
|
+
/**
|
|
3
|
+
* Report an error an app saw, into the platform's one error log (the same BigQuery error-events table the
|
|
4
|
+
* server writes to). Best effort: never throws into the flow that failed.
|
|
5
|
+
*/
|
|
6
|
+
export var errors;
|
|
7
|
+
(function (errors) {
|
|
8
|
+
async function report(event) {
|
|
9
|
+
try {
|
|
10
|
+
return await post(`/admin/log/error`, event);
|
|
11
|
+
}
|
|
12
|
+
catch (_a) {
|
|
13
|
+
return { kept: false };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
errors.report = report;
|
|
17
|
+
})(errors || (errors = {}));
|
package/dist/api/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export { form } from "./form.js";
|
|
|
11
11
|
export { authKit } from "./authKit.js";
|
|
12
12
|
export { claimSet } from "./claimSet.js";
|
|
13
13
|
export { partner } from "./partner.js";
|
|
14
|
+
export { errors } from "./errors.js";
|
|
14
15
|
export { crate } from "./crate.js";
|
|
15
16
|
export { batch } from "./batch.js";
|
|
16
17
|
export { variant } from "./variant.js";
|
package/dist/api/index.js
CHANGED
|
@@ -13,6 +13,7 @@ export { form } from "./form.js";
|
|
|
13
13
|
export { authKit } from "./authKit.js";
|
|
14
14
|
export { claimSet } from "./claimSet.js";
|
|
15
15
|
export { partner } from "./partner.js";
|
|
16
|
+
export { errors } from "./errors.js";
|
|
16
17
|
export { crate } from "./crate.js";
|
|
17
18
|
export { batch } from "./batch.js";
|
|
18
19
|
export { variant } from "./variant.js";
|
package/dist/api/partner.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Partner, PartnerClaimSet, CreatePartnerClaimSetRequest, PartnerTagHit } from "../types/index.js";
|
|
1
|
+
import { Partner, PartnerClaimSet, CreatePartnerClaimSetRequest, PartnerTagHit, ClientErrorEvent } from "../types/index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Partners: organisations above collections (FanConnect, Zenith Coins, …) that own NFC claim sets and
|
|
4
4
|
* assign their tags into collections their people administer. Partners and their members are set up by
|
|
@@ -21,4 +21,10 @@ export declare namespace partner {
|
|
|
21
21
|
uid?: string;
|
|
22
22
|
code?: string;
|
|
23
23
|
}): Promise<PartnerTagHit[]>;
|
|
24
|
+
/**
|
|
25
|
+
* What phones reported about one chip (errors.report with entityType 'tag'), newest first: a tag that
|
|
26
|
+
* failed to program or register, with the host's NFC log in context. For a chip in the partner's sets,
|
|
27
|
+
* or attempts that named one of them.
|
|
28
|
+
*/
|
|
29
|
+
function tagAttempts(partnerId: string, uid: string): Promise<ClientErrorEvent[]>;
|
|
24
30
|
}
|
package/dist/api/partner.js
CHANGED
|
@@ -42,4 +42,13 @@ export var partner;
|
|
|
42
42
|
return request(`/admin/partner/${encodeURIComponent(partnerId)}/tags/lookup?${q}`);
|
|
43
43
|
}
|
|
44
44
|
partner.lookupTags = lookupTags;
|
|
45
|
+
/**
|
|
46
|
+
* What phones reported about one chip (errors.report with entityType 'tag'), newest first: a tag that
|
|
47
|
+
* failed to program or register, with the host's NFC log in context. For a chip in the partner's sets,
|
|
48
|
+
* or attempts that named one of them.
|
|
49
|
+
*/
|
|
50
|
+
async function tagAttempts(partnerId, uid) {
|
|
51
|
+
return request(`/admin/partner/${encodeURIComponent(partnerId)}/tags/attempts?uid=${encodeURIComponent(uid)}`);
|
|
52
|
+
}
|
|
53
|
+
partner.tagAttempts = tagAttempts;
|
|
45
54
|
})(partner || (partner = {}));
|
package/dist/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.17 | Generated: 2026-11-11T09:04:21.796Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -144,6 +144,7 @@ The Smartlinks SDK is organized into the following namespaces:
|
|
|
144
144
|
- **bookings** - Functions for bookings operations
|
|
145
145
|
- **config** - Functions for config operations
|
|
146
146
|
- **containers** - Functions for containers operations
|
|
147
|
+
- **errors** - Functions for errors operations
|
|
147
148
|
- **facets** - Functions for facets operations
|
|
148
149
|
- **functions** - Functions for functions operations
|
|
149
150
|
- **http** - Functions for http operations
|
|
@@ -2838,11 +2839,46 @@ interface ServerFunctionBookings {
|
|
|
2838
2839
|
}
|
|
2839
2840
|
```
|
|
2840
2841
|
|
|
2842
|
+
**AppHistoryEvent** (interface)
|
|
2843
|
+
```typescript
|
|
2844
|
+
interface AppHistoryEvent {
|
|
2845
|
+
id: string;
|
|
2846
|
+
at: string;
|
|
2847
|
+
type: string;
|
|
2848
|
+
entityId: string | null;
|
|
2849
|
+
data: Record<string, any>;
|
|
2850
|
+
actorType: 'user' | 'contact' | null;
|
|
2851
|
+
actorId: string | null;
|
|
2852
|
+
}
|
|
2853
|
+
```
|
|
2854
|
+
|
|
2855
|
+
**AppHistoryQuery** (interface)
|
|
2856
|
+
```typescript
|
|
2857
|
+
interface AppHistoryQuery {
|
|
2858
|
+
types?: string | string[];
|
|
2859
|
+
entityId?: string;
|
|
2860
|
+
data?: Record<string, string | number | boolean | Array<string | number | boolean>>;
|
|
2861
|
+
from?: string;
|
|
2862
|
+
to?: string;
|
|
2863
|
+
limit?: number;
|
|
2864
|
+
}
|
|
2865
|
+
```
|
|
2866
|
+
|
|
2841
2867
|
**ServerFunctionSl** (interface)
|
|
2842
2868
|
```typescript
|
|
2843
2869
|
interface ServerFunctionSl {
|
|
2844
2870
|
bookings: ServerFunctionBookings;
|
|
2845
|
-
appRecords: {
|
|
2871
|
+
appRecords: {
|
|
2872
|
+
claim(fields: Record<string, any>): Promise<AppRecordClaimResult>;
|
|
2873
|
+
adjust(recordId: string, by: Record<string, number>, opts?: { atLeast?: Record<string, number>; atMost?: Record<string, number> }): Promise<any>;
|
|
2874
|
+
aggregate(params?: import('./appObjects').AggregateRequest): Promise<import('./appObjects').AggregateResponse & Record<string, unknown>>;
|
|
2875
|
+
[method: string]: any;
|
|
2876
|
+
};
|
|
2877
|
+
transaction(ops: RecordTransactionOp[], opts?: { idempotencyKey?: string }): Promise<{ results: any[]; replayed: boolean }>;
|
|
2878
|
+
history: {
|
|
2879
|
+
log(type: string, data?: Record<string, any>, opts?: { entityId?: string }): Promise<{ id: string }>;
|
|
2880
|
+
query(params?: AppHistoryQuery): Promise<AppHistoryEvent[]>;
|
|
2881
|
+
};
|
|
2846
2882
|
counters: ServerFunctionCounters;
|
|
2847
2883
|
tags: { resolve(id: string): Promise<ResolvedTag | null> };
|
|
2848
2884
|
contacts: {
|
|
@@ -3298,6 +3334,8 @@ interface GetCollectionWidgetsOptions {
|
|
|
3298
3334
|
|
|
3299
3335
|
**AppFunctionAuthority** = `'caller' | 'collection'`
|
|
3300
3336
|
|
|
3337
|
+
**RecordTransactionOp** = ``
|
|
3338
|
+
|
|
3301
3339
|
### appObjects
|
|
3302
3340
|
|
|
3303
3341
|
**PaginatedResponse<T>** (interface)
|
|
@@ -3324,9 +3362,12 @@ interface AggregateRequest {
|
|
|
3324
3362
|
created_at?: { gte?: string; lte?: string }
|
|
3325
3363
|
closed_at?: '__notnull__' | { gte?: string; lte?: string } // cases only
|
|
3326
3364
|
expires_at?: { lte?: string } // records only
|
|
3365
|
+
updated_at?: { gte?: string; lte?: string } // records only
|
|
3366
|
+
data?: Record<string, string | number | boolean | Array<string | number | boolean>>
|
|
3367
|
+
dataRange?: Record<string, { gte?: number; gt?: number; lte?: number; lt?: number }>
|
|
3327
3368
|
}
|
|
3328
|
-
groupBy?: string[]
|
|
3329
|
-
metrics?: string[]
|
|
3369
|
+
groupBy?: string[]
|
|
3370
|
+
metrics?: string[]
|
|
3330
3371
|
timeSeriesField?: string // e.g. 'created_at'
|
|
3331
3372
|
timeSeriesInterval?: 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year'
|
|
3332
3373
|
}
|
|
@@ -3335,7 +3376,7 @@ interface AggregateRequest {
|
|
|
3335
3376
|
**AggregateResponse** (interface)
|
|
3336
3377
|
```typescript
|
|
3337
3378
|
interface AggregateResponse {
|
|
3338
|
-
groups?: ({ count
|
|
3379
|
+
groups?: ({ count?: number } & Record<string, unknown>)[]
|
|
3339
3380
|
timeSeries?: ({ bucket: string; count: number } & Record<string, unknown>)[]
|
|
3340
3381
|
count?: number
|
|
3341
3382
|
avg_close_time_seconds?: number
|
|
@@ -5775,10 +5816,11 @@ interface ClaimSetRange {
|
|
|
5775
5816
|
id: string
|
|
5776
5817
|
claimSetId: string
|
|
5777
5818
|
namespace: string
|
|
5819
|
+
kind: ClaimSetRangeKind
|
|
5778
5820
|
name: string
|
|
5779
5821
|
notes: string | null
|
|
5780
|
-
startIndex: number
|
|
5781
|
-
endIndex: number
|
|
5822
|
+
startIndex: number | null
|
|
5823
|
+
endIndex: number | null
|
|
5782
5824
|
quantity: number
|
|
5783
5825
|
tagType: ClaimSetTagType
|
|
5784
5826
|
fulfilment: 'printer' | 'sidekick'
|
|
@@ -5801,8 +5843,9 @@ interface ClaimSetRange {
|
|
|
5801
5843
|
**CreateClaimSetRangeRequest** (interface)
|
|
5802
5844
|
```typescript
|
|
5803
5845
|
interface CreateClaimSetRangeRequest {
|
|
5846
|
+
kind?: ClaimSetRangeKind
|
|
5804
5847
|
name: string
|
|
5805
|
-
quantity
|
|
5848
|
+
quantity?: number
|
|
5806
5849
|
intendedCollectionId?: string
|
|
5807
5850
|
intendedProductId?: string
|
|
5808
5851
|
intendedBatchId?: string
|
|
@@ -5837,6 +5880,8 @@ interface ClaimSetRangeTag {
|
|
|
5837
5880
|
productId: string | null
|
|
5838
5881
|
batchId: string | null
|
|
5839
5882
|
proofId: string | null
|
|
5883
|
+
rangeId: string | null
|
|
5884
|
+
groupId: string | null
|
|
5840
5885
|
programmedAt: string | null
|
|
5841
5886
|
scans: number
|
|
5842
5887
|
}
|
|
@@ -5850,6 +5895,29 @@ interface ClaimSetRangeTagsPage {
|
|
|
5850
5895
|
}
|
|
5851
5896
|
```
|
|
5852
5897
|
|
|
5898
|
+
**AddClaimSetRangeMemberRequest** (interface)
|
|
5899
|
+
```typescript
|
|
5900
|
+
interface AddClaimSetRangeMemberRequest {
|
|
5901
|
+
code?: string
|
|
5902
|
+
uid?: string
|
|
5903
|
+
collectionId?: string
|
|
5904
|
+
productId?: string
|
|
5905
|
+
batchId?: string
|
|
5906
|
+
data?: Record<string, unknown>
|
|
5907
|
+
clear?: boolean
|
|
5908
|
+
}
|
|
5909
|
+
```
|
|
5910
|
+
|
|
5911
|
+
**AddClaimSetRangeMemberResponse** (interface)
|
|
5912
|
+
```typescript
|
|
5913
|
+
interface AddClaimSetRangeMemberResponse {
|
|
5914
|
+
tag: ClaimSetRangeTag
|
|
5915
|
+
range: ClaimSetRange
|
|
5916
|
+
assigned: { changed: number; skipped: Array<{ code: string; index: number | null; reason: 'other_range' | 'has_proof' | 'assigned_elsewhere'; collectionId?: string }> }
|
|
5917
|
+
movedFrom: string | null
|
|
5918
|
+
}
|
|
5919
|
+
```
|
|
5920
|
+
|
|
5853
5921
|
**ImportClaimSetRangeUidsRequest** (interface)
|
|
5854
5922
|
```typescript
|
|
5855
5923
|
interface ImportClaimSetRangeUidsRequest {
|
|
@@ -5939,6 +6007,7 @@ interface PartnerTagHit {
|
|
|
5939
6007
|
set: PartnerClaimSet | null
|
|
5940
6008
|
tag: ClaimSetRangeTag & { url: string | null }
|
|
5941
6009
|
range: ClaimSetRange | null
|
|
6010
|
+
group: ClaimSetRange | null
|
|
5942
6011
|
}
|
|
5943
6012
|
```
|
|
5944
6013
|
|
|
@@ -5958,10 +6027,56 @@ type ClaimSetScope = { collectionId: string }
|
|
|
5958
6027
|
|
|
5959
6028
|
**ClaimSetTagType** = `'ntag424' | 'ntag21x' | 'qr'`
|
|
5960
6029
|
|
|
5961
|
-
**
|
|
6030
|
+
**ClaimSetRangeKind** = `'range' | 'open' | 'group'`
|
|
6031
|
+
|
|
6032
|
+
**ClaimSetRangeStatus** = `'minting' | 'minted' | 'sent' | 'received' | 'assigned' | 'open' | 'group'`
|
|
6033
|
+
|
|
6034
|
+
**CloseClaimSetRangeResponse** = `ClaimSetRange | { id: string`
|
|
5962
6035
|
|
|
5963
6036
|
**ClaimSetImportResult** = ``
|
|
5964
6037
|
|
|
6038
|
+
### clientLog
|
|
6039
|
+
|
|
6040
|
+
**ClientErrorReport** (interface)
|
|
6041
|
+
```typescript
|
|
6042
|
+
interface ClientErrorReport {
|
|
6043
|
+
app?: string
|
|
6044
|
+
appVersion?: string
|
|
6045
|
+
collectionId?: string
|
|
6046
|
+
operation?: string
|
|
6047
|
+
severity?: 'debug' | 'info' | 'warning' | 'error' | 'critical'
|
|
6048
|
+
errorCode?: string
|
|
6049
|
+
errorType?: string
|
|
6050
|
+
message?: string
|
|
6051
|
+
stack?: string
|
|
6052
|
+
entityType?: string
|
|
6053
|
+
entityId?: string
|
|
6054
|
+
labels?: Record<string, unknown>
|
|
6055
|
+
context?: Record<string, unknown>
|
|
6056
|
+
refId?: string
|
|
6057
|
+
correlationId?: string
|
|
6058
|
+
}
|
|
6059
|
+
```
|
|
6060
|
+
|
|
6061
|
+
**ClientErrorEvent** (interface)
|
|
6062
|
+
```typescript
|
|
6063
|
+
interface ClientErrorEvent {
|
|
6064
|
+
id: string
|
|
6065
|
+
time: string
|
|
6066
|
+
event_category: string
|
|
6067
|
+
event_action: string | null
|
|
6068
|
+
log_level: string
|
|
6069
|
+
error_code: string | null
|
|
6070
|
+
error_message: string | null
|
|
6071
|
+
service_name: string | null
|
|
6072
|
+
service_version: string | null
|
|
6073
|
+
collection_id: string | null
|
|
6074
|
+
user_id: string | null
|
|
6075
|
+
labels: Record<string, unknown> | null
|
|
6076
|
+
context: Record<string, unknown> | null
|
|
6077
|
+
}
|
|
6078
|
+
```
|
|
6079
|
+
|
|
5965
6080
|
### collection
|
|
5966
6081
|
|
|
5967
6082
|
**Collection** (interface)
|
|
@@ -12464,6 +12579,15 @@ Name, notes, order details, or a stage move (sent to the printer, received).
|
|
|
12464
12579
|
**resume**(scope: ClaimSetScope, claimSetId: string, rangeId: string) → `Promise<ClaimSetRange>`
|
|
12465
12580
|
Finish minting a range that was interrupted.
|
|
12466
12581
|
|
|
12582
|
+
**close**(scope: ClaimSetScope, claimSetId: string, rangeId: string) → `Promise<CloseClaimSetRangeResponse>`
|
|
12583
|
+
Close an open range: it becomes a range with the quantity it reached (removed if nothing was minted).
|
|
12584
|
+
|
|
12585
|
+
**addMember**(scope: ClaimSetScope, claimSetId: string, groupId: string, params: AddClaimSetRangeMemberRequest) → `Promise<AddClaimSetRangeMemberResponse>`
|
|
12586
|
+
Put an existing tag of the set into a group (by code or chip UID), assigning it if a collection is given.
|
|
12587
|
+
|
|
12588
|
+
**removeMember**(scope: ClaimSetScope, claimSetId: string, groupId: string, code: string) → `Promise<`
|
|
12589
|
+
Take a tag out of a group. Its assignment is left as it is.
|
|
12590
|
+
|
|
12467
12591
|
**tags**(scope: ClaimSetScope, claimSetId: string, rangeId: string,
|
|
12468
12592
|
options: { from?: number; limit?: number; keys?: boolean } = {}) → `Promise<ClaimSetRangeTagsPage>`
|
|
12469
12593
|
The range's tags in index order, a page at a time (keys: owners/admins only).
|
|
@@ -12790,6 +12914,10 @@ Update a crate for a collection (admin only). ```typescript const updated = awai
|
|
|
12790
12914
|
crateId: string) → `Promise<DeleteCrateResponse>`
|
|
12791
12915
|
Delete a crate for a collection (admin only). This performs a soft delete. ```typescript await crate.remove('coll_123', 'crate_abc123') ```
|
|
12792
12916
|
|
|
12917
|
+
### errors
|
|
12918
|
+
|
|
12919
|
+
**report**(event: ClientErrorReport) → `Promise<`
|
|
12920
|
+
|
|
12793
12921
|
### facets
|
|
12794
12922
|
|
|
12795
12923
|
**list**(collectionId: string,
|
|
@@ -13422,6 +13550,9 @@ A new claim set for the partner, on one of its tap domains (owners and admins).
|
|
|
13422
13550
|
**lookupTags**(partnerId: string, query: { uid?: string; code?: string }) → `Promise<PartnerTagHit[]>`
|
|
13423
13551
|
Find a tag across the partner's sets by its chip UID (8 or 14 hex) or its code (printed or bare). Never returns keys.
|
|
13424
13552
|
|
|
13553
|
+
**tagAttempts**(partnerId: string, uid: string) → `Promise<ClientErrorEvent[]>`
|
|
13554
|
+
What phones reported about one chip (errors.report with entityType 'tag'), newest first: a tag that failed to program or register, with the host's NFC log in context. For a chip in the partner's sets, or attempts that named one of them.
|
|
13555
|
+
|
|
13425
13556
|
### podcast
|
|
13426
13557
|
|
|
13427
13558
|
**generate**(collectionId: string,
|
package/dist/docs/app-objects.md
CHANGED
|
@@ -807,6 +807,29 @@ await app.records.upsert(collectionId, appId, {
|
|
|
807
807
|
// customId is stored for later reverse-lookup via ?customId=&sourceSystem=
|
|
808
808
|
```
|
|
809
809
|
|
|
810
|
+
### Totals over data (sum, average, min, max)
|
|
811
|
+
|
|
812
|
+
Records also total the numbers in their `data`, grouped by top-level data keys, with data filters and
|
|
813
|
+
numeric ranges. Stock per location, forecast per SKU:
|
|
814
|
+
|
|
815
|
+
```typescript
|
|
816
|
+
const stock = await app.records.aggregate(collectionId, appId, {
|
|
817
|
+
groupBy: ['data.location'], // up to 5: columns or 'data.<key>'
|
|
818
|
+
metrics: ['count', 'sum:qty', 'min:qty'], // count; sum: / avg: / min: / max: + a data key
|
|
819
|
+
filters: {
|
|
820
|
+
record_type: 'bin',
|
|
821
|
+
data: { warehouse: ['north', 'south'] }, // exact match, one value or any of several
|
|
822
|
+
dataRange: { qty: { gt: 0 } }, // gte / gt / lte / lt, numbers only
|
|
823
|
+
updated_at: { gte: '2026-11-01T00:00:00Z' },
|
|
824
|
+
},
|
|
825
|
+
}, true)
|
|
826
|
+
// stock.groups → [{ 'data.location': 'A1', count: 12, sum_qty: 340, min_qty: 2 }, …]
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
Values that aren't numbers are left out of sums and averages. To CHANGE numbers safely (stock moves,
|
|
830
|
+
counts), use a server function: `ctx.sl.appRecords.adjust` and `ctx.sl.transaction`
|
|
831
|
+
([server-functions.md](server-functions.md)).
|
|
832
|
+
|
|
810
833
|
### Counts by Record Type
|
|
811
834
|
|
|
812
835
|
`aggregate()` returns counts grouped by `record_type` in a single round-trip — no separate endpoint needed:
|
|
@@ -514,6 +514,10 @@ Prefer the platform primitives above over a dependency; when you do need one, pi
|
|
|
514
514
|
| Read ANOTHER app's data (as the caller may see it) | `ctx.sl.app('other-app').data.get()` — caller-authority, this collection, public-filtered, read-only | `sl:data:read` |
|
|
515
515
|
| Guarantee a UNIQUE claim (one entry per tag, one-per-user, idempotency key, a number nobody else holds) | `ctx.sl.appRecords.claim({ …, singletonPer, customId })` → `{ record, created, conflict? }` — see below | `sl:records:write` |
|
|
516
516
|
| Hand out the next number (tickets, order numbers) | `ctx.sl.counters.next('tickets')` — atomic, distinct per caller | `sl:data:write` |
|
|
517
|
+
| Change numbers in a record (stock, counts, balances) without losing updates | `ctx.sl.appRecords.adjust(id, { qty: -5 }, { atLeast: { qty: 0 } })` — in place, conditions checked after the change | `sl:records:write` |
|
|
518
|
+
| Several record writes that land together or not at all (a stock move) | `ctx.sl.transaction([ops], { idempotencyKey })` — see below | `sl:records:write` |
|
|
519
|
+
| Totals: stock per location, forecast per SKU | `ctx.sl.appRecords.aggregate({ groupBy: ['data.location'], metrics: ['sum:qty'] })` | `sl:records:read` |
|
|
520
|
+
| Keep a history of what happened (stock moves, counts) without growing your records | `ctx.sl.history.log('stock.moved', {…})`, or a `log` op in a transaction; read with `ctx.sl.history.query({…})` | `sl:history:write` / `sl:history:read` |
|
|
517
521
|
| Check a tapped tag is real | `ctx.sl.tags.resolve(proofId)` → `{ id, claimSetId, code }` or `null` | `sl:tags:read` |
|
|
518
522
|
| Put a visitor's details on a contact | `ctx.sl.contacts.upsert({ email, firstName, … })` → `{ contactId, created }` (fills empty fields only) | `sl:contacts:write` |
|
|
519
523
|
| Record "they did X" | `ctx.sl.interactions.record({ interactionId, contactId, outcome, metadata })` | `sl:interactions:write` |
|
|
@@ -579,6 +583,90 @@ reads the last value handed out (`null` before the first). Name a new counter to
|
|
|
579
583
|
`customId: String(n)`. If the claim says `conflict: 'customId'`, take `next()` again. A failed or raced
|
|
580
584
|
attempt only leaves a gap — never a duplicate.
|
|
581
585
|
|
|
586
|
+
### `appRecords.adjust(id, by, { atLeast?, atMost? })` — numbers that never lose an update
|
|
587
|
+
|
|
588
|
+
Adds to numbers in a record's `data` in ONE statement, so twenty scanners taking from the same bin at
|
|
589
|
+
once each land: no read-then-write, no lost counts. A missing value counts as 0. `atLeast` / `atMost` are
|
|
590
|
+
checked on the values **after** the change, inside the same statement:
|
|
591
|
+
|
|
592
|
+
```ts
|
|
593
|
+
// Take 5 from bin A — refused (nothing changes) if it would go below zero.
|
|
594
|
+
await ctx.sl.appRecords.adjust(binA, { qty: -5 }, { atLeast: { qty: 0 } })
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
Refusals carry `code`: `NOT_FOUND` (not this app's record in this collection, or deleted), `NOT_A_NUMBER`
|
|
598
|
+
(the key holds something else), `CONDITION_FAILED` (409, with the `current` values). Only top-level data
|
|
599
|
+
keys; a key named only in a condition is checked as it stands.
|
|
600
|
+
|
|
601
|
+
### `transaction(ops, { idempotencyKey? })` — all or nothing
|
|
602
|
+
|
|
603
|
+
Several writes as ONE transaction: every op lands, or none does. The classic: take stock out of bin A,
|
|
604
|
+
put it on order line B, and log the move.
|
|
605
|
+
|
|
606
|
+
```ts
|
|
607
|
+
const { results, replayed } = await ctx.sl.transaction([
|
|
608
|
+
{ op: 'adjust', recordId: binA, by: { qty: -5 }, atLeast: { qty: 0 } },
|
|
609
|
+
{ op: 'adjust', recordId: orderLineB, by: { picked: 5 } },
|
|
610
|
+
{ op: 'create', record: { recordType: 'movement', data: { from: binA, to: orderLineB, qty: 5 } } },
|
|
611
|
+
], { idempotencyKey: scanId })
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
- Ops: `create` (`record`), `update` (`recordId`, `fields`), `adjust` (`recordId`, `by`, `atLeast?`,
|
|
615
|
+
`atMost?`), `delete` (`recordId`), `log` (`type`, `data`, `entityId?`: a history event, see below).
|
|
616
|
+
Up to 50, run in order. This app's records in this collection only.
|
|
617
|
+
- A failing op rolls everything back. The error says which op (`opIndex`) and why (its `code`).
|
|
618
|
+
- Change events and realtime updates go out only after the transaction commits, never for a rollback.
|
|
619
|
+
- **`idempotencyKey`** ("this was already done"): recorded in the same commit, with what was written
|
|
620
|
+
(ids only). The same key again within 7 days doesn't write; it returns those records as they are now,
|
|
621
|
+
with `replayed: true`. So a handheld that retries after a dropped signal never moves stock twice. Two
|
|
622
|
+
calls with one key at the same moment: one commits, the other replays it. A transaction that failed
|
|
623
|
+
leaves its key free, so a retry can still succeed.
|
|
624
|
+
- Use the scan's or the request's own id as the key (one key = one intended change).
|
|
625
|
+
- Browser code never writes stock directly: a warehouse screen calls your function.
|
|
626
|
+
|
|
627
|
+
### `history` — what happened, kept without growing your records
|
|
628
|
+
|
|
629
|
+
Keep **current state** in records (a bin's quantity, an order's status) and **what happened** in the app's
|
|
630
|
+
history: append-only events in SmartLinks' analytics store, kept for good, cheap however many there
|
|
631
|
+
are. Picking every order line for years would bloat records; as history it costs nothing operational.
|
|
632
|
+
|
|
633
|
+
```ts
|
|
634
|
+
// In a transaction: commits with the stock change, or not at all.
|
|
635
|
+
await ctx.sl.transaction([
|
|
636
|
+
{ op: 'adjust', recordId: binA, by: { qty: -5 }, atLeast: { qty: 0 } },
|
|
637
|
+
{ op: 'log', type: 'stock.moved', entityId: binA, data: { sku: 'EDP-50', from: 'A1', to: orderId, qty: 5 } },
|
|
638
|
+
], { idempotencyKey: scanId })
|
|
639
|
+
|
|
640
|
+
// On its own:
|
|
641
|
+
await ctx.sl.history.log('count.taken', { bin: 'A1', counted: 40, expected: 42 }, { entityId: binA })
|
|
642
|
+
|
|
643
|
+
// Reading back: this app's events in this collection, newest first (default last 30 days, max 400).
|
|
644
|
+
const moves = await ctx.sl.history.query({ types: 'stock.moved', entityId: binA, limit: 20 })
|
|
645
|
+
// → [{ id, at, type, entityId, data, actorType, actorId }]
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
- `type`: lowercase letters, digits and `. _ -` (`stock.moved`). `data`: up to 32 KB, so **log a summary**:
|
|
649
|
+
one line for "5 of EDP-50", not five; one line for an RFID count, not one per tag.
|
|
650
|
+
- Delivery takes seconds and is retried until it lands; a logged event is never lost. A query reads the
|
|
651
|
+
analytics store, so expect about a second: right for a history panel, not for a hot path.
|
|
652
|
+
- The person who called your function is recorded as the actor.
|
|
653
|
+
|
|
654
|
+
### `appRecords.aggregate(params)` — totals
|
|
655
|
+
|
|
656
|
+
Counts and sums over your app's records, worked out in the database:
|
|
657
|
+
|
|
658
|
+
```ts
|
|
659
|
+
await ctx.sl.appRecords.aggregate({
|
|
660
|
+
groupBy: ['data.location', 'data.sku'], // columns, or top-level data keys
|
|
661
|
+
metrics: ['count', 'sum:qty'], // sum: / avg: / min: / max: over data numbers
|
|
662
|
+
filters: { record_type: 'bin', data: { warehouse: 'north' }, dataRange: { qty: { gt: 0 } } },
|
|
663
|
+
})
|
|
664
|
+
// → { groups: [{ 'data.location': 'A1', 'data.sku': 'EDP-50', count: 3, sum_qty: 42 }, …] }
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
Non-numbers are ignored by `sum`/`avg`/`min`/`max`. The same request works from the browser through
|
|
668
|
+
`app.records.aggregate` (admin) — see [app-objects.md](app-objects.md).
|
|
669
|
+
|
|
582
670
|
### `tags.resolve(id)` — is this tap real?
|
|
583
671
|
|
|
584
672
|
A tap hands your app the virtual-proof id `<claimSetId>-<code>`. `resolve` returns
|
package/dist/docs/tag-ranges.md
CHANGED
|
@@ -55,6 +55,35 @@ tag without a chip, with its URL and key; write it, then `ranges.recordTag(scope
|
|
|
55
55
|
|
|
56
56
|
To find where a chip or code went, `partner.lookupTags(partner.id, { uid })` or `{ code }` searches every set the partner owns and returns each hit's set, tag and range, never a key.
|
|
57
57
|
|
|
58
|
+
## Open ranges and groups
|
|
59
|
+
|
|
60
|
+
A range's count is fixed when it is minted. Two phone-side jobs don't know their count in advance, so a range
|
|
61
|
+
has a `kind`:
|
|
62
|
+
|
|
63
|
+
- **`open`**: blank tags programmed on Sidekick one at a time. `ranges.create(scope, set.id, { kind: 'open', name })`
|
|
64
|
+
reserves only a start index; each `ranges.next()` hands back a free minted code or mints one more, so
|
|
65
|
+
`quantity`/`endIndex` grow as tags are written (`remaining` is null). One open range per set, and nothing can
|
|
66
|
+
be minted behind it (`409 RANGE_OPEN`) until `ranges.close(scope, set.id, range.id)` turns it into an ordinary
|
|
67
|
+
range (an open range that minted nothing is removed instead).
|
|
68
|
+
- **`group`**: tags that already exist, added by tapping, assigned by hand, and moved together later. Assigners may
|
|
69
|
+
make one: `ranges.create(scope, set.id, { kind: 'group', name, intendedCollectionId? })`. Each tap goes through
|
|
70
|
+
`ranges.addMember(scope, set.id, group.id, { code | uid, collectionId, productId? })`, which stamps the tag with
|
|
71
|
+
the group and assigns it with the single-tag rules; `assigned.skipped` says when a tag was left alone (claimed,
|
|
72
|
+
or in a collection you don't administer). `ranges.assign(scope, set.id, group.id, { collectionId })` moves every
|
|
73
|
+
member in one go; `ranges.removeMember` takes one out. Groups have no printer file, instructions, import or
|
|
74
|
+
`next` (`400 NOT_A_RANGE`). Its tags must be codes of the group's set; a chip that is a code elsewhere is
|
|
75
|
+
`409 OTHER_SET`.
|
|
76
|
+
|
|
77
|
+
Status reads `open` or `group` for these (and `assigned` once every member of a group is assigned).
|
|
78
|
+
|
|
79
|
+
## When a tag fails on the phone
|
|
80
|
+
|
|
81
|
+
`errors.report({ app: 'sidekick', operation: 'tag.program', errorCode: 'TAG_LOST', message, entityType: 'tag',
|
|
82
|
+
entityId: chipUid, labels: { claimSetId, code, failedStep }, context: { steps, timings, hostLog } })` keeps what
|
|
83
|
+
the phone saw in the platform's one error log (never a key: fields that look like one are dropped).
|
|
84
|
+
`partner.tagAttempts(partner.id, chipUid)` and the platform's tag lookup read it back, newest first, so a
|
|
85
|
+
failing chip can be understood by its UID without the phone's console.
|
|
86
|
+
|
|
58
87
|
## The printer file
|
|
59
88
|
|
|
60
89
|
One row per tag, in index order. The manufacturer fills in `UID` and sends the same file back; rows are
|