@proveanything/smartlinks 2.0.19 → 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 +37 -0
- package/dist/api/functions.js +63 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -0
- package/dist/docs/API_SUMMARY.md +50 -1
- 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 +22 -0
- package/docs/API_SUMMARY.md +50 -1
- package/docs/server-functions.md +61 -6
- package/openapi.yaml +22 -0
- package/package.json +1 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** A server function's returned value — shape is app-defined, so untyped by default. */
|
|
2
|
+
export type FunctionCallResult = any;
|
|
3
|
+
export interface FunctionListEntry {
|
|
4
|
+
name: string;
|
|
5
|
+
visibility?: string;
|
|
6
|
+
trigger?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface FunctionListResponse {
|
|
9
|
+
functions: FunctionListEntry[];
|
|
10
|
+
}
|
|
11
|
+
/** Options for a function call. `appId` scopes resolution to one app (recommended). */
|
|
12
|
+
export interface FunctionCallOptions {
|
|
13
|
+
appId?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare namespace functions {
|
|
16
|
+
/**
|
|
17
|
+
* Call a PUBLIC app server function inline (surface `'public'`).
|
|
18
|
+
* App-scoped: `POST /public/collection/:c/app/:appId/functions/:name`.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
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' })
|
|
25
|
+
*/
|
|
26
|
+
function call<T = FunctionCallResult>(collectionId: string, name: string, body?: Record<string, any>, opts?: FunctionCallOptions): Promise<T>;
|
|
27
|
+
/**
|
|
28
|
+
* Call an ADMIN app server function (surface `'admin'`; requires an admin session).
|
|
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`.
|
|
35
|
+
*/
|
|
36
|
+
function list(collectionId: string, opts?: FunctionCallOptions): Promise<FunctionListResponse>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Client-side invocation of app SERVER FUNCTIONS.
|
|
2
|
+
//
|
|
3
|
+
// The function itself is authored server-side (one contract: `async (ctx, event) => result`,
|
|
4
|
+
// see docs/server-functions.md). THIS is how a page/UI actually calls one — the missing
|
|
5
|
+
// client half. The PUBLIC route runs a function inline on the caller's own authority (owner if
|
|
6
|
+
// signed in via authKit, else public); the ADMIN route runs on the admin surface (needs an admin
|
|
7
|
+
// session). The returned value is the function's own result (`event.body` is what you pass here).
|
|
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
|
+
}
|
|
25
|
+
export var functions;
|
|
26
|
+
(function (functions) {
|
|
27
|
+
/**
|
|
28
|
+
* Call a PUBLIC app server function inline (surface `'public'`).
|
|
29
|
+
* App-scoped: `POST /public/collection/:c/app/:appId/functions/:name`.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
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' })
|
|
36
|
+
*/
|
|
37
|
+
async function call(collectionId, name, body = {}, opts = {}) {
|
|
38
|
+
return post(fnPath('public', collectionId, name, opts.appId), body);
|
|
39
|
+
}
|
|
40
|
+
functions.call = call;
|
|
41
|
+
/**
|
|
42
|
+
* Call an ADMIN app server function (surface `'admin'`; requires an admin session).
|
|
43
|
+
* App-scoped: `POST /admin/collection/:c/app/:appId/functions/:name`.
|
|
44
|
+
*/
|
|
45
|
+
async function callAdmin(collectionId, name, body = {}, opts = {}) {
|
|
46
|
+
return post(fnPath('admin', collectionId, name, opts.appId), body);
|
|
47
|
+
}
|
|
48
|
+
functions.callAdmin = callAdmin;
|
|
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`;
|
|
60
|
+
return request(path);
|
|
61
|
+
}
|
|
62
|
+
functions.list = list;
|
|
63
|
+
})(functions || (functions = {}));
|
package/dist/api/index.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export { qr } from "./qr.js";
|
|
|
28
28
|
export { template } from "./template.js";
|
|
29
29
|
export { interactions } from "./interactions.js";
|
|
30
30
|
export { analytics } from "./analytics.js";
|
|
31
|
+
export { functions } from "./functions.js";
|
|
31
32
|
export { location } from "./location.js";
|
|
32
33
|
export * as realtime from "./realtime.js";
|
|
33
34
|
export { tags } from "./tags.js";
|
package/dist/api/index.js
CHANGED
|
@@ -30,6 +30,7 @@ export { qr } from "./qr.js";
|
|
|
30
30
|
export { template } from "./template.js";
|
|
31
31
|
export { interactions } from "./interactions.js";
|
|
32
32
|
export { analytics } from "./analytics.js";
|
|
33
|
+
export { functions } from "./functions.js";
|
|
33
34
|
export { location } from "./location.js";
|
|
34
35
|
import * as realtime_1 from "./realtime.js";
|
|
35
36
|
export { realtime_1 as realtime };
|
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
|
|
|
@@ -135,6 +135,7 @@ The Smartlinks SDK is organized into the following namespaces:
|
|
|
135
135
|
- **config** - Functions for config operations
|
|
136
136
|
- **containers** - Functions for containers operations
|
|
137
137
|
- **facets** - Functions for facets operations
|
|
138
|
+
- **functions** - Functions for functions operations
|
|
138
139
|
- **http** - Functions for http operations
|
|
139
140
|
- **integrations** - Functions for integrations operations
|
|
140
141
|
- **jobs** - Functions for jobs operations
|
|
@@ -165,6 +166,12 @@ Reset the diagnostics counters (does not touch the cache itself).
|
|
|
165
166
|
**isProxyEnabled**() → `boolean`
|
|
166
167
|
Return whether proxy mode is currently enabled.
|
|
167
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
|
+
|
|
168
175
|
**initializeApi**(options: {
|
|
169
176
|
baseURL: string
|
|
170
177
|
apiKey?: string
|
|
@@ -8943,6 +8950,31 @@ type VerifyTokenResponse = {
|
|
|
8943
8950
|
}
|
|
8944
8951
|
```
|
|
8945
8952
|
|
|
8953
|
+
### functions (api)
|
|
8954
|
+
|
|
8955
|
+
**FunctionListEntry** (interface)
|
|
8956
|
+
```typescript
|
|
8957
|
+
interface FunctionListEntry {
|
|
8958
|
+
name: string; visibility?: string; trigger?: string
|
|
8959
|
+
}
|
|
8960
|
+
```
|
|
8961
|
+
|
|
8962
|
+
**FunctionListResponse** (interface)
|
|
8963
|
+
```typescript
|
|
8964
|
+
interface FunctionListResponse {
|
|
8965
|
+
functions: FunctionListEntry[]
|
|
8966
|
+
}
|
|
8967
|
+
```
|
|
8968
|
+
|
|
8969
|
+
**FunctionCallOptions** (interface)
|
|
8970
|
+
```typescript
|
|
8971
|
+
interface FunctionCallOptions {
|
|
8972
|
+
appId?: string
|
|
8973
|
+
}
|
|
8974
|
+
```
|
|
8975
|
+
|
|
8976
|
+
**FunctionCallResult** = `any`
|
|
8977
|
+
|
|
8946
8978
|
### sequence (api)
|
|
8947
8979
|
|
|
8948
8980
|
**AllocateSequenceInput** (interface)
|
|
@@ -10435,6 +10467,23 @@ Update a form for a collection (admin only).
|
|
|
10435
10467
|
**remove**(collectionId: string, formId: string) → `Promise<void>`
|
|
10436
10468
|
Delete a form for a collection (admin only).
|
|
10437
10469
|
|
|
10470
|
+
### functions
|
|
10471
|
+
|
|
10472
|
+
**call**(collectionId: string,
|
|
10473
|
+
name: string,
|
|
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' })
|
|
10477
|
+
|
|
10478
|
+
**callAdmin**(collectionId: string,
|
|
10479
|
+
name: string,
|
|
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`.
|
|
10483
|
+
|
|
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`.
|
|
10486
|
+
|
|
10438
10487
|
### http
|
|
10439
10488
|
|
|
10440
10489
|
**get**(path: string) → `Promise<T>`
|
|
@@ -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
|
@@ -29269,6 +29269,28 @@ components:
|
|
|
29269
29269
|
additionalProperties: true
|
|
29270
29270
|
required:
|
|
29271
29271
|
- valid
|
|
29272
|
+
FunctionListEntry:
|
|
29273
|
+
type: object
|
|
29274
|
+
properties:
|
|
29275
|
+
name:
|
|
29276
|
+
type: object
|
|
29277
|
+
additionalProperties: true
|
|
29278
|
+
required:
|
|
29279
|
+
- name
|
|
29280
|
+
FunctionListResponse:
|
|
29281
|
+
type: object
|
|
29282
|
+
properties:
|
|
29283
|
+
functions:
|
|
29284
|
+
type: array
|
|
29285
|
+
items:
|
|
29286
|
+
$ref: "#/components/schemas/FunctionListEntry"
|
|
29287
|
+
required:
|
|
29288
|
+
- functions
|
|
29289
|
+
FunctionCallOptions:
|
|
29290
|
+
type: object
|
|
29291
|
+
properties:
|
|
29292
|
+
appId:
|
|
29293
|
+
type: string
|
|
29272
29294
|
AllocateSequenceInput:
|
|
29273
29295
|
type: object
|
|
29274
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
|
|
|
@@ -135,6 +135,7 @@ The Smartlinks SDK is organized into the following namespaces:
|
|
|
135
135
|
- **config** - Functions for config operations
|
|
136
136
|
- **containers** - Functions for containers operations
|
|
137
137
|
- **facets** - Functions for facets operations
|
|
138
|
+
- **functions** - Functions for functions operations
|
|
138
139
|
- **http** - Functions for http operations
|
|
139
140
|
- **integrations** - Functions for integrations operations
|
|
140
141
|
- **jobs** - Functions for jobs operations
|
|
@@ -165,6 +166,12 @@ Reset the diagnostics counters (does not touch the cache itself).
|
|
|
165
166
|
**isProxyEnabled**() → `boolean`
|
|
166
167
|
Return whether proxy mode is currently enabled.
|
|
167
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
|
+
|
|
168
175
|
**initializeApi**(options: {
|
|
169
176
|
baseURL: string
|
|
170
177
|
apiKey?: string
|
|
@@ -8943,6 +8950,31 @@ type VerifyTokenResponse = {
|
|
|
8943
8950
|
}
|
|
8944
8951
|
```
|
|
8945
8952
|
|
|
8953
|
+
### functions (api)
|
|
8954
|
+
|
|
8955
|
+
**FunctionListEntry** (interface)
|
|
8956
|
+
```typescript
|
|
8957
|
+
interface FunctionListEntry {
|
|
8958
|
+
name: string; visibility?: string; trigger?: string
|
|
8959
|
+
}
|
|
8960
|
+
```
|
|
8961
|
+
|
|
8962
|
+
**FunctionListResponse** (interface)
|
|
8963
|
+
```typescript
|
|
8964
|
+
interface FunctionListResponse {
|
|
8965
|
+
functions: FunctionListEntry[]
|
|
8966
|
+
}
|
|
8967
|
+
```
|
|
8968
|
+
|
|
8969
|
+
**FunctionCallOptions** (interface)
|
|
8970
|
+
```typescript
|
|
8971
|
+
interface FunctionCallOptions {
|
|
8972
|
+
appId?: string
|
|
8973
|
+
}
|
|
8974
|
+
```
|
|
8975
|
+
|
|
8976
|
+
**FunctionCallResult** = `any`
|
|
8977
|
+
|
|
8946
8978
|
### sequence (api)
|
|
8947
8979
|
|
|
8948
8980
|
**AllocateSequenceInput** (interface)
|
|
@@ -10435,6 +10467,23 @@ Update a form for a collection (admin only).
|
|
|
10435
10467
|
**remove**(collectionId: string, formId: string) → `Promise<void>`
|
|
10436
10468
|
Delete a form for a collection (admin only).
|
|
10437
10469
|
|
|
10470
|
+
### functions
|
|
10471
|
+
|
|
10472
|
+
**call**(collectionId: string,
|
|
10473
|
+
name: string,
|
|
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' })
|
|
10477
|
+
|
|
10478
|
+
**callAdmin**(collectionId: string,
|
|
10479
|
+
name: string,
|
|
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`.
|
|
10483
|
+
|
|
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`.
|
|
10486
|
+
|
|
10438
10487
|
### http
|
|
10439
10488
|
|
|
10440
10489
|
**get**(path: string) → `Promise<T>`
|
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
|
@@ -29269,6 +29269,28 @@ components:
|
|
|
29269
29269
|
additionalProperties: true
|
|
29270
29270
|
required:
|
|
29271
29271
|
- valid
|
|
29272
|
+
FunctionListEntry:
|
|
29273
|
+
type: object
|
|
29274
|
+
properties:
|
|
29275
|
+
name:
|
|
29276
|
+
type: object
|
|
29277
|
+
additionalProperties: true
|
|
29278
|
+
required:
|
|
29279
|
+
- name
|
|
29280
|
+
FunctionListResponse:
|
|
29281
|
+
type: object
|
|
29282
|
+
properties:
|
|
29283
|
+
functions:
|
|
29284
|
+
type: array
|
|
29285
|
+
items:
|
|
29286
|
+
$ref: "#/components/schemas/FunctionListEntry"
|
|
29287
|
+
required:
|
|
29288
|
+
- functions
|
|
29289
|
+
FunctionCallOptions:
|
|
29290
|
+
type: object
|
|
29291
|
+
properties:
|
|
29292
|
+
appId:
|
|
29293
|
+
type: string
|
|
29272
29294
|
AllocateSequenceInput:
|
|
29273
29295
|
type: object
|
|
29274
29296
|
properties:
|