@proveanything/smartlinks 1.0.54 → 1.0.56

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/API_SUMMARY.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.0.54 | Generated: 2025-11-27T11:26:08.078Z
3
+ Version: 1.0.56 | Generated: 2025-12-10T12:13:56.087Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -39,6 +39,7 @@ Core HTTP functions for API configuration and communication:
39
39
  ngrokSkipBrowserWarning?: boolean
40
40
  extraHeaders?: Record<string, string>
41
41
  iframeAutoResize?: boolean // default true when in iframe
42
+ logger?: Logger // optional console-like or function to enable verbose logging
42
43
  }) → `void`
43
44
  Call this once (e.g. at app startup) to configure baseURL/auth.
44
45
 
@@ -319,30 +320,30 @@ interface AuthKitConfig {
319
320
  **ClaimCodeRef** (interface)
320
321
  ```typescript
321
322
  interface ClaimCodeRef {
322
- codeId: string
323
- claimId: string
323
+ codeId: string // Identifier of the code (e.g., tag or QR code)
324
+ claimId: string // Identifier of the claim within the claim set
324
325
  }
325
326
  ```
326
327
 
327
328
  **UpdateClaimDataRequest** (interface)
328
329
  ```typescript
329
330
  interface UpdateClaimDataRequest {
330
- data: Record<string, any>
331
- codes: ClaimCodeRef[]
331
+ data: Record<string, any> // Arbitrary key/value pairs for the claim data update
332
+ codes: ClaimCodeRef[] // Array of code+claim references affected by this update
332
333
  }
333
334
  ```
334
335
 
335
336
  **AssignClaimsRequest** (interface)
336
337
  ```typescript
337
338
  interface AssignClaimsRequest {
338
- id: string
339
- collectionId: string
340
- productId: string
341
- batchId?: string
342
- start?: number
343
- end?: number
344
- codeId?: string
345
- data?: Record<string, any>
339
+ id: string // The claim set ID (required)
340
+ collectionId: string // The collection ID (required)
341
+ productId: string // The product ID (required)
342
+ batchId?: string // Optional batch identifier
343
+ start?: number // Optional start index for bulk assignment
344
+ end?: number // Optional end index for bulk assignment
345
+ codeId?: string // Optional single code identifier for single assignment
346
+ data?: Record<string, any> // Optional key/value pairs to set on the claim
346
347
  }
347
348
  ```
348
349
 
@@ -487,6 +488,65 @@ interface ErrorResponse {
487
488
  }
488
489
  ```
489
490
 
491
+ ### nfc
492
+
493
+ **NfcTagInfo** (interface)
494
+ ```typescript
495
+ interface NfcTagInfo {
496
+ id: string
497
+ tagId: string
498
+ claimSetId: string
499
+ collectionId?: string
500
+ productId?: string
501
+ batchId?: string
502
+ variantId?: string
503
+ proofId?: string
504
+ index?: number
505
+ data?: Record<string, any>
506
+ }
507
+ ```
508
+
509
+ **NfcValidateRequest** (interface)
510
+ ```typescript
511
+ interface NfcValidateRequest {
512
+ claimSetId: string
513
+ codeId: string
514
+ mirror?: string
515
+ userId?: string
516
+ }
517
+ ```
518
+
519
+ **NfcValidateResponse** (interface)
520
+ ```typescript
521
+ interface NfcValidateResponse {
522
+ claimSetId: string
523
+ codeId: string
524
+ tagId: string
525
+ index?: number
526
+ isAdmin: boolean
527
+ path?: string
528
+ collectionId?: string
529
+ collection?: Record<string, any>
530
+ count: number,
531
+ previousCount: number
532
+ data?: Record<string, any>
533
+ productId?: string
534
+ product?: Record<string, any>
535
+ batchId?: string
536
+ variantId?: string
537
+ proofId?: string
538
+ }
539
+ ```
540
+
541
+ **NfcClaimTagRequest** (interface)
542
+ ```typescript
543
+ interface NfcClaimTagRequest {
544
+ claimSetId: string
545
+ codeId: string
546
+ data: Record<string, any>
547
+ }
548
+ ```
549
+
490
550
  ### product
491
551
 
492
552
  **ProductResponse** (interface)
@@ -530,6 +590,8 @@ interface ProofResponse {
530
590
  productId: string
531
591
  tokenId: string
532
592
  userId: string
593
+ claimable: boolean
594
+ transient: boolean
533
595
  values: Record<string, any>
534
596
  }
535
597
  ```
package/README.md CHANGED
@@ -28,6 +28,7 @@ import { initializeApi } from '@proveanything/smartlinks'
28
28
 
29
29
  initializeApi({
30
30
  baseURL: 'https://smartlinks.app/api/v1', // or 'https://smartlinks.app/api/v1/'
31
+ // logger: console, // optional: verbose logging of requests/responses and proxy messages
31
32
  // apiKey: process.env.SMARTLINKS_API_KEY, // Node/server only (optional)
32
33
  // ngrokSkipBrowserWarning: true, // adds 'ngrok-skip-browser-warning: true'
33
34
  // extraHeaders: { 'X-Debug': '1' } // merged into every request
@@ -204,11 +205,13 @@ initializeApi({
204
205
  ngrokSkipBrowserWarning?: boolean // forces header 'ngrok-skip-browser-warning: true'
205
206
  extraHeaders?: Record<string,string> // custom headers merged in each request
206
207
  iframeAutoResize?: boolean // default true when embedded in an iframe
208
+ logger?: Function | { debug?: Function; info?: Function; warn?: Function; error?: Function; log?: Function } // optional verbose logging
207
209
  })
208
210
 
209
211
  // Auto-detection: If baseURL contains '.ngrok.io' or '.ngrok-free.dev' the header is added automatically
210
212
  // unless you explicitly set ngrokSkipBrowserWarning: false.
211
213
  // Auto iframe resize: When in an iframe, resize messages are sent by default unless iframeAutoResize: false.
214
+ // Verbose logging: Pass a logger (e.g. console) to log outbound requests/responses and proxy postMessages.
212
215
  ```
213
216
 
214
217
  When embedding the SDK in an iframe with `proxyMode: true`, you can also use:
package/dist/api/nfc.d.ts CHANGED
@@ -1,7 +1,18 @@
1
+ import type { NfcValidateRequest, NfcValidateResponse, NfcTagInfo, NfcClaimTagRequest } from "../types/nfc";
1
2
  export declare const nfc: {
2
3
  /**
3
4
  * Claim an NFC tag (public).
4
5
  * POST /api/va/public/nfc/claimTag
5
6
  */
6
- claimTag<T = any>(data: any): Promise<T>;
7
+ claimTag(data: NfcClaimTagRequest): Promise<NfcTagInfo>;
8
+ /**
9
+ * Validate an NFC tag payload (public).
10
+ * POST /public/nfc/validate
11
+ */
12
+ validate(data: NfcValidateRequest): Promise<NfcValidateResponse>;
13
+ /**
14
+ * Lookup a tag by its ID (public).
15
+ * GET /public/nfc/findByTag/:tagId
16
+ */
17
+ lookupTag(tagId: string): Promise<NfcTagInfo[]>;
7
18
  };
package/dist/api/nfc.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/api/nfc.ts
2
- import { post } from "../http";
2
+ import { post, request } from "../http";
3
3
  export const nfc = {
4
4
  /**
5
5
  * Claim an NFC tag (public).
@@ -8,4 +8,18 @@ export const nfc = {
8
8
  async claimTag(data) {
9
9
  return post("/public/nfc/claimTag", data);
10
10
  },
11
+ /**
12
+ * Validate an NFC tag payload (public).
13
+ * POST /public/nfc/validate
14
+ */
15
+ async validate(data) {
16
+ return post("/public/nfc/validate", data);
17
+ },
18
+ /**
19
+ * Lookup a tag by its ID (public).
20
+ * GET /public/nfc/findByTag/:tagId
21
+ */
22
+ async lookupTag(tagId) {
23
+ return request(`/public/nfc/findByTag/${encodeURIComponent(tagId)}`);
24
+ },
11
25
  };
package/dist/http.d.ts CHANGED
@@ -1,3 +1,10 @@
1
+ type Logger = {
2
+ debug?: (...args: any[]) => void;
3
+ info?: (...args: any[]) => void;
4
+ warn?: (...args: any[]) => void;
5
+ error?: (...args: any[]) => void;
6
+ log?: (...args: any[]) => void;
7
+ } | ((...args: any[]) => void);
1
8
  export declare function initializeApi(options: {
2
9
  baseURL: string;
3
10
  apiKey?: string;
@@ -6,6 +13,7 @@ export declare function initializeApi(options: {
6
13
  ngrokSkipBrowserWarning?: boolean;
7
14
  extraHeaders?: Record<string, string>;
8
15
  iframeAutoResize?: boolean;
16
+ logger?: Logger;
9
17
  }): void;
10
18
  /** Enable/disable automatic "ngrok-skip-browser-warning" header. */
11
19
  export declare function setNgrokSkipBrowserWarning(flag: boolean): void;
@@ -60,3 +68,4 @@ export declare function getApiHeaders(): Record<string, string>;
60
68
  * @returns The data from the proxy response
61
69
  */
62
70
  export declare function sendCustomProxyMessage<T = any>(request: string, params: any): Promise<T>;
71
+ export {};
package/dist/http.js CHANGED
@@ -8,6 +8,57 @@ let bearerToken = undefined;
8
8
  let proxyMode = false;
9
9
  let ngrokSkipBrowserWarning = false;
10
10
  let extraHeadersGlobal = {};
11
+ let logger;
12
+ function logDebug(...args) {
13
+ if (!logger)
14
+ return;
15
+ if (typeof logger === 'function')
16
+ return logger(...args);
17
+ if (logger.debug)
18
+ return logger.debug(...args);
19
+ if (logger.log)
20
+ return logger.log(...args);
21
+ }
22
+ function maskSensitive(value) {
23
+ if (!value)
24
+ return value;
25
+ if (value.length <= 8)
26
+ return '*'.repeat(Math.max(4, value.length));
27
+ return value.slice(0, 2) + '***' + value.slice(-4);
28
+ }
29
+ function redactHeaders(headers) {
30
+ const h = Object.assign({}, headers);
31
+ for (const key of Object.keys(h)) {
32
+ const k = key.toLowerCase();
33
+ if (k === 'authorization' || k === 'x-api-key' || k === 'auth' || k === 'proxy-authorization') {
34
+ h[key] = maskSensitive(h[key]);
35
+ }
36
+ }
37
+ return h;
38
+ }
39
+ function safeBodyPreview(body) {
40
+ if (body == null)
41
+ return undefined;
42
+ if (typeof FormData !== 'undefined' && body instanceof FormData)
43
+ return '[FormData]';
44
+ if (typeof body === 'string')
45
+ return body.slice(0, 1000);
46
+ if (typeof body === 'object') {
47
+ const copy = Array.isArray(body) ? [...body] : Object.assign({}, body);
48
+ const redactKeys = ['password', 'token', 'authorization', 'apiKey', 'bearerToken'];
49
+ for (const k of Object.keys(copy)) {
50
+ if (redactKeys.includes(k))
51
+ copy[k] = '[redacted]';
52
+ }
53
+ try {
54
+ return JSON.parse(JSON.stringify(copy));
55
+ }
56
+ catch (_a) {
57
+ return '[Object]';
58
+ }
59
+ }
60
+ return body;
61
+ }
11
62
  /**
12
63
  * Call this once (e.g. at app startup) to configure baseURL/auth.
13
64
  *
@@ -35,6 +86,15 @@ export function initializeApi(options) {
35
86
  if (isIframe() && options.iframeAutoResize !== false) {
36
87
  enableAutoIframeResize();
37
88
  }
89
+ logger = options.logger;
90
+ logDebug('[smartlinks] initializeApi', {
91
+ baseURL,
92
+ proxyMode,
93
+ inferredNgrok,
94
+ ngrokSkipBrowserWarning,
95
+ extraHeaders: Object.keys(extraHeadersGlobal),
96
+ iframeAutoResizeEnabled: isIframe() && options.iframeAutoResize !== false,
97
+ });
38
98
  }
39
99
  /** Enable/disable automatic "ngrok-skip-browser-warning" header. */
40
100
  export function setNgrokSkipBrowserWarning(flag) {
@@ -63,6 +123,7 @@ function ensureProxyListener() {
63
123
  const msg = event.data;
64
124
  if (!msg || !msg._smartlinksProxyResponse || !msg.id)
65
125
  return;
126
+ logDebug('[smartlinks] proxy:response', { id: msg.id, ok: !msg.error, keys: Object.keys(msg) });
66
127
  const pending = proxyPending[msg.id];
67
128
  if (pending) {
68
129
  if (msg.error) {
@@ -89,6 +150,7 @@ async function proxyRequest(method, path, body, headers, options) {
89
150
  headers,
90
151
  options,
91
152
  };
153
+ logDebug('[smartlinks] proxy:postMessage', { id, method, path, headers: headers ? redactHeaders(headers) : undefined, hasBody: !!body });
92
154
  return new Promise((resolve, reject) => {
93
155
  proxyPending[id] = { resolve, reject };
94
156
  window.parent.postMessage(msg, "*");
@@ -102,6 +164,7 @@ async function proxyRequest(method, path, body, headers, options) {
102
164
  */
103
165
  export async function request(path) {
104
166
  if (proxyMode) {
167
+ logDebug('[smartlinks] GET via proxy', { path });
105
168
  return proxyRequest("GET", path);
106
169
  }
107
170
  if (!baseURL) {
@@ -117,10 +180,12 @@ export async function request(path) {
117
180
  headers["ngrok-skip-browser-warning"] = "true";
118
181
  for (const [k, v] of Object.entries(extraHeadersGlobal))
119
182
  headers[k] = v;
183
+ logDebug('[smartlinks] GET fetch', { url, headers: redactHeaders(headers) });
120
184
  const response = await fetch(url, {
121
185
  method: "GET",
122
186
  headers,
123
187
  });
188
+ logDebug('[smartlinks] GET response', { url, status: response.status, ok: response.ok });
124
189
  if (!response.ok) {
125
190
  // Try to parse ErrorResponse; if that fails, throw generic
126
191
  try {
@@ -141,6 +206,7 @@ export async function request(path) {
141
206
  */
142
207
  export async function post(path, body, extraHeaders) {
143
208
  if (proxyMode) {
209
+ logDebug('[smartlinks] POST via proxy', { path, body: safeBodyPreview(body) });
144
210
  return proxyRequest("POST", path, body, extraHeaders);
145
211
  }
146
212
  if (!baseURL) {
@@ -161,11 +227,13 @@ export async function post(path, body, extraHeaders) {
161
227
  if (!(body instanceof FormData)) {
162
228
  headers["Content-Type"] = "application/json";
163
229
  }
230
+ logDebug('[smartlinks] POST fetch', { url, headers: redactHeaders(headers), body: safeBodyPreview(body) });
164
231
  const response = await fetch(url, {
165
232
  method: "POST",
166
233
  headers,
167
234
  body: body instanceof FormData ? body : JSON.stringify(body),
168
235
  });
236
+ logDebug('[smartlinks] POST response', { url, status: response.status, ok: response.ok });
169
237
  if (!response.ok) {
170
238
  try {
171
239
  const errBody = (await response.json());
@@ -185,6 +253,7 @@ export async function post(path, body, extraHeaders) {
185
253
  */
186
254
  export async function put(path, body, extraHeaders) {
187
255
  if (proxyMode) {
256
+ logDebug('[smartlinks] PUT via proxy', { path, body: safeBodyPreview(body) });
188
257
  return proxyRequest("PUT", path, body, extraHeaders);
189
258
  }
190
259
  if (!baseURL) {
@@ -205,11 +274,13 @@ export async function put(path, body, extraHeaders) {
205
274
  if (!(body instanceof FormData)) {
206
275
  headers["Content-Type"] = "application/json";
207
276
  }
277
+ logDebug('[smartlinks] PUT fetch', { url, headers: redactHeaders(headers), body: safeBodyPreview(body) });
208
278
  const response = await fetch(url, {
209
279
  method: "PUT",
210
280
  headers,
211
281
  body: body instanceof FormData ? body : JSON.stringify(body),
212
282
  });
283
+ logDebug('[smartlinks] PUT response', { url, status: response.status, ok: response.ok });
213
284
  if (!response.ok) {
214
285
  try {
215
286
  const errBody = (await response.json());
@@ -228,6 +299,7 @@ export async function put(path, body, extraHeaders) {
228
299
  */
229
300
  export async function requestWithOptions(path, options) {
230
301
  if (proxyMode) {
302
+ logDebug('[smartlinks] requestWithOptions via proxy', { path, method: options.method || 'GET' });
231
303
  return proxyRequest(options.method || "GET", path, options.body, options.headers, options);
232
304
  }
233
305
  if (!baseURL) {
@@ -256,7 +328,9 @@ export async function requestWithOptions(path, options) {
256
328
  for (const [k, v] of Object.entries(extraHeadersGlobal))
257
329
  if (!(k in headers))
258
330
  headers[k] = v;
331
+ logDebug('[smartlinks] requestWithOptions fetch', { url, method: options.method || 'GET', headers: redactHeaders(headers), body: safeBodyPreview(options.body) });
259
332
  const response = await fetch(url, Object.assign(Object.assign({}, options), { headers }));
333
+ logDebug('[smartlinks] requestWithOptions response', { url, status: response.status, ok: response.ok });
260
334
  if (!response.ok) {
261
335
  try {
262
336
  const errBody = (await response.json());
@@ -275,6 +349,7 @@ export async function requestWithOptions(path, options) {
275
349
  */
276
350
  export async function del(path, extraHeaders) {
277
351
  if (proxyMode) {
352
+ logDebug('[smartlinks] DELETE via proxy', { path });
278
353
  return proxyRequest("DELETE", path, undefined, extraHeaders);
279
354
  }
280
355
  if (!baseURL) {
@@ -291,10 +366,12 @@ export async function del(path, extraHeaders) {
291
366
  for (const [k, v] of Object.entries(extraHeadersGlobal))
292
367
  if (!(k in headers))
293
368
  headers[k] = v;
369
+ logDebug('[smartlinks] DELETE fetch', { url, headers: redactHeaders(headers) });
294
370
  const response = await fetch(url, {
295
371
  method: "DELETE",
296
372
  headers,
297
373
  });
374
+ logDebug('[smartlinks] DELETE response', { url, status: response.status, ok: response.ok });
298
375
  if (!response.ok) {
299
376
  try {
300
377
  const errBody = (await response.json());
@@ -345,6 +422,7 @@ export async function sendCustomProxyMessage(request, params) {
345
422
  request,
346
423
  params,
347
424
  };
425
+ logDebug('[smartlinks] proxy:custom postMessage', { id, request, params: safeBodyPreview(params) });
348
426
  return new Promise((resolve, reject) => {
349
427
  proxyPending[id] = { resolve, reject };
350
428
  window.parent.postMessage(msg, "*");
@@ -2,9 +2,7 @@
2
2
  * Reference to a specific claim attached to a code/tag.
3
3
  */
4
4
  export interface ClaimCodeRef {
5
- /** Identifier of the code (e.g., tag or QR code) */
6
5
  codeId: string;
7
- /** Identifier of the claim within the claim set */
8
6
  claimId: string;
9
7
  }
10
8
  /**
@@ -12,29 +10,19 @@ export interface ClaimCodeRef {
12
10
  * Contains arbitrary key/value pairs and a list of code+claim references to update.
13
11
  */
14
12
  export interface UpdateClaimDataRequest {
15
- /** Arbitrary key/value pairs for the claim data update */
16
13
  data: Record<string, any>;
17
- /** Array of code+claim references affected by this update */
18
14
  codes: ClaimCodeRef[];
19
15
  }
20
16
  /**
21
17
  * Request body for assigning claims to codes or ranges within a collection.
22
18
  */
23
19
  export interface AssignClaimsRequest {
24
- /** The claim set ID (required) */
25
20
  id: string;
26
- /** The collection ID (required) */
27
21
  collectionId: string;
28
- /** The product ID (required) */
29
22
  productId: string;
30
- /** Optional batch identifier */
31
23
  batchId?: string;
32
- /** Optional start index for bulk assignment */
33
24
  start?: number;
34
- /** Optional end index for bulk assignment */
35
25
  end?: number;
36
- /** Optional single code identifier for single assignment */
37
26
  codeId?: string;
38
- /** Optional key/value pairs to set on the claim */
39
27
  data?: Record<string, any>;
40
28
  }
@@ -9,3 +9,4 @@ export * from "./variant";
9
9
  export * from "./claimSet";
10
10
  export * from "./auth";
11
11
  export * from "./comms";
12
+ export * from "./nfc";
@@ -11,3 +11,4 @@ export * from "./variant";
11
11
  export * from "./claimSet";
12
12
  export * from "./auth";
13
13
  export * from "./comms";
14
+ export * from "./nfc";
@@ -0,0 +1,41 @@
1
+ export interface NfcTagInfo {
2
+ id: string;
3
+ tagId: string;
4
+ claimSetId: string;
5
+ collectionId?: string;
6
+ productId?: string;
7
+ batchId?: string;
8
+ variantId?: string;
9
+ proofId?: string;
10
+ index?: number;
11
+ data?: Record<string, any>;
12
+ }
13
+ export interface NfcValidateRequest {
14
+ claimSetId: string;
15
+ codeId: string;
16
+ mirror?: string;
17
+ userId?: string;
18
+ }
19
+ export interface NfcValidateResponse {
20
+ claimSetId: string;
21
+ codeId: string;
22
+ tagId: string;
23
+ index?: number;
24
+ isAdmin: boolean;
25
+ path?: string;
26
+ collectionId?: string;
27
+ collection?: Record<string, any>;
28
+ count: number;
29
+ previousCount: number;
30
+ data?: Record<string, any>;
31
+ productId?: string;
32
+ product?: Record<string, any>;
33
+ batchId?: string;
34
+ variantId?: string;
35
+ proofId?: string;
36
+ }
37
+ export interface NfcClaimTagRequest {
38
+ claimSetId: string;
39
+ codeId: string;
40
+ data: Record<string, any>;
41
+ }
@@ -0,0 +1,2 @@
1
+ // src/types/nfc.ts
2
+ export {};
@@ -14,6 +14,10 @@ export interface ProofResponse {
14
14
  tokenId: string;
15
15
  /** Unique identifier for the user */
16
16
  userId: string;
17
+ /** Is this proof available to be claimed */
18
+ claimable: boolean;
19
+ /** Is this proof transient */
20
+ transient: boolean;
17
21
  /** Arbitrary key-value pairs for proof values */
18
22
  values: Record<string, any>;
19
23
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "1.0.54",
3
+ "version": "1.0.56",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",