@oxy-hq/sdk 2.12.0 → 2.16.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.
- package/README.md +67 -0
- package/dist/{function-context-D8eyZuw_.d.cts → function-context-BNpL5bFb.d.cts} +223 -20
- package/dist/function-context-BNpL5bFb.d.cts.map +1 -0
- package/dist/{function-context-D8eyZuw_.d.mts → function-context-BNpL5bFb.d.mts} +223 -20
- package/dist/function-context-BNpL5bFb.d.mts.map +1 -0
- package/dist/index.cjs +80 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +164 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +164 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +78 -16
- package/dist/index.mjs.map +1 -1
- package/dist/ops.d.cts +1 -1
- package/dist/ops.d.mts +1 -1
- package/dist/{react-DW7Z96sD.d.mts → react-CljeXJuw.d.cts} +142 -8
- package/dist/react-CljeXJuw.d.cts.map +1 -0
- package/dist/{react-DW7Z96sD.d.cts → react-CljeXJuw.d.mts} +142 -8
- package/dist/react-CljeXJuw.d.mts.map +1 -0
- package/dist/{react-DcT-mUPj.cjs → react-Dvkv2deI.cjs} +110 -59
- package/dist/react-Dvkv2deI.cjs.map +1 -0
- package/dist/{react-BXGyzgz0.mjs → react-OW1t_J0M.mjs} +103 -26
- package/dist/react-OW1t_J0M.mjs.map +1 -0
- package/dist/rolldown-runtime-KC0qvQup.cjs +34 -0
- package/dist/shell.cjs +38 -3
- package/dist/shell.cjs.map +1 -1
- package/dist/shell.d.cts +26 -3
- package/dist/shell.d.cts.map +1 -1
- package/dist/shell.d.mts +26 -3
- package/dist/shell.d.mts.map +1 -1
- package/dist/shell.mjs +34 -2
- package/dist/shell.mjs.map +1 -1
- package/dist/testing.cjs +4431 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +656 -0
- package/dist/testing.d.cts.map +1 -0
- package/dist/testing.d.mts +656 -0
- package/dist/testing.d.mts.map +1 -0
- package/dist/testing.mjs +4395 -0
- package/dist/testing.mjs.map +1 -0
- package/package.json +22 -9
- package/dist/function-context-D8eyZuw_.d.cts.map +0 -1
- package/dist/function-context-D8eyZuw_.d.mts.map +0 -1
- package/dist/react-BXGyzgz0.mjs.map +0 -1
- package/dist/react-DW7Z96sD.d.cts.map +0 -1
- package/dist/react-DW7Z96sD.d.mts.map +0 -1
- package/dist/react-DcT-mUPj.cjs.map +0 -1
|
@@ -3,12 +3,27 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* The request passed as the first argument to a function's default export.
|
|
5
5
|
*
|
|
6
|
-
* The host
|
|
7
|
-
* `
|
|
8
|
-
* `JSON.parse(req.body || "{}")
|
|
9
|
-
*
|
|
6
|
+
* The host builds this as `{ method, headers, body }` (`req_json` in
|
|
7
|
+
* `runtime.rs`). It is intentionally *not* a full Web `Request`: the body
|
|
8
|
+
* arrives as a string, so parse it yourself — `JSON.parse(req.body || "{}")`
|
|
9
|
+
* — and there is no `.json()`, no `url`, and no `Headers` object.
|
|
10
10
|
*/
|
|
11
11
|
interface OxyFunctionRequest {
|
|
12
|
+
/**
|
|
13
|
+
* HTTP method of the triggering request, upper-case (`"POST"`, `"GET"`).
|
|
14
|
+
* A scheduled or Airway run has no real request and reports `"POST"`.
|
|
15
|
+
*/
|
|
16
|
+
method: string;
|
|
17
|
+
/**
|
|
18
|
+
* The headers the function is allowed to see, keyed by **lower-case** name.
|
|
19
|
+
*
|
|
20
|
+
* The host drops everything that is not on its passthrough list and not
|
|
21
|
+
* `x-*`, plus its own `x-oxy-*` prefix and a blocked list; a header sent
|
|
22
|
+
* twice collapses to its **first** value, and one whose bytes are not UTF-8
|
|
23
|
+
* is dropped rather than lossily decoded. A scheduled or Airway run has no
|
|
24
|
+
* headers, so this is `{}` — never absent.
|
|
25
|
+
*/
|
|
26
|
+
headers: Record<string, string>;
|
|
12
27
|
/** Raw request body as received (JSON string for a JSON POST). */
|
|
13
28
|
body: string;
|
|
14
29
|
}
|
|
@@ -191,6 +206,12 @@ type OxyFetchInit = RequestInit & {
|
|
|
191
206
|
* `query` does not, because that allowlist is about modifying a project's
|
|
192
207
|
* warehouse, and a `postgres_managed` database resolves the read-only analyst
|
|
193
208
|
* for every caller regardless.
|
|
209
|
+
*
|
|
210
|
+
* **Shape: the customer's warehouse — read it, don't write it.** Writes to a
|
|
211
|
+
* customer warehouse (anything but `airhouse` / `airhouse_managed`) are refused
|
|
212
|
+
* unless the function names the database in `customerWarehouseWrites` with a
|
|
213
|
+
* reason. Facts your app records go to `ctx.airhouse`, records it edits to
|
|
214
|
+
* `ctx.oltp`, files to `ctx.storage`.
|
|
194
215
|
*/
|
|
195
216
|
interface OxyWarehouseApi {
|
|
196
217
|
/**
|
|
@@ -206,11 +227,21 @@ interface OxyWarehouseApi {
|
|
|
206
227
|
}>;
|
|
207
228
|
insert(database: string, table: string, rows: OxyFunctionRow[]): Promise<unknown>;
|
|
208
229
|
exec(database: string, sql: string): Promise<unknown>;
|
|
230
|
+
/**
|
|
231
|
+
* Insert rows, updating any whose `conflictColumns` already exist.
|
|
232
|
+
*
|
|
233
|
+
* Compiles to `INSERT … ON CONFLICT … DO UPDATE`, which only Postgres and
|
|
234
|
+
* DuckDB parse, and which needs a primary key or unique constraint on
|
|
235
|
+
* `conflictColumns`. On any other warehouse — ClickHouse, Snowflake, BigQuery,
|
|
236
|
+
* MySQL — the call is refused by name before anything is sent; use `exec` with
|
|
237
|
+
* that warehouse's own upsert statement instead. Airhouse (DuckLake) tables
|
|
238
|
+
* carry no such constraint, so there the engine refuses it.
|
|
239
|
+
*/
|
|
209
240
|
upsert(database: string, table: string, rows: OxyFunctionRow[], conflictColumns: string[]): Promise<unknown>;
|
|
210
241
|
}
|
|
211
242
|
/**
|
|
212
|
-
* The handle `ctx.tx`
|
|
213
|
-
* open transaction.
|
|
243
|
+
* The handle `ctx.tx` and `ctx.oltp.tx` pass to your callback — a pinned
|
|
244
|
+
* connection with an open transaction.
|
|
214
245
|
*
|
|
215
246
|
* Both methods take **bound parameters** (`$1`, `$2`, …). Never build SQL by
|
|
216
247
|
* concatenating request data: `ctx.warehouse.exec` takes a bare string, but a
|
|
@@ -227,6 +258,11 @@ interface OxyTransaction {
|
|
|
227
258
|
exec(sql: string, params?: unknown[]): Promise<number>;
|
|
228
259
|
}
|
|
229
260
|
/**
|
|
261
|
+
* **Shape: records your app edits** — current state that needs constraints or
|
|
262
|
+
* transactions: a booking, a shift assignment, a template, a count. What
|
|
263
|
+
* happened (history that will not change) goes to `ctx.airhouse`; bytes go to
|
|
264
|
+
* `ctx.storage`.
|
|
265
|
+
*
|
|
230
266
|
* `ctx.oltp` — read and WRITE the app's OWN per-org OLTP schema (`app_<writer>`)
|
|
231
267
|
* on the managed Postgres tenant, and nothing else.
|
|
232
268
|
*
|
|
@@ -253,8 +289,9 @@ interface OxyTransaction {
|
|
|
253
289
|
* handshake, and a wake-up if the compute was idle) and its own transaction, so
|
|
254
290
|
* a per-row loop pays that per row. Prefer one statement over many — a
|
|
255
291
|
* multi-row `INSERT`, an `INSERT … SELECT`, or `INSERT … RETURNING` to avoid a
|
|
256
|
-
* follow-up read —
|
|
257
|
-
* in a hot
|
|
292
|
+
* follow-up read — or run several inside one `ctx.oltp.tx`, which holds a single
|
|
293
|
+
* connection. Reach for `ctx.oltp` a handful of times per request, not in a hot
|
|
294
|
+
* loop.
|
|
258
295
|
*
|
|
259
296
|
* ```ts
|
|
260
297
|
* const [row] = await ctx.oltp.query(
|
|
@@ -268,11 +305,147 @@ interface OxyOltpApi {
|
|
|
268
305
|
query(sql: string, params?: unknown[]): Promise<OxyFunctionRow[]>;
|
|
269
306
|
/** Run a statement for its effect; resolves to the number of rows affected. */
|
|
270
307
|
exec(sql: string, params?: unknown[]): Promise<number>;
|
|
308
|
+
/**
|
|
309
|
+
* Run several statements as one transaction on one connection: commits when
|
|
310
|
+
* `fn` resolves, rolls back when it throws, and rethrows your error. The same
|
|
311
|
+
* handle and rules as `ctx.tx` — let a failed statement's error propagate —
|
|
312
|
+
* without naming a database: the app's own store is implicit.
|
|
313
|
+
*
|
|
314
|
+
* ```ts
|
|
315
|
+
* await ctx.oltp.tx(async (tx) => {
|
|
316
|
+
* await tx.exec("UPDATE shifts SET status = 'closed' WHERE id = $1", [shiftId]);
|
|
317
|
+
* await tx.exec("INSERT INTO shift_notes (shift_id, body) VALUES ($1, $2)", [shiftId, note]);
|
|
318
|
+
* });
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
tx<T>(fn: (tx: OxyTransaction) => Promise<T> | T): Promise<T>;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* **Shape: facts — what happened, which will not change**: an order, a completed
|
|
325
|
+
* checklist, a delivery, a reading. `ctx.airhouse` appends them to your app's own
|
|
326
|
+
* schema in the workspace's Airhouse, where the analytics agent, semantic views
|
|
327
|
+
* and other apps read them as history. Records your app edits in place belong in
|
|
328
|
+
* `ctx.oltp`; files in `ctx.storage`.
|
|
329
|
+
*
|
|
330
|
+
* Gated by the fail-closed `airhouse` manifest capability (`"airhouse": {
|
|
331
|
+
* "enabled": true }`), a pure gate: the schema is `app_<writer>`, derived from
|
|
332
|
+
* the app's slug (`store-ops` → `app_store_ops`) and exposed as `schema`. Writes
|
|
333
|
+
* run **as the app**, whoever invoked the function — a schedule, a webhook and a
|
|
334
|
+
* click write the same way.
|
|
335
|
+
*
|
|
336
|
+
* Every statement is checked before it is sent. Reads may name any schema;
|
|
337
|
+
* writes must target `<schema>.<table>`; `exec` runs no DDL — declare tables in
|
|
338
|
+
* `airhouseMigrations` files, which run once at publish. One statement per call.
|
|
339
|
+
*
|
|
340
|
+
* Airhouse is DuckLake: **no primary keys, UNIQUE, indexes or foreign keys**, and
|
|
341
|
+
* no bound parameters. Give every fact the id its source assigned and a
|
|
342
|
+
* `recorded_at`, append a correction as a new fact instead of updating, and keep
|
|
343
|
+
* one row per id when reading — a retried function can append twice:
|
|
344
|
+
*
|
|
345
|
+
* ```ts
|
|
346
|
+
* await ctx.airhouse.append("checklist_completions", [
|
|
347
|
+
* { completion_id: id, store_guid: store, recorded_at: new Date().toISOString() },
|
|
348
|
+
* ]);
|
|
349
|
+
*
|
|
350
|
+
* const { rows } = await ctx.airhouse.query(`
|
|
351
|
+
* SELECT * FROM ${ctx.airhouse.schema}.checklist_completions
|
|
352
|
+
* QUALIFY row_number() OVER (PARTITION BY completion_id ORDER BY recorded_at DESC) = 1
|
|
353
|
+
* `);
|
|
354
|
+
* ```
|
|
355
|
+
*/
|
|
356
|
+
interface OxyAirhouseApi {
|
|
357
|
+
/** `app_<writer>` when the function declares the capability, else `null`. */
|
|
358
|
+
readonly schema: string | null;
|
|
359
|
+
/** Read, from any schema. Capped like `ctx.warehouse.query`; `truncated` says the cap cut rows. */
|
|
360
|
+
query(sql: string): Promise<{
|
|
361
|
+
rows: OxyFunctionRow[];
|
|
362
|
+
truncated: boolean;
|
|
363
|
+
}>;
|
|
364
|
+
/**
|
|
365
|
+
* Append rows to `<schema>.<table>`. Pass the bare table name; every row must
|
|
366
|
+
* carry the first row's columns. Values are sent as literals, safely quoted.
|
|
367
|
+
* Resolves to the number of rows sent.
|
|
368
|
+
*/
|
|
369
|
+
append(table: string, rows: OxyFunctionRow[]): Promise<number>;
|
|
370
|
+
/**
|
|
371
|
+
* One write statement against your own schema: a `DELETE` for retention or
|
|
372
|
+
* erasure, an `INSERT … SELECT` deriving facts from other facts. Nothing is
|
|
373
|
+
* bound, so never interpolate request data here — that is what `append` is for.
|
|
374
|
+
*/
|
|
375
|
+
exec(sql: string): Promise<void>;
|
|
271
376
|
}
|
|
272
|
-
/**
|
|
377
|
+
/**
|
|
378
|
+
* `ctx.secrets` — write app-scoped secrets (gated by the `secrets.write` capability).
|
|
379
|
+
*
|
|
380
|
+
* **Credentials only — not state.** A secret is for a value you authenticate
|
|
381
|
+
* with, like a rotated token. A cursor, a counter or a JSON blob that changes
|
|
382
|
+
* between runs is a record: keep it in `ctx.oltp`.
|
|
383
|
+
*/
|
|
273
384
|
interface OxySecretsApi {
|
|
274
385
|
set(key: string, value: string): Promise<void>;
|
|
275
386
|
}
|
|
387
|
+
/**
|
|
388
|
+
* `ctx.crypto` — HMAC signing and verification, and a constant-time compare.
|
|
389
|
+
* **Synchronous**: pure CPU inside the isolate, so these skip the host-call
|
|
390
|
+
* channel and there is nothing to `await`. Mirrors `crypto` in `__buildCtx`
|
|
391
|
+
* (`runtime.rs`); the three members here are the three the host binds.
|
|
392
|
+
*
|
|
393
|
+
* `key` and `data` are read as UTF-8 — every webhook scheme in the wild signs a
|
|
394
|
+
* UTF-8 base string with a UTF-8 secret (GitHub the body, Slack `v0:ts:body`,
|
|
395
|
+
* Stripe `ts.body`) — so there is deliberately no per-argument encoding knob.
|
|
396
|
+
*
|
|
397
|
+
* Who controls an input decides what its absence does. An unset or empty `key`,
|
|
398
|
+
* or an unknown `algorithm` / `encoding`, is the author's mistake and **throws**.
|
|
399
|
+
* A `signature` that is absent or will not decode is the caller's, and returns
|
|
400
|
+
* **`false`** — throwing would turn a forged request into a 500. Both sides of
|
|
401
|
+
* `timingSafeEqual` are symmetric, so an absent or empty side is `false` and
|
|
402
|
+
* never a throw: with the secret unset, every request is rejected.
|
|
403
|
+
*/
|
|
404
|
+
interface OxyCryptoApi {
|
|
405
|
+
/**
|
|
406
|
+
* The digest of `data` under `key`, as a string in `encoding`. For signing an
|
|
407
|
+
* **outbound** request; `verifyHmac` is the inverse direction.
|
|
408
|
+
*/
|
|
409
|
+
hmac(input: OxyHmacInput): string;
|
|
410
|
+
/**
|
|
411
|
+
* Whether `signature` is the digest of `data` under `key`, compared in
|
|
412
|
+
* constant time. Strip the provider's prefix first (`sha256=`, `v0=`) and
|
|
413
|
+
* pass the bare digest — prefix formats are per-provider. A header the caller
|
|
414
|
+
* omitted can be passed as-is: absent is `false`, not a throw.
|
|
415
|
+
*/
|
|
416
|
+
verifyHmac(input: OxyVerifyHmacInput): boolean;
|
|
417
|
+
/**
|
|
418
|
+
* Constant-time equality for a plain shared secret where there is no HMAC.
|
|
419
|
+
* Use it, not `===`, for any secret comparison: `===` short-circuits at the
|
|
420
|
+
* first differing byte and leaks the secret one byte at a time to anyone who
|
|
421
|
+
* can time the endpoint. `false` when either side is absent or empty.
|
|
422
|
+
*/
|
|
423
|
+
timingSafeEqual(a: string | null | undefined, b: string | null | undefined): boolean;
|
|
424
|
+
}
|
|
425
|
+
/** The inputs `ctx.crypto.hmac` and `ctx.crypto.verifyHmac` share. */
|
|
426
|
+
interface OxyHmacInput {
|
|
427
|
+
/** `"sha256"` (default) or `"sha512"`. Anything else throws. */
|
|
428
|
+
algorithm?: "sha256" | "sha512";
|
|
429
|
+
/**
|
|
430
|
+
* The secret, from configuration (`ctx.env.…`), never from the request.
|
|
431
|
+
* Required and non-empty: an absent one throws rather than signing with `""`
|
|
432
|
+
* or the literal `"undefined"` — keys an attacker guesses as easily as you do.
|
|
433
|
+
*/
|
|
434
|
+
key: string;
|
|
435
|
+
/** The base string to sign — for a webhook, the body or `v0:{ts}:{body}`. */
|
|
436
|
+
data: string;
|
|
437
|
+
/** How the digest is written (`hmac`) or read (`verifyHmac`): `"hex"` (default) or `"base64"`. */
|
|
438
|
+
encoding?: "hex" | "base64";
|
|
439
|
+
}
|
|
440
|
+
/** `ctx.crypto.verifyHmac`'s input: {@link OxyHmacInput} plus the signature to check. */
|
|
441
|
+
interface OxyVerifyHmacInput extends OxyHmacInput {
|
|
442
|
+
/**
|
|
443
|
+
* The bare digest the caller sent, provider prefix (`sha256=`, `v0=`) already
|
|
444
|
+
* stripped. Attacker-controlled, so a header the caller omitted may be passed
|
|
445
|
+
* as-is: absent, or not decodable in `encoding`, is `false`, never a throw.
|
|
446
|
+
*/
|
|
447
|
+
signature: string | null | undefined;
|
|
448
|
+
}
|
|
276
449
|
/** `ctx.semantic` — airlayer-compiled semantic queries (inherits the pre-agg fast path). */
|
|
277
450
|
interface OxySemanticApi {
|
|
278
451
|
/**
|
|
@@ -544,7 +717,10 @@ interface OxyStorageApi {
|
|
|
544
717
|
delete(keyOrKeys: string | string[]): Promise<{
|
|
545
718
|
deleted: number;
|
|
546
719
|
}>;
|
|
547
|
-
/**
|
|
720
|
+
/**
|
|
721
|
+
* Server-side copy within the app's silo (requires `storage.read` **and**
|
|
722
|
+
* `storage.write`: it reads the source and writes the destination).
|
|
723
|
+
*/
|
|
548
724
|
copy(fromKey: string, toPathname: string, opts?: {
|
|
549
725
|
allowOverwrite?: boolean;
|
|
550
726
|
}): Promise<StoragePutResult>;
|
|
@@ -589,7 +765,8 @@ interface OxyOrgAssignment {
|
|
|
589
765
|
/**
|
|
590
766
|
* The data-plane context passed as the second argument to a function's default
|
|
591
767
|
* export. Mirrors the host-assembled `ctx` (`__buildCtx` in `runtime.rs`);
|
|
592
|
-
* every member is a host-provided async function bridged to a Rust backend
|
|
768
|
+
* every member is a host-provided async function bridged to a Rust backend,
|
|
769
|
+
* except `crypto`, which is synchronous (pure CPU inside the isolate).
|
|
593
770
|
*/
|
|
594
771
|
interface OxyFunctionContext {
|
|
595
772
|
/** Invoking user (route) or system identity (schedule/airway). */
|
|
@@ -655,8 +832,22 @@ interface OxyFunctionContext {
|
|
|
655
832
|
env: Record<string, string>;
|
|
656
833
|
/** Structured per-invocation logging (captured + surfaced with the response). */
|
|
657
834
|
log(...args: unknown[]): void;
|
|
658
|
-
/**
|
|
659
|
-
|
|
835
|
+
/**
|
|
836
|
+
* HMAC sign / verify and a constant-time compare. Synchronous — no `await`.
|
|
837
|
+
* See {@link OxyCryptoApi}.
|
|
838
|
+
*/
|
|
839
|
+
crypto: OxyCryptoApi;
|
|
840
|
+
/**
|
|
841
|
+
* Read-only SQL (`SELECT` / `WITH` only) against the app's default database,
|
|
842
|
+
* capped at the function row limit. Resolves to `{ rows, truncated }` — the
|
|
843
|
+
* shape the host sends (`host.rs` `query`), the same as `ctx.warehouse.query`;
|
|
844
|
+
* `truncated` says the cap cut rows. Destructure it:
|
|
845
|
+
* `const { rows } = await ctx.query(sql)`.
|
|
846
|
+
*/
|
|
847
|
+
query(sql: string): Promise<{
|
|
848
|
+
rows: OxyFunctionRow[];
|
|
849
|
+
truncated: boolean;
|
|
850
|
+
}>;
|
|
660
851
|
/** Read-only SQL with a higher row cap, yielded to the caller in batches. */
|
|
661
852
|
queryStream(sql: string, opts?: {
|
|
662
853
|
batchSize?: number;
|
|
@@ -675,7 +866,11 @@ interface OxyFunctionContext {
|
|
|
675
866
|
*
|
|
676
867
|
* `database` must be in this function's manifest `destinations` — a
|
|
677
868
|
* transaction is a write, and the same fail-closed allowlist applies. Postgres
|
|
678
|
-
* only; other backends reject `ctx.tx` rather than faking it.
|
|
869
|
+
* only; other backends reject `ctx.tx` rather than faking it. A customer
|
|
870
|
+
* warehouse is refused unless named in `customerWarehouseWrites`; for the app's
|
|
871
|
+
* own OLTP store use `ctx.oltp.tx`, which needs no destination. A transaction
|
|
872
|
+
* counts as a write even when your callback only reads — `begin` cannot know —
|
|
873
|
+
* so for reads alone use `ctx.warehouse.query`.
|
|
679
874
|
*
|
|
680
875
|
* **Do not catch a failed statement and return normally.** A statement the
|
|
681
876
|
* server rejects aborts the whole transaction, and `COMMIT` on an aborted
|
|
@@ -701,20 +896,28 @@ interface OxyFunctionContext {
|
|
|
701
896
|
*/
|
|
702
897
|
tx<T>(database: string, fn: (tx: OxyTransaction) => Promise<T> | T): Promise<T>;
|
|
703
898
|
/**
|
|
704
|
-
* Read/write the app's OWN per-org OLTP schema
|
|
705
|
-
*
|
|
706
|
-
* by the fail-closed `oltp` manifest capability (`{ enabled: true }`).
|
|
707
|
-
* {@link OxyOltpApi}.
|
|
899
|
+
* **Records your app edits.** Read/write the app's OWN per-org OLTP schema
|
|
900
|
+
* (derived from its slug), with `ctx.oltp.tx` for several statements at once.
|
|
901
|
+
* Gated by the fail-closed `oltp` manifest capability (`{ enabled: true }`).
|
|
902
|
+
* See {@link OxyOltpApi}.
|
|
708
903
|
*/
|
|
709
904
|
oltp: OxyOltpApi;
|
|
905
|
+
/**
|
|
906
|
+
* **Facts: what happened.** Append-only history in the app's own Airhouse
|
|
907
|
+
* schema, written as the app. Gated by the fail-closed `airhouse` manifest
|
|
908
|
+
* capability (`{ enabled: true }`). See {@link OxyAirhouseApi}.
|
|
909
|
+
*/
|
|
910
|
+
airhouse: OxyAirhouseApi;
|
|
911
|
+
/** Credentials the app rotates — not a state store. See {@link OxySecretsApi}. */
|
|
710
912
|
secrets: OxySecretsApi;
|
|
711
913
|
semantic: OxySemanticApi;
|
|
712
914
|
airway: OxyAirwayApi;
|
|
713
915
|
email: OxyEmailApi;
|
|
916
|
+
/** **Files: bytes.** The app's private storage silo. See {@link OxyStorageApi}. */
|
|
714
917
|
storage: OxyStorageApi;
|
|
715
918
|
}
|
|
716
919
|
/** Signature of a function's default export: `export default async (req, ctx) => Response`. */
|
|
717
920
|
type OxyFunctionHandler = (req: OxyFunctionRequest, ctx: OxyFunctionContext) => Promise<Response> | Response;
|
|
718
921
|
//#endregion
|
|
719
|
-
export {
|
|
720
|
-
//# sourceMappingURL=function-context-
|
|
922
|
+
export { StoragePutOptions as A, OxyStorageApi as C, StorageDownloadUrl as D, OxyWarehouseApi as E, StorageUploadUrl as M, StorageUploadUrlInput as N, StorageListPage as O, OxySemanticApi as S, OxyVerifyHmacInput as T, OxyOrgAssignment as _, OxyAirwayApi as a, OxyReach as b, OxyFetchResult as c, OxyFunctionRequest as d, OxyFunctionRow as f, OxyOltpApi as g, OxyIdentityKind as h, OxyAirhouseApi as i, StoragePutResult as j, StorageObject as k, OxyFunctionContext as l, OxyHmacInput as m, EmailSendInput as n, OxyCryptoApi as o, OxyFunctionUser as p, EmailSendResult as r, OxyEmailApi as s, EmailAttachment as t, OxyFunctionHandler as u, OxyOrgPlace as v, OxyTransaction as w, OxySecretsApi as x, OxyOrgTeam as y };
|
|
923
|
+
//# sourceMappingURL=function-context-BNpL5bFb.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"function-context-BNpL5bFb.d.mts","names":[],"sources":["../src/custom-app/function-context.ts"],"mappings":";;;;;;;;;;UA+BiB;;;;;EAKf;;;;;;;;;;EAUA,SAAS;;EAET;;;KAMU,iBAAiB;;UAGZ;EACf;EACA;;;;;;;;;;;;;;;;;KAkBU;;;;;;;;;;;UAYK;;;;;EAKf;;;;;;;;;;EAUA;;;;;;;;;EASA;;;;EAIA;;EAEA;;;;;;;;;;;;;;;;;;;;;;EAsBA;;;;;;;;;;EAUA;;;;;;;;;;;;;;;EAeA,QAAQ;;;;;;;;;;;;;;;;;;;;;EAqBR,OAAO;;;;;;;;;;EAUP,OAAO;;;UAIQ;EACf;;EAEA;;EAEA;;;UAIe;EACf;;EAEA;;EAEA;;;;;;KAOU,eAAe;;;;;;;EAOzB;;;;;;;;;;;;;;;;UAiBe;;;;;;;;EAQf,MAAM,kBAAkB,cAAc;IAAU,MAAM;IAAkB;;EACxE,OAAO,kBAAkB,eAAe,MAAM,mBAAmB;EACjE,KAAK,kBAAkB,cAAc;;;;;;;;;;;EAWrC,OACE,kBACA,eACA,MAAM,kBACN,4BACC;;;;;;;;;;;;;;UAeY;;EAEf,MAAM,aAAa,qBAAqB,QAAQ;;EAEhD,KAAK,aAAa,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA8CxB;;EAEf,MAAM,aAAa,qBAAqB,QAAQ;;EAEhD,KAAK,aAAa,qBAAqB;;;;;;;;;;;;;;EAcvC,GAAG,GAAG,KAAK,IAAI,mBAAmB,QAAQ,KAAK,IAAI,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAoC5C;;WAEN;;EAET,MAAM,cAAc;IAAU,MAAM;IAAkB;;;;;;;EAMtD,OAAO,eAAe,MAAM,mBAAmB;;;;;;EAM/C,KAAK,cAAc;;;;;;;;;UAUJ;EACf,IAAI,aAAa,gBAAgB;;;;;;;;;;;;;;;;;;;UAoBlB;;;;;EAKf,KAAK,OAAO;;;;;;;EAOZ,WAAW,OAAO;;;;;;;EAOlB,gBAAgB,8BAA8B;;;UAI/B;;EAEf;;;;;;EAMA;;EAEA;;EAEA;;;UAIe,2BAA2B;;;;;;EAM1C;;;UAIe;;;;;;;;;EASf,MAAM,MAAM;IAA4B;MAAoB;;;UAI7C;EACf,IAAI,qBAAqB,YAAY,iCAAiC;IAAU;;;;;;;;;UAWjE;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;;;;;EAMA;;;;;;;;;EASA,cAAc;;;UAIC;;EAEf;;;;;EAKA;;;;;;;;;;;;EAYA;;EAEA;;EAEA;;EAEA;;;UAIe;;EAEf;;;UAIe;EACf,KAAK,OAAO,iBAAiB,QAAQ;;;UAMtB;;;;;;EAMf;;EAEA;;EAEA;;;;;;EAMA;;EAEA;;;UAIe;;EAEf;;;;;;EAMA;;EAEA;;;;;;;;;;;;;;;;;;;;;;;;EAwBA;;;UAIe;EACf;EACA;;;UAIe;EACf;EACA;EACA;;EAEA;;;UAIe;EACf,SAAS;;EAET;EACA;;;UAIe;;EAEf;;;;;EAKA;;EAEA;;;;;EAKA;;EAEA;;;UAIe;EACf;EACA;EACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAiCe;;EAEf,aAAa,OAAO,wBAAwB,QAAQ;;;;;EAKpD,eACE,aACA;IAAS;IAA2B;MACnC,QAAQ;;;;;EAKX,IAAI,kBAAkB,cAAc,OAAO,oBAAoB,QAAQ;;EAEvE,IACE,aACA;IAAS;MACR;IAAU;IAAc;IAA4B;IAAc;;;EAErE,KAAK,cAAc,QAAQ;;;;;EAK3B,KAAK;IAAS;IAAiB;IAAgB;MAAoB,QAAQ;;;;;;EAM3E,OAAO,+BAA+B;IAAU;;;;;;EAKhD,KACE,iBACA,oBACA;IAAS;MACR,QAAQ;;;UAMI;EACf;EACA;EACA;;EAEA;;EAEA;EACA;;EAEA;;EAEA;;EAEA,cAAc;EACd;EACA;;;UAIe;EACf;EACA;EACA;EACA;EACA;EACA;;EAEA;;EAEA;EACA;;EAEA;EACA;EACA;;;;;;;;UASe;;EAEf,MAAM;;;;;;;;;;;;;;;;;;;;;;;;EAwBN;IACE,UAAU;MACR,QAAQ;QACN;QACA;;QAEA;QACA;;MAEF;;;;;;;;;;IAUF,UAAU;MAAU,QAAQ;MAAe;;;;;;;;IAO3C,eAAe;MAAU,aAAa;MAAoB;;;;EAG5D,KAAK;;EAEL,OAAO;;;;;EAKP,QAAQ;;;;;;;;EAQR,MAAM,cAAc;IAAU,MAAM;IAAkB;;;EAEtD,YACE,aACA;IAAS;MACR,eAAe;;;;;;EAMlB,MAAM,aAAa,OAAO,eAAe,QAAQ;EACjD,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCX,GAAG,GAAG,kBAAkB,KAAK,IAAI,mBAAmB,QAAQ,KAAK,IAAI,QAAQ;;;;;;;EAO7E,MAAM;;;;;;EAMN,UAAU;;EAEV,SAAS;EACT,UAAU;EACV,QAAQ;EACR,OAAO;;EAEP,SAAS;;;KAIC,sBACV,KAAK,oBACL,KAAK,uBACF,QAAQ,YAAY"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// @oxy/sdk - TypeScript SDK for Oxy data platform
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
3
|
-
const
|
|
3
|
+
const require_rolldown_runtime = require('./rolldown-runtime-KC0qvQup.cjs');
|
|
4
|
+
const require_react = require('./react-Dvkv2deI.cjs');
|
|
4
5
|
let react = require("react");
|
|
5
|
-
react =
|
|
6
|
+
react = require_rolldown_runtime.__toESM(react, 1);
|
|
6
7
|
|
|
7
8
|
//#region src/anomalies.ts
|
|
8
9
|
/** Which buckets a write may touch when the caller didn't say. Live statuses
|
|
@@ -318,7 +319,7 @@ function useMetricTreeEndpoint(key, run, enabled) {
|
|
|
318
319
|
const [data, setData] = react.useState(null);
|
|
319
320
|
const [loading, setLoading] = react.useState(enabled && key !== null);
|
|
320
321
|
const [error, setError] = react.useState(null);
|
|
321
|
-
const [
|
|
322
|
+
const [nonce, setNonce] = react.useState(0);
|
|
322
323
|
const runRef = react.useRef(run);
|
|
323
324
|
runRef.current = run;
|
|
324
325
|
react.useEffect(() => {
|
|
@@ -336,15 +337,18 @@ function useMetricTreeEndpoint(key, run, enabled) {
|
|
|
336
337
|
setLoading(false);
|
|
337
338
|
}).catch((err) => {
|
|
338
339
|
if (cancelled) return;
|
|
339
|
-
|
|
340
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
340
|
+
setError(require_react.asReportableError(err));
|
|
341
341
|
setLoading(false);
|
|
342
342
|
});
|
|
343
343
|
return () => {
|
|
344
344
|
cancelled = true;
|
|
345
345
|
ctrl.abort();
|
|
346
346
|
};
|
|
347
|
-
}, [
|
|
347
|
+
}, [
|
|
348
|
+
key,
|
|
349
|
+
enabled,
|
|
350
|
+
nonce
|
|
351
|
+
]);
|
|
348
352
|
return {
|
|
349
353
|
data,
|
|
350
354
|
loading,
|
|
@@ -563,7 +567,7 @@ function useWorldModelGraph(opts = {}) {
|
|
|
563
567
|
const [data, setData] = react.useState(null);
|
|
564
568
|
const [loading, setLoading] = react.useState(enabled && !!projectId);
|
|
565
569
|
const [error, setError] = react.useState(null);
|
|
566
|
-
const [
|
|
570
|
+
const [nonce, setNonce] = react.useState(0);
|
|
567
571
|
react.useEffect(() => {
|
|
568
572
|
if (!enabled || !projectId) {
|
|
569
573
|
setLoading(false);
|
|
@@ -585,8 +589,7 @@ function useWorldModelGraph(opts = {}) {
|
|
|
585
589
|
setLoading(false);
|
|
586
590
|
}).catch((err) => {
|
|
587
591
|
if (cancelled) return;
|
|
588
|
-
|
|
589
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
592
|
+
setError(require_react.asReportableError(err));
|
|
590
593
|
setLoading(false);
|
|
591
594
|
});
|
|
592
595
|
return () => {
|
|
@@ -596,7 +599,8 @@ function useWorldModelGraph(opts = {}) {
|
|
|
596
599
|
}, [
|
|
597
600
|
enabled,
|
|
598
601
|
projectId,
|
|
599
|
-
fetcher
|
|
602
|
+
fetcher,
|
|
603
|
+
nonce
|
|
600
604
|
]);
|
|
601
605
|
return {
|
|
602
606
|
data,
|
|
@@ -617,7 +621,7 @@ function useWorldModelInstances(entityId, opts = {}) {
|
|
|
617
621
|
const [data, setData] = react.useState(null);
|
|
618
622
|
const [loading, setLoading] = react.useState(enabled && !!projectId && !!entityId);
|
|
619
623
|
const [error, setError] = react.useState(null);
|
|
620
|
-
const [
|
|
624
|
+
const [nonce, setNonce] = react.useState(0);
|
|
621
625
|
react.useEffect(() => {
|
|
622
626
|
if (!enabled || !projectId || !entityId) {
|
|
623
627
|
setLoading(false);
|
|
@@ -646,8 +650,7 @@ function useWorldModelInstances(entityId, opts = {}) {
|
|
|
646
650
|
setLoading(false);
|
|
647
651
|
}).catch((err) => {
|
|
648
652
|
if (cancelled) return;
|
|
649
|
-
|
|
650
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
653
|
+
setError(require_react.asReportableError(err));
|
|
651
654
|
setLoading(false);
|
|
652
655
|
});
|
|
653
656
|
return () => {
|
|
@@ -662,7 +665,8 @@ function useWorldModelInstances(entityId, opts = {}) {
|
|
|
662
665
|
limit,
|
|
663
666
|
fetcher,
|
|
664
667
|
scope,
|
|
665
|
-
appId
|
|
668
|
+
appId,
|
|
669
|
+
nonce
|
|
666
670
|
]);
|
|
667
671
|
return {
|
|
668
672
|
data,
|
|
@@ -740,8 +744,7 @@ function useMeasureBreakdown(entityId, keyValue, measure) {
|
|
|
740
744
|
if (!cancelled) setLoading(false);
|
|
741
745
|
}).catch((err) => {
|
|
742
746
|
if (cancelled) return;
|
|
743
|
-
|
|
744
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
747
|
+
setError(require_react.asReportableError(err));
|
|
745
748
|
setLoading(false);
|
|
746
749
|
});
|
|
747
750
|
return () => {
|
|
@@ -1086,6 +1089,66 @@ var MetricTreeClient = class {
|
|
|
1086
1089
|
}
|
|
1087
1090
|
};
|
|
1088
1091
|
|
|
1092
|
+
//#endregion
|
|
1093
|
+
//#region src/peerCohort.ts
|
|
1094
|
+
/**
|
|
1095
|
+
* Client for the `/semantic/cohort` endpoint. Surfaces airlayer's peer-cohort
|
|
1096
|
+
* benchmarking — comparing an entity's subjects against their declared peers
|
|
1097
|
+
* on a measure, with exclusions explained rather than silently dropped.
|
|
1098
|
+
*
|
|
1099
|
+
* Construction is internal to {@link OxyClient} — call `client.peerCohort`
|
|
1100
|
+
* to access an instance rather than building one yourself.
|
|
1101
|
+
*
|
|
1102
|
+
* @example
|
|
1103
|
+
* ```typescript
|
|
1104
|
+
* const client = await OxyClient.create({ projectId: "...", apiKey: "..." });
|
|
1105
|
+
* const result = await client.peerCohort.resolve({
|
|
1106
|
+
* entity: "restaurant_id",
|
|
1107
|
+
* measure: "orders.net_revenue",
|
|
1108
|
+
* time_dimension: "orders.order_date",
|
|
1109
|
+
* period: ["2025-09-01", "2025-09-30"],
|
|
1110
|
+
* });
|
|
1111
|
+
* for (const excluded of result.excluded) {
|
|
1112
|
+
* console.warn(excluded.key, excluded.reason);
|
|
1113
|
+
* }
|
|
1114
|
+
* ```
|
|
1115
|
+
*/
|
|
1116
|
+
var PeerCohortClient = class {
|
|
1117
|
+
constructor(config, request) {
|
|
1118
|
+
this.config = config;
|
|
1119
|
+
this.request = request;
|
|
1120
|
+
}
|
|
1121
|
+
path(suffix) {
|
|
1122
|
+
return `/${this.config.projectId}${suffix}`;
|
|
1123
|
+
}
|
|
1124
|
+
buildQuery(extra = {}) {
|
|
1125
|
+
const params = { ...extra };
|
|
1126
|
+
if (this.config.branch) params.branch = this.config.branch;
|
|
1127
|
+
const qs = new URLSearchParams(params).toString();
|
|
1128
|
+
return qs ? `?${qs}` : "";
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Resolve a subject's peer cohort and every peer's comparison against it.
|
|
1132
|
+
*
|
|
1133
|
+
* @example
|
|
1134
|
+
* ```typescript
|
|
1135
|
+
* const result = await client.peerCohort.resolve({
|
|
1136
|
+
* entity: "restaurant_id",
|
|
1137
|
+
* measure: "orders.net_revenue",
|
|
1138
|
+
* time_dimension: "orders.order_date",
|
|
1139
|
+
* period: ["2025-09-01", "2025-09-30"],
|
|
1140
|
+
* });
|
|
1141
|
+
* ```
|
|
1142
|
+
*/
|
|
1143
|
+
async resolve(request) {
|
|
1144
|
+
const query = this.buildQuery();
|
|
1145
|
+
return this.request(this.path(`/semantic/cohort${query}`), {
|
|
1146
|
+
method: "POST",
|
|
1147
|
+
body: JSON.stringify(request)
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
};
|
|
1151
|
+
|
|
1089
1152
|
//#endregion
|
|
1090
1153
|
exports.AnomaliesClient = AnomaliesClient;
|
|
1091
1154
|
exports.MetricTreeClient = MetricTreeClient;
|
|
@@ -1093,6 +1156,7 @@ exports.OxyAnswer = require_react.OxyAnswer;
|
|
|
1093
1156
|
exports.OxyApiError = require_react.OxyApiError;
|
|
1094
1157
|
exports.OxyAppProvider = require_react.OxyAppProvider;
|
|
1095
1158
|
exports.OxyChat = require_react.OxyChat;
|
|
1159
|
+
exports.PeerCohortClient = PeerCohortClient;
|
|
1096
1160
|
exports.WorldModelScopeUnsupportedError = WorldModelScopeUnsupportedError;
|
|
1097
1161
|
exports._resetCustomAppManifestCacheForTest = require_react._resetCustomAppManifestCacheForTest;
|
|
1098
1162
|
exports.apiErrorFromResponse = require_react.apiErrorFromResponse;
|