@proveanything/smartlinks 2.0.5 → 2.0.9
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/api/ai.d.ts +1 -1
- package/dist/api/ai.js +1 -1
- package/dist/api/analytics.d.ts +1 -1
- package/dist/api/analytics.js +1 -1
- package/dist/api/appConfiguration.d.ts +3 -3
- package/dist/api/appConfiguration.js +3 -3
- package/dist/api/appObjects.d.ts +1 -1
- package/dist/api/appObjects.js +1 -1
- package/dist/api/asset.d.ts +1 -1
- package/dist/api/asset.js +2 -2
- package/dist/api/async.d.ts +1 -1
- package/dist/api/async.js +1 -1
- package/dist/api/attestation.d.ts +1 -1
- package/dist/api/attestation.js +1 -1
- package/dist/api/attestations.d.ts +1 -1
- package/dist/api/attestations.js +1 -1
- package/dist/api/auth.d.ts +2 -2
- package/dist/api/auth.js +2 -2
- package/dist/api/authKit.d.ts +1 -1
- package/dist/api/authKit.js +1 -1
- package/dist/api/batch.d.ts +1 -1
- package/dist/api/batch.js +1 -1
- package/dist/api/broadcasts.d.ts +2 -2
- package/dist/api/broadcasts.js +1 -1
- package/dist/api/claimSet.d.ts +1 -1
- package/dist/api/claimSet.js +1 -1
- package/dist/api/collection.d.ts +1 -1
- package/dist/api/collection.js +1 -1
- package/dist/api/comms.d.ts +15 -15
- package/dist/api/comms.js +1 -1
- package/dist/api/config.d.ts +1 -1
- package/dist/api/config.js +1 -1
- package/dist/api/contact.d.ts +1 -1
- package/dist/api/contact.js +1 -1
- package/dist/api/containers.d.ts +1 -1
- package/dist/api/containers.js +1 -1
- package/dist/api/crate.d.ts +1 -1
- package/dist/api/crate.js +1 -1
- package/dist/api/facets.d.ts +1 -1
- package/dist/api/facets.js +1 -1
- package/dist/api/form.js +1 -1
- package/dist/api/http.js +1 -1
- package/dist/api/index.d.ts +46 -46
- package/dist/api/index.js +46 -46
- package/dist/api/integrations.d.ts +1 -1
- package/dist/api/integrations.js +1 -1
- package/dist/api/interactions.d.ts +1 -1
- package/dist/api/interactions.js +1 -1
- package/dist/api/jobs.d.ts +1 -1
- package/dist/api/jobs.js +1 -1
- package/dist/api/journeys.d.ts +1 -1
- package/dist/api/journeys.js +1 -1
- package/dist/api/journeysAnalytics.d.ts +1 -1
- package/dist/api/journeysAnalytics.js +1 -1
- package/dist/api/location.d.ts +1 -1
- package/dist/api/location.js +1 -1
- package/dist/api/lots.d.ts +1 -1
- package/dist/api/lots.js +1 -1
- package/dist/api/loyalty.d.ts +1 -1
- package/dist/api/loyalty.js +1 -1
- package/dist/api/navigation.d.ts +1 -1
- package/dist/api/navigation.js +1 -1
- package/dist/api/nfc.d.ts +1 -1
- package/dist/api/nfc.js +1 -1
- package/dist/api/order.d.ts +1 -1
- package/dist/api/order.js +1 -1
- package/dist/api/product.d.ts +1 -1
- package/dist/api/product.js +1 -1
- package/dist/api/products.d.ts +1 -1
- package/dist/api/products.js +1 -1
- package/dist/api/proof.d.ts +1 -1
- package/dist/api/proof.js +1 -1
- package/dist/api/qr.d.ts +1 -1
- package/dist/api/qr.js +1 -1
- package/dist/api/realtime.d.ts +1 -1
- package/dist/api/realtime.js +1 -1
- package/dist/api/research.d.ts +1 -1
- package/dist/api/research.js +1 -1
- package/dist/api/secrets.d.ts +1 -1
- package/dist/api/secrets.js +1 -1
- package/dist/api/segments.d.ts +1 -1
- package/dist/api/segments.js +1 -1
- package/dist/api/sequence.js +1 -1
- package/dist/api/tags.d.ts +1 -1
- package/dist/api/tags.js +1 -1
- package/dist/api/template.d.ts +1 -1
- package/dist/api/template.js +1 -1
- package/dist/api/translations.d.ts +1 -1
- package/dist/api/translations.js +2 -2
- package/dist/api/variant.d.ts +1 -1
- package/dist/api/variant.js +1 -1
- package/dist/containers/types.d.ts +1 -1
- package/dist/docs/API_SUMMARY.md +7 -7
- package/dist/docs/agent-tools.md +111 -0
- package/dist/docs/ai.md +14 -520
- package/dist/docs/analytics.md +41 -2
- package/dist/docs/app-data-storage.md +0 -38
- package/dist/docs/app-manifest.md +104 -7
- package/dist/docs/app-objects.md +0 -148
- package/dist/docs/app-records-pattern.md +2 -2
- package/dist/docs/building-react-components.md +6 -14
- package/dist/docs/caching.md +20 -21
- package/dist/docs/container-tracking.md +2 -0
- package/dist/docs/containers.md +14 -66
- package/dist/docs/deploying-apps.md +8 -3
- package/dist/docs/executor.md +4 -4
- package/dist/docs/host-dependency-contract.md +159 -0
- package/dist/docs/iframe-responder.md +308 -0
- package/dist/docs/item-context.md +0 -2
- package/dist/docs/manifests.md +3 -3
- package/dist/docs/mobile-admin-container.md +4 -4
- package/dist/docs/mpa.md +5 -5
- package/dist/docs/native-facade.md +1 -1
- package/dist/docs/overview.md +36 -15
- package/dist/docs/portal-back-button.md +2 -3
- package/dist/docs/sequences.md +1 -1
- package/dist/docs/server-functions.md +2 -3
- package/dist/docs/widgets.md +11 -69
- package/dist/http.d.ts +24 -8
- package/dist/http.js +32 -14
- package/dist/iframe.d.ts +2 -2
- package/dist/iframe.js +1 -1
- package/dist/iframeResponder.d.ts +7 -1
- package/dist/iframeResponder.js +45 -4
- package/dist/index.d.ts +30 -27
- package/dist/index.js +10 -8
- package/dist/mobile-admin/errors.d.ts +1 -1
- package/dist/mobile-admin/types.d.ts +2 -2
- package/dist/openapi.yaml +12 -0
- package/dist/shared-dependencies.d.ts +37 -0
- package/dist/shared-dependencies.js +79 -0
- package/dist/testing/index.d.ts +1 -1
- package/dist/translationCache.d.ts +1 -1
- package/dist/types/appManifest.d.ts +23 -0
- package/dist/types/broadcasts.d.ts +1 -1
- package/dist/types/collection.d.ts +2 -2
- package/dist/types/comms.d.ts +5 -5
- package/dist/types/contact.d.ts +1 -1
- package/dist/types/facets.d.ts +1 -1
- package/dist/types/iframeResponder.d.ts +3 -3
- package/dist/types/index.d.ts +44 -44
- package/dist/types/index.js +44 -44
- package/dist/types/interaction.d.ts +1 -1
- package/dist/types/itemContext.d.ts +1 -1
- package/dist/types/journeysAnalytics.d.ts +1 -1
- package/dist/types/navigation.d.ts +1 -1
- package/dist/types/product.d.ts +1 -1
- package/dist/types/proof.d.ts +1 -1
- package/dist/types/segments.d.ts +1 -1
- package/dist/types/widgets.d.ts +2 -2
- package/dist/utils/conditions.d.ts +1 -1
- package/dist/utils/index.d.ts +3 -3
- package/dist/utils/index.js +3 -3
- package/dist/utils/paths.d.ts +4 -4
- package/docs/API_SUMMARY.md +7 -7
- package/docs/agent-tools.md +111 -0
- package/docs/ai.md +14 -520
- package/docs/analytics.md +41 -2
- package/docs/app-data-storage.md +0 -38
- package/docs/app-manifest.md +104 -7
- package/docs/app-objects.md +0 -148
- package/docs/app-records-pattern.md +2 -2
- package/docs/building-react-components.md +6 -14
- package/docs/caching.md +20 -21
- package/docs/container-tracking.md +2 -0
- package/docs/containers.md +14 -66
- package/docs/deploying-apps.md +8 -3
- package/docs/executor.md +4 -4
- package/docs/host-dependency-contract.md +159 -0
- package/docs/iframe-responder.md +308 -0
- package/docs/item-context.md +0 -2
- package/docs/mobile-admin-container.md +4 -4
- package/docs/mpa.md +5 -5
- package/docs/native-facade.md +1 -1
- package/docs/overview.md +36 -15
- package/docs/portal-back-button.md +2 -3
- package/docs/sequences.md +1 -1
- package/docs/server-functions.md +2 -3
- package/docs/widgets.md +11 -69
- package/openapi.yaml +12 -0
- package/package.json +17 -6
- package/scripts/doctor.mjs +171 -0
- package/docs/analytics-metadata-conventions.md +0 -88
- package/docs/iframe-streaming-parent-changes.md +0 -308
- package/docs/manifests.md +0 -204
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
# Iframe Streaming Parent Changes
|
|
2
|
-
|
|
3
|
-
This note describes the parent-side changes needed to support AI streaming when an embedded SmartLinks app is running in iframe proxy mode.
|
|
4
|
-
|
|
5
|
-
If you are using the SDK `IframeResponder` directly, this is already implemented in the SDK changes. You only need this document if your parent application has its own iframe proxy handler and does not rely on `IframeResponder`.
|
|
6
|
-
|
|
7
|
-
## Goal
|
|
8
|
-
|
|
9
|
-
Keep the existing architecture:
|
|
10
|
-
|
|
11
|
-
- local mode: child calls API directly
|
|
12
|
-
- iframe proxy mode: child never owns auth state and streams through the parent
|
|
13
|
-
|
|
14
|
-
This keeps user/session authority in the parent while making AI streaming behave like the rest of the SDK transport.
|
|
15
|
-
|
|
16
|
-
## What changed
|
|
17
|
-
|
|
18
|
-
Previously, proxy mode only supported one-shot request/response messages:
|
|
19
|
-
|
|
20
|
-
- `_smartlinksProxyRequest`
|
|
21
|
-
- `_smartlinksProxyResponse`
|
|
22
|
-
|
|
23
|
-
Streaming now adds a second protocol for long-lived responses:
|
|
24
|
-
|
|
25
|
-
- `_smartlinksProxyStreamRequest`
|
|
26
|
-
- `_smartlinksProxyStream`
|
|
27
|
-
- `_smartlinksProxyStreamAbort`
|
|
28
|
-
|
|
29
|
-
## New parent message handling
|
|
30
|
-
|
|
31
|
-
### 1. Listen for stream requests
|
|
32
|
-
|
|
33
|
-
The iframe child may now send this message:
|
|
34
|
-
|
|
35
|
-
```ts
|
|
36
|
-
{
|
|
37
|
-
_smartlinksProxyStreamRequest: true,
|
|
38
|
-
id: string,
|
|
39
|
-
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
|
|
40
|
-
path: string,
|
|
41
|
-
body?: any,
|
|
42
|
-
headers?: Record<string, string>
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Parent behavior:
|
|
47
|
-
|
|
48
|
-
- treat this like a proxied API request
|
|
49
|
-
- build the real API URL from your configured base URL plus `path`
|
|
50
|
-
- send the request using the parent's current auth/session context
|
|
51
|
-
- expect an SSE / streaming response body
|
|
52
|
-
- keep the request open until the stream ends or is aborted
|
|
53
|
-
|
|
54
|
-
### 2. Forward stream lifecycle messages back to the child
|
|
55
|
-
|
|
56
|
-
The parent should send messages back to the iframe using this envelope:
|
|
57
|
-
|
|
58
|
-
```ts
|
|
59
|
-
{
|
|
60
|
-
_smartlinksProxyStream: true,
|
|
61
|
-
id: string,
|
|
62
|
-
phase: 'open' | 'event' | 'end' | 'error',
|
|
63
|
-
data?: any,
|
|
64
|
-
error?: string,
|
|
65
|
-
status?: number
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Phases:
|
|
70
|
-
|
|
71
|
-
- `open`
|
|
72
|
-
- optional but recommended
|
|
73
|
-
- indicates the upstream streaming request was accepted and a body exists
|
|
74
|
-
- `event`
|
|
75
|
-
- contains one parsed JSON event from an SSE `data:` frame
|
|
76
|
-
- send one message per logical event payload
|
|
77
|
-
- `end`
|
|
78
|
-
- sent once when the stream finishes normally
|
|
79
|
-
- `error`
|
|
80
|
-
- sent if the upstream request fails before or during streaming
|
|
81
|
-
|
|
82
|
-
### 3. Support abort from the child
|
|
83
|
-
|
|
84
|
-
The child may stop reading early and send:
|
|
85
|
-
|
|
86
|
-
```ts
|
|
87
|
-
{
|
|
88
|
-
_smartlinksProxyStreamAbort: true,
|
|
89
|
-
id: string
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Parent behavior:
|
|
94
|
-
|
|
95
|
-
- look up the active stream by `id`
|
|
96
|
-
- abort the underlying fetch / reader
|
|
97
|
-
- clean up any local state for that stream
|
|
98
|
-
- do not keep streaming after abort
|
|
99
|
-
|
|
100
|
-
## SSE forwarding rules
|
|
101
|
-
|
|
102
|
-
The upstream AI endpoints return SSE-like frames. The parent should:
|
|
103
|
-
|
|
104
|
-
- read the response body as a stream
|
|
105
|
-
- buffer text until line boundaries
|
|
106
|
-
- collect `data:` lines for a single event
|
|
107
|
-
- join multi-line `data:` payloads with `\n`
|
|
108
|
-
- ignore blank events
|
|
109
|
-
- stop on `data: [DONE]`
|
|
110
|
-
- JSON-parse each event payload
|
|
111
|
-
- forward parsed payloads to the iframe as `_smartlinksProxyStream` with `phase: 'event'`
|
|
112
|
-
|
|
113
|
-
Minimal parsing behavior:
|
|
114
|
-
|
|
115
|
-
1. accumulate bytes into text
|
|
116
|
-
2. split on `\r?\n`
|
|
117
|
-
3. collect each `data:` line
|
|
118
|
-
4. on blank line, finalize the event
|
|
119
|
-
5. if payload is `[DONE]`, finish
|
|
120
|
-
6. otherwise `JSON.parse(payload)` and forward
|
|
121
|
-
|
|
122
|
-
## Auth and session expectations
|
|
123
|
-
|
|
124
|
-
The parent remains the source of truth for auth.
|
|
125
|
-
|
|
126
|
-
That means the parent stream handler should:
|
|
127
|
-
|
|
128
|
-
- use the same auth headers/token source as normal proxied requests
|
|
129
|
-
- not require the iframe to know the bearer token or API key
|
|
130
|
-
- naturally pick up the current logged-in user when the stream starts
|
|
131
|
-
- cancel active streams if your app invalidates session state on logout or account switch
|
|
132
|
-
|
|
133
|
-
In practice, the stream request should use the same header-building logic as your normal parent proxy transport.
|
|
134
|
-
|
|
135
|
-
## Error handling expectations
|
|
136
|
-
|
|
137
|
-
If the upstream fetch returns a non-2xx status:
|
|
138
|
-
|
|
139
|
-
- try to read the JSON error body
|
|
140
|
-
- derive a useful message
|
|
141
|
-
- send one `_smartlinksProxyStream` message with `phase: 'error'`
|
|
142
|
-
- include `status` when available
|
|
143
|
-
- do not send `end` afterward
|
|
144
|
-
|
|
145
|
-
If the stream body is missing unexpectedly:
|
|
146
|
-
|
|
147
|
-
- send `phase: 'error'`
|
|
148
|
-
|
|
149
|
-
If JSON parsing fails for a single event chunk:
|
|
150
|
-
|
|
151
|
-
- safest behavior is to ignore that malformed chunk and continue
|
|
152
|
-
|
|
153
|
-
## State the parent should keep
|
|
154
|
-
|
|
155
|
-
Track active streams in a map keyed by `id`:
|
|
156
|
-
|
|
157
|
-
```ts
|
|
158
|
-
Map<string, AbortController>
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
Recommended cleanup points:
|
|
162
|
-
|
|
163
|
-
- on normal stream end
|
|
164
|
-
- on error
|
|
165
|
-
- on child abort
|
|
166
|
-
- on iframe detach/unmount
|
|
167
|
-
- on parent auth reset/logout if you want all in-flight streams cancelled immediately
|
|
168
|
-
|
|
169
|
-
## Parent implementation outline
|
|
170
|
-
|
|
171
|
-
```ts
|
|
172
|
-
const activeStreams = new Map<string, AbortController>()
|
|
173
|
-
|
|
174
|
-
window.addEventListener('message', async (event) => {
|
|
175
|
-
const msg = event.data
|
|
176
|
-
|
|
177
|
-
if (msg?._smartlinksProxyStreamAbort && msg.id) {
|
|
178
|
-
activeStreams.get(msg.id)?.abort()
|
|
179
|
-
activeStreams.delete(msg.id)
|
|
180
|
-
return
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (msg?._smartlinksProxyStreamRequest && msg.id) {
|
|
184
|
-
const controller = new AbortController()
|
|
185
|
-
activeStreams.set(msg.id, controller)
|
|
186
|
-
|
|
187
|
-
try {
|
|
188
|
-
const response = await fetch(buildUrl(msg.path), {
|
|
189
|
-
method: msg.method,
|
|
190
|
-
headers: msg.headers,
|
|
191
|
-
body: msg.body ? JSON.stringify(msg.body) : undefined,
|
|
192
|
-
signal: controller.signal,
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
if (!response.ok || !response.body) {
|
|
196
|
-
postError(...)
|
|
197
|
-
return
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
postOpen(...)
|
|
201
|
-
await forwardSse(response.body, parsed => postEvent(...parsed))
|
|
202
|
-
postEnd(...)
|
|
203
|
-
} catch (err) {
|
|
204
|
-
if (err?.name !== 'AbortError') postError(...)
|
|
205
|
-
} finally {
|
|
206
|
-
activeStreams.delete(msg.id)
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
})
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
## Exact protocol summary
|
|
213
|
-
|
|
214
|
-
### Child → parent
|
|
215
|
-
|
|
216
|
-
Standard stream request:
|
|
217
|
-
|
|
218
|
-
```ts
|
|
219
|
-
{
|
|
220
|
-
_smartlinksProxyStreamRequest: true,
|
|
221
|
-
id,
|
|
222
|
-
method,
|
|
223
|
-
path,
|
|
224
|
-
body,
|
|
225
|
-
headers
|
|
226
|
-
}
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
Abort request:
|
|
230
|
-
|
|
231
|
-
```ts
|
|
232
|
-
{
|
|
233
|
-
_smartlinksProxyStreamAbort: true,
|
|
234
|
-
id
|
|
235
|
-
}
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### Parent → child
|
|
239
|
-
|
|
240
|
-
Open:
|
|
241
|
-
|
|
242
|
-
```ts
|
|
243
|
-
{
|
|
244
|
-
_smartlinksProxyStream: true,
|
|
245
|
-
id,
|
|
246
|
-
phase: 'open'
|
|
247
|
-
}
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
Event:
|
|
251
|
-
|
|
252
|
-
```ts
|
|
253
|
-
{
|
|
254
|
-
_smartlinksProxyStream: true,
|
|
255
|
-
id,
|
|
256
|
-
phase: 'event',
|
|
257
|
-
data: parsedJsonEvent
|
|
258
|
-
}
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
End:
|
|
262
|
-
|
|
263
|
-
```ts
|
|
264
|
-
{
|
|
265
|
-
_smartlinksProxyStream: true,
|
|
266
|
-
id,
|
|
267
|
-
phase: 'end'
|
|
268
|
-
}
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
Error:
|
|
272
|
-
|
|
273
|
-
```ts
|
|
274
|
-
{
|
|
275
|
-
_smartlinksProxyStream: true,
|
|
276
|
-
id,
|
|
277
|
-
phase: 'error',
|
|
278
|
-
error: 'message',
|
|
279
|
-
status?: number
|
|
280
|
-
}
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
## What does not change
|
|
284
|
-
|
|
285
|
-
These parts of the parent iframe integration stay the same:
|
|
286
|
-
|
|
287
|
-
- normal `_smartlinksProxyRequest` request/response flow
|
|
288
|
-
- upload proxy flow
|
|
289
|
-
- auth login/logout postMessage handling
|
|
290
|
-
- route/deep-link handling
|
|
291
|
-
- resize handling
|
|
292
|
-
|
|
293
|
-
This is an additive protocol, not a replacement.
|
|
294
|
-
|
|
295
|
-
## Current SDK reference
|
|
296
|
-
|
|
297
|
-
The SDK implementation lives in:
|
|
298
|
-
|
|
299
|
-
- [src/http.ts](src/http.ts)
|
|
300
|
-
- [src/iframeResponder.ts](src/iframeResponder.ts)
|
|
301
|
-
- [src/types/iframeResponder.ts](src/types/iframeResponder.ts)
|
|
302
|
-
- [src/api/ai.ts](src/api/ai.ts)
|
|
303
|
-
|
|
304
|
-
## Practical recommendation
|
|
305
|
-
|
|
306
|
-
If your parent already uses `IframeResponder`, prefer upgrading to the SDK version with these changes instead of re-implementing the protocol manually.
|
|
307
|
-
|
|
308
|
-
If your parent has a custom iframe bridge, implement exactly the three new message types above and reuse your existing auth/header logic from normal proxied requests.
|
package/docs/manifests.md
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
# AI-Native App Manifests
|
|
2
|
-
|
|
3
|
-
SmartLinks apps are designed to be **AI-discoverable, AI-configurable, and AI-importable**. Every app ships with a structured manifest and a prose guide that allow AI systems to set up, configure, and populate apps without custom integration code.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## The Split Manifest
|
|
8
|
-
|
|
9
|
-
The manifest is split into two files so the public portal never loads admin-only configuration data.
|
|
10
|
-
|
|
11
|
-
```text
|
|
12
|
-
app.manifest.json ← lean, always loaded (widget render, SEO, executor discovery)
|
|
13
|
-
app.admin.json ← loaded on-demand (setup wizards, import, AI config flows)
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
### `app.manifest.json` — always loaded
|
|
17
|
-
|
|
18
|
-
| Section | Purpose | AI Consumer |
|
|
19
|
-
|---------|---------|-------------|
|
|
20
|
-
| `meta` | App identity, version, appId, SEO priority | All workflows |
|
|
21
|
-
| `admin` | Pointer to `app.admin.json` | Admin orchestrators |
|
|
22
|
-
| `widgets` | Bundle files + component definitions + settings schemas; can also declare widget-instance resolution via `widgetId` | Widget Builder |
|
|
23
|
-
| `containers` | Bundle files + component definitions | Container Loader |
|
|
24
|
-
| `executor` | Bundle files, factory name, exports list | Server / AI |
|
|
25
|
-
| `linkable` | Static deep-link routes | Portal menus / AI nav |
|
|
26
|
-
|
|
27
|
-
```json
|
|
28
|
-
{
|
|
29
|
-
"meta": { "name": "My App", "appId": "my-app", "version": "1.0.0" },
|
|
30
|
-
"admin": "app.admin.json",
|
|
31
|
-
"widgets": {
|
|
32
|
-
"instanceResolution": true,
|
|
33
|
-
"instanceParam": "widgetId",
|
|
34
|
-
"files": {
|
|
35
|
-
"js": { "umd": "dist/widgets.umd.js", "esm": "dist/widgets.es.js" },
|
|
36
|
-
"css": null
|
|
37
|
-
},
|
|
38
|
-
"components": [
|
|
39
|
-
{
|
|
40
|
-
"name": "MyWidget",
|
|
41
|
-
"description": "Compact summary card.",
|
|
42
|
-
"sizes": ["compact", "standard", "large"],
|
|
43
|
-
"settings": { ... }
|
|
44
|
-
}
|
|
45
|
-
]
|
|
46
|
-
},
|
|
47
|
-
"containers": {
|
|
48
|
-
"files": {
|
|
49
|
-
"js": { "umd": "dist/containers.umd.js", "esm": "dist/containers.es.js" },
|
|
50
|
-
"css": null
|
|
51
|
-
},
|
|
52
|
-
"components": [{ "name": "PublicContainer", "description": "Full app view." }]
|
|
53
|
-
},
|
|
54
|
-
"executor": {
|
|
55
|
-
"files": { "js": { "umd": "dist/executor.umd.js", "esm": "dist/executor.es.js" } },
|
|
56
|
-
"factory": "createMyAppExecutor",
|
|
57
|
-
"exports": ["createMyAppExecutor", "getSEO", "getLLMContent"],
|
|
58
|
-
"description": "Programmatic configuration and SEO API for My App."
|
|
59
|
-
},
|
|
60
|
-
"linkable": [
|
|
61
|
-
{ "title": "Home", "path": "/" },
|
|
62
|
-
{ "title": "Gallery", "path": "/gallery" }
|
|
63
|
-
]
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
When `instanceResolution` is enabled, the app is declaring that consumers can pass a widget instance identifier such as `?appId=widget-toolkit&widgetId=launch-countdown`, and the widget bundle will resolve its stored configuration from app config.
|
|
68
|
-
|
|
69
|
-
> ⚠️ **`css` is `null` by default.** Most widgets and containers use Tailwind/shadcn classes inherited from the parent and produce **no CSS output file**. Set `"css": null` in the manifest. Only set it to a filename if your widget/container ships a custom CSS file that actually exists in `dist/`. The parent portal checks this value before injecting a `<link>` tag — a non-null value pointing to a missing file will cause a 404.
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
### `app.admin.json` — loaded on-demand
|
|
74
|
-
|
|
75
|
-
| Section | Purpose | AI Consumer |
|
|
76
|
-
|---------|---------|-------------|
|
|
77
|
-
| `aiGuide` | Pointer to `ai-guide.md` prose instructions | All AI workflows |
|
|
78
|
-
| `setup` | Setup wizard: questions, config schema, save instructions | Setup Wizard |
|
|
79
|
-
| `import` | Bulk data import: field definitions, CSV shape, API calls | Data Importer |
|
|
80
|
-
| `tunable` | Runtime-adjustable settings | AI Optimizer |
|
|
81
|
-
| `metrics` | Tracked interactions and KPIs | Analytics Advisor |
|
|
82
|
-
|
|
83
|
-
The admin orchestrator fetches the manifest, reads the `admin` pointer, and fetches `app.admin.json` only when needed — never on public page loads.
|
|
84
|
-
|
|
85
|
-
See the [App Configuration Files reference](app-manifest.md) for the full field-by-field schema for both files.
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## Widget Settings Schema
|
|
90
|
-
|
|
91
|
-
Each widget component in `app.manifest.json` should include a `settings` object using **JSON Schema** to describe its configurable props. This enables schema-form libraries and AI orchestrators to auto-generate configuration UIs without per-widget code.
|
|
92
|
-
|
|
93
|
-
```json
|
|
94
|
-
"components": [
|
|
95
|
-
{
|
|
96
|
-
"name": "MyWidget",
|
|
97
|
-
"description": "What this widget does",
|
|
98
|
-
"sizes": ["compact", "standard", "large"],
|
|
99
|
-
"settings": {
|
|
100
|
-
"type": "object",
|
|
101
|
-
"properties": {
|
|
102
|
-
"displayMode": {
|
|
103
|
-
"type": "string",
|
|
104
|
-
"title": "Display Mode",
|
|
105
|
-
"description": "How the widget renders",
|
|
106
|
-
"enum": ["compact", "standard", "large"],
|
|
107
|
-
"enumLabels": {
|
|
108
|
-
"compact": "Icons only",
|
|
109
|
-
"standard": "With names",
|
|
110
|
-
"large": "Full cards"
|
|
111
|
-
},
|
|
112
|
-
"default": "standard",
|
|
113
|
-
"order": 1
|
|
114
|
-
},
|
|
115
|
-
"showImage": {
|
|
116
|
-
"type": "boolean",
|
|
117
|
-
"title": "Show Product Image",
|
|
118
|
-
"default": true,
|
|
119
|
-
"order": 2
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
]
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
| Field | Purpose |
|
|
128
|
-
|-------|---------|
|
|
129
|
-
| `type`, `enum` | Standard JSON Schema for validation |
|
|
130
|
-
| `title` | Human-readable label for form rendering |
|
|
131
|
-
| `description` | Help text shown alongside the field |
|
|
132
|
-
| `enumLabels` | Friendly display names for enum values (`{ value → label }`) |
|
|
133
|
-
| `default` | Pre-selected value when no configuration exists |
|
|
134
|
-
| `order` | Field display order in rendered forms (lower number = higher position) |
|
|
135
|
-
|
|
136
|
-
The `settings` schema serves dual purposes: AI orchestrators use it to understand what a widget accepts and generate configuration conversationally; schema-form renderers (e.g., in admin consoles) use it to auto-generate settings UIs.
|
|
137
|
-
|
|
138
|
-
---
|
|
139
|
-
|
|
140
|
-
## The AI Guide (`ai-guide.md`)
|
|
141
|
-
|
|
142
|
-
A companion Markdown file deployed alongside the manifest provides **natural-language instructions** for AI orchestrators. The admin config references it via `"aiGuide": "ai-guide.md"` — orchestrators resolve and fetch it relative to the manifest URL.
|
|
143
|
-
|
|
144
|
-
While the manifest is structured data, the AI guide provides prose context, nuance, and step-by-step instructions that help an LLM drive setup wizards, imports, and troubleshooting flows conversationally.
|
|
145
|
-
|
|
146
|
-
Use the [AI Guide Template](ai-guide-template.md) as your starting point.
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
## Three AI Workflows
|
|
151
|
-
|
|
152
|
-
### 1. Widget Builder
|
|
153
|
-
|
|
154
|
-
An AI fetches `app.manifest.json`, reads `widgets.components[]` including the `settings` JSON Schema for each widget, and can:
|
|
155
|
-
- Generate React code to embed the widget with correct props
|
|
156
|
-
- Auto-render a configuration UI from the settings schema
|
|
157
|
-
- Understand valid size hints and required vs optional props
|
|
158
|
-
|
|
159
|
-
### 2. Setup Wizard
|
|
160
|
-
|
|
161
|
-
An AI reads `setup` from `app.admin.json` to drive a conversational configuration flow:
|
|
162
|
-
|
|
163
|
-
1. Walk the user through each `setup.questions[]` entry
|
|
164
|
-
2. Validate answers against `setup.configSchema` (JSON Schema)
|
|
165
|
-
3. Optionally use `setup.contentHints` to auto-generate content via `SL.ai.chat.completions`
|
|
166
|
-
4. Save using the `setup.saveWith` instructions (method, scope, admin flag)
|
|
167
|
-
|
|
168
|
-
The AI guide (`ai-guide.md`) provides prose instructions on how to handle each question, what sensible defaults look like, and what to do if the user is unsure.
|
|
169
|
-
|
|
170
|
-
### 3. Data Importer
|
|
171
|
-
|
|
172
|
-
An AI reads `import` from `app.admin.json` to:
|
|
173
|
-
|
|
174
|
-
1. Generate a CSV template from `import.fields[]` (with types, required flags, and examples)
|
|
175
|
-
2. Normalise user-provided data against field types
|
|
176
|
-
3. Call `import.saveWith.method` for each row
|
|
177
|
-
|
|
178
|
-
For multi-app imports, fields from multiple manifests can be merged into a single CSV template.
|
|
179
|
-
|
|
180
|
-
---
|
|
181
|
-
|
|
182
|
-
## Maintaining the Manifest
|
|
183
|
-
|
|
184
|
-
When you change your app's configuration shape, update all three files together:
|
|
185
|
-
|
|
186
|
-
| File | What to update |
|
|
187
|
-
|------|---------------|
|
|
188
|
-
| `app.manifest.json` | `widgets.components[].settings`, `containers`, `executor.exports`, `linkable` |
|
|
189
|
-
| `app.admin.json` | `setup.questions`, `setup.configSchema`, `import.fields`, `tunable.fields` |
|
|
190
|
-
| `ai-guide.md` | Prose instructions, validation rules, examples, and any new question guidance |
|
|
191
|
-
|
|
192
|
-
Keeping all three in sync ensures AI orchestrators, setup wizards, and data importers all work from consistent, accurate information.
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
|
-
## Related Guides
|
|
197
|
-
|
|
198
|
-
| Guide | What it covers |
|
|
199
|
-
|-------|---------------|
|
|
200
|
-
| [App Configuration Files](app-manifest.md) | Full field-by-field reference for both JSON files |
|
|
201
|
-
| [Executor Model](executor.md) | Building `executor.umd.js` — SEO, LLM content, config mutations |
|
|
202
|
-
| [Deep Link Discovery](deep-link-discovery.md) | `linkable` — static and dynamic navigable states |
|
|
203
|
-
| [AI Guide Template](ai-guide-template.md) | Starter template for `ai-guide.md` |
|
|
204
|
-
| [AI & Chat Completions](ai.md) | `SL.ai` — used in `contentHints` auto-generation |
|