@proveanything/smartlinks 2.0.35 → 2.0.36
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/collection.d.ts +4 -4
- package/dist/api/collection.js +4 -4
- package/dist/api/functions.d.ts +30 -0
- package/dist/api/functions.js +28 -0
- package/dist/docs/API_SUMMARY.md +20 -4
- package/dist/docs/server-functions.md +43 -4
- package/dist/openapi.yaml +15 -0
- package/dist/types/collection.d.ts +9 -2
- package/dist/utils/paths.js +1 -1
- package/docs/API_SUMMARY.md +20 -4
- package/docs/server-functions.md +43 -4
- package/openapi.yaml +15 -0
- package/package.json +1 -1
package/dist/api/collection.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export declare namespace collection {
|
|
|
27
27
|
* The server derives the requesting domain from the request headers
|
|
28
28
|
* (`X-Source-Domain` / `X-Forwarded-Host` / `Host`), so no identifier is
|
|
29
29
|
* passed — this is the call a Hub frontend makes on load to find out which
|
|
30
|
-
* collection it is serving, whether it's reached via `{brand}.
|
|
30
|
+
* collection it is serving, whether it's reached via `{brand}.smartlinks.host`
|
|
31
31
|
* or a bring-your-own custom domain (e.g. `hub.acme.com`).
|
|
32
32
|
*
|
|
33
33
|
* @returns Promise resolving to the CollectionResponse mapped to the domain
|
|
@@ -39,9 +39,9 @@ export declare namespace collection {
|
|
|
39
39
|
*
|
|
40
40
|
* Unlike {@link getByHub}, the domain is passed explicitly rather than derived
|
|
41
41
|
* from request headers — use this for raw/cross-origin calls where the Hub
|
|
42
|
-
* frontend knows its own hostname (e.g. "erbauer.
|
|
42
|
+
* frontend knows its own hostname (e.g. "erbauer.smartlinks.host").
|
|
43
43
|
*
|
|
44
|
-
* @param domain – The Hub domain to resolve (custom domain or {brand}.
|
|
44
|
+
* @param domain – The Hub domain to resolve (custom domain or {brand}.smartlinks.host)
|
|
45
45
|
* @returns Promise resolving to the CollectionResponse mapped to the domain
|
|
46
46
|
* @throws ErrorResponse (404) if no collection is mapped to the domain
|
|
47
47
|
*/
|
|
@@ -57,7 +57,7 @@ export declare namespace collection {
|
|
|
57
57
|
/**
|
|
58
58
|
* Claim or rename the Hub subdomain for a collection (admin only).
|
|
59
59
|
*
|
|
60
|
-
* Maps `{hubName}.
|
|
60
|
+
* Maps `{hubName}.smartlinks.host` to the collection. If the collection
|
|
61
61
|
* already had a different hub name, the previous subdomain is released
|
|
62
62
|
* automatically.
|
|
63
63
|
*
|
package/dist/api/collection.js
CHANGED
|
@@ -43,7 +43,7 @@ export var collection;
|
|
|
43
43
|
* The server derives the requesting domain from the request headers
|
|
44
44
|
* (`X-Source-Domain` / `X-Forwarded-Host` / `Host`), so no identifier is
|
|
45
45
|
* passed — this is the call a Hub frontend makes on load to find out which
|
|
46
|
-
* collection it is serving, whether it's reached via `{brand}.
|
|
46
|
+
* collection it is serving, whether it's reached via `{brand}.smartlinks.host`
|
|
47
47
|
* or a bring-your-own custom domain (e.g. `hub.acme.com`).
|
|
48
48
|
*
|
|
49
49
|
* @returns Promise resolving to the CollectionResponse mapped to the domain
|
|
@@ -59,9 +59,9 @@ export var collection;
|
|
|
59
59
|
*
|
|
60
60
|
* Unlike {@link getByHub}, the domain is passed explicitly rather than derived
|
|
61
61
|
* from request headers — use this for raw/cross-origin calls where the Hub
|
|
62
|
-
* frontend knows its own hostname (e.g. "erbauer.
|
|
62
|
+
* frontend knows its own hostname (e.g. "erbauer.smartlinks.host").
|
|
63
63
|
*
|
|
64
|
-
* @param domain – The Hub domain to resolve (custom domain or {brand}.
|
|
64
|
+
* @param domain – The Hub domain to resolve (custom domain or {brand}.smartlinks.host)
|
|
65
65
|
* @returns Promise resolving to the CollectionResponse mapped to the domain
|
|
66
66
|
* @throws ErrorResponse (404) if no collection is mapped to the domain
|
|
67
67
|
*/
|
|
@@ -86,7 +86,7 @@ export var collection;
|
|
|
86
86
|
/**
|
|
87
87
|
* Claim or rename the Hub subdomain for a collection (admin only).
|
|
88
88
|
*
|
|
89
|
-
* Maps `{hubName}.
|
|
89
|
+
* Maps `{hubName}.smartlinks.host` to the collection. If the collection
|
|
90
90
|
* already had a different hub name, the previous subdomain is released
|
|
91
91
|
* automatically.
|
|
92
92
|
*
|
package/dist/api/functions.d.ts
CHANGED
|
@@ -29,7 +29,37 @@ export interface FunctionCallOptions {
|
|
|
29
29
|
export declare function resolveFunctionChannel(opts?: FunctionCallOptions, appId?: string): string | undefined;
|
|
30
30
|
/** The API path a function call goes to (exported for hosts/tests that need the exact URL). */
|
|
31
31
|
export declare function functionPath(surface: 'public' | 'admin', collectionId: string, name: string, opts?: FunctionCallOptions): string;
|
|
32
|
+
/** Options for {@link functions.siteUrl}. */
|
|
33
|
+
export interface FunctionSiteUrlOptions {
|
|
34
|
+
/** Release channel ('dev' | 'alpha' | 'beta' | 'stable'); omit for the collection's installed release. */
|
|
35
|
+
channel?: string;
|
|
36
|
+
/** Sub-path after the function name, e.g. "/orders/123" (the function must declare trigger.path). */
|
|
37
|
+
path?: string;
|
|
38
|
+
/** Query parameters to append. */
|
|
39
|
+
query?: Record<string, string>;
|
|
40
|
+
/** Use this host instead of the collection's siteHost (e.g. its connected custom domain). */
|
|
41
|
+
host?: string;
|
|
42
|
+
}
|
|
32
43
|
export declare namespace functions {
|
|
44
|
+
/**
|
|
45
|
+
* The PUBLIC address of an app function on the collection's own site — what you give a third party
|
|
46
|
+
* as a webhook URL, or call from the collection's public pages:
|
|
47
|
+
* `https://<siteHost>/_fn/<appId>[/<channel>]/<name>[/<path>]`.
|
|
48
|
+
* Every HTTP method the function declares works there, with the raw body for signature checks.
|
|
49
|
+
* Pass the collection (or its siteHost). This address is for public/integration calls; signed-in
|
|
50
|
+
* calls from your app keep using {@link call} / {@link callAdmin}, so the user's SmartLinks session
|
|
51
|
+
* never goes to a tenant hostname.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const col = await SL.collection.get(collectionId)
|
|
55
|
+
* const hookUrl = SL.functions.siteUrl(col, 'stripeWebhook', { appId: 'my-shop' })
|
|
56
|
+
* // → https://acme.smartlinks.host/_fn/my-shop/stripeWebhook
|
|
57
|
+
*/
|
|
58
|
+
function siteUrl(collection: {
|
|
59
|
+
siteHost?: string | null;
|
|
60
|
+
} | string, name: string, opts?: FunctionSiteUrlOptions & {
|
|
61
|
+
appId?: string;
|
|
62
|
+
}): string;
|
|
33
63
|
/**
|
|
34
64
|
* Call a PUBLIC app server function inline (surface `'public'`).
|
|
35
65
|
* App-scoped: `POST /public/collection/:c/app/:appId/functions/:name`.
|
package/dist/api/functions.js
CHANGED
|
@@ -64,6 +64,34 @@ export function functionPath(surface, collectionId, name, opts = {}) {
|
|
|
64
64
|
const fnPath = functionPath;
|
|
65
65
|
export var functions;
|
|
66
66
|
(function (functions) {
|
|
67
|
+
/**
|
|
68
|
+
* The PUBLIC address of an app function on the collection's own site — what you give a third party
|
|
69
|
+
* as a webhook URL, or call from the collection's public pages:
|
|
70
|
+
* `https://<siteHost>/_fn/<appId>[/<channel>]/<name>[/<path>]`.
|
|
71
|
+
* Every HTTP method the function declares works there, with the raw body for signature checks.
|
|
72
|
+
* Pass the collection (or its siteHost). This address is for public/integration calls; signed-in
|
|
73
|
+
* calls from your app keep using {@link call} / {@link callAdmin}, so the user's SmartLinks session
|
|
74
|
+
* never goes to a tenant hostname.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* const col = await SL.collection.get(collectionId)
|
|
78
|
+
* const hookUrl = SL.functions.siteUrl(col, 'stripeWebhook', { appId: 'my-shop' })
|
|
79
|
+
* // → https://acme.smartlinks.host/_fn/my-shop/stripeWebhook
|
|
80
|
+
*/
|
|
81
|
+
function siteUrl(collection, name, opts = {}) {
|
|
82
|
+
var _a, _b;
|
|
83
|
+
const host = opts.host || (typeof collection === 'string' ? collection : collection && collection.siteHost);
|
|
84
|
+
if (!host)
|
|
85
|
+
throw new Error('functions.siteUrl: the collection has no siteHost (fetch it with SL.collection.get)');
|
|
86
|
+
const app = (_a = opts.appId) !== null && _a !== void 0 ? _a : getAppContext();
|
|
87
|
+
if (!app)
|
|
88
|
+
throw new Error('functions.siteUrl: appId required (pass it, or initializeApi({ appId }))');
|
|
89
|
+
const ch = resolveFunctionChannel({ channel: (_b = opts.channel) !== null && _b !== void 0 ? _b : null }, app);
|
|
90
|
+
const sub = opts.path ? '/' + String(opts.path).replace(/^\/+/, '') : '';
|
|
91
|
+
const qs = opts.query && Object.keys(opts.query).length ? '?' + new URLSearchParams(opts.query).toString() : '';
|
|
92
|
+
return `https://${String(host).replace(/^https?:\/\//, '').replace(/\/+$/, '')}/_fn/${encodeURIComponent(app)}${ch ? `/${ch}` : ''}/${encodeURIComponent(name)}${sub}${qs}`;
|
|
93
|
+
}
|
|
94
|
+
functions.siteUrl = siteUrl;
|
|
67
95
|
/**
|
|
68
96
|
* Call a PUBLIC app server function inline (surface `'public'`).
|
|
69
97
|
* App-scoped: `POST /public/collection/:c/app/:appId/functions/:name`.
|
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.36 | Generated: 2026-10-03T15:04:37.396Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -4839,6 +4839,7 @@ interface Collection {
|
|
|
4839
4839
|
redirectUrl?: string // Whether the collection has a custom domain
|
|
4840
4840
|
hubName?: string
|
|
4841
4841
|
hubCustomDomain?: string
|
|
4842
|
+
siteHost?: string | null
|
|
4842
4843
|
shortId: string, // The shortId of this collection
|
|
4843
4844
|
dark?: boolean // if dark mode is enabled for this collection
|
|
4844
4845
|
primaryColor?: string
|
|
@@ -9594,6 +9595,16 @@ interface FunctionCallOptions {
|
|
|
9594
9595
|
}
|
|
9595
9596
|
```
|
|
9596
9597
|
|
|
9598
|
+
**FunctionSiteUrlOptions** (interface)
|
|
9599
|
+
```typescript
|
|
9600
|
+
interface FunctionSiteUrlOptions {
|
|
9601
|
+
channel?: string
|
|
9602
|
+
path?: string
|
|
9603
|
+
query?: Record<string, string>
|
|
9604
|
+
host?: string
|
|
9605
|
+
}
|
|
9606
|
+
```
|
|
9607
|
+
|
|
9597
9608
|
**FunctionCallResult** = `any`
|
|
9598
9609
|
|
|
9599
9610
|
### sequence (api)
|
|
@@ -10722,16 +10733,16 @@ Retrieves all Collections.
|
|
|
10722
10733
|
Retrieve a collection by its shortId (public endpoint).
|
|
10723
10734
|
|
|
10724
10735
|
**getByHub**() → `Promise<CollectionResponse>`
|
|
10725
|
-
Resolve the collection for the current Hub domain (public endpoint). The server derives the requesting domain from the request headers (`X-Source-Domain` / `X-Forwarded-Host` / `Host`), so no identifier is passed — this is the call a Hub frontend makes on load to find out which collection it is serving, whether it's reached via `{brand}.
|
|
10736
|
+
Resolve the collection for the current Hub domain (public endpoint). The server derives the requesting domain from the request headers (`X-Source-Domain` / `X-Forwarded-Host` / `Host`), so no identifier is passed — this is the call a Hub frontend makes on load to find out which collection it is serving, whether it's reached via `{brand}.smartlinks.host` or a bring-your-own custom domain (e.g. `hub.acme.com`).
|
|
10726
10737
|
|
|
10727
10738
|
**getByDomain**(domain: string) → `Promise<CollectionResponse>`
|
|
10728
|
-
Resolve the collection for an explicit Hub domain (public endpoint). Unlike {@link getByHub}, the domain is passed explicitly rather than derived from request headers — use this for raw/cross-origin calls where the Hub frontend knows its own hostname (e.g. "erbauer.
|
|
10739
|
+
Resolve the collection for an explicit Hub domain (public endpoint). Unlike {@link getByHub}, the domain is passed explicitly rather than derived from request headers — use this for raw/cross-origin calls where the Hub frontend knows its own hostname (e.g. "erbauer.smartlinks.host").
|
|
10729
10740
|
|
|
10730
10741
|
**checkHubAvailability**(collectionId: string, name: string) → `Promise<HubAvailabilityResponse>`
|
|
10731
10742
|
Check whether a Hub subdomain name is available to claim (admin only).
|
|
10732
10743
|
|
|
10733
10744
|
**claimHub**(collectionId: string, hubName: string) → `Promise<CollectionResponse>`
|
|
10734
|
-
Claim or rename the Hub subdomain for a collection (admin only). Maps `{hubName}.
|
|
10745
|
+
Claim or rename the Hub subdomain for a collection (admin only). Maps `{hubName}.smartlinks.host` to the collection. If the collection already had a different hub name, the previous subdomain is released automatically.
|
|
10735
10746
|
|
|
10736
10747
|
**registerDomain**(collectionId: string, domain: string, target: DomainTarget = "smartlinks") → `Promise<any>`
|
|
10737
10748
|
Register a custom domain for a collection and provision its managed certificate (admin only). `"smartlinks"` (the id.smartlinks.app load balancer). Pass `"hub"` to register a bring-your-own Hub domain.
|
|
@@ -11108,6 +11119,11 @@ The release channel a call targets, or undefined for "the collection's installed
|
|
|
11108
11119
|
**functionPath**(surface: 'public' | 'admin', collectionId: string, name: string, opts: FunctionCallOptions = {}) → `string`
|
|
11109
11120
|
The API path a function call goes to (exported for hosts/tests that need the exact URL).
|
|
11110
11121
|
|
|
11122
|
+
**siteUrl**(collection: { siteHost?: string | null } | string,
|
|
11123
|
+
name: string,
|
|
11124
|
+
opts: FunctionSiteUrlOptions & { appId?: string } = {}) → `string`
|
|
11125
|
+
The PUBLIC address of an app function on the collection's own site — what you give a third party as a webhook URL, or call from the collection's public pages: `https://<siteHost>/_fn/<appId>[/<channel>]/<name>[/<path>]`. Every HTTP method the function declares works there, with the raw body for signature checks. Pass the collection (or its siteHost). This address is for public/integration calls; signed-in calls from your app keep using {@link call} / {@link callAdmin}, so the user's SmartLinks session never goes to a tenant hostname. const col = await SL.collection.get(collectionId) const hookUrl = SL.functions.siteUrl(col, 'stripeWebhook', { appId: 'my-shop' }) // → https://acme.smartlinks.host/_fn/my-shop/stripeWebhook
|
|
11126
|
+
|
|
11111
11127
|
**call**(collectionId: string,
|
|
11112
11128
|
name: string,
|
|
11113
11129
|
body: Record<string, any> = {},
|
|
@@ -251,10 +251,15 @@ await SL.functions.call(collectionId, 'pressCounter', {}, { appId: 'some-other-a
|
|
|
251
251
|
**Where it runs.** A function runs on a collection when the app is **installed** there (enabled in
|
|
252
252
|
the collection's apps); or the app is **restricted** to a list of collections (what publishing from
|
|
253
253
|
Forge sets for every developer) and this collection is on it, e.g. your own sandbox; or the app is
|
|
254
|
-
**public**, meaning a registered
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
**public**, meaning a registered app with no restriction list, which only platform admins can
|
|
255
|
+
publish. Anything else gets `404 APP_NOT_INSTALLED`: a function can run with the collection's own
|
|
256
|
+
authority and secrets, so a developer's app can't reach a collection that hasn't taken it on.
|
|
257
|
+
|
|
258
|
+
**Who may run server code at all.** Until functions move to an isolated runner, only TRUSTED apps
|
|
259
|
+
execute: public (unrestricted) apps, or apps a platform admin has marked `functionsTrusted: true`.
|
|
260
|
+
Developer apps — restricted to their own collections, which includes every app published from
|
|
261
|
+
self-serve Forge — get `403 FUNCTIONS_NOT_ENABLED` until they're trusted. A platform admin can also
|
|
262
|
+
switch any app's functions off with `functionsTrusted: false`.
|
|
258
263
|
|
|
259
264
|
**Which release.** With no channel, the server runs the release the collection has **installed** (stable for a
|
|
260
265
|
public app that isn't installed) — what production wants, so app code just calls `SL.functions.call(collectionId, name)`. To run
|
|
@@ -269,6 +274,40 @@ await SL.functions.call(collectionId, 'pressCounter', {}, { channel: 'beta' }) /
|
|
|
269
274
|
await SL.functions.call(collectionId, 'pressCounter', {}, { channel: null }) // force the installed release
|
|
270
275
|
```
|
|
271
276
|
|
|
277
|
+
**Public address on the collection's own site (webhooks, integrations).** Every collection has a
|
|
278
|
+
site host — `<name>.smartlinks.host` once a name is claimed, else `c-<shortId>.smartlinks.host` —
|
|
279
|
+
returned as `collection.siteHost`. App functions are reachable there:
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
https://<siteHost>/_fn/<appId>[/<channel>]/<function>[/<sub-path…>]
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
const col = await SL.collection.get(collectionId)
|
|
287
|
+
const webhookUrl = SL.functions.siteUrl(col, 'stripeWebhook', { appId: 'my-shop' })
|
|
288
|
+
// → https://acme.smartlinks.host/_fn/my-shop/stripeWebhook (give this to Stripe)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Built for integrations: **every HTTP method** the function declares in `trigger.methods` (default
|
|
292
|
+
POST only), **any content type** with the exact bytes in `event.rawBody` (verify signatures with
|
|
293
|
+
`crypto.subtle`), **sub-paths** after the name when the function declares `trigger.path` (`"/*"`, or a
|
|
294
|
+
pattern like `"/orders/:id"` → `event.params.id`), and the function's own `Response` — status, headers,
|
|
295
|
+
CORS — goes back unchanged (the platform adds no CORS headers there; declare `OPTIONS` and answer
|
|
296
|
+
preflights yourself if browsers call you cross-origin). Bodies up to 6 MB.
|
|
297
|
+
|
|
298
|
+
```js
|
|
299
|
+
// manifest: { name: 'orders', trigger: { type: 'http', methods: ['GET', 'PUT'], path: '/orders/:id' }, visibility: 'public' }
|
|
300
|
+
export async function orders(ctx, event) {
|
|
301
|
+
if (event.method === 'GET') return ctx.sl.appRecords.get(event.params.id)
|
|
302
|
+
// PUT: verify the sender first — e.g. an HMAC over event.rawBody with a secret
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Security: the platform never hands a caller's SmartLinks credential to function code (if it signed
|
|
307
|
+
the caller in from `Authorization`, that header is removed and you get `ctx.caller`); your OWN
|
|
308
|
+
`Authorization` scheme for webhooks passes through. `siteUrl` only includes a channel you ask for —
|
|
309
|
+
point production webhooks at the bare address and test ones at `/dev/`.
|
|
310
|
+
|
|
272
311
|
The channel is never a query parameter: the function owns its query string (`?channel=sms` reaches
|
|
273
312
|
your handler untouched), and a configured URL — a webhook, a third-party callback — can only ever
|
|
274
313
|
hit the channel it names. Point production webhooks at the bare path and test ones at `/dev/`.
|
package/dist/openapi.yaml
CHANGED
|
@@ -23052,6 +23052,8 @@ components:
|
|
|
23052
23052
|
type: string
|
|
23053
23053
|
hubCustomDomain:
|
|
23054
23054
|
type: string
|
|
23055
|
+
siteHost:
|
|
23056
|
+
type: string
|
|
23055
23057
|
shortId:
|
|
23056
23058
|
type: string
|
|
23057
23059
|
dark:
|
|
@@ -30539,6 +30541,19 @@ components:
|
|
|
30539
30541
|
appId:
|
|
30540
30542
|
type: object
|
|
30541
30543
|
additionalProperties: true
|
|
30544
|
+
FunctionSiteUrlOptions:
|
|
30545
|
+
type: object
|
|
30546
|
+
properties:
|
|
30547
|
+
channel:
|
|
30548
|
+
type: string
|
|
30549
|
+
path:
|
|
30550
|
+
type: string
|
|
30551
|
+
query:
|
|
30552
|
+
type: object
|
|
30553
|
+
additionalProperties:
|
|
30554
|
+
type: string
|
|
30555
|
+
host:
|
|
30556
|
+
type: string
|
|
30542
30557
|
AllocateSequenceInput:
|
|
30543
30558
|
type: object
|
|
30544
30559
|
properties:
|
|
@@ -42,10 +42,17 @@ export interface Collection {
|
|
|
42
42
|
groupTags?: string[];
|
|
43
43
|
/** Whether the collection has a custom domain */
|
|
44
44
|
redirectUrl?: string;
|
|
45
|
-
/** The claimed Hub subdomain prefix (e.g. "acme" → acme.
|
|
45
|
+
/** The claimed Hub subdomain prefix (e.g. "acme" → acme.smartlinks.host) */
|
|
46
46
|
hubName?: string;
|
|
47
47
|
/** The collection's bring-your-own custom Hub domain (e.g. "hub.acme.com") */
|
|
48
48
|
hubCustomDomain?: string;
|
|
49
|
+
/**
|
|
50
|
+
* The collection's SITE HOST on the tenant domain — computed by the server, never stored:
|
|
51
|
+
* `<hubName>.smartlinks.host` when a name is claimed, else the default `c-<shortId>.smartlinks.host`.
|
|
52
|
+
* Hub serves it, and app functions are reachable under it at `https://<siteHost>/_fn/…`
|
|
53
|
+
* (see SL.functions.siteUrl).
|
|
54
|
+
*/
|
|
55
|
+
siteHost?: string | null;
|
|
49
56
|
/** The shortId of this collection */
|
|
50
57
|
shortId: string;
|
|
51
58
|
/** if dark mode is enabled for this collection */
|
|
@@ -97,7 +104,7 @@ export type DomainTarget = "smartlinks" | "hub";
|
|
|
97
104
|
export interface HubAvailabilityResponse {
|
|
98
105
|
/** Whether the name can be claimed by this collection */
|
|
99
106
|
available: boolean;
|
|
100
|
-
/** The full domain that was checked (e.g. "acme.
|
|
107
|
+
/** The full domain that was checked (e.g. "acme.smartlinks.host") */
|
|
101
108
|
domain: string;
|
|
102
109
|
}
|
|
103
110
|
/**
|
package/dist/utils/paths.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// URL on any of these is NOT a custom domain, so non-master GTINs still need the
|
|
3
3
|
// `/gc/{shortId}` collection prefix. `portalUrl` is only ever set to the platform
|
|
4
4
|
// default or a collection's custom domain, so exact-host matching is sufficient here.
|
|
5
|
-
const PLATFORM_HOSTS = ['smartlinks.app', 'mysmartlinks.app', 'zt.smartlinks.io'];
|
|
5
|
+
const PLATFORM_HOSTS = ['smartlinks.app', 'smartlinks.host', 'mysmartlinks.app', 'zt.smartlinks.io'];
|
|
6
6
|
/** True when `baseUrl`'s host is a collection's own custom domain (not a platform host). */
|
|
7
7
|
function baseIsCustomDomain(baseUrl) {
|
|
8
8
|
if (!baseUrl)
|
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.36 | Generated: 2026-10-03T15:04:37.396Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -4839,6 +4839,7 @@ interface Collection {
|
|
|
4839
4839
|
redirectUrl?: string // Whether the collection has a custom domain
|
|
4840
4840
|
hubName?: string
|
|
4841
4841
|
hubCustomDomain?: string
|
|
4842
|
+
siteHost?: string | null
|
|
4842
4843
|
shortId: string, // The shortId of this collection
|
|
4843
4844
|
dark?: boolean // if dark mode is enabled for this collection
|
|
4844
4845
|
primaryColor?: string
|
|
@@ -9594,6 +9595,16 @@ interface FunctionCallOptions {
|
|
|
9594
9595
|
}
|
|
9595
9596
|
```
|
|
9596
9597
|
|
|
9598
|
+
**FunctionSiteUrlOptions** (interface)
|
|
9599
|
+
```typescript
|
|
9600
|
+
interface FunctionSiteUrlOptions {
|
|
9601
|
+
channel?: string
|
|
9602
|
+
path?: string
|
|
9603
|
+
query?: Record<string, string>
|
|
9604
|
+
host?: string
|
|
9605
|
+
}
|
|
9606
|
+
```
|
|
9607
|
+
|
|
9597
9608
|
**FunctionCallResult** = `any`
|
|
9598
9609
|
|
|
9599
9610
|
### sequence (api)
|
|
@@ -10722,16 +10733,16 @@ Retrieves all Collections.
|
|
|
10722
10733
|
Retrieve a collection by its shortId (public endpoint).
|
|
10723
10734
|
|
|
10724
10735
|
**getByHub**() → `Promise<CollectionResponse>`
|
|
10725
|
-
Resolve the collection for the current Hub domain (public endpoint). The server derives the requesting domain from the request headers (`X-Source-Domain` / `X-Forwarded-Host` / `Host`), so no identifier is passed — this is the call a Hub frontend makes on load to find out which collection it is serving, whether it's reached via `{brand}.
|
|
10736
|
+
Resolve the collection for the current Hub domain (public endpoint). The server derives the requesting domain from the request headers (`X-Source-Domain` / `X-Forwarded-Host` / `Host`), so no identifier is passed — this is the call a Hub frontend makes on load to find out which collection it is serving, whether it's reached via `{brand}.smartlinks.host` or a bring-your-own custom domain (e.g. `hub.acme.com`).
|
|
10726
10737
|
|
|
10727
10738
|
**getByDomain**(domain: string) → `Promise<CollectionResponse>`
|
|
10728
|
-
Resolve the collection for an explicit Hub domain (public endpoint). Unlike {@link getByHub}, the domain is passed explicitly rather than derived from request headers — use this for raw/cross-origin calls where the Hub frontend knows its own hostname (e.g. "erbauer.
|
|
10739
|
+
Resolve the collection for an explicit Hub domain (public endpoint). Unlike {@link getByHub}, the domain is passed explicitly rather than derived from request headers — use this for raw/cross-origin calls where the Hub frontend knows its own hostname (e.g. "erbauer.smartlinks.host").
|
|
10729
10740
|
|
|
10730
10741
|
**checkHubAvailability**(collectionId: string, name: string) → `Promise<HubAvailabilityResponse>`
|
|
10731
10742
|
Check whether a Hub subdomain name is available to claim (admin only).
|
|
10732
10743
|
|
|
10733
10744
|
**claimHub**(collectionId: string, hubName: string) → `Promise<CollectionResponse>`
|
|
10734
|
-
Claim or rename the Hub subdomain for a collection (admin only). Maps `{hubName}.
|
|
10745
|
+
Claim or rename the Hub subdomain for a collection (admin only). Maps `{hubName}.smartlinks.host` to the collection. If the collection already had a different hub name, the previous subdomain is released automatically.
|
|
10735
10746
|
|
|
10736
10747
|
**registerDomain**(collectionId: string, domain: string, target: DomainTarget = "smartlinks") → `Promise<any>`
|
|
10737
10748
|
Register a custom domain for a collection and provision its managed certificate (admin only). `"smartlinks"` (the id.smartlinks.app load balancer). Pass `"hub"` to register a bring-your-own Hub domain.
|
|
@@ -11108,6 +11119,11 @@ The release channel a call targets, or undefined for "the collection's installed
|
|
|
11108
11119
|
**functionPath**(surface: 'public' | 'admin', collectionId: string, name: string, opts: FunctionCallOptions = {}) → `string`
|
|
11109
11120
|
The API path a function call goes to (exported for hosts/tests that need the exact URL).
|
|
11110
11121
|
|
|
11122
|
+
**siteUrl**(collection: { siteHost?: string | null } | string,
|
|
11123
|
+
name: string,
|
|
11124
|
+
opts: FunctionSiteUrlOptions & { appId?: string } = {}) → `string`
|
|
11125
|
+
The PUBLIC address of an app function on the collection's own site — what you give a third party as a webhook URL, or call from the collection's public pages: `https://<siteHost>/_fn/<appId>[/<channel>]/<name>[/<path>]`. Every HTTP method the function declares works there, with the raw body for signature checks. Pass the collection (or its siteHost). This address is for public/integration calls; signed-in calls from your app keep using {@link call} / {@link callAdmin}, so the user's SmartLinks session never goes to a tenant hostname. const col = await SL.collection.get(collectionId) const hookUrl = SL.functions.siteUrl(col, 'stripeWebhook', { appId: 'my-shop' }) // → https://acme.smartlinks.host/_fn/my-shop/stripeWebhook
|
|
11126
|
+
|
|
11111
11127
|
**call**(collectionId: string,
|
|
11112
11128
|
name: string,
|
|
11113
11129
|
body: Record<string, any> = {},
|
package/docs/server-functions.md
CHANGED
|
@@ -251,10 +251,15 @@ await SL.functions.call(collectionId, 'pressCounter', {}, { appId: 'some-other-a
|
|
|
251
251
|
**Where it runs.** A function runs on a collection when the app is **installed** there (enabled in
|
|
252
252
|
the collection's apps); or the app is **restricted** to a list of collections (what publishing from
|
|
253
253
|
Forge sets for every developer) and this collection is on it, e.g. your own sandbox; or the app is
|
|
254
|
-
**public**, meaning a registered
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
**public**, meaning a registered app with no restriction list, which only platform admins can
|
|
255
|
+
publish. Anything else gets `404 APP_NOT_INSTALLED`: a function can run with the collection's own
|
|
256
|
+
authority and secrets, so a developer's app can't reach a collection that hasn't taken it on.
|
|
257
|
+
|
|
258
|
+
**Who may run server code at all.** Until functions move to an isolated runner, only TRUSTED apps
|
|
259
|
+
execute: public (unrestricted) apps, or apps a platform admin has marked `functionsTrusted: true`.
|
|
260
|
+
Developer apps — restricted to their own collections, which includes every app published from
|
|
261
|
+
self-serve Forge — get `403 FUNCTIONS_NOT_ENABLED` until they're trusted. A platform admin can also
|
|
262
|
+
switch any app's functions off with `functionsTrusted: false`.
|
|
258
263
|
|
|
259
264
|
**Which release.** With no channel, the server runs the release the collection has **installed** (stable for a
|
|
260
265
|
public app that isn't installed) — what production wants, so app code just calls `SL.functions.call(collectionId, name)`. To run
|
|
@@ -269,6 +274,40 @@ await SL.functions.call(collectionId, 'pressCounter', {}, { channel: 'beta' }) /
|
|
|
269
274
|
await SL.functions.call(collectionId, 'pressCounter', {}, { channel: null }) // force the installed release
|
|
270
275
|
```
|
|
271
276
|
|
|
277
|
+
**Public address on the collection's own site (webhooks, integrations).** Every collection has a
|
|
278
|
+
site host — `<name>.smartlinks.host` once a name is claimed, else `c-<shortId>.smartlinks.host` —
|
|
279
|
+
returned as `collection.siteHost`. App functions are reachable there:
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
https://<siteHost>/_fn/<appId>[/<channel>]/<function>[/<sub-path…>]
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
const col = await SL.collection.get(collectionId)
|
|
287
|
+
const webhookUrl = SL.functions.siteUrl(col, 'stripeWebhook', { appId: 'my-shop' })
|
|
288
|
+
// → https://acme.smartlinks.host/_fn/my-shop/stripeWebhook (give this to Stripe)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Built for integrations: **every HTTP method** the function declares in `trigger.methods` (default
|
|
292
|
+
POST only), **any content type** with the exact bytes in `event.rawBody` (verify signatures with
|
|
293
|
+
`crypto.subtle`), **sub-paths** after the name when the function declares `trigger.path` (`"/*"`, or a
|
|
294
|
+
pattern like `"/orders/:id"` → `event.params.id`), and the function's own `Response` — status, headers,
|
|
295
|
+
CORS — goes back unchanged (the platform adds no CORS headers there; declare `OPTIONS` and answer
|
|
296
|
+
preflights yourself if browsers call you cross-origin). Bodies up to 6 MB.
|
|
297
|
+
|
|
298
|
+
```js
|
|
299
|
+
// manifest: { name: 'orders', trigger: { type: 'http', methods: ['GET', 'PUT'], path: '/orders/:id' }, visibility: 'public' }
|
|
300
|
+
export async function orders(ctx, event) {
|
|
301
|
+
if (event.method === 'GET') return ctx.sl.appRecords.get(event.params.id)
|
|
302
|
+
// PUT: verify the sender first — e.g. an HMAC over event.rawBody with a secret
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Security: the platform never hands a caller's SmartLinks credential to function code (if it signed
|
|
307
|
+
the caller in from `Authorization`, that header is removed and you get `ctx.caller`); your OWN
|
|
308
|
+
`Authorization` scheme for webhooks passes through. `siteUrl` only includes a channel you ask for —
|
|
309
|
+
point production webhooks at the bare address and test ones at `/dev/`.
|
|
310
|
+
|
|
272
311
|
The channel is never a query parameter: the function owns its query string (`?channel=sms` reaches
|
|
273
312
|
your handler untouched), and a configured URL — a webhook, a third-party callback — can only ever
|
|
274
313
|
hit the channel it names. Point production webhooks at the bare path and test ones at `/dev/`.
|
package/openapi.yaml
CHANGED
|
@@ -23052,6 +23052,8 @@ components:
|
|
|
23052
23052
|
type: string
|
|
23053
23053
|
hubCustomDomain:
|
|
23054
23054
|
type: string
|
|
23055
|
+
siteHost:
|
|
23056
|
+
type: string
|
|
23055
23057
|
shortId:
|
|
23056
23058
|
type: string
|
|
23057
23059
|
dark:
|
|
@@ -30539,6 +30541,19 @@ components:
|
|
|
30539
30541
|
appId:
|
|
30540
30542
|
type: object
|
|
30541
30543
|
additionalProperties: true
|
|
30544
|
+
FunctionSiteUrlOptions:
|
|
30545
|
+
type: object
|
|
30546
|
+
properties:
|
|
30547
|
+
channel:
|
|
30548
|
+
type: string
|
|
30549
|
+
path:
|
|
30550
|
+
type: string
|
|
30551
|
+
query:
|
|
30552
|
+
type: object
|
|
30553
|
+
additionalProperties:
|
|
30554
|
+
type: string
|
|
30555
|
+
host:
|
|
30556
|
+
type: string
|
|
30542
30557
|
AllocateSequenceInput:
|
|
30543
30558
|
type: object
|
|
30544
30559
|
properties:
|