@proveanything/smartlinks 1.9.4 → 1.9.6

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,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.9.4 | Generated: 2026-03-23T19:52:46.756Z
3
+ Version: 1.9.6 | Generated: 2026-03-28T15:04:22.535Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -10,13 +10,16 @@ For detailed guides on specific features:
10
10
 
11
11
  - **[SmartLinks Microapp Overview](overview.md)** - Platform architecture, data model, auth patterns, storage, anti-patterns, and quick-reference for all SDK docs
12
12
  - **[AI & Chat Completions](ai.md)** - Chat completions, RAG (document-grounded Q&A), voice integration, streaming, tool calling, podcast generation
13
+ - **[Translations](translations.md)** - Runtime translation lookup, browser-side IndexedDB caching, and admin translation management
13
14
  - **[Widgets](widgets.md)** - Embeddable React components for parent applications
14
15
  - **[Containers](containers.md)** - Building full-app embeddable containers (lazy-loaded)
16
+ - **[Scanner Containers](scanner-container.md)** - Building scanner microapps for the SmartLinks Scanner Android host (RFID, NFC, QR, key events)
15
17
  - **[Multi-Page App Architecture](mpa.md)** - Vite MPA build pipeline: public/admin entry points, widget/container/executor bundles, content-hashed CDN assets
16
18
  - **[App Configuration Files](app-manifest.md)** - `app.manifest.json` and `app.admin.json` reference — bundles, components, setup questions, import schemas, tunable fields, and metrics
17
19
  - **[Executor Model](executor.md)** - Programmatic JS bundles for AI-driven setup, server-side SEO metadata generation, and LLM content for AI crawlers
18
20
  - **[Realtime](realtime.md)** - Real-time data updates and WebSocket connections
19
21
  - **[iframe Responder](iframe-responder.md)** - iframe integration and cross-origin communication
22
+ - **[Utilities](utils.md)** - Helper functions for building portal paths, URLs, and common tasks
20
23
  - **[i18n](i18n.md)** - Internationalization and localization
21
24
  - **[Liquid Templates](liquid-templates.md)** - Dynamic templating for content generation
22
25
  - **[Theme System](theme.system.md)** - Theme configuration and customization
@@ -4465,6 +4468,8 @@ interface ProxyResponse {
4465
4468
  id: string;
4466
4469
  data?: any;
4467
4470
  error?: string;
4471
+ statusCode?: number;
4472
+ errorBody?: any;
4468
4473
  }
4469
4474
  ```
4470
4475
 
@@ -6560,6 +6565,140 @@ type VerifyTokenResponse = {
6560
6565
  }
6561
6566
  ```
6562
6567
 
6568
+ ### conditions (utils)
6569
+
6570
+ **BaseCondition** (interface)
6571
+ ```typescript
6572
+ interface BaseCondition {
6573
+ type: string
6574
+ contains?: boolean
6575
+ passes?: boolean
6576
+ }
6577
+ ```
6578
+
6579
+ **ConditionSet** (interface)
6580
+ ```typescript
6581
+ interface ConditionSet {
6582
+ id?: string
6583
+ type?: 'and' | 'or'
6584
+ conditions?: Condition[]
6585
+ }
6586
+ ```
6587
+
6588
+ **UserLocation** (interface)
6589
+ ```typescript
6590
+ interface UserLocation {
6591
+ country?: string
6592
+ latitude?: number
6593
+ longitude?: number
6594
+ }
6595
+ ```
6596
+
6597
+ **PlatformInfo** (interface)
6598
+ ```typescript
6599
+ interface PlatformInfo {
6600
+ android?: boolean
6601
+ ios?: boolean
6602
+ win?: boolean
6603
+ mac?: boolean
6604
+ }
6605
+ ```
6606
+
6607
+ **StatsInfo** (interface)
6608
+ ```typescript
6609
+ interface StatsInfo {
6610
+ version?: string | null
6611
+ platform?: PlatformInfo
6612
+ mobile?: boolean
6613
+ }
6614
+ ```
6615
+
6616
+ **UserInfo** (interface)
6617
+ ```typescript
6618
+ interface UserInfo {
6619
+ valid: boolean
6620
+ uid?: string
6621
+ location?: UserLocation
6622
+ groups?: string[]
6623
+ }
6624
+ ```
6625
+
6626
+ **ProductInfo** (interface)
6627
+ ```typescript
6628
+ interface ProductInfo {
6629
+ id: string
6630
+ tags?: Record<string, any>
6631
+ }
6632
+ ```
6633
+
6634
+ **ProofInfo** (interface)
6635
+ ```typescript
6636
+ interface ProofInfo {
6637
+ id?: string
6638
+ userId?: string
6639
+ claimable?: boolean
6640
+ virtual?: boolean
6641
+ }
6642
+ ```
6643
+
6644
+ **CollectionInfo** (interface)
6645
+ ```typescript
6646
+ interface CollectionInfo {
6647
+ id: string
6648
+ roles?: Record<string, any>
6649
+ }
6650
+ ```
6651
+
6652
+ **ConditionParams** (interface)
6653
+ ```typescript
6654
+ interface ConditionParams {
6655
+ condition?: ConditionSet
6656
+ conditionId?: string
6657
+ conditionStack?: string[]
6658
+ user?: UserInfo
6659
+ product?: ProductInfo
6660
+ proof?: ProofInfo
6661
+ collection?: CollectionInfo
6662
+ stats?: StatsInfo
6663
+ fetchCondition?: (collectionId: string, conditionId: string) => Promise<ConditionSet | null>
6664
+ getLocation?: () => Promise<{ latitude: number; longitude: number }>
6665
+ debugConditions?: boolean | ConditionDebugOptions
6666
+ [key: string]: any
6667
+ }
6668
+ ```
6669
+
6670
+ **ConditionDebugOptions** (interface)
6671
+ ```typescript
6672
+ interface ConditionDebugOptions {
6673
+ enabled?: boolean
6674
+ logger?: ConditionDebugLogger
6675
+ label?: string
6676
+ }
6677
+ ```
6678
+
6679
+ **RegionKey** = `keyof typeof REGION_COUNTRIES`
6680
+
6681
+ **Condition** = ``
6682
+
6683
+ **ConditionDebugLogger** = `(...args: any[]) => void`
6684
+
6685
+ ### paths (utils)
6686
+
6687
+ **PortalPathParams** (interface)
6688
+ ```typescript
6689
+ interface PortalPathParams {
6690
+ collection: Collection | { shortId: string; portalUrl?: string }
6691
+ product?: Product
6692
+ productId?: string
6693
+ batch?: BatchResponse
6694
+ batchId?: string
6695
+ variant?: { id: string } | string
6696
+ proof?: Proof | string
6697
+ queryParams?: Record<string, string>
6698
+ pathOnly?: boolean
6699
+ }
6700
+ ```
6701
+
6563
6702
  ## API Functions
6564
6703
 
6565
6704
  ### analytics.admin
@@ -92,6 +92,88 @@ const response = await translations.lookup('collection-123', {
92
92
  })
93
93
  ```
94
94
 
95
+ ## Content Types
96
+
97
+ `contentType` is part of the translation cache identity. Use it to tell the backend what kind of content is being translated so it can preserve structure correctly.
98
+
99
+ ### `text/plain`
100
+
101
+ Use this for normal strings, paragraphs, labels, and other plain text content with no markup.
102
+
103
+ ```ts
104
+ await translations.resolve('collection-123', {
105
+ targetLanguage: 'fr',
106
+ sourceLanguage: 'en',
107
+ contentType: 'text/plain',
108
+ texts: [
109
+ 'Welcome to the product page',
110
+ 'Scan to verify authenticity',
111
+ ],
112
+ })
113
+ ```
114
+
115
+ ### `text/html`
116
+
117
+ Use this when the source contains HTML tags that must survive translation unchanged. This is important for rich text descriptions, CMS content, and formatted snippets.
118
+
119
+ ```ts
120
+ await translations.resolve('collection-123', {
121
+ targetLanguage: 'de',
122
+ sourceLanguage: 'en',
123
+ contentType: 'text/html',
124
+ context: {
125
+ surface: 'portal-product-page',
126
+ field: 'rich-description',
127
+ },
128
+ texts: [
129
+ '<p>Welcome to the <strong>product page</strong>.</p>',
130
+ '<p>Scan the tag to <a href="/verify">verify authenticity</a>.</p>',
131
+ ],
132
+ })
133
+ ```
134
+
135
+ Use `text/html` when you want the translation system to preserve tags such as:
136
+
137
+ - `<p>`, `<strong>`, `<em>`
138
+ - `<ul>`, `<li>`
139
+ - `<a>`
140
+ - inline markup embedded in CMS-rendered HTML
141
+
142
+ ### `text/x-liquid`
143
+
144
+ Use this when the content includes Liquid syntax that must be preserved exactly, including output tags, control-flow blocks, and filters.
145
+
146
+ ```ts
147
+ await translations.resolve('collection-123', {
148
+ targetLanguage: 'es',
149
+ sourceLanguage: 'en',
150
+ contentType: 'text/x-liquid',
151
+ context: {
152
+ surface: 'portal-email-template',
153
+ field: 'body',
154
+ },
155
+ texts: [
156
+ 'Hello {{ customer.first_name }}, your item {{ product.title }} is ready.',
157
+ '{% if claimable %}Claim your item{% else %}View item details{% endif %}',
158
+ ],
159
+ })
160
+ ```
161
+
162
+ Use `text/x-liquid` when the source includes constructs such as:
163
+
164
+ - `{{ customer.first_name }}`
165
+ - `{{ product.title | upcase }}`
166
+ - `{% if claimable %}...{% endif %}`
167
+ - loop or conditional blocks used in templates
168
+
169
+ ### Choosing The Right Value
170
+
171
+ - use `text/plain` for normal strings with no markup
172
+ - use `text/html` when HTML tags are part of the source and must be preserved
173
+ - use `text/x-liquid` when Liquid template syntax is part of the source and must be preserved
174
+
175
+ Do not mix plain text, HTML, and Liquid under the same `contentType` if you want stable cache keys and predictable translation behavior.
176
+
95
177
  ## Local-First Resolution
96
178
 
97
179
  `resolve(...)` is intended for browser rendering paths where repeated translations should not keep hitting the network.
package/dist/http.js CHANGED
@@ -680,6 +680,7 @@ function ensureProxyListener() {
680
680
  if (window._smartlinksProxyListener)
681
681
  return;
682
682
  window.addEventListener("message", (event) => {
683
+ var _a;
683
684
  const msg = event.data;
684
685
  if ((msg === null || msg === void 0 ? void 0 : msg._smartlinksProxyStream) && msg.id) {
685
686
  const pendingStream = proxyStreamPending.get(msg.id);
@@ -705,7 +706,13 @@ function ensureProxyListener() {
705
706
  const pending = proxyPending[msg.id];
706
707
  if (pending) {
707
708
  if (msg.error) {
708
- pending.reject(new Error(msg.error));
709
+ if (msg.statusCode) {
710
+ const errBody = normalizeErrorResponse((_a = msg.errorBody) !== null && _a !== void 0 ? _a : msg.error, msg.statusCode);
711
+ pending.reject(new SmartlinksApiError(msg.error, msg.statusCode, errBody));
712
+ }
713
+ else {
714
+ pending.reject(new Error(msg.error));
715
+ }
709
716
  }
710
717
  else {
711
718
  pending.resolve(msg.data);
@@ -429,8 +429,15 @@ export class IframeResponder {
429
429
  fetchOptions.headers = Object.assign(Object.assign({}, fetchOptions.headers), { 'Content-Type': 'application/json' });
430
430
  }
431
431
  const fetchResponse = await fetch(fullUrl, fetchOptions);
432
- const responseData = await fetchResponse.json();
433
- response.data = responseData;
432
+ const responseData = await fetchResponse.json().catch(() => null);
433
+ if (!fetchResponse.ok) {
434
+ response.error = (responseData === null || responseData === void 0 ? void 0 : responseData.message) || `Request failed with status ${fetchResponse.status}`;
435
+ response.statusCode = fetchResponse.status;
436
+ response.errorBody = responseData;
437
+ }
438
+ else {
439
+ response.data = responseData;
440
+ }
434
441
  }
435
442
  catch (err) {
436
443
  console.error('[IframeResponder] Proxy request error:', err);