@proveanything/smartlinks 1.4.1 → 1.4.3
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/containers.md +198 -0
- package/dist/types/appManifest.d.ts +70 -19
- package/docs/API_SUMMARY.md +52 -27
- package/docs/containers.md +198 -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.3 | Generated: 2026-02-20T22:45:10.423Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -10,6 +10,7 @@ For detailed guides on specific features:
|
|
|
10
10
|
|
|
11
11
|
- **[AI & Chat Completions](ai.md)** - Chat completions, RAG (document-grounded Q&A), voice integration, streaming, tool calling, podcast generation
|
|
12
12
|
- **[Widgets](widgets.md)** - Embeddable React components for parent applications
|
|
13
|
+
- **[Containers](containers.md)** - Building full-app embeddable containers (lazy-loaded)
|
|
13
14
|
- **[Realtime](realtime.md)** - Real-time data updates and WebSocket connections
|
|
14
15
|
- **[iframe Responder](iframe-responder.md)** - iframe integration and cross-origin communication
|
|
15
16
|
- **[i18n](i18n.md)** - Internationalization and localization
|
|
@@ -821,6 +822,41 @@ interface AppConfigurationResponse {
|
|
|
821
822
|
|
|
822
823
|
### appManifest
|
|
823
824
|
|
|
825
|
+
**AppBundle** (interface)
|
|
826
|
+
```typescript
|
|
827
|
+
interface AppBundle {
|
|
828
|
+
js: string | null;
|
|
829
|
+
css: string | null;
|
|
830
|
+
source?: string;
|
|
831
|
+
styles?: string;
|
|
832
|
+
}
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
**AppWidgetDefinition** (interface)
|
|
836
|
+
```typescript
|
|
837
|
+
interface AppWidgetDefinition {
|
|
838
|
+
name: string;
|
|
839
|
+
description?: string;
|
|
840
|
+
sizes?: Array<'compact' | 'standard' | 'large' | string>;
|
|
841
|
+
props?: {
|
|
842
|
+
required?: string[];
|
|
843
|
+
optional?: string[];
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
**AppContainerDefinition** (interface)
|
|
849
|
+
```typescript
|
|
850
|
+
interface AppContainerDefinition {
|
|
851
|
+
name: string;
|
|
852
|
+
description?: string;
|
|
853
|
+
props?: {
|
|
854
|
+
required?: string[];
|
|
855
|
+
optional?: string[];
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
```
|
|
859
|
+
|
|
824
860
|
**AppManifest** (interface)
|
|
825
861
|
```typescript
|
|
826
862
|
interface AppManifest {
|
|
@@ -832,15 +868,8 @@ interface AppManifest {
|
|
|
832
868
|
platformRevision?: string;
|
|
833
869
|
appId: string;
|
|
834
870
|
};
|
|
835
|
-
widgets?:
|
|
836
|
-
|
|
837
|
-
description?: string;
|
|
838
|
-
sizes?: string[];
|
|
839
|
-
props?: {
|
|
840
|
-
required?: string[];
|
|
841
|
-
optional?: string[];
|
|
842
|
-
};
|
|
843
|
-
}>;
|
|
871
|
+
widgets?: AppWidgetDefinition[];
|
|
872
|
+
containers?: AppContainerDefinition[];
|
|
844
873
|
setup?: {
|
|
845
874
|
description?: string;
|
|
846
875
|
questions?: Array<{
|
|
@@ -849,12 +878,14 @@ interface AppManifest {
|
|
|
849
878
|
type: string;
|
|
850
879
|
default?: any;
|
|
851
880
|
required?: boolean;
|
|
881
|
+
options?: Array<{ value: string; label: string }>;
|
|
852
882
|
}>;
|
|
853
883
|
configSchema?: Record<string, any>;
|
|
854
884
|
saveWith?: {
|
|
855
885
|
method: string;
|
|
856
|
-
scope: string;
|
|
886
|
+
scope: 'collection' | 'product' | string;
|
|
857
887
|
admin?: boolean;
|
|
888
|
+
note?: string;
|
|
858
889
|
};
|
|
859
890
|
contentHints?: Record<string, {
|
|
860
891
|
aiGenerate?: boolean;
|
|
@@ -885,44 +916,38 @@ interface AppManifest {
|
|
|
885
916
|
name: string;
|
|
886
917
|
description?: string;
|
|
887
918
|
type: string;
|
|
919
|
+
options?: string[];
|
|
888
920
|
}>;
|
|
889
921
|
};
|
|
890
922
|
metrics?: {
|
|
891
|
-
interactions?: Array<{
|
|
892
|
-
|
|
893
|
-
description?: string;
|
|
894
|
-
}>;
|
|
895
|
-
kpis?: Array<{
|
|
896
|
-
name: string;
|
|
897
|
-
compute?: string;
|
|
898
|
-
}>;
|
|
923
|
+
interactions?: Array<{ id: string; description?: string }>;
|
|
924
|
+
kpis?: Array<{ name: string; compute?: string }>;
|
|
899
925
|
};
|
|
900
|
-
[key: string]: any;
|
|
926
|
+
[key: string]: any;
|
|
901
927
|
}
|
|
902
928
|
```
|
|
903
929
|
|
|
904
|
-
**
|
|
930
|
+
**CollectionAppWidget** (interface)
|
|
905
931
|
```typescript
|
|
906
|
-
interface
|
|
932
|
+
interface CollectionAppWidget {
|
|
907
933
|
appId: string;
|
|
908
|
-
manifestUrl: string;
|
|
909
934
|
manifest: AppManifest;
|
|
910
|
-
|
|
911
|
-
|
|
935
|
+
widget: AppBundle;
|
|
936
|
+
container: AppBundle | null;
|
|
912
937
|
}
|
|
913
938
|
```
|
|
914
939
|
|
|
915
940
|
**CollectionWidgetsResponse** (interface)
|
|
916
941
|
```typescript
|
|
917
942
|
interface CollectionWidgetsResponse {
|
|
918
|
-
apps:
|
|
943
|
+
apps: CollectionAppWidget[];
|
|
919
944
|
}
|
|
920
945
|
```
|
|
921
946
|
|
|
922
947
|
**GetCollectionWidgetsOptions** (interface)
|
|
923
948
|
```typescript
|
|
924
949
|
interface GetCollectionWidgetsOptions {
|
|
925
|
-
force?: boolean;
|
|
950
|
+
force?: boolean;
|
|
926
951
|
}
|
|
927
952
|
```
|
|
928
953
|
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# SmartLinks Containers
|
|
2
|
+
|
|
3
|
+
> **Copy this file into `node_modules/@proveanything/smartlinks/docs/containers.md`** in the published SDK package.
|
|
4
|
+
|
|
5
|
+
Containers are the **full public app experience** packaged as an embeddable React component. Unlike widgets (lightweight previews/cards), containers render the complete public interface — all pages, routing, and features — inside a parent React application.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Widgets vs Containers
|
|
10
|
+
|
|
11
|
+
| Aspect | Widget | Container |
|
|
12
|
+
| --------------- | ---------------------------------- | -------------------------------------------- |
|
|
13
|
+
| **Purpose** | Lightweight preview / summary | Full app experience |
|
|
14
|
+
| **Bundle size** | ~10KB (app-specific code only) | ~150KB+ (full public app) |
|
|
15
|
+
| **Loading** | Loaded immediately with page | Lazy-loaded on demand |
|
|
16
|
+
| **Routing** | None (single component) | MemoryRouter (parent owns URL bar) |
|
|
17
|
+
| **Use case** | Cards, thumbnails, quick glance | "Open full view", embedded experiences |
|
|
18
|
+
| **Build output**| `widgets.umd.js` / `widgets.es.js` | `containers.umd.js` / `containers.es.js` |
|
|
19
|
+
|
|
20
|
+
### Why Separate Bundles?
|
|
21
|
+
|
|
22
|
+
Imagine a homepage displaying 10 app widgets. If containers were bundled with widgets, loading 10 small widget cards would also pull in 10 full app bundles — potentially megabytes of unused code. By splitting them:
|
|
23
|
+
|
|
24
|
+
1. **Widgets load fast** — parent loads `widgets.*.js` for all apps on the page (~10KB each)
|
|
25
|
+
2. **Containers load on demand** — only when user clicks "Open full view" does `containers.*.js` get fetched
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Container Props
|
|
30
|
+
|
|
31
|
+
Container props extend the standard `SmartLinksWidgetProps` with an additional `className` prop:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
interface SmartLinksContainerProps extends SmartLinksWidgetProps {
|
|
35
|
+
/** Optional className for the container wrapper element */
|
|
36
|
+
className?: string;
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
All standard widget props apply:
|
|
41
|
+
|
|
42
|
+
| Prop | Type | Required | Description |
|
|
43
|
+
| ----------------- | -------------- | -------- | --------------------------------------- |
|
|
44
|
+
| `collectionId` | string | ✅ | Collection context |
|
|
45
|
+
| `appId` | string | ✅ | App identifier |
|
|
46
|
+
| `SL` | SmartLinks SDK | ✅ | Pre-initialized SDK instance |
|
|
47
|
+
| `productId` | string | ❌ | Product context |
|
|
48
|
+
| `proofId` | string | ❌ | Proof context |
|
|
49
|
+
| `user` | object | ❌ | Current user info |
|
|
50
|
+
| `onNavigate` | function | ❌ | Navigation callback |
|
|
51
|
+
| `size` | string | ❌ | `"compact"`, `"standard"`, or `"large"` |
|
|
52
|
+
| `lang` | string | ❌ | Language code (e.g., `"en"`) |
|
|
53
|
+
| `translations` | object | ❌ | Translation overrides |
|
|
54
|
+
| `className` | string | ❌ | CSS class for the wrapper element |
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Architecture
|
|
59
|
+
|
|
60
|
+
Containers use **MemoryRouter** (not HashRouter) because the parent app owns the browser's URL bar. Context is passed via props rather than URL parameters. Each container gets its own `QueryClient` to avoid cache collisions with the parent app.
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Parent App (owns URL bar, provides globals)
|
|
64
|
+
└── <PublicContainer> ← Container component
|
|
65
|
+
├── QueryClientProvider (isolated)
|
|
66
|
+
├── MemoryRouter (internal routing)
|
|
67
|
+
├── LanguageProvider
|
|
68
|
+
└── PublicPage (+ all sub-routes)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Usage in Parent Apps
|
|
74
|
+
|
|
75
|
+
### ESM (Modern Bundlers)
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// Lazy-load the container only when needed
|
|
79
|
+
const { PublicContainer } = await import('https://my-app.com/containers.es.js');
|
|
80
|
+
|
|
81
|
+
<PublicContainer
|
|
82
|
+
collectionId="abc"
|
|
83
|
+
appId="my-app"
|
|
84
|
+
productId="prod-123"
|
|
85
|
+
SL={SL}
|
|
86
|
+
onNavigate={handleNavigate}
|
|
87
|
+
lang="en"
|
|
88
|
+
className="max-w-4xl mx-auto"
|
|
89
|
+
/>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### UMD (Script Tag)
|
|
93
|
+
|
|
94
|
+
```html
|
|
95
|
+
<!-- Ensure shared globals are set up first (see Shared Dependencies Contract) -->
|
|
96
|
+
<script src="https://my-app.com/containers.umd.js"></script>
|
|
97
|
+
<script>
|
|
98
|
+
const { PublicContainer } = window.SmartLinksContainers;
|
|
99
|
+
// Render with React
|
|
100
|
+
</script>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Shared Dependencies Contract
|
|
106
|
+
|
|
107
|
+
Containers use the **exact same Shared Dependencies Contract** as widgets. No additional globals are needed. The parent app must expose these globals before loading container bundles:
|
|
108
|
+
|
|
109
|
+
- React, ReactDOM, jsxRuntime
|
|
110
|
+
- SL (SmartLinks SDK)
|
|
111
|
+
- CVA (class-variance-authority) — **uppercase to avoid `cva.cva` collision**
|
|
112
|
+
- ReactRouterDOM, ReactQuery
|
|
113
|
+
- LucideReact, dateFns, LiquidJS
|
|
114
|
+
- 12 Radix UI primitives (Slot, Dialog, Popover, Tooltip, Tabs, Accordion, Select, ScrollArea, Label, Toast, Progress, Avatar)
|
|
115
|
+
|
|
116
|
+
See `widgets.md` for the complete table with globals and version expectations.
|
|
117
|
+
|
|
118
|
+
> **Why `CVA` not `cva`?** The `class-variance-authority` package exports a named function called `cva`. If the UMD global is also `cva`, the wrapper resolves it as `window.cva.cva` — a double-nesting bug. Using uppercase `CVA` avoids this collision.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Build Configuration
|
|
123
|
+
|
|
124
|
+
Containers are built via a dedicated Vite config: `vite.config.container.ts`.
|
|
125
|
+
|
|
126
|
+
### Enable Container Builds
|
|
127
|
+
|
|
128
|
+
Add to your `.env` file:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
VITE_ENABLE_CONTAINERS=true
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Build Command
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Full pipeline (main + widgets + containers)
|
|
138
|
+
vite build && vite build --config vite.config.widget.ts && vite build --config vite.config.container.ts
|
|
139
|
+
|
|
140
|
+
# Containers only
|
|
141
|
+
vite build --config vite.config.container.ts
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Build Output
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
dist/
|
|
148
|
+
├── containers.umd.js # Full app container (UMD)
|
|
149
|
+
├── containers.es.js # Full app container (ESM)
|
|
150
|
+
└── containers.css # Container styles
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
When `VITE_ENABLE_CONTAINERS` is not set, the build produces a harmless `containers.stub.js` and skips quickly.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## File Structure
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
src/containers/
|
|
161
|
+
├── index.ts # Main exports barrel + ContainerManifest
|
|
162
|
+
├── types.ts # SmartLinksContainerProps interface
|
|
163
|
+
├── stub.ts # Minimal stub for skipped builds
|
|
164
|
+
└── PublicContainer.tsx # Full public app wrapper
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Creating a New Container
|
|
168
|
+
|
|
169
|
+
1. Create your container component in `src/containers/MyContainer.tsx`
|
|
170
|
+
2. Export it from `src/containers/index.ts`
|
|
171
|
+
3. Add it to the `CONTAINER_MANIFEST` in `src/containers/index.ts`
|
|
172
|
+
4. Ensure it uses `MemoryRouter` (not HashRouter)
|
|
173
|
+
5. Give it its own `QueryClient` to avoid cache collisions
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Key Differences from Iframe Apps
|
|
178
|
+
|
|
179
|
+
| Concern | Iframe App | Container |
|
|
180
|
+
| ----------------- | --------------------------------- | ---------------------------------- |
|
|
181
|
+
| **Isolation** | Full browser isolation | Shares parent's React tree |
|
|
182
|
+
| **URL control** | Owns its own URL (HashRouter) | Parent owns URL (MemoryRouter) |
|
|
183
|
+
| **Context source**| URL parameters | React props |
|
|
184
|
+
| **Styling** | Fully isolated CSS | Inherits parent CSS variables |
|
|
185
|
+
| **Communication** | postMessage | Direct props / callbacks |
|
|
186
|
+
| **Auth** | Via `SL.auth.getAccount()` | Via `user` prop from parent |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Troubleshooting
|
|
191
|
+
|
|
192
|
+
| Issue | Cause | Fix |
|
|
193
|
+
| -------------------------- | ---------------------------------------- | ---------------------------------------------------- |
|
|
194
|
+
| Container doesn't render | Missing shared globals | Ensure all Shared Dependencies are on `window` |
|
|
195
|
+
| Styles don't apply | Missing `containers.css` | Load the CSS file alongside the JS bundle |
|
|
196
|
+
| Routing doesn't work | Using HashRouter instead of MemoryRouter | Containers must use MemoryRouter |
|
|
197
|
+
| Query cache conflicts | Sharing parent's QueryClient | Each container needs its own `QueryClient` instance |
|
|
198
|
+
| `cva.cva` runtime error | Global set to lowercase `cva` | Use uppercase `CVA` for the global name |
|
|
@@ -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.3 | Generated: 2026-02-20T22:45:10.423Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -10,6 +10,7 @@ For detailed guides on specific features:
|
|
|
10
10
|
|
|
11
11
|
- **[AI & Chat Completions](ai.md)** - Chat completions, RAG (document-grounded Q&A), voice integration, streaming, tool calling, podcast generation
|
|
12
12
|
- **[Widgets](widgets.md)** - Embeddable React components for parent applications
|
|
13
|
+
- **[Containers](containers.md)** - Building full-app embeddable containers (lazy-loaded)
|
|
13
14
|
- **[Realtime](realtime.md)** - Real-time data updates and WebSocket connections
|
|
14
15
|
- **[iframe Responder](iframe-responder.md)** - iframe integration and cross-origin communication
|
|
15
16
|
- **[i18n](i18n.md)** - Internationalization and localization
|
|
@@ -821,6 +822,41 @@ interface AppConfigurationResponse {
|
|
|
821
822
|
|
|
822
823
|
### appManifest
|
|
823
824
|
|
|
825
|
+
**AppBundle** (interface)
|
|
826
|
+
```typescript
|
|
827
|
+
interface AppBundle {
|
|
828
|
+
js: string | null;
|
|
829
|
+
css: string | null;
|
|
830
|
+
source?: string;
|
|
831
|
+
styles?: string;
|
|
832
|
+
}
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
**AppWidgetDefinition** (interface)
|
|
836
|
+
```typescript
|
|
837
|
+
interface AppWidgetDefinition {
|
|
838
|
+
name: string;
|
|
839
|
+
description?: string;
|
|
840
|
+
sizes?: Array<'compact' | 'standard' | 'large' | string>;
|
|
841
|
+
props?: {
|
|
842
|
+
required?: string[];
|
|
843
|
+
optional?: string[];
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
**AppContainerDefinition** (interface)
|
|
849
|
+
```typescript
|
|
850
|
+
interface AppContainerDefinition {
|
|
851
|
+
name: string;
|
|
852
|
+
description?: string;
|
|
853
|
+
props?: {
|
|
854
|
+
required?: string[];
|
|
855
|
+
optional?: string[];
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
```
|
|
859
|
+
|
|
824
860
|
**AppManifest** (interface)
|
|
825
861
|
```typescript
|
|
826
862
|
interface AppManifest {
|
|
@@ -832,15 +868,8 @@ interface AppManifest {
|
|
|
832
868
|
platformRevision?: string;
|
|
833
869
|
appId: string;
|
|
834
870
|
};
|
|
835
|
-
widgets?:
|
|
836
|
-
|
|
837
|
-
description?: string;
|
|
838
|
-
sizes?: string[];
|
|
839
|
-
props?: {
|
|
840
|
-
required?: string[];
|
|
841
|
-
optional?: string[];
|
|
842
|
-
};
|
|
843
|
-
}>;
|
|
871
|
+
widgets?: AppWidgetDefinition[];
|
|
872
|
+
containers?: AppContainerDefinition[];
|
|
844
873
|
setup?: {
|
|
845
874
|
description?: string;
|
|
846
875
|
questions?: Array<{
|
|
@@ -849,12 +878,14 @@ interface AppManifest {
|
|
|
849
878
|
type: string;
|
|
850
879
|
default?: any;
|
|
851
880
|
required?: boolean;
|
|
881
|
+
options?: Array<{ value: string; label: string }>;
|
|
852
882
|
}>;
|
|
853
883
|
configSchema?: Record<string, any>;
|
|
854
884
|
saveWith?: {
|
|
855
885
|
method: string;
|
|
856
|
-
scope: string;
|
|
886
|
+
scope: 'collection' | 'product' | string;
|
|
857
887
|
admin?: boolean;
|
|
888
|
+
note?: string;
|
|
858
889
|
};
|
|
859
890
|
contentHints?: Record<string, {
|
|
860
891
|
aiGenerate?: boolean;
|
|
@@ -885,44 +916,38 @@ interface AppManifest {
|
|
|
885
916
|
name: string;
|
|
886
917
|
description?: string;
|
|
887
918
|
type: string;
|
|
919
|
+
options?: string[];
|
|
888
920
|
}>;
|
|
889
921
|
};
|
|
890
922
|
metrics?: {
|
|
891
|
-
interactions?: Array<{
|
|
892
|
-
|
|
893
|
-
description?: string;
|
|
894
|
-
}>;
|
|
895
|
-
kpis?: Array<{
|
|
896
|
-
name: string;
|
|
897
|
-
compute?: string;
|
|
898
|
-
}>;
|
|
923
|
+
interactions?: Array<{ id: string; description?: string }>;
|
|
924
|
+
kpis?: Array<{ name: string; compute?: string }>;
|
|
899
925
|
};
|
|
900
|
-
[key: string]: any;
|
|
926
|
+
[key: string]: any;
|
|
901
927
|
}
|
|
902
928
|
```
|
|
903
929
|
|
|
904
|
-
**
|
|
930
|
+
**CollectionAppWidget** (interface)
|
|
905
931
|
```typescript
|
|
906
|
-
interface
|
|
932
|
+
interface CollectionAppWidget {
|
|
907
933
|
appId: string;
|
|
908
|
-
manifestUrl: string;
|
|
909
934
|
manifest: AppManifest;
|
|
910
|
-
|
|
911
|
-
|
|
935
|
+
widget: AppBundle;
|
|
936
|
+
container: AppBundle | null;
|
|
912
937
|
}
|
|
913
938
|
```
|
|
914
939
|
|
|
915
940
|
**CollectionWidgetsResponse** (interface)
|
|
916
941
|
```typescript
|
|
917
942
|
interface CollectionWidgetsResponse {
|
|
918
|
-
apps:
|
|
943
|
+
apps: CollectionAppWidget[];
|
|
919
944
|
}
|
|
920
945
|
```
|
|
921
946
|
|
|
922
947
|
**GetCollectionWidgetsOptions** (interface)
|
|
923
948
|
```typescript
|
|
924
949
|
interface GetCollectionWidgetsOptions {
|
|
925
|
-
force?: boolean;
|
|
950
|
+
force?: boolean;
|
|
926
951
|
}
|
|
927
952
|
```
|
|
928
953
|
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# SmartLinks Containers
|
|
2
|
+
|
|
3
|
+
> **Copy this file into `node_modules/@proveanything/smartlinks/docs/containers.md`** in the published SDK package.
|
|
4
|
+
|
|
5
|
+
Containers are the **full public app experience** packaged as an embeddable React component. Unlike widgets (lightweight previews/cards), containers render the complete public interface — all pages, routing, and features — inside a parent React application.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Widgets vs Containers
|
|
10
|
+
|
|
11
|
+
| Aspect | Widget | Container |
|
|
12
|
+
| --------------- | ---------------------------------- | -------------------------------------------- |
|
|
13
|
+
| **Purpose** | Lightweight preview / summary | Full app experience |
|
|
14
|
+
| **Bundle size** | ~10KB (app-specific code only) | ~150KB+ (full public app) |
|
|
15
|
+
| **Loading** | Loaded immediately with page | Lazy-loaded on demand |
|
|
16
|
+
| **Routing** | None (single component) | MemoryRouter (parent owns URL bar) |
|
|
17
|
+
| **Use case** | Cards, thumbnails, quick glance | "Open full view", embedded experiences |
|
|
18
|
+
| **Build output**| `widgets.umd.js` / `widgets.es.js` | `containers.umd.js` / `containers.es.js` |
|
|
19
|
+
|
|
20
|
+
### Why Separate Bundles?
|
|
21
|
+
|
|
22
|
+
Imagine a homepage displaying 10 app widgets. If containers were bundled with widgets, loading 10 small widget cards would also pull in 10 full app bundles — potentially megabytes of unused code. By splitting them:
|
|
23
|
+
|
|
24
|
+
1. **Widgets load fast** — parent loads `widgets.*.js` for all apps on the page (~10KB each)
|
|
25
|
+
2. **Containers load on demand** — only when user clicks "Open full view" does `containers.*.js` get fetched
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Container Props
|
|
30
|
+
|
|
31
|
+
Container props extend the standard `SmartLinksWidgetProps` with an additional `className` prop:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
interface SmartLinksContainerProps extends SmartLinksWidgetProps {
|
|
35
|
+
/** Optional className for the container wrapper element */
|
|
36
|
+
className?: string;
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
All standard widget props apply:
|
|
41
|
+
|
|
42
|
+
| Prop | Type | Required | Description |
|
|
43
|
+
| ----------------- | -------------- | -------- | --------------------------------------- |
|
|
44
|
+
| `collectionId` | string | ✅ | Collection context |
|
|
45
|
+
| `appId` | string | ✅ | App identifier |
|
|
46
|
+
| `SL` | SmartLinks SDK | ✅ | Pre-initialized SDK instance |
|
|
47
|
+
| `productId` | string | ❌ | Product context |
|
|
48
|
+
| `proofId` | string | ❌ | Proof context |
|
|
49
|
+
| `user` | object | ❌ | Current user info |
|
|
50
|
+
| `onNavigate` | function | ❌ | Navigation callback |
|
|
51
|
+
| `size` | string | ❌ | `"compact"`, `"standard"`, or `"large"` |
|
|
52
|
+
| `lang` | string | ❌ | Language code (e.g., `"en"`) |
|
|
53
|
+
| `translations` | object | ❌ | Translation overrides |
|
|
54
|
+
| `className` | string | ❌ | CSS class for the wrapper element |
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Architecture
|
|
59
|
+
|
|
60
|
+
Containers use **MemoryRouter** (not HashRouter) because the parent app owns the browser's URL bar. Context is passed via props rather than URL parameters. Each container gets its own `QueryClient` to avoid cache collisions with the parent app.
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Parent App (owns URL bar, provides globals)
|
|
64
|
+
└── <PublicContainer> ← Container component
|
|
65
|
+
├── QueryClientProvider (isolated)
|
|
66
|
+
├── MemoryRouter (internal routing)
|
|
67
|
+
├── LanguageProvider
|
|
68
|
+
└── PublicPage (+ all sub-routes)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Usage in Parent Apps
|
|
74
|
+
|
|
75
|
+
### ESM (Modern Bundlers)
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// Lazy-load the container only when needed
|
|
79
|
+
const { PublicContainer } = await import('https://my-app.com/containers.es.js');
|
|
80
|
+
|
|
81
|
+
<PublicContainer
|
|
82
|
+
collectionId="abc"
|
|
83
|
+
appId="my-app"
|
|
84
|
+
productId="prod-123"
|
|
85
|
+
SL={SL}
|
|
86
|
+
onNavigate={handleNavigate}
|
|
87
|
+
lang="en"
|
|
88
|
+
className="max-w-4xl mx-auto"
|
|
89
|
+
/>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### UMD (Script Tag)
|
|
93
|
+
|
|
94
|
+
```html
|
|
95
|
+
<!-- Ensure shared globals are set up first (see Shared Dependencies Contract) -->
|
|
96
|
+
<script src="https://my-app.com/containers.umd.js"></script>
|
|
97
|
+
<script>
|
|
98
|
+
const { PublicContainer } = window.SmartLinksContainers;
|
|
99
|
+
// Render with React
|
|
100
|
+
</script>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Shared Dependencies Contract
|
|
106
|
+
|
|
107
|
+
Containers use the **exact same Shared Dependencies Contract** as widgets. No additional globals are needed. The parent app must expose these globals before loading container bundles:
|
|
108
|
+
|
|
109
|
+
- React, ReactDOM, jsxRuntime
|
|
110
|
+
- SL (SmartLinks SDK)
|
|
111
|
+
- CVA (class-variance-authority) — **uppercase to avoid `cva.cva` collision**
|
|
112
|
+
- ReactRouterDOM, ReactQuery
|
|
113
|
+
- LucideReact, dateFns, LiquidJS
|
|
114
|
+
- 12 Radix UI primitives (Slot, Dialog, Popover, Tooltip, Tabs, Accordion, Select, ScrollArea, Label, Toast, Progress, Avatar)
|
|
115
|
+
|
|
116
|
+
See `widgets.md` for the complete table with globals and version expectations.
|
|
117
|
+
|
|
118
|
+
> **Why `CVA` not `cva`?** The `class-variance-authority` package exports a named function called `cva`. If the UMD global is also `cva`, the wrapper resolves it as `window.cva.cva` — a double-nesting bug. Using uppercase `CVA` avoids this collision.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Build Configuration
|
|
123
|
+
|
|
124
|
+
Containers are built via a dedicated Vite config: `vite.config.container.ts`.
|
|
125
|
+
|
|
126
|
+
### Enable Container Builds
|
|
127
|
+
|
|
128
|
+
Add to your `.env` file:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
VITE_ENABLE_CONTAINERS=true
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Build Command
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Full pipeline (main + widgets + containers)
|
|
138
|
+
vite build && vite build --config vite.config.widget.ts && vite build --config vite.config.container.ts
|
|
139
|
+
|
|
140
|
+
# Containers only
|
|
141
|
+
vite build --config vite.config.container.ts
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Build Output
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
dist/
|
|
148
|
+
├── containers.umd.js # Full app container (UMD)
|
|
149
|
+
├── containers.es.js # Full app container (ESM)
|
|
150
|
+
└── containers.css # Container styles
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
When `VITE_ENABLE_CONTAINERS` is not set, the build produces a harmless `containers.stub.js` and skips quickly.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## File Structure
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
src/containers/
|
|
161
|
+
├── index.ts # Main exports barrel + ContainerManifest
|
|
162
|
+
├── types.ts # SmartLinksContainerProps interface
|
|
163
|
+
├── stub.ts # Minimal stub for skipped builds
|
|
164
|
+
└── PublicContainer.tsx # Full public app wrapper
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Creating a New Container
|
|
168
|
+
|
|
169
|
+
1. Create your container component in `src/containers/MyContainer.tsx`
|
|
170
|
+
2. Export it from `src/containers/index.ts`
|
|
171
|
+
3. Add it to the `CONTAINER_MANIFEST` in `src/containers/index.ts`
|
|
172
|
+
4. Ensure it uses `MemoryRouter` (not HashRouter)
|
|
173
|
+
5. Give it its own `QueryClient` to avoid cache collisions
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Key Differences from Iframe Apps
|
|
178
|
+
|
|
179
|
+
| Concern | Iframe App | Container |
|
|
180
|
+
| ----------------- | --------------------------------- | ---------------------------------- |
|
|
181
|
+
| **Isolation** | Full browser isolation | Shares parent's React tree |
|
|
182
|
+
| **URL control** | Owns its own URL (HashRouter) | Parent owns URL (MemoryRouter) |
|
|
183
|
+
| **Context source**| URL parameters | React props |
|
|
184
|
+
| **Styling** | Fully isolated CSS | Inherits parent CSS variables |
|
|
185
|
+
| **Communication** | postMessage | Direct props / callbacks |
|
|
186
|
+
| **Auth** | Via `SL.auth.getAccount()` | Via `user` prop from parent |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Troubleshooting
|
|
191
|
+
|
|
192
|
+
| Issue | Cause | Fix |
|
|
193
|
+
| -------------------------- | ---------------------------------------- | ---------------------------------------------------- |
|
|
194
|
+
| Container doesn't render | Missing shared globals | Ensure all Shared Dependencies are on `window` |
|
|
195
|
+
| Styles don't apply | Missing `containers.css` | Load the CSS file alongside the JS bundle |
|
|
196
|
+
| Routing doesn't work | Using HashRouter instead of MemoryRouter | Containers must use MemoryRouter |
|
|
197
|
+
| Query cache conflicts | Sharing parent's QueryClient | Each container needs its own `QueryClient` instance |
|
|
198
|
+
| `cva.cva` runtime error | Global set to lowercase `cva` | Use uppercase `CVA` for the global name |
|