primitive-functions 0.2.0-alpha.7 → 0.2.0-alpha.9
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 +383 -38
- package/index.js +30 -0
- 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
|
-
/**
|
|
36
|
-
|
|
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,10 +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
|
|
75
|
-
*
|
|
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).
|
|
76
96
|
*/
|
|
77
|
-
| { kind: "
|
|
97
|
+
| { kind: "manual"; userId: string; runKey: string | null };
|
|
78
98
|
|
|
79
99
|
/** The result shape of an operation that answers in response headers. */
|
|
80
100
|
export interface HeaderResult {
|
|
@@ -708,6 +728,12 @@ export interface FunctionApi {
|
|
|
708
728
|
}): Promise<any>;
|
|
709
729
|
};
|
|
710
730
|
"documents": {
|
|
731
|
+
/** `documents.abortIngest` — POST /documents/{documentId}/ingest/{sessionId}/abort. Abort a bulk-load session before its swap */
|
|
732
|
+
"abortIngest"(args: {
|
|
733
|
+
"documentId": string | number;
|
|
734
|
+
"sessionId": string | number;
|
|
735
|
+
body: unknown;
|
|
736
|
+
}): Promise<any>;
|
|
711
737
|
/** `documents.addTag` — POST /documents/{documentId}/tags. Add a tag to a document */
|
|
712
738
|
"addTag"(args: {
|
|
713
739
|
"documentId": string | number;
|
|
@@ -785,10 +811,21 @@ export interface FunctionApi {
|
|
|
785
811
|
"clearLinkAccess"(args: {
|
|
786
812
|
"documentId": string | number;
|
|
787
813
|
}): Promise<any>;
|
|
814
|
+
/** `documents.commitIngest` — POST /documents/{documentId}/ingest/{sessionId}/commit. Commit a bulk-load session: freeze its manifest and apply it */
|
|
815
|
+
"commitIngest"(args: {
|
|
816
|
+
"documentId": string | number;
|
|
817
|
+
"sessionId": string | number;
|
|
818
|
+
body: unknown;
|
|
819
|
+
}): Promise<any>;
|
|
788
820
|
/** `documents.create` — POST /documents. Create a new document */
|
|
789
821
|
"create"(args: {
|
|
790
822
|
body: unknown;
|
|
791
823
|
}): Promise<any>;
|
|
824
|
+
/** `documents.createIngest` — POST /documents/{documentId}/ingest. Open a bulk-load session on a large document */
|
|
825
|
+
"createIngest"(args: {
|
|
826
|
+
"documentId": string | number;
|
|
827
|
+
body: unknown;
|
|
828
|
+
}): Promise<any>;
|
|
792
829
|
/** `documents.createWithAlias` — POST /documents/create-with-alias. Create a document and bind it to an alias */
|
|
793
830
|
"createWithAlias"(args: {
|
|
794
831
|
body: unknown;
|
|
@@ -846,6 +883,11 @@ export interface FunctionApi {
|
|
|
846
883
|
"getImportChainStatus"(args: {
|
|
847
884
|
"documentId": string | number;
|
|
848
885
|
}): Promise<any>;
|
|
886
|
+
/** `documents.getIngest` — GET /documents/{documentId}/ingest/{sessionId}. One bulk-load session's status */
|
|
887
|
+
"getIngest"(args: {
|
|
888
|
+
"documentId": string | number;
|
|
889
|
+
"sessionId": string | number;
|
|
890
|
+
}): Promise<any>;
|
|
849
891
|
/** `documents.getLinkAccess` — GET /documents/{documentId}/link-access. Get the document's "anyone with the link" access level */
|
|
850
892
|
"getLinkAccess"(args: {
|
|
851
893
|
"documentId": string | number;
|
|
@@ -862,6 +904,11 @@ export interface FunctionApi {
|
|
|
862
904
|
"getSchema"(args: {
|
|
863
905
|
"documentId": string | number;
|
|
864
906
|
}): Promise<any>;
|
|
907
|
+
/** `documents.getSnapshot` — GET /documents/{documentId}/snapshots/{buildId}. One snapshot build with its verification result */
|
|
908
|
+
"getSnapshot"(args: {
|
|
909
|
+
"documentId": string | number;
|
|
910
|
+
"buildId": string | number;
|
|
911
|
+
}): Promise<any>;
|
|
865
912
|
/** `documents.getStats` — GET /documents/{documentId}/stats. Document statistics (record/model/blob counts, approximate size) */
|
|
866
913
|
"getStats"(args: {
|
|
867
914
|
"documentId": string | number;
|
|
@@ -899,10 +946,22 @@ export interface FunctionApi {
|
|
|
899
946
|
"listGroupPermissions"(args: {
|
|
900
947
|
"documentId": string | number;
|
|
901
948
|
}): Promise<any>;
|
|
949
|
+
/** `documents.listIngests` — GET /documents/{documentId}/ingest. List a large document's bulk-load sessions, newest first */
|
|
950
|
+
"listIngests"(args: {
|
|
951
|
+
"documentId": string | number;
|
|
952
|
+
"limit"?: string | number | boolean;
|
|
953
|
+
"cursor"?: string | number | boolean;
|
|
954
|
+
}): Promise<any>;
|
|
902
955
|
/** `documents.listPendingInvitations` — GET /documents/{documentId}/pending-invitations. List a document's pending (deferred) invitations */
|
|
903
956
|
"listPendingInvitations"(args: {
|
|
904
957
|
"documentId": string | number;
|
|
905
958
|
}): Promise<any>;
|
|
959
|
+
/** `documents.listSnapshots` — GET /documents/{documentId}/snapshots. List a large document's snapshot builds, newest first */
|
|
960
|
+
"listSnapshots"(args: {
|
|
961
|
+
"documentId": string | number;
|
|
962
|
+
"limit"?: string | number | boolean;
|
|
963
|
+
"cursor"?: string | number | boolean;
|
|
964
|
+
}): Promise<any>;
|
|
906
965
|
/** `documents.open` — POST /documents/open. Open a document for collaboration (resolves access + alias) */
|
|
907
966
|
"open"(args: {
|
|
908
967
|
body: unknown;
|
|
@@ -999,6 +1058,12 @@ export interface FunctionApi {
|
|
|
999
1058
|
"documentId": string | number;
|
|
1000
1059
|
body: unknown;
|
|
1001
1060
|
}): Promise<any>;
|
|
1061
|
+
/** `documents.uploadIngestChunk` — POST /documents/{documentId}/ingest/{sessionId}/chunks. Upload one chunk of a bulk-load session's artifact */
|
|
1062
|
+
"uploadIngestChunk"(args: {
|
|
1063
|
+
"documentId": string | number;
|
|
1064
|
+
"sessionId": string | number;
|
|
1065
|
+
body: FormData | ArrayBuffer | Uint8Array | string;
|
|
1066
|
+
}): Promise<any>;
|
|
1002
1067
|
/** `documents.validateAccess` — POST /documents/{documentId}/validate-access. Resolve the caller's effective access level for a document */
|
|
1003
1068
|
"validateAccess"(args: {
|
|
1004
1069
|
"documentId": string | number;
|
|
@@ -1016,13 +1081,19 @@ export interface FunctionApi {
|
|
|
1016
1081
|
"functionKey": string | number;
|
|
1017
1082
|
body?: unknown;
|
|
1018
1083
|
}): Promise<any>;
|
|
1084
|
+
/** `functions.invokeAsSystem` — POST /functions/{functionKey}/invoke-as-system. Invoke a server function as the system, with no caller */
|
|
1085
|
+
"invokeAsSystem"(args: {
|
|
1086
|
+
"functionKey": string | number;
|
|
1087
|
+
body?: unknown;
|
|
1088
|
+
}): Promise<any>;
|
|
1019
1089
|
/** `functions.logs` — GET /functions/{functionKey}/logs. List a server function's invocation logs, newest first */
|
|
1020
1090
|
"logs"(args: {
|
|
1021
1091
|
"functionKey": string | number;
|
|
1022
1092
|
"limit"?: string | number | boolean;
|
|
1023
1093
|
"cursor"?: string | number | boolean;
|
|
1094
|
+
"runId"?: string | number | boolean;
|
|
1024
1095
|
}): Promise<any>;
|
|
1025
|
-
/** `functions.start` — POST /functions/{functionKey}/start. Start a
|
|
1096
|
+
/** `functions.start` — POST /functions/{functionKey}/start. Start a server function as a task run */
|
|
1026
1097
|
"start"(args: {
|
|
1027
1098
|
"functionKey": string | number;
|
|
1028
1099
|
body?: unknown;
|
|
@@ -1313,8 +1384,8 @@ export type DatabaseModels<K extends string> = K extends keyof DatabaseSchemas
|
|
|
1313
1384
|
* The app's functions, key by key — EMPTY here and filled by the declaration
|
|
1314
1385
|
* `primitive config push` writes into the config tree's `functions/`
|
|
1315
1386
|
* directory (`primitive-function-types.d.ts`): each key's declared input and
|
|
1316
|
-
* output types
|
|
1317
|
-
*
|
|
1387
|
+
* output types, from its `inputSchema` and `outputSchema`. It is what types
|
|
1388
|
+
* `defineFunction("<key>", handler)`.
|
|
1318
1389
|
*/
|
|
1319
1390
|
export interface FunctionSchemas {}
|
|
1320
1391
|
|
|
@@ -1342,13 +1413,6 @@ export type FunctionOutput<K extends string> = K extends keyof FunctionSchemas
|
|
|
1342
1413
|
: any
|
|
1343
1414
|
: any;
|
|
1344
1415
|
|
|
1345
|
-
/** A declared function's mode, fixed at generation time. */
|
|
1346
|
-
export type FunctionMode<K extends string> = K extends keyof FunctionSchemas
|
|
1347
|
-
? FunctionSchemas[K] extends { mode: infer M }
|
|
1348
|
-
? M
|
|
1349
|
-
: "request" | "task"
|
|
1350
|
-
: "request" | "task";
|
|
1351
|
-
|
|
1352
1416
|
/**
|
|
1353
1417
|
* The model names one database type addresses — its own, or any name at all
|
|
1354
1418
|
* for a type that declares no schema (the DO is schemaless, so a grant on such
|
|
@@ -1358,9 +1422,38 @@ export type DatabaseModelNames<TModels> = [keyof TModels] extends [never]
|
|
|
1358
1422
|
? string
|
|
1359
1423
|
: keyof TModels & string;
|
|
1360
1424
|
|
|
1425
|
+
/**
|
|
1426
|
+
* A row as the platform HANDS IT BACK: whatever the schema declared, plus the
|
|
1427
|
+
* record identity the platform owns (#3450).
|
|
1428
|
+
*
|
|
1429
|
+
* Every stored record has an `id`. A save that arrives without one is given a
|
|
1430
|
+
* ULID, a projection always keeps it, and `delete` and `patch` take nothing
|
|
1431
|
+
* else — so a function that queries a model and then moves one of its rows
|
|
1432
|
+
* needs the id of the row it just read. A schema is free to say nothing about
|
|
1433
|
+
* that field, and most do; the identity is the platform's, not the schema's,
|
|
1434
|
+
* so it is added here rather than rendered into each declaration.
|
|
1435
|
+
*
|
|
1436
|
+
* A declared `id` is REPLACED, never intersected: one declared optional would
|
|
1437
|
+
* stay optional on a read row it is always present on, and one declared with
|
|
1438
|
+
* some other type would intersect to `never` and be unusable. The platform
|
|
1439
|
+
* stamps a string whatever the schema says.
|
|
1440
|
+
*
|
|
1441
|
+
* An `any` row stays `any` — `DatabaseHandle<any>` is `defineQuery`'s default
|
|
1442
|
+
* handle, and turning its rows into an object with one known member would
|
|
1443
|
+
* narrow code that was deliberately left open.
|
|
1444
|
+
*
|
|
1445
|
+
* Writes are untouched: every one of them takes `Partial<TRow>`, so a row a
|
|
1446
|
+
* function BUILDS still needs no id.
|
|
1447
|
+
*/
|
|
1448
|
+
export type PlatformRow<TRow> = 0 extends 1 & TRow
|
|
1449
|
+
? TRow
|
|
1450
|
+
: Omit<TRow, "id"> & { id: string };
|
|
1451
|
+
|
|
1361
1452
|
/** One model's row shape, open when the type declares no schema. */
|
|
1362
1453
|
export type DatabaseModelRow<TModels, M extends string> =
|
|
1363
|
-
M extends keyof TModels
|
|
1454
|
+
M extends keyof TModels
|
|
1455
|
+
? PlatformRow<TModels[M]>
|
|
1456
|
+
: Record<string, unknown> & { id: string };
|
|
1364
1457
|
|
|
1365
1458
|
/**
|
|
1366
1459
|
* One model of one database, scoped: the `modelName` every records call needs
|
|
@@ -1404,6 +1497,29 @@ export interface DatabaseModelHandle<TRow> {
|
|
|
1404
1497
|
count(body?: ModelScopedBody): Promise<any>;
|
|
1405
1498
|
aggregate(body: ModelScopedBody): Promise<any>;
|
|
1406
1499
|
save(body: ModelScopedBody<{ id?: string; data: Partial<TRow>; [key: string]: unknown }>): Promise<any>;
|
|
1500
|
+
/**
|
|
1501
|
+
* Change some fields of ONE row — `databases.records.patch`, with this
|
|
1502
|
+
* handle's model bound (#3450).
|
|
1503
|
+
*
|
|
1504
|
+
* The record id is positional and the body may not carry another, for the
|
|
1505
|
+
* same reason it may not name another model: the runtime assigns both LAST,
|
|
1506
|
+
* so a body that appeared to choose either would be a lie about which row
|
|
1507
|
+
* moved. `condition`, `stringSets` and the rest of the operation's own keys
|
|
1508
|
+
* pass through untouched.
|
|
1509
|
+
*/
|
|
1510
|
+
patch(
|
|
1511
|
+
recordId: string,
|
|
1512
|
+
body: ModelScopedBody<{ data: Partial<TRow>; id?: never; [key: string]: unknown }>
|
|
1513
|
+
): Promise<any>;
|
|
1514
|
+
/**
|
|
1515
|
+
* Remove ONE row by the id a read handed back — `databases.records.delete`,
|
|
1516
|
+
* with this handle's model bound (#3450). An optional `condition` makes it
|
|
1517
|
+
* conditional, and travels untouched.
|
|
1518
|
+
*/
|
|
1519
|
+
delete(
|
|
1520
|
+
recordId: string,
|
|
1521
|
+
body?: ModelScopedBody<{ condition?: Record<string, unknown>; id?: never }>
|
|
1522
|
+
): Promise<any>;
|
|
1407
1523
|
/** Several writes to THIS model in one request; the binding is per item. */
|
|
1408
1524
|
batch(body: {
|
|
1409
1525
|
operations: Array<ModelBatchOperation<TRow>>;
|
|
@@ -1445,10 +1561,15 @@ export type DocumentModelNames = [keyof DocumentSchemas] extends [never]
|
|
|
1445
1561
|
? string
|
|
1446
1562
|
: keyof DocumentSchemas & string;
|
|
1447
1563
|
|
|
1448
|
-
/**
|
|
1564
|
+
/**
|
|
1565
|
+
* A document model's row shape, or an open record for an undeclared schema —
|
|
1566
|
+
* carrying the platform's record identity either way (#3450), by the same rule
|
|
1567
|
+
* and for the same reason as a database row: the records DO is one
|
|
1568
|
+
* implementation, and `patch` and `delete` here take an id too.
|
|
1569
|
+
*/
|
|
1449
1570
|
export type DocumentModelRow<M extends string> = M extends keyof DocumentSchemas
|
|
1450
|
-
? DocumentSchemas[M]
|
|
1451
|
-
: Record<string, unknown
|
|
1571
|
+
? PlatformRow<DocumentSchemas[M]>
|
|
1572
|
+
: Record<string, unknown> & { id: string };
|
|
1452
1573
|
|
|
1453
1574
|
/** The options a document model read takes: a filter object (or its JSON), a page size, a cursor. */
|
|
1454
1575
|
export interface DocumentQueryOptions {
|
|
@@ -1461,6 +1582,26 @@ export interface DocumentQueryOptions {
|
|
|
1461
1582
|
* One document model, bound to its document and its model name — a thin
|
|
1462
1583
|
* binding over `ctx.api.documents.records.*` with the route's own shapes.
|
|
1463
1584
|
*/
|
|
1585
|
+
/**
|
|
1586
|
+
* One op of a document `batch` — the `documents.records.bulk` blob's shape,
|
|
1587
|
+
* typed to this handle's model (#3455).
|
|
1588
|
+
*
|
|
1589
|
+
* `model` is NOT a member: the handle already names it and assigns it last, so
|
|
1590
|
+
* a multi-model blob stays on the raw `ctx.api.documents.records.bulk`
|
|
1591
|
+
* operation rather than becoming a second way to say the same thing.
|
|
1592
|
+
*/
|
|
1593
|
+
export type DocumentBatchOp<TRow> =
|
|
1594
|
+
| { action: "create" | "patch"; id: string; data: Partial<TRow>; precondition?: Record<string, unknown> }
|
|
1595
|
+
| { action: "delete"; id: string; precondition?: Record<string, unknown> };
|
|
1596
|
+
|
|
1597
|
+
/** What `documents.records.bulk` answers: the blob's aggregate effect. */
|
|
1598
|
+
export interface DocumentBulkResult {
|
|
1599
|
+
applied: number;
|
|
1600
|
+
added: Array<{ model: string; id: string }>;
|
|
1601
|
+
updated: Array<{ model: string; id: string }>;
|
|
1602
|
+
deleted: number;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1464
1605
|
export interface DocumentModelHandle<TRow> {
|
|
1465
1606
|
query(options?: DocumentQueryOptions): Promise<{ items: TRow[]; hasMore: boolean; nextCursor?: string }>;
|
|
1466
1607
|
count(options?: { filter?: Record<string, unknown> | string }): Promise<{ count: number }>;
|
|
@@ -1468,6 +1609,15 @@ export interface DocumentModelHandle<TRow> {
|
|
|
1468
1609
|
save(body: { id: string; data: Partial<TRow>; options?: Record<string, unknown> }): Promise<{ record: TRow }>;
|
|
1469
1610
|
patch(recordId: string, body: { data: Partial<TRow>; options?: Record<string, unknown> }): Promise<{ record: TRow }>;
|
|
1470
1611
|
delete(recordId: string): Promise<{ deleted: boolean }>;
|
|
1612
|
+
/**
|
|
1613
|
+
* Apply an ordered blob of this model's ops in ONE transaction — all of it
|
|
1614
|
+
* commits or none of it does, and connected clients see one update.
|
|
1615
|
+
*
|
|
1616
|
+
* One model's ops, by construction: every op's `model` is this handle's.
|
|
1617
|
+
* A blob that spans models is the raw `ctx.api.documents.records.bulk`
|
|
1618
|
+
* operation's job.
|
|
1619
|
+
*/
|
|
1620
|
+
batch(ops: Array<DocumentBatchOp<TRow>>): Promise<DocumentBulkResult>;
|
|
1471
1621
|
}
|
|
1472
1622
|
|
|
1473
1623
|
/** A document, addressed once; its models are typed from `DocumentSchemas`. */
|
|
@@ -1517,15 +1667,94 @@ export interface PromptRunArgs {
|
|
|
1517
1667
|
configId?: string;
|
|
1518
1668
|
}
|
|
1519
1669
|
|
|
1520
|
-
/**
|
|
1521
|
-
|
|
1670
|
+
/**
|
|
1671
|
+
* The app's PROMPTS — EMPTY here and filled by the declaration
|
|
1672
|
+
* `primitive config push` writes into the config tree's `functions/` directory
|
|
1673
|
+
* (`primitive-prompt-types.d.ts`, from the tree's `prompts/*.toml`). A prompt
|
|
1674
|
+
* that declares an `outputSchema` carries `{ output: <Key>PromptOutput }`; one
|
|
1675
|
+
* that declares none carries `{}`, so reading `parsed.field` on it is a
|
|
1676
|
+
* compile error rather than a runtime `undefined`.
|
|
1677
|
+
*/
|
|
1678
|
+
export interface PromptSchemas {}
|
|
1679
|
+
|
|
1680
|
+
/** The keys `ctx.prompts.run` accepts — every declared one, or `string` before a push. */
|
|
1681
|
+
export type PromptKeys = [keyof PromptSchemas] extends [never]
|
|
1682
|
+
? string
|
|
1683
|
+
: keyof PromptSchemas & string;
|
|
1684
|
+
|
|
1685
|
+
/** One prompt's declared output type, or `unknown` where none is declared. */
|
|
1686
|
+
export type PromptOutput<K extends string> = K extends keyof PromptSchemas
|
|
1687
|
+
? PromptSchemas[K] extends { output: infer O }
|
|
1688
|
+
? O
|
|
1689
|
+
: unknown
|
|
1690
|
+
: unknown;
|
|
1691
|
+
|
|
1692
|
+
/**
|
|
1693
|
+
* Why a prompt's own answer was refused — #3330. Never set on a PROVIDER
|
|
1694
|
+
* failure, which is what makes "the model returned the wrong shape"
|
|
1695
|
+
* distinguishable from "the model failed".
|
|
1696
|
+
*/
|
|
1697
|
+
export type PromptOutputErrorCode =
|
|
1698
|
+
| "PROMPT_OUTPUT_NOT_JSON"
|
|
1699
|
+
| "PROMPT_OUTPUT_SCHEMA_VIOLATION";
|
|
1700
|
+
|
|
1701
|
+
/** A prompt that declares an output shape, when the answer matched it. */
|
|
1702
|
+
export interface PromptRunSuccess<TParsed> {
|
|
1703
|
+
success: true;
|
|
1704
|
+
output: string;
|
|
1705
|
+
/** The parsed, validated answer — no caller-side `JSON.parse` (#3330). */
|
|
1706
|
+
parsed: TParsed;
|
|
1707
|
+
error?: null;
|
|
1708
|
+
errorCode?: null;
|
|
1709
|
+
metrics?: Record<string, unknown>;
|
|
1710
|
+
configId: string;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
/**
|
|
1714
|
+
* The failure arm, whichever failed. `errorCode` is set for a SHAPE failure
|
|
1715
|
+
* and absent for a provider one; `output` carries the text either way, which
|
|
1716
|
+
* is where the model's own value lives — a validation `error` names paths and
|
|
1717
|
+
* schema constraints only.
|
|
1718
|
+
*/
|
|
1719
|
+
export interface PromptRunFailure {
|
|
1720
|
+
success: false;
|
|
1721
|
+
output: string;
|
|
1722
|
+
error: string | null;
|
|
1723
|
+
errorCode?: PromptOutputErrorCode | null;
|
|
1724
|
+
parsed?: undefined;
|
|
1725
|
+
metrics?: Record<string, unknown>;
|
|
1726
|
+
configId: string;
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
/** The envelope for a key whose declaration says nothing about its output. */
|
|
1730
|
+
export interface PromptRunOpenResult {
|
|
1522
1731
|
success: boolean;
|
|
1523
1732
|
output: string;
|
|
1733
|
+
/**
|
|
1734
|
+
* Present when the config that ran declares `outputFormat = "json"` and the
|
|
1735
|
+
* text parsed. Untyped: nothing declared its shape.
|
|
1736
|
+
*/
|
|
1737
|
+
parsed?: unknown;
|
|
1524
1738
|
error?: string | null;
|
|
1739
|
+
errorCode?: PromptOutputErrorCode | null;
|
|
1525
1740
|
metrics?: Record<string, unknown>;
|
|
1526
1741
|
configId: string;
|
|
1527
1742
|
}
|
|
1528
1743
|
|
|
1744
|
+
/**
|
|
1745
|
+
* The member execute envelope, plus what the prompt's own declaration adds.
|
|
1746
|
+
*
|
|
1747
|
+
* For a key whose `prompts/<key>.toml` declares an `outputSchema`, this is a
|
|
1748
|
+
* discriminated union: narrow on `success` and `parsed` is the declared type,
|
|
1749
|
+
* required. For every other key — and in a tree that has not pushed — it is
|
|
1750
|
+
* the open shape, with `parsed` optional and `unknown`.
|
|
1751
|
+
*/
|
|
1752
|
+
export type PromptRunResult<K extends string = string> = K extends keyof PromptSchemas
|
|
1753
|
+
? PromptSchemas[K] extends { output: infer O }
|
|
1754
|
+
? PromptRunSuccess<O> | PromptRunFailure
|
|
1755
|
+
: PromptRunOpenResult
|
|
1756
|
+
: PromptRunOpenResult;
|
|
1757
|
+
|
|
1529
1758
|
/** What a send delivered to. */
|
|
1530
1759
|
export interface SendResult {
|
|
1531
1760
|
/** Unique live connections the frame was sent to. Zero is a success. */
|
|
@@ -1616,9 +1845,45 @@ export interface FunctionStartResult {
|
|
|
1616
1845
|
}
|
|
1617
1846
|
|
|
1618
1847
|
export interface FunctionContext {
|
|
1619
|
-
/** The HTTP caller, or null for a webhook
|
|
1848
|
+
/** The HTTP caller, or null for a webhook or cron fire. */
|
|
1620
1849
|
user: FunctionUser | null;
|
|
1621
1850
|
trigger: FunctionTrigger;
|
|
1851
|
+
/**
|
|
1852
|
+
* Which RUNTIME is hosting this code — #3482.
|
|
1853
|
+
*
|
|
1854
|
+
* Beside `trigger`, which says which DOOR fired, and they are different
|
|
1855
|
+
* questions: an HTTP call is whichever runtime the caller chose
|
|
1856
|
+
* (`invoke` or `start`), a cron fire is always a task and a webhook
|
|
1857
|
+
* delivery is always a request.
|
|
1858
|
+
*
|
|
1859
|
+
* To REFUSE a runtime rather than branch on it, call
|
|
1860
|
+
* `assertRuntime("task")` — at module scope to refuse it outright, or in
|
|
1861
|
+
* the handler to refuse one call.
|
|
1862
|
+
*/
|
|
1863
|
+
runtime: "request" | "task";
|
|
1864
|
+
/**
|
|
1865
|
+
* The RUN this invocation belongs to, or null — #3562.
|
|
1866
|
+
*
|
|
1867
|
+
* Set under the task runtime (every slice of the run, the first and every
|
|
1868
|
+
* resume) and for a webhook-fired request run, which writes a row. Null for
|
|
1869
|
+
* an HTTP `invoke`, which writes no run row at all.
|
|
1870
|
+
*
|
|
1871
|
+
* It is the deterministic OWNER a task run presents to re-take its own
|
|
1872
|
+
* lease: `ctx.api.locks.tryAcquire({ body: { key, ttlMs, owner: ctx.runId } })`
|
|
1873
|
+
* succeeds for the run that already holds the key, with a fresh handle.
|
|
1874
|
+
*/
|
|
1875
|
+
runId: string | null;
|
|
1876
|
+
/**
|
|
1877
|
+
* The SLICE of the run this code is running in, or null — #3562.
|
|
1878
|
+
*
|
|
1879
|
+
* The same identifier `primitive functions runs` and the run-status
|
|
1880
|
+
* route's `slice.sliceId` report. A task run is a sequence of slices: it
|
|
1881
|
+
* changes when the run hibernates and wakes, which is how a handler can tell
|
|
1882
|
+
* a resume from a first pass.
|
|
1883
|
+
*
|
|
1884
|
+
* Null under the request runtime: a request invocation is not a slice.
|
|
1885
|
+
*/
|
|
1886
|
+
sliceId: string | null;
|
|
1622
1887
|
api: FunctionApi;
|
|
1623
1888
|
/**
|
|
1624
1889
|
* A typed handle over one database. The second argument is the database TYPE
|
|
@@ -1673,14 +1938,33 @@ export interface FunctionContext {
|
|
|
1673
1938
|
): Promise<FunctionStartResult>;
|
|
1674
1939
|
};
|
|
1675
1940
|
/**
|
|
1676
|
-
* Run one of the app's prompts,
|
|
1941
|
+
* Run one of the app's prompts, with nothing to declare (#3183, #3279).
|
|
1677
1942
|
*
|
|
1678
1943
|
* The prompt's `accessRule` is not consulted — it states which MEMBERS may
|
|
1679
|
-
* execute the prompt from a client, and the
|
|
1680
|
-
* call. The provider request is bounded by the invocation's
|
|
1944
|
+
* execute the prompt from a client, and the invocation gate is what
|
|
1945
|
+
* authorized this call. The provider request is bounded by the invocation's
|
|
1946
|
+
* own deadline.
|
|
1947
|
+
*
|
|
1948
|
+
* TYPED BY KEY (#3330). Where `prompts/<key>.toml` declares an
|
|
1949
|
+
* `outputSchema`, the platform parses the answer, validates it against that
|
|
1950
|
+
* schema and hands it back as `parsed`, typed — so the shape is written once
|
|
1951
|
+
* in TOML instead of restated as a `JSON.parse` at every call site. Where
|
|
1952
|
+
* only the config that ran declares `outputFormat = "json"`, `parsed` is
|
|
1953
|
+
* present but `unknown`. Where neither is declared the envelope is exactly
|
|
1954
|
+
* what it has always been.
|
|
1955
|
+
*
|
|
1956
|
+
* A shape the declaration refuses is `success: false` with an `errorCode`
|
|
1957
|
+
* (`PROMPT_OUTPUT_NOT_JSON` or `PROMPT_OUTPUT_SCHEMA_VIOLATION`) and the
|
|
1958
|
+
* text still in `output`; a PROVIDER failure has `error` and no
|
|
1959
|
+
* `errorCode`, so the two are told apart without guessing.
|
|
1960
|
+
*
|
|
1961
|
+
* Once a tree has pushed, a key it does not declare is a compile error.
|
|
1681
1962
|
*/
|
|
1682
1963
|
prompts: {
|
|
1683
|
-
run
|
|
1964
|
+
run<K extends PromptKeys>(
|
|
1965
|
+
promptKey: K,
|
|
1966
|
+
args?: PromptRunArgs
|
|
1967
|
+
): Promise<PromptRunResult<K>>;
|
|
1684
1968
|
};
|
|
1685
1969
|
/**
|
|
1686
1970
|
* The value of one app secret, under a `secret:<NAME>` grant (#3183).
|
|
@@ -1750,13 +2034,22 @@ export interface FunctionContext {
|
|
|
1750
2034
|
}
|
|
1751
2035
|
|
|
1752
2036
|
/**
|
|
1753
|
-
* The
|
|
1754
|
-
*
|
|
2037
|
+
* The step handle. `step` is the third argument under BOTH runners, so the
|
|
2038
|
+
* same body runs either way — which is what `mode = "any"` is for (#3454).
|
|
1755
2039
|
*
|
|
1756
|
-
*
|
|
1757
|
-
*
|
|
1758
|
-
*
|
|
1759
|
-
*
|
|
2040
|
+
* Under the TASK runner it is Cloudflare Workflows' `WorkflowStep`, forwarded
|
|
2041
|
+
* untouched: `step.do` results are memoized and replayed, and `step.sleep`
|
|
2042
|
+
* hibernates.
|
|
2043
|
+
*
|
|
2044
|
+
* Under the REQUEST runner it is the platform's own, bounded by the request's
|
|
2045
|
+
* clock: `do` executes the body inline (there is no engine to memoize into,
|
|
2046
|
+
* and nothing is replayed); `sleep` and `sleepUntil` REALLY wait when the
|
|
2047
|
+
* remaining request budget covers the duration, and otherwise fail the
|
|
2048
|
+
* invocation with `errorCode: "FUNCTION_RUNTIME_REFUSED"` saying to start the
|
|
2049
|
+
* function as a task; `waitForEvent` fails the same way, because nothing can
|
|
2050
|
+
* deliver an event to an invocation that has to return now. The thrown error's
|
|
2051
|
+
* `name` is `STEP_NOT_AVAILABLE` in every case, so a body that catches it
|
|
2052
|
+
* keeps catching it.
|
|
1760
2053
|
*/
|
|
1761
2054
|
export interface FunctionStep {
|
|
1762
2055
|
do<T>(name: string, body: () => T | Promise<T>): Promise<T>;
|
|
@@ -1775,13 +2068,57 @@ export interface FunctionStep {
|
|
|
1775
2068
|
|
|
1776
2069
|
export declare const SDK_STUB_VERSION: string;
|
|
1777
2070
|
|
|
2071
|
+
/**
|
|
2072
|
+
* Thrown by `assertRuntime` when this function is running under the other
|
|
2073
|
+
* runtime — #3482.
|
|
2074
|
+
*
|
|
2075
|
+
* The platform settles it as `status: "failed"` with
|
|
2076
|
+
* `errorCode: "FUNCTION_RUNTIME_REFUSED"`, on a request invocation's
|
|
2077
|
+
* envelope and on a task run's row and record alike.
|
|
2078
|
+
*/
|
|
2079
|
+
export declare class FunctionRuntimeError extends Error {
|
|
2080
|
+
name: "FUNCTION_RUNTIME_REFUSED";
|
|
2081
|
+
/** The runtime this invocation is actually running under. */
|
|
2082
|
+
runtime: "request" | "task";
|
|
2083
|
+
/** The runtime the function asked for. */
|
|
2084
|
+
required: "request" | "task";
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
/**
|
|
2088
|
+
* Refuse the runtime this function was not written for — #3482.
|
|
2089
|
+
*
|
|
2090
|
+
* A function is a function and the caller picks the runtime at each call, so
|
|
2091
|
+
* nothing in config says which one a function may run under. This is the lock,
|
|
2092
|
+
* and it lives in the one place that can always be right about the code:
|
|
2093
|
+
*
|
|
2094
|
+
* ```ts
|
|
2095
|
+
* import { assertRuntime } from "primitive-functions";
|
|
2096
|
+
*
|
|
2097
|
+
* // At module scope: this function is never runnable inside a request.
|
|
2098
|
+
* assertRuntime("task");
|
|
2099
|
+
*
|
|
2100
|
+
* export default async function (input, ctx, step) {
|
|
2101
|
+
* await step.sleep("cool-off", "1 hour");
|
|
2102
|
+
* return { ok: true };
|
|
2103
|
+
* }
|
|
2104
|
+
* ```
|
|
2105
|
+
*
|
|
2106
|
+
* Returns when the runtimes match; otherwise throws
|
|
2107
|
+
* {@link FunctionRuntimeError}, which the platform settles as
|
|
2108
|
+
* `status: "failed"` with `errorCode: "FUNCTION_RUNTIME_REFUSED"` and a
|
|
2109
|
+
* message naming both runtimes and the verb that takes the one required.
|
|
2110
|
+
*/
|
|
2111
|
+
export declare function assertRuntime(required: "request" | "task"): void;
|
|
2112
|
+
|
|
1778
2113
|
/**
|
|
1779
2114
|
* The handler a function exports, typed for one declared key.
|
|
1780
2115
|
*
|
|
1781
|
-
* `step` is the third argument
|
|
1782
|
-
* engine's live `WorkflowStep`; a request invocation gets
|
|
1783
|
-
*
|
|
1784
|
-
*
|
|
2116
|
+
* `step` is the third argument under BOTH runners (#3186, #3454). A task run
|
|
2117
|
+
* gets the engine's live `WorkflowStep`; a request invocation gets the
|
|
2118
|
+
* platform's own, where `do` runs the body inline and a wait the request
|
|
2119
|
+
* budget cannot cover fails the invocation naming the task runner — so a
|
|
2120
|
+
* task-authored body can be exercised as a request, and the one place the two
|
|
2121
|
+
* genuinely differ says so rather than pretending.
|
|
1785
2122
|
*/
|
|
1786
2123
|
export type FunctionHandler<TInput, TOutput> = (
|
|
1787
2124
|
input: TInput,
|
|
@@ -2005,6 +2342,12 @@ export declare const stepPolicy: {
|
|
|
2005
2342
|
database: StepPolicy;
|
|
2006
2343
|
};
|
|
2007
2344
|
|
|
2345
|
+
// Every member the three runtime copies put on their own default export — the
|
|
2346
|
+
// platform's `sdk-core.ts`, the published stub and the CLI's collect stub —
|
|
2347
|
+
// and nothing else. A helper the module hands a default import but does not
|
|
2348
|
+
// declare here is one an author cannot call without the compiler refusing it
|
|
2349
|
+
// (#3482 CR3482-002); `tests/api/spec/function-profile.test.ts` holds the four
|
|
2350
|
+
// lists equal and compiles a default import against them.
|
|
2008
2351
|
declare const _default: {
|
|
2009
2352
|
SDK_STUB_VERSION: string;
|
|
2010
2353
|
defineFunction: typeof defineFunction;
|
|
@@ -2012,5 +2355,7 @@ declare const _default: {
|
|
|
2012
2355
|
defineMutation: typeof defineMutation;
|
|
2013
2356
|
pMap: typeof pMap;
|
|
2014
2357
|
ulid: typeof ulid;
|
|
2358
|
+
assertRuntime: typeof assertRuntime;
|
|
2359
|
+
FunctionRuntimeError: typeof FunctionRuntimeError;
|
|
2015
2360
|
};
|
|
2016
2361
|
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.
|
|
3
|
+
"version": "0.2.0-alpha.9",
|
|
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",
|