@proveanything/smartlinks 1.3.26 → 1.3.28

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
@@ -18,6 +18,7 @@ For the full list of functions and types, see the API summary:
18
18
  - [Widgets](docs/widgets.md) - Embeddable React components
19
19
  - [Realtime](docs/realtime.md) - Realtime data updates
20
20
  - [iframe Responder](docs/iframe-responder.md) - iframe integration
21
+ - [Utilities](docs/utils.md) - Helper functions for paths, URLs, and common tasks
21
22
 
22
23
  ## Install
23
24
 
@@ -159,6 +160,53 @@ try {
159
160
 
160
161
  For comprehensive error handling examples and migration guidance, see [examples/error-handling-demo.ts](examples/error-handling-demo.ts).
161
162
 
163
+ ## Utility Functions
164
+
165
+ The SDK includes a simple utility for building portal URLs. Pass in objects and it extracts what it needs:
166
+
167
+ ### Build Portal Paths
168
+
169
+ ```ts
170
+ import { utils } from '@proveanything/smartlinks'
171
+
172
+ // Pass in objects - extracts shortId, portalUrl, product ID, GTIN, etc.
173
+ const url = utils.buildPortalPath({
174
+ collection: myCollection,
175
+ product: myProduct // reads ownGtin from product
176
+ })
177
+ // Returns: https://portal.smartlinks.io/c/abc123/prod1
178
+
179
+ // With proof object
180
+ const withProof = utils.buildPortalPath({
181
+ collection: myCollection,
182
+ product: myProduct,
183
+ proof: myProof
184
+ })
185
+ // Returns: https://portal.smartlinks.io/c/abc123/prod1/proof1
186
+
187
+ // GTIN path (ownGtin read from product.ownGtin)
188
+ const gtinPath = utils.buildPortalPath({
189
+ collection: myCollection,
190
+ product: myProduct, // if product.ownGtin is true, uses /01/ format
191
+ batch: myBatch, // extracts batch ID and expiry date
192
+ variant: myVariant
193
+ })
194
+ // Returns: https://portal.smartlinks.io/01/1234567890123/10/batch1/22/var1?17=260630
195
+
196
+ // Or pass just IDs if you don't have full objects
197
+ const simple = utils.buildPortalPath({
198
+ collection: { shortId: 'abc123' },
199
+ productId: 'prod1',
200
+ batchId: 'batch1', // just string, no expiry
201
+ queryParams: { utm_source: 'email' }
202
+ })
203
+ // Returns: /c/abc123/prod1?utm_source=email
204
+ ```
205
+
206
+ Pass objects where you have them (collection, product, batch, variant, proof) and the function extracts the needed properties. Or pass just IDs (productId, batchId) for simpler cases.
207
+
208
+ For complete documentation, see [docs/utils.md](docs/utils.md).
209
+
162
210
  ## Common tasks
163
211
 
164
212
  ### Products
package/dist/api/ai.d.ts CHANGED
@@ -1,382 +1,5 @@
1
- /** Content part for multimodal messages */
2
- export interface ContentPart {
3
- type: 'text' | 'image_url';
4
- text?: string;
5
- image_url?: {
6
- url: string;
7
- detail?: 'auto' | 'low' | 'high';
8
- };
9
- }
10
- /** Function call representation */
11
- export interface FunctionCall {
12
- name: string;
13
- arguments: string;
14
- }
15
- /** Tool call representation */
16
- export interface ToolCall {
17
- id: string;
18
- type: 'function';
19
- function: {
20
- name: string;
21
- arguments: string;
22
- };
23
- }
24
- /** Chat message with role and content */
25
- export interface ChatMessage {
26
- role: 'system' | 'user' | 'assistant' | 'function' | 'tool';
27
- content: string | ContentPart[];
28
- name?: string;
29
- function_call?: FunctionCall;
30
- tool_calls?: ToolCall[];
31
- tool_call_id?: string;
32
- }
33
- /** Tool/Function definition */
34
- export interface ToolDefinition {
35
- type: 'function';
36
- function: {
37
- name: string;
38
- description: string;
39
- parameters: {
40
- type: 'object';
41
- properties: Record<string, {
42
- type: string;
43
- description?: string;
44
- enum?: string[];
45
- }>;
46
- required?: string[];
47
- };
48
- };
49
- }
50
- /** Chat completion request */
51
- export interface ChatCompletionRequest {
52
- messages: ChatMessage[];
53
- model?: string;
54
- stream?: boolean;
55
- tools?: ToolDefinition[];
56
- tool_choice?: 'none' | 'auto' | 'required' | {
57
- type: 'function';
58
- function: {
59
- name: string;
60
- };
61
- };
62
- temperature?: number;
63
- max_tokens?: number;
64
- top_p?: number;
65
- frequency_penalty?: number;
66
- presence_penalty?: number;
67
- response_format?: {
68
- type: 'text' | 'json_object';
69
- };
70
- user?: string;
71
- }
72
- /** Chat completion choice */
73
- export interface ChatCompletionChoice {
74
- index: number;
75
- message: ChatMessage;
76
- finish_reason: 'stop' | 'length' | 'function_call' | 'tool_calls' | 'content_filter' | null;
77
- }
78
- /** Chat completion response */
79
- export interface ChatCompletionResponse {
80
- id: string;
81
- object: 'chat.completion';
82
- created: number;
83
- model: string;
84
- choices: ChatCompletionChoice[];
85
- usage: {
86
- prompt_tokens: number;
87
- completion_tokens: number;
88
- total_tokens: number;
89
- };
90
- }
91
- /** Streaming chunk */
92
- export interface ChatCompletionChunk {
93
- id: string;
94
- object: 'chat.completion.chunk';
95
- created: number;
96
- model: string;
97
- choices: Array<{
98
- index: number;
99
- delta: Partial<ChatMessage>;
100
- finish_reason: string | null;
101
- }>;
102
- }
103
- /** AI Model information */
104
- export interface AIModel {
105
- id: string;
106
- provider: 'gemini' | 'openai';
107
- modelId: string;
108
- name: string;
109
- description: string;
110
- capabilities: Array<'text' | 'vision' | 'audio' | 'code'>;
111
- contextWindow: number;
112
- pricing: {
113
- input: number;
114
- output: number;
115
- cached?: number;
116
- };
117
- features: string[];
118
- recommended?: string;
119
- }
120
- /** List of models */
121
- export interface ModelList {
122
- object: 'list';
123
- data: AIModel[];
124
- }
125
- /** Document chunk with embedding */
126
- export interface DocumentChunk {
127
- text: string;
128
- embedding: number[];
129
- metadata: {
130
- chunkIndex: number;
131
- documentId: string;
132
- [key: string]: any;
133
- };
134
- }
135
- /** Index document request */
136
- export interface IndexDocumentRequest {
137
- productId: string;
138
- text?: string;
139
- documentUrl?: string;
140
- metadata?: Record<string, any>;
141
- chunkSize?: number;
142
- overlap?: number;
143
- provider?: 'openai' | 'gemini';
144
- }
145
- /** Index document response */
146
- export interface IndexDocumentResponse {
147
- success: boolean;
148
- productId: string;
149
- documentId: string;
150
- chunks: number;
151
- metadata: {
152
- textLength: number;
153
- chunkSize: number;
154
- overlap: number;
155
- embeddingDimensions: number;
156
- };
157
- sample?: {
158
- text: string;
159
- chunkIndex: number;
160
- };
161
- }
162
- /** Configure assistant request */
163
- export interface ConfigureAssistantRequest {
164
- productId: string;
165
- systemPrompt?: string;
166
- model?: string;
167
- maxTokensPerResponse?: number;
168
- temperature?: number;
169
- rateLimitPerUser?: number;
170
- allowedTopics?: string[];
171
- customInstructions?: {
172
- tone?: string;
173
- additionalRules?: string;
174
- [key: string]: any;
175
- };
176
- }
177
- /** Configure assistant response */
178
- export interface ConfigureAssistantResponse {
179
- success: boolean;
180
- configuration: {
181
- productId: string;
182
- systemPrompt: string;
183
- model: string;
184
- maxTokensPerResponse: number;
185
- temperature: number;
186
- rateLimitPerUser: number;
187
- allowedTopics: string[];
188
- customInstructions?: Record<string, any>;
189
- updatedAt: string;
190
- };
191
- }
192
- /** Public chat request */
193
- export interface PublicChatRequest {
194
- productId: string;
195
- userId: string;
196
- message: string;
197
- sessionId?: string;
198
- stream?: boolean;
199
- }
200
- /** Public chat response */
201
- export interface PublicChatResponse {
202
- message: string;
203
- sessionId: string;
204
- usage: {
205
- prompt_tokens: number;
206
- completion_tokens: number;
207
- total_tokens: number;
208
- };
209
- context?: {
210
- chunksUsed: number;
211
- topSimilarity: number;
212
- };
213
- }
214
- /** Session information */
215
- export interface Session {
216
- sessionId: string;
217
- productId: string;
218
- userId: string;
219
- messageCount: number;
220
- createdAt: string;
221
- lastActivityAt: string;
222
- messages: ChatMessage[];
223
- }
224
- /** Rate limit status */
225
- export interface RateLimitStatus {
226
- used: number;
227
- remaining: number;
228
- resetAt: string;
229
- }
230
- /** Session statistics */
231
- export interface SessionStatistics {
232
- totalSessions: number;
233
- activeSessions: number;
234
- totalMessages: number;
235
- rateLimitedUsers: number;
236
- }
237
- /** Voice session request */
238
- export interface VoiceSessionRequest {
239
- productId: string;
240
- userId: string;
241
- collectionId: string;
242
- settings?: {
243
- voice?: string;
244
- language?: string;
245
- model?: string;
246
- };
247
- }
248
- /** Voice session response */
249
- export interface VoiceSessionResponse {
250
- token: string;
251
- systemInstruction: string;
252
- expiresAt: string;
253
- productName: string;
254
- }
255
- /** Ephemeral token request */
256
- export interface EphemeralTokenRequest {
257
- settings?: {
258
- ttl?: number;
259
- voice?: string;
260
- language?: string;
261
- model?: string;
262
- };
263
- }
264
- /** Ephemeral token response */
265
- export interface EphemeralTokenResponse {
266
- token: string;
267
- expiresAt: string;
268
- }
269
- /** Transcription response */
270
- export interface TranscriptionResponse {
271
- text: string;
272
- }
273
- /** TTS request */
274
- export interface TTSRequest {
275
- text: string;
276
- voice?: 'alloy' | 'echo' | 'fable' | 'onyx' | 'nova' | 'shimmer';
277
- speed?: number;
278
- format?: 'mp3' | 'opus' | 'aac' | 'flac';
279
- }
280
- /** Podcast generation request */
281
- export interface GeneratePodcastRequest {
282
- productId: string;
283
- documentText?: string;
284
- duration?: number;
285
- style?: 'casual' | 'professional' | 'educational' | 'entertaining';
286
- voices?: {
287
- host1?: string;
288
- host2?: string;
289
- };
290
- includeAudio?: boolean;
291
- language?: string;
292
- customInstructions?: string;
293
- }
294
- /** Podcast script segment */
295
- export interface PodcastSegment {
296
- speaker: 'host1' | 'host2';
297
- text: string;
298
- timestamp?: number;
299
- duration?: number;
300
- }
301
- /** Podcast script */
302
- export interface PodcastScript {
303
- title: string;
304
- description: string;
305
- segments: PodcastSegment[];
306
- }
307
- /** Podcast generation response */
308
- export interface GeneratePodcastResponse {
309
- success: boolean;
310
- podcastId: string;
311
- script: PodcastScript;
312
- audio?: {
313
- host1Url?: string;
314
- host2Url?: string;
315
- mixedUrl?: string;
316
- };
317
- metadata: {
318
- duration: number;
319
- wordCount: number;
320
- generatedAt: string;
321
- };
322
- }
323
- /** Podcast status */
324
- export interface PodcastStatus {
325
- podcastId: string;
326
- status: 'generating_script' | 'generating_audio' | 'mixing' | 'completed' | 'failed';
327
- progress: number;
328
- estimatedTimeRemaining?: number;
329
- error?: string;
330
- result?: GeneratePodcastResponse;
331
- }
332
- export interface AIGenerateContentRequest {
333
- /** The prompt or message contents sent to the AI */
334
- contents: string | any;
335
- /** Desired MIME type of the response payload (e.g. 'application/json', 'text/plain') */
336
- responseMimeType?: string;
337
- /** Optional system instruction or system prompt to steer the model */
338
- systemInstruction?: string;
339
- /** AI provider identifier (e.g. 'openai', 'google', 'anthropic') */
340
- provider?: string;
341
- /** The model name to use (e.g. 'gpt-4o', 'gemini-1.5-pro') */
342
- model?: string;
343
- /** Allow passing additional provider/model-specific options */
344
- [key: string]: any;
345
- }
346
- export interface AIGenerateImageRequest {
347
- /** Text prompt describing the desired image */
348
- prompt: string;
349
- /** AI provider identifier (e.g. 'openai', 'google', 'stability') */
350
- provider?: string;
351
- /** Optional model name to use for image generation */
352
- model?: string;
353
- /** Requested image size, e.g. '1024x1024' */
354
- size?: string;
355
- /** Additional provider/model-specific options */
356
- [key: string]: any;
357
- }
358
- export interface AISearchPhotosRequest {
359
- /** Search query keyword(s) */
360
- query: string;
361
- /** Number of results to return per page (e.g. 1) */
362
- per_page?: number;
363
- /** Desired orientation of photos */
364
- orientation?: 'landscape' | 'portrait' | 'squarish';
365
- /** Additional provider-specific options */
366
- [key: string]: any;
367
- }
368
- export interface AISearchPhotosPhoto {
369
- /** Direct image URL */
370
- url: string;
371
- /** Alt text/description for accessibility */
372
- alt?: string;
373
- /** Photographer display name */
374
- photographer?: string;
375
- /** Link to the photographer profile */
376
- photographerUrl?: string;
377
- /** Allow extra fields */
378
- [key: string]: any;
379
- }
1
+ import type { ContentPart, FunctionCall, ToolCall, ChatMessage, ToolDefinition, ChatCompletionRequest, ChatCompletionChoice, ChatCompletionResponse, ChatCompletionChunk, AIModel, DocumentChunk, IndexDocumentRequest, IndexDocumentResponse, ConfigureAssistantRequest, ConfigureAssistantResponse, PublicChatRequest, PublicChatResponse, Session, RateLimitStatus, SessionStatistics, VoiceSessionRequest, VoiceSessionResponse, EphemeralTokenRequest, EphemeralTokenResponse, TranscriptionResponse, TTSRequest, GeneratePodcastRequest, PodcastScript, GeneratePodcastResponse, PodcastStatus, AIGenerateContentRequest, AIGenerateImageRequest, AISearchPhotosRequest, AISearchPhotosPhoto } from "../types/ai";
2
+ export type { ContentPart, FunctionCall, ToolCall, ChatMessage, ToolDefinition, ChatCompletionRequest, ChatCompletionChoice, ChatCompletionResponse, ChatCompletionChunk, AIModel, DocumentChunk, IndexDocumentRequest, IndexDocumentResponse, ConfigureAssistantRequest, ConfigureAssistantResponse, PublicChatRequest, PublicChatResponse, Session, RateLimitStatus, SessionStatistics, VoiceSessionRequest, VoiceSessionResponse, EphemeralTokenRequest, EphemeralTokenResponse, TranscriptionResponse, TTSRequest, GeneratePodcastRequest, PodcastScript, GeneratePodcastResponse, PodcastStatus, AIGenerateContentRequest, AIGenerateImageRequest, AISearchPhotosRequest, AISearchPhotosPhoto, };
380
3
  export declare namespace ai {
381
4
  namespace chat {
382
5
  namespace completions {
@@ -393,7 +16,10 @@ export declare namespace ai {
393
16
  /**
394
17
  * List available AI models
395
18
  */
396
- function list(collectionId: string): Promise<ModelList>;
19
+ function list(collectionId: string): Promise<{
20
+ object: 'list';
21
+ data: AIModel[];
22
+ }>;
397
23
  /**
398
24
  * Get specific model information
399
25
  */
package/dist/api/ai.js CHANGED
@@ -17,7 +17,7 @@ export var ai;
17
17
  * @returns Chat completion response or async iterable for streaming
18
18
  */
19
19
  async function create(collectionId, request) {
20
- const path = `/admin/${encodeURIComponent(collectionId)}/ai/v1/chat/completions`;
20
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/ai/v1/chat/completions`;
21
21
  if (request.stream) {
22
22
  // TODO: Implement streaming via SSE
23
23
  throw new Error('Streaming not yet implemented');
@@ -36,7 +36,7 @@ export var ai;
36
36
  * List available AI models
37
37
  */
38
38
  async function list(collectionId) {
39
- const path = `/admin/${encodeURIComponent(collectionId)}/ai/models`;
39
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/ai/models`;
40
40
  return request(path);
41
41
  }
42
42
  models.list = list;
@@ -44,7 +44,7 @@ export var ai;
44
44
  * Get specific model information
45
45
  */
46
46
  async function get(collectionId, modelId) {
47
- const path = `/admin/${encodeURIComponent(collectionId)}/ai/models/${encodeURIComponent(modelId)}`;
47
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/ai/models/${encodeURIComponent(modelId)}`;
48
48
  return request(path);
49
49
  }
50
50
  models.get = get;
@@ -58,7 +58,7 @@ export var ai;
58
58
  * Index a document for RAG
59
59
  */
60
60
  async function indexDocument(collectionId, request) {
61
- const path = `/admin/${encodeURIComponent(collectionId)}/ai/indexDocument`;
61
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/ai/indexDocument`;
62
62
  return post(path, request);
63
63
  }
64
64
  rag.indexDocument = indexDocument;
@@ -66,7 +66,7 @@ export var ai;
66
66
  * Configure AI assistant behavior
67
67
  */
68
68
  async function configureAssistant(collectionId, request) {
69
- const path = `/admin/${encodeURIComponent(collectionId)}/ai/configureAssistant`;
69
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/ai/configureAssistant`;
70
70
  return post(path, request);
71
71
  }
72
72
  rag.configureAssistant = configureAssistant;
@@ -80,7 +80,7 @@ export var ai;
80
80
  * Get session statistics
81
81
  */
82
82
  async function stats(collectionId) {
83
- const path = `/admin/${encodeURIComponent(collectionId)}/ai/sessions/stats`;
83
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/ai/sessions/stats`;
84
84
  return request(path);
85
85
  }
86
86
  sessions.stats = stats;
@@ -94,7 +94,7 @@ export var ai;
94
94
  * Reset rate limit for a user
95
95
  */
96
96
  async function reset(collectionId, userId) {
97
- const path = `/admin/${encodeURIComponent(collectionId)}/ai/rate-limit/${encodeURIComponent(userId)}/reset`;
97
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/ai/rate-limit/${encodeURIComponent(userId)}/reset`;
98
98
  return post(path, {});
99
99
  }
100
100
  rateLimit.reset = reset;
@@ -108,7 +108,7 @@ export var ai;
108
108
  * Generate a NotebookLM-style conversational podcast from product documents
109
109
  */
110
110
  async function generate(collectionId, request) {
111
- const path = `/admin/${encodeURIComponent(collectionId)}/ai/generatePodcast`;
111
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/ai/generatePodcast`;
112
112
  return post(path, request);
113
113
  }
114
114
  podcast.generate = generate;
@@ -116,7 +116,7 @@ export var ai;
116
116
  * Get podcast generation status
117
117
  */
118
118
  async function getStatus(collectionId, podcastId) {
119
- const path = `/admin/${encodeURIComponent(collectionId)}/ai/podcast/${encodeURIComponent(podcastId)}`;
119
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/ai/podcast/${encodeURIComponent(podcastId)}`;
120
120
  return request(path);
121
121
  }
122
122
  podcast.getStatus = getStatus;
@@ -130,7 +130,7 @@ export var ai;
130
130
  * Generate text-to-speech audio
131
131
  */
132
132
  async function generate(collectionId, request) {
133
- const path = `/admin/${encodeURIComponent(collectionId)}/ai/tts`;
133
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/ai/tts`;
134
134
  // Note: This would need special handling for binary response
135
135
  return post(path, request);
136
136
  }
@@ -145,7 +145,7 @@ export var ai;
145
145
  * Chat with product assistant (RAG)
146
146
  */
147
147
  async function chat(collectionId, request) {
148
- const path = `/${encodeURIComponent(collectionId)}/ai/chat`;
148
+ const path = `/public/collection/${encodeURIComponent(collectionId)}/ai/chat`;
149
149
  return post(path, request);
150
150
  }
151
151
  publicApi.chat = chat;
@@ -153,7 +153,7 @@ export var ai;
153
153
  * Get session history
154
154
  */
155
155
  async function getSession(collectionId, sessionId) {
156
- const path = `/${encodeURIComponent(collectionId)}/ai/session/${encodeURIComponent(sessionId)}`;
156
+ const path = `/public/collection/${encodeURIComponent(collectionId)}/ai/session/${encodeURIComponent(sessionId)}`;
157
157
  return request(path);
158
158
  }
159
159
  publicApi.getSession = getSession;
@@ -161,7 +161,7 @@ export var ai;
161
161
  * Clear session history
162
162
  */
163
163
  async function clearSession(collectionId, sessionId) {
164
- const path = `/${encodeURIComponent(collectionId)}/ai/session/${encodeURIComponent(sessionId)}`;
164
+ const path = `/public/collection/${encodeURIComponent(collectionId)}/ai/session/${encodeURIComponent(sessionId)}`;
165
165
  return del(path);
166
166
  }
167
167
  publicApi.clearSession = clearSession;
@@ -169,7 +169,7 @@ export var ai;
169
169
  * Check rate limit status
170
170
  */
171
171
  async function getRateLimit(collectionId, userId) {
172
- const path = `/${encodeURIComponent(collectionId)}/ai/rate-limit/${encodeURIComponent(userId)}`;
172
+ const path = `/public/collection/${encodeURIComponent(collectionId)}/ai/rate-limit/${encodeURIComponent(userId)}`;
173
173
  return request(path);
174
174
  }
175
175
  publicApi.getRateLimit = getRateLimit;
@@ -177,7 +177,7 @@ export var ai;
177
177
  * Generate ephemeral token for Gemini Live
178
178
  */
179
179
  async function getToken(collectionId, request) {
180
- const path = `/${encodeURIComponent(collectionId)}/ai/token`;
180
+ const path = `/public/collection/${encodeURIComponent(collectionId)}/ai/token`;
181
181
  return post(path, request);
182
182
  }
183
183
  publicApi.getToken = getToken;
@@ -29,4 +29,3 @@ export { location } from "./location";
29
29
  export * as realtime from "./realtime";
30
30
  export { tags } from "./tags";
31
31
  export { order } from "./order";
32
- export type { AIGenerateContentRequest, AIGenerateImageRequest, AISearchPhotosRequest, AISearchPhotosPhoto, ContentPart, FunctionCall, ToolCall, ChatMessage, ToolDefinition, ChatCompletionRequest, ChatCompletionChoice, ChatCompletionResponse, ChatCompletionChunk, AIModel, ModelList, DocumentChunk, IndexDocumentRequest, IndexDocumentResponse, ConfigureAssistantRequest, ConfigureAssistantResponse, PublicChatRequest, PublicChatResponse, Session, RateLimitStatus, SessionStatistics, VoiceSessionRequest, VoiceSessionResponse, EphemeralTokenRequest, EphemeralTokenResponse, TranscriptionResponse, TTSRequest, GeneratePodcastRequest, GeneratePodcastResponse, PodcastScript, PodcastSegment, PodcastStatus, } from "./ai";