@proveanything/smartlinks 1.4.0 → 1.4.2
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 +52 -27
- package/dist/docs/ai-guide-template.md +241 -0
- package/dist/types/appManifest.d.ts +70 -19
- package/docs/API_SUMMARY.md +52 -27
- package/docs/ai-guide-template.md +241 -0
- 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.4.
|
|
3
|
+
Version: 1.4.2 | Generated: 2026-02-20T21:56:06.588Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -18,6 +18,7 @@ For detailed guides on specific features:
|
|
|
18
18
|
- **[Theme Defaults](theme-defaults.md)** - Default theme values and presets
|
|
19
19
|
- **[Proof Claiming Methods](proof-claiming-methods.md)** - All methods for claiming/registering product ownership (NFC tags, serial numbers, auto-generated claims)
|
|
20
20
|
- **[App Data Storage](app-data-storage.md)** - User-specific and collection-scoped app data storage
|
|
21
|
+
- **[AI Guide Template](ai-guide-template.md)** - A sample for an app on how to build an AI setup guide
|
|
21
22
|
|
|
22
23
|
## API Namespaces
|
|
23
24
|
|
|
@@ -820,6 +821,41 @@ interface AppConfigurationResponse {
|
|
|
820
821
|
|
|
821
822
|
### appManifest
|
|
822
823
|
|
|
824
|
+
**AppBundle** (interface)
|
|
825
|
+
```typescript
|
|
826
|
+
interface AppBundle {
|
|
827
|
+
js: string | null;
|
|
828
|
+
css: string | null;
|
|
829
|
+
source?: string;
|
|
830
|
+
styles?: string;
|
|
831
|
+
}
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
**AppWidgetDefinition** (interface)
|
|
835
|
+
```typescript
|
|
836
|
+
interface AppWidgetDefinition {
|
|
837
|
+
name: string;
|
|
838
|
+
description?: string;
|
|
839
|
+
sizes?: Array<'compact' | 'standard' | 'large' | string>;
|
|
840
|
+
props?: {
|
|
841
|
+
required?: string[];
|
|
842
|
+
optional?: string[];
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
**AppContainerDefinition** (interface)
|
|
848
|
+
```typescript
|
|
849
|
+
interface AppContainerDefinition {
|
|
850
|
+
name: string;
|
|
851
|
+
description?: string;
|
|
852
|
+
props?: {
|
|
853
|
+
required?: string[];
|
|
854
|
+
optional?: string[];
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
```
|
|
858
|
+
|
|
823
859
|
**AppManifest** (interface)
|
|
824
860
|
```typescript
|
|
825
861
|
interface AppManifest {
|
|
@@ -831,15 +867,8 @@ interface AppManifest {
|
|
|
831
867
|
platformRevision?: string;
|
|
832
868
|
appId: string;
|
|
833
869
|
};
|
|
834
|
-
widgets?:
|
|
835
|
-
|
|
836
|
-
description?: string;
|
|
837
|
-
sizes?: string[];
|
|
838
|
-
props?: {
|
|
839
|
-
required?: string[];
|
|
840
|
-
optional?: string[];
|
|
841
|
-
};
|
|
842
|
-
}>;
|
|
870
|
+
widgets?: AppWidgetDefinition[];
|
|
871
|
+
containers?: AppContainerDefinition[];
|
|
843
872
|
setup?: {
|
|
844
873
|
description?: string;
|
|
845
874
|
questions?: Array<{
|
|
@@ -848,12 +877,14 @@ interface AppManifest {
|
|
|
848
877
|
type: string;
|
|
849
878
|
default?: any;
|
|
850
879
|
required?: boolean;
|
|
880
|
+
options?: Array<{ value: string; label: string }>;
|
|
851
881
|
}>;
|
|
852
882
|
configSchema?: Record<string, any>;
|
|
853
883
|
saveWith?: {
|
|
854
884
|
method: string;
|
|
855
|
-
scope: string;
|
|
885
|
+
scope: 'collection' | 'product' | string;
|
|
856
886
|
admin?: boolean;
|
|
887
|
+
note?: string;
|
|
857
888
|
};
|
|
858
889
|
contentHints?: Record<string, {
|
|
859
890
|
aiGenerate?: boolean;
|
|
@@ -884,44 +915,38 @@ interface AppManifest {
|
|
|
884
915
|
name: string;
|
|
885
916
|
description?: string;
|
|
886
917
|
type: string;
|
|
918
|
+
options?: string[];
|
|
887
919
|
}>;
|
|
888
920
|
};
|
|
889
921
|
metrics?: {
|
|
890
|
-
interactions?: Array<{
|
|
891
|
-
|
|
892
|
-
description?: string;
|
|
893
|
-
}>;
|
|
894
|
-
kpis?: Array<{
|
|
895
|
-
name: string;
|
|
896
|
-
compute?: string;
|
|
897
|
-
}>;
|
|
922
|
+
interactions?: Array<{ id: string; description?: string }>;
|
|
923
|
+
kpis?: Array<{ name: string; compute?: string }>;
|
|
898
924
|
};
|
|
899
|
-
[key: string]: any;
|
|
925
|
+
[key: string]: any;
|
|
900
926
|
}
|
|
901
927
|
```
|
|
902
928
|
|
|
903
|
-
**
|
|
929
|
+
**CollectionAppWidget** (interface)
|
|
904
930
|
```typescript
|
|
905
|
-
interface
|
|
931
|
+
interface CollectionAppWidget {
|
|
906
932
|
appId: string;
|
|
907
|
-
manifestUrl: string;
|
|
908
933
|
manifest: AppManifest;
|
|
909
|
-
|
|
910
|
-
|
|
934
|
+
widget: AppBundle;
|
|
935
|
+
container: AppBundle | null;
|
|
911
936
|
}
|
|
912
937
|
```
|
|
913
938
|
|
|
914
939
|
**CollectionWidgetsResponse** (interface)
|
|
915
940
|
```typescript
|
|
916
941
|
interface CollectionWidgetsResponse {
|
|
917
|
-
apps:
|
|
942
|
+
apps: CollectionAppWidget[];
|
|
918
943
|
}
|
|
919
944
|
```
|
|
920
945
|
|
|
921
946
|
**GetCollectionWidgetsOptions** (interface)
|
|
922
947
|
```typescript
|
|
923
948
|
interface GetCollectionWidgetsOptions {
|
|
924
|
-
force?: boolean;
|
|
949
|
+
force?: boolean;
|
|
925
950
|
}
|
|
926
951
|
```
|
|
927
952
|
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# AI Guide: Example App
|
|
2
|
+
|
|
3
|
+
<!-- CUSTOMIZE: Replace "Example App" and all content below with your app's specifics. -->
|
|
4
|
+
<!-- This file is consumed by AI orchestrators alongside public/app.manifest.json. -->
|
|
5
|
+
<!-- The manifest provides structured data; this file provides prose context and nuance. -->
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Purpose & Identity
|
|
10
|
+
|
|
11
|
+
<!-- CUSTOMIZE: Describe what your app does in 2-3 sentences. -->
|
|
12
|
+
|
|
13
|
+
The **Example App** is a template SmartLinks microapp that demonstrates all platform patterns including setup wizards, data imports, widget embedding, and analytics. It serves as a reference implementation for app authors building on the SmartLinks platform.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Setup Wizard Instructions
|
|
18
|
+
|
|
19
|
+
An AI orchestrator should follow these steps to configure the Example App for a collection. The structured questions and schema are in `app.manifest.json` under `setup`.
|
|
20
|
+
|
|
21
|
+
### Prerequisites
|
|
22
|
+
|
|
23
|
+
- The user must have **admin access** to the target collection.
|
|
24
|
+
- The `collectionId` and `appId` must be known (typically from URL context).
|
|
25
|
+
|
|
26
|
+
### Questions to Ask
|
|
27
|
+
|
|
28
|
+
Walk the user through each question defined in `setup.questions[]` of the manifest:
|
|
29
|
+
|
|
30
|
+
1. **App Title** (`appTitle`): Ask what the app should be called. Offer to auto-generate a suggestion using `SL.ai.chat.completions` if the user wants help (see `contentHints` in the manifest).
|
|
31
|
+
2. **Enable Notifications** (`enableNotifications`): Ask whether the app should send notifications to users.
|
|
32
|
+
|
|
33
|
+
<!-- CUSTOMIZE: Add app-specific guidance for each question. For example: -->
|
|
34
|
+
<!-- "If the user is setting up a competition, suggest a title like 'Win a [Product Name]!'" -->
|
|
35
|
+
<!-- "For plant passports, notifications are typically disabled." -->
|
|
36
|
+
|
|
37
|
+
### How to Save the Config
|
|
38
|
+
|
|
39
|
+
After collecting answers, validate against `setup.configSchema` and save:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
await SL.appConfiguration.setConfig({
|
|
43
|
+
collectionId,
|
|
44
|
+
appId,
|
|
45
|
+
config: {
|
|
46
|
+
appTitle: "User's chosen title",
|
|
47
|
+
enableNotifications: false
|
|
48
|
+
},
|
|
49
|
+
admin: true // REQUIRED for admin operations
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Post-Setup Verification
|
|
54
|
+
|
|
55
|
+
After saving, confirm by reading the config back:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
const saved = await SL.appConfiguration.getConfig({
|
|
59
|
+
collectionId,
|
|
60
|
+
appId,
|
|
61
|
+
admin: true
|
|
62
|
+
});
|
|
63
|
+
// Verify saved.appTitle and saved.enableNotifications match expectations
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Tell the user: "Your app is configured! You can adjust settings anytime by asking me to update the configuration."
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Import Instructions
|
|
71
|
+
|
|
72
|
+
The app supports bulk import of product-level configuration. The field definitions are in `app.manifest.json` under `import`.
|
|
73
|
+
|
|
74
|
+
### CSV Template
|
|
75
|
+
|
|
76
|
+
Generate or share this template with the user:
|
|
77
|
+
|
|
78
|
+
```csv
|
|
79
|
+
productId,appTitle,enableNotifications
|
|
80
|
+
prod_001,My First Product,true
|
|
81
|
+
prod_002,My Second Product,false
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
<!-- CUSTOMIZE: Add real-world examples relevant to your app. -->
|
|
85
|
+
|
|
86
|
+
### Field Validation Rules
|
|
87
|
+
|
|
88
|
+
| Field | Type | Required | Validation |
|
|
89
|
+
| --------------------- | ------- | -------- | ------------------------------------- |
|
|
90
|
+
| `productId` | string | ✅ | Must be a valid SmartLinks product ID |
|
|
91
|
+
| `appTitle` | string | ✅ | Non-empty string |
|
|
92
|
+
| `enableNotifications` | boolean | ❌ | Defaults to `false` |
|
|
93
|
+
|
|
94
|
+
<!-- CUSTOMIZE: Add app-specific validation rules. For example: -->
|
|
95
|
+
<!-- "For plant passports: botanicalName must be in Latin binomial format." -->
|
|
96
|
+
|
|
97
|
+
### API Call Sequence
|
|
98
|
+
|
|
99
|
+
For each row in the CSV:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
await SL.appConfiguration.setConfig({
|
|
103
|
+
collectionId,
|
|
104
|
+
productId: row.productId, // From CSV
|
|
105
|
+
appId,
|
|
106
|
+
config: {
|
|
107
|
+
appTitle: row.appTitle,
|
|
108
|
+
enableNotifications: row.enableNotifications ?? false
|
|
109
|
+
},
|
|
110
|
+
admin: true
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Error Handling
|
|
115
|
+
|
|
116
|
+
- If a `productId` is invalid, log the error and continue with the next row.
|
|
117
|
+
- After processing all rows, report a summary: `"Imported X of Y products successfully. Z failed."`.
|
|
118
|
+
- For failed rows, list the product ID and error message so the user can fix the data.
|
|
119
|
+
|
|
120
|
+
### Cross-App Import
|
|
121
|
+
|
|
122
|
+
When importing data for multiple apps simultaneously:
|
|
123
|
+
|
|
124
|
+
1. Fetch `app.manifest.json` from each app.
|
|
125
|
+
2. Merge `import.fields` arrays (prefix field names with app name if there are conflicts).
|
|
126
|
+
3. Generate a combined CSV template.
|
|
127
|
+
4. For each row, split into separate payloads per app and call each app's `saveWith.method`.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Widget Embedding Guide
|
|
132
|
+
|
|
133
|
+
### Available Widgets
|
|
134
|
+
|
|
135
|
+
| Widget | Description | Sizes |
|
|
136
|
+
| --------------- | ------------------------------------------ | ------------------------ |
|
|
137
|
+
| `ExampleWidget` | Demo widget showing SmartLinks integration | compact, standard, large |
|
|
138
|
+
|
|
139
|
+
<!-- CUSTOMIZE: List all widgets your app exports. -->
|
|
140
|
+
|
|
141
|
+
### Props Reference
|
|
142
|
+
|
|
143
|
+
All widgets receive `SmartLinksWidgetProps`:
|
|
144
|
+
|
|
145
|
+
| Prop | Type | Required | Description |
|
|
146
|
+
| ----------------- | -------------- | -------- | --------------------------------------- |
|
|
147
|
+
| `collectionId` | string | ✅ | Collection context |
|
|
148
|
+
| `appId` | string | ✅ | App identifier |
|
|
149
|
+
| `SL` | SmartLinks SDK | ✅ | Pre-initialized SDK instance |
|
|
150
|
+
| `productId` | string | ❌ | Product context |
|
|
151
|
+
| `proofId` | string | ❌ | Proof context |
|
|
152
|
+
| `user` | object | ❌ | Current user info |
|
|
153
|
+
| `onNavigate` | function | ❌ | Navigation callback |
|
|
154
|
+
| `publicPortalUrl` | string | ❌ | URL to full app for deep linking |
|
|
155
|
+
| `size` | string | ❌ | `"compact"`, `"standard"`, or `"large"` |
|
|
156
|
+
| `lang` | string | ❌ | Language code (e.g., `"en"`) |
|
|
157
|
+
| `translations` | object | ❌ | Translation overrides |
|
|
158
|
+
|
|
159
|
+
### Example Code
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
import { ExampleWidget } from '@my-app/widgets';
|
|
163
|
+
|
|
164
|
+
<ExampleWidget
|
|
165
|
+
collectionId="col_123"
|
|
166
|
+
appId="example-app"
|
|
167
|
+
SL={SL}
|
|
168
|
+
size="standard"
|
|
169
|
+
onNavigate={(path) => router.push(path)}
|
|
170
|
+
/>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
<!-- CUSTOMIZE: Show real widget usage with app-specific props. -->
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Tunable Settings
|
|
178
|
+
|
|
179
|
+
These settings can be adjusted after initial setup without reconfiguring everything. The AI can modify them in response to user requests like "turn off notifications" or optimization suggestions.
|
|
180
|
+
|
|
181
|
+
| Setting | Type | Description |
|
|
182
|
+
| --------------------- | ------- | ------------------------------ |
|
|
183
|
+
| `enableNotifications` | boolean | Toggle notifications on or off |
|
|
184
|
+
|
|
185
|
+
<!-- CUSTOMIZE: List all tunable fields with guidance on when to change them. -->
|
|
186
|
+
|
|
187
|
+
To update a tunable setting:
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// 1. Read current config
|
|
191
|
+
const current = await SL.appConfiguration.getConfig({ collectionId, appId, admin: true });
|
|
192
|
+
|
|
193
|
+
// 2. Merge the change
|
|
194
|
+
await SL.appConfiguration.setConfig({
|
|
195
|
+
collectionId,
|
|
196
|
+
appId,
|
|
197
|
+
config: { ...current, enableNotifications: true },
|
|
198
|
+
admin: true
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Metrics & Analytics
|
|
205
|
+
|
|
206
|
+
### Tracked Interactions
|
|
207
|
+
|
|
208
|
+
| Interaction ID | Description |
|
|
209
|
+
| -------------- | --------------------------------------------- |
|
|
210
|
+
| `page-view` | Tracks each time a user views the public page |
|
|
211
|
+
|
|
212
|
+
<!-- CUSTOMIZE: List all interaction IDs your app tracks. -->
|
|
213
|
+
|
|
214
|
+
### KPIs
|
|
215
|
+
|
|
216
|
+
| KPI | How to Compute |
|
|
217
|
+
| ----------- | -------------------------------------------------------------------------------------- |
|
|
218
|
+
| Total Views | `SL.interactions.countsByOutcome(collectionId, { appId, interactionId: 'page-view' })` |
|
|
219
|
+
|
|
220
|
+
<!-- CUSTOMIZE: Add app-specific KPIs and interpretation guidance. -->
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Troubleshooting
|
|
225
|
+
|
|
226
|
+
### Common Issues
|
|
227
|
+
|
|
228
|
+
| Issue | Cause | Fix |
|
|
229
|
+
| --------------------- | -------------------------- | ----------------------------------------------------- |
|
|
230
|
+
| Config save fails | Missing `admin: true` flag | Always include `admin: true` for admin operations |
|
|
231
|
+
| Widget doesn't render | Missing required props | Ensure `collectionId`, `appId`, and `SL` are provided |
|
|
232
|
+
| Import skips rows | Invalid `productId` | Verify product IDs exist in the collection |
|
|
233
|
+
| Theme not applied | Missing `?theme=` param | Check URL parameters or postMessage setup |
|
|
234
|
+
|
|
235
|
+
<!-- CUSTOMIZE: Add app-specific troubleshooting entries. -->
|
|
236
|
+
|
|
237
|
+
### Getting Help
|
|
238
|
+
|
|
239
|
+
- **SDK Docs**: `node_modules/@proveanything/smartlinks/docs/`
|
|
240
|
+
- **App Manifest**: `public/app.manifest.json`
|
|
241
|
+
- **Platform Guide**: `src/docs/smartlinks/about.md`
|
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* A bundle (widget or container) as returned by the collection widgets endpoint.
|
|
3
|
+
*
|
|
4
|
+
* The server currently returns URLs only. In future it may also inline the file
|
|
5
|
+
* contents when bundles are small or frequently accessed. Clients should check
|
|
6
|
+
* for inline content first and fall back to loading the URL.
|
|
7
|
+
*
|
|
8
|
+
* if (bundle.source) {
|
|
9
|
+
* // inline JS — create a Blob URL or inject directly
|
|
10
|
+
* } else if (bundle.js) {
|
|
11
|
+
* // load from URL
|
|
12
|
+
* }
|
|
13
|
+
*/
|
|
14
|
+
export interface AppBundle {
|
|
15
|
+
/** URL to the JavaScript file — load if `source` is absent */
|
|
16
|
+
js: string | null;
|
|
17
|
+
/** URL to the CSS file — load if `styles` is absent */
|
|
18
|
+
css: string | null;
|
|
19
|
+
/** Inlined JavaScript source (present when server bundles it inline) */
|
|
20
|
+
source?: string;
|
|
21
|
+
/** Inlined CSS styles (present when server bundles it inline) */
|
|
22
|
+
styles?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A single widget defined in the manifest.
|
|
26
|
+
* Presence of the `widgets` array means a widget bundle exists for this app.
|
|
27
|
+
*/
|
|
28
|
+
export interface AppWidgetDefinition {
|
|
29
|
+
name: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
sizes?: Array<'compact' | 'standard' | 'large' | string>;
|
|
32
|
+
props?: {
|
|
33
|
+
required?: string[];
|
|
34
|
+
optional?: string[];
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A single container defined in the manifest.
|
|
39
|
+
* Presence of the `containers` array means a container bundle exists for this app.
|
|
40
|
+
* Containers are full-page / embedded components (larger than widgets, no iframe needed).
|
|
41
|
+
*/
|
|
42
|
+
export interface AppContainerDefinition {
|
|
43
|
+
name: string;
|
|
44
|
+
description?: string;
|
|
45
|
+
props?: {
|
|
46
|
+
required?: string[];
|
|
47
|
+
optional?: string[];
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* SmartLinks App Manifest — the app.manifest.json structure.
|
|
4
52
|
*/
|
|
5
53
|
export interface AppManifest {
|
|
6
54
|
$schema?: string;
|
|
@@ -11,15 +59,10 @@ export interface AppManifest {
|
|
|
11
59
|
platformRevision?: string;
|
|
12
60
|
appId: string;
|
|
13
61
|
};
|
|
14
|
-
widgets
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
props?: {
|
|
19
|
-
required?: string[];
|
|
20
|
-
optional?: string[];
|
|
21
|
-
};
|
|
22
|
-
}>;
|
|
62
|
+
/** Presence means a widget bundle (widgets.umd.js / widgets.css) exists */
|
|
63
|
+
widgets?: AppWidgetDefinition[];
|
|
64
|
+
/** Presence means a container bundle (containers.umd.js / containers.css) exists */
|
|
65
|
+
containers?: AppContainerDefinition[];
|
|
23
66
|
setup?: {
|
|
24
67
|
description?: string;
|
|
25
68
|
questions?: Array<{
|
|
@@ -28,12 +71,17 @@ export interface AppManifest {
|
|
|
28
71
|
type: string;
|
|
29
72
|
default?: any;
|
|
30
73
|
required?: boolean;
|
|
74
|
+
options?: Array<{
|
|
75
|
+
value: string;
|
|
76
|
+
label: string;
|
|
77
|
+
}>;
|
|
31
78
|
}>;
|
|
32
79
|
configSchema?: Record<string, any>;
|
|
33
80
|
saveWith?: {
|
|
34
81
|
method: string;
|
|
35
|
-
scope: string;
|
|
82
|
+
scope: 'collection' | 'product' | string;
|
|
36
83
|
admin?: boolean;
|
|
84
|
+
note?: string;
|
|
37
85
|
};
|
|
38
86
|
contentHints?: Record<string, {
|
|
39
87
|
aiGenerate?: boolean;
|
|
@@ -64,6 +112,7 @@ export interface AppManifest {
|
|
|
64
112
|
name: string;
|
|
65
113
|
description?: string;
|
|
66
114
|
type: string;
|
|
115
|
+
options?: string[];
|
|
67
116
|
}>;
|
|
68
117
|
};
|
|
69
118
|
metrics?: {
|
|
@@ -79,24 +128,26 @@ export interface AppManifest {
|
|
|
79
128
|
[key: string]: any;
|
|
80
129
|
}
|
|
81
130
|
/**
|
|
82
|
-
*
|
|
131
|
+
* One app entry in the collection widgets response.
|
|
83
132
|
*/
|
|
84
|
-
export interface
|
|
133
|
+
export interface CollectionAppWidget {
|
|
85
134
|
appId: string;
|
|
86
|
-
manifestUrl: string;
|
|
87
135
|
manifest: AppManifest;
|
|
88
|
-
|
|
89
|
-
|
|
136
|
+
/** Widget bundle — always present (apps without widgets are excluded from the response) */
|
|
137
|
+
widget: AppBundle;
|
|
138
|
+
/** Container bundle — null when the app has no containers */
|
|
139
|
+
container: AppBundle | null;
|
|
90
140
|
}
|
|
91
141
|
/**
|
|
92
|
-
* Response from collection
|
|
142
|
+
* Response from GET /api/v1/public/collection/:collectionId/widgets
|
|
93
143
|
*/
|
|
94
144
|
export interface CollectionWidgetsResponse {
|
|
95
|
-
apps:
|
|
145
|
+
apps: CollectionAppWidget[];
|
|
96
146
|
}
|
|
97
147
|
/**
|
|
98
148
|
* Options for fetching collection widgets
|
|
99
149
|
*/
|
|
100
150
|
export interface GetCollectionWidgetsOptions {
|
|
151
|
+
/** Bypass server cache and fetch fresh manifests */
|
|
101
152
|
force?: boolean;
|
|
102
153
|
}
|
package/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.2 | Generated: 2026-02-20T21:56:06.588Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -18,6 +18,7 @@ For detailed guides on specific features:
|
|
|
18
18
|
- **[Theme Defaults](theme-defaults.md)** - Default theme values and presets
|
|
19
19
|
- **[Proof Claiming Methods](proof-claiming-methods.md)** - All methods for claiming/registering product ownership (NFC tags, serial numbers, auto-generated claims)
|
|
20
20
|
- **[App Data Storage](app-data-storage.md)** - User-specific and collection-scoped app data storage
|
|
21
|
+
- **[AI Guide Template](ai-guide-template.md)** - A sample for an app on how to build an AI setup guide
|
|
21
22
|
|
|
22
23
|
## API Namespaces
|
|
23
24
|
|
|
@@ -820,6 +821,41 @@ interface AppConfigurationResponse {
|
|
|
820
821
|
|
|
821
822
|
### appManifest
|
|
822
823
|
|
|
824
|
+
**AppBundle** (interface)
|
|
825
|
+
```typescript
|
|
826
|
+
interface AppBundle {
|
|
827
|
+
js: string | null;
|
|
828
|
+
css: string | null;
|
|
829
|
+
source?: string;
|
|
830
|
+
styles?: string;
|
|
831
|
+
}
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
**AppWidgetDefinition** (interface)
|
|
835
|
+
```typescript
|
|
836
|
+
interface AppWidgetDefinition {
|
|
837
|
+
name: string;
|
|
838
|
+
description?: string;
|
|
839
|
+
sizes?: Array<'compact' | 'standard' | 'large' | string>;
|
|
840
|
+
props?: {
|
|
841
|
+
required?: string[];
|
|
842
|
+
optional?: string[];
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
**AppContainerDefinition** (interface)
|
|
848
|
+
```typescript
|
|
849
|
+
interface AppContainerDefinition {
|
|
850
|
+
name: string;
|
|
851
|
+
description?: string;
|
|
852
|
+
props?: {
|
|
853
|
+
required?: string[];
|
|
854
|
+
optional?: string[];
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
```
|
|
858
|
+
|
|
823
859
|
**AppManifest** (interface)
|
|
824
860
|
```typescript
|
|
825
861
|
interface AppManifest {
|
|
@@ -831,15 +867,8 @@ interface AppManifest {
|
|
|
831
867
|
platformRevision?: string;
|
|
832
868
|
appId: string;
|
|
833
869
|
};
|
|
834
|
-
widgets?:
|
|
835
|
-
|
|
836
|
-
description?: string;
|
|
837
|
-
sizes?: string[];
|
|
838
|
-
props?: {
|
|
839
|
-
required?: string[];
|
|
840
|
-
optional?: string[];
|
|
841
|
-
};
|
|
842
|
-
}>;
|
|
870
|
+
widgets?: AppWidgetDefinition[];
|
|
871
|
+
containers?: AppContainerDefinition[];
|
|
843
872
|
setup?: {
|
|
844
873
|
description?: string;
|
|
845
874
|
questions?: Array<{
|
|
@@ -848,12 +877,14 @@ interface AppManifest {
|
|
|
848
877
|
type: string;
|
|
849
878
|
default?: any;
|
|
850
879
|
required?: boolean;
|
|
880
|
+
options?: Array<{ value: string; label: string }>;
|
|
851
881
|
}>;
|
|
852
882
|
configSchema?: Record<string, any>;
|
|
853
883
|
saveWith?: {
|
|
854
884
|
method: string;
|
|
855
|
-
scope: string;
|
|
885
|
+
scope: 'collection' | 'product' | string;
|
|
856
886
|
admin?: boolean;
|
|
887
|
+
note?: string;
|
|
857
888
|
};
|
|
858
889
|
contentHints?: Record<string, {
|
|
859
890
|
aiGenerate?: boolean;
|
|
@@ -884,44 +915,38 @@ interface AppManifest {
|
|
|
884
915
|
name: string;
|
|
885
916
|
description?: string;
|
|
886
917
|
type: string;
|
|
918
|
+
options?: string[];
|
|
887
919
|
}>;
|
|
888
920
|
};
|
|
889
921
|
metrics?: {
|
|
890
|
-
interactions?: Array<{
|
|
891
|
-
|
|
892
|
-
description?: string;
|
|
893
|
-
}>;
|
|
894
|
-
kpis?: Array<{
|
|
895
|
-
name: string;
|
|
896
|
-
compute?: string;
|
|
897
|
-
}>;
|
|
922
|
+
interactions?: Array<{ id: string; description?: string }>;
|
|
923
|
+
kpis?: Array<{ name: string; compute?: string }>;
|
|
898
924
|
};
|
|
899
|
-
[key: string]: any;
|
|
925
|
+
[key: string]: any;
|
|
900
926
|
}
|
|
901
927
|
```
|
|
902
928
|
|
|
903
|
-
**
|
|
929
|
+
**CollectionAppWidget** (interface)
|
|
904
930
|
```typescript
|
|
905
|
-
interface
|
|
931
|
+
interface CollectionAppWidget {
|
|
906
932
|
appId: string;
|
|
907
|
-
manifestUrl: string;
|
|
908
933
|
manifest: AppManifest;
|
|
909
|
-
|
|
910
|
-
|
|
934
|
+
widget: AppBundle;
|
|
935
|
+
container: AppBundle | null;
|
|
911
936
|
}
|
|
912
937
|
```
|
|
913
938
|
|
|
914
939
|
**CollectionWidgetsResponse** (interface)
|
|
915
940
|
```typescript
|
|
916
941
|
interface CollectionWidgetsResponse {
|
|
917
|
-
apps:
|
|
942
|
+
apps: CollectionAppWidget[];
|
|
918
943
|
}
|
|
919
944
|
```
|
|
920
945
|
|
|
921
946
|
**GetCollectionWidgetsOptions** (interface)
|
|
922
947
|
```typescript
|
|
923
948
|
interface GetCollectionWidgetsOptions {
|
|
924
|
-
force?: boolean;
|
|
949
|
+
force?: boolean;
|
|
925
950
|
}
|
|
926
951
|
```
|
|
927
952
|
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# AI Guide: Example App
|
|
2
|
+
|
|
3
|
+
<!-- CUSTOMIZE: Replace "Example App" and all content below with your app's specifics. -->
|
|
4
|
+
<!-- This file is consumed by AI orchestrators alongside public/app.manifest.json. -->
|
|
5
|
+
<!-- The manifest provides structured data; this file provides prose context and nuance. -->
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Purpose & Identity
|
|
10
|
+
|
|
11
|
+
<!-- CUSTOMIZE: Describe what your app does in 2-3 sentences. -->
|
|
12
|
+
|
|
13
|
+
The **Example App** is a template SmartLinks microapp that demonstrates all platform patterns including setup wizards, data imports, widget embedding, and analytics. It serves as a reference implementation for app authors building on the SmartLinks platform.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Setup Wizard Instructions
|
|
18
|
+
|
|
19
|
+
An AI orchestrator should follow these steps to configure the Example App for a collection. The structured questions and schema are in `app.manifest.json` under `setup`.
|
|
20
|
+
|
|
21
|
+
### Prerequisites
|
|
22
|
+
|
|
23
|
+
- The user must have **admin access** to the target collection.
|
|
24
|
+
- The `collectionId` and `appId` must be known (typically from URL context).
|
|
25
|
+
|
|
26
|
+
### Questions to Ask
|
|
27
|
+
|
|
28
|
+
Walk the user through each question defined in `setup.questions[]` of the manifest:
|
|
29
|
+
|
|
30
|
+
1. **App Title** (`appTitle`): Ask what the app should be called. Offer to auto-generate a suggestion using `SL.ai.chat.completions` if the user wants help (see `contentHints` in the manifest).
|
|
31
|
+
2. **Enable Notifications** (`enableNotifications`): Ask whether the app should send notifications to users.
|
|
32
|
+
|
|
33
|
+
<!-- CUSTOMIZE: Add app-specific guidance for each question. For example: -->
|
|
34
|
+
<!-- "If the user is setting up a competition, suggest a title like 'Win a [Product Name]!'" -->
|
|
35
|
+
<!-- "For plant passports, notifications are typically disabled." -->
|
|
36
|
+
|
|
37
|
+
### How to Save the Config
|
|
38
|
+
|
|
39
|
+
After collecting answers, validate against `setup.configSchema` and save:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
await SL.appConfiguration.setConfig({
|
|
43
|
+
collectionId,
|
|
44
|
+
appId,
|
|
45
|
+
config: {
|
|
46
|
+
appTitle: "User's chosen title",
|
|
47
|
+
enableNotifications: false
|
|
48
|
+
},
|
|
49
|
+
admin: true // REQUIRED for admin operations
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Post-Setup Verification
|
|
54
|
+
|
|
55
|
+
After saving, confirm by reading the config back:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
const saved = await SL.appConfiguration.getConfig({
|
|
59
|
+
collectionId,
|
|
60
|
+
appId,
|
|
61
|
+
admin: true
|
|
62
|
+
});
|
|
63
|
+
// Verify saved.appTitle and saved.enableNotifications match expectations
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Tell the user: "Your app is configured! You can adjust settings anytime by asking me to update the configuration."
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Import Instructions
|
|
71
|
+
|
|
72
|
+
The app supports bulk import of product-level configuration. The field definitions are in `app.manifest.json` under `import`.
|
|
73
|
+
|
|
74
|
+
### CSV Template
|
|
75
|
+
|
|
76
|
+
Generate or share this template with the user:
|
|
77
|
+
|
|
78
|
+
```csv
|
|
79
|
+
productId,appTitle,enableNotifications
|
|
80
|
+
prod_001,My First Product,true
|
|
81
|
+
prod_002,My Second Product,false
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
<!-- CUSTOMIZE: Add real-world examples relevant to your app. -->
|
|
85
|
+
|
|
86
|
+
### Field Validation Rules
|
|
87
|
+
|
|
88
|
+
| Field | Type | Required | Validation |
|
|
89
|
+
| --------------------- | ------- | -------- | ------------------------------------- |
|
|
90
|
+
| `productId` | string | ✅ | Must be a valid SmartLinks product ID |
|
|
91
|
+
| `appTitle` | string | ✅ | Non-empty string |
|
|
92
|
+
| `enableNotifications` | boolean | ❌ | Defaults to `false` |
|
|
93
|
+
|
|
94
|
+
<!-- CUSTOMIZE: Add app-specific validation rules. For example: -->
|
|
95
|
+
<!-- "For plant passports: botanicalName must be in Latin binomial format." -->
|
|
96
|
+
|
|
97
|
+
### API Call Sequence
|
|
98
|
+
|
|
99
|
+
For each row in the CSV:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
await SL.appConfiguration.setConfig({
|
|
103
|
+
collectionId,
|
|
104
|
+
productId: row.productId, // From CSV
|
|
105
|
+
appId,
|
|
106
|
+
config: {
|
|
107
|
+
appTitle: row.appTitle,
|
|
108
|
+
enableNotifications: row.enableNotifications ?? false
|
|
109
|
+
},
|
|
110
|
+
admin: true
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Error Handling
|
|
115
|
+
|
|
116
|
+
- If a `productId` is invalid, log the error and continue with the next row.
|
|
117
|
+
- After processing all rows, report a summary: `"Imported X of Y products successfully. Z failed."`.
|
|
118
|
+
- For failed rows, list the product ID and error message so the user can fix the data.
|
|
119
|
+
|
|
120
|
+
### Cross-App Import
|
|
121
|
+
|
|
122
|
+
When importing data for multiple apps simultaneously:
|
|
123
|
+
|
|
124
|
+
1. Fetch `app.manifest.json` from each app.
|
|
125
|
+
2. Merge `import.fields` arrays (prefix field names with app name if there are conflicts).
|
|
126
|
+
3. Generate a combined CSV template.
|
|
127
|
+
4. For each row, split into separate payloads per app and call each app's `saveWith.method`.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Widget Embedding Guide
|
|
132
|
+
|
|
133
|
+
### Available Widgets
|
|
134
|
+
|
|
135
|
+
| Widget | Description | Sizes |
|
|
136
|
+
| --------------- | ------------------------------------------ | ------------------------ |
|
|
137
|
+
| `ExampleWidget` | Demo widget showing SmartLinks integration | compact, standard, large |
|
|
138
|
+
|
|
139
|
+
<!-- CUSTOMIZE: List all widgets your app exports. -->
|
|
140
|
+
|
|
141
|
+
### Props Reference
|
|
142
|
+
|
|
143
|
+
All widgets receive `SmartLinksWidgetProps`:
|
|
144
|
+
|
|
145
|
+
| Prop | Type | Required | Description |
|
|
146
|
+
| ----------------- | -------------- | -------- | --------------------------------------- |
|
|
147
|
+
| `collectionId` | string | ✅ | Collection context |
|
|
148
|
+
| `appId` | string | ✅ | App identifier |
|
|
149
|
+
| `SL` | SmartLinks SDK | ✅ | Pre-initialized SDK instance |
|
|
150
|
+
| `productId` | string | ❌ | Product context |
|
|
151
|
+
| `proofId` | string | ❌ | Proof context |
|
|
152
|
+
| `user` | object | ❌ | Current user info |
|
|
153
|
+
| `onNavigate` | function | ❌ | Navigation callback |
|
|
154
|
+
| `publicPortalUrl` | string | ❌ | URL to full app for deep linking |
|
|
155
|
+
| `size` | string | ❌ | `"compact"`, `"standard"`, or `"large"` |
|
|
156
|
+
| `lang` | string | ❌ | Language code (e.g., `"en"`) |
|
|
157
|
+
| `translations` | object | ❌ | Translation overrides |
|
|
158
|
+
|
|
159
|
+
### Example Code
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
import { ExampleWidget } from '@my-app/widgets';
|
|
163
|
+
|
|
164
|
+
<ExampleWidget
|
|
165
|
+
collectionId="col_123"
|
|
166
|
+
appId="example-app"
|
|
167
|
+
SL={SL}
|
|
168
|
+
size="standard"
|
|
169
|
+
onNavigate={(path) => router.push(path)}
|
|
170
|
+
/>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
<!-- CUSTOMIZE: Show real widget usage with app-specific props. -->
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Tunable Settings
|
|
178
|
+
|
|
179
|
+
These settings can be adjusted after initial setup without reconfiguring everything. The AI can modify them in response to user requests like "turn off notifications" or optimization suggestions.
|
|
180
|
+
|
|
181
|
+
| Setting | Type | Description |
|
|
182
|
+
| --------------------- | ------- | ------------------------------ |
|
|
183
|
+
| `enableNotifications` | boolean | Toggle notifications on or off |
|
|
184
|
+
|
|
185
|
+
<!-- CUSTOMIZE: List all tunable fields with guidance on when to change them. -->
|
|
186
|
+
|
|
187
|
+
To update a tunable setting:
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// 1. Read current config
|
|
191
|
+
const current = await SL.appConfiguration.getConfig({ collectionId, appId, admin: true });
|
|
192
|
+
|
|
193
|
+
// 2. Merge the change
|
|
194
|
+
await SL.appConfiguration.setConfig({
|
|
195
|
+
collectionId,
|
|
196
|
+
appId,
|
|
197
|
+
config: { ...current, enableNotifications: true },
|
|
198
|
+
admin: true
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Metrics & Analytics
|
|
205
|
+
|
|
206
|
+
### Tracked Interactions
|
|
207
|
+
|
|
208
|
+
| Interaction ID | Description |
|
|
209
|
+
| -------------- | --------------------------------------------- |
|
|
210
|
+
| `page-view` | Tracks each time a user views the public page |
|
|
211
|
+
|
|
212
|
+
<!-- CUSTOMIZE: List all interaction IDs your app tracks. -->
|
|
213
|
+
|
|
214
|
+
### KPIs
|
|
215
|
+
|
|
216
|
+
| KPI | How to Compute |
|
|
217
|
+
| ----------- | -------------------------------------------------------------------------------------- |
|
|
218
|
+
| Total Views | `SL.interactions.countsByOutcome(collectionId, { appId, interactionId: 'page-view' })` |
|
|
219
|
+
|
|
220
|
+
<!-- CUSTOMIZE: Add app-specific KPIs and interpretation guidance. -->
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Troubleshooting
|
|
225
|
+
|
|
226
|
+
### Common Issues
|
|
227
|
+
|
|
228
|
+
| Issue | Cause | Fix |
|
|
229
|
+
| --------------------- | -------------------------- | ----------------------------------------------------- |
|
|
230
|
+
| Config save fails | Missing `admin: true` flag | Always include `admin: true` for admin operations |
|
|
231
|
+
| Widget doesn't render | Missing required props | Ensure `collectionId`, `appId`, and `SL` are provided |
|
|
232
|
+
| Import skips rows | Invalid `productId` | Verify product IDs exist in the collection |
|
|
233
|
+
| Theme not applied | Missing `?theme=` param | Check URL parameters or postMessage setup |
|
|
234
|
+
|
|
235
|
+
<!-- CUSTOMIZE: Add app-specific troubleshooting entries. -->
|
|
236
|
+
|
|
237
|
+
### Getting Help
|
|
238
|
+
|
|
239
|
+
- **SDK Docs**: `node_modules/@proveanything/smartlinks/docs/`
|
|
240
|
+
- **App Manifest**: `public/app.manifest.json`
|
|
241
|
+
- **Platform Guide**: `src/docs/smartlinks/about.md`
|