@proveanything/smartlinks 1.9.3 → 1.9.5

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/README.md CHANGED
@@ -22,6 +22,7 @@ If you're new to the SDK, this is the easiest path:
22
22
 
23
23
  - [docs/ai.md](docs/ai.md) — AI responses, chat, RAG, voice, streaming, and product assistants
24
24
  - [docs/analytics.md](docs/analytics.md) — fire-and-forget web analytics, tag scan telemetry, and dashboard queries
25
+ - [docs/translations.md](docs/translations.md) — runtime translation lookup, browser-side caching, and translation admin flows
25
26
  - [docs/widgets.md](docs/widgets.md) — embeddable React components
26
27
  - [docs/realtime.md](docs/realtime.md) — subscriptions and live updates
27
28
  - [docs/iframe-responder.md](docs/iframe-responder.md) — iframe integration and parent/child messaging
@@ -31,6 +32,7 @@ If you're new to the SDK, this is the easiest path:
31
32
 
32
33
  - **Build an AI assistant** → start with [docs/ai.md](docs/ai.md)
33
34
  - **Track page views, clicks, or tag scans** → start with [docs/analytics.md](docs/analytics.md)
35
+ - **Translate dynamic content with local browser caching** → start with [docs/translations.md](docs/translations.md)
34
36
  - **Fetch collections/products** → see [Quick start](README.md#quick-start)
35
37
  - **Authenticate admins or end users** → see [Authentication](README.md#authentication)
36
38
  - **Upload and manage files** → see [Assets](README.md#assets)
@@ -42,6 +44,7 @@ For the full list of functions and types, see the API summary:
42
44
  **Documentation:**
43
45
  - [AI & Chat Completions](docs/ai.md) - Chat completions, RAG, voice integration
44
46
  - [Analytics](docs/analytics.md) - Fire-and-forget analytics tracking, tag scans, and dashboard queries
47
+ - [Translations](docs/translations.md) - Runtime translation lookup, browser-side IndexedDB caching, and admin translation management
45
48
  - [Widgets](docs/widgets.md) - Embeddable React components
46
49
  - [Realtime](docs/realtime.md) - Realtime data updates
47
50
  - [iframe Responder](docs/iframe-responder.md) - iframe integration
@@ -35,3 +35,4 @@ export { app } from "./appObjects";
35
35
  export { attestations } from "./attestations";
36
36
  export { containers } from "./containers";
37
37
  export { loyalty } from "./loyalty";
38
+ export { translations } from "./translations";
package/dist/api/index.js CHANGED
@@ -38,3 +38,4 @@ export { app } from "./appObjects";
38
38
  export { attestations } from "./attestations";
39
39
  export { containers } from "./containers";
40
40
  export { loyalty } from "./loyalty";
41
+ export { translations } from "./translations";
@@ -0,0 +1,12 @@
1
+ import type { ResolvedTranslationResponse, TranslationHashOptions, TranslationListParams, TranslationListResponse, TranslationLookupRequest, TranslationLookupResponse, TranslationRecord, TranslationResolveOptions, TranslationUpdateRequest } from '../types/translations';
2
+ export declare namespace translations {
3
+ function hashText(text: string, options?: TranslationHashOptions): Promise<string>;
4
+ function hashTexts(texts: string[], options?: TranslationHashOptions): Promise<string[]>;
5
+ function normalizeText(text: string, options?: TranslationHashOptions): string;
6
+ function lookup(collectionId: string, body: TranslationLookupRequest): Promise<TranslationLookupResponse>;
7
+ function resolve(collectionId: string, body: TranslationLookupRequest, options?: TranslationResolveOptions): Promise<ResolvedTranslationResponse>;
8
+ function list(collectionId: string, params?: TranslationListParams): Promise<TranslationListResponse>;
9
+ function get(collectionId: string, translationId: string): Promise<TranslationRecord>;
10
+ function update(collectionId: string, translationId: string, body: TranslationUpdateRequest): Promise<TranslationRecord>;
11
+ function clearLocalCache(collectionId?: string): Promise<void>;
12
+ }
@@ -0,0 +1,217 @@
1
+ import { patch, post, request } from '../http';
2
+ import { clearCachedTranslations, deriveTranslationContextKey, getCachedTranslations, getDefaultTranslationCacheTtlMs, hashTranslationText, normalizeTranslationText, setCachedTranslations, } from '../translationCache';
3
+ function normalizeLookupRequest(body) {
4
+ var _a, _b, _c;
5
+ const texts = Array.isArray(body.texts)
6
+ ? [...(body.texts)]
7
+ : typeof body.text === 'string'
8
+ ? [body.text]
9
+ : [];
10
+ if (!body.targetLanguage) {
11
+ throw new Error('[smartlinks] translations.lookup requires targetLanguage');
12
+ }
13
+ if (texts.length === 0) {
14
+ throw new Error('[smartlinks] translations.lookup requires text or texts');
15
+ }
16
+ return {
17
+ targetLanguage: body.targetLanguage,
18
+ sourceLanguage: (_a = body.sourceLanguage) !== null && _a !== void 0 ? _a : 'en',
19
+ mode: (_b = body.mode) !== null && _b !== void 0 ? _b : 'cache-fill',
20
+ contentType: (_c = body.contentType) !== null && _c !== void 0 ? _c : 'text/plain',
21
+ contextKey: deriveTranslationContextKey(body.context),
22
+ requestBody: {
23
+ targetLanguage: body.targetLanguage,
24
+ sourceLanguage: body.sourceLanguage,
25
+ mode: body.mode,
26
+ contentType: body.contentType,
27
+ context: body.context,
28
+ returnMeta: body.returnMeta,
29
+ texts,
30
+ },
31
+ texts,
32
+ };
33
+ }
34
+ function buildTranslationListQuery(params = {}) {
35
+ const query = new URLSearchParams();
36
+ for (const [key, value] of Object.entries(params)) {
37
+ if (value === undefined || value === null)
38
+ continue;
39
+ query.append(key, String(value));
40
+ }
41
+ const queryString = query.toString();
42
+ return queryString ? `?${queryString}` : '';
43
+ }
44
+ function sameLanguage(left, right) {
45
+ return left.trim().toLowerCase() === right.trim().toLowerCase();
46
+ }
47
+ function toResolvedItem(item, index, cacheSource) {
48
+ return Object.assign(Object.assign({}, item), { index,
49
+ cacheSource });
50
+ }
51
+ export var translations;
52
+ (function (translations) {
53
+ async function hashText(text, options) {
54
+ return hashTranslationText(text, options);
55
+ }
56
+ translations.hashText = hashText;
57
+ async function hashTexts(texts, options) {
58
+ return Promise.all(texts.map((text) => hashTranslationText(text, options)));
59
+ }
60
+ translations.hashTexts = hashTexts;
61
+ function normalizeText(text, options) {
62
+ return normalizeTranslationText(text, options);
63
+ }
64
+ translations.normalizeText = normalizeText;
65
+ async function lookup(collectionId, body) {
66
+ const path = `/public/collection/${encodeURIComponent(collectionId)}/translations/lookup`;
67
+ const normalized = normalizeLookupRequest(body);
68
+ return post(path, normalized.requestBody);
69
+ }
70
+ translations.lookup = lookup;
71
+ async function resolve(collectionId, body, options = {}) {
72
+ var _a, _b, _c;
73
+ const normalized = normalizeLookupRequest(body);
74
+ const { useLocalCache = true, refreshLocalCache = false, localCacheTtlMs = getDefaultTranslationCacheTtlMs(), hashOptions, } = options;
75
+ const hashes = await Promise.all(normalized.texts.map((text) => hashTranslationText(text, hashOptions)));
76
+ const results = new Array(normalized.texts.length);
77
+ if (sameLanguage(normalized.sourceLanguage, normalized.targetLanguage)) {
78
+ const passthroughItems = normalized.texts.map((text, index) => ({
79
+ index,
80
+ hash: hashes[index],
81
+ sourceText: text,
82
+ translatedText: text,
83
+ status: 'passthrough',
84
+ quality: 'passthrough',
85
+ cacheSource: 'local',
86
+ expiresAt: Date.now() + localCacheTtlMs,
87
+ }));
88
+ if (useLocalCache) {
89
+ await setCachedTranslations({
90
+ collectionId,
91
+ sourceLanguage: normalized.sourceLanguage,
92
+ targetLanguage: normalized.targetLanguage,
93
+ contentType: normalized.contentType,
94
+ contextKey: normalized.contextKey,
95
+ ttlMs: localCacheTtlMs,
96
+ items: passthroughItems.map((item) => ({ hash: item.hash, item })),
97
+ });
98
+ }
99
+ return {
100
+ targetLanguage: normalized.targetLanguage,
101
+ sourceLanguage: normalized.sourceLanguage,
102
+ mode: normalized.mode,
103
+ items: passthroughItems,
104
+ };
105
+ }
106
+ const cachedByHash = useLocalCache && !refreshLocalCache
107
+ ? await getCachedTranslations({
108
+ collectionId,
109
+ sourceLanguage: normalized.sourceLanguage,
110
+ targetLanguage: normalized.targetLanguage,
111
+ contentType: normalized.contentType,
112
+ contextKey: normalized.contextKey,
113
+ hashes,
114
+ })
115
+ : new Map();
116
+ const missingIndexes = [];
117
+ for (let index = 0; index < normalized.texts.length; index += 1) {
118
+ const cached = cachedByHash.get(hashes[index]);
119
+ if ((_a = cached === null || cached === void 0 ? void 0 : cached.item) === null || _a === void 0 ? void 0 : _a.translatedText) {
120
+ results[index] = toResolvedItem(cached.item, index, 'local');
121
+ }
122
+ else {
123
+ missingIndexes.push(index);
124
+ }
125
+ }
126
+ if (missingIndexes.length === 0) {
127
+ return {
128
+ targetLanguage: normalized.targetLanguage,
129
+ sourceLanguage: normalized.sourceLanguage,
130
+ mode: normalized.mode,
131
+ items: results,
132
+ };
133
+ }
134
+ const uniqueMisses = [];
135
+ const uniqueMissLookup = new Map();
136
+ for (const index of missingIndexes) {
137
+ const hash = hashes[index];
138
+ const existing = uniqueMissLookup.get(hash);
139
+ if (existing) {
140
+ existing.indexes.push(index);
141
+ continue;
142
+ }
143
+ uniqueMissLookup.set(hash, { firstIndex: index, indexes: [index] });
144
+ uniqueMisses.push({ index, hash, text: normalized.texts[index] });
145
+ }
146
+ const remoteResponse = await lookup(collectionId, {
147
+ targetLanguage: normalized.targetLanguage,
148
+ sourceLanguage: body.sourceLanguage,
149
+ mode: body.mode,
150
+ contentType: body.contentType,
151
+ context: body.context,
152
+ returnMeta: body.returnMeta,
153
+ texts: uniqueMisses.map((item) => item.text),
154
+ });
155
+ const cacheableRemoteItems = [];
156
+ remoteResponse.items.forEach((remoteItem, remoteIndex) => {
157
+ var _a, _b;
158
+ const miss = uniqueMisses[remoteIndex];
159
+ if (!miss)
160
+ return;
161
+ const indexes = (_b = (_a = uniqueMissLookup.get(miss.hash)) === null || _a === void 0 ? void 0 : _a.indexes) !== null && _b !== void 0 ? _b : [miss.index];
162
+ for (const index of indexes) {
163
+ const resolvedItem = Object.assign(Object.assign({}, remoteItem), { index, hash: miss.hash, sourceText: normalized.texts[index], cacheSource: 'remote' });
164
+ results[index] = resolvedItem;
165
+ }
166
+ if (remoteItem.translatedText) {
167
+ cacheableRemoteItems.push({
168
+ hash: miss.hash,
169
+ item: Object.assign(Object.assign({}, remoteItem), { index: miss.index, hash: miss.hash, sourceText: miss.text, cacheSource: 'remote' }),
170
+ });
171
+ }
172
+ });
173
+ if (useLocalCache && cacheableRemoteItems.length > 0) {
174
+ await setCachedTranslations({
175
+ collectionId,
176
+ sourceLanguage: normalized.sourceLanguage,
177
+ targetLanguage: normalized.targetLanguage,
178
+ contentType: normalized.contentType,
179
+ contextKey: normalized.contextKey,
180
+ ttlMs: localCacheTtlMs,
181
+ items: cacheableRemoteItems,
182
+ });
183
+ }
184
+ return {
185
+ targetLanguage: remoteResponse.targetLanguage,
186
+ sourceLanguage: (_b = remoteResponse.sourceLanguage) !== null && _b !== void 0 ? _b : normalized.sourceLanguage,
187
+ mode: (_c = remoteResponse.mode) !== null && _c !== void 0 ? _c : normalized.mode,
188
+ items: results.map((item, index) => item !== null && item !== void 0 ? item : {
189
+ index,
190
+ hash: hashes[index],
191
+ sourceText: normalized.texts[index],
192
+ cacheSource: 'remote',
193
+ }),
194
+ };
195
+ }
196
+ translations.resolve = resolve;
197
+ async function list(collectionId, params) {
198
+ const query = buildTranslationListQuery(params);
199
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/translations${query}`;
200
+ return request(path);
201
+ }
202
+ translations.list = list;
203
+ async function get(collectionId, translationId) {
204
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/translations/${encodeURIComponent(translationId)}`;
205
+ return request(path);
206
+ }
207
+ translations.get = get;
208
+ async function update(collectionId, translationId, body) {
209
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/translations/${encodeURIComponent(translationId)}`;
210
+ return patch(path, body);
211
+ }
212
+ translations.update = update;
213
+ async function clearLocalCache(collectionId) {
214
+ await clearCachedTranslations(collectionId);
215
+ }
216
+ translations.clearLocalCache = clearLocalCache;
217
+ })(translations || (translations = {}));
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.9.3 | Generated: 2026-03-23T18:12:23.239Z
3
+ Version: 1.9.5 | Generated: 2026-03-23T20:19:00.201Z
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
@@ -110,6 +113,7 @@ The Smartlinks SDK is organized into the following namespaces:
110
113
  - **realtime** - Functions for realtime operations
111
114
  - **tags** - Functions for tags operations
112
115
  - **template** - Functions for template operations
116
+ - **translations** - Functions for translations operations
113
117
 
114
118
  ## HTTP Utilities
115
119
 
@@ -6343,6 +6347,153 @@ interface TemplateRenderSourceResponse {
6343
6347
 
6344
6348
  **TemplatePublic** = `TemplateBase`
6345
6349
 
6350
+ ### translations
6351
+
6352
+ **TranslationContext** (interface)
6353
+ ```typescript
6354
+ interface TranslationContext {
6355
+ surface?: string
6356
+ field?: string
6357
+ [key: string]: TranslationContextValue | undefined
6358
+ }
6359
+ ```
6360
+
6361
+ **TranslationLookupRequestBase** (interface)
6362
+ ```typescript
6363
+ interface TranslationLookupRequestBase {
6364
+ targetLanguage: string
6365
+ sourceLanguage?: string
6366
+ mode?: TranslationLookupMode
6367
+ contentType?: TranslationContentType
6368
+ context?: TranslationContext
6369
+ returnMeta?: boolean
6370
+ }
6371
+ ```
6372
+
6373
+ **TranslationLookupItem** (interface)
6374
+ ```typescript
6375
+ interface TranslationLookupItem {
6376
+ index: number
6377
+ hash: string
6378
+ sourceText: string
6379
+ translatedText?: string
6380
+ status?: TranslationItemStatus
6381
+ provider?: string
6382
+ model?: string
6383
+ isOverride?: boolean
6384
+ quality?: TranslationQuality
6385
+ createdAt?: string
6386
+ updatedAt?: string
6387
+ }
6388
+ ```
6389
+
6390
+ **TranslationLookupResponse** (interface)
6391
+ ```typescript
6392
+ interface TranslationLookupResponse {
6393
+ targetLanguage: string
6394
+ sourceLanguage?: string
6395
+ mode?: TranslationLookupMode
6396
+ items: TranslationLookupItem[]
6397
+ }
6398
+ ```
6399
+
6400
+ **ResolvedTranslationResponse** (interface)
6401
+ ```typescript
6402
+ interface ResolvedTranslationResponse {
6403
+ targetLanguage: string
6404
+ sourceLanguage?: string
6405
+ mode?: TranslationLookupMode
6406
+ items: ResolvedTranslationItem[]
6407
+ }
6408
+ ```
6409
+
6410
+ **TranslationHashOptions** (interface)
6411
+ ```typescript
6412
+ interface TranslationHashOptions {
6413
+ trim?: boolean
6414
+ collapseWhitespace?: boolean
6415
+ unicodeNormalization?: 'NFC' | 'NFKC' | false
6416
+ }
6417
+ ```
6418
+
6419
+ **TranslationResolveOptions** (interface)
6420
+ ```typescript
6421
+ interface TranslationResolveOptions {
6422
+ useLocalCache?: boolean
6423
+ refreshLocalCache?: boolean
6424
+ localCacheTtlMs?: number
6425
+ hashOptions?: TranslationHashOptions
6426
+ }
6427
+ ```
6428
+
6429
+ **TranslationRecord** (interface)
6430
+ ```typescript
6431
+ interface TranslationRecord {
6432
+ id: string
6433
+ collectionId: string
6434
+ sourceHash: string
6435
+ sourceText: string
6436
+ sourceLanguage?: string
6437
+ targetLanguage: string
6438
+ contentType: string
6439
+ contextKey?: string | null
6440
+ translatedText: string
6441
+ provider?: string | null
6442
+ model?: string | null
6443
+ quality: TranslationQuality
6444
+ isOverride: boolean
6445
+ metadata?: Record<string, any>
6446
+ createdAt: string
6447
+ updatedAt: string
6448
+ }
6449
+ ```
6450
+
6451
+ **TranslationListParams** (interface)
6452
+ ```typescript
6453
+ interface TranslationListParams {
6454
+ targetLanguage?: string
6455
+ sourceLanguage?: string
6456
+ contentType?: string
6457
+ contextKey?: string
6458
+ q?: string
6459
+ isOverride?: boolean
6460
+ limit?: number
6461
+ offset?: number
6462
+ }
6463
+ ```
6464
+
6465
+ **TranslationListResponse** (interface)
6466
+ ```typescript
6467
+ interface TranslationListResponse {
6468
+ items: TranslationRecord[]
6469
+ total?: number
6470
+ limit?: number
6471
+ offset?: number
6472
+ }
6473
+ ```
6474
+
6475
+ **TranslationUpdateRequest** (interface)
6476
+ ```typescript
6477
+ interface TranslationUpdateRequest {
6478
+ translatedText?: string
6479
+ isOverride?: boolean
6480
+ quality?: TranslationQuality
6481
+ metadata?: Record<string, any>
6482
+ }
6483
+ ```
6484
+
6485
+ **TranslationLookupMode** = `'cache-fill' | 'cache-only'`
6486
+
6487
+ **TranslationContentType** = `'text/plain' | 'text/html' | 'text/x-liquid' | (string & {})`
6488
+
6489
+ **TranslationQuality** = `'machine' | 'human' | 'passthrough' | (string & {})`
6490
+
6491
+ **TranslationItemStatus** = `'cached' | 'generated' | 'miss' | 'passthrough' | 'local-cache' | (string & {})`
6492
+
6493
+ **TranslationContextValue** = `string | number | boolean | null`
6494
+
6495
+ **TranslationLookupRequest** = `TranslationLookupSingleRequest | TranslationLookupBatchRequest`
6496
+
6346
6497
  ### variant
6347
6498
 
6348
6499
  **VariantResponse** = `any`
@@ -6412,6 +6563,140 @@ type VerifyTokenResponse = {
6412
6563
  }
6413
6564
  ```
6414
6565
 
6566
+ ### conditions (utils)
6567
+
6568
+ **BaseCondition** (interface)
6569
+ ```typescript
6570
+ interface BaseCondition {
6571
+ type: string
6572
+ contains?: boolean
6573
+ passes?: boolean
6574
+ }
6575
+ ```
6576
+
6577
+ **ConditionSet** (interface)
6578
+ ```typescript
6579
+ interface ConditionSet {
6580
+ id?: string
6581
+ type?: 'and' | 'or'
6582
+ conditions?: Condition[]
6583
+ }
6584
+ ```
6585
+
6586
+ **UserLocation** (interface)
6587
+ ```typescript
6588
+ interface UserLocation {
6589
+ country?: string
6590
+ latitude?: number
6591
+ longitude?: number
6592
+ }
6593
+ ```
6594
+
6595
+ **PlatformInfo** (interface)
6596
+ ```typescript
6597
+ interface PlatformInfo {
6598
+ android?: boolean
6599
+ ios?: boolean
6600
+ win?: boolean
6601
+ mac?: boolean
6602
+ }
6603
+ ```
6604
+
6605
+ **StatsInfo** (interface)
6606
+ ```typescript
6607
+ interface StatsInfo {
6608
+ version?: string | null
6609
+ platform?: PlatformInfo
6610
+ mobile?: boolean
6611
+ }
6612
+ ```
6613
+
6614
+ **UserInfo** (interface)
6615
+ ```typescript
6616
+ interface UserInfo {
6617
+ valid: boolean
6618
+ uid?: string
6619
+ location?: UserLocation
6620
+ groups?: string[]
6621
+ }
6622
+ ```
6623
+
6624
+ **ProductInfo** (interface)
6625
+ ```typescript
6626
+ interface ProductInfo {
6627
+ id: string
6628
+ tags?: Record<string, any>
6629
+ }
6630
+ ```
6631
+
6632
+ **ProofInfo** (interface)
6633
+ ```typescript
6634
+ interface ProofInfo {
6635
+ id?: string
6636
+ userId?: string
6637
+ claimable?: boolean
6638
+ virtual?: boolean
6639
+ }
6640
+ ```
6641
+
6642
+ **CollectionInfo** (interface)
6643
+ ```typescript
6644
+ interface CollectionInfo {
6645
+ id: string
6646
+ roles?: Record<string, any>
6647
+ }
6648
+ ```
6649
+
6650
+ **ConditionParams** (interface)
6651
+ ```typescript
6652
+ interface ConditionParams {
6653
+ condition?: ConditionSet
6654
+ conditionId?: string
6655
+ conditionStack?: string[]
6656
+ user?: UserInfo
6657
+ product?: ProductInfo
6658
+ proof?: ProofInfo
6659
+ collection?: CollectionInfo
6660
+ stats?: StatsInfo
6661
+ fetchCondition?: (collectionId: string, conditionId: string) => Promise<ConditionSet | null>
6662
+ getLocation?: () => Promise<{ latitude: number; longitude: number }>
6663
+ debugConditions?: boolean | ConditionDebugOptions
6664
+ [key: string]: any
6665
+ }
6666
+ ```
6667
+
6668
+ **ConditionDebugOptions** (interface)
6669
+ ```typescript
6670
+ interface ConditionDebugOptions {
6671
+ enabled?: boolean
6672
+ logger?: ConditionDebugLogger
6673
+ label?: string
6674
+ }
6675
+ ```
6676
+
6677
+ **RegionKey** = `keyof typeof REGION_COUNTRIES`
6678
+
6679
+ **Condition** = ``
6680
+
6681
+ **ConditionDebugLogger** = `(...args: any[]) => void`
6682
+
6683
+ ### paths (utils)
6684
+
6685
+ **PortalPathParams** (interface)
6686
+ ```typescript
6687
+ interface PortalPathParams {
6688
+ collection: Collection | { shortId: string; portalUrl?: string }
6689
+ product?: Product
6690
+ productId?: string
6691
+ batch?: BatchResponse
6692
+ batchId?: string
6693
+ variant?: { id: string } | string
6694
+ proof?: Proof | string
6695
+ queryParams?: Record<string, string>
6696
+ pathOnly?: boolean
6697
+ }
6698
+ ```
6699
+
6415
6700
  ## API Functions
6416
6701
 
6417
6702
  ### analytics.admin
@@ -8169,6 +8454,33 @@ Reverse lookup by ref via POST (public). `POST /public/collection/:collectionId/
8169
8454
  **renderSource**(collectionId: string,
8170
8455
  body: TemplateRenderSourceRequest) → `Promise<TemplateRenderSourceResponse>`
8171
8456
 
8457
+ ### translations
8458
+
8459
+ **hashText**(text: string, options?: TranslationHashOptions) → `Promise<string>`
8460
+
8461
+ **hashTexts**(texts: string[], options?: TranslationHashOptions) → `Promise<string[]>`
8462
+
8463
+ **normalizeText**(text: string, options?: TranslationHashOptions) → `string`
8464
+
8465
+ **lookup**(collectionId: string,
8466
+ body: TranslationLookupRequest) → `Promise<TranslationLookupResponse>`
8467
+
8468
+ **resolve**(collectionId: string,
8469
+ body: TranslationLookupRequest,
8470
+ options: TranslationResolveOptions = {}) → `Promise<ResolvedTranslationResponse>`
8471
+
8472
+ **list**(collectionId: string,
8473
+ params?: TranslationListParams) → `Promise<TranslationListResponse>`
8474
+
8475
+ **get**(collectionId: string,
8476
+ translationId: string) → `Promise<TranslationRecord>`
8477
+
8478
+ **update**(collectionId: string,
8479
+ translationId: string,
8480
+ body: TranslationUpdateRequest) → `Promise<TranslationRecord>`
8481
+
8482
+ **clearLocalCache**(collectionId?: string) → `Promise<void>`
8483
+
8172
8484
  ### tts
8173
8485
 
8174
8486
  **generate**(collectionId: string,
@@ -49,6 +49,7 @@ The SmartLinks SDK (`@proveanything/smartlinks`) includes comprehensive document
49
49
  | **Multi-Page Architecture** | `docs/mpa.md` | Build pipeline, entry points, multi-page setup, content hashing |
50
50
  | **AI & Chat** | `docs/ai.md` | Chat completions, RAG, streaming, tool calling, voice, podcasts, TTS |
51
51
  | **Analytics** | `docs/analytics.md` | Fire-and-forget page/click/tag analytics plus admin dashboard queries |
52
+ | **Translations** | `docs/translations.md` | Runtime translation lookup, local-first IndexedDB caching, and translation admin APIs |
52
53
  | **Theming** | `docs/theme.system.md` | Implementing dynamic themes via URL params or postMessage |
53
54
  | **Theme Defaults** | `docs/theme-defaults.md` | Default colour values for light/dark modes |
54
55
  | **Internationalization** | `docs/i18n.md` | Adding multi-language support, translation patterns |