@proveanything/smartlinks 2.0.34 → 2.0.35

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.
@@ -32,6 +32,9 @@ export declare const AI_TOOL_NAMES: {
32
32
  readonly PDF_EXTRACT: "pdf.extract";
33
33
  readonly PDF_DECODE_BARCODES: "pdf.decodeBarcodes";
34
34
  readonly PDF_INSPECT_GRAPHICS: "pdf.inspectGraphics";
35
+ readonly PDF_EDIT: "pdf.edit";
36
+ readonly PDF_PREFLIGHT: "pdf.preflight";
37
+ readonly PDF_PRINT_READY: "pdf.printReady";
35
38
  readonly HTTP_REQUEST: "http.request";
36
39
  readonly TRANSLATE: "translate";
37
40
  };
package/dist/ai-tools.js CHANGED
@@ -29,6 +29,9 @@ export const AI_TOOL_NAMES = {
29
29
  PDF_EXTRACT: 'pdf.extract',
30
30
  PDF_DECODE_BARCODES: 'pdf.decodeBarcodes',
31
31
  PDF_INSPECT_GRAPHICS: 'pdf.inspectGraphics',
32
+ PDF_EDIT: 'pdf.edit',
33
+ PDF_PREFLIGHT: 'pdf.preflight',
34
+ PDF_PRINT_READY: 'pdf.printReady',
32
35
  HTTP_REQUEST: 'http.request',
33
36
  TRANSLATE: 'translate',
34
37
  };
@@ -76,6 +79,12 @@ export const BUILTIN_AI_TOOLS = [
76
79
  description: 'Deterministically decode 1D/2D barcodes (EAN/UPC/QR/Code128/DataMatrix/…) on a PDF page by rasterizing and running a WASM decoder — reliable barcode/QR values where vision hallucinates. Returns value, symbology, page, bbox, confidence. No AI.' },
77
80
  { name: 'pdf.inspectGraphics', group: 'media', capabilities: ['web:read'],
78
81
  description: 'Prepress structural inspection: per-page vector-path/image/outlined-text counts + colour spaces used, plus document-level named SPOT colours (e.g. "PANTONE 871 C"). Answers whether spot/foil plates survived. Deterministic, no AI.' },
82
+ { name: 'pdf.edit', group: 'media', capabilities: ['web:read', 'media:pdf'],
83
+ description: 'Edit an existing PDF: replace LIVE text (glyph-exact removal so neighbouring text never moves; redrawn in the original font when it has the glyphs, else an embedded fallback; CMYK/spot colour kept; matches may span lines), add text and images in boxes (cmyk converts images for print). Returns url + per-item results with verified flags. Outlined text cannot be edited.' },
84
+ { name: 'pdf.preflight', group: 'media', capabilities: ['web:read'],
85
+ description: 'Prepress preflight without changing the PDF: non-embedded fonts, RGB/Lab content, missing TrimBox/BleedBox and short bleed, low effective image resolution, transparency, white overprint, missing PDF/X output intent. Severity follows the target profile. No AI.' },
86
+ { name: 'pdf.printReady', group: 'media', capabilities: ['web:read', 'media:pdf'],
87
+ description: 'Prepare a PDF for print: RGB/Lab -> CMYK with a real press profile (spot colours kept), embed fonts, optional transparency flattening, mark as PDF/X-1a or PDF/X-4 with the output intent embedded, then preflight the RESULT. Returns url + report { compliant, findings, changes }.' },
79
88
  { name: 'http.request', group: 'net', capabilities: ['net:http'],
80
89
  description: 'SSRF-guarded outbound HTTP(S) request to a public URL; returns status/headers/body.' },
81
90
  { name: 'translate', group: 'text', capabilities: ['ai:text'],
@@ -11,14 +11,24 @@ export interface FunctionListResponse {
11
11
  /**
12
12
  * Options for a function call.
13
13
  * - `appId` scopes resolution to one app (recommended; falls back to the SDK app context).
14
- * - `channel` selects which release to run when addressing an app that is NOT enabled on the
15
- * collection (enablement isn't required — the app is resolved directly by id). Defaults to
16
- * `stable` server-side, so pass `channel: 'dev'` to test a dev build before installing it.
14
+ * - `channel` runs a specific release ('dev' | 'alpha' | 'beta' | 'stable') instead of the one the
15
+ * collection has installed — normally left unset (see RELEASE CHANNEL above); `null` forces the
16
+ * installed release even when the app/host set a channel. The app must be installed on the
17
+ * collection, restricted to it (e.g. the developer's sandbox), or a platform-approved public app.
17
18
  */
18
19
  export interface FunctionCallOptions {
19
20
  appId?: string;
20
- channel?: string;
21
+ channel?: string | null;
21
22
  }
23
+ /**
24
+ * The release channel a call targets, or undefined for "the collection's installed release".
25
+ * A host context `appChannel` can be scoped to ONE app with `appChannelApp` — needed where several
26
+ * apps share a page (Forge's portal preview of a dev component), so only the app under development
27
+ * calls its dev build.
28
+ */
29
+ export declare function resolveFunctionChannel(opts?: FunctionCallOptions, appId?: string): string | undefined;
30
+ /** The API path a function call goes to (exported for hosts/tests that need the exact URL). */
31
+ export declare function functionPath(surface: 'public' | 'admin', collectionId: string, name: string, opts?: FunctionCallOptions): string;
22
32
  export declare namespace functions {
23
33
  /**
24
34
  * Call a PUBLIC app server function inline (surface `'public'`).
@@ -13,17 +13,55 @@
13
13
  // available, the call falls back to the DEPRECATED flat path `/collection/:c/functions/:name`,
14
14
  // which the server resolves by bare name and REJECTS with 409 AMBIGUOUS_FUNCTION when more than one
15
15
  // installed app defines that name. Always prefer an appId.
16
- import { post, request, getAppContext } from "../http.js";
17
- function fnPath(surface, collectionId, name, opts = {}) {
16
+ //
17
+ // RELEASE CHANNEL. The channel is part of the URL — /collection/:c/app/:appId/<channel>/functions/:name
18
+ // — never a query param (the function owns its query string, and a configured URL such as a webhook
19
+ // can only ever hit the channel it names). With NO channel the server runs the release the collection
20
+ // has installed, which is what production wants. A channel comes from, in order: `opts.channel`, the
21
+ // app's channel (initializeApi({ appChannel }) / setAppChannel), or the host's `appChannel` context
22
+ // param (Forge's preview of a Test build passes appChannel=dev). Pass `channel: null` to force the
23
+ // installed release regardless.
24
+ import { post, request, getAppContext, getAppChannel } from "../http.js";
25
+ import { readContext } from "../context.js";
26
+ const CHANNELS = ['dev', 'alpha', 'beta', 'stable'];
27
+ /**
28
+ * The release channel a call targets, or undefined for "the collection's installed release".
29
+ * A host context `appChannel` can be scoped to ONE app with `appChannelApp` — needed where several
30
+ * apps share a page (Forge's portal preview of a dev component), so only the app under development
31
+ * calls its dev build.
32
+ */
33
+ export function resolveFunctionChannel(opts = {}, appId) {
34
+ var _a, _b;
35
+ if (opts.channel === null)
36
+ return undefined;
37
+ let raw = (_a = opts.channel) !== null && _a !== void 0 ? _a : getAppChannel();
38
+ if (raw == null) {
39
+ const ctx = readContext();
40
+ const scopedTo = ctx.appChannelApp;
41
+ if (ctx.appChannel && (!scopedTo || scopedTo === ((_b = appId !== null && appId !== void 0 ? appId : opts.appId) !== null && _b !== void 0 ? _b : getAppContext())))
42
+ raw = ctx.appChannel;
43
+ }
44
+ if (!raw)
45
+ return undefined;
46
+ const ch = String(raw).trim().toLowerCase();
47
+ if (!CHANNELS.includes(ch))
48
+ throw new Error(`Unknown release channel "${raw}" (expected ${CHANNELS.join(' | ')})`);
49
+ return ch;
50
+ }
51
+ function appBase(surface, collectionId, opts) {
18
52
  var _a;
19
53
  const c = encodeURIComponent(collectionId);
20
- const n = encodeURIComponent(name);
21
54
  const app = (_a = opts.appId) !== null && _a !== void 0 ? _a : getAppContext();
22
- const q = opts.channel ? `?channel=${encodeURIComponent(opts.channel)}` : '';
23
- return app
24
- ? `/${surface}/collection/${c}/app/${encodeURIComponent(app)}/functions/${n}${q}`
25
- : `/${surface}/collection/${c}/functions/${n}${q}`; // deprecated flat alias
55
+ if (!app)
56
+ return `/${surface}/collection/${c}`; // deprecated flat alias — resolves installed apps only
57
+ const ch = resolveFunctionChannel(opts, app);
58
+ return `/${surface}/collection/${c}/app/${encodeURIComponent(app)}${ch ? `/${ch}` : ''}`;
59
+ }
60
+ /** The API path a function call goes to (exported for hosts/tests that need the exact URL). */
61
+ export function functionPath(surface, collectionId, name, opts = {}) {
62
+ return `${appBase(surface, collectionId, opts)}/functions/${encodeURIComponent(name)}`;
26
63
  }
64
+ const fnPath = functionPath;
27
65
  export var functions;
28
66
  (function (functions) {
29
67
  /**
@@ -53,14 +91,7 @@ export var functions;
53
91
  * appId is given (or set as the SDK app context): `GET /public/collection/:c[/app/:appId]/functions`.
54
92
  */
55
93
  async function list(collectionId, opts = {}) {
56
- var _a;
57
- const c = encodeURIComponent(collectionId);
58
- const app = (_a = opts.appId) !== null && _a !== void 0 ? _a : getAppContext();
59
- const q = opts.channel ? `?channel=${encodeURIComponent(opts.channel)}` : '';
60
- const path = app
61
- ? `/public/collection/${c}/app/${encodeURIComponent(app)}/functions${q}`
62
- : `/public/collection/${c}/functions${q}`;
63
- return request(path);
94
+ return request(`${appBase('public', collectionId, opts)}/functions`);
64
95
  }
65
96
  functions.list = list;
66
97
  })(functions || (functions = {}));
package/dist/context.d.ts CHANGED
@@ -3,6 +3,13 @@ export interface SmartLinksContext {
3
3
  appId?: string;
4
4
  productId?: string;
5
5
  proofId?: string;
6
+ /**
7
+ * The release channel the host is running this build as (e.g. 'dev' in Forge's preview of a Test
8
+ * build). SL.functions uses it to call that channel's server functions. Absent in production.
9
+ */
10
+ appChannel?: string;
11
+ /** Limits `appChannel` to one app (where several apps share a page, e.g. a portal preview). */
12
+ appChannelApp?: string;
6
13
  /** Any other declared view params (e.g. pageId, voteId, orientation, tvMode). */
7
14
  [key: string]: string | undefined;
8
15
  }
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 2.0.34 | Generated: 2026-10-02T16:06:32.154Z
3
+ Version: 2.0.35 | Generated: 2026-10-03T12:37:51.058Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -172,17 +172,23 @@ The current app context (appId), if the SDK was initialized with one.
172
172
  **setAppContext**(id: string | undefined) → `void`
173
173
  Set (or clear) the current app context — the appId used to scope SL.functions calls.
174
174
 
175
- **initializeApi**(options: {
176
- baseURL: string
177
- apiKey?: string
178
- bearerToken?: string
179
- proxyMode?: boolean
180
- ngrokSkipBrowserWarning?: boolean
181
- extraHeaders?: Record<string, string>
182
- /**
183
- * Declares the host platform. Set to `'native'` on native/Capacitor hosts to opt into
184
- * AuthKit refresh tokens — the SDK then sends `X-Client-Platform: native` on every
185
- * request, so login endpoints return `refreshToken`/`refreshTokenExpiresAt` and a
175
+ **getAppChannel**() → `string | undefined`
176
+ The release channel explicitly set for this app build (initializeApi({ appChannel }) / setAppChannel).
177
+
178
+ **setAppChannel**(channel: string | undefined) → `void`
179
+ Set (or clear) the release channel SL.functions calls target.
180
+
181
+ **initializeApi**(options: {
182
+ baseURL: string
183
+ apiKey?: string
184
+ bearerToken?: string
185
+ proxyMode?: boolean
186
+ ngrokSkipBrowserWarning?: boolean
187
+ extraHeaders?: Record<string, string>
188
+ /**
189
+ * Declares the host platform. Set to `'native'` on native/Capacitor hosts to opt into
190
+ * AuthKit refresh tokens — the SDK then sends `X-Client-Platform: native` on every
191
+ * request, so login endpoints return `refreshToken`/`refreshTokenExpiresAt` and a
186
192
  * short-lived access token. Omit (or `'web'`) → `void`
187
193
  Call this once (e.g. at app startup) to configure baseURL/auth.
188
194
 
@@ -213,56 +219,56 @@ Returns true if initializeApi() has been called at least once. Useful for guards
213
219
  **hasAuthCredentials**() → `boolean`
214
220
  Returns true if the SDK currently has any auth credential set (bearer token or API key). Use this as a cheap pre-flight check before calling endpoints that require authentication, to avoid issuing a network request that you already know will return a 401. ```ts if (hasAuthCredentials()) { const account = await auth.getAccount() } ```
215
221
 
216
- **configureSdkCache**(options: {
217
- enabled?: boolean
218
- ttlMs?: number
219
- maxEntries?: number
220
- persistence?: 'none' | 'indexeddb'
221
- persistenceTtlMs?: number
222
- serveStaleOnOffline?: boolean
223
- clearOnPageLoad?: boolean
222
+ **configureSdkCache**(options: {
223
+ enabled?: boolean
224
+ ttlMs?: number
225
+ maxEntries?: number
226
+ persistence?: 'none' | 'indexeddb'
227
+ persistenceTtlMs?: number
228
+ serveStaleOnOffline?: boolean
229
+ clearOnPageLoad?: boolean
224
230
  }) → `void`
225
231
  Configure the SDK's built-in in-memory GET cache. The cache is transparent — it sits inside the HTTP layer and requires no changes to your existing API calls. All GET requests benefit automatically. Per-resource rules (collections/products → 1 h, proofs → 30 s, etc.) override this value. in-memory only (`'none'`, default). Ignored in Node.js. fallback, from the original fetch time (default: 7 days). `SmartlinksOfflineError` with stale data instead of propagating the network error. caches on page load/refresh. IndexedDB persists for offline. ```ts // Enable IndexedDB persistence for offline support configureSdkCache({ persistence: 'indexeddb' }) // Disable cache entirely in test environments configureSdkCache({ enabled: false }) // Keep caches across page refreshes (not recommended for production) configureSdkCache({ clearOnPageLoad: false }) ```
226
232
 
227
233
  **invalidateCache**(urlPattern?: string, options?: InvalidateCacheOptions) → `void`
228
234
  Manually invalidate entries in the SDK's GET cache. Note: the GET cache is **in-memory, per page load** (with an optional L2 IndexedDB layer when persistence is enabled) — it does not persist across reloads unless you opt into persistence, so it rarely needs disabling "for correctness". *contains* this string is removed). With `{ exact: true }`, matches the path precisely. Omit to wipe the entire cache. ```ts invalidateCache() // clear everything invalidateCache('/collection/abc123') // that collection AND everything under it invalidateCache('/collection/abc123', { exact: true }) // ONLY that collection entry invalidateCache('/products/') // all canonical plural product responses ```
229
235
 
230
- **proxyUploadFormData**(path: string,
231
- formData: FormData,
236
+ **proxyUploadFormData**(path: string,
237
+ formData: FormData,
232
238
  onProgress?: (percent: number) → `void`
233
239
  Upload a FormData payload via proxy with progress events using chunked postMessage. Parent is expected to implement the counterpart protocol.
234
240
 
235
241
  **request**(path: string) → `Promise<T>`
236
242
  Internal helper that performs a GET request to `${baseURL}${path}`, injecting headers for apiKey or bearerToken if present. Cache pipeline (when caching is not skipped): L1 hit → return from memory (no I/O) L2 hit → return from IndexedDB, promote to L1 (no network) Miss → fetch from network, store in L1 + L2 Offline → serve stale L2 entry via SmartlinksOfflineError (if persistence enabled) Concurrent identical GETs share one in-flight promise (deduplication). Node-safe: IndexedDB calls are no-ops when IDB is unavailable.
237
243
 
238
- **post**(path: string,
239
- body: any,
244
+ **post**(path: string,
245
+ body: any,
240
246
  extraHeaders?: Record<string, string>) → `Promise<T>`
241
247
  Internal helper that performs a POST request to `${baseURL}${path}`, injecting headers for apiKey or bearerToken if present. If body is FormData, Content-Type is not set. Returns the parsed JSON as T, or throws an Error.
242
248
 
243
- **put**(path: string,
244
- body: any,
249
+ **put**(path: string,
250
+ body: any,
245
251
  extraHeaders?: Record<string, string>) → `Promise<T>`
246
252
  Internal helper that performs a PUT request to `${baseURL}${path}`, injecting headers for apiKey or bearerToken if present. If body is FormData, Content-Type is not set. Returns the parsed JSON as T, or throws an Error.
247
253
 
248
- **patch**(path: string,
249
- body: any,
254
+ **patch**(path: string,
255
+ body: any,
250
256
  extraHeaders?: Record<string, string>) → `Promise<T>`
251
257
  Internal helper that performs a PATCH request to `${baseURL}${path}`, injecting headers for apiKey or bearerToken if present. If body is FormData, Content-Type is not set. Returns the parsed JSON as T, or throws an Error.
252
258
 
253
- **requestWithOptions**(path: string,
259
+ **requestWithOptions**(path: string,
254
260
  options: RequestInit) → `Promise<T>`
255
261
  Internal helper that performs a request to `${baseURL}${path}` with custom options, injecting headers for apiKey or bearerToken if present. Returns the parsed JSON as T, or throws an Error.
256
262
 
257
- **requestStream**(path: string,
258
- options?: {
259
- method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
260
- body?: any
261
- headers?: Record<string, string>
263
+ **requestStream**(path: string,
264
+ options?: {
265
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
266
+ body?: any
267
+ headers?: Record<string, string>
262
268
  }) → `Promise<AsyncIterable<T>>`
263
269
  Internal helper that performs a streaming request using the shared auth and proxy transport. The response is expected to be `text/event-stream` with JSON payloads in `data:` frames.
264
270
 
265
- **del**(path: string,
271
+ **del**(path: string,
266
272
  extraHeaders?: Record<string, string>) → `Promise<T>`
267
273
  Internal helper that performs a DELETE request to `${baseURL}${path}`, injecting headers for apiKey or bearerToken if present. Returns the parsed JSON as T, or throws an Error.
268
274
 
@@ -1528,6 +1534,45 @@ interface PdfInspectGraphicsArgs {
1528
1534
  }
1529
1535
  ```
1530
1536
 
1537
+ **PdfBox** (interface)
1538
+ ```typescript
1539
+ interface PdfBox {
1540
+ x: number; y: number; w: number; h: number
1541
+ }
1542
+ ```
1543
+
1544
+ **PdfEditArgs** (interface)
1545
+ ```typescript
1546
+ interface PdfEditArgs {
1547
+ url: string
1548
+ replaceText?: { id?: string; page?: number; find: string; replace: string; bold?: boolean; align?: 'left' | 'center' | 'right' }[]
1549
+ addText?: { id?: string; page: number; box: PdfBox; text: string; size?: number; bold?: boolean; colour?: PdfColour; align?: 'left' | 'center' | 'right' }[]
1550
+ addImages?: { id?: string; page: number; box: PdfBox; imageUrl: string; colorSpace?: 'rgb' | 'cmyk' }[]
1551
+ preserveColour?: boolean
1552
+ }
1553
+ ```
1554
+
1555
+ **PdfPreflightArgs** (interface)
1556
+ ```typescript
1557
+ interface PdfPreflightArgs {
1558
+ url: string; profile?: PdfXProfile; bleed?: { mm: number }; minDpi?: number
1559
+ }
1560
+ ```
1561
+
1562
+ **PdfPrintReadyArgs** (interface)
1563
+ ```typescript
1564
+ interface PdfPrintReadyArgs {
1565
+ url: string
1566
+ profile?: PdfXProfile
1567
+ outputIntent?: string
1568
+ convertToCmyk?: boolean
1569
+ embedFonts?: boolean
1570
+ bleed?: { mm: number }
1571
+ flattenTransparency?: boolean
1572
+ minDpi?: number
1573
+ }
1574
+ ```
1575
+
1531
1576
  **HttpRequestArgs** (interface)
1532
1577
  ```typescript
1533
1578
  interface HttpRequestArgs {
@@ -1566,6 +1611,9 @@ interface AiToolArgsMap {
1566
1611
  'pdf.extract': PdfExtractArgs
1567
1612
  'pdf.decodeBarcodes': PdfDecodeBarcodesArgs
1568
1613
  'pdf.inspectGraphics': PdfInspectGraphicsArgs
1614
+ 'pdf.edit': PdfEditArgs
1615
+ 'pdf.preflight': PdfPreflightArgs
1616
+ 'pdf.printReady': PdfPrintReadyArgs
1569
1617
  'http.request': HttpRequestArgs
1570
1618
  'translate': TranslateArgs
1571
1619
  }
@@ -1741,6 +1789,68 @@ interface PdfInspectGraphicsResult {
1741
1789
  }
1742
1790
  ```
1743
1791
 
1792
+ **PdfEditItemResult** (interface)
1793
+ ```typescript
1794
+ interface PdfEditItemResult {
1795
+ id: string
1796
+ status: 'done' | 'failed'
1797
+ note?: string
1798
+ verified?: boolean
1799
+ usedFallbackFont?: boolean
1800
+ }
1801
+ ```
1802
+
1803
+ **PdfEditResult** (interface)
1804
+ ```typescript
1805
+ interface PdfEditResult {
1806
+ url: string; results: PdfEditItemResult[]; warnings: string[]
1807
+ }
1808
+ ```
1809
+
1810
+ **PdfPreflightFinding** (interface)
1811
+ ```typescript
1812
+ interface PdfPreflightFinding {
1813
+ severity: 'error' | 'warning'; code: string; page?: number; message: string
1814
+ }
1815
+ ```
1816
+
1817
+ **PdfPreflightResult** (interface)
1818
+ ```typescript
1819
+ interface PdfPreflightResult {
1820
+ url: string
1821
+ compliant: boolean
1822
+ profile: PdfXProfile | null
1823
+ version: string | null
1824
+ findings: PdfPreflightFinding[]
1825
+ stats: {
1826
+ pageCount: number
1827
+ fonts: { name: string; embedded: boolean; subset: boolean; type: string; pages: number[] }[]
1828
+ spotColours: string[]
1829
+ images: { page: number; dpi: number; width: number; height: number; space: string; placedMm: { w: number; h: number } }[]
1830
+ transparency: boolean
1831
+ outputIntent: { identifier: string | null; hasProfile: boolean } | null
1832
+ [key: string]: any
1833
+ }
1834
+ }
1835
+ ```
1836
+
1837
+ **PdfPrintReadyResult** (interface)
1838
+ ```typescript
1839
+ interface PdfPrintReadyResult {
1840
+ url: string
1841
+ report: {
1842
+ compliant: boolean
1843
+ profile: PdfXProfile
1844
+ outputIntent: string
1845
+ findings: PdfPreflightFinding[]
1846
+ changes: { code: string; message: string }[]
1847
+ before: { compliant: boolean; errors: number; findings: PdfPreflightFinding[] }
1848
+ stats: Record<string, any>
1849
+ note: string
1850
+ }
1851
+ }
1852
+ ```
1853
+
1744
1854
  **ResponsesAgentTrace** (interface)
1745
1855
  ```typescript
1746
1856
  interface ResponsesAgentTrace {
@@ -1778,6 +1888,10 @@ interface AgentResponseCompletedEvent {
1778
1888
 
1779
1889
  **AiToolName** = ``
1780
1890
 
1891
+ **PdfColour** = `string | [number, number, number, number]`
1892
+
1893
+ **PdfXProfile** = `'pdfx-1a' | 'pdfx-4'`
1894
+
1781
1895
  **AgentStreamEvent** = ``
1782
1896
 
1783
1897
  ### analytics
@@ -9476,7 +9590,7 @@ interface FunctionListResponse {
9476
9590
  **FunctionCallOptions** (interface)
9477
9591
  ```typescript
9478
9592
  interface FunctionCallOptions {
9479
- appId?: string; channel?: string
9593
+ appId?: string; channel?: string | null
9480
9594
  }
9481
9595
  ```
9482
9596
 
@@ -10988,6 +11102,12 @@ Delete a form for a collection (admin only).
10988
11102
 
10989
11103
  ### functions
10990
11104
 
11105
+ **resolveFunctionChannel**(opts: FunctionCallOptions = {}, appId?: string) → `string | undefined`
11106
+ The release channel a call targets, or undefined for "the collection's installed release". A host context `appChannel` can be scoped to ONE app with `appChannelApp` — needed where several apps share a page (Forge's portal preview of a dev component), so only the app under development calls its dev build.
11107
+
11108
+ **functionPath**(surface: 'public' | 'admin', collectionId: string, name: string, opts: FunctionCallOptions = {}) → `string`
11109
+ The API path a function call goes to (exported for hosts/tests that need the exact URL).
11110
+
10991
11111
  **call**(collectionId: string,
10992
11112
  name: string,
10993
11113
  body: Record<string, any> = {},