@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.
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.4.0 | Generated: 2026-02-20T14:52:16.722Z
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?: Array<{
835
- name: string;
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
- id: string;
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; // Allow additional custom fields
925
+ [key: string]: any;
900
926
  }
901
927
  ```
902
928
 
903
- **CollectionWidget** (interface)
929
+ **CollectionAppWidget** (interface)
904
930
  ```typescript
905
- interface CollectionWidget {
931
+ interface CollectionAppWidget {
906
932
  appId: string;
907
- manifestUrl: string;
908
933
  manifest: AppManifest;
909
- bundleSource: string;
910
- bundleCss?: string; // Optional CSS file
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: CollectionWidget[];
942
+ apps: CollectionAppWidget[];
918
943
  }
919
944
  ```
920
945
 
921
946
  **GetCollectionWidgetsOptions** (interface)
922
947
  ```typescript
923
948
  interface GetCollectionWidgetsOptions {
924
- force?: boolean; // Bypass cache and fetch fresh data
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
- * SmartLinks App Manifest structure
3
- * Defines the configuration, widgets, setup, import, and metrics for a microapp
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?: Array<{
15
- name: string;
16
- description?: string;
17
- sizes?: string[];
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
- * Single app widget data with manifest and bundle files
131
+ * One app entry in the collection widgets response.
83
132
  */
84
- export interface CollectionWidget {
133
+ export interface CollectionAppWidget {
85
134
  appId: string;
86
- manifestUrl: string;
87
135
  manifest: AppManifest;
88
- bundleSource: string;
89
- bundleCss?: string;
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 widgets endpoint
142
+ * Response from GET /api/v1/public/collection/:collectionId/widgets
93
143
  */
94
144
  export interface CollectionWidgetsResponse {
95
- apps: CollectionWidget[];
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
  }
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.4.0 | Generated: 2026-02-20T14:52:16.722Z
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?: Array<{
835
- name: string;
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
- id: string;
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; // Allow additional custom fields
925
+ [key: string]: any;
900
926
  }
901
927
  ```
902
928
 
903
- **CollectionWidget** (interface)
929
+ **CollectionAppWidget** (interface)
904
930
  ```typescript
905
- interface CollectionWidget {
931
+ interface CollectionAppWidget {
906
932
  appId: string;
907
- manifestUrl: string;
908
933
  manifest: AppManifest;
909
- bundleSource: string;
910
- bundleCss?: string; // Optional CSS file
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: CollectionWidget[];
942
+ apps: CollectionAppWidget[];
918
943
  }
919
944
  ```
920
945
 
921
946
  **GetCollectionWidgetsOptions** (interface)
922
947
  ```typescript
923
948
  interface GetCollectionWidgetsOptions {
924
- force?: boolean; // Bypass cache and fetch fresh data
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`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",