primitive-functions 0.2.0-alpha.1 → 0.2.0-alpha.11
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/index.d.ts +814 -53
- package/index.js +35 -3
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -10,16 +10,91 @@
|
|
|
10
10
|
* time, and reaching the stub means it did not.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* The signed-in user who invoked the function over HTTP.
|
|
15
|
+
*
|
|
16
|
+
* Attribution, never authority (#3279): function code acts as the system
|
|
17
|
+
* whoever called it, so this says WHO asked, and the rows the function writes
|
|
18
|
+
* are attributed to them. A trigger fire has no caller and `ctx.user` is
|
|
19
|
+
* null.
|
|
20
|
+
*/
|
|
14
21
|
export interface FunctionUser {
|
|
15
22
|
userId: string;
|
|
16
23
|
email: string | null;
|
|
17
24
|
}
|
|
18
25
|
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
/**
|
|
27
|
+
* What started this invocation. Narrow on `kind`.
|
|
28
|
+
*
|
|
29
|
+
* The same union the runtime builds (`src/server-functions/trigger-descriptor.ts`),
|
|
30
|
+
* held identical by `tests/api/spec/function-trigger-declarations-3281.test.ts`:
|
|
31
|
+
* a field the fire path sets is declared here, and nothing is declared here
|
|
32
|
+
* that the fire path does not set.
|
|
33
|
+
*/
|
|
34
|
+
export type FunctionTrigger =
|
|
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 }
|
|
44
|
+
/** A verified webhook delivery to the function's own key. */
|
|
45
|
+
| {
|
|
46
|
+
kind: "webhook";
|
|
47
|
+
/** The webhook key, which is the function key. */
|
|
48
|
+
webhookKey: string;
|
|
49
|
+
/** The platform's webhook row the delivery log lives under. */
|
|
50
|
+
webhookId: string;
|
|
51
|
+
/** The provider's event id (`X-Webhook-Event-Id`), when it sent one. */
|
|
52
|
+
externalEventId: string | null;
|
|
53
|
+
}
|
|
54
|
+
/** A cron entry firing, scheduled or from the `cron-triggers test` diagnostic. */
|
|
55
|
+
| {
|
|
56
|
+
kind: "cron";
|
|
57
|
+
/** The `[[function.triggers.cron]]` entry's `name`. */
|
|
58
|
+
name: string;
|
|
59
|
+
/** The platform's cron row. */
|
|
60
|
+
triggerId: string;
|
|
61
|
+
/** ISO 8601. The instant the fire was scheduled for; a diagnostic fire's is "now". */
|
|
62
|
+
scheduledFor: string;
|
|
63
|
+
/** Present, and true, only on the diagnostic fire: nothing was scheduled. */
|
|
64
|
+
manual?: true;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A DSL workflow's `workflow.call` step reached this function (#3288).
|
|
68
|
+
*
|
|
69
|
+
* TRANSITIONAL: the bridge exists so a workflow tree can migrate leaf-first
|
|
70
|
+
* during the transition, and it retires with the workflow engine in phase 7,
|
|
71
|
+
* taking this variant with it. `workflowKey` names the PARENT workflow, and
|
|
72
|
+
* `runId`/`stepId` locate the step inside its run.
|
|
73
|
+
*/
|
|
74
|
+
| { kind: "workflow"; workflowKey: string; runId: string; stepId: string }
|
|
75
|
+
/**
|
|
76
|
+
* Another function started this one with `ctx.functions.start` (#3280).
|
|
77
|
+
*
|
|
78
|
+
* `functionKey` names the PARENT, and `runId` its run — null when the
|
|
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).
|
|
81
|
+
*/
|
|
82
|
+
| {
|
|
83
|
+
kind: "function";
|
|
84
|
+
functionKey: string;
|
|
85
|
+
runId: string | null;
|
|
86
|
+
runKey: string | null;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* An admin ran this function as the SYSTEM, from outside any trigger
|
|
90
|
+
* (#3448) — `primitive functions invoke --as system`.
|
|
91
|
+
*
|
|
92
|
+
* `ctx.user` is null and the code runs with the app's system authority, as
|
|
93
|
+
* it does for a cron or webhook fire. `userId` names the admin who asked:
|
|
94
|
+
* attribution, never the principal the code runs as. `runKey` is the key
|
|
95
|
+
* the admin's start named, or null (#3562).
|
|
96
|
+
*/
|
|
97
|
+
| { kind: "manual"; userId: string; runKey: string | null };
|
|
23
98
|
|
|
24
99
|
/** The result shape of an operation that answers in response headers. */
|
|
25
100
|
export interface HeaderResult {
|
|
@@ -39,16 +114,21 @@ export interface PrimitivePlatformError extends Error {
|
|
|
39
114
|
|
|
40
115
|
/**
|
|
41
116
|
* The typed HTTP profile, generated from the platform's OpenAPI document. Its
|
|
42
|
-
* namespaces mirror the operation ids: analytics, blobBuckets, collections, configVars, connections, databaseTypeConfigs, databases, documents, email, functions, gemini, groups, integrations,
|
|
117
|
+
* 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.
|
|
43
118
|
* Methods take one options object carrying the operation's path parameters,
|
|
44
119
|
* query parameters, request headers (under their wire names) and `body`.
|
|
45
120
|
*
|
|
46
121
|
* Generated from the same operations as the runtime profile, so a method that
|
|
47
122
|
* type-checks is a method the platform publishes — and a missing path
|
|
48
123
|
* parameter or a missing required header is a compile error rather than a
|
|
49
|
-
* `TypeError` at invoke time.
|
|
50
|
-
*
|
|
51
|
-
*
|
|
124
|
+
* `TypeError` at invoke time. Every call runs with the app's own SYSTEM
|
|
125
|
+
* authority (#3279): the invocation gate was the authorization. The two
|
|
126
|
+
* namespaces the gateway does not admit are still declared: they exist, they
|
|
127
|
+
* answer the gateway's structured denial, and hiding them would make a route's
|
|
128
|
+
* availability look like a typo. Those are `databaseTypeConfigs` whole, and
|
|
129
|
+
* `functions` except for `functions.start` — the nested-start door #3280
|
|
130
|
+
* admits by name, which `ctx.functions.start` calls. `functions.invoke`
|
|
131
|
+
* stays refused: same-run composition is an import.
|
|
52
132
|
*/
|
|
53
133
|
export interface FunctionApi {
|
|
54
134
|
"analytics": {
|
|
@@ -124,6 +204,10 @@ export interface FunctionApi {
|
|
|
124
204
|
"searchUsers"(args?: {
|
|
125
205
|
"q"?: string | number | boolean;
|
|
126
206
|
"limit"?: string | number | boolean;
|
|
207
|
+
"signupDay"?: string | number | boolean;
|
|
208
|
+
"signupStartDay"?: string | number | boolean;
|
|
209
|
+
"signupEndDay"?: string | number | boolean;
|
|
210
|
+
"offset"?: string | number | boolean;
|
|
127
211
|
"current_timestamp"?: string | number | boolean;
|
|
128
212
|
"_bust"?: string | number | boolean;
|
|
129
213
|
}): Promise<any>;
|
|
@@ -233,6 +317,18 @@ export interface FunctionApi {
|
|
|
233
317
|
body: ArrayBuffer | Uint8Array | string;
|
|
234
318
|
}): Promise<any>;
|
|
235
319
|
};
|
|
320
|
+
"channels": {
|
|
321
|
+
/** `channels.authorize` — POST /channels/{channel}/grants. Issue a channel grant under a server function's grant */
|
|
322
|
+
"authorize"(args: {
|
|
323
|
+
"channel": string | number;
|
|
324
|
+
body: unknown;
|
|
325
|
+
}): Promise<any>;
|
|
326
|
+
/** `channels.publish` — POST /channels/{channel}/publish. Publish a message to a channel under a server function's grant */
|
|
327
|
+
"publish"(args: {
|
|
328
|
+
"channel": string | number;
|
|
329
|
+
body: unknown;
|
|
330
|
+
}): Promise<any>;
|
|
331
|
+
};
|
|
236
332
|
"collections": {
|
|
237
333
|
/** `collections.addDocument` — POST /collections/{collectionId}/documents. Add a document to a collection */
|
|
238
334
|
"addDocument"(args: {
|
|
@@ -273,6 +369,8 @@ export interface FunctionApi {
|
|
|
273
369
|
/** `collections.listCollectionsForDocument` — GET /documents/{documentId}/collections. List collections a document belongs to (reverse lookup) */
|
|
274
370
|
"listCollectionsForDocument"(args: {
|
|
275
371
|
"documentId": string | number;
|
|
372
|
+
"limit"?: string | number | boolean;
|
|
373
|
+
"cursor"?: string | number | boolean;
|
|
276
374
|
}): Promise<any>;
|
|
277
375
|
/** `collections.listDocuments` — GET /collections/{collectionId}/documents. List documents in a collection */
|
|
278
376
|
"listDocuments"(args: {
|
|
@@ -567,7 +665,7 @@ export interface FunctionApi {
|
|
|
567
665
|
"query"(args: {
|
|
568
666
|
"databaseId": string | number;
|
|
569
667
|
body: unknown;
|
|
570
|
-
}): Promise<any>;
|
|
668
|
+
}): Promise<{ items: any[]; hasMore: boolean; nextCursor?: string; prevCursor?: string }>;
|
|
571
669
|
/** `databases.records.registerIndex` — POST /databases/{databaseId}/records/index/register. Database records: index/register (requires manager-or-higher on the database, or an app-admin/owner role) */
|
|
572
670
|
"registerIndex"(args: {
|
|
573
671
|
"databaseId": string | number;
|
|
@@ -632,6 +730,12 @@ export interface FunctionApi {
|
|
|
632
730
|
}): Promise<any>;
|
|
633
731
|
};
|
|
634
732
|
"documents": {
|
|
733
|
+
/** `documents.abortIngest` — POST /documents/{documentId}/ingest/{sessionId}/abort. Abort a bulk-load session before its swap */
|
|
734
|
+
"abortIngest"(args: {
|
|
735
|
+
"documentId": string | number;
|
|
736
|
+
"sessionId": string | number;
|
|
737
|
+
body: unknown;
|
|
738
|
+
}): Promise<any>;
|
|
635
739
|
/** `documents.addTag` — POST /documents/{documentId}/tags. Add a tag to a document */
|
|
636
740
|
"addTag"(args: {
|
|
637
741
|
"documentId": string | number;
|
|
@@ -709,10 +813,21 @@ export interface FunctionApi {
|
|
|
709
813
|
"clearLinkAccess"(args: {
|
|
710
814
|
"documentId": string | number;
|
|
711
815
|
}): Promise<any>;
|
|
816
|
+
/** `documents.commitIngest` — POST /documents/{documentId}/ingest/{sessionId}/commit. Commit a bulk-load session: freeze its manifest and apply it */
|
|
817
|
+
"commitIngest"(args: {
|
|
818
|
+
"documentId": string | number;
|
|
819
|
+
"sessionId": string | number;
|
|
820
|
+
body: unknown;
|
|
821
|
+
}): Promise<any>;
|
|
712
822
|
/** `documents.create` — POST /documents. Create a new document */
|
|
713
823
|
"create"(args: {
|
|
714
824
|
body: unknown;
|
|
715
825
|
}): Promise<any>;
|
|
826
|
+
/** `documents.createIngest` — POST /documents/{documentId}/ingest. Open a bulk-load session on a large document */
|
|
827
|
+
"createIngest"(args: {
|
|
828
|
+
"documentId": string | number;
|
|
829
|
+
body: unknown;
|
|
830
|
+
}): Promise<any>;
|
|
716
831
|
/** `documents.createWithAlias` — POST /documents/create-with-alias. Create a document and bind it to an alias */
|
|
717
832
|
"createWithAlias"(args: {
|
|
718
833
|
body: unknown;
|
|
@@ -770,6 +885,11 @@ export interface FunctionApi {
|
|
|
770
885
|
"getImportChainStatus"(args: {
|
|
771
886
|
"documentId": string | number;
|
|
772
887
|
}): Promise<any>;
|
|
888
|
+
/** `documents.getIngest` — GET /documents/{documentId}/ingest/{sessionId}. One bulk-load session's status */
|
|
889
|
+
"getIngest"(args: {
|
|
890
|
+
"documentId": string | number;
|
|
891
|
+
"sessionId": string | number;
|
|
892
|
+
}): Promise<any>;
|
|
773
893
|
/** `documents.getLinkAccess` — GET /documents/{documentId}/link-access. Get the document's "anyone with the link" access level */
|
|
774
894
|
"getLinkAccess"(args: {
|
|
775
895
|
"documentId": string | number;
|
|
@@ -786,6 +906,11 @@ export interface FunctionApi {
|
|
|
786
906
|
"getSchema"(args: {
|
|
787
907
|
"documentId": string | number;
|
|
788
908
|
}): Promise<any>;
|
|
909
|
+
/** `documents.getSnapshot` — GET /documents/{documentId}/snapshots/{buildId}. One snapshot build with its verification result */
|
|
910
|
+
"getSnapshot"(args: {
|
|
911
|
+
"documentId": string | number;
|
|
912
|
+
"buildId": string | number;
|
|
913
|
+
}): Promise<any>;
|
|
789
914
|
/** `documents.getStats` — GET /documents/{documentId}/stats. Document statistics (record/model/blob counts, approximate size) */
|
|
790
915
|
"getStats"(args: {
|
|
791
916
|
"documentId": string | number;
|
|
@@ -823,10 +948,22 @@ export interface FunctionApi {
|
|
|
823
948
|
"listGroupPermissions"(args: {
|
|
824
949
|
"documentId": string | number;
|
|
825
950
|
}): Promise<any>;
|
|
951
|
+
/** `documents.listIngests` — GET /documents/{documentId}/ingest. List a large document's bulk-load sessions, newest first */
|
|
952
|
+
"listIngests"(args: {
|
|
953
|
+
"documentId": string | number;
|
|
954
|
+
"limit"?: string | number | boolean;
|
|
955
|
+
"cursor"?: string | number | boolean;
|
|
956
|
+
}): Promise<any>;
|
|
826
957
|
/** `documents.listPendingInvitations` — GET /documents/{documentId}/pending-invitations. List a document's pending (deferred) invitations */
|
|
827
958
|
"listPendingInvitations"(args: {
|
|
828
959
|
"documentId": string | number;
|
|
829
960
|
}): Promise<any>;
|
|
961
|
+
/** `documents.listSnapshots` — GET /documents/{documentId}/snapshots. List a large document's snapshot builds, newest first */
|
|
962
|
+
"listSnapshots"(args: {
|
|
963
|
+
"documentId": string | number;
|
|
964
|
+
"limit"?: string | number | boolean;
|
|
965
|
+
"cursor"?: string | number | boolean;
|
|
966
|
+
}): Promise<any>;
|
|
830
967
|
/** `documents.open` — POST /documents/open. Open a document for collaboration (resolves access + alias) */
|
|
831
968
|
"open"(args: {
|
|
832
969
|
body: unknown;
|
|
@@ -847,6 +984,7 @@ export interface FunctionApi {
|
|
|
847
984
|
"count"(args: {
|
|
848
985
|
"documentId": string | number;
|
|
849
986
|
"model": string | number;
|
|
987
|
+
"filter"?: Record<string, unknown> | string;
|
|
850
988
|
}): Promise<any>;
|
|
851
989
|
/** `documents.records.delete` — DELETE /documents/{documentId}/records/{model}/{recordId}. Delete a record from a document model */
|
|
852
990
|
"delete"(args: {
|
|
@@ -865,6 +1003,9 @@ export interface FunctionApi {
|
|
|
865
1003
|
"query"(args: {
|
|
866
1004
|
"documentId": string | number;
|
|
867
1005
|
"model": string | number;
|
|
1006
|
+
"limit"?: string | number | boolean;
|
|
1007
|
+
"cursor"?: string | number | boolean;
|
|
1008
|
+
"filter"?: Record<string, unknown> | string;
|
|
868
1009
|
}): Promise<any>;
|
|
869
1010
|
/** `documents.records.save` — POST /documents/{documentId}/records/{model}. Create or replace a record in a document model */
|
|
870
1011
|
"save"(args: {
|
|
@@ -893,6 +1034,11 @@ export interface FunctionApi {
|
|
|
893
1034
|
"documentId": string | number;
|
|
894
1035
|
body: unknown;
|
|
895
1036
|
}): Promise<any>;
|
|
1037
|
+
/** `documents.requestSnapshot` — POST /documents/{documentId}/snapshots. Snapshot a large document now: seal the open epoch and build a base */
|
|
1038
|
+
"requestSnapshot"(args: {
|
|
1039
|
+
"documentId": string | number;
|
|
1040
|
+
body: unknown;
|
|
1041
|
+
}): Promise<any>;
|
|
896
1042
|
/** `documents.revokeGroupPermission` — DELETE /documents/{documentId}/group-permissions/{groupType}/{groupId}. Revoke a group permission on a document */
|
|
897
1043
|
"revokeGroupPermission"(args: {
|
|
898
1044
|
"documentId": string | number;
|
|
@@ -919,6 +1065,12 @@ export interface FunctionApi {
|
|
|
919
1065
|
"documentId": string | number;
|
|
920
1066
|
body: unknown;
|
|
921
1067
|
}): Promise<any>;
|
|
1068
|
+
/** `documents.uploadIngestChunk` — POST /documents/{documentId}/ingest/{sessionId}/chunks. Upload one chunk of a bulk-load session's artifact */
|
|
1069
|
+
"uploadIngestChunk"(args: {
|
|
1070
|
+
"documentId": string | number;
|
|
1071
|
+
"sessionId": string | number;
|
|
1072
|
+
body: FormData | ArrayBuffer | Uint8Array | string;
|
|
1073
|
+
}): Promise<any>;
|
|
922
1074
|
/** `documents.validateAccess` — POST /documents/{documentId}/validate-access. Resolve the caller's effective access level for a document */
|
|
923
1075
|
"validateAccess"(args: {
|
|
924
1076
|
"documentId": string | number;
|
|
@@ -931,11 +1083,28 @@ export interface FunctionApi {
|
|
|
931
1083
|
}): Promise<any>;
|
|
932
1084
|
};
|
|
933
1085
|
"functions": {
|
|
934
|
-
/** `functions.invoke` — POST /functions/{functionKey}. Invoke a server function: a
|
|
1086
|
+
/** `functions.invoke` — POST /functions/{functionKey}. Invoke a server function: a request function returns its result, a task function starts a run */
|
|
935
1087
|
"invoke"(args: {
|
|
936
1088
|
"functionKey": string | number;
|
|
937
1089
|
body?: unknown;
|
|
938
1090
|
}): Promise<any>;
|
|
1091
|
+
/** `functions.invokeAsSystem` — POST /functions/{functionKey}/invoke-as-system. Invoke a server function as the system, with no caller */
|
|
1092
|
+
"invokeAsSystem"(args: {
|
|
1093
|
+
"functionKey": string | number;
|
|
1094
|
+
body?: unknown;
|
|
1095
|
+
}): Promise<any>;
|
|
1096
|
+
/** `functions.logs` — GET /functions/{functionKey}/logs. List a server function's invocation logs, newest first */
|
|
1097
|
+
"logs"(args: {
|
|
1098
|
+
"functionKey": string | number;
|
|
1099
|
+
"limit"?: string | number | boolean;
|
|
1100
|
+
"cursor"?: string | number | boolean;
|
|
1101
|
+
"runId"?: string | number | boolean;
|
|
1102
|
+
}): Promise<any>;
|
|
1103
|
+
/** `functions.start` — POST /functions/{functionKey}/start. Start a server function as a task run */
|
|
1104
|
+
"start"(args: {
|
|
1105
|
+
"functionKey": string | number;
|
|
1106
|
+
body?: unknown;
|
|
1107
|
+
}): Promise<any>;
|
|
939
1108
|
};
|
|
940
1109
|
"gemini": {
|
|
941
1110
|
/** `gemini.countTokens` — POST /gemini/count-tokens. Count tokens for a Gemini request */
|
|
@@ -1043,18 +1212,6 @@ export interface FunctionApi {
|
|
|
1043
1212
|
"integrationKey": string | number;
|
|
1044
1213
|
}): Promise<any>;
|
|
1045
1214
|
};
|
|
1046
|
-
"iterations": {
|
|
1047
|
-
/** `iterations.get` — GET /iterations/{iterationName}. Get details for a single iteration */
|
|
1048
|
-
"get"(args: {
|
|
1049
|
-
"iterationName": string | number;
|
|
1050
|
-
}): Promise<any>;
|
|
1051
|
-
/** `iterations.list` — GET /iterations. List iteration runs */
|
|
1052
|
-
"list"(args?: Record<string, never>): Promise<any>;
|
|
1053
|
-
/** `iterations.reset` — POST /iterations/{iterationName}/reset. Reset a terminal iteration so the next trigger runs fresh */
|
|
1054
|
-
"reset"(args: {
|
|
1055
|
-
"iterationName": string | number;
|
|
1056
|
-
}): Promise<any>;
|
|
1057
|
-
};
|
|
1058
1215
|
"llm": {
|
|
1059
1216
|
/** `llm.chat` — POST /llm/chat. Run an LLM chat completion */
|
|
1060
1217
|
"chat"(args: {
|
|
@@ -1230,6 +1387,39 @@ export type DatabaseModels<K extends string> = K extends keyof DatabaseSchemas
|
|
|
1230
1387
|
? DatabaseSchemas[K]
|
|
1231
1388
|
: Record<string, Record<string, unknown>>;
|
|
1232
1389
|
|
|
1390
|
+
/**
|
|
1391
|
+
* The app's functions, key by key — EMPTY here and filled by the declaration
|
|
1392
|
+
* `primitive config push` writes into the config tree's `functions/`
|
|
1393
|
+
* directory (`primitive-function-types.d.ts`): each key's declared input and
|
|
1394
|
+
* output types, from its `inputSchema` and `outputSchema`. It is what types
|
|
1395
|
+
* `defineFunction("<key>", handler)`.
|
|
1396
|
+
*/
|
|
1397
|
+
export interface FunctionSchemas {}
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* The keys `defineFunction(key, handler)` accepts: every key the augmentation
|
|
1401
|
+
* declares once a tree has pushed, so a key the tree does not declare is a
|
|
1402
|
+
* compile error — and `string` before that, the `DatabaseTypeKeys` rule, so an
|
|
1403
|
+
* unaugmented tree keeps compiling.
|
|
1404
|
+
*/
|
|
1405
|
+
export type FunctionKeys = [keyof FunctionSchemas] extends [never]
|
|
1406
|
+
? string
|
|
1407
|
+
: keyof FunctionSchemas & string;
|
|
1408
|
+
|
|
1409
|
+
/** A declared function's input type, or `any` when nothing is declared. */
|
|
1410
|
+
export type FunctionInput<K extends string> = K extends keyof FunctionSchemas
|
|
1411
|
+
? FunctionSchemas[K] extends { input: infer I }
|
|
1412
|
+
? I
|
|
1413
|
+
: any
|
|
1414
|
+
: any;
|
|
1415
|
+
|
|
1416
|
+
/** A declared function's output type, or `any` when nothing is declared. */
|
|
1417
|
+
export type FunctionOutput<K extends string> = K extends keyof FunctionSchemas
|
|
1418
|
+
? FunctionSchemas[K] extends { output: infer O }
|
|
1419
|
+
? O
|
|
1420
|
+
: any
|
|
1421
|
+
: any;
|
|
1422
|
+
|
|
1233
1423
|
/**
|
|
1234
1424
|
* The model names one database type addresses — its own, or any name at all
|
|
1235
1425
|
* for a type that declares no schema (the DO is schemaless, so a grant on such
|
|
@@ -1239,9 +1429,38 @@ export type DatabaseModelNames<TModels> = [keyof TModels] extends [never]
|
|
|
1239
1429
|
? string
|
|
1240
1430
|
: keyof TModels & string;
|
|
1241
1431
|
|
|
1432
|
+
/**
|
|
1433
|
+
* A row as the platform HANDS IT BACK: whatever the schema declared, plus the
|
|
1434
|
+
* record identity the platform owns (#3450).
|
|
1435
|
+
*
|
|
1436
|
+
* Every stored record has an `id`. A save that arrives without one is given a
|
|
1437
|
+
* ULID, a projection always keeps it, and `delete` and `patch` take nothing
|
|
1438
|
+
* else — so a function that queries a model and then moves one of its rows
|
|
1439
|
+
* needs the id of the row it just read. A schema is free to say nothing about
|
|
1440
|
+
* that field, and most do; the identity is the platform's, not the schema's,
|
|
1441
|
+
* so it is added here rather than rendered into each declaration.
|
|
1442
|
+
*
|
|
1443
|
+
* A declared `id` is REPLACED, never intersected: one declared optional would
|
|
1444
|
+
* stay optional on a read row it is always present on, and one declared with
|
|
1445
|
+
* some other type would intersect to `never` and be unusable. The platform
|
|
1446
|
+
* stamps a string whatever the schema says.
|
|
1447
|
+
*
|
|
1448
|
+
* An `any` row stays `any` — `DatabaseHandle<any>` is `defineQuery`'s default
|
|
1449
|
+
* handle, and turning its rows into an object with one known member would
|
|
1450
|
+
* narrow code that was deliberately left open.
|
|
1451
|
+
*
|
|
1452
|
+
* Writes are untouched: every one of them takes `Partial<TRow>`, so a row a
|
|
1453
|
+
* function BUILDS still needs no id.
|
|
1454
|
+
*/
|
|
1455
|
+
export type PlatformRow<TRow> = 0 extends 1 & TRow
|
|
1456
|
+
? TRow
|
|
1457
|
+
: Omit<TRow, "id"> & { id: string };
|
|
1458
|
+
|
|
1242
1459
|
/** One model's row shape, open when the type declares no schema. */
|
|
1243
1460
|
export type DatabaseModelRow<TModels, M extends string> =
|
|
1244
|
-
M extends keyof TModels
|
|
1461
|
+
M extends keyof TModels
|
|
1462
|
+
? PlatformRow<TModels[M]>
|
|
1463
|
+
: Record<string, unknown> & { id: string };
|
|
1245
1464
|
|
|
1246
1465
|
/**
|
|
1247
1466
|
* One model of one database, scoped: the `modelName` every records call needs
|
|
@@ -1274,10 +1493,40 @@ export type ModelBatchOperation<TRow> = {
|
|
|
1274
1493
|
};
|
|
1275
1494
|
|
|
1276
1495
|
export interface DatabaseModelHandle<TRow> {
|
|
1277
|
-
|
|
1496
|
+
/**
|
|
1497
|
+
* One page of this model's rows, in the decided envelope — `{ items,
|
|
1498
|
+
* hasMore, nextCursor? }` (#3287), the same shape `ctx.doc(...)`,
|
|
1499
|
+
* `ctx.users.list` and the client library answer. The route's own wire
|
|
1500
|
+
* shape is unchanged; the SDK is where the one name lives, so shared paging
|
|
1501
|
+
* code can be written once.
|
|
1502
|
+
*/
|
|
1503
|
+
query(body?: ModelScopedBody): Promise<{ items: TRow[]; hasMore: boolean; nextCursor?: string }>;
|
|
1278
1504
|
count(body?: ModelScopedBody): Promise<any>;
|
|
1279
1505
|
aggregate(body: ModelScopedBody): Promise<any>;
|
|
1280
1506
|
save(body: ModelScopedBody<{ id?: string; data: Partial<TRow>; [key: string]: unknown }>): Promise<any>;
|
|
1507
|
+
/**
|
|
1508
|
+
* Change some fields of ONE row — `databases.records.patch`, with this
|
|
1509
|
+
* handle's model bound (#3450).
|
|
1510
|
+
*
|
|
1511
|
+
* The record id is positional and the body may not carry another, for the
|
|
1512
|
+
* same reason it may not name another model: the runtime assigns both LAST,
|
|
1513
|
+
* so a body that appeared to choose either would be a lie about which row
|
|
1514
|
+
* moved. `condition`, `stringSets` and the rest of the operation's own keys
|
|
1515
|
+
* pass through untouched.
|
|
1516
|
+
*/
|
|
1517
|
+
patch(
|
|
1518
|
+
recordId: string,
|
|
1519
|
+
body: ModelScopedBody<{ data: Partial<TRow>; id?: never; [key: string]: unknown }>
|
|
1520
|
+
): Promise<any>;
|
|
1521
|
+
/**
|
|
1522
|
+
* Remove ONE row by the id a read handed back — `databases.records.delete`,
|
|
1523
|
+
* with this handle's model bound (#3450). An optional `condition` makes it
|
|
1524
|
+
* conditional, and travels untouched.
|
|
1525
|
+
*/
|
|
1526
|
+
delete(
|
|
1527
|
+
recordId: string,
|
|
1528
|
+
body?: ModelScopedBody<{ condition?: Record<string, unknown>; id?: never }>
|
|
1529
|
+
): Promise<any>;
|
|
1281
1530
|
/** Several writes to THIS model in one request; the binding is per item. */
|
|
1282
1531
|
batch(body: {
|
|
1283
1532
|
operations: Array<ModelBatchOperation<TRow>>;
|
|
@@ -1306,6 +1555,84 @@ export interface DatabaseHandle<TModels> {
|
|
|
1306
1555
|
runOperation(name: string, params?: Record<string, unknown>): Promise<any>;
|
|
1307
1556
|
}
|
|
1308
1557
|
|
|
1558
|
+
/**
|
|
1559
|
+
* The app's DOCUMENT models — EMPTY here and filled by the declaration
|
|
1560
|
+
* `primitive config push` writes into the config tree's `functions/` directory
|
|
1561
|
+
* (`primitive-document-types.d.ts`, from the project's `models/models.toml`).
|
|
1562
|
+
* A project with no document schema gets the open form and still compiles.
|
|
1563
|
+
*/
|
|
1564
|
+
export interface DocumentSchemas {}
|
|
1565
|
+
|
|
1566
|
+
/** The model names `ctx.doc(id).model()` accepts — every declared one, or `string` before a push. */
|
|
1567
|
+
export type DocumentModelNames = [keyof DocumentSchemas] extends [never]
|
|
1568
|
+
? string
|
|
1569
|
+
: keyof DocumentSchemas & string;
|
|
1570
|
+
|
|
1571
|
+
/**
|
|
1572
|
+
* A document model's row shape, or an open record for an undeclared schema —
|
|
1573
|
+
* carrying the platform's record identity either way (#3450), by the same rule
|
|
1574
|
+
* and for the same reason as a database row: the records DO is one
|
|
1575
|
+
* implementation, and `patch` and `delete` here take an id too.
|
|
1576
|
+
*/
|
|
1577
|
+
export type DocumentModelRow<M extends string> = M extends keyof DocumentSchemas
|
|
1578
|
+
? PlatformRow<DocumentSchemas[M]>
|
|
1579
|
+
: Record<string, unknown> & { id: string };
|
|
1580
|
+
|
|
1581
|
+
/** The options a document model read takes: a filter object (or its JSON), a page size, a cursor. */
|
|
1582
|
+
export interface DocumentQueryOptions {
|
|
1583
|
+
filter?: Record<string, unknown> | string;
|
|
1584
|
+
limit?: number;
|
|
1585
|
+
cursor?: string;
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
/**
|
|
1589
|
+
* One document model, bound to its document and its model name — a thin
|
|
1590
|
+
* binding over `ctx.api.documents.records.*` with the route's own shapes.
|
|
1591
|
+
*/
|
|
1592
|
+
/**
|
|
1593
|
+
* One op of a document `batch` — the `documents.records.bulk` blob's shape,
|
|
1594
|
+
* typed to this handle's model (#3455).
|
|
1595
|
+
*
|
|
1596
|
+
* `model` is NOT a member: the handle already names it and assigns it last, so
|
|
1597
|
+
* a multi-model blob stays on the raw `ctx.api.documents.records.bulk`
|
|
1598
|
+
* operation rather than becoming a second way to say the same thing.
|
|
1599
|
+
*/
|
|
1600
|
+
export type DocumentBatchOp<TRow> =
|
|
1601
|
+
| { action: "create" | "patch"; id: string; data: Partial<TRow>; precondition?: Record<string, unknown> }
|
|
1602
|
+
| { action: "delete"; id: string; precondition?: Record<string, unknown> };
|
|
1603
|
+
|
|
1604
|
+
/** What `documents.records.bulk` answers: the blob's aggregate effect. */
|
|
1605
|
+
export interface DocumentBulkResult {
|
|
1606
|
+
applied: number;
|
|
1607
|
+
added: Array<{ model: string; id: string }>;
|
|
1608
|
+
updated: Array<{ model: string; id: string }>;
|
|
1609
|
+
deleted: number;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
export interface DocumentModelHandle<TRow> {
|
|
1613
|
+
query(options?: DocumentQueryOptions): Promise<{ items: TRow[]; hasMore: boolean; nextCursor?: string }>;
|
|
1614
|
+
count(options?: { filter?: Record<string, unknown> | string }): Promise<{ count: number }>;
|
|
1615
|
+
aggregate(body: Record<string, unknown>): Promise<any>;
|
|
1616
|
+
save(body: { id: string; data: Partial<TRow>; options?: Record<string, unknown> }): Promise<{ record: TRow }>;
|
|
1617
|
+
patch(recordId: string, body: { data: Partial<TRow>; options?: Record<string, unknown> }): Promise<{ record: TRow }>;
|
|
1618
|
+
delete(recordId: string): Promise<{ deleted: boolean }>;
|
|
1619
|
+
/**
|
|
1620
|
+
* Apply an ordered blob of this model's ops in ONE transaction — all of it
|
|
1621
|
+
* commits or none of it does, and connected clients see one update.
|
|
1622
|
+
*
|
|
1623
|
+
* One model's ops, by construction: every op's `model` is this handle's.
|
|
1624
|
+
* A blob that spans models is the raw `ctx.api.documents.records.bulk`
|
|
1625
|
+
* operation's job.
|
|
1626
|
+
*/
|
|
1627
|
+
batch(ops: Array<DocumentBatchOp<TRow>>): Promise<DocumentBulkResult>;
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
/** A document, addressed once; its models are typed from `DocumentSchemas`. */
|
|
1631
|
+
export interface DocumentHandle {
|
|
1632
|
+
documentId: string;
|
|
1633
|
+
model<M extends DocumentModelNames>(modelName: M): DocumentModelHandle<DocumentModelRow<M>>;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1309
1636
|
/**
|
|
1310
1637
|
* One call through a granted integration — #3183.
|
|
1311
1638
|
*
|
|
@@ -1347,15 +1674,94 @@ export interface PromptRunArgs {
|
|
|
1347
1674
|
configId?: string;
|
|
1348
1675
|
}
|
|
1349
1676
|
|
|
1350
|
-
/**
|
|
1351
|
-
|
|
1677
|
+
/**
|
|
1678
|
+
* The app's PROMPTS — EMPTY here and filled by the declaration
|
|
1679
|
+
* `primitive config push` writes into the config tree's `functions/` directory
|
|
1680
|
+
* (`primitive-prompt-types.d.ts`, from the tree's `prompts/*.toml`). A prompt
|
|
1681
|
+
* that declares an `outputSchema` carries `{ output: <Key>PromptOutput }`; one
|
|
1682
|
+
* that declares none carries `{}`, so reading `parsed.field` on it is a
|
|
1683
|
+
* compile error rather than a runtime `undefined`.
|
|
1684
|
+
*/
|
|
1685
|
+
export interface PromptSchemas {}
|
|
1686
|
+
|
|
1687
|
+
/** The keys `ctx.prompts.run` accepts — every declared one, or `string` before a push. */
|
|
1688
|
+
export type PromptKeys = [keyof PromptSchemas] extends [never]
|
|
1689
|
+
? string
|
|
1690
|
+
: keyof PromptSchemas & string;
|
|
1691
|
+
|
|
1692
|
+
/** One prompt's declared output type, or `unknown` where none is declared. */
|
|
1693
|
+
export type PromptOutput<K extends string> = K extends keyof PromptSchemas
|
|
1694
|
+
? PromptSchemas[K] extends { output: infer O }
|
|
1695
|
+
? O
|
|
1696
|
+
: unknown
|
|
1697
|
+
: unknown;
|
|
1698
|
+
|
|
1699
|
+
/**
|
|
1700
|
+
* Why a prompt's own answer was refused — #3330. Never set on a PROVIDER
|
|
1701
|
+
* failure, which is what makes "the model returned the wrong shape"
|
|
1702
|
+
* distinguishable from "the model failed".
|
|
1703
|
+
*/
|
|
1704
|
+
export type PromptOutputErrorCode =
|
|
1705
|
+
| "PROMPT_OUTPUT_NOT_JSON"
|
|
1706
|
+
| "PROMPT_OUTPUT_SCHEMA_VIOLATION";
|
|
1707
|
+
|
|
1708
|
+
/** A prompt that declares an output shape, when the answer matched it. */
|
|
1709
|
+
export interface PromptRunSuccess<TParsed> {
|
|
1710
|
+
success: true;
|
|
1711
|
+
output: string;
|
|
1712
|
+
/** The parsed, validated answer — no caller-side `JSON.parse` (#3330). */
|
|
1713
|
+
parsed: TParsed;
|
|
1714
|
+
error?: null;
|
|
1715
|
+
errorCode?: null;
|
|
1716
|
+
metrics?: Record<string, unknown>;
|
|
1717
|
+
configId: string;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
/**
|
|
1721
|
+
* The failure arm, whichever failed. `errorCode` is set for a SHAPE failure
|
|
1722
|
+
* and absent for a provider one; `output` carries the text either way, which
|
|
1723
|
+
* is where the model's own value lives — a validation `error` names paths and
|
|
1724
|
+
* schema constraints only.
|
|
1725
|
+
*/
|
|
1726
|
+
export interface PromptRunFailure {
|
|
1727
|
+
success: false;
|
|
1728
|
+
output: string;
|
|
1729
|
+
error: string | null;
|
|
1730
|
+
errorCode?: PromptOutputErrorCode | null;
|
|
1731
|
+
parsed?: undefined;
|
|
1732
|
+
metrics?: Record<string, unknown>;
|
|
1733
|
+
configId: string;
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
/** The envelope for a key whose declaration says nothing about its output. */
|
|
1737
|
+
export interface PromptRunOpenResult {
|
|
1352
1738
|
success: boolean;
|
|
1353
1739
|
output: string;
|
|
1740
|
+
/**
|
|
1741
|
+
* Present when the config that ran declares `outputFormat = "json"` and the
|
|
1742
|
+
* text parsed. Untyped: nothing declared its shape.
|
|
1743
|
+
*/
|
|
1744
|
+
parsed?: unknown;
|
|
1354
1745
|
error?: string | null;
|
|
1746
|
+
errorCode?: PromptOutputErrorCode | null;
|
|
1355
1747
|
metrics?: Record<string, unknown>;
|
|
1356
1748
|
configId: string;
|
|
1357
1749
|
}
|
|
1358
1750
|
|
|
1751
|
+
/**
|
|
1752
|
+
* The member execute envelope, plus what the prompt's own declaration adds.
|
|
1753
|
+
*
|
|
1754
|
+
* For a key whose `prompts/<key>.toml` declares an `outputSchema`, this is a
|
|
1755
|
+
* discriminated union: narrow on `success` and `parsed` is the declared type,
|
|
1756
|
+
* required. For every other key — and in a tree that has not pushed — it is
|
|
1757
|
+
* the open shape, with `parsed` optional and `unknown`.
|
|
1758
|
+
*/
|
|
1759
|
+
export type PromptRunResult<K extends string = string> = K extends keyof PromptSchemas
|
|
1760
|
+
? PromptSchemas[K] extends { output: infer O }
|
|
1761
|
+
? PromptRunSuccess<O> | PromptRunFailure
|
|
1762
|
+
: PromptRunOpenResult
|
|
1763
|
+
: PromptRunOpenResult;
|
|
1764
|
+
|
|
1359
1765
|
/** What a send delivered to. */
|
|
1360
1766
|
export interface SendResult {
|
|
1361
1767
|
/** Unique live connections the frame was sent to. Zero is a success. */
|
|
@@ -1364,9 +1770,127 @@ export interface SendResult {
|
|
|
1364
1770
|
truncated: boolean;
|
|
1365
1771
|
}
|
|
1366
1772
|
|
|
1773
|
+
/** Who a channel grant is for, and for how long — #3184. */
|
|
1774
|
+
export interface ChannelAuthorizeOptions {
|
|
1775
|
+
/**
|
|
1776
|
+
* The member the grant names. Caller mode defaults to the invoking caller;
|
|
1777
|
+
* system mode has no caller and must say.
|
|
1778
|
+
*/
|
|
1779
|
+
userId?: string;
|
|
1780
|
+
/** Default 300 s, clamped to the platform ceiling of 900 s. */
|
|
1781
|
+
ttlSeconds?: number;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
/** The credential a client presents on the WebSocket it already has. */
|
|
1785
|
+
export interface ChannelGrantResult {
|
|
1786
|
+
channel: string;
|
|
1787
|
+
/** The signed grant. Hand it to the client; it is not readable here. */
|
|
1788
|
+
grant: string;
|
|
1789
|
+
/** Epoch milliseconds. Expiry is the only revocation a channel has. */
|
|
1790
|
+
expiresAt: number;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
/** Where to start and how big a page to take — #3280. */
|
|
1794
|
+
export interface UserPageOptions {
|
|
1795
|
+
/** Page size. Capped by the route at 100. */
|
|
1796
|
+
limit?: number;
|
|
1797
|
+
/** The `nextCursor` of the page before this one. */
|
|
1798
|
+
cursor?: string;
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
/** One user on the roster, as the platform's own users route reports them. */
|
|
1802
|
+
export interface UserPageItem {
|
|
1803
|
+
userId: string;
|
|
1804
|
+
email: string | null;
|
|
1805
|
+
name: string | null;
|
|
1806
|
+
avatarUrl: string | null;
|
|
1807
|
+
role: string;
|
|
1808
|
+
addedAt: string | null;
|
|
1809
|
+
status: string;
|
|
1810
|
+
disabledAt: string | null;
|
|
1811
|
+
[key: string]: unknown;
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
/** The decided paged envelope, the same shape every paged read answers. */
|
|
1815
|
+
export interface UserPage {
|
|
1816
|
+
items: UserPageItem[];
|
|
1817
|
+
hasMore: boolean;
|
|
1818
|
+
/** Absent on the last page. */
|
|
1819
|
+
nextCursor?: string;
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
/** How a nested start is keyed and labelled — #3280. */
|
|
1823
|
+
export interface FunctionStartOptions {
|
|
1824
|
+
/**
|
|
1825
|
+
* Idempotency key, scoped to the tree's root initiator and the resolved
|
|
1826
|
+
* context document: a repeat replays the run that already exists rather than
|
|
1827
|
+
* starting a second. At most 100 characters.
|
|
1828
|
+
*/
|
|
1829
|
+
runKey?: string;
|
|
1830
|
+
/**
|
|
1831
|
+
* The document the child's run is keyed under. Defaults through the
|
|
1832
|
+
* inheritance rule: the parent run's context, else the root caller's root
|
|
1833
|
+
* document, else `fn:<the root function's id>`. At most 100 characters.
|
|
1834
|
+
*/
|
|
1835
|
+
contextDocId?: string;
|
|
1836
|
+
/** Caller metadata, at most 1 KB encoded. */
|
|
1837
|
+
meta?: Record<string, unknown>;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
/** The start envelope, the same one a workflow start answers with — #3280. */
|
|
1841
|
+
export interface FunctionStartResult {
|
|
1842
|
+
/** Poll this on the platform's run-status route. */
|
|
1843
|
+
runId: string;
|
|
1844
|
+
runKey: string;
|
|
1845
|
+
instanceId: string;
|
|
1846
|
+
status: string;
|
|
1847
|
+
/**
|
|
1848
|
+
* True when `runKey` already named a run in this tree, which this envelope
|
|
1849
|
+
* describes. That is what makes a run key a singleton.
|
|
1850
|
+
*/
|
|
1851
|
+
existing?: boolean;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1367
1854
|
export interface FunctionContext {
|
|
1368
|
-
|
|
1855
|
+
/** The HTTP caller, or null for a webhook or cron fire. */
|
|
1856
|
+
user: FunctionUser | null;
|
|
1369
1857
|
trigger: FunctionTrigger;
|
|
1858
|
+
/**
|
|
1859
|
+
* Which RUNTIME is hosting this code — #3482.
|
|
1860
|
+
*
|
|
1861
|
+
* Beside `trigger`, which says which DOOR fired, and they are different
|
|
1862
|
+
* questions: an HTTP call is whichever runtime the caller chose
|
|
1863
|
+
* (`invoke` or `start`), a cron fire is always a task and a webhook
|
|
1864
|
+
* delivery is always a request.
|
|
1865
|
+
*
|
|
1866
|
+
* To REFUSE a runtime rather than branch on it, call
|
|
1867
|
+
* `assertRuntime("task")` — at module scope to refuse it outright, or in
|
|
1868
|
+
* the handler to refuse one call.
|
|
1869
|
+
*/
|
|
1870
|
+
runtime: "request" | "task";
|
|
1871
|
+
/**
|
|
1872
|
+
* The RUN this invocation belongs to, or null — #3562.
|
|
1873
|
+
*
|
|
1874
|
+
* Set under the task runtime (every slice of the run, the first and every
|
|
1875
|
+
* resume) and for a webhook-fired request run, which writes a row. Null for
|
|
1876
|
+
* an HTTP `invoke`, which writes no run row at all.
|
|
1877
|
+
*
|
|
1878
|
+
* It is the deterministic OWNER a task run presents to re-take its own
|
|
1879
|
+
* lease: `ctx.api.locks.tryAcquire({ body: { key, ttlMs, owner: ctx.runId } })`
|
|
1880
|
+
* succeeds for the run that already holds the key, with a fresh handle.
|
|
1881
|
+
*/
|
|
1882
|
+
runId: string | null;
|
|
1883
|
+
/**
|
|
1884
|
+
* The SLICE of the run this code is running in, or null — #3562.
|
|
1885
|
+
*
|
|
1886
|
+
* The same identifier `primitive functions runs` and the run-status
|
|
1887
|
+
* route's `slice.sliceId` report. A task run is a sequence of slices: it
|
|
1888
|
+
* changes when the run hibernates and wakes, which is how a handler can tell
|
|
1889
|
+
* a resume from a first pass.
|
|
1890
|
+
*
|
|
1891
|
+
* Null under the request runtime: a request invocation is not a slice.
|
|
1892
|
+
*/
|
|
1893
|
+
sliceId: string | null;
|
|
1370
1894
|
api: FunctionApi;
|
|
1371
1895
|
/**
|
|
1372
1896
|
* A typed handle over one database. The second argument is the database TYPE
|
|
@@ -1377,6 +1901,13 @@ export interface FunctionContext {
|
|
|
1377
1901
|
databaseId: string,
|
|
1378
1902
|
databaseType: K
|
|
1379
1903
|
): DatabaseHandle<DatabaseModels<K>>;
|
|
1904
|
+
/**
|
|
1905
|
+
* A typed handle over one document's record models, typed from the
|
|
1906
|
+
* project's `models/models.toml` — `ctx.db`'s shape for documents. It
|
|
1907
|
+
* confers nothing: every call is a `documents.records.*` operation on the
|
|
1908
|
+
* same authority.
|
|
1909
|
+
*/
|
|
1910
|
+
doc(documentId: string): DocumentHandle;
|
|
1380
1911
|
/**
|
|
1381
1912
|
* Outbound HTTP, through a granted integration and nowhere else (#3183).
|
|
1382
1913
|
*
|
|
@@ -1394,14 +1925,53 @@ export interface FunctionContext {
|
|
|
1394
1925
|
): Promise<IntegrationCallResult>;
|
|
1395
1926
|
};
|
|
1396
1927
|
/**
|
|
1397
|
-
*
|
|
1928
|
+
* Start a TASK function from inside this one — #3280.
|
|
1929
|
+
*
|
|
1930
|
+
* The one nested door, and it is a START. A request function is code and
|
|
1931
|
+
* code composes by being IMPORTED, so there is no synchronous nested
|
|
1932
|
+
* invocation to reach for; a request-mode callee answers
|
|
1933
|
+
* `FUNCTION_MODE_MISMATCH`.
|
|
1934
|
+
*
|
|
1935
|
+
* The callee's `access` gate is not consulted — this function's own gate was
|
|
1936
|
+
* the authorization — and every run in the tree is keyed by whoever started
|
|
1937
|
+
* it, so the member who invoked the root polls and terminates them all.
|
|
1938
|
+
* Nesting is bounded at four levels.
|
|
1939
|
+
*/
|
|
1940
|
+
functions: {
|
|
1941
|
+
start(
|
|
1942
|
+
functionKey: string,
|
|
1943
|
+
input?: unknown,
|
|
1944
|
+
options?: FunctionStartOptions
|
|
1945
|
+
): Promise<FunctionStartResult>;
|
|
1946
|
+
};
|
|
1947
|
+
/**
|
|
1948
|
+
* Run one of the app's prompts, with nothing to declare (#3183, #3279).
|
|
1398
1949
|
*
|
|
1399
1950
|
* The prompt's `accessRule` is not consulted — it states which MEMBERS may
|
|
1400
|
-
* execute the prompt from a client, and the
|
|
1401
|
-
* call. The provider request is bounded by the invocation's
|
|
1951
|
+
* execute the prompt from a client, and the invocation gate is what
|
|
1952
|
+
* authorized this call. The provider request is bounded by the invocation's
|
|
1953
|
+
* own deadline.
|
|
1954
|
+
*
|
|
1955
|
+
* TYPED BY KEY (#3330). Where `prompts/<key>.toml` declares an
|
|
1956
|
+
* `outputSchema`, the platform parses the answer, validates it against that
|
|
1957
|
+
* schema and hands it back as `parsed`, typed — so the shape is written once
|
|
1958
|
+
* in TOML instead of restated as a `JSON.parse` at every call site. Where
|
|
1959
|
+
* only the config that ran declares `outputFormat = "json"`, `parsed` is
|
|
1960
|
+
* present but `unknown`. Where neither is declared the envelope is exactly
|
|
1961
|
+
* what it has always been.
|
|
1962
|
+
*
|
|
1963
|
+
* A shape the declaration refuses is `success: false` with an `errorCode`
|
|
1964
|
+
* (`PROMPT_OUTPUT_NOT_JSON` or `PROMPT_OUTPUT_SCHEMA_VIOLATION`) and the
|
|
1965
|
+
* text still in `output`; a PROVIDER failure has `error` and no
|
|
1966
|
+
* `errorCode`, so the two are told apart without guessing.
|
|
1967
|
+
*
|
|
1968
|
+
* Once a tree has pushed, a key it does not declare is a compile error.
|
|
1402
1969
|
*/
|
|
1403
1970
|
prompts: {
|
|
1404
|
-
run
|
|
1971
|
+
run<K extends PromptKeys>(
|
|
1972
|
+
promptKey: K,
|
|
1973
|
+
args?: PromptRunArgs
|
|
1974
|
+
): Promise<PromptRunResult<K>>;
|
|
1405
1975
|
};
|
|
1406
1976
|
/**
|
|
1407
1977
|
* The value of one app secret, under a `secret:<NAME>` grant (#3183).
|
|
@@ -1427,22 +1997,66 @@ export interface FunctionContext {
|
|
|
1427
1997
|
* error.
|
|
1428
1998
|
*/
|
|
1429
1999
|
users: {
|
|
2000
|
+
/**
|
|
2001
|
+
* One page of the app's users — #3280.
|
|
2002
|
+
*
|
|
2003
|
+
* On the APP's system authority, whoever invoked the function: a member
|
|
2004
|
+
* who passes this function's gate reads whatever roster it chooses to
|
|
2005
|
+
* expose, so say who may in the function's own `access` expression.
|
|
2006
|
+
* `limit` is capped by the route at 100.
|
|
2007
|
+
*/
|
|
2008
|
+
list(options?: UserPageOptions): Promise<UserPage>;
|
|
2009
|
+
/**
|
|
2010
|
+
* Every page of the app's users, in order — #3280.
|
|
2011
|
+
*
|
|
2012
|
+
* FOR A REQUEST FUNCTION AND A SINGLE-SLICE LOOP. A durable loop must take
|
|
2013
|
+
* its pages inside `step.do` with an EXPLICIT cursor: a memoized step does
|
|
2014
|
+
* not advance an iterator on resume, so an iteration across a sleep would
|
|
2015
|
+
* replay pages it had already taken.
|
|
2016
|
+
*/
|
|
2017
|
+
iterate(options?: UserPageOptions): AsyncIterable<UserPage>;
|
|
1430
2018
|
send(userId: string, payload: unknown): Promise<SendResult>;
|
|
1431
2019
|
};
|
|
1432
2020
|
/** The same frame to ONE connection, under a `connections:send` grant. */
|
|
1433
2021
|
connections: {
|
|
1434
2022
|
send(connectionId: string, payload: unknown): Promise<SendResult>;
|
|
1435
2023
|
};
|
|
2024
|
+
/**
|
|
2025
|
+
* Realtime channels, under a `channel:<namespace>` grant that COVERS the
|
|
2026
|
+
* channel — #3184.
|
|
2027
|
+
*
|
|
2028
|
+
* `authorize` hands back a short-lived grant for ONE member to present on
|
|
2029
|
+
* the socket it already has; `publish` delivers a `channel.message` frame to
|
|
2030
|
+
* every connection that has joined and whose grant has not expired. Expiry is
|
|
2031
|
+
* the only revocation, so `expiresAt` comes back for the client to renew
|
|
2032
|
+
* ahead of — a renewal is another authorize and another subscribe.
|
|
2033
|
+
*/
|
|
2034
|
+
channels: {
|
|
2035
|
+
authorize(
|
|
2036
|
+
channel: string,
|
|
2037
|
+
options?: ChannelAuthorizeOptions
|
|
2038
|
+
): Promise<ChannelGrantResult>;
|
|
2039
|
+
publish(channel: string, payload: unknown): Promise<SendResult>;
|
|
2040
|
+
};
|
|
1436
2041
|
}
|
|
1437
2042
|
|
|
1438
2043
|
/**
|
|
1439
|
-
* The
|
|
1440
|
-
*
|
|
2044
|
+
* The step handle. `step` is the third argument under BOTH runners, so the
|
|
2045
|
+
* same body runs either way — which is what `mode = "any"` is for (#3454).
|
|
2046
|
+
*
|
|
2047
|
+
* Under the TASK runner it is Cloudflare Workflows' `WorkflowStep`, forwarded
|
|
2048
|
+
* untouched: `step.do` results are memoized and replayed, and `step.sleep`
|
|
2049
|
+
* hibernates.
|
|
1441
2050
|
*
|
|
1442
|
-
*
|
|
1443
|
-
*
|
|
1444
|
-
*
|
|
1445
|
-
*
|
|
2051
|
+
* Under the REQUEST runner it is the platform's own, bounded by the request's
|
|
2052
|
+
* clock: `do` executes the body inline (there is no engine to memoize into,
|
|
2053
|
+
* and nothing is replayed); `sleep` and `sleepUntil` REALLY wait when the
|
|
2054
|
+
* remaining request budget covers the duration, and otherwise fail the
|
|
2055
|
+
* invocation with `errorCode: "FUNCTION_RUNTIME_REFUSED"` saying to start the
|
|
2056
|
+
* function as a task; `waitForEvent` fails the same way, because nothing can
|
|
2057
|
+
* deliver an event to an invocation that has to return now. The thrown error's
|
|
2058
|
+
* `name` is `STEP_NOT_AVAILABLE` in every case, so a body that catches it
|
|
2059
|
+
* keeps catching it.
|
|
1446
2060
|
*/
|
|
1447
2061
|
export interface FunctionStep {
|
|
1448
2062
|
do<T>(name: string, body: () => T | Promise<T>): Promise<T>;
|
|
@@ -1462,29 +2076,93 @@ export interface FunctionStep {
|
|
|
1462
2076
|
export declare const SDK_STUB_VERSION: string;
|
|
1463
2077
|
|
|
1464
2078
|
/**
|
|
1465
|
-
*
|
|
2079
|
+
* Thrown by `assertRuntime` when this function is running under the other
|
|
2080
|
+
* runtime — #3482.
|
|
2081
|
+
*
|
|
2082
|
+
* The platform settles it as `status: "failed"` with
|
|
2083
|
+
* `errorCode: "FUNCTION_RUNTIME_REFUSED"`, on a request invocation's
|
|
2084
|
+
* envelope and on a task run's row and record alike.
|
|
2085
|
+
*/
|
|
2086
|
+
export declare class FunctionRuntimeError extends Error {
|
|
2087
|
+
name: "FUNCTION_RUNTIME_REFUSED";
|
|
2088
|
+
/** The runtime this invocation is actually running under. */
|
|
2089
|
+
runtime: "request" | "task";
|
|
2090
|
+
/** The runtime the function asked for. */
|
|
2091
|
+
required: "request" | "task";
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
/**
|
|
2095
|
+
* Refuse the runtime this function was not written for — #3482.
|
|
2096
|
+
*
|
|
2097
|
+
* A function is a function and the caller picks the runtime at each call, so
|
|
2098
|
+
* nothing in config says which one a function may run under. This is the lock,
|
|
2099
|
+
* and it lives in the one place that can always be right about the code:
|
|
2100
|
+
*
|
|
2101
|
+
* ```ts
|
|
2102
|
+
* import { assertRuntime } from "primitive-functions";
|
|
2103
|
+
*
|
|
2104
|
+
* // At module scope: this function is never runnable inside a request.
|
|
2105
|
+
* assertRuntime("task");
|
|
2106
|
+
*
|
|
2107
|
+
* export default async function (input, ctx, step) {
|
|
2108
|
+
* await step.sleep("cool-off", "1 hour");
|
|
2109
|
+
* return { ok: true };
|
|
2110
|
+
* }
|
|
2111
|
+
* ```
|
|
2112
|
+
*
|
|
2113
|
+
* Returns when the runtimes match; otherwise throws
|
|
2114
|
+
* {@link FunctionRuntimeError}, which the platform settles as
|
|
2115
|
+
* `status: "failed"` with `errorCode: "FUNCTION_RUNTIME_REFUSED"` and a
|
|
2116
|
+
* message naming both runtimes and the verb that takes the one required.
|
|
2117
|
+
*/
|
|
2118
|
+
export declare function assertRuntime(required: "request" | "task"): void;
|
|
2119
|
+
|
|
2120
|
+
/**
|
|
2121
|
+
* The handler a function exports, typed for one declared key.
|
|
2122
|
+
*
|
|
2123
|
+
* `step` is the third argument under BOTH runners (#3186, #3454). A task run
|
|
2124
|
+
* gets the engine's live `WorkflowStep`; a request invocation gets the
|
|
2125
|
+
* platform's own, where `do` runs the body inline and a wait the request
|
|
2126
|
+
* budget cannot cover fails the invocation naming the task runner — so a
|
|
2127
|
+
* task-authored body can be exercised as a request, and the one place the two
|
|
2128
|
+
* genuinely differ says so rather than pretending.
|
|
2129
|
+
*/
|
|
2130
|
+
export type FunctionHandler<TInput, TOutput> = (
|
|
2131
|
+
input: TInput,
|
|
2132
|
+
ctx: FunctionContext,
|
|
2133
|
+
step: FunctionStep
|
|
2134
|
+
) => Promise<TOutput>;
|
|
2135
|
+
|
|
2136
|
+
/**
|
|
2137
|
+
* Declare a server function's handler, typed from its declaration.
|
|
1466
2138
|
*
|
|
1467
|
-
*
|
|
1468
|
-
*
|
|
1469
|
-
*
|
|
1470
|
-
*
|
|
2139
|
+
* The KEYED form, `defineFunction("<key>", handler)`, is typed from the
|
|
2140
|
+
* `FunctionSchemas` augmentation `primitive config push` writes beside the
|
|
2141
|
+
* sources: `input` is the key's declared input, the return is checked against
|
|
2142
|
+
* its declared output, and a key the tree does not declare is a compile error.
|
|
2143
|
+
* `config push` also refuses an entry whose key names another file's. In a
|
|
2144
|
+
* tree that has not pushed yet the key is any string and both types are `any`.
|
|
1471
2145
|
*
|
|
1472
|
-
*
|
|
1473
|
-
*
|
|
1474
|
-
* (`
|
|
1475
|
-
*
|
|
2146
|
+
* The UNKEYED form is what it always was: author-declared generics. Both
|
|
2147
|
+
* styles reach the platform bootstrap identically — a plain default export
|
|
2148
|
+
* taking `(input, ctx, step)` runs exactly as a wrapped one does — so this is
|
|
2149
|
+
* a typing and intent marker, not a different calling convention.
|
|
1476
2150
|
*/
|
|
2151
|
+
export declare function defineFunction<K extends FunctionKeys>(
|
|
2152
|
+
key: K,
|
|
2153
|
+
handler: (
|
|
2154
|
+
input: FunctionInput<K>,
|
|
2155
|
+
ctx: FunctionContext,
|
|
2156
|
+
step: FunctionStep
|
|
2157
|
+
) => FunctionOutput<K> | Promise<FunctionOutput<K>>
|
|
2158
|
+
): FunctionHandler<FunctionInput<K>, FunctionOutput<K>> & { functionKey: K };
|
|
1477
2159
|
export declare function defineFunction<TInput = unknown, TOutput = unknown>(
|
|
1478
2160
|
handler: (
|
|
1479
2161
|
input: TInput,
|
|
1480
2162
|
ctx: FunctionContext,
|
|
1481
2163
|
step: FunctionStep
|
|
1482
2164
|
) => TOutput | Promise<TOutput>
|
|
1483
|
-
):
|
|
1484
|
-
input: TInput,
|
|
1485
|
-
ctx: FunctionContext,
|
|
1486
|
-
step: FunctionStep
|
|
1487
|
-
) => Promise<TOutput>;
|
|
2165
|
+
): FunctionHandler<TInput, TOutput>;
|
|
1488
2166
|
|
|
1489
2167
|
/**
|
|
1490
2168
|
* One declared parameter of a registered query.
|
|
@@ -1493,13 +2171,64 @@ export declare function defineFunction<TInput = unknown, TOutput = unknown>(
|
|
|
1493
2171
|
* the platform injects the invocation's user and refuses a call that supplies
|
|
1494
2172
|
* the parameter itself.
|
|
1495
2173
|
*/
|
|
2174
|
+
/** The scalar parameter types, and an array parameter's element types. */
|
|
2175
|
+
export type QueryScalarParamType = "string" | "number" | "boolean" | "any";
|
|
2176
|
+
|
|
1496
2177
|
export interface QueryParamSpec {
|
|
1497
|
-
type?:
|
|
2178
|
+
type?: QueryScalarParamType | "$caller" | "array";
|
|
2179
|
+
/** For `type: "array"` — the element type; absent means any element. */
|
|
2180
|
+
items?: { type: QueryScalarParamType };
|
|
1498
2181
|
caller?: boolean;
|
|
1499
2182
|
optional?: boolean;
|
|
1500
2183
|
default?: unknown;
|
|
1501
2184
|
}
|
|
1502
2185
|
|
|
2186
|
+
/** A scalar parameter type's TypeScript type. */
|
|
2187
|
+
export type QueryScalarValue<T> = T extends "string"
|
|
2188
|
+
? string
|
|
2189
|
+
: T extends "number"
|
|
2190
|
+
? number
|
|
2191
|
+
: T extends "boolean"
|
|
2192
|
+
? boolean
|
|
2193
|
+
: T extends "$caller"
|
|
2194
|
+
? string
|
|
2195
|
+
: any;
|
|
2196
|
+
|
|
2197
|
+
/** The value `run` receives for one declared parameter. */
|
|
2198
|
+
export type QueryParamValue<S> = S extends { caller: true }
|
|
2199
|
+
? string
|
|
2200
|
+
: S extends { type: "array"; items: { type: infer I } }
|
|
2201
|
+
? QueryScalarValue<I>[]
|
|
2202
|
+
: S extends { type: "array" }
|
|
2203
|
+
? unknown[]
|
|
2204
|
+
: S extends { type: infer T }
|
|
2205
|
+
? QueryScalarValue<T>
|
|
2206
|
+
: any;
|
|
2207
|
+
|
|
2208
|
+
type QueryOptionalKeys<P> = {
|
|
2209
|
+
[K in keyof P]: P[K] extends { optional: true } ? K : never;
|
|
2210
|
+
}[keyof P];
|
|
2211
|
+
|
|
2212
|
+
/**
|
|
2213
|
+
* `run`'s `params`, typed from the declaration: scalars as their scalar,
|
|
2214
|
+
* `$caller` as a string, an array as `T[]`, an `optional: true` parameter
|
|
2215
|
+
* as an optional key (a parameter with a default is always present). An
|
|
2216
|
+
* undeclared name is a compile error.
|
|
2217
|
+
*/
|
|
2218
|
+
export type QueryParams<P> = {
|
|
2219
|
+
[K in Exclude<keyof P, QueryOptionalKeys<P>>]: QueryParamValue<P[K]>;
|
|
2220
|
+
} & {
|
|
2221
|
+
[K in QueryOptionalKeys<P>]?: QueryParamValue<P[K]>;
|
|
2222
|
+
};
|
|
2223
|
+
|
|
2224
|
+
/** A registration's definition with its parameters DECLARED, so `run` is typed from them. */
|
|
2225
|
+
export interface TypedQueryDefinition<TDb, TSpec extends Record<string, QueryParamSpec>, TResult> {
|
|
2226
|
+
models: string[];
|
|
2227
|
+
params?: TSpec;
|
|
2228
|
+
cache?: { ttlMs: number };
|
|
2229
|
+
run: (db: TDb, params: QueryParams<TSpec>) => TResult | Promise<TResult>;
|
|
2230
|
+
}
|
|
2231
|
+
|
|
1503
2232
|
export interface QueryDefinition<TDb, TParams, TResult> {
|
|
1504
2233
|
/** The models this query touches. Caching is off unless the run matches. */
|
|
1505
2234
|
models: string[];
|
|
@@ -1524,7 +2253,23 @@ export interface QueryDefinition<TDb, TParams, TResult> {
|
|
|
1524
2253
|
*
|
|
1525
2254
|
* Register at MODULE scope: a registration made inside the handler still works
|
|
1526
2255
|
* for direct calls but is invisible to `config push`'s manifest.
|
|
2256
|
+
*
|
|
2257
|
+
* `run`'s `params` are TYPED from the declaration (the first overload,
|
|
2258
|
+
* inferred with a `const` type parameter): a scalar as its scalar, `$caller`
|
|
2259
|
+
* as a string, `{ type: "array", items: { type: "string" } }` as `string[]`,
|
|
2260
|
+
* an `optional: true` parameter as an optional key; an undeclared name inside
|
|
2261
|
+
* `run` is a compile error. A declared default is coerced to the declared
|
|
2262
|
+
* type at registration, so `run` receives what the declaration promises. The
|
|
2263
|
+
* second overload keeps an explicit `TParams`.
|
|
1527
2264
|
*/
|
|
2265
|
+
export declare function defineQuery<
|
|
2266
|
+
const TSpec extends Record<string, QueryParamSpec>,
|
|
2267
|
+
TDb = DatabaseHandle<any>,
|
|
2268
|
+
TResult = any
|
|
2269
|
+
>(
|
|
2270
|
+
name: string,
|
|
2271
|
+
definition: TypedQueryDefinition<TDb, TSpec, TResult>
|
|
2272
|
+
): (db: TDb, params?: Record<string, unknown>) => Promise<TResult>;
|
|
1528
2273
|
export declare function defineQuery<
|
|
1529
2274
|
TDb = DatabaseHandle<any>,
|
|
1530
2275
|
TParams = Record<string, any>,
|
|
@@ -1535,6 +2280,14 @@ export declare function defineQuery<
|
|
|
1535
2280
|
): (db: TDb, params?: Record<string, unknown>) => Promise<TResult>;
|
|
1536
2281
|
|
|
1537
2282
|
/** The same, for a registration that writes. A mutation is never cached. */
|
|
2283
|
+
export declare function defineMutation<
|
|
2284
|
+
const TSpec extends Record<string, QueryParamSpec>,
|
|
2285
|
+
TDb = DatabaseHandle<any>,
|
|
2286
|
+
TResult = any
|
|
2287
|
+
>(
|
|
2288
|
+
name: string,
|
|
2289
|
+
definition: TypedQueryDefinition<TDb, TSpec, TResult>
|
|
2290
|
+
): (db: TDb, params?: Record<string, unknown>) => Promise<TResult>;
|
|
1538
2291
|
export declare function defineMutation<
|
|
1539
2292
|
TDb = DatabaseHandle<any>,
|
|
1540
2293
|
TParams = Record<string, any>,
|
|
@@ -1596,6 +2349,12 @@ export declare const stepPolicy: {
|
|
|
1596
2349
|
database: StepPolicy;
|
|
1597
2350
|
};
|
|
1598
2351
|
|
|
2352
|
+
// Every member the three runtime copies put on their own default export — the
|
|
2353
|
+
// platform's `sdk-core.ts`, the published stub and the CLI's collect stub —
|
|
2354
|
+
// and nothing else. A helper the module hands a default import but does not
|
|
2355
|
+
// declare here is one an author cannot call without the compiler refusing it
|
|
2356
|
+
// (#3482 CR3482-002); `tests/api/spec/function-profile.test.ts` holds the four
|
|
2357
|
+
// lists equal and compiles a default import against them.
|
|
1599
2358
|
declare const _default: {
|
|
1600
2359
|
SDK_STUB_VERSION: string;
|
|
1601
2360
|
defineFunction: typeof defineFunction;
|
|
@@ -1603,5 +2362,7 @@ declare const _default: {
|
|
|
1603
2362
|
defineMutation: typeof defineMutation;
|
|
1604
2363
|
pMap: typeof pMap;
|
|
1605
2364
|
ulid: typeof ulid;
|
|
2365
|
+
assertRuntime: typeof assertRuntime;
|
|
2366
|
+
FunctionRuntimeError: typeof FunctionRuntimeError;
|
|
1606
2367
|
};
|
|
1607
2368
|
export default _default;
|
package/index.js
CHANGED
|
@@ -24,10 +24,12 @@ const NOT_PROVIDED =
|
|
|
24
24
|
export const SDK_STUB_VERSION = "0.0.1";
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* Declare a function's handler
|
|
28
|
-
*
|
|
27
|
+
* Declare a function's handler — `defineFunction(handler)` or the keyed
|
|
28
|
+
* `defineFunction("<key>", handler)`. The platform copy returns the handler
|
|
29
|
+
* wrapped with its invocation context; this one refuses, loudly, whichever
|
|
30
|
+
* shape it is called with.
|
|
29
31
|
*/
|
|
30
|
-
export function defineFunction() {
|
|
32
|
+
export function defineFunction(_keyOrHandler, _maybeHandler) {
|
|
31
33
|
throw new Error(NOT_PROVIDED);
|
|
32
34
|
}
|
|
33
35
|
|
|
@@ -80,6 +82,34 @@ export const stepPolicy = {
|
|
|
80
82
|
database: null,
|
|
81
83
|
};
|
|
82
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
|
+
|
|
83
113
|
export default {
|
|
84
114
|
SDK_STUB_VERSION,
|
|
85
115
|
defineFunction,
|
|
@@ -87,4 +117,6 @@ export default {
|
|
|
87
117
|
defineMutation,
|
|
88
118
|
pMap,
|
|
89
119
|
ulid,
|
|
120
|
+
assertRuntime,
|
|
121
|
+
FunctionRuntimeError,
|
|
90
122
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primitive-functions",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.11",
|
|
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",
|