@on-belay/sdk 1.0.0

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.
@@ -0,0 +1,531 @@
1
+ /**
2
+ * @on-belay/sdk — Exported Types
3
+ *
4
+ * All types used by fieldset authors are exported from here.
5
+ * Fieldsets import from "@on-belay/sdk" only — never from platform internals.
6
+ */
7
+ type ProxyResult = {
8
+ status: number;
9
+ data: unknown;
10
+ blocked?: boolean;
11
+ error?: string;
12
+ };
13
+ type ConnectedIntegration = {
14
+ slug: string;
15
+ status: "active" | "error" | "pending";
16
+ extraConfig: Record<string, string | null>;
17
+ };
18
+ type OrgContext = {
19
+ orgId: string;
20
+ orgName: string;
21
+ connectedIntegrations: ConnectedIntegration[];
22
+ };
23
+ type PortfolioOrg = {
24
+ orgId: string;
25
+ orgName: string;
26
+ orgSlug: string;
27
+ };
28
+ type FieldsetManifest = {
29
+ /** Unique kebab-case slug. Immutable after first deploy. */
30
+ slug: string;
31
+ /** Display name shown in the dashboard. */
32
+ name: string;
33
+ /** Short description shown in the fieldset catalog. */
34
+ description: string;
35
+ /**
36
+ * Execution model.
37
+ * - 'per-org': standard fieldset, enrolled per STANDARD org. Default.
38
+ * - 'portfolio': enrolled once at an AGENCY org level; has access to all child orgs.
39
+ *
40
+ * Omitting this field is treated as 'per-org' for backward compatibility.
41
+ */
42
+ executionModel?: "per-org" | "portfolio";
43
+ /** Integration slugs the org must have connected before enrolling. */
44
+ requiredIntegrations: string[];
45
+ /** Integration slugs that improve the fieldset but are not required. */
46
+ optionalIntegrations?: string[];
47
+ /**
48
+ * Every (integrationSlug, operationKey) pair this fieldset ever calls via executeProxyCall.
49
+ * The proxy rejects any call not in this manifest.
50
+ */
51
+ requiredOperations: Array<{
52
+ slug: string;
53
+ operationKey: string;
54
+ }>;
55
+ /**
56
+ * Billing configuration. Required if the fieldset calls recordPublish().
57
+ * Each key is a contentType string. freeAllowance is per-org, per-contentType.
58
+ */
59
+ billing?: {
60
+ contentTypes: Record<string, {
61
+ label: string;
62
+ freeAllowance: number;
63
+ }>;
64
+ };
65
+ /**
66
+ * Default values written into OrgFieldset.config at enrollment time.
67
+ * The fieldset reads these back via getFieldsetConfig().
68
+ */
69
+ configDefaults?: Record<string, unknown>;
70
+ /**
71
+ * Migration file names (relative to the fieldset's migrations/ directory), in order.
72
+ * The platform runs these at enrollment time.
73
+ */
74
+ migrations?: string[];
75
+ /**
76
+ * Exported Inngest function names from the fieldset's inngest/ directory.
77
+ * The platform registers these at app startup.
78
+ */
79
+ inngestFunctions?: string[];
80
+ };
81
+ /** Opaque Inngest function type — returned by createScheduler / createOrgRunner / createPortfolioRunner. */
82
+ type InngestFunction = any;
83
+ /** Opaque Inngest step object — provided by Inngest to function handlers. */
84
+ type InngestStep = any;
85
+ /** Opaque Inngest event object — full event payload including data, id, ts. */
86
+ type InngestEvent = any;
87
+ type SchedulerConfig = {
88
+ /** Inngest function ID — must be unique across the platform. E.g. "content-engine-scheduler". */
89
+ id: string;
90
+ /** The fieldset slug — used to query enrolled orgs via getEnrolledOrgs. */
91
+ fieldsetSlug: string;
92
+ /** Cron expression (UTC). E.g. "0 9 * * 1-5" for weekdays at 9am UTC. */
93
+ cron: string;
94
+ /** The event name to emit for each enrolled org. E.g. "content-engine/run.org". */
95
+ eventName: string;
96
+ /**
97
+ * Optional: extra event data to include per org event.
98
+ * Called once per org — return any serializable data to merge into the event payload.
99
+ */
100
+ eventData?: (orgId: string) => Record<string, unknown>;
101
+ /** Maximum concurrent scheduler runs. Default: 1. */
102
+ concurrency?: number;
103
+ };
104
+ type OrgRunContext = {
105
+ /** The org this run is for. */
106
+ orgId: string;
107
+ /** Inngest step object — use step.run() to create durable, retriable steps. */
108
+ step: InngestStep;
109
+ /** Full Inngest event — includes any extra data from the scheduler. */
110
+ event: InngestEvent;
111
+ };
112
+ type OrgRunnerConfig = {
113
+ /** Inngest function ID. E.g. "content-engine-runner". */
114
+ id: string;
115
+ /** Event that triggers this runner. Must match scheduler's eventName. */
116
+ triggerEvent: string;
117
+ /** Fieldset slug — used for enrollment verification inside the runner. */
118
+ fieldsetSlug: string;
119
+ /**
120
+ * Concurrency key expression. Default: "event.data.orgId".
121
+ * One concurrent run per unique key value at a time.
122
+ */
123
+ concurrencyKey?: string;
124
+ /** Default: 1. */
125
+ concurrencyLimit?: number;
126
+ /** Number of Inngest retries on failure. Default: 2. */
127
+ retries?: number;
128
+ /** Inngest function timeout in minutes. Default: 10. */
129
+ timeoutMinutes?: number;
130
+ /** The fieldset's run logic. Receives orgId, step, and the full event. */
131
+ run: (context: OrgRunContext) => Promise<unknown>;
132
+ };
133
+ type PortfolioRunContext = {
134
+ /** The enrolled AGENCY org. */
135
+ parentOrgId: string;
136
+ /** Pre-fetched client orgs via getPortfolioOrgs — iterate these in isolation. */
137
+ clientOrgs: PortfolioOrg[];
138
+ /** Inngest step object. */
139
+ step: InngestStep;
140
+ /** Full Inngest event. */
141
+ event: InngestEvent;
142
+ };
143
+ type PortfolioRunnerConfig = {
144
+ /** Inngest function ID. E.g. "pe-revenue-tracker-runner". */
145
+ id: string;
146
+ /** Event that triggers this runner. E.g. "pe-revenue-tracker/run.portfolio". */
147
+ triggerEvent: string;
148
+ /** Fieldset slug — used for enrollment verification. */
149
+ fieldsetSlug: string;
150
+ /** Default: 1. */
151
+ concurrencyLimit?: number;
152
+ /** Default: 2. */
153
+ retries?: number;
154
+ /** Default: 15 minutes (portfolio runs aggregate across N orgs). */
155
+ timeoutMinutes?: number;
156
+ /** The fieldset's portfolio run logic. */
157
+ run: (context: PortfolioRunContext) => Promise<unknown>;
158
+ };
159
+
160
+ /**
161
+ * @on-belay/sdk — executeProxyCall
162
+ *
163
+ * The only way a fieldset may call a third-party API. Routes through the
164
+ * On Belay proxy layer, which handles credential retrieval, decryption, token
165
+ * refresh, audit logging, and org-scoping.
166
+ *
167
+ * Fieldsets never construct AuthResult objects or touch proxy-handler.ts directly.
168
+ *
169
+ * Dual-mode execution:
170
+ * - Internal mode (no ONBELAY_FIELDSET_TOKEN env var): direct import from platform
171
+ * internals. Used by fieldsets running inside the On Belay monorepo.
172
+ * - External mode (ONBELAY_FIELDSET_TOKEN is set): HTTP POST to ONBELAY_PROXY_URL.
173
+ * Used by external fieldsets deployed as standalone services (e.g. on Railway).
174
+ */
175
+
176
+ /**
177
+ * Execute an authenticated API call to a third-party integration on behalf of an org.
178
+ *
179
+ * This is the ONLY way a fieldset may call any external API.
180
+ *
181
+ * Dispatches to external HTTP mode when ONBELAY_FIELDSET_TOKEN is set in the environment,
182
+ * otherwise falls back to direct internal platform imports (monorepo mode).
183
+ *
184
+ * @param orgId - The org on whose behalf the call is made. For portfolio runners
185
+ * acting on a client, pass the clientOrgId here.
186
+ * @param fieldsetSlug - The fieldset's slug (from its manifest). Used to construct
187
+ * the fieldset-master AuthResult and enforce operation permissions.
188
+ * @param integrationSlug - The On Belay integration slug (e.g. "shopify", "hubspot").
189
+ * @param operationKey - The operation key declared in the fieldset manifest (e.g. "shopify.products.list").
190
+ * @param path - The API path (e.g. "/admin/api/2024-01/products.json").
191
+ * @param options - Optional: method, body, queryParams, _portfolioParentOrgId.
192
+ *
193
+ * @returns ProxyResult — check result.blocked before using result.data.
194
+ *
195
+ * Error behavior:
196
+ * - result.blocked === true: integration not connected or operation not in manifest. Log and skip.
197
+ * - result.status >= 500: upstream API error. Throw to let Inngest retry.
198
+ * - Throws if fieldsetSlug is not registered: developer error, fix before deploying.
199
+ */
200
+ declare function executeProxyCall(orgId: string, fieldsetSlug: string, integrationSlug: string, operationKey: string, path: string, options?: {
201
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
202
+ body?: Record<string, unknown>;
203
+ queryParams?: Record<string, string>;
204
+ /**
205
+ * Portfolio runners only. When set, the SDK validates that orgId is a client
206
+ * of this parent org before dispatching the proxy call. Returns blocked: true
207
+ * if orgId is not a valid client of the parent.
208
+ *
209
+ * NOTE: Only available in internal mode. In external mode this field is ignored
210
+ * — parent validation is enforced server-side by the proxy endpoint.
211
+ *
212
+ * TODO: platform-team (P0 #15) — When proxy-handler gains native portfolio
213
+ * parent validation, delegate there instead of doing it here.
214
+ */
215
+ _portfolioParentOrgId?: string;
216
+ }): Promise<ProxyResult>;
217
+
218
+ /**
219
+ * @on-belay/sdk — validateWebhookSignature
220
+ *
221
+ * Self-contained HMAC-SHA256 webhook signature verification.
222
+ * Mirrors the implementation in src/lib/webhook-signing.ts but has zero
223
+ * imports from platform internals — safe for npm publishing.
224
+ *
225
+ * Usage:
226
+ * import { validateWebhookSignature } from "@on-belay/sdk"
227
+ *
228
+ * app.post("/api/webhook", express.raw({ type: "application/json" }), (req, res) => {
229
+ * const isValid = validateWebhookSignature(
230
+ * req.body,
231
+ * req.headers["x-onbelay-signature"] as string,
232
+ * process.env.ONBELAY_WEBHOOK_SECRET!,
233
+ * req.headers["x-onbelay-timestamp"] as string,
234
+ * { maxAgeSeconds: 300 }
235
+ * )
236
+ * if (!isValid) return res.status(401).json({ error: "invalid_signature" })
237
+ * // ... handle webhook
238
+ * })
239
+ */
240
+ interface WebhookVerifyOptions {
241
+ maxAgeSeconds?: number;
242
+ }
243
+ /**
244
+ * Verifies an inbound webhook signature from On Belay.
245
+ * Uses constant-time comparison to prevent timing side-channel attacks.
246
+ * Returns false (never throws) on any mismatch or error.
247
+ *
248
+ * @param rawBody - Raw request body before JSON.parse (string or Buffer).
249
+ * Must be the exact bytes received — do NOT parse first.
250
+ * @param signatureHeader - Value of X-Onbelay-Signature header ("sha256=<hex>")
251
+ * @param secret - Your webhook secret (ONBELAY_WEBHOOK_SECRET env var)
252
+ * @param timestamp - Optional. Value of X-Onbelay-Timestamp header (ISO8601).
253
+ * When provided, the function rejects payloads older than
254
+ * maxAgeSeconds (replay-attack defense).
255
+ * @param options - Optional. { maxAgeSeconds?: number } — defaults to 300 (5 min).
256
+ *
257
+ * @returns true if the signature is valid (and timestamp is within age limit when provided)
258
+ */
259
+ declare function validateWebhookSignature(rawBody: string | Buffer, signatureHeader: string, secret: string, timestamp?: string, options?: WebhookVerifyOptions): boolean;
260
+
261
+ /**
262
+ * @on-belay/sdk — validateDashboardToken
263
+ *
264
+ * Browser and Node.js compatible JWT verification using jose.
265
+ * Validates a dashboard context token issued by the On Belay platform.
266
+ *
267
+ * Usage:
268
+ * import { validateDashboardToken } from "@on-belay/sdk"
269
+ *
270
+ * app.post("/api/my-data", express.json(), async (req, res) => {
271
+ * const context = await validateDashboardToken(
272
+ * req.body.token,
273
+ * process.env.ONBELAY_DASHBOARD_SECRET!
274
+ * )
275
+ * if (!context) return res.status(401).json({ error: "invalid_token" })
276
+ *
277
+ * const { orgId, userId, fieldsetSlug } = context
278
+ * // act on behalf of this org
279
+ * })
280
+ */
281
+ interface DashboardTokenPayload {
282
+ orgId: string;
283
+ userId: string;
284
+ fieldsetSlug: string;
285
+ iat?: number;
286
+ exp?: number;
287
+ }
288
+ /**
289
+ * Validates a dashboard context token issued by the On Belay platform.
290
+ * Returns the decoded payload on success, or null on any validation failure
291
+ * (expired, bad signature, malformed). Never throws.
292
+ *
293
+ * @param token - The JWT string received via postMessage from the platform
294
+ * @param secret - process.env.ONBELAY_DASHBOARD_SECRET
295
+ */
296
+ declare function validateDashboardToken(token: string, secret: string): Promise<{
297
+ orgId: string;
298
+ userId: string;
299
+ fieldsetSlug: string;
300
+ } | null>;
301
+
302
+ /**
303
+ * @on-belay/sdk — getOrgContext
304
+ *
305
+ * Returns org name and connected integrations for a given org.
306
+ * Read-only. Does not expose encrypted fields or credentials.
307
+ */
308
+
309
+ /**
310
+ * Returns the org's name and list of connected integrations with their status
311
+ * and extraConfig. Read-only — credentials are never exposed here.
312
+ *
313
+ * @throws If orgId does not exist in the database.
314
+ */
315
+ declare function getOrgContext(orgId: string): Promise<OrgContext>;
316
+
317
+ /**
318
+ * @on-belay/sdk — getFieldsetConfig / setFieldsetConfig
319
+ *
320
+ * Read and write the OrgFieldset.config JSON blob for an org+fieldset pair.
321
+ * Config is plaintext — do NOT store credentials, tokens, or sensitive values here.
322
+ */
323
+ /**
324
+ * Returns the OrgFieldset.config for this org and fieldset.
325
+ * Returns {} (empty object cast to T) if no config has been set yet.
326
+ *
327
+ * @param orgId - The org ID.
328
+ * @param fieldsetSlug - The fieldset's slug.
329
+ * @returns The config cast to T. The fieldset declares T to get type safety.
330
+ *
331
+ * @throws If orgId does not exist.
332
+ */
333
+ declare function getFieldsetConfig<T = Record<string, unknown>>(orgId: string, fieldsetSlug: string): Promise<T>;
334
+ /**
335
+ * Merges patch into the existing OrgFieldset.config. Non-destructive:
336
+ * keys not in patch are preserved.
337
+ *
338
+ * @param orgId - The org ID.
339
+ * @param fieldsetSlug - The fieldset's slug.
340
+ * @param patch - Partial config to merge in.
341
+ *
342
+ * @throws If the OrgFieldset row does not exist (org not enrolled in this fieldset).
343
+ * Call isEnrolled() before calling this if enrollment is uncertain.
344
+ */
345
+ declare function setFieldsetConfig<T = Record<string, unknown>>(orgId: string, fieldsetSlug: string, patch: Partial<T>): Promise<void>;
346
+
347
+ /**
348
+ * @on-belay/sdk — recordPublish
349
+ *
350
+ * Records a billing event for a publish (writeback) action.
351
+ * Increments the PublishCounter for this org+fieldset+contentType.
352
+ * If Stripe metered billing is configured, fires the usage event.
353
+ *
354
+ * Call at writeback time, NOT at generation time.
355
+ */
356
+ /**
357
+ * Records a publish billing event for an org+fieldset+contentType combination.
358
+ *
359
+ * - Upserts a PublishCounter row (increments publishCount).
360
+ * - Fires a Stripe metered billing event when STRIPE_SECRET_KEY is configured.
361
+ * Stripe failures are logged but do NOT throw — the publish proceeds regardless.
362
+ * If the Prisma upsert fails, it throws so the Inngest step retries.
363
+ *
364
+ * IMPORTANT: Call this at writeback time, not generation time. Billing is
365
+ * triggered by publish-to-live, not by content generation.
366
+ *
367
+ * IMPORTANT: This call and the writeback itself must be inside the SAME
368
+ * step.run() block to ensure atomicity — if the writeback fails, the billing
369
+ * event does not fire (Inngest retries the entire step).
370
+ *
371
+ * @param orgId - The org being billed.
372
+ * @param fieldsetSlug - The fieldset slug.
373
+ * @param contentType - The content type (must match a key in the fieldset's
374
+ * manifest billing.contentTypes). E.g. "product_description".
375
+ * @param metadata - Optional metadata to log with the billing event.
376
+ */
377
+ declare function recordPublish(orgId: string, fieldsetSlug: string, contentType: string, metadata?: Record<string, unknown>): Promise<void>;
378
+
379
+ /**
380
+ * @on-belay/sdk — isEnrolled / getEnrolledOrgs
381
+ *
382
+ * Enrollment state queries for fieldset schedulers and runners.
383
+ */
384
+ /**
385
+ * Returns true if the org has an active OrgFieldset record for this fieldset.
386
+ * Returns false for any non-active status (suspended, expired, disabled) or if
387
+ * no record exists.
388
+ *
389
+ * Use this inside runners to gate execution. Do NOT use it to gate proxy calls —
390
+ * the proxy already enforces enrollment.
391
+ *
392
+ * @param orgId - The org to check.
393
+ * @param fieldsetSlug - The fieldset slug.
394
+ */
395
+ declare function isEnrolled(orgId: string, fieldsetSlug: string): Promise<boolean>;
396
+ /**
397
+ * Returns an array of orgId strings for all orgs with an active enrollment
398
+ * in this fieldset.
399
+ *
400
+ * Use this inside a scheduler to discover orgs to fan out to. Do NOT query
401
+ * OrgFieldset directly from fieldset code — this is the canonical path.
402
+ *
403
+ * @param fieldsetSlug - The fieldset slug.
404
+ * @returns Array of org IDs with active enrollment.
405
+ */
406
+ declare function getEnrolledOrgs(fieldsetSlug: string): Promise<string[]>;
407
+
408
+ /**
409
+ * @on-belay/sdk — getPortfolioOrgs
410
+ *
411
+ * Returns client orgs for a portfolio (AGENCY) org. Used by portfolio runners
412
+ * to discover which client orgs to iterate over.
413
+ */
414
+
415
+ /**
416
+ * Returns all client orgs that are children of the given parentOrgId.
417
+ * These are the orgs a portfolio fieldset is authorized to read from and
418
+ * act on behalf of.
419
+ *
420
+ * Data isolation law: process each client org in isolation inside its own
421
+ * step.run() block. Aggregate only scalar outputs across client contexts —
422
+ * never raw credential-adjacent data.
423
+ *
424
+ * @param parentOrgId - The enrolled AGENCY org.
425
+ * @returns Array of client orgs. Returns [] if no clients — not an error.
426
+ *
427
+ * @throws If parentOrgId does not exist.
428
+ * @throws If parentOrgId resolves to a non-AGENCY org.
429
+ */
430
+ declare function getPortfolioOrgs(parentOrgId: string): Promise<PortfolioOrg[]>;
431
+
432
+ /**
433
+ * @on-belay/sdk — createScheduler / createOrgRunner / createPortfolioRunner
434
+ *
435
+ * Inngest function builders for fieldsets. These cover the standard
436
+ * scheduler → fan-out → per-org runner pattern.
437
+ *
438
+ * For complex multi-stage pipelines (like the marketing agent), write
439
+ * Inngest functions directly using inngest.createFunction — do not stretch
440
+ * these builders to cover cases they weren't designed for.
441
+ */
442
+
443
+ /**
444
+ * Creates an Inngest function that runs on a cron schedule, queries enrolled
445
+ * orgs via getEnrolledOrgs, and fans out one event per org.
446
+ *
447
+ * Returns the Inngest function object for registration in route.ts.
448
+ *
449
+ * Use this for the standard scheduler pattern. If your scheduler needs custom
450
+ * logic beyond fan-out, write inngest.createFunction directly.
451
+ *
452
+ * @example
453
+ * export const myFieldsetScheduler = createScheduler({
454
+ * id: "my-fieldset-scheduler",
455
+ * fieldsetSlug: "my-fieldset",
456
+ * cron: "0 9 * * 1-5",
457
+ * eventName: "my-fieldset/run.org",
458
+ * })
459
+ */
460
+ declare function createScheduler(config: SchedulerConfig): InngestFunction;
461
+ /**
462
+ * Creates an Inngest function triggered by triggerEvent. Extracts orgId from
463
+ * event.data, verifies enrollment (short-circuits if not enrolled), and calls
464
+ * run(context) which the fieldset implements.
465
+ *
466
+ * @example
467
+ * export const myFieldsetRunner = createOrgRunner({
468
+ * id: "my-fieldset-runner",
469
+ * triggerEvent: "my-fieldset/run.org",
470
+ * fieldsetSlug: "my-fieldset",
471
+ * async run({ orgId, step }) {
472
+ * await step.run("do-work", async () => { ... })
473
+ * },
474
+ * })
475
+ */
476
+ declare function createOrgRunner(config: OrgRunnerConfig): InngestFunction;
477
+ /**
478
+ * Creates an Inngest function for portfolio (AGENCY org level) fieldsets.
479
+ * Extracts parentOrgId from event.data, verifies enrollment, fetches client
480
+ * orgs via getPortfolioOrgs, then calls run(context) with the full client list.
481
+ *
482
+ * The runner does NOT fan out to per-client Inngest events automatically.
483
+ * Fieldsets receive the full client org list and iterate internally using
484
+ * step.run() blocks for per-client retry granularity.
485
+ *
486
+ * @example
487
+ * export const myPortfolioRunner = createPortfolioRunner({
488
+ * id: "my-portfolio-runner",
489
+ * triggerEvent: "my-fieldset/run.portfolio",
490
+ * fieldsetSlug: "my-fieldset",
491
+ * async run({ parentOrgId, clientOrgs, step }) {
492
+ * for (const client of clientOrgs) {
493
+ * await step.run(`process-${client.orgId}`, async () => { ... })
494
+ * }
495
+ * },
496
+ * })
497
+ */
498
+ declare function createPortfolioRunner(config: PortfolioRunnerConfig): InngestFunction;
499
+
500
+ /**
501
+ * @on-belay/sdk — defineFieldset
502
+ *
503
+ * Helper to define a fieldset manifest with type checking.
504
+ * Use this in every fieldset's fieldset.manifest.ts file.
505
+ *
506
+ * @example
507
+ * import { defineFieldset } from "@on-belay/sdk"
508
+ *
509
+ * export default defineFieldset({
510
+ * slug: "content-engine",
511
+ * name: "Content Engine",
512
+ * description: "AI-powered product and blog content for Shopify brands.",
513
+ * executionModel: "per-org",
514
+ * requiredIntegrations: ["shopify"],
515
+ * requiredOperations: [
516
+ * { slug: "shopify", operationKey: "shopify.products.list" },
517
+ * ],
518
+ * })
519
+ */
520
+
521
+ /**
522
+ * Define a fieldset manifest. This is a typed identity function — it returns
523
+ * the manifest object unchanged but provides TypeScript type checking at
524
+ * authoring time.
525
+ *
526
+ * The platform reads the default export of fieldset.manifest.ts at registration
527
+ * and enrollment time.
528
+ */
529
+ declare function defineFieldset(manifest: FieldsetManifest): FieldsetManifest;
530
+
531
+ export { type ConnectedIntegration, type DashboardTokenPayload, type FieldsetManifest, type InngestEvent, type InngestFunction, type InngestStep, type OrgContext, type OrgRunContext, type OrgRunnerConfig, type PortfolioOrg, type PortfolioRunContext, type PortfolioRunnerConfig, type ProxyResult, type SchedulerConfig, type WebhookVerifyOptions, createOrgRunner, createPortfolioRunner, createScheduler, defineFieldset, executeProxyCall, getEnrolledOrgs, getFieldsetConfig, getOrgContext, getPortfolioOrgs, isEnrolled, recordPublish, setFieldsetConfig, validateDashboardToken, validateWebhookSignature };