primitive-functions 0.2.0-alpha.8 → 0.2.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.
Files changed (3) hide show
  1. package/index.d.ts +360 -78
  2. package/index.js +30 -0
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -32,8 +32,15 @@ export interface FunctionUser {
32
32
  * that the fire path does not set.
33
33
  */
34
34
  export type FunctionTrigger =
35
- /** An HTTP invocation: the caller is `ctx.user`. */
36
- | { kind: "http" }
35
+ /**
36
+ * An HTTP invocation: the caller is `ctx.user`.
37
+ *
38
+ * `runKey` is the key a `start` was coalesced by (#3562) — what you
39
+ * passed as `runKey` to make the run a singleton — and null when the
40
+ * start named none, or when the call was an `invoke`, which coalesces
41
+ * nothing.
42
+ */
43
+ | { kind: "http"; runKey: string | null }
37
44
  /** A verified webhook delivery to the function's own key. */
38
45
  | {
39
46
  kind: "webhook";
@@ -56,8 +63,6 @@ export type FunctionTrigger =
56
63
  /** Present, and true, only on the diagnostic fire: nothing was scheduled. */
57
64
  manual?: true;
58
65
  }
59
- /** A write to a watched database type. */
60
- | { kind: "database"; databaseId: string; databaseType: string }
61
66
  /**
62
67
  * A DSL workflow's `workflow.call` step reached this function (#3288).
63
68
  *
@@ -71,19 +76,25 @@ export type FunctionTrigger =
71
76
  * Another function started this one with `ctx.functions.start` (#3280).
72
77
  *
73
78
  * `functionKey` names the PARENT, and `runId` its run — null when the
74
- * parent was a request invocation over HTTP, which writes no run row, or a
75
- * database-change fire, which writes none either.
79
+ * parent was a request invocation over HTTP, which writes no run row.
80
+ * `runKey` is the key the parent's start named, or null (#3562).
76
81
  */
77
- | { kind: "function"; functionKey: string; runId: string | null }
82
+ | {
83
+ kind: "function";
84
+ functionKey: string;
85
+ runId: string | null;
86
+ runKey: string | null;
87
+ }
78
88
  /**
79
89
  * An admin ran this function as the SYSTEM, from outside any trigger
80
90
  * (#3448) — `primitive functions invoke --as system`.
81
91
  *
82
92
  * `ctx.user` is null and the code runs with the app's system authority, as
83
93
  * it does for a cron or webhook fire. `userId` names the admin who asked:
84
- * attribution, never the principal the code runs as.
94
+ * attribution, never the principal the code runs as. `runKey` is the key
95
+ * the admin's start named, or null (#3562).
85
96
  */
86
- | { kind: "manual"; userId: string };
97
+ | { kind: "manual"; userId: string; runKey: string | null };
87
98
 
88
99
  /** The result shape of an operation that answers in response headers. */
89
100
  export interface HeaderResult {
@@ -103,7 +114,7 @@ export interface PrimitivePlatformError extends Error {
103
114
 
104
115
  /**
105
116
  * The typed HTTP profile, generated from the platform's OpenAPI document. Its
106
- * namespaces mirror the operation ids: analytics, blobBuckets, channels, collections, configVars, connections, databaseTypeConfigs, databases, documents, email, functions, gemini, groups, integrations, llm, locks, notifications, prompts, resourceMetadata, secrets, users.
117
+ * namespaces mirror the operation ids: analytics, blobBuckets, channels, collections, configVars, connections, databaseTypeConfigs, databases, documents, email, functions, groups, integrations, locks, notifications, prompts, resourceMetadata, secrets, users.
107
118
  * Methods take one options object carrying the operation's path parameters,
108
119
  * query parameters, request headers (under their wire names) and `body`.
109
120
  *
@@ -358,6 +369,8 @@ export interface FunctionApi {
358
369
  /** `collections.listCollectionsForDocument` — GET /documents/{documentId}/collections. List collections a document belongs to (reverse lookup) */
359
370
  "listCollectionsForDocument"(args: {
360
371
  "documentId": string | number;
372
+ "limit"?: string | number | boolean;
373
+ "cursor"?: string | number | boolean;
361
374
  }): Promise<any>;
362
375
  /** `collections.listDocuments` — GET /collections/{collectionId}/documents. List documents in a collection */
363
376
  "listDocuments"(args: {
@@ -497,32 +510,50 @@ export interface FunctionApi {
497
510
  body: unknown;
498
511
  }): Promise<any>;
499
512
  "adminData": {
500
- /** `databases.adminData.batch` — POST /databases/{databaseId}/admin-data/batch. DEPRECATED — direct database batch; use databases/{databaseId}/records/batch */
513
+ /**
514
+ * `databases.adminData.batch` — POST /databases/{databaseId}/admin-data/batch. DEPRECATED — direct database batch; use databases/{databaseId}/records/batch
515
+ * @deprecated Use databases/{databaseId}/records/batch
516
+ */
501
517
  "batch"(args: {
502
518
  "databaseId": string | number;
503
519
  body: unknown;
504
520
  }): Promise<any>;
505
- /** `databases.adminData.count` — POST /databases/{databaseId}/admin-data/count. DEPRECATED — direct database count; use databases/{databaseId}/records/count */
521
+ /**
522
+ * `databases.adminData.count` — POST /databases/{databaseId}/admin-data/count. DEPRECATED — direct database count; use databases/{databaseId}/records/count
523
+ * @deprecated Use databases/{databaseId}/records/count
524
+ */
506
525
  "count"(args: {
507
526
  "databaseId": string | number;
508
527
  body: unknown;
509
528
  }): Promise<any>;
510
- /** `databases.adminData.delete` — POST /databases/{databaseId}/admin-data/delete. DEPRECATED — direct database delete; use databases/{databaseId}/records/delete */
529
+ /**
530
+ * `databases.adminData.delete` — POST /databases/{databaseId}/admin-data/delete. DEPRECATED — direct database delete; use databases/{databaseId}/records/delete
531
+ * @deprecated Use databases/{databaseId}/records/delete
532
+ */
511
533
  "delete"(args: {
512
534
  "databaseId": string | number;
513
535
  body: unknown;
514
536
  }): Promise<any>;
515
- /** `databases.adminData.patch` — POST /databases/{databaseId}/admin-data/patch. DEPRECATED — direct database patch; use databases/{databaseId}/records/patch */
537
+ /**
538
+ * `databases.adminData.patch` — POST /databases/{databaseId}/admin-data/patch. DEPRECATED — direct database patch; use databases/{databaseId}/records/patch
539
+ * @deprecated Use databases/{databaseId}/records/patch
540
+ */
516
541
  "patch"(args: {
517
542
  "databaseId": string | number;
518
543
  body: unknown;
519
544
  }): Promise<any>;
520
- /** `databases.adminData.query` — POST /databases/{databaseId}/admin-data/query. DEPRECATED — direct database query; use databases/{databaseId}/records/query */
545
+ /**
546
+ * `databases.adminData.query` — POST /databases/{databaseId}/admin-data/query. DEPRECATED — direct database query; use databases/{databaseId}/records/query
547
+ * @deprecated Use databases/{databaseId}/records/query
548
+ */
521
549
  "query"(args: {
522
550
  "databaseId": string | number;
523
551
  body: unknown;
524
552
  }): Promise<any>;
525
- /** `databases.adminData.save` — POST /databases/{databaseId}/admin-data/save. DEPRECATED — direct database save; use databases/{databaseId}/records/save */
553
+ /**
554
+ * `databases.adminData.save` — POST /databases/{databaseId}/admin-data/save. DEPRECATED — direct database save; use databases/{databaseId}/records/save
555
+ * @deprecated Use databases/{databaseId}/records/save
556
+ */
526
557
  "save"(args: {
527
558
  "databaseId": string | number;
528
559
  body: unknown;
@@ -553,7 +584,10 @@ export interface FunctionApi {
553
584
  "get"(args: {
554
585
  "databaseId": string | number;
555
586
  }): Promise<any>;
556
- /** `databases.getMetadata` — GET /databases/{databaseId}/metadata. Get database metadata */
587
+ /**
588
+ * `databases.getMetadata` — GET /databases/{databaseId}/metadata. DEPRECATED — get database metadata; use resource metadata categories (resources/database/:databaseId/metadata/:category)
589
+ * @deprecated Use resource metadata categories (resources/database/:databaseId/metadata/:category)
590
+ */
557
591
  "getMetadata"(args: {
558
592
  "databaseId": string | number;
559
593
  }): Promise<any>;
@@ -710,13 +744,22 @@ export interface FunctionApi {
710
744
  "databaseId": string | number;
711
745
  body: unknown;
712
746
  }): Promise<any>;
713
- /** `databases.updateMetadata` — PATCH /databases/{databaseId}/metadata. Update database metadata */
747
+ /**
748
+ * `databases.updateMetadata` — PATCH /databases/{databaseId}/metadata. DEPRECATED — update database metadata; use resource metadata categories (resources/database/:databaseId/metadata/:category)
749
+ * @deprecated Use resource metadata categories (resources/database/:databaseId/metadata/:category)
750
+ */
714
751
  "updateMetadata"(args: {
715
752
  "databaseId": string | number;
716
753
  body: unknown;
717
754
  }): Promise<any>;
718
755
  };
719
756
  "documents": {
757
+ /** `documents.abortIngest` — POST /documents/{documentId}/ingest/{sessionId}/abort. Abort a bulk-load session before its swap */
758
+ "abortIngest"(args: {
759
+ "documentId": string | number;
760
+ "sessionId": string | number;
761
+ body: unknown;
762
+ }): Promise<any>;
720
763
  /** `documents.addTag` — POST /documents/{documentId}/tags. Add a tag to a document */
721
764
  "addTag"(args: {
722
765
  "documentId": string | number;
@@ -727,6 +770,7 @@ export interface FunctionApi {
727
770
  "delete"(args: {
728
771
  "scope": string | number;
729
772
  "aliasKey": string | number;
773
+ "userId"?: string | number | boolean;
730
774
  }): Promise<any>;
731
775
  /** `documents.aliases.listForDocument` — GET /documents/{documentId}/aliases. List aliases bound to a document */
732
776
  "listForDocument"(args: {
@@ -736,6 +780,7 @@ export interface FunctionApi {
736
780
  "resolve"(args: {
737
781
  "scope": string | number;
738
782
  "aliasKey": string | number;
783
+ "userId"?: string | number | boolean;
739
784
  }): Promise<any>;
740
785
  /** `documents.aliases.set` — PUT /document-aliases/{scope}/{aliasKey}. Bind a (scope, aliasKey) alias to a document */
741
786
  "set"(args: {
@@ -785,7 +830,10 @@ export interface FunctionApi {
785
830
  "X-Blob-Sha256": string | number;
786
831
  body: ArrayBuffer | Uint8Array | string;
787
832
  }): Promise<any>;
788
- /** `documents.blobs.uploadWithoutId` — PUT /documents/{documentId}/blobs. Deprecated: upload a document blob without a client-specified id */
833
+ /**
834
+ * `documents.blobs.uploadWithoutId` — PUT /documents/{documentId}/blobs. Deprecated: upload a document blob without a client-specified id
835
+ * @deprecated Deprecated in the app API spec; see its description.
836
+ */
789
837
  "uploadWithoutId"(args: {
790
838
  "documentId": string | number;
791
839
  }): Promise<any>;
@@ -794,10 +842,21 @@ export interface FunctionApi {
794
842
  "clearLinkAccess"(args: {
795
843
  "documentId": string | number;
796
844
  }): Promise<any>;
845
+ /** `documents.commitIngest` — POST /documents/{documentId}/ingest/{sessionId}/commit. Commit a bulk-load session: freeze its manifest and apply it */
846
+ "commitIngest"(args: {
847
+ "documentId": string | number;
848
+ "sessionId": string | number;
849
+ body: unknown;
850
+ }): Promise<any>;
797
851
  /** `documents.create` — POST /documents. Create a new document */
798
852
  "create"(args: {
799
853
  body: unknown;
800
854
  }): Promise<any>;
855
+ /** `documents.createIngest` — POST /documents/{documentId}/ingest. Open a bulk-load session on a large document */
856
+ "createIngest"(args: {
857
+ "documentId": string | number;
858
+ body: unknown;
859
+ }): Promise<any>;
801
860
  /** `documents.createWithAlias` — POST /documents/create-with-alias. Create a document and bind it to an alias */
802
861
  "createWithAlias"(args: {
803
862
  body: unknown;
@@ -855,6 +914,11 @@ export interface FunctionApi {
855
914
  "getImportChainStatus"(args: {
856
915
  "documentId": string | number;
857
916
  }): Promise<any>;
917
+ /** `documents.getIngest` — GET /documents/{documentId}/ingest/{sessionId}. One bulk-load session's status */
918
+ "getIngest"(args: {
919
+ "documentId": string | number;
920
+ "sessionId": string | number;
921
+ }): Promise<any>;
858
922
  /** `documents.getLinkAccess` — GET /documents/{documentId}/link-access. Get the document's "anyone with the link" access level */
859
923
  "getLinkAccess"(args: {
860
924
  "documentId": string | number;
@@ -913,6 +977,12 @@ export interface FunctionApi {
913
977
  "listGroupPermissions"(args: {
914
978
  "documentId": string | number;
915
979
  }): Promise<any>;
980
+ /** `documents.listIngests` — GET /documents/{documentId}/ingest. List a large document's bulk-load sessions, newest first */
981
+ "listIngests"(args: {
982
+ "documentId": string | number;
983
+ "limit"?: string | number | boolean;
984
+ "cursor"?: string | number | boolean;
985
+ }): Promise<any>;
916
986
  /** `documents.listPendingInvitations` — GET /documents/{documentId}/pending-invitations. List a document's pending (deferred) invitations */
917
987
  "listPendingInvitations"(args: {
918
988
  "documentId": string | number;
@@ -932,17 +1002,20 @@ export interface FunctionApi {
932
1002
  "aggregate"(args: {
933
1003
  "documentId": string | number;
934
1004
  "model": string | number;
1005
+ "documentFormat"?: string | number | boolean;
935
1006
  body: unknown;
936
1007
  }): Promise<any>;
937
1008
  /** `documents.records.bulk` — POST /documents/{documentId}/records/bulk. Apply an atomic multi-model record blob to a document (create/patch/delete) */
938
1009
  "bulk"(args: {
939
1010
  "documentId": string | number;
1011
+ "documentFormat"?: string | number | boolean;
940
1012
  body: unknown;
941
1013
  }): Promise<any>;
942
1014
  /** `documents.records.count` — GET /documents/{documentId}/records/{model}/count. Count records in a document model */
943
1015
  "count"(args: {
944
1016
  "documentId": string | number;
945
1017
  "model": string | number;
1018
+ "documentFormat"?: string | number | boolean;
946
1019
  "filter"?: Record<string, unknown> | string;
947
1020
  }): Promise<any>;
948
1021
  /** `documents.records.delete` — DELETE /documents/{documentId}/records/{model}/{recordId}. Delete a record from a document model */
@@ -950,18 +1023,21 @@ export interface FunctionApi {
950
1023
  "documentId": string | number;
951
1024
  "model": string | number;
952
1025
  "recordId": string | number;
1026
+ "documentFormat"?: string | number | boolean;
953
1027
  }): Promise<any>;
954
1028
  /** `documents.records.patch` — PATCH /documents/{documentId}/records/{model}/{recordId}. Merge fields into an existing record in a document model */
955
1029
  "patch"(args: {
956
1030
  "documentId": string | number;
957
1031
  "model": string | number;
958
1032
  "recordId": string | number;
1033
+ "documentFormat"?: string | number | boolean;
959
1034
  body: unknown;
960
1035
  }): Promise<any>;
961
1036
  /** `documents.records.query` — GET /documents/{documentId}/records/{model}. Query records in a document model */
962
1037
  "query"(args: {
963
1038
  "documentId": string | number;
964
1039
  "model": string | number;
1040
+ "documentFormat"?: string | number | boolean;
965
1041
  "limit"?: string | number | boolean;
966
1042
  "cursor"?: string | number | boolean;
967
1043
  "filter"?: Record<string, unknown> | string;
@@ -970,6 +1046,7 @@ export interface FunctionApi {
970
1046
  "save"(args: {
971
1047
  "documentId": string | number;
972
1048
  "model": string | number;
1049
+ "documentFormat"?: string | number | boolean;
973
1050
  body: unknown;
974
1051
  }): Promise<any>;
975
1052
  };
@@ -993,6 +1070,11 @@ export interface FunctionApi {
993
1070
  "documentId": string | number;
994
1071
  body: unknown;
995
1072
  }): Promise<any>;
1073
+ /** `documents.requestSnapshot` — POST /documents/{documentId}/snapshots. Snapshot a large document now: seal the open epoch and build a base */
1074
+ "requestSnapshot"(args: {
1075
+ "documentId": string | number;
1076
+ body: unknown;
1077
+ }): Promise<any>;
996
1078
  /** `documents.revokeGroupPermission` — DELETE /documents/{documentId}/group-permissions/{groupType}/{groupId}. Revoke a group permission on a document */
997
1079
  "revokeGroupPermission"(args: {
998
1080
  "documentId": string | number;
@@ -1019,9 +1101,16 @@ export interface FunctionApi {
1019
1101
  "documentId": string | number;
1020
1102
  body: unknown;
1021
1103
  }): Promise<any>;
1022
- /** `documents.validateAccess` — POST /documents/{documentId}/validate-access. Resolve the caller's effective access level for a document */
1104
+ /** `documents.uploadIngestChunk` — POST /documents/{documentId}/ingest/{sessionId}/chunks. Upload one chunk of a bulk-load session's artifact */
1105
+ "uploadIngestChunk"(args: {
1106
+ "documentId": string | number;
1107
+ "sessionId": string | number;
1108
+ body: FormData | ArrayBuffer | Uint8Array | string;
1109
+ }): Promise<any>;
1110
+ /** `documents.validateAccess` — POST /documents/{documentId}/validate-access. Resolve effective access to a document, for the caller or a named user */
1023
1111
  "validateAccess"(args: {
1024
1112
  "documentId": string | number;
1113
+ body?: unknown;
1025
1114
  }): Promise<any>;
1026
1115
  };
1027
1116
  "email": {
@@ -1048,29 +1137,12 @@ export interface FunctionApi {
1048
1137
  "cursor"?: string | number | boolean;
1049
1138
  "runId"?: string | number | boolean;
1050
1139
  }): Promise<any>;
1051
- /** `functions.start` — POST /functions/{functionKey}/start. Start a task function from inside another server function */
1140
+ /** `functions.start` — POST /functions/{functionKey}/start. Start a server function as a task run */
1052
1141
  "start"(args: {
1053
1142
  "functionKey": string | number;
1054
1143
  body?: unknown;
1055
1144
  }): Promise<any>;
1056
1145
  };
1057
- "gemini": {
1058
- /** `gemini.countTokens` — POST /gemini/count-tokens. Count tokens for a Gemini request */
1059
- "countTokens"(args: {
1060
- body: unknown;
1061
- }): Promise<any>;
1062
- /** `gemini.generate` — POST /gemini/generate. Generate content with Gemini */
1063
- "generate"(args: {
1064
- body: unknown;
1065
- }): Promise<any>;
1066
- /** `gemini.generateRaw` — POST /gemini/generate-raw. Generate content with Gemini (raw passthrough) */
1067
- "generateRaw"(args: {
1068
- "model"?: string | number | boolean;
1069
- body: unknown;
1070
- }): Promise<any>;
1071
- /** `gemini.models` — GET /gemini/models. List available Gemini models */
1072
- "models"(args?: Record<string, never>): Promise<any>;
1073
- };
1074
1146
  "groups": {
1075
1147
  /** `groups.addMember` — POST /groups/{groupType}/{groupId}/members. Add a member to a group */
1076
1148
  "addMember"(args: {
@@ -1160,14 +1232,6 @@ export interface FunctionApi {
1160
1232
  "integrationKey": string | number;
1161
1233
  }): Promise<any>;
1162
1234
  };
1163
- "llm": {
1164
- /** `llm.chat` — POST /llm/chat. Run an LLM chat completion */
1165
- "chat"(args: {
1166
- body: unknown;
1167
- }): Promise<any>;
1168
- /** `llm.models` — GET /llm/models. List available LLM models */
1169
- "models"(args?: Record<string, never>): Promise<any>;
1170
- };
1171
1235
  "locks": {
1172
1236
  /** `locks.list` — GET /locks. List all currently-held named locks in the app */
1173
1237
  "list"(args?: Record<string, never>): Promise<any>;
@@ -1278,6 +1342,10 @@ export interface FunctionApi {
1278
1342
  "getProfiles"(args: {
1279
1343
  body: unknown;
1280
1344
  }): Promise<any>;
1345
+ /** `users.getRootDocument` — GET /users/{userId}/root-document. Get an app user's root document id */
1346
+ "getRootDocument"(args: {
1347
+ "userId": string | number;
1348
+ }): Promise<any>;
1281
1349
  /** `users.list` — GET /users. List app users */
1282
1350
  "list"(args?: {
1283
1351
  "email"?: string | number | boolean;
@@ -1290,7 +1358,10 @@ export interface FunctionApi {
1290
1358
  "lookup"(args?: {
1291
1359
  "email"?: string | number | boolean;
1292
1360
  }): Promise<any>;
1293
- /** `users.remove` — DELETE /users/{userId}. Remove a user from the app */
1361
+ /**
1362
+ * `users.remove` — DELETE /users/{userId}. DEPRECATED — remove a user from the app; use the admin API's PUT apps/:appId/users/:userId/disable (`primitive users disable`)
1363
+ * @deprecated Use the admin API's PUT apps/:appId/users/:userId/disable (`primitive users disable`)
1364
+ */
1294
1365
  "remove"(args: {
1295
1366
  "userId": string | number;
1296
1367
  }): Promise<any>;
@@ -1339,8 +1410,8 @@ export type DatabaseModels<K extends string> = K extends keyof DatabaseSchemas
1339
1410
  * The app's functions, key by key — EMPTY here and filled by the declaration
1340
1411
  * `primitive config push` writes into the config tree's `functions/`
1341
1412
  * directory (`primitive-function-types.d.ts`): each key's declared input and
1342
- * output types (from its `inputSchema` and `outputSchema`) and its mode. It
1343
- * is what types `defineFunction("<key>", handler)`.
1413
+ * output types, from its `inputSchema` and `outputSchema`. It is what types
1414
+ * `defineFunction("<key>", handler)`.
1344
1415
  */
1345
1416
  export interface FunctionSchemas {}
1346
1417
 
@@ -1368,20 +1439,6 @@ export type FunctionOutput<K extends string> = K extends keyof FunctionSchemas
1368
1439
  : any
1369
1440
  : any;
1370
1441
 
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
- */
1379
- export type FunctionMode<K extends string> = K extends keyof FunctionSchemas
1380
- ? FunctionSchemas[K] extends { mode: infer M }
1381
- ? M
1382
- : "request" | "task" | "any"
1383
- : "request" | "task" | "any";
1384
-
1385
1442
  /**
1386
1443
  * The model names one database type addresses — its own, or any name at all
1387
1444
  * for a type that declares no schema (the DO is schemaless, so a grant on such
@@ -1545,12 +1602,40 @@ export interface DocumentQueryOptions {
1545
1602
  filter?: Record<string, unknown> | string;
1546
1603
  limit?: number;
1547
1604
  cursor?: string;
1605
+ /**
1606
+ * The document format you expect (#3764). When it disagrees with the format
1607
+ * the platform resolved, the call is refused with a 409
1608
+ * DOCUMENT_FORMAT_MISMATCH rather than answered out of the wrong tables.
1609
+ * Usually stated once on the handle, as ctx.doc(id, { documentFormat: 2 }),
1610
+ * rather than per read.
1611
+ */
1612
+ documentFormat?: 1 | 2;
1548
1613
  }
1549
1614
 
1550
1615
  /**
1551
1616
  * One document model, bound to its document and its model name — a thin
1552
1617
  * binding over `ctx.api.documents.records.*` with the route's own shapes.
1553
1618
  */
1619
+ /**
1620
+ * One op of a document `batch` — the `documents.records.bulk` blob's shape,
1621
+ * typed to this handle's model (#3455).
1622
+ *
1623
+ * `model` is NOT a member: the handle already names it and assigns it last, so
1624
+ * a multi-model blob stays on the raw `ctx.api.documents.records.bulk`
1625
+ * operation rather than becoming a second way to say the same thing.
1626
+ */
1627
+ export type DocumentBatchOp<TRow> =
1628
+ | { action: "create" | "patch"; id: string; data: Partial<TRow>; precondition?: Record<string, unknown> }
1629
+ | { action: "delete"; id: string; precondition?: Record<string, unknown> };
1630
+
1631
+ /** What `documents.records.bulk` answers: the blob's aggregate effect. */
1632
+ export interface DocumentBulkResult {
1633
+ applied: number;
1634
+ added: Array<{ model: string; id: string }>;
1635
+ updated: Array<{ model: string; id: string }>;
1636
+ deleted: number;
1637
+ }
1638
+
1554
1639
  export interface DocumentModelHandle<TRow> {
1555
1640
  query(options?: DocumentQueryOptions): Promise<{ items: TRow[]; hasMore: boolean; nextCursor?: string }>;
1556
1641
  count(options?: { filter?: Record<string, unknown> | string }): Promise<{ count: number }>;
@@ -1558,6 +1643,15 @@ export interface DocumentModelHandle<TRow> {
1558
1643
  save(body: { id: string; data: Partial<TRow>; options?: Record<string, unknown> }): Promise<{ record: TRow }>;
1559
1644
  patch(recordId: string, body: { data: Partial<TRow>; options?: Record<string, unknown> }): Promise<{ record: TRow }>;
1560
1645
  delete(recordId: string): Promise<{ deleted: boolean }>;
1646
+ /**
1647
+ * Apply an ordered blob of this model's ops in ONE transaction — all of it
1648
+ * commits or none of it does, and connected clients see one update.
1649
+ *
1650
+ * One model's ops, by construction: every op's `model` is this handle's.
1651
+ * A blob that spans models is the raw `ctx.api.documents.records.bulk`
1652
+ * operation's job.
1653
+ */
1654
+ batch(ops: Array<DocumentBatchOp<TRow>>): Promise<DocumentBulkResult>;
1561
1655
  }
1562
1656
 
1563
1657
  /** A document, addressed once; its models are typed from `DocumentSchemas`. */
@@ -1600,6 +1694,13 @@ export interface IntegrationCallResult {
1600
1694
 
1601
1695
  /** What a prompt run is given — the member execute route's own body. */
1602
1696
  export interface PromptRunArgs {
1697
+ /**
1698
+ * The prompt's variables. A `kind = "decisions"` prompt takes
1699
+ * `{ state, criteria? }`: `state` is the value its questions are asked
1700
+ * about, and `criteria.<question>` supplies this run's options for each
1701
+ * choice question declared `criteriaSource = "dynamic"` — a table of option
1702
+ * key = description (a string or a JSON object), at least two entries (#3813).
1703
+ */
1603
1704
  variables?: Record<string, unknown>;
1604
1705
  /** Run against a different model for this call only. */
1605
1706
  modelOverride?: string;
@@ -1617,10 +1718,45 @@ export interface PromptRunArgs {
1617
1718
  */
1618
1719
  export interface PromptSchemas {}
1619
1720
 
1620
- /** The keys `ctx.prompts.run` accepts — every declared one, or `string` before a push. */
1721
+ /**
1722
+ * The keys whose declaration is an AGENT (`kind = "agent"`, #3798): entries
1723
+ * carrying `{ agent: … }` instead of an output. An agent runs turn by turn in
1724
+ * a session and never single-shot, so these are the keys `PromptKeys` leaves
1725
+ * out.
1726
+ */
1727
+ export type AgentKeys = {
1728
+ [K in keyof PromptSchemas]: PromptSchemas[K] extends { agent: unknown } ? K : never;
1729
+ }[keyof PromptSchemas] &
1730
+ string;
1731
+
1732
+ /**
1733
+ * The keys `ctx.prompts.run` accepts — every declared one that is not an
1734
+ * agent, or `string` before a push.
1735
+ */
1621
1736
  export type PromptKeys = [keyof PromptSchemas] extends [never]
1622
1737
  ? string
1623
- : keyof PromptSchemas & string;
1738
+ : Exclude<keyof PromptSchemas & string, AgentKeys>;
1739
+
1740
+ /** One agent's session variables, typed from its `inputSchema` (#3798). */
1741
+ export type AgentVariables<K extends AgentKeys> = PromptSchemas[K] extends {
1742
+ agent: { variables: infer V };
1743
+ }
1744
+ ? V
1745
+ : never;
1746
+
1747
+ /** One agent's client tools, by name: each one's `input` and `output` (#3798). */
1748
+ export type AgentClientTools<K extends AgentKeys> = PromptSchemas[K] extends {
1749
+ agent: { clientTools: infer T };
1750
+ }
1751
+ ? T
1752
+ : never;
1753
+
1754
+ /** One agent's event kinds, by name: each one's payload (#3798). */
1755
+ export type AgentEvents<K extends AgentKeys> = PromptSchemas[K] extends {
1756
+ agent: { events: infer E };
1757
+ }
1758
+ ? E
1759
+ : never;
1624
1760
 
1625
1761
  /** One prompt's declared output type, or `unknown` where none is declared. */
1626
1762
  export type PromptOutput<K extends string> = K extends keyof PromptSchemas
@@ -1638,6 +1774,29 @@ export type PromptOutputErrorCode =
1638
1774
  | "PROMPT_OUTPUT_NOT_JSON"
1639
1775
  | "PROMPT_OUTPUT_SCHEMA_VIOLATION";
1640
1776
 
1777
+ /**
1778
+ * Every code the envelope's `errorCode` can carry — #3663, #3813.
1779
+ *
1780
+ * `PROMPT_UPSTREAM_TIMEOUT` is the one that is NOT about the prompt's own
1781
+ * answer: the provider ran out of time, so there was no answer to refuse. It
1782
+ * is the only provider failure that sets `errorCode` at all, which is what
1783
+ * leaves "the model returned the wrong shape" distinguishable from "the model
1784
+ * failed" while still letting a caller retry the one failure worth retrying.
1785
+ *
1786
+ * `PROMPT_CRITERIA_INVALID` is the run that never reached a provider: a
1787
+ * decisions run's `variables.criteria` was refused before the call, so
1788
+ * nothing was billed (#3813).
1789
+ *
1790
+ * `PROMPT_STRICT_OUTPUT_SCHEMA_MISSING` never reached one either: the config
1791
+ * sets `strictOutput = true` and the prompt has no usable `outputSchema` to
1792
+ * send as the strict `json_schema` (#3801).
1793
+ */
1794
+ export type PromptRunErrorCode =
1795
+ | PromptOutputErrorCode
1796
+ | "PROMPT_UPSTREAM_TIMEOUT"
1797
+ | "PROMPT_CRITERIA_INVALID"
1798
+ | "PROMPT_STRICT_OUTPUT_SCHEMA_MISSING";
1799
+
1641
1800
  /** A prompt that declares an output shape, when the answer matched it. */
1642
1801
  export interface PromptRunSuccess<TParsed> {
1643
1802
  success: true;
@@ -1651,19 +1810,31 @@ export interface PromptRunSuccess<TParsed> {
1651
1810
  }
1652
1811
 
1653
1812
  /**
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.
1813
+ * The failure arm, whichever failed. `errorCode` is set for a SHAPE failure,
1814
+ * for a refused run (`PROMPT_CRITERIA_INVALID`, #3813), and for a provider
1815
+ * one only when the upstream TIMED OUT (#3663); `output` carries the text
1816
+ * either way, which is where the model's own value lives — a validation
1817
+ * `error` names paths and schema constraints only.
1658
1818
  */
1659
1819
  export interface PromptRunFailure {
1660
1820
  success: false;
1661
1821
  output: string;
1662
1822
  error: string | null;
1663
- errorCode?: PromptOutputErrorCode | null;
1823
+ errorCode?: PromptRunErrorCode | null;
1664
1824
  parsed?: undefined;
1665
1825
  metrics?: Record<string, unknown>;
1666
1826
  configId: string;
1827
+ /**
1828
+ * The upstream provider's HTTP status, when the call reached a provider and
1829
+ * it answered — #3663. This is what a retry decision is made on: a 504 or a
1830
+ * 503 is worth another attempt, a 400 on a refused payload is not.
1831
+ *
1832
+ * It does not depend on which provider the config named: Gemini and
1833
+ * OpenRouter report it identically. It is absent when no provider answer was
1834
+ * observed — an unset key, an oversized payload, a completion that came back
1835
+ * empty — so a number here is always the provider's own.
1836
+ */
1837
+ upstreamStatus?: number;
1667
1838
  }
1668
1839
 
1669
1840
  /** The envelope for a key whose declaration says nothing about its output. */
@@ -1676,9 +1847,11 @@ export interface PromptRunOpenResult {
1676
1847
  */
1677
1848
  parsed?: unknown;
1678
1849
  error?: string | null;
1679
- errorCode?: PromptOutputErrorCode | null;
1850
+ errorCode?: PromptRunErrorCode | null;
1680
1851
  metrics?: Record<string, unknown>;
1681
1852
  configId: string;
1853
+ /** The upstream provider's HTTP status on a provider failure — #3663. */
1854
+ upstreamStatus?: number;
1682
1855
  }
1683
1856
 
1684
1857
  /**
@@ -1785,9 +1958,45 @@ export interface FunctionStartResult {
1785
1958
  }
1786
1959
 
1787
1960
  export interface FunctionContext {
1788
- /** The HTTP caller, or null for a webhook, cron or database-change fire. */
1961
+ /** The HTTP caller, or null for a webhook or cron fire. */
1789
1962
  user: FunctionUser | null;
1790
1963
  trigger: FunctionTrigger;
1964
+ /**
1965
+ * Which RUNTIME is hosting this code — #3482.
1966
+ *
1967
+ * Beside `trigger`, which says which DOOR fired, and they are different
1968
+ * questions: an HTTP call is whichever runtime the caller chose
1969
+ * (`invoke` or `start`), a cron fire is always a task and a webhook
1970
+ * delivery is always a request.
1971
+ *
1972
+ * To REFUSE a runtime rather than branch on it, call
1973
+ * `assertRuntime("task")` — at module scope to refuse it outright, or in
1974
+ * the handler to refuse one call.
1975
+ */
1976
+ runtime: "request" | "task";
1977
+ /**
1978
+ * The RUN this invocation belongs to, or null — #3562.
1979
+ *
1980
+ * Set under the task runtime (every slice of the run, the first and every
1981
+ * resume) and for a webhook-fired request run, which writes a row. Null for
1982
+ * an HTTP `invoke`, which writes no run row at all.
1983
+ *
1984
+ * It is the deterministic OWNER a task run presents to re-take its own
1985
+ * lease: `ctx.api.locks.tryAcquire({ body: { key, ttlMs, owner: ctx.runId } })`
1986
+ * succeeds for the run that already holds the key, with a fresh handle.
1987
+ */
1988
+ runId: string | null;
1989
+ /**
1990
+ * The SLICE of the run this code is running in, or null — #3562.
1991
+ *
1992
+ * The same identifier `primitive functions runs` and the run-status
1993
+ * route's `slice.sliceId` report. A task run is a sequence of slices: it
1994
+ * changes when the run hibernates and wakes, which is how a handler can tell
1995
+ * a resume from a first pass.
1996
+ *
1997
+ * Null under the request runtime: a request invocation is not a slice.
1998
+ */
1999
+ sliceId: string | null;
1791
2000
  api: FunctionApi;
1792
2001
  /**
1793
2002
  * A typed handle over one database. The second argument is the database TYPE
@@ -1804,7 +2013,7 @@ export interface FunctionContext {
1804
2013
  * confers nothing: every call is a `documents.records.*` operation on the
1805
2014
  * same authority.
1806
2015
  */
1807
- doc(documentId: string): DocumentHandle;
2016
+ doc(documentId: string, options?: { documentFormat?: 1 | 2 }): DocumentHandle;
1808
2017
  /**
1809
2018
  * Outbound HTTP, through a granted integration and nowhere else (#3183).
1810
2019
  *
@@ -1937,6 +2146,29 @@ export interface FunctionContext {
1937
2146
  };
1938
2147
  }
1939
2148
 
2149
+ /** How the wait between one step's retries grows. */
2150
+ export type StepBackoff = "constant" | "linear" | "exponential";
2151
+
2152
+ /**
2153
+ * The retry and timeout policy for ONE `step.do` — Cloudflare Workflows' own
2154
+ * step config.
2155
+ *
2156
+ * Under the TASK runner the platform forwards this object to Workflows
2157
+ * untouched, so these are its fields and its spellings: a duration is either a
2158
+ * number of milliseconds or a string Workflows parses (`"10 seconds"`,
2159
+ * `"5 minutes"`). Under the REQUEST runner `step.do` accepts a config and
2160
+ * ignores it — the body runs inline, and there is nothing to retry into.
2161
+ *
2162
+ * `stepPolicy.<family>` IS a `StepConfig`, so the platform's own defaults
2163
+ * hand straight to `step.do` (#3657). The shape is closed on purpose: a key
2164
+ * outside it — `retry` for `retries`, `timeoutMs` for `timeout` — is a
2165
+ * refusal at `config push` rather than an option the engine silently drops.
2166
+ */
2167
+ export interface StepConfig {
2168
+ retries?: { limit: number; delay: string | number; backoff?: StepBackoff };
2169
+ timeout?: string | number;
2170
+ }
2171
+
1940
2172
  /**
1941
2173
  * The step handle. `step` is the third argument under BOTH runners, so the
1942
2174
  * same body runs either way — which is what `mode = "any"` is for (#3454).
@@ -1949,7 +2181,7 @@ export interface FunctionContext {
1949
2181
  * clock: `do` executes the body inline (there is no engine to memoize into,
1950
2182
  * and nothing is replayed); `sleep` and `sleepUntil` REALLY wait when the
1951
2183
  * remaining request budget covers the duration, and otherwise fail the
1952
- * invocation with `errorCode: "FUNCTION_STEP_NEEDS_TASK"` saying to start the
2184
+ * invocation with `errorCode: "FUNCTION_RUNTIME_REFUSED"` saying to start the
1953
2185
  * function as a task; `waitForEvent` fails the same way, because nothing can
1954
2186
  * deliver an event to an invocation that has to return now. The thrown error's
1955
2187
  * `name` is `STEP_NOT_AVAILABLE` in every case, so a body that catches it
@@ -1959,7 +2191,7 @@ export interface FunctionStep {
1959
2191
  do<T>(name: string, body: () => T | Promise<T>): Promise<T>;
1960
2192
  do<T>(
1961
2193
  name: string,
1962
- config: Record<string, unknown>,
2194
+ config: StepConfig,
1963
2195
  body: () => T | Promise<T>
1964
2196
  ): Promise<T>;
1965
2197
  sleep(name: string, duration: number | string): Promise<void>;
@@ -1972,6 +2204,48 @@ export interface FunctionStep {
1972
2204
 
1973
2205
  export declare const SDK_STUB_VERSION: string;
1974
2206
 
2207
+ /**
2208
+ * Thrown by `assertRuntime` when this function is running under the other
2209
+ * runtime — #3482.
2210
+ *
2211
+ * The platform settles it as `status: "failed"` with
2212
+ * `errorCode: "FUNCTION_RUNTIME_REFUSED"`, on a request invocation's
2213
+ * envelope and on a task run's row and record alike.
2214
+ */
2215
+ export declare class FunctionRuntimeError extends Error {
2216
+ name: "FUNCTION_RUNTIME_REFUSED";
2217
+ /** The runtime this invocation is actually running under. */
2218
+ runtime: "request" | "task";
2219
+ /** The runtime the function asked for. */
2220
+ required: "request" | "task";
2221
+ }
2222
+
2223
+ /**
2224
+ * Refuse the runtime this function was not written for — #3482.
2225
+ *
2226
+ * A function is a function and the caller picks the runtime at each call, so
2227
+ * nothing in config says which one a function may run under. This is the lock,
2228
+ * and it lives in the one place that can always be right about the code:
2229
+ *
2230
+ * ```ts
2231
+ * import { assertRuntime } from "primitive-functions";
2232
+ *
2233
+ * // At module scope: this function is never runnable inside a request.
2234
+ * assertRuntime("task");
2235
+ *
2236
+ * export default async function (input, ctx, step) {
2237
+ * await step.sleep("cool-off", "1 hour");
2238
+ * return { ok: true };
2239
+ * }
2240
+ * ```
2241
+ *
2242
+ * Returns when the runtimes match; otherwise throws
2243
+ * {@link FunctionRuntimeError}, which the platform settles as
2244
+ * `status: "failed"` with `errorCode: "FUNCTION_RUNTIME_REFUSED"` and a
2245
+ * message naming both runtimes and the verb that takes the one required.
2246
+ */
2247
+ export declare function assertRuntime(required: "request" | "task"): void;
2248
+
1975
2249
  /**
1976
2250
  * The handler a function exports, typed for one declared key.
1977
2251
  *
@@ -2181,9 +2455,9 @@ export declare const PMAP_DEFAULT_CONCURRENCY: number;
2181
2455
  */
2182
2456
  export declare function ulid(): string;
2183
2457
 
2184
- /** One family's durable `step.do` configuration. */
2185
- export interface StepPolicy {
2186
- retries: { limit: number; delay: string; backoff: string };
2458
+ /** One family's durable `step.do` configuration — a `StepConfig` with every field decided. */
2459
+ export interface StepPolicy extends StepConfig {
2460
+ retries: { limit: number; delay: string; backoff: StepBackoff };
2187
2461
  timeout: string;
2188
2462
  }
2189
2463
 
@@ -2204,6 +2478,12 @@ export declare const stepPolicy: {
2204
2478
  database: StepPolicy;
2205
2479
  };
2206
2480
 
2481
+ // Every member the three runtime copies put on their own default export — the
2482
+ // platform's `sdk-core.ts`, the published stub and the CLI's collect stub —
2483
+ // and nothing else. A helper the module hands a default import but does not
2484
+ // declare here is one an author cannot call without the compiler refusing it
2485
+ // (#3482 CR3482-002); `tests/api/spec/function-profile.test.ts` holds the four
2486
+ // lists equal and compiles a default import against them.
2207
2487
  declare const _default: {
2208
2488
  SDK_STUB_VERSION: string;
2209
2489
  defineFunction: typeof defineFunction;
@@ -2211,5 +2491,7 @@ declare const _default: {
2211
2491
  defineMutation: typeof defineMutation;
2212
2492
  pMap: typeof pMap;
2213
2493
  ulid: typeof ulid;
2494
+ assertRuntime: typeof assertRuntime;
2495
+ FunctionRuntimeError: typeof FunctionRuntimeError;
2214
2496
  };
2215
2497
  export default _default;
package/index.js CHANGED
@@ -82,6 +82,34 @@ export const stepPolicy = {
82
82
  database: null,
83
83
  };
84
84
 
85
+ /**
86
+ * The runtime refusal's error class — #3482.
87
+ *
88
+ * Carried rather than thrown from: a function narrows a `catch` with
89
+ * `instanceof FunctionRuntimeError`, and a class that threw on construction
90
+ * would break a build that only type-checks. The platform copy is the one that
91
+ * is ever really thrown.
92
+ */
93
+ export class FunctionRuntimeError extends Error {
94
+ constructor(message, runtime, required) {
95
+ super(message);
96
+ this.name = "FUNCTION_RUNTIME_REFUSED";
97
+ this.runtime = runtime;
98
+ this.required = required;
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Refuse the runtime this function was not written for — #3482.
104
+ *
105
+ * The platform copy compares the required runtime against the one the isolate
106
+ * declared. This one refuses, loudly, like every other function here: an
107
+ * assertion answered outside a sandbox would be answering about nothing.
108
+ */
109
+ export function assertRuntime() {
110
+ throw new Error(NOT_PROVIDED);
111
+ }
112
+
85
113
  export default {
86
114
  SDK_STUB_VERSION,
87
115
  defineFunction,
@@ -89,4 +117,6 @@ export default {
89
117
  defineMutation,
90
118
  pMap,
91
119
  ulid,
120
+ assertRuntime,
121
+ FunctionRuntimeError,
92
122
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primitive-functions",
3
- "version": "0.2.0-alpha.8",
3
+ "version": "0.2.0",
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",