@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.
- package/dist/docs/API_SUMMARY.md +140 -1
- package/dist/docs/translations.md +82 -0
- package/dist/http.js +8 -1
- package/dist/iframeResponder.js +9 -2
- package/dist/openapi.yaml +1438 -496
- package/dist/types/iframeResponder.d.ts +2 -0
- package/docs/API_SUMMARY.md +140 -1
- package/docs/translations.md +82 -0
- package/openapi.yaml +1438 -496
- package/package.json +1 -1
package/dist/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.9.
|
|
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
|
-
|
|
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);
|
package/dist/iframeResponder.js
CHANGED
|
@@ -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
|
-
|
|
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);
|