@oxy-hq/sdk 2.9.1 → 2.10.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.
@@ -64,6 +64,25 @@ interface OxyAppFunctionManifest {
64
64
  email?: {
65
65
  send?: boolean;
66
66
  };
67
+ /**
68
+ * Capability for `ctx.oltp` — read/write the app's OWN per-org OLTP schema on
69
+ * the managed Postgres tenant (fail-closed: omit → every `ctx.oltp` call
70
+ * rejected). A pure GATE: the target schema is derived from the app's own slug
71
+ * host-side (`oltp-bookings` → `app_oltp_bookings`), never named here, so a
72
+ * manifest cannot point `ctx.oltp` at another app's schema. The resolved role
73
+ * has DML rights on that one schema and nothing else — reaching neither another
74
+ * app's data nor the analyst-visible `raw_*` schemas. The store must be
75
+ * provisioned first (ask whoever operates the org).
76
+ *
77
+ * NOTE: this shape is `{ enabled }`, not the earlier `{ writer }` — an app
78
+ * had no business naming its own writer (that was the cross-app hole). A
79
+ * manifest still carrying `"oltp": { "writer": "…" }` deserializes to
80
+ * `enabled: undefined` → **disabled**, and `ctx.oltp` then reports the
81
+ * capability as missing. Switch it to `{ "enabled": true }`.
82
+ */
83
+ oltp?: {
84
+ enabled?: boolean;
85
+ };
67
86
  /**
68
87
  * Retry policy for **background** runs (a `schedule` fire or a manual job
69
88
  * trigger). Omit → a job run is attempted once. Route (HTTP) invocations are
@@ -137,6 +156,46 @@ interface OxyAppManifest {
137
156
  * shares.
138
157
  */
139
158
  storage?: OxyAppStorageManifest;
159
+ /**
160
+ * Browser-runtime performance opt-outs. Both features below are **on by
161
+ * default** — an app that says nothing gets them — so this block exists only
162
+ * to turn one off.
163
+ *
164
+ * Read by the platform at **publish time** (like {@link OxyAppStorageManifest})
165
+ * rather than by this loader, so the field is documented here but not
166
+ * round-tripped through the dev-time manifest fetch.
167
+ */
168
+ performance?: OxyAppPerformanceManifest;
169
+ /**
170
+ * Opt out of the platform's automatic, zero-config usage instrumentation:
171
+ * SPA pageviews, Core Web Vitals, engagement time, and uncaught-error counts,
172
+ * posted to `<base>/__oxy/beacon` by the runtime Oxy injects into every served
173
+ * page. `false` silences the **client** runtime only — the server still
174
+ * records one view row per HTML navigation (that floor is not opt-out-able),
175
+ * so the Activity tab never goes dark, it just loses the in-page detail.
176
+ *
177
+ * Distinct from `useTrackEvent` (your own named events): those are additive and
178
+ * always on. This governs only the events the platform sends on your behalf.
179
+ *
180
+ * Honored at publish time (see {@link performance} for why it is not
181
+ * round-tripped here). Default: `true`.
182
+ */
183
+ analytics?: boolean;
184
+ }
185
+ /** Browser-runtime performance opt-outs — the `performance` block in `oxy-app.json`. */
186
+ interface OxyAppPerformanceManifest {
187
+ /**
188
+ * Opt out of the platform service worker Oxy registers at `<base>/__oxy/sw.js`.
189
+ * It precaches your build's entry assets and serves content-hashed files
190
+ * cache-first, so a repeat load of a published app is near-instant.
191
+ *
192
+ * Set `false` only if your app ships its own service worker (two workers
193
+ * cannot both control the same scope) or genuinely must never be cached.
194
+ * There is nothing to configure to opt *in* — a normal build is precached
195
+ * automatically, and a bundle that inlines everything into one HTML file
196
+ * simply has nothing to precache, which is fine. Default: `true`.
197
+ */
198
+ serviceWorker?: boolean;
140
199
  }
141
200
  /** How long assets under a given prefix are kept. */
142
201
  interface OxyAppRetentionRule {
@@ -270,6 +329,27 @@ interface FunctionLog {
270
329
  level: string;
271
330
  message: string;
272
331
  }
332
+ /** A successful function result plus the logs captured during the run. */
333
+ interface FunctionResult<Data> {
334
+ value: Data;
335
+ logs: FunctionLog[];
336
+ }
337
+ /**
338
+ * An error carries the logs captured before the throw, so the app can show them.
339
+ *
340
+ * `status` is the HTTP status the FUNCTION returned, present when the function
341
+ * ran and answered a non-2xx. It is absent when the run itself failed (an
342
+ * `event: error` frame — a crash, a timeout, a cancellation), because there was
343
+ * no response to have a status.
344
+ *
345
+ * `body` is the parsed payload the function returned with that status, so a
346
+ * caller can read `{ error: "…" }` without re-parsing the message.
347
+ */
348
+ type FunctionError = Error & {
349
+ logs?: FunctionLog[];
350
+ status?: number;
351
+ body?: unknown;
352
+ };
273
353
  //#endregion
274
354
  //#region src/custom-app/react.d.ts
275
355
  /**
@@ -469,7 +549,7 @@ interface UseSemanticQueryResult<Row = Record<string, unknown>> {
469
549
  refetch: () => void;
470
550
  }
471
551
  /**
472
- * Run a semantic-layer query against the project's `.view.yml` /
552
+ * Run a semantic-model query against the project's `.view.yml` /
473
553
  * `.topic.yml` definitions. The server compiles to SQL and executes
474
554
  * through the same connector path as `useQuery`, so result shape
475
555
  * matches.
@@ -704,5 +784,5 @@ interface OxyChatProps {
704
784
  */
705
785
  declare function OxyChat(props: OxyChatProps): React.JSX.Element;
706
786
  //#endregion
707
- export { UseSemanticQueryOpts as A, CustomAppErrorReport as B, UseProcedureRunInput as C, UseQueryOpts as D, UseQueryInput as E, useProcedureRun as F, OxyAppFunctionManifest as G, apiErrorFromResponse as H, useQuery as I, _resetCustomAppManifestCacheForTest as J, OxyAppManifest as K, useResolvedManifest as L, useAgentRun as M, useFunction as N, UseQueryResult as O, useOxyApp as P, useSemanticQuery as R, UseFunctionResult as S, UseProcedureRunResult as T, interpretCustomAppError as U, OxyApiError as V, LoadManifestOptions as W, loadCustomAppManifest as Y, SemanticFilter as _, AppFetcher as a, UseAgentRunInput as b, OxyAppProvider as c, OxyChatProps as d, ProcedureProgress as f, SemanticDateRangeOp as g, SemanticArrayOp as h, AgentSqlArtifact as i, UseSemanticQueryResult as j, UseSemanticQueryInput as k, OxyAppProviderProps as l, ProcedureRunState as m, AgentRunEvent as n, OxyAnswer as o, ProcedureResult as p, ResolvedCustomAppManifest as q, AgentRunState as r, OxyAnswerProps as s, AgentArtifact as t, OxyChat as u, SemanticScalarOp as v, UseProcedureRunOpts as w, UseAgentRunResult as x, SemanticTimeDimension as y, useTrackEvent as z };
708
- //# sourceMappingURL=react-DBG6Pfp_.d.cts.map
787
+ export { loadCustomAppManifest as $, UseSemanticQueryOpts as A, FunctionError as B, UseProcedureRunInput as C, UseQueryOpts as D, UseQueryInput as E, useProcedureRun as F, apiErrorFromResponse as G, FunctionResult as H, useQuery as I, OxyAppFunctionManifest as J, interpretCustomAppError as K, useResolvedManifest as L, useAgentRun as M, useFunction as N, UseQueryResult as O, useOxyApp as P, _resetCustomAppManifestCacheForTest as Q, useSemanticQuery as R, UseFunctionResult as S, UseProcedureRunResult as T, CustomAppErrorReport as U, FunctionLog as V, OxyApiError as W, OxyAppPerformanceManifest as X, OxyAppManifest as Y, ResolvedCustomAppManifest as Z, SemanticFilter as _, AppFetcher as a, UseAgentRunInput as b, OxyAppProvider as c, OxyChatProps as d, ProcedureProgress as f, SemanticDateRangeOp as g, SemanticArrayOp as h, AgentSqlArtifact as i, UseSemanticQueryResult as j, UseSemanticQueryInput as k, OxyAppProviderProps as l, ProcedureRunState as m, AgentRunEvent as n, OxyAnswer as o, ProcedureResult as p, LoadManifestOptions as q, AgentRunState as r, OxyAnswerProps as s, AgentArtifact as t, OxyChat as u, SemanticScalarOp as v, UseProcedureRunOpts as w, UseAgentRunResult as x, SemanticTimeDimension as y, useTrackEvent as z };
788
+ //# sourceMappingURL=react-BGUzRMxq.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-BGUzRMxq.d.mts","names":[],"sources":["../src/custom-app/manifest.ts","../src/custom-app/errors.ts","../src/custom-app/function-sse.ts","../src/custom-app/react.tsx"],"mappings":"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"}
@@ -300,6 +300,7 @@ function validateManifest(raw, url) {
300
300
  if (raw.schemaVersion !== 2) throw new Error(`oxy-app.json: schemaVersion must be 2 (got ${JSON.stringify(raw.schemaVersion)}). v1 manifests are no longer supported — upgrade to the identity-only shape.`);
301
301
  if (raw.products !== void 0 || raw.writers !== void 0) throw new Error(`oxy-app.json is schemaVersion 2 (identity-only); \`products\` and \`writers\` are no longer supported`);
302
302
  if (typeof raw.slug !== "string" || !raw.slug.trim()) throw new Error("oxy-app.json: `slug` is required and must be a non-empty string");
303
+ if (!isValidSlug(raw.slug)) throw new Error(`oxy-app.json: \`slug\` ${JSON.stringify(raw.slug)} is invalid — use 1–63 lowercase letters, digits and single hyphens (no leading/trailing/double hyphen, no underscore)`);
303
304
  return {
304
305
  schemaVersion: 2,
305
306
  name: typeof raw.name === "string" ? raw.name : void 0,
@@ -313,12 +314,21 @@ function validateManifest(raw, url) {
313
314
  } : void 0
314
315
  };
315
316
  }
317
+ const SLUG_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
318
+ function isValidSlug(s) {
319
+ return s.length <= 63 && SLUG_RE.test(s);
320
+ }
316
321
  const FUNCTION_NAME_RE = /^[a-z][a-z0-9-]{0,63}$/;
317
322
  /**
318
- * Validate the optional `functions` map. Each key is a function name;
319
- * each value declares how the function is invoked. Mirrors the
320
- * server-side validation in `custom_apps_publish.rs` so a bad
321
- * manifest fails at build, not at publish.
323
+ * Validate the optional `functions` map. Each key is a function name; each value
324
+ * declares how the function is invoked. Mirrors the server-side function-name
325
+ * rule enforced at publish in `custom_apps_publish.rs` — `is_valid_function_name`,
326
+ * checked in `record_functions` before any row is written.
327
+ *
328
+ * This runs at manifest LOAD (app boot / `pnpm dev`), not at `oxy build` — the
329
+ * build-time gate is the vite plugin's `validateManifest`, which now checks
330
+ * function names too. `oxy publish` also validates them locally before esbuild,
331
+ * so a bad name fails before the upload regardless.
322
332
  */
323
333
  function validateFunctions(raw) {
324
334
  if (!isRecord(raw)) throw new Error("oxy-app.json: `functions` must be an object keyed by function name");
@@ -447,11 +457,24 @@ async function readFunctionSseStream(resp) {
447
457
  });
448
458
  } catch {}
449
459
  else if (event === "data") dataPayload = data;
450
- else if (event === "done") return {
451
- done: true,
452
- value: dataPayload ? JSON.parse(dataPayload) : null
453
- };
454
- else if (event === "error") {
460
+ else if (event === "done") {
461
+ const parsed = dataPayload ? JSON.parse(dataPayload) : null;
462
+ const meta = data ? JSON.parse(data) : {};
463
+ const status = typeof meta.status === "number" ? meta.status : 200;
464
+ if (status < 200 || status >= 300) {
465
+ const payload = parsed;
466
+ const err = new Error(String(payload?.message ?? payload?.error ?? `function returned ${status}`));
467
+ err.name = "FunctionStatusError";
468
+ err.status = status;
469
+ err.body = parsed;
470
+ err.logs = logs;
471
+ throw err;
472
+ }
473
+ return {
474
+ done: true,
475
+ value: parsed
476
+ };
477
+ } else if (event === "error") {
455
478
  const payload = data ? JSON.parse(data) : {};
456
479
  const err = new Error(payload.message || payload.error || "function invocation failed");
457
480
  err.name = payload.error || "FunctionError";
@@ -941,7 +964,7 @@ function useFunction(name) {
941
964
  };
942
965
  }
943
966
  /**
944
- * Run a semantic-layer query against the project's `.view.yml` /
967
+ * Run a semantic-model query against the project's `.view.yml` /
945
968
  * `.topic.yml` definitions. The server compiles to SQL and executes
946
969
  * through the same connector path as `useQuery`, so result shape
947
970
  * matches.
@@ -2408,4 +2431,4 @@ Object.defineProperty(exports, 'useTrackEvent', {
2408
2431
  return useTrackEvent;
2409
2432
  }
2410
2433
  });
2411
- //# sourceMappingURL=react-CDYGAfGA.cjs.map
2434
+ //# sourceMappingURL=react-Cas_DVKe.cjs.map