primitive-functions 0.2.0-alpha.6 → 0.2.0-alpha.8

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.
Files changed (2) hide show
  1. package/index.d.ts +223 -24
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -74,7 +74,16 @@ export type FunctionTrigger =
74
74
  * parent was a request invocation over HTTP, which writes no run row, or a
75
75
  * database-change fire, which writes none either.
76
76
  */
77
- | { kind: "function"; functionKey: string; runId: string | null };
77
+ | { kind: "function"; functionKey: string; runId: string | null }
78
+ /**
79
+ * An admin ran this function as the SYSTEM, from outside any trigger
80
+ * (#3448) — `primitive functions invoke --as system`.
81
+ *
82
+ * `ctx.user` is null and the code runs with the app's system authority, as
83
+ * it does for a cron or webhook fire. `userId` names the admin who asked:
84
+ * attribution, never the principal the code runs as.
85
+ */
86
+ | { kind: "manual"; userId: string };
78
87
 
79
88
  /** The result shape of an operation that answers in response headers. */
80
89
  export interface HeaderResult {
@@ -862,6 +871,11 @@ export interface FunctionApi {
862
871
  "getSchema"(args: {
863
872
  "documentId": string | number;
864
873
  }): Promise<any>;
874
+ /** `documents.getSnapshot` — GET /documents/{documentId}/snapshots/{buildId}. One snapshot build with its verification result */
875
+ "getSnapshot"(args: {
876
+ "documentId": string | number;
877
+ "buildId": string | number;
878
+ }): Promise<any>;
865
879
  /** `documents.getStats` — GET /documents/{documentId}/stats. Document statistics (record/model/blob counts, approximate size) */
866
880
  "getStats"(args: {
867
881
  "documentId": string | number;
@@ -903,6 +917,12 @@ export interface FunctionApi {
903
917
  "listPendingInvitations"(args: {
904
918
  "documentId": string | number;
905
919
  }): Promise<any>;
920
+ /** `documents.listSnapshots` — GET /documents/{documentId}/snapshots. List a large document's snapshot builds, newest first */
921
+ "listSnapshots"(args: {
922
+ "documentId": string | number;
923
+ "limit"?: string | number | boolean;
924
+ "cursor"?: string | number | boolean;
925
+ }): Promise<any>;
906
926
  /** `documents.open` — POST /documents/open. Open a document for collaboration (resolves access + alias) */
907
927
  "open"(args: {
908
928
  body: unknown;
@@ -1016,11 +1036,17 @@ export interface FunctionApi {
1016
1036
  "functionKey": string | number;
1017
1037
  body?: unknown;
1018
1038
  }): Promise<any>;
1039
+ /** `functions.invokeAsSystem` — POST /functions/{functionKey}/invoke-as-system. Invoke a server function as the system, with no caller */
1040
+ "invokeAsSystem"(args: {
1041
+ "functionKey": string | number;
1042
+ body?: unknown;
1043
+ }): Promise<any>;
1019
1044
  /** `functions.logs` — GET /functions/{functionKey}/logs. List a server function's invocation logs, newest first */
1020
1045
  "logs"(args: {
1021
1046
  "functionKey": string | number;
1022
1047
  "limit"?: string | number | boolean;
1023
1048
  "cursor"?: string | number | boolean;
1049
+ "runId"?: string | number | boolean;
1024
1050
  }): Promise<any>;
1025
1051
  /** `functions.start` — POST /functions/{functionKey}/start. Start a task function from inside another server function */
1026
1052
  "start"(args: {
@@ -1342,12 +1368,19 @@ export type FunctionOutput<K extends string> = K extends keyof FunctionSchemas
1342
1368
  : any
1343
1369
  : any;
1344
1370
 
1345
- /** A declared function's mode, fixed at generation time. */
1371
+ /**
1372
+ * A declared function's mode, fixed at generation time.
1373
+ *
1374
+ * `"any"` — the default when the authored file names no mode (#3454) — takes
1375
+ * EITHER runner and the caller picks at call time; `"request"` and `"task"`
1376
+ * lock it to one. An UNDECLARED key is the whole union, because nothing has
1377
+ * said which of the three it is.
1378
+ */
1346
1379
  export type FunctionMode<K extends string> = K extends keyof FunctionSchemas
1347
1380
  ? FunctionSchemas[K] extends { mode: infer M }
1348
1381
  ? M
1349
- : "request" | "task"
1350
- : "request" | "task";
1382
+ : "request" | "task" | "any"
1383
+ : "request" | "task" | "any";
1351
1384
 
1352
1385
  /**
1353
1386
  * The model names one database type addresses — its own, or any name at all
@@ -1358,9 +1391,38 @@ export type DatabaseModelNames<TModels> = [keyof TModels] extends [never]
1358
1391
  ? string
1359
1392
  : keyof TModels & string;
1360
1393
 
1394
+ /**
1395
+ * A row as the platform HANDS IT BACK: whatever the schema declared, plus the
1396
+ * record identity the platform owns (#3450).
1397
+ *
1398
+ * Every stored record has an `id`. A save that arrives without one is given a
1399
+ * ULID, a projection always keeps it, and `delete` and `patch` take nothing
1400
+ * else — so a function that queries a model and then moves one of its rows
1401
+ * needs the id of the row it just read. A schema is free to say nothing about
1402
+ * that field, and most do; the identity is the platform's, not the schema's,
1403
+ * so it is added here rather than rendered into each declaration.
1404
+ *
1405
+ * A declared `id` is REPLACED, never intersected: one declared optional would
1406
+ * stay optional on a read row it is always present on, and one declared with
1407
+ * some other type would intersect to `never` and be unusable. The platform
1408
+ * stamps a string whatever the schema says.
1409
+ *
1410
+ * An `any` row stays `any` — `DatabaseHandle<any>` is `defineQuery`'s default
1411
+ * handle, and turning its rows into an object with one known member would
1412
+ * narrow code that was deliberately left open.
1413
+ *
1414
+ * Writes are untouched: every one of them takes `Partial<TRow>`, so a row a
1415
+ * function BUILDS still needs no id.
1416
+ */
1417
+ export type PlatformRow<TRow> = 0 extends 1 & TRow
1418
+ ? TRow
1419
+ : Omit<TRow, "id"> & { id: string };
1420
+
1361
1421
  /** One model's row shape, open when the type declares no schema. */
1362
1422
  export type DatabaseModelRow<TModels, M extends string> =
1363
- M extends keyof TModels ? TModels[M] : Record<string, unknown>;
1423
+ M extends keyof TModels
1424
+ ? PlatformRow<TModels[M]>
1425
+ : Record<string, unknown> & { id: string };
1364
1426
 
1365
1427
  /**
1366
1428
  * One model of one database, scoped: the `modelName` every records call needs
@@ -1404,6 +1466,29 @@ export interface DatabaseModelHandle<TRow> {
1404
1466
  count(body?: ModelScopedBody): Promise<any>;
1405
1467
  aggregate(body: ModelScopedBody): Promise<any>;
1406
1468
  save(body: ModelScopedBody<{ id?: string; data: Partial<TRow>; [key: string]: unknown }>): Promise<any>;
1469
+ /**
1470
+ * Change some fields of ONE row — `databases.records.patch`, with this
1471
+ * handle's model bound (#3450).
1472
+ *
1473
+ * The record id is positional and the body may not carry another, for the
1474
+ * same reason it may not name another model: the runtime assigns both LAST,
1475
+ * so a body that appeared to choose either would be a lie about which row
1476
+ * moved. `condition`, `stringSets` and the rest of the operation's own keys
1477
+ * pass through untouched.
1478
+ */
1479
+ patch(
1480
+ recordId: string,
1481
+ body: ModelScopedBody<{ data: Partial<TRow>; id?: never; [key: string]: unknown }>
1482
+ ): Promise<any>;
1483
+ /**
1484
+ * Remove ONE row by the id a read handed back — `databases.records.delete`,
1485
+ * with this handle's model bound (#3450). An optional `condition` makes it
1486
+ * conditional, and travels untouched.
1487
+ */
1488
+ delete(
1489
+ recordId: string,
1490
+ body?: ModelScopedBody<{ condition?: Record<string, unknown>; id?: never }>
1491
+ ): Promise<any>;
1407
1492
  /** Several writes to THIS model in one request; the binding is per item. */
1408
1493
  batch(body: {
1409
1494
  operations: Array<ModelBatchOperation<TRow>>;
@@ -1445,10 +1530,15 @@ export type DocumentModelNames = [keyof DocumentSchemas] extends [never]
1445
1530
  ? string
1446
1531
  : keyof DocumentSchemas & string;
1447
1532
 
1448
- /** A document model's row shape, or an open record for an undeclared schema. */
1533
+ /**
1534
+ * A document model's row shape, or an open record for an undeclared schema —
1535
+ * carrying the platform's record identity either way (#3450), by the same rule
1536
+ * and for the same reason as a database row: the records DO is one
1537
+ * implementation, and `patch` and `delete` here take an id too.
1538
+ */
1449
1539
  export type DocumentModelRow<M extends string> = M extends keyof DocumentSchemas
1450
- ? DocumentSchemas[M]
1451
- : Record<string, unknown>;
1540
+ ? PlatformRow<DocumentSchemas[M]>
1541
+ : Record<string, unknown> & { id: string };
1452
1542
 
1453
1543
  /** The options a document model read takes: a filter object (or its JSON), a page size, a cursor. */
1454
1544
  export interface DocumentQueryOptions {
@@ -1517,15 +1607,94 @@ export interface PromptRunArgs {
1517
1607
  configId?: string;
1518
1608
  }
1519
1609
 
1520
- /** The member execute envelope, unchanged on the function path. */
1521
- export interface PromptRunResult {
1610
+ /**
1611
+ * The app's PROMPTS — EMPTY here and filled by the declaration
1612
+ * `primitive config push` writes into the config tree's `functions/` directory
1613
+ * (`primitive-prompt-types.d.ts`, from the tree's `prompts/*.toml`). A prompt
1614
+ * that declares an `outputSchema` carries `{ output: <Key>PromptOutput }`; one
1615
+ * that declares none carries `{}`, so reading `parsed.field` on it is a
1616
+ * compile error rather than a runtime `undefined`.
1617
+ */
1618
+ export interface PromptSchemas {}
1619
+
1620
+ /** The keys `ctx.prompts.run` accepts — every declared one, or `string` before a push. */
1621
+ export type PromptKeys = [keyof PromptSchemas] extends [never]
1622
+ ? string
1623
+ : keyof PromptSchemas & string;
1624
+
1625
+ /** One prompt's declared output type, or `unknown` where none is declared. */
1626
+ export type PromptOutput<K extends string> = K extends keyof PromptSchemas
1627
+ ? PromptSchemas[K] extends { output: infer O }
1628
+ ? O
1629
+ : unknown
1630
+ : unknown;
1631
+
1632
+ /**
1633
+ * Why a prompt's own answer was refused — #3330. Never set on a PROVIDER
1634
+ * failure, which is what makes "the model returned the wrong shape"
1635
+ * distinguishable from "the model failed".
1636
+ */
1637
+ export type PromptOutputErrorCode =
1638
+ | "PROMPT_OUTPUT_NOT_JSON"
1639
+ | "PROMPT_OUTPUT_SCHEMA_VIOLATION";
1640
+
1641
+ /** A prompt that declares an output shape, when the answer matched it. */
1642
+ export interface PromptRunSuccess<TParsed> {
1643
+ success: true;
1644
+ output: string;
1645
+ /** The parsed, validated answer — no caller-side `JSON.parse` (#3330). */
1646
+ parsed: TParsed;
1647
+ error?: null;
1648
+ errorCode?: null;
1649
+ metrics?: Record<string, unknown>;
1650
+ configId: string;
1651
+ }
1652
+
1653
+ /**
1654
+ * The failure arm, whichever failed. `errorCode` is set for a SHAPE failure
1655
+ * and absent for a provider one; `output` carries the text either way, which
1656
+ * is where the model's own value lives — a validation `error` names paths and
1657
+ * schema constraints only.
1658
+ */
1659
+ export interface PromptRunFailure {
1660
+ success: false;
1661
+ output: string;
1662
+ error: string | null;
1663
+ errorCode?: PromptOutputErrorCode | null;
1664
+ parsed?: undefined;
1665
+ metrics?: Record<string, unknown>;
1666
+ configId: string;
1667
+ }
1668
+
1669
+ /** The envelope for a key whose declaration says nothing about its output. */
1670
+ export interface PromptRunOpenResult {
1522
1671
  success: boolean;
1523
1672
  output: string;
1673
+ /**
1674
+ * Present when the config that ran declares `outputFormat = "json"` and the
1675
+ * text parsed. Untyped: nothing declared its shape.
1676
+ */
1677
+ parsed?: unknown;
1524
1678
  error?: string | null;
1679
+ errorCode?: PromptOutputErrorCode | null;
1525
1680
  metrics?: Record<string, unknown>;
1526
1681
  configId: string;
1527
1682
  }
1528
1683
 
1684
+ /**
1685
+ * The member execute envelope, plus what the prompt's own declaration adds.
1686
+ *
1687
+ * For a key whose `prompts/<key>.toml` declares an `outputSchema`, this is a
1688
+ * discriminated union: narrow on `success` and `parsed` is the declared type,
1689
+ * required. For every other key — and in a tree that has not pushed — it is
1690
+ * the open shape, with `parsed` optional and `unknown`.
1691
+ */
1692
+ export type PromptRunResult<K extends string = string> = K extends keyof PromptSchemas
1693
+ ? PromptSchemas[K] extends { output: infer O }
1694
+ ? PromptRunSuccess<O> | PromptRunFailure
1695
+ : PromptRunOpenResult
1696
+ : PromptRunOpenResult;
1697
+
1529
1698
  /** What a send delivered to. */
1530
1699
  export interface SendResult {
1531
1700
  /** Unique live connections the frame was sent to. Zero is a success. */
@@ -1673,14 +1842,33 @@ export interface FunctionContext {
1673
1842
  ): Promise<FunctionStartResult>;
1674
1843
  };
1675
1844
  /**
1676
- * Run one of the app's prompts, under a `prompt:<key>` grant (#3183).
1845
+ * Run one of the app's prompts, with nothing to declare (#3183, #3279).
1677
1846
  *
1678
1847
  * The prompt's `accessRule` is not consulted — it states which MEMBERS may
1679
- * execute the prompt from a client, and the grant is what authorizes this
1680
- * call. The provider request is bounded by the invocation's own deadline.
1848
+ * execute the prompt from a client, and the invocation gate is what
1849
+ * authorized this call. The provider request is bounded by the invocation's
1850
+ * own deadline.
1851
+ *
1852
+ * TYPED BY KEY (#3330). Where `prompts/<key>.toml` declares an
1853
+ * `outputSchema`, the platform parses the answer, validates it against that
1854
+ * schema and hands it back as `parsed`, typed — so the shape is written once
1855
+ * in TOML instead of restated as a `JSON.parse` at every call site. Where
1856
+ * only the config that ran declares `outputFormat = "json"`, `parsed` is
1857
+ * present but `unknown`. Where neither is declared the envelope is exactly
1858
+ * what it has always been.
1859
+ *
1860
+ * A shape the declaration refuses is `success: false` with an `errorCode`
1861
+ * (`PROMPT_OUTPUT_NOT_JSON` or `PROMPT_OUTPUT_SCHEMA_VIOLATION`) and the
1862
+ * text still in `output`; a PROVIDER failure has `error` and no
1863
+ * `errorCode`, so the two are told apart without guessing.
1864
+ *
1865
+ * Once a tree has pushed, a key it does not declare is a compile error.
1681
1866
  */
1682
1867
  prompts: {
1683
- run(promptKey: string, args?: PromptRunArgs): Promise<PromptRunResult>;
1868
+ run<K extends PromptKeys>(
1869
+ promptKey: K,
1870
+ args?: PromptRunArgs
1871
+ ): Promise<PromptRunResult<K>>;
1684
1872
  };
1685
1873
  /**
1686
1874
  * The value of one app secret, under a `secret:<NAME>` grant (#3183).
@@ -1750,13 +1938,22 @@ export interface FunctionContext {
1750
1938
  }
1751
1939
 
1752
1940
  /**
1753
- * The durable step handle — Cloudflare Workflows' `WorkflowStep`, forwarded
1754
- * untouched, so `step.do` results are memoized and `step.sleep` hibernates.
1941
+ * The step handle. `step` is the third argument under BOTH runners, so the
1942
+ * same body runs either way — which is what `mode = "any"` is for (#3454).
1943
+ *
1944
+ * Under the TASK runner it is Cloudflare Workflows' `WorkflowStep`, forwarded
1945
+ * untouched: `step.do` results are memoized and replayed, and `step.sleep`
1946
+ * hibernates.
1755
1947
  *
1756
- * A SYNCHRONOUS invocation gets a passthrough shim of the same shape, so a body
1757
- * written for durable mode runs either way: `do` executes the body (nothing to
1758
- * memoize into without an engine), `sleep` resolves immediately (the sync
1759
- * ceiling is seconds), and `waitForEvent` throws `STEP_NOT_AVAILABLE`.
1948
+ * Under the REQUEST runner it is the platform's own, bounded by the request's
1949
+ * clock: `do` executes the body inline (there is no engine to memoize into,
1950
+ * and nothing is replayed); `sleep` and `sleepUntil` REALLY wait when the
1951
+ * remaining request budget covers the duration, and otherwise fail the
1952
+ * invocation with `errorCode: "FUNCTION_STEP_NEEDS_TASK"` saying to start the
1953
+ * function as a task; `waitForEvent` fails the same way, because nothing can
1954
+ * deliver an event to an invocation that has to return now. The thrown error's
1955
+ * `name` is `STEP_NOT_AVAILABLE` in every case, so a body that catches it
1956
+ * keeps catching it.
1760
1957
  */
1761
1958
  export interface FunctionStep {
1762
1959
  do<T>(name: string, body: () => T | Promise<T>): Promise<T>;
@@ -1778,10 +1975,12 @@ export declare const SDK_STUB_VERSION: string;
1778
1975
  /**
1779
1976
  * The handler a function exports, typed for one declared key.
1780
1977
  *
1781
- * `step` is the third argument in BOTH modes (#3186). A task run gets the
1782
- * engine's live `WorkflowStep`; a request invocation gets a passthrough shim
1783
- * (`do` runs the body, `sleep` resolves at once, `waitForEvent` throws a
1784
- * named error), so a task-authored body can be exercised as a request.
1978
+ * `step` is the third argument under BOTH runners (#3186, #3454). A task run
1979
+ * gets the engine's live `WorkflowStep`; a request invocation gets the
1980
+ * platform's own, where `do` runs the body inline and a wait the request
1981
+ * budget cannot cover fails the invocation naming the task runner — so a
1982
+ * task-authored body can be exercised as a request, and the one place the two
1983
+ * genuinely differ says so rather than pretending.
1785
1984
  */
1786
1985
  export type FunctionHandler<TInput, TOutput> = (
1787
1986
  input: TInput,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primitive-functions",
3
- "version": "0.2.0-alpha.6",
3
+ "version": "0.2.0-alpha.8",
4
4
  "description": "The module a Primitive server function imports. Supplied by the platform at invoke time; reserved here so the name is ours before the runtime lands.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "Primitive LLC",