@proveanything/smartlinks 2.0.20 → 2.0.21
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/functions.d.ts +18 -8
- package/dist/api/functions.js +39 -14
- package/dist/docs/API_SUMMARY.md +22 -7
- package/dist/docs/server-functions.md +61 -6
- package/dist/http.d.ts +10 -0
- package/dist/http.js +18 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/openapi.yaml +5 -28
- package/docs/API_SUMMARY.md +22 -7
- package/docs/server-functions.md +61 -6
- package/openapi.yaml +5 -28
- package/package.json +1 -1
package/dist/api/functions.d.ts
CHANGED
|
@@ -8,20 +8,30 @@ export interface FunctionListEntry {
|
|
|
8
8
|
export interface FunctionListResponse {
|
|
9
9
|
functions: FunctionListEntry[];
|
|
10
10
|
}
|
|
11
|
+
/** Options for a function call. `appId` scopes resolution to one app (recommended). */
|
|
12
|
+
export interface FunctionCallOptions {
|
|
13
|
+
appId?: string;
|
|
14
|
+
}
|
|
11
15
|
export declare namespace functions {
|
|
12
16
|
/**
|
|
13
|
-
* Call a PUBLIC app server function inline.
|
|
14
|
-
* `POST /public/collection/:
|
|
17
|
+
* Call a PUBLIC app server function inline (surface `'public'`).
|
|
18
|
+
* App-scoped: `POST /public/collection/:c/app/:appId/functions/:name`.
|
|
15
19
|
*
|
|
16
20
|
* @example
|
|
17
|
-
*
|
|
21
|
+
* // App calling its own function (appId from initializeApi({ appId })):
|
|
22
|
+
* const { value } = await SL.functions.call<{ value: number }>(collectionId, 'pressCounter')
|
|
23
|
+
* // Or address another app explicitly:
|
|
24
|
+
* await SL.functions.call(collectionId, 'pressCounter', {}, { appId: 'my-counter-app' })
|
|
18
25
|
*/
|
|
19
|
-
function call<T = FunctionCallResult>(collectionId: string, name: string, body?: Record<string, any
|
|
26
|
+
function call<T = FunctionCallResult>(collectionId: string, name: string, body?: Record<string, any>, opts?: FunctionCallOptions): Promise<T>;
|
|
20
27
|
/**
|
|
21
28
|
* Call an ADMIN app server function (surface `'admin'`; requires an admin session).
|
|
22
|
-
* `POST /admin/collection/:
|
|
29
|
+
* App-scoped: `POST /admin/collection/:c/app/:appId/functions/:name`.
|
|
30
|
+
*/
|
|
31
|
+
function callAdmin<T = FunctionCallResult>(collectionId: string, name: string, body?: Record<string, any>, opts?: FunctionCallOptions): Promise<T>;
|
|
32
|
+
/**
|
|
33
|
+
* List the public functions available for a collection (discovery). Scoped to one app when an
|
|
34
|
+
* appId is given (or set as the SDK app context): `GET /public/collection/:c[/app/:appId]/functions`.
|
|
23
35
|
*/
|
|
24
|
-
function
|
|
25
|
-
/** List the public functions available for a collection (discovery). `GET /public/collection/:c/functions`. */
|
|
26
|
-
function list(collectionId: string): Promise<FunctionListResponse>;
|
|
36
|
+
function list(collectionId: string, opts?: FunctionCallOptions): Promise<FunctionListResponse>;
|
|
27
37
|
}
|
package/dist/api/functions.js
CHANGED
|
@@ -5,33 +5,58 @@
|
|
|
5
5
|
// client half. The PUBLIC route runs a function inline on the caller's own authority (owner if
|
|
6
6
|
// signed in via authKit, else public); the ADMIN route runs on the admin surface (needs an admin
|
|
7
7
|
// session). The returned value is the function's own result (`event.body` is what you pass here).
|
|
8
|
-
|
|
8
|
+
//
|
|
9
|
+
// ADDRESSING. A function always belongs to an app, so the canonical route is app-scoped:
|
|
10
|
+
// /collection/:c/app/:appId/functions/:name
|
|
11
|
+
// The appId comes from `opts.appId`, else the SDK's app context (initializeApi({ appId })) — so an
|
|
12
|
+
// app calling its OWN function just writes `SL.functions.call(collectionId, name)`. With no appId
|
|
13
|
+
// available, the call falls back to the DEPRECATED flat path `/collection/:c/functions/:name`,
|
|
14
|
+
// which the server resolves by bare name and REJECTS with 409 AMBIGUOUS_FUNCTION when more than one
|
|
15
|
+
// installed app defines that name. Always prefer an appId.
|
|
16
|
+
import { post, request, getAppContext } from "../http.js";
|
|
17
|
+
function fnPath(surface, collectionId, name, appId) {
|
|
18
|
+
const c = encodeURIComponent(collectionId);
|
|
19
|
+
const n = encodeURIComponent(name);
|
|
20
|
+
const app = appId !== null && appId !== void 0 ? appId : getAppContext();
|
|
21
|
+
return app
|
|
22
|
+
? `/${surface}/collection/${c}/app/${encodeURIComponent(app)}/functions/${n}`
|
|
23
|
+
: `/${surface}/collection/${c}/functions/${n}`; // deprecated flat alias
|
|
24
|
+
}
|
|
9
25
|
export var functions;
|
|
10
26
|
(function (functions) {
|
|
11
27
|
/**
|
|
12
|
-
* Call a PUBLIC app server function inline.
|
|
13
|
-
* `POST /public/collection/:
|
|
28
|
+
* Call a PUBLIC app server function inline (surface `'public'`).
|
|
29
|
+
* App-scoped: `POST /public/collection/:c/app/:appId/functions/:name`.
|
|
14
30
|
*
|
|
15
31
|
* @example
|
|
16
|
-
*
|
|
32
|
+
* // App calling its own function (appId from initializeApi({ appId })):
|
|
33
|
+
* const { value } = await SL.functions.call<{ value: number }>(collectionId, 'pressCounter')
|
|
34
|
+
* // Or address another app explicitly:
|
|
35
|
+
* await SL.functions.call(collectionId, 'pressCounter', {}, { appId: 'my-counter-app' })
|
|
17
36
|
*/
|
|
18
|
-
async function call(collectionId, name, body = {}) {
|
|
19
|
-
|
|
20
|
-
return post(path, body);
|
|
37
|
+
async function call(collectionId, name, body = {}, opts = {}) {
|
|
38
|
+
return post(fnPath('public', collectionId, name, opts.appId), body);
|
|
21
39
|
}
|
|
22
40
|
functions.call = call;
|
|
23
41
|
/**
|
|
24
42
|
* Call an ADMIN app server function (surface `'admin'`; requires an admin session).
|
|
25
|
-
* `POST /admin/collection/:
|
|
43
|
+
* App-scoped: `POST /admin/collection/:c/app/:appId/functions/:name`.
|
|
26
44
|
*/
|
|
27
|
-
async function callAdmin(collectionId, name, body = {}) {
|
|
28
|
-
|
|
29
|
-
return post(path, body);
|
|
45
|
+
async function callAdmin(collectionId, name, body = {}, opts = {}) {
|
|
46
|
+
return post(fnPath('admin', collectionId, name, opts.appId), body);
|
|
30
47
|
}
|
|
31
48
|
functions.callAdmin = callAdmin;
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
49
|
+
/**
|
|
50
|
+
* List the public functions available for a collection (discovery). Scoped to one app when an
|
|
51
|
+
* appId is given (or set as the SDK app context): `GET /public/collection/:c[/app/:appId]/functions`.
|
|
52
|
+
*/
|
|
53
|
+
async function list(collectionId, opts = {}) {
|
|
54
|
+
var _a;
|
|
55
|
+
const c = encodeURIComponent(collectionId);
|
|
56
|
+
const app = (_a = opts.appId) !== null && _a !== void 0 ? _a : getAppContext();
|
|
57
|
+
const path = app
|
|
58
|
+
? `/public/collection/${c}/app/${encodeURIComponent(app)}/functions`
|
|
59
|
+
: `/public/collection/${c}/functions`;
|
|
35
60
|
return request(path);
|
|
36
61
|
}
|
|
37
62
|
functions.list = list;
|
package/dist/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.21 | Generated: 2026-09-25T17:47:14.766Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -166,6 +166,12 @@ Reset the diagnostics counters (does not touch the cache itself).
|
|
|
166
166
|
**isProxyEnabled**() → `boolean`
|
|
167
167
|
Return whether proxy mode is currently enabled.
|
|
168
168
|
|
|
169
|
+
**getAppContext**() → `string | undefined`
|
|
170
|
+
The current app context (appId), if the SDK was initialized with one.
|
|
171
|
+
|
|
172
|
+
**setAppContext**(id: string | undefined) → `void`
|
|
173
|
+
Set (or clear) the current app context — the appId used to scope SL.functions calls.
|
|
174
|
+
|
|
169
175
|
**initializeApi**(options: {
|
|
170
176
|
baseURL: string
|
|
171
177
|
apiKey?: string
|
|
@@ -8960,6 +8966,13 @@ interface FunctionListResponse {
|
|
|
8960
8966
|
}
|
|
8961
8967
|
```
|
|
8962
8968
|
|
|
8969
|
+
**FunctionCallOptions** (interface)
|
|
8970
|
+
```typescript
|
|
8971
|
+
interface FunctionCallOptions {
|
|
8972
|
+
appId?: string
|
|
8973
|
+
}
|
|
8974
|
+
```
|
|
8975
|
+
|
|
8963
8976
|
**FunctionCallResult** = `any`
|
|
8964
8977
|
|
|
8965
8978
|
### sequence (api)
|
|
@@ -10458,16 +10471,18 @@ Delete a form for a collection (admin only).
|
|
|
10458
10471
|
|
|
10459
10472
|
**call**(collectionId: string,
|
|
10460
10473
|
name: string,
|
|
10461
|
-
body: Record<string, any> = {}
|
|
10462
|
-
|
|
10474
|
+
body: Record<string, any> = {},
|
|
10475
|
+
opts: FunctionCallOptions = {}) → `Promise<T>`
|
|
10476
|
+
Call a PUBLIC app server function inline (surface `'public'`). App-scoped: `POST /public/collection/:c/app/:appId/functions/:name`. // App calling its own function (appId from initializeApi({ appId })): const { value } = await SL.functions.call<{ value: number }>(collectionId, 'pressCounter') // Or address another app explicitly: await SL.functions.call(collectionId, 'pressCounter', {}, { appId: 'my-counter-app' })
|
|
10463
10477
|
|
|
10464
10478
|
**callAdmin**(collectionId: string,
|
|
10465
10479
|
name: string,
|
|
10466
|
-
body: Record<string, any> = {}
|
|
10467
|
-
|
|
10480
|
+
body: Record<string, any> = {},
|
|
10481
|
+
opts: FunctionCallOptions = {}) → `Promise<T>`
|
|
10482
|
+
Call an ADMIN app server function (surface `'admin'`; requires an admin session). App-scoped: `POST /admin/collection/:c/app/:appId/functions/:name`.
|
|
10468
10483
|
|
|
10469
|
-
**list**(collectionId: string) → `Promise<FunctionListResponse>`
|
|
10470
|
-
List the public functions available for a collection (discovery). `GET /public/collection/:c/functions`.
|
|
10484
|
+
**list**(collectionId: string, opts: FunctionCallOptions = {}) → `Promise<FunctionListResponse>`
|
|
10485
|
+
List the public functions available for a collection (discovery). Scoped to one app when an appId is given (or set as the SDK app context): `GET /public/collection/:c[/app/:appId]/functions`.
|
|
10471
10486
|
|
|
10472
10487
|
### http
|
|
10473
10488
|
|
|
@@ -181,11 +181,14 @@ interface ServerFunctionContext {
|
|
|
181
181
|
collectionId: string
|
|
182
182
|
appId: string
|
|
183
183
|
|
|
184
|
-
/** SmartLinks SDK, pre-scoped to your declared `authority`. Capabilities cap what it may do.
|
|
184
|
+
/** SmartLinks SDK, pre-scoped to your declared `authority`. Capabilities cap what it may do.
|
|
185
|
+
* Key resources: `sl.appRecords` (per-app records), `sl.appData` (general/app-wide config +
|
|
186
|
+
* data — URLs, flags, counters, arrays), `sl.products`, `sl.attestations`. */
|
|
185
187
|
sl: SmartLinks
|
|
186
188
|
|
|
187
|
-
/** Capability-gated secrets
|
|
188
|
-
|
|
189
|
+
/** Capability-gated secrets (need `secrets:<ref>`). `get(ref)` resolves the collection's OWN
|
|
190
|
+
* secret first, then the app-level one; `app(ref)` reads the app-level secret only. */
|
|
191
|
+
secrets: { get(ref: string): Promise<string | null>; app(ref: string): Promise<string | null> }
|
|
189
192
|
|
|
190
193
|
/** Who invoked this function. */
|
|
191
194
|
caller: {
|
|
@@ -211,6 +214,50 @@ already authenticated as your declared authority and scoped to the collection. D
|
|
|
211
214
|
to construct your own SDK client or carry your own key; that's what `ctx.sl` is for, and it's
|
|
212
215
|
the only way authority stays correct.
|
|
213
216
|
|
|
217
|
+
### Calling a function from your app (client side)
|
|
218
|
+
|
|
219
|
+
From a page/UI, invoke an `http`-trigger function with the SDK — no manual fetch, no URL building:
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
// public function (runs on the caller's authority — signed-in owner, else public):
|
|
223
|
+
const res = await SL.functions.call(collectionId, 'increment', { /* becomes event.body */ })
|
|
224
|
+
// admin surface (needs an admin session):
|
|
225
|
+
const res = await SL.functions.callAdmin(collectionId, 'recomputeTotals', { … })
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
`res` is whatever your handler returns. See the `edge-function-test` example for a full page +
|
|
229
|
+
function + manifest.
|
|
230
|
+
|
|
231
|
+
#### Functions are ALWAYS app-scoped
|
|
232
|
+
|
|
233
|
+
A function belongs to an app, so the canonical route carries the appId:
|
|
234
|
+
`POST /collection/:collectionId/app/:appId/functions/:name`. Two different installed apps can each
|
|
235
|
+
ship a function of the same name without clashing.
|
|
236
|
+
|
|
237
|
+
The SDK fills the appId in for you. Initialize with your app's id once, then call by bare name —
|
|
238
|
+
the SDK routes it app-scoped:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
SL.initializeApi({ baseURL, appId: 'my-counter-app' }) // usually done by the host/bootstrap
|
|
242
|
+
await SL.functions.call(collectionId, 'pressCounter') // → /collection/:c/app/my-counter-app/functions/pressCounter
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
To call a *different* app's function, pass the appId explicitly:
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
await SL.functions.call(collectionId, 'pressCounter', {}, { appId: 'some-other-app' })
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
If no appId is available (not set on init, none passed), the call falls back to the **deprecated
|
|
252
|
+
flat path** `/collection/:c/functions/:name`, which the server resolves by bare name and **rejects
|
|
253
|
+
with `409 AMBIGUOUS_FUNCTION`** when more than one installed app defines that name (a first-party
|
|
254
|
+
builtin still wins). Always prefer an appId.
|
|
255
|
+
|
|
256
|
+
> There is no such thing as an app-less function. First-party builtins (e.g. the `functions.ping`
|
|
257
|
+
> diagnostic) belong to the reserved `smartlinks` app. A "global" function is just an app enabled on
|
|
258
|
+
> the `global` collection and called at `/collection/global/app/:appId/functions/:name` — same two
|
|
259
|
+
> facets (collection + app), with `global` as the sentinel collection.
|
|
260
|
+
|
|
214
261
|
---
|
|
215
262
|
|
|
216
263
|
## Runtime — what your function can use
|
|
@@ -262,6 +309,8 @@ Prefer the platform primitives above over a dependency; when you do need one, pi
|
|
|
262
309
|
| Hash / HMAC-sign / verify / encrypt | `crypto.subtle` (Web Crypto) | — |
|
|
263
310
|
| Random id / bytes | `crypto.randomUUID()` / `crypto.getRandomValues()` | — |
|
|
264
311
|
| Read or write SmartLinks data | `ctx.sl.*` (records, products, attestations, …) | the matching `sl:<res>:<read\|write>` |
|
|
312
|
+
| Read/write general or app-wide data (config, URLs, counters, arrays) | `ctx.sl.appData.get()` / `ctx.sl.appData.set({…})` — pass `{ scope: 'global' }` for app-wide (shared by every install; global writes need collection authority) | `sl:data:read` / `sl:data:write` |
|
|
313
|
+
| Guarantee a UNIQUE claim (pool of numbers, one-per-user, idempotency key) | `ctx.sl.appRecords.create({ ref: 'ball:57' })` — the DB unique index rejects a duplicate `ref` (catch = "already taken") | `sl:records:write` |
|
|
265
314
|
|
|
266
315
|
Notes:
|
|
267
316
|
- **Talking to the SmartLinks core is `ctx.sl`, not HTTP.** The common pattern — *validate /
|
|
@@ -318,14 +367,20 @@ other secrets, or any other collection.
|
|
|
318
367
|
|
|
319
368
|
## Invoking an http function
|
|
320
369
|
|
|
321
|
-
An `http` function is called by POSTing to the
|
|
370
|
+
An `http` function is called by POSTing to the app-scoped functions endpoint on the
|
|
322
371
|
surface that matches its `visibility`:
|
|
323
372
|
|
|
324
373
|
```
|
|
325
|
-
POST /admin/collection/:collectionId/functions/:name # visibility: admin (collection-admin auth)
|
|
326
|
-
POST /public/collection/:collectionId/functions/:name
|
|
374
|
+
POST /admin/collection/:collectionId/app/:appId/functions/:name # visibility: admin (collection-admin auth)
|
|
375
|
+
POST /public/collection/:collectionId/app/:appId/functions/:name # visibility: public (auth optional)
|
|
376
|
+
GET /{admin|public}/collection/:collectionId/app/:appId/functions # list this app's functions on the surface
|
|
327
377
|
```
|
|
328
378
|
|
|
379
|
+
The bare-name form (`/collection/:c/functions/:name`, no `/app/:appId`) is a **deprecated alias**:
|
|
380
|
+
it resolves by name across all installed apps, lets a first-party builtin win, and returns
|
|
381
|
+
`409 AMBIGUOUS_FUNCTION` when two apps define the same name. Prefer the app-scoped route (the SDK
|
|
382
|
+
emits it automatically once an appId is set — see "Calling a function from your app").
|
|
383
|
+
|
|
329
384
|
The request body is delivered to the handler as `event.body` (query string as
|
|
330
385
|
`event.query`). A function only runs on its own surface — calling an `admin` function on
|
|
331
386
|
the public endpoint is a `403`. The response is `{ ok: true, result }` on success, or
|
package/dist/http.d.ts
CHANGED
|
@@ -27,6 +27,10 @@ export declare function getHttpCacheDiagnostics(): {
|
|
|
27
27
|
export declare function resetHttpCacheDiagnostics(): void;
|
|
28
28
|
/** Return whether proxy mode is currently enabled. */
|
|
29
29
|
export declare function isProxyEnabled(): boolean;
|
|
30
|
+
/** The current app context (appId), if the SDK was initialized with one. */
|
|
31
|
+
export declare function getAppContext(): string | undefined;
|
|
32
|
+
/** Set (or clear) the current app context — the appId used to scope SL.functions calls. */
|
|
33
|
+
export declare function setAppContext(id: string | undefined): void;
|
|
30
34
|
export declare function initializeApi(options: {
|
|
31
35
|
baseURL: string;
|
|
32
36
|
apiKey?: string;
|
|
@@ -42,6 +46,12 @@ export declare function initializeApi(options: {
|
|
|
42
46
|
* across re-initialization when not supplied.
|
|
43
47
|
*/
|
|
44
48
|
platform?: 'native' | 'web';
|
|
49
|
+
/**
|
|
50
|
+
* The appId of the micro-app initializing the SDK. When set, `SL.functions.call(...)` and
|
|
51
|
+
* `callAdmin(...)` resolve app-scoped by default (no need to pass appId on every call).
|
|
52
|
+
* Preserved across re-initialization when not supplied.
|
|
53
|
+
*/
|
|
54
|
+
appId?: string;
|
|
45
55
|
iframeAutoResize?: boolean;
|
|
46
56
|
logger?: Logger;
|
|
47
57
|
/**
|
package/dist/http.js
CHANGED
|
@@ -45,6 +45,13 @@ let clientPlatform = undefined;
|
|
|
45
45
|
* data call that touches the granted proof (attestations, threads, app data).
|
|
46
46
|
*/
|
|
47
47
|
let grantToken = undefined;
|
|
48
|
+
/**
|
|
49
|
+
* The current app context — the appId of the micro-app this SDK instance belongs to.
|
|
50
|
+
* Set via initializeApi({ appId }) or setAppContext(). Lets an app call its OWN server
|
|
51
|
+
* functions without repeating its id: SL.functions.call(collectionId, name) resolves
|
|
52
|
+
* app-scoped when this is set. Explicit `appId` on a call always overrides it.
|
|
53
|
+
*/
|
|
54
|
+
let appContextId = undefined;
|
|
48
55
|
/** Whether initializeApi has been successfully called at least once. */
|
|
49
56
|
let initialized = false;
|
|
50
57
|
/** Safely returns the current browser hostname, or an empty string in non-browser / Node environments. */
|
|
@@ -293,6 +300,14 @@ function logDebug(...args) {
|
|
|
293
300
|
export function isProxyEnabled() {
|
|
294
301
|
return proxyMode;
|
|
295
302
|
}
|
|
303
|
+
/** The current app context (appId), if the SDK was initialized with one. */
|
|
304
|
+
export function getAppContext() {
|
|
305
|
+
return appContextId;
|
|
306
|
+
}
|
|
307
|
+
/** Set (or clear) the current app context — the appId used to scope SL.functions calls. */
|
|
308
|
+
export function setAppContext(id) {
|
|
309
|
+
appContextId = id;
|
|
310
|
+
}
|
|
296
311
|
function maskSensitive(value) {
|
|
297
312
|
if (!value)
|
|
298
313
|
return value;
|
|
@@ -443,6 +458,9 @@ export function initializeApi(options) {
|
|
|
443
458
|
}
|
|
444
459
|
baseURL = normalizedBaseURL;
|
|
445
460
|
apiKey = options.apiKey;
|
|
461
|
+
// Preserve the app context across re-inits that omit it (mirrors platform/token handling).
|
|
462
|
+
if (options.appId !== undefined)
|
|
463
|
+
appContextId = options.appId;
|
|
446
464
|
// Enable token persistence before restoring the token.
|
|
447
465
|
if (options.persistToken !== undefined)
|
|
448
466
|
tokenPersistenceEnabled = options.persistToken;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { initializeApi, isInitialized, hasAuthCredentials, configureSdkCache, invalidateCache, getHttpCacheDiagnostics, resetHttpCacheDiagnostics, request, post, put, patch, del, sendCustomProxyMessage, getApiHeaders, getBaseURL, isProxyEnabled, setBearerToken, getBearerToken, setGrantToken, getGrantToken } from "./http.js";
|
|
1
|
+
export { initializeApi, isInitialized, hasAuthCredentials, configureSdkCache, invalidateCache, getHttpCacheDiagnostics, resetHttpCacheDiagnostics, request, post, put, patch, del, sendCustomProxyMessage, getApiHeaders, getBaseURL, isProxyEnabled, setBearerToken, getBearerToken, setGrantToken, getGrantToken, getAppContext, setAppContext } from "./http.js";
|
|
2
2
|
export * from "./api/index.js";
|
|
3
3
|
export * from "./types/index.js";
|
|
4
4
|
export { iframe } from "./iframe.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
// Top-level entrypoint of the npm package. Re-export initializeApi + all namespaces.
|
|
3
|
-
export { initializeApi, isInitialized, hasAuthCredentials, configureSdkCache, invalidateCache, getHttpCacheDiagnostics, resetHttpCacheDiagnostics, request, post, put, patch, del, sendCustomProxyMessage, getApiHeaders, getBaseURL, isProxyEnabled, setBearerToken, getBearerToken, setGrantToken, getGrantToken } from "./http.js";
|
|
3
|
+
export { initializeApi, isInitialized, hasAuthCredentials, configureSdkCache, invalidateCache, getHttpCacheDiagnostics, resetHttpCacheDiagnostics, request, post, put, patch, del, sendCustomProxyMessage, getApiHeaders, getBaseURL, isProxyEnabled, setBearerToken, getBearerToken, setGrantToken, getGrantToken, getAppContext, setAppContext } from "./http.js";
|
|
4
4
|
export * from "./api/index.js";
|
|
5
5
|
export * from "./types/index.js";
|
|
6
6
|
// Iframe namespace
|
package/dist/openapi.yaml
CHANGED
|
@@ -72,8 +72,6 @@ tags:
|
|
|
72
72
|
description: Product facet querying and aggregation.
|
|
73
73
|
- name: form
|
|
74
74
|
description: Form definitions and submissions.
|
|
75
|
-
- name: functions
|
|
76
|
-
description: functions API
|
|
77
75
|
- name: integrations
|
|
78
76
|
description: Third-party integration flows and imports.
|
|
79
77
|
- name: interactions
|
|
@@ -12152,32 +12150,6 @@ paths:
|
|
|
12152
12150
|
description: Unauthorized
|
|
12153
12151
|
404:
|
|
12154
12152
|
description: Not found
|
|
12155
|
-
/public/collection/{collectionId}/functions:
|
|
12156
|
-
get:
|
|
12157
|
-
tags:
|
|
12158
|
-
- functions
|
|
12159
|
-
summary: List the public functions available for a collection (discovery).
|
|
12160
|
-
operationId: functions_list
|
|
12161
|
-
security: []
|
|
12162
|
-
parameters:
|
|
12163
|
-
- name: collectionId
|
|
12164
|
-
in: path
|
|
12165
|
-
required: true
|
|
12166
|
-
schema:
|
|
12167
|
-
type: string
|
|
12168
|
-
responses:
|
|
12169
|
-
200:
|
|
12170
|
-
description: Success
|
|
12171
|
-
content:
|
|
12172
|
-
application/json:
|
|
12173
|
-
schema:
|
|
12174
|
-
$ref: "#/components/schemas/FunctionListResponse"
|
|
12175
|
-
400:
|
|
12176
|
-
description: Bad request
|
|
12177
|
-
401:
|
|
12178
|
-
description: Unauthorized
|
|
12179
|
-
404:
|
|
12180
|
-
description: Not found
|
|
12181
12153
|
/public/collection/{collectionId}/interactions:
|
|
12182
12154
|
get:
|
|
12183
12155
|
tags:
|
|
@@ -29314,6 +29286,11 @@ components:
|
|
|
29314
29286
|
$ref: "#/components/schemas/FunctionListEntry"
|
|
29315
29287
|
required:
|
|
29316
29288
|
- functions
|
|
29289
|
+
FunctionCallOptions:
|
|
29290
|
+
type: object
|
|
29291
|
+
properties:
|
|
29292
|
+
appId:
|
|
29293
|
+
type: string
|
|
29317
29294
|
AllocateSequenceInput:
|
|
29318
29295
|
type: object
|
|
29319
29296
|
properties:
|
package/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.21 | Generated: 2026-09-25T17:47:14.766Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -166,6 +166,12 @@ Reset the diagnostics counters (does not touch the cache itself).
|
|
|
166
166
|
**isProxyEnabled**() → `boolean`
|
|
167
167
|
Return whether proxy mode is currently enabled.
|
|
168
168
|
|
|
169
|
+
**getAppContext**() → `string | undefined`
|
|
170
|
+
The current app context (appId), if the SDK was initialized with one.
|
|
171
|
+
|
|
172
|
+
**setAppContext**(id: string | undefined) → `void`
|
|
173
|
+
Set (or clear) the current app context — the appId used to scope SL.functions calls.
|
|
174
|
+
|
|
169
175
|
**initializeApi**(options: {
|
|
170
176
|
baseURL: string
|
|
171
177
|
apiKey?: string
|
|
@@ -8960,6 +8966,13 @@ interface FunctionListResponse {
|
|
|
8960
8966
|
}
|
|
8961
8967
|
```
|
|
8962
8968
|
|
|
8969
|
+
**FunctionCallOptions** (interface)
|
|
8970
|
+
```typescript
|
|
8971
|
+
interface FunctionCallOptions {
|
|
8972
|
+
appId?: string
|
|
8973
|
+
}
|
|
8974
|
+
```
|
|
8975
|
+
|
|
8963
8976
|
**FunctionCallResult** = `any`
|
|
8964
8977
|
|
|
8965
8978
|
### sequence (api)
|
|
@@ -10458,16 +10471,18 @@ Delete a form for a collection (admin only).
|
|
|
10458
10471
|
|
|
10459
10472
|
**call**(collectionId: string,
|
|
10460
10473
|
name: string,
|
|
10461
|
-
body: Record<string, any> = {}
|
|
10462
|
-
|
|
10474
|
+
body: Record<string, any> = {},
|
|
10475
|
+
opts: FunctionCallOptions = {}) → `Promise<T>`
|
|
10476
|
+
Call a PUBLIC app server function inline (surface `'public'`). App-scoped: `POST /public/collection/:c/app/:appId/functions/:name`. // App calling its own function (appId from initializeApi({ appId })): const { value } = await SL.functions.call<{ value: number }>(collectionId, 'pressCounter') // Or address another app explicitly: await SL.functions.call(collectionId, 'pressCounter', {}, { appId: 'my-counter-app' })
|
|
10463
10477
|
|
|
10464
10478
|
**callAdmin**(collectionId: string,
|
|
10465
10479
|
name: string,
|
|
10466
|
-
body: Record<string, any> = {}
|
|
10467
|
-
|
|
10480
|
+
body: Record<string, any> = {},
|
|
10481
|
+
opts: FunctionCallOptions = {}) → `Promise<T>`
|
|
10482
|
+
Call an ADMIN app server function (surface `'admin'`; requires an admin session). App-scoped: `POST /admin/collection/:c/app/:appId/functions/:name`.
|
|
10468
10483
|
|
|
10469
|
-
**list**(collectionId: string) → `Promise<FunctionListResponse>`
|
|
10470
|
-
List the public functions available for a collection (discovery). `GET /public/collection/:c/functions`.
|
|
10484
|
+
**list**(collectionId: string, opts: FunctionCallOptions = {}) → `Promise<FunctionListResponse>`
|
|
10485
|
+
List the public functions available for a collection (discovery). Scoped to one app when an appId is given (or set as the SDK app context): `GET /public/collection/:c[/app/:appId]/functions`.
|
|
10471
10486
|
|
|
10472
10487
|
### http
|
|
10473
10488
|
|
package/docs/server-functions.md
CHANGED
|
@@ -181,11 +181,14 @@ interface ServerFunctionContext {
|
|
|
181
181
|
collectionId: string
|
|
182
182
|
appId: string
|
|
183
183
|
|
|
184
|
-
/** SmartLinks SDK, pre-scoped to your declared `authority`. Capabilities cap what it may do.
|
|
184
|
+
/** SmartLinks SDK, pre-scoped to your declared `authority`. Capabilities cap what it may do.
|
|
185
|
+
* Key resources: `sl.appRecords` (per-app records), `sl.appData` (general/app-wide config +
|
|
186
|
+
* data — URLs, flags, counters, arrays), `sl.products`, `sl.attestations`. */
|
|
185
187
|
sl: SmartLinks
|
|
186
188
|
|
|
187
|
-
/** Capability-gated secrets
|
|
188
|
-
|
|
189
|
+
/** Capability-gated secrets (need `secrets:<ref>`). `get(ref)` resolves the collection's OWN
|
|
190
|
+
* secret first, then the app-level one; `app(ref)` reads the app-level secret only. */
|
|
191
|
+
secrets: { get(ref: string): Promise<string | null>; app(ref: string): Promise<string | null> }
|
|
189
192
|
|
|
190
193
|
/** Who invoked this function. */
|
|
191
194
|
caller: {
|
|
@@ -211,6 +214,50 @@ already authenticated as your declared authority and scoped to the collection. D
|
|
|
211
214
|
to construct your own SDK client or carry your own key; that's what `ctx.sl` is for, and it's
|
|
212
215
|
the only way authority stays correct.
|
|
213
216
|
|
|
217
|
+
### Calling a function from your app (client side)
|
|
218
|
+
|
|
219
|
+
From a page/UI, invoke an `http`-trigger function with the SDK — no manual fetch, no URL building:
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
// public function (runs on the caller's authority — signed-in owner, else public):
|
|
223
|
+
const res = await SL.functions.call(collectionId, 'increment', { /* becomes event.body */ })
|
|
224
|
+
// admin surface (needs an admin session):
|
|
225
|
+
const res = await SL.functions.callAdmin(collectionId, 'recomputeTotals', { … })
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
`res` is whatever your handler returns. See the `edge-function-test` example for a full page +
|
|
229
|
+
function + manifest.
|
|
230
|
+
|
|
231
|
+
#### Functions are ALWAYS app-scoped
|
|
232
|
+
|
|
233
|
+
A function belongs to an app, so the canonical route carries the appId:
|
|
234
|
+
`POST /collection/:collectionId/app/:appId/functions/:name`. Two different installed apps can each
|
|
235
|
+
ship a function of the same name without clashing.
|
|
236
|
+
|
|
237
|
+
The SDK fills the appId in for you. Initialize with your app's id once, then call by bare name —
|
|
238
|
+
the SDK routes it app-scoped:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
SL.initializeApi({ baseURL, appId: 'my-counter-app' }) // usually done by the host/bootstrap
|
|
242
|
+
await SL.functions.call(collectionId, 'pressCounter') // → /collection/:c/app/my-counter-app/functions/pressCounter
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
To call a *different* app's function, pass the appId explicitly:
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
await SL.functions.call(collectionId, 'pressCounter', {}, { appId: 'some-other-app' })
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
If no appId is available (not set on init, none passed), the call falls back to the **deprecated
|
|
252
|
+
flat path** `/collection/:c/functions/:name`, which the server resolves by bare name and **rejects
|
|
253
|
+
with `409 AMBIGUOUS_FUNCTION`** when more than one installed app defines that name (a first-party
|
|
254
|
+
builtin still wins). Always prefer an appId.
|
|
255
|
+
|
|
256
|
+
> There is no such thing as an app-less function. First-party builtins (e.g. the `functions.ping`
|
|
257
|
+
> diagnostic) belong to the reserved `smartlinks` app. A "global" function is just an app enabled on
|
|
258
|
+
> the `global` collection and called at `/collection/global/app/:appId/functions/:name` — same two
|
|
259
|
+
> facets (collection + app), with `global` as the sentinel collection.
|
|
260
|
+
|
|
214
261
|
---
|
|
215
262
|
|
|
216
263
|
## Runtime — what your function can use
|
|
@@ -262,6 +309,8 @@ Prefer the platform primitives above over a dependency; when you do need one, pi
|
|
|
262
309
|
| Hash / HMAC-sign / verify / encrypt | `crypto.subtle` (Web Crypto) | — |
|
|
263
310
|
| Random id / bytes | `crypto.randomUUID()` / `crypto.getRandomValues()` | — |
|
|
264
311
|
| Read or write SmartLinks data | `ctx.sl.*` (records, products, attestations, …) | the matching `sl:<res>:<read\|write>` |
|
|
312
|
+
| Read/write general or app-wide data (config, URLs, counters, arrays) | `ctx.sl.appData.get()` / `ctx.sl.appData.set({…})` — pass `{ scope: 'global' }` for app-wide (shared by every install; global writes need collection authority) | `sl:data:read` / `sl:data:write` |
|
|
313
|
+
| Guarantee a UNIQUE claim (pool of numbers, one-per-user, idempotency key) | `ctx.sl.appRecords.create({ ref: 'ball:57' })` — the DB unique index rejects a duplicate `ref` (catch = "already taken") | `sl:records:write` |
|
|
265
314
|
|
|
266
315
|
Notes:
|
|
267
316
|
- **Talking to the SmartLinks core is `ctx.sl`, not HTTP.** The common pattern — *validate /
|
|
@@ -318,14 +367,20 @@ other secrets, or any other collection.
|
|
|
318
367
|
|
|
319
368
|
## Invoking an http function
|
|
320
369
|
|
|
321
|
-
An `http` function is called by POSTing to the
|
|
370
|
+
An `http` function is called by POSTing to the app-scoped functions endpoint on the
|
|
322
371
|
surface that matches its `visibility`:
|
|
323
372
|
|
|
324
373
|
```
|
|
325
|
-
POST /admin/collection/:collectionId/functions/:name # visibility: admin (collection-admin auth)
|
|
326
|
-
POST /public/collection/:collectionId/functions/:name
|
|
374
|
+
POST /admin/collection/:collectionId/app/:appId/functions/:name # visibility: admin (collection-admin auth)
|
|
375
|
+
POST /public/collection/:collectionId/app/:appId/functions/:name # visibility: public (auth optional)
|
|
376
|
+
GET /{admin|public}/collection/:collectionId/app/:appId/functions # list this app's functions on the surface
|
|
327
377
|
```
|
|
328
378
|
|
|
379
|
+
The bare-name form (`/collection/:c/functions/:name`, no `/app/:appId`) is a **deprecated alias**:
|
|
380
|
+
it resolves by name across all installed apps, lets a first-party builtin win, and returns
|
|
381
|
+
`409 AMBIGUOUS_FUNCTION` when two apps define the same name. Prefer the app-scoped route (the SDK
|
|
382
|
+
emits it automatically once an appId is set — see "Calling a function from your app").
|
|
383
|
+
|
|
329
384
|
The request body is delivered to the handler as `event.body` (query string as
|
|
330
385
|
`event.query`). A function only runs on its own surface — calling an `admin` function on
|
|
331
386
|
the public endpoint is a `403`. The response is `{ ok: true, result }` on success, or
|
package/openapi.yaml
CHANGED
|
@@ -72,8 +72,6 @@ tags:
|
|
|
72
72
|
description: Product facet querying and aggregation.
|
|
73
73
|
- name: form
|
|
74
74
|
description: Form definitions and submissions.
|
|
75
|
-
- name: functions
|
|
76
|
-
description: functions API
|
|
77
75
|
- name: integrations
|
|
78
76
|
description: Third-party integration flows and imports.
|
|
79
77
|
- name: interactions
|
|
@@ -12152,32 +12150,6 @@ paths:
|
|
|
12152
12150
|
description: Unauthorized
|
|
12153
12151
|
404:
|
|
12154
12152
|
description: Not found
|
|
12155
|
-
/public/collection/{collectionId}/functions:
|
|
12156
|
-
get:
|
|
12157
|
-
tags:
|
|
12158
|
-
- functions
|
|
12159
|
-
summary: List the public functions available for a collection (discovery).
|
|
12160
|
-
operationId: functions_list
|
|
12161
|
-
security: []
|
|
12162
|
-
parameters:
|
|
12163
|
-
- name: collectionId
|
|
12164
|
-
in: path
|
|
12165
|
-
required: true
|
|
12166
|
-
schema:
|
|
12167
|
-
type: string
|
|
12168
|
-
responses:
|
|
12169
|
-
200:
|
|
12170
|
-
description: Success
|
|
12171
|
-
content:
|
|
12172
|
-
application/json:
|
|
12173
|
-
schema:
|
|
12174
|
-
$ref: "#/components/schemas/FunctionListResponse"
|
|
12175
|
-
400:
|
|
12176
|
-
description: Bad request
|
|
12177
|
-
401:
|
|
12178
|
-
description: Unauthorized
|
|
12179
|
-
404:
|
|
12180
|
-
description: Not found
|
|
12181
12153
|
/public/collection/{collectionId}/interactions:
|
|
12182
12154
|
get:
|
|
12183
12155
|
tags:
|
|
@@ -29314,6 +29286,11 @@ components:
|
|
|
29314
29286
|
$ref: "#/components/schemas/FunctionListEntry"
|
|
29315
29287
|
required:
|
|
29316
29288
|
- functions
|
|
29289
|
+
FunctionCallOptions:
|
|
29290
|
+
type: object
|
|
29291
|
+
properties:
|
|
29292
|
+
appId:
|
|
29293
|
+
type: string
|
|
29317
29294
|
AllocateSequenceInput:
|
|
29318
29295
|
type: object
|
|
29319
29296
|
properties:
|