@proveanything/smartlinks 2.0.21 → 2.0.24
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 +8 -1
- package/dist/api/functions.js +11 -8
- package/dist/context.d.ts +18 -0
- package/dist/context.js +48 -0
- package/dist/docs/API_SUMMARY.md +74 -3
- package/dist/docs/app-manifest.md +34 -0
- package/dist/docs/server-functions.md +51 -16
- package/dist/http.d.ts +8 -0
- package/dist/http.js +33 -0
- package/dist/iframe.d.ts +14 -0
- package/dist/iframe.js +43 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/openapi.yaml +111 -2
- package/dist/testing/index.d.ts +19 -0
- package/dist/testing/index.js +30 -0
- package/dist/types/appManifest.d.ts +127 -2
- package/docs/API_SUMMARY.md +74 -3
- package/docs/app-manifest.md +34 -0
- package/docs/server-functions.md +51 -16
- package/openapi.yaml +111 -2
- package/package.json +1 -1
package/docs/server-functions.md
CHANGED
|
@@ -248,10 +248,21 @@ To call a *different* app's function, pass the appId explicitly:
|
|
|
248
248
|
await SL.functions.call(collectionId, 'pressCounter', {}, { appId: 'some-other-app' })
|
|
249
249
|
```
|
|
250
250
|
|
|
251
|
+
**The app does NOT have to be enabled on the collection.** Because the appId is explicit, the
|
|
252
|
+
function is resolved directly from the app's release — so you can test an app on any collection
|
|
253
|
+
before installing it (and without it showing up in that collection's menus). Enabling an app is
|
|
254
|
+
currently just a UX courtesy (dropdowns/menus), not a gate on running its functions. For a build
|
|
255
|
+
that isn't the default `stable` channel — e.g. a **dev** app you haven't installed — pass the
|
|
256
|
+
channel:
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
await SL.functions.call(collectionId, 'pressCounter', {}, { appId: 'my-counter-app', channel: 'dev' })
|
|
260
|
+
```
|
|
261
|
+
|
|
251
262
|
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
|
|
253
|
-
with `409 AMBIGUOUS_FUNCTION`** when more than one
|
|
254
|
-
builtin still wins). Always prefer an appId.
|
|
263
|
+
flat path** `/collection/:c/functions/:name`, which searches only the collection's **enabled** apps,
|
|
264
|
+
resolves by bare name, and **rejects with `409 AMBIGUOUS_FUNCTION`** when more than one defines that
|
|
265
|
+
name (a first-party builtin still wins). Always prefer an appId.
|
|
255
266
|
|
|
256
267
|
> There is no such thing as an app-less function. First-party builtins (e.g. the `functions.ping`
|
|
257
268
|
> diagnostic) belong to the reserved `smartlinks` app. A "global" function is just an app enabled on
|
|
@@ -309,7 +320,8 @@ Prefer the platform primitives above over a dependency; when you do need one, pi
|
|
|
309
320
|
| Hash / HMAC-sign / verify / encrypt | `crypto.subtle` (Web Crypto) | — |
|
|
310
321
|
| Random id / bytes | `crypto.randomUUID()` / `crypto.getRandomValues()` | — |
|
|
311
322
|
| Read or write SmartLinks data | `ctx.sl.*` (records, products, attestations, …) | the matching `sl:<res>:<read\|write>` |
|
|
312
|
-
| Read/write
|
|
323
|
+
| Read/write your app's own data (config, URLs, counters, arrays) | `ctx.sl.appData.get()` / `ctx.sl.appData.set({…})` — collection-scoped by default; `ctx.sl.appData.global.*` (or `{ scope:'global' }`, or declare `dataScope:'global'`) for the app-wide bucket. It's your OWN namespace, so **any** authority may read/write it | `sl:data:read` / `sl:data:write` |
|
|
324
|
+
| Read ANOTHER app's data (as the caller may see it) | `ctx.sl.app('other-app').data.get()` — caller-authority, this collection, public-filtered, read-only | `sl:data:read` |
|
|
313
325
|
| 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` |
|
|
314
326
|
|
|
315
327
|
Notes:
|
|
@@ -376,18 +388,41 @@ POST /public/collection/:collectionId/app/:appId/functions/:name # visibility:
|
|
|
376
388
|
GET /{admin|public}/collection/:collectionId/app/:appId/functions # list this app's functions on the surface
|
|
377
389
|
```
|
|
378
390
|
|
|
391
|
+
The app-scoped route resolves the app **directly by id**, so the app need not be enabled on the
|
|
392
|
+
collection — handy for testing an un-installed (dev) app. Add `?channel=dev` (default `stable`) to
|
|
393
|
+
pick the release. Enablement (`appConfig.apps[]`) currently only controls menus/discovery, not
|
|
394
|
+
whether a function can run.
|
|
395
|
+
|
|
379
396
|
The bare-name form (`/collection/:c/functions/:name`, no `/app/:appId`) is a **deprecated alias**:
|
|
380
|
-
it
|
|
381
|
-
`409 AMBIGUOUS_FUNCTION` when two apps define the same name. Prefer the
|
|
382
|
-
emits it automatically once an appId is set — see "Calling a function
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
397
|
+
it searches only the collection's **enabled** apps, resolves by name, lets a first-party builtin
|
|
398
|
+
win, and returns `409 AMBIGUOUS_FUNCTION` when two enabled apps define the same name. Prefer the
|
|
399
|
+
app-scoped route (the SDK emits it automatically once an appId is set — see "Calling a function
|
|
400
|
+
from your app").
|
|
401
|
+
|
|
402
|
+
> **Security note (first-party model, today):** because enablement is not an auth gate, any app's
|
|
403
|
+
> function can be invoked on any collection by id. That's fine while all apps are first-party and
|
|
404
|
+
> trusted. When untrusted third-party apps arrive, gate *elevated* (`public` + `collection`)
|
|
405
|
+
> invocation of a **non-enabled** app behind install/consent — the app-scoped resolver is the seam.
|
|
406
|
+
|
|
407
|
+
The handler receives the request as `event`: `event.body` (parsed JSON), `event.query`,
|
|
408
|
+
`event.headers`, `event.rawBody` (raw bytes, for XML/form/other inputs), and `event.contentType`.
|
|
409
|
+
A function only runs on its own surface — calling an `admin` function on the public endpoint is a
|
|
410
|
+
`403`. `GET` on either endpoint lists the functions callable on that surface.
|
|
411
|
+
|
|
412
|
+
**Response contract — your return IS the response (no envelope):**
|
|
413
|
+
- Return a **plain value** → it becomes the JSON body, HTTP `200`. (`SL.functions.call()` gives you
|
|
414
|
+
that value directly — `res.value`, not `res.result.value`.)
|
|
415
|
+
- Return a web-standard **`Response`** → passed through verbatim: your status, headers, content-type
|
|
416
|
+
and body (XML, CSV, text, binary, redirect, custom status). `Response` is a runtime global.
|
|
417
|
+
```js
|
|
418
|
+
return new Response(toXml(data), { status: 200, headers: { "content-type": "application/xml" } })
|
|
419
|
+
```
|
|
420
|
+
- **Throw** → HTTP `500` `{ error: "FUNCTION_ERROR", message, code }`. For *expected* errors (400/404/
|
|
421
|
+
409…), return a `Response` with your own status + body.
|
|
422
|
+
|
|
423
|
+
One rule: **plain object ⇒ 200; want any other status/headers/content-type ⇒ return a `Response`.**
|
|
424
|
+
Timing comes back in an `X-SL-Function-Duration-Ms` header (admin surface); your `ctx.log` lines land
|
|
425
|
+
in the collection's Errors & Activity feed — the body stays purely your output.
|
|
391
426
|
|
|
392
427
|
The admin surface is collection-admin gated, so an admin function's `caller` authority runs
|
|
393
428
|
at admin level, attributed to the signed-in admin. The public surface resolves auth if a
|
|
@@ -412,7 +447,7 @@ So the end-to-end path is: *write → register the release → enable on a colle
|
|
|
412
447
|
Every invocation is recorded as an **execution** activity event, carrying your `ctx.log`
|
|
413
448
|
lines. Where to look, easiest first:
|
|
414
449
|
|
|
415
|
-
- **Admin-surface response** —
|
|
450
|
+
- **Admin-surface response** — timing comes back in the `X-SL-Function-Duration-Ms` header (logs are in Errors & Activity, not the body).
|
|
416
451
|
- **Deployed test mode** — see below; real run, isolated logging.
|
|
417
452
|
- **Owner console** — the collection's **Advanced → Errors & Activity → events** tab,
|
|
418
453
|
filtered to **source = execution**: each run shows as `function <name> ok` (or an error),
|
package/openapi.yaml
CHANGED
|
@@ -18255,6 +18255,11 @@ components:
|
|
|
18255
18255
|
type: array
|
|
18256
18256
|
items:
|
|
18257
18257
|
type: string
|
|
18258
|
+
dataScope:
|
|
18259
|
+
type: string
|
|
18260
|
+
enum:
|
|
18261
|
+
- collection
|
|
18262
|
+
- global
|
|
18258
18263
|
apiVersion:
|
|
18259
18264
|
type: string
|
|
18260
18265
|
handler:
|
|
@@ -18274,6 +18279,41 @@ components:
|
|
|
18274
18279
|
required:
|
|
18275
18280
|
- files
|
|
18276
18281
|
- definitions
|
|
18282
|
+
AppDataOpts:
|
|
18283
|
+
type: object
|
|
18284
|
+
properties:
|
|
18285
|
+
scope:
|
|
18286
|
+
type: string
|
|
18287
|
+
enum:
|
|
18288
|
+
- collection
|
|
18289
|
+
- global
|
|
18290
|
+
productId:
|
|
18291
|
+
type: string
|
|
18292
|
+
variantId:
|
|
18293
|
+
type: string
|
|
18294
|
+
batchId:
|
|
18295
|
+
type: string
|
|
18296
|
+
dataId:
|
|
18297
|
+
type: string
|
|
18298
|
+
queries:
|
|
18299
|
+
type: object
|
|
18300
|
+
additionalProperties: true
|
|
18301
|
+
AppDataHandle:
|
|
18302
|
+
type: object
|
|
18303
|
+
properties: {}
|
|
18304
|
+
ServerFunctionSl:
|
|
18305
|
+
type: object
|
|
18306
|
+
properties:
|
|
18307
|
+
appRecords: {}
|
|
18308
|
+
products: {}
|
|
18309
|
+
attestations: {}
|
|
18310
|
+
appData:
|
|
18311
|
+
$ref: "#/components/schemas/AppDataHandle"
|
|
18312
|
+
required:
|
|
18313
|
+
- appRecords
|
|
18314
|
+
- products
|
|
18315
|
+
- attestations
|
|
18316
|
+
- appData
|
|
18277
18317
|
ServerFunctionCaller:
|
|
18278
18318
|
type: object
|
|
18279
18319
|
properties:
|
|
@@ -18298,7 +18338,8 @@ components:
|
|
|
18298
18338
|
type: string
|
|
18299
18339
|
appId:
|
|
18300
18340
|
type: string
|
|
18301
|
-
sl:
|
|
18341
|
+
sl:
|
|
18342
|
+
$ref: "#/components/schemas/ServerFunctionSl"
|
|
18302
18343
|
secrets:
|
|
18303
18344
|
type: object
|
|
18304
18345
|
additionalProperties: true
|
|
@@ -18314,6 +18355,30 @@ components:
|
|
|
18314
18355
|
- secrets
|
|
18315
18356
|
- caller
|
|
18316
18357
|
- fetch
|
|
18358
|
+
ServerFunctionHttpEvent:
|
|
18359
|
+
type: object
|
|
18360
|
+
properties:
|
|
18361
|
+
method:
|
|
18362
|
+
type: string
|
|
18363
|
+
body:
|
|
18364
|
+
type: object
|
|
18365
|
+
additionalProperties: true
|
|
18366
|
+
query:
|
|
18367
|
+
type: object
|
|
18368
|
+
additionalProperties: true
|
|
18369
|
+
headers:
|
|
18370
|
+
type: object
|
|
18371
|
+
additionalProperties: true
|
|
18372
|
+
rawBody:
|
|
18373
|
+
type: object
|
|
18374
|
+
additionalProperties: true
|
|
18375
|
+
contentType:
|
|
18376
|
+
type: string
|
|
18377
|
+
required:
|
|
18378
|
+
- method
|
|
18379
|
+
- body
|
|
18380
|
+
- query
|
|
18381
|
+
- headers
|
|
18317
18382
|
AppAdminConfig:
|
|
18318
18383
|
type: object
|
|
18319
18384
|
properties:
|
|
@@ -18397,6 +18462,40 @@ components:
|
|
|
18397
18462
|
- scope
|
|
18398
18463
|
- name
|
|
18399
18464
|
- type
|
|
18465
|
+
PublicViewParams:
|
|
18466
|
+
type: object
|
|
18467
|
+
properties:
|
|
18468
|
+
required:
|
|
18469
|
+
type: array
|
|
18470
|
+
items:
|
|
18471
|
+
type: string
|
|
18472
|
+
optional:
|
|
18473
|
+
type: array
|
|
18474
|
+
items:
|
|
18475
|
+
type: string
|
|
18476
|
+
PublicView:
|
|
18477
|
+
type: object
|
|
18478
|
+
properties:
|
|
18479
|
+
id:
|
|
18480
|
+
type: string
|
|
18481
|
+
title:
|
|
18482
|
+
type: string
|
|
18483
|
+
kind:
|
|
18484
|
+
$ref: "#/components/schemas/PublicViewKind"
|
|
18485
|
+
route:
|
|
18486
|
+
type: string
|
|
18487
|
+
set:
|
|
18488
|
+
type: object
|
|
18489
|
+
additionalProperties:
|
|
18490
|
+
type: string
|
|
18491
|
+
params:
|
|
18492
|
+
$ref: "#/components/schemas/PublicViewParams"
|
|
18493
|
+
default:
|
|
18494
|
+
type: boolean
|
|
18495
|
+
required:
|
|
18496
|
+
- id
|
|
18497
|
+
- title
|
|
18498
|
+
- kind
|
|
18400
18499
|
AppManifest:
|
|
18401
18500
|
type: object
|
|
18402
18501
|
properties:
|
|
@@ -18472,6 +18571,10 @@ components:
|
|
|
18472
18571
|
type: array
|
|
18473
18572
|
items:
|
|
18474
18573
|
$ref: "#/components/schemas/DeepLinkEntry"
|
|
18574
|
+
publicViews:
|
|
18575
|
+
type: array
|
|
18576
|
+
items:
|
|
18577
|
+
$ref: "#/components/schemas/PublicView"
|
|
18475
18578
|
executor:
|
|
18476
18579
|
$ref: "#/components/schemas/AppManifestExecutor"
|
|
18477
18580
|
functions:
|
|
@@ -18532,6 +18635,11 @@ components:
|
|
|
18532
18635
|
enum:
|
|
18533
18636
|
- caller
|
|
18534
18637
|
- collection
|
|
18638
|
+
PublicViewKind:
|
|
18639
|
+
type: string
|
|
18640
|
+
enum:
|
|
18641
|
+
- contextual
|
|
18642
|
+
- standalone
|
|
18535
18643
|
PaginatedResponse:
|
|
18536
18644
|
type: object
|
|
18537
18645
|
properties:
|
|
@@ -29290,7 +29398,8 @@ components:
|
|
|
29290
29398
|
type: object
|
|
29291
29399
|
properties:
|
|
29292
29400
|
appId:
|
|
29293
|
-
type:
|
|
29401
|
+
type: object
|
|
29402
|
+
additionalProperties: true
|
|
29294
29403
|
AllocateSequenceInput:
|
|
29295
29404
|
type: object
|
|
29296
29405
|
properties:
|