primitive-admin 1.1.0-alpha.78 → 1.1.0-alpha.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -17
- package/assets/skill/skills/primitive-platform/SKILL.md +39 -52
- package/dist/bin/primitive.js +14 -25
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/admins.js +8 -18
- package/dist/src/commands/admins.js.map +1 -1
- package/dist/src/commands/analytics.js +46 -5
- package/dist/src/commands/analytics.js.map +1 -1
- package/dist/src/commands/auth.js +16 -1
- package/dist/src/commands/auth.js.map +1 -1
- package/dist/src/commands/collection-type-configs.js +1 -9
- package/dist/src/commands/collection-type-configs.js.map +1 -1
- package/dist/src/commands/config.js +11 -29
- package/dist/src/commands/config.js.map +1 -1
- package/dist/src/commands/database-type-configs.js +1 -9
- package/dist/src/commands/database-type-configs.js.map +1 -1
- package/dist/src/commands/databases.js +8 -38
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/env.js +27 -32
- package/dist/src/commands/env.js.map +1 -1
- package/dist/src/commands/functions.js +197 -23
- package/dist/src/commands/functions.js.map +1 -1
- package/dist/src/commands/groups.js +1 -9
- package/dist/src/commands/groups.js.map +1 -1
- package/dist/src/commands/init.js +6 -0
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/rule-sets.js +1 -9
- package/dist/src/commands/rule-sets.js.map +1 -1
- package/dist/src/commands/scripts.js +12 -28
- package/dist/src/commands/scripts.js.map +1 -1
- package/dist/src/commands/sync.d.ts +119 -0
- package/dist/src/commands/sync.js +387 -196
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/workflows.js +2 -14
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/api-client.d.ts +46 -11
- package/dist/src/lib/api-client.js +21 -11
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +24 -57
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +30 -204
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -1
- package/dist/src/lib/config-json-field.d.ts +28 -0
- package/dist/src/lib/config-json-field.js +56 -0
- package/dist/src/lib/config-json-field.js.map +1 -0
- package/dist/src/lib/config-object-descriptor.js +4 -3
- package/dist/src/lib/config-object-descriptor.js.map +1 -1
- package/dist/src/lib/config-surface.js +1 -1
- package/dist/src/lib/config-surface.js.map +1 -1
- package/dist/src/lib/config.d.ts +21 -14
- package/dist/src/lib/config.js +25 -44
- package/dist/src/lib/config.js.map +1 -1
- package/dist/src/lib/credentials-store.d.ts +31 -8
- package/dist/src/lib/credentials-store.js +52 -13
- package/dist/src/lib/credentials-store.js.map +1 -1
- package/dist/src/lib/env-resolver-core.d.ts +18 -0
- package/dist/src/lib/env-resolver-core.js +26 -3
- package/dist/src/lib/env-resolver-core.js.map +1 -1
- package/dist/src/lib/env-resolver.d.ts +15 -0
- package/dist/src/lib/env-resolver.js +21 -1
- package/dist/src/lib/env-resolver.js.map +1 -1
- package/dist/src/lib/function-collect.d.ts +1 -1
- package/dist/src/lib/function-collect.js +138 -7
- package/dist/src/lib/function-collect.js.map +1 -1
- package/dist/src/lib/function-db-types.d.ts +49 -11
- package/dist/src/lib/function-db-types.js +234 -39
- package/dist/src/lib/function-db-types.js.map +1 -1
- package/dist/src/lib/function-document-types.d.ts +50 -0
- package/dist/src/lib/function-document-types.js +163 -0
- package/dist/src/lib/function-document-types.js.map +1 -0
- package/dist/src/lib/function-log-tail.d.ts +83 -0
- package/dist/src/lib/function-log-tail.js +115 -0
- package/dist/src/lib/function-log-tail.js.map +1 -0
- package/dist/src/lib/function-schema-codegen.d.ts +118 -0
- package/dist/src/lib/function-schema-codegen.js +402 -0
- package/dist/src/lib/function-schema-codegen.js.map +1 -0
- package/dist/src/lib/function-sync.d.ts +85 -2
- package/dist/src/lib/function-sync.js +196 -27
- package/dist/src/lib/function-sync.js.map +1 -1
- package/dist/src/lib/function-triggers.d.ts +9 -3
- package/dist/src/lib/function-triggers.js +12 -9
- package/dist/src/lib/function-triggers.js.map +1 -1
- package/dist/src/lib/function-typecheck.d.ts +86 -0
- package/dist/src/lib/function-typecheck.js +370 -0
- package/dist/src/lib/function-typecheck.js.map +1 -0
- package/dist/src/lib/generated-allowlist.js +4 -0
- package/dist/src/lib/generated-allowlist.js.map +1 -1
- package/dist/src/lib/generated-config-surfaces.d.ts +422 -0
- package/dist/src/lib/generated-config-surfaces.js +838 -9
- package/dist/src/lib/generated-config-surfaces.js.map +1 -1
- package/dist/src/lib/generated-sdk-types.d.ts +1 -1
- package/dist/src/lib/generated-sdk-types.js +1 -1
- package/dist/src/lib/generated-sdk-types.js.map +1 -1
- package/dist/src/lib/log-inspection.d.ts +116 -4
- package/dist/src/lib/log-inspection.js +147 -2
- package/dist/src/lib/log-inspection.js.map +1 -1
- package/dist/src/lib/snapshots.d.ts +6 -7
- package/dist/src/lib/snapshots.js +18 -81
- package/dist/src/lib/snapshots.js.map +1 -1
- package/dist/src/lib/sync-paths.d.ts +29 -53
- package/dist/src/lib/sync-paths.js +46 -97
- package/dist/src/lib/sync-paths.js.map +1 -1
- package/dist/src/lib/workflow-toml-validator.d.ts +8 -3
- package/dist/src/lib/workflow-toml-validator.js +8 -3
- package/dist/src/lib/workflow-toml-validator.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema-typed codegen for server functions — #3281, project
|
|
3
|
+
* `server-functions` phase 4.
|
|
4
|
+
*
|
|
5
|
+
* The intent's "Schema-typed codegen on every push": `<Key>Input` and
|
|
6
|
+
* `<Key>Output` from the declared schemas, a handler helper so function code
|
|
7
|
+
* is typed from the declaration, and a typed per-key invoker with the MODE
|
|
8
|
+
* fixed at generation time so a mismatch is a compile error. Two artifacts,
|
|
9
|
+
* both rendered from the same `functions/<key>.toml` and both regenerated by
|
|
10
|
+
* `config push`, `config pull` and `primitive functions codegen`:
|
|
11
|
+
*
|
|
12
|
+
* - `functions/primitive-function-types.d.ts` — every key's input and
|
|
13
|
+
* output types, and a `FunctionSchemas` augmentation keyed by function
|
|
14
|
+
* key (the `DatabaseSchemas` shape `primitive-db-types.d.ts` uses), which
|
|
15
|
+
* is what types `defineFunction("<key>", handler)`: `input` is the
|
|
16
|
+
* declared input, the return is checked against the declared output, and
|
|
17
|
+
* a key the tree does not declare is a compile error.
|
|
18
|
+
* - `functions/generated/<key>.generated.ts` — the client invoker, the
|
|
19
|
+
* `workflows codegen` layout: imports only from `js-bao-wss-client`,
|
|
20
|
+
* exports the two types and a `<key>(client)` factory whose members are
|
|
21
|
+
* the verbs the MODE allows and nothing else. A request function's
|
|
22
|
+
* invoker has exactly `invoke`; a task function's exactly `start`,
|
|
23
|
+
* `getStatus`, `waitFor` and `terminate`. The task `waitFor` binds
|
|
24
|
+
* `<Key>Output`, so the completion path is typed too (D3281-SO-003).
|
|
25
|
+
*
|
|
26
|
+
* ── The same descriptor the platform validates with ──────────────────────
|
|
27
|
+
*
|
|
28
|
+
* Schemas are interpreted through the vendored descriptor `workflows codegen`
|
|
29
|
+
* already reads (`workflow-codegen/schemaToTs.ts`, a byte copy of the server's
|
|
30
|
+
* `schema-descriptor.ts`), so what compiles is what every invocation door
|
|
31
|
+
* accepts: `input` is a REQUIRED option iff the schema rejects `{}` (the
|
|
32
|
+
* client sends `rootInput` only when `input !== undefined`, and the server
|
|
33
|
+
* defaults an absent one to `{}`), an absent schema is `unknown`, and a
|
|
34
|
+
* malformed schema fails naming the file rather than typing something false.
|
|
35
|
+
*
|
|
36
|
+
* ── Identifiers ──────────────────────────────────────────────────────────
|
|
37
|
+
*
|
|
38
|
+
* Names come from the workflow naming helpers (PascalCase, the digit-leading
|
|
39
|
+
* and reserved-word rules), and the runtime call always passes the ORIGINAL
|
|
40
|
+
* key. Two keys that sanitize to one identifier would render one file over the
|
|
41
|
+
* other, so that is refused naming both.
|
|
42
|
+
*
|
|
43
|
+
* FORMATTING CONTRACT (#1565): the invoker is emitted as a fixed point of
|
|
44
|
+
* Prettier's default config through `codegen-shared/prettierStable.ts`, like
|
|
45
|
+
* the other two generators, because `--check` byte-compares.
|
|
46
|
+
*/
|
|
47
|
+
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
48
|
+
import { basename, join } from "path";
|
|
49
|
+
import { parseConfigToml } from "./config-toml.js";
|
|
50
|
+
import { safeJsonParse } from "./workflow-payload.js";
|
|
51
|
+
import { resolveDeclaredMode, } from "./generated-config-surfaces.js";
|
|
52
|
+
import { schemaRejectsEmptyObject, schemaToTypeNode, } from "./workflow-codegen/schemaToTs.js";
|
|
53
|
+
import { describeSchema } from "./workflow-codegen/generated-schema-descriptor.js";
|
|
54
|
+
import { workflowFactoryName, workflowTypeBaseName, } from "./workflow-codegen/naming.js";
|
|
55
|
+
import { fingerprintToml } from "./db-codegen/dbFingerprint.js";
|
|
56
|
+
import { atom, generic, indent, intersection, objectType, printType, renderArrowCall, renderArrowProperty, renderParenList, renderTypeAlias, tsStringLiteral, union, } from "./codegen-shared/prettierStable.js";
|
|
57
|
+
/** The regenerated declaration beside `primitive-db-types.d.ts`. */
|
|
58
|
+
export const FUNCTION_TYPES_DECLARATION_FILE = "primitive-function-types.d.ts";
|
|
59
|
+
/** Where the per-key invokers go, under `functions/`, unless `-o` says otherwise. */
|
|
60
|
+
export const FUNCTION_INVOKERS_DIR = "generated";
|
|
61
|
+
/** Suffix identifying a generated invoker (shared with the other generators). */
|
|
62
|
+
export const GENERATED_FILE_SUFFIX = ".generated.ts";
|
|
63
|
+
/** The client package the invoker imports its types from. */
|
|
64
|
+
const CLIENT_PACKAGE = "js-bao-wss-client";
|
|
65
|
+
export class FunctionSchemaCodegenError extends Error {
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The key push will identify this file by, resolved exactly the way push
|
|
69
|
+
* resolves it (CR3281-001).
|
|
70
|
+
*
|
|
71
|
+
* Push reads `tomlData.function?.key || basename(file, ".toml")`, so a file
|
|
72
|
+
* named `local.toml` carrying `key = "remote"` is pushed, collected and
|
|
73
|
+
* key-checked as `remote`. Reading only the stem here would have generated a
|
|
74
|
+
* `remote`-less declaration and an invoker calling a function that does not
|
|
75
|
+
* exist, while the collect step compared the exported handler against
|
|
76
|
+
* `remote` — three spellings of one identity. The file stem stays the
|
|
77
|
+
* fallback, which is what a pulled tree always uses.
|
|
78
|
+
*
|
|
79
|
+
* Same rule, same reason as `databaseTypeSources` (SO3182-003): the generator
|
|
80
|
+
* reads the key the platform will hear about, never the file name alone.
|
|
81
|
+
*/
|
|
82
|
+
function resolveFunctionKey(source, table) {
|
|
83
|
+
return table?.key ? String(table.key) : source.key;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Every `functions/*.toml` in a tree, read once. The key is the one push
|
|
87
|
+
* uses: the file name (push takes the identity from it and attaches
|
|
88
|
+
* `functionKey` itself).
|
|
89
|
+
*/
|
|
90
|
+
export function functionSchemaSources(configDir) {
|
|
91
|
+
const dir = join(configDir, "functions");
|
|
92
|
+
if (!existsSync(dir))
|
|
93
|
+
return [];
|
|
94
|
+
const sources = [];
|
|
95
|
+
for (const file of readdirSync(dir).filter((f) => f.endsWith(".toml"))) {
|
|
96
|
+
const tomlPath = join(dir, file);
|
|
97
|
+
let tomlContent;
|
|
98
|
+
try {
|
|
99
|
+
tomlContent = readFileSync(tomlPath, "utf-8");
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
sources.push({ key: basename(file, ".toml"), tomlPath, tomlContent });
|
|
105
|
+
}
|
|
106
|
+
return sources;
|
|
107
|
+
}
|
|
108
|
+
/** The tree-relative spelling of a source, for a message an author acts on. */
|
|
109
|
+
function fileLabel(source) {
|
|
110
|
+
const at = source.tomlPath.lastIndexOf("/functions/");
|
|
111
|
+
return at >= 0 ? source.tomlPath.slice(at + 1) : source.tomlPath;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Parse one file into the data both renderers need. Throws a
|
|
115
|
+
* `FunctionSchemaCodegenError` naming the file for malformed schema JSON or an
|
|
116
|
+
* unresolvable mode — the honest `unknown` is for an ABSENT schema, never a
|
|
117
|
+
* broken one.
|
|
118
|
+
*/
|
|
119
|
+
export function describeFunctionSchemas(source) {
|
|
120
|
+
let table;
|
|
121
|
+
try {
|
|
122
|
+
table = parseConfigToml(source.tomlContent)?.function ?? {};
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
throw new FunctionSchemaCodegenError(`${fileLabel(source)}: the file does not parse as TOML (${error?.message ?? error})`);
|
|
126
|
+
}
|
|
127
|
+
// The key push identifies this file by — an authored `[function] key` when
|
|
128
|
+
// there is one, the file stem otherwise (CR3281-001).
|
|
129
|
+
const key = resolveFunctionKey(source, table);
|
|
130
|
+
const mode = resolveDeclaredMode({ mode: table.mode, durable: table.durable });
|
|
131
|
+
if (mode.ok === false) {
|
|
132
|
+
throw new FunctionSchemaCodegenError(`${fileLabel(source)}: ${mode.error}`);
|
|
133
|
+
}
|
|
134
|
+
const schema = (field) => {
|
|
135
|
+
try {
|
|
136
|
+
return safeJsonParse(table[field]);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
throw new FunctionSchemaCodegenError(`${fileLabel(source)}: \`${field}\` is not valid JSON (${error?.message ?? error})`);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const inputSchema = schema("inputSchema");
|
|
143
|
+
const outputSchema = schema("outputSchema");
|
|
144
|
+
const typeBaseName = workflowTypeBaseName(key);
|
|
145
|
+
return {
|
|
146
|
+
key,
|
|
147
|
+
mode: mode.mode,
|
|
148
|
+
fileLabel: fileLabel(source),
|
|
149
|
+
inputSchema,
|
|
150
|
+
outputSchema,
|
|
151
|
+
inputRequired: inputSchema !== undefined && schemaRejectsEmptyObject(inputSchema),
|
|
152
|
+
typeBaseName,
|
|
153
|
+
inputTypeName: `${typeBaseName}Input`,
|
|
154
|
+
outputTypeName: `${typeBaseName}Output`,
|
|
155
|
+
factoryName: workflowFactoryName(key),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Describe every source, sorted by key, refusing two keys that sanitize to
|
|
160
|
+
* one identifier: they would render one file over the other and one type
|
|
161
|
+
* name for two schemas.
|
|
162
|
+
*/
|
|
163
|
+
function describeAll(sources) {
|
|
164
|
+
const described = sources.map((source) => ({ fn: describeFunctionSchemas(source), source }));
|
|
165
|
+
described.sort((a, b) => (a.fn.key < b.fn.key ? -1 : a.fn.key > b.fn.key ? 1 : 0));
|
|
166
|
+
// Two files resolving to ONE key — only reachable through an authored
|
|
167
|
+
// `[function] key` (CR3281-001), since file stems are unique by
|
|
168
|
+
// construction. They would render one invoker over the other and push one
|
|
169
|
+
// function twice, so name both files rather than pick a winner.
|
|
170
|
+
const byKey = new Map();
|
|
171
|
+
for (const { fn, source } of described) {
|
|
172
|
+
const other = byKey.get(fn.key);
|
|
173
|
+
if (other !== undefined) {
|
|
174
|
+
throw new FunctionSchemaCodegenError(`${fileLabel(other)} and ${fileLabel(source)} both declare the function ` +
|
|
175
|
+
`key '${fn.key}' — one file is one function, so rename or remove one ` +
|
|
176
|
+
`\`[function] key\``);
|
|
177
|
+
}
|
|
178
|
+
byKey.set(fn.key, source);
|
|
179
|
+
}
|
|
180
|
+
const byBaseName = new Map();
|
|
181
|
+
for (const { fn } of described) {
|
|
182
|
+
const other = byBaseName.get(fn.typeBaseName);
|
|
183
|
+
if (other !== undefined && other !== fn.key) {
|
|
184
|
+
throw new FunctionSchemaCodegenError(`function keys '${other}' and '${fn.key}' both name the generated type ` +
|
|
185
|
+
`\`${fn.typeBaseName}Input\` — rename one so the two do not collide after sanitizing`);
|
|
186
|
+
}
|
|
187
|
+
byBaseName.set(fn.typeBaseName, fn.key);
|
|
188
|
+
}
|
|
189
|
+
return described;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* A top-level `<Name>Input`/`<Name>Output` declaration: an absent schema →
|
|
193
|
+
* `unknown`, a plain object → an `interface`, anything else (a `oneOf` above
|
|
194
|
+
* all, which begins with `{` too) → a `type` alias. Same decision as the
|
|
195
|
+
* workflow generator, through the shared descriptor rather than a heuristic.
|
|
196
|
+
*/
|
|
197
|
+
function renderTypeDecl(name, schema) {
|
|
198
|
+
if (schema === undefined)
|
|
199
|
+
return renderTypeAlias(name, atom("unknown"));
|
|
200
|
+
const node = schemaToTypeNode(schema);
|
|
201
|
+
if (node.kind === "block" && !describeSchema(schema).oneOf) {
|
|
202
|
+
return `export interface ${name} ${printType(node, 0, 0)}`;
|
|
203
|
+
}
|
|
204
|
+
return renderTypeAlias(name, node);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* `renderTypeDecl` for one declared field, with a failure that names the file
|
|
208
|
+
* and the field (CR3281-004).
|
|
209
|
+
*
|
|
210
|
+
* The shared renderer refuses a schema it cannot type — a `oneOf` of objects
|
|
211
|
+
* with no usable discriminator, above all — by throwing a plain `Error` that
|
|
212
|
+
* says "workflows codegen" and names neither. Push catches
|
|
213
|
+
* `FunctionSchemaCodegenError` per tree and lets the rest of it land, so an
|
|
214
|
+
* unconverted throw took the whole command down before a single healthy
|
|
215
|
+
* function was sent, over a file the author could not identify from the
|
|
216
|
+
* message.
|
|
217
|
+
*/
|
|
218
|
+
function renderDeclaredType(fn, field) {
|
|
219
|
+
const name = field === "inputSchema" ? fn.inputTypeName : fn.outputTypeName;
|
|
220
|
+
const schema = field === "inputSchema" ? fn.inputSchema : fn.outputSchema;
|
|
221
|
+
try {
|
|
222
|
+
return renderTypeDecl(name, schema);
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
if (error instanceof FunctionSchemaCodegenError)
|
|
226
|
+
throw error;
|
|
227
|
+
throw new FunctionSchemaCodegenError(`${fn.fileLabel}: \`${field}\` cannot be rendered as a TypeScript type ` +
|
|
228
|
+
`(${error?.message ?? error})`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const DECLARATION_HEADER = `// GENERATED by \`primitive config push\` from functions/*.toml.
|
|
232
|
+
// DO NOT EDIT — your changes are overwritten on the next push.
|
|
233
|
+
//
|
|
234
|
+
// It gives \`defineFunction("<key>", handler)\` its types: \`input\` is the
|
|
235
|
+
// function's declared inputSchema and the return is checked against its
|
|
236
|
+
// declared outputSchema. A key this tree does not declare is a compile error.
|
|
237
|
+
// The client-side invokers are the \`generated/<key>.generated.ts\` files beside
|
|
238
|
+
// this one.
|
|
239
|
+
`;
|
|
240
|
+
/**
|
|
241
|
+
* The declaration for a whole tree's functions. Sorted by key so the bytes
|
|
242
|
+
* depend on the files and not on the order they were read in. The
|
|
243
|
+
* augmentation is emitted even when the tree has no function yet: an empty
|
|
244
|
+
* `FunctionSchemas` keeps `FunctionKeys` open (`string`), so nothing breaks.
|
|
245
|
+
*/
|
|
246
|
+
export function renderFunctionSchemasDeclaration(sources) {
|
|
247
|
+
const functions = describeAll(sources).map((entry) => entry.fn);
|
|
248
|
+
const lines = [DECLARATION_HEADER];
|
|
249
|
+
for (const fn of functions) {
|
|
250
|
+
lines.push(renderDeclaredType(fn, "inputSchema"));
|
|
251
|
+
lines.push("");
|
|
252
|
+
lines.push(renderDeclaredType(fn, "outputSchema"));
|
|
253
|
+
lines.push("");
|
|
254
|
+
}
|
|
255
|
+
if (functions.length === 0) {
|
|
256
|
+
lines.push("export interface PrimitiveFunctionSchemas {}");
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
lines.push("export interface PrimitiveFunctionSchemas {");
|
|
260
|
+
for (const fn of functions) {
|
|
261
|
+
lines.push(` ${JSON.stringify(fn.key)}: {`);
|
|
262
|
+
lines.push(` input: ${fn.inputTypeName};`);
|
|
263
|
+
lines.push(` output: ${fn.outputTypeName};`);
|
|
264
|
+
lines.push(` mode: ${JSON.stringify(fn.mode)};`);
|
|
265
|
+
lines.push(` };`);
|
|
266
|
+
}
|
|
267
|
+
lines.push("}");
|
|
268
|
+
}
|
|
269
|
+
lines.push("");
|
|
270
|
+
lines.push(`declare module "primitive-functions" {`);
|
|
271
|
+
lines.push(` interface FunctionSchemas extends PrimitiveFunctionSchemas {}`);
|
|
272
|
+
lines.push(`}`);
|
|
273
|
+
lines.push("");
|
|
274
|
+
return lines.join("\n");
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* The invoker factory for one function — the verbs its mode allows and
|
|
278
|
+
* nothing else, so the wrong verb is a compile error, not a runtime
|
|
279
|
+
* `FUNCTION_MODE_MISMATCH`.
|
|
280
|
+
*
|
|
281
|
+
* `invoke`/`start` take the key POSITIONALLY (`client.functions.<verb>(key,
|
|
282
|
+
* opts)`), so the key cannot ride in through `opts`; `terminate` addresses a
|
|
283
|
+
* run by a ref object, where the spread comes first and the pinned key last —
|
|
284
|
+
* a caller passing a ref variable carrying another key still terminates this
|
|
285
|
+
* function's run.
|
|
286
|
+
*/
|
|
287
|
+
function renderFactory(fn) {
|
|
288
|
+
const keyLiteral = tsStringLiteral(fn.key);
|
|
289
|
+
const inputMember = fn.inputRequired
|
|
290
|
+
? `input: ${fn.inputTypeName}`
|
|
291
|
+
: `input?: ${fn.inputTypeName}`;
|
|
292
|
+
const lines = [
|
|
293
|
+
renderParenList(`export function ${fn.factoryName}`, ["client: JsBaoClient"], " {", 0),
|
|
294
|
+
` return {`,
|
|
295
|
+
];
|
|
296
|
+
// `opts: { input: X } & Omit<<Options><X>, "input">` — always broken onto its
|
|
297
|
+
// own line: the shortest possible form is already wider than 80 columns.
|
|
298
|
+
const optsParam = (optionsTypeName) => {
|
|
299
|
+
const node = intersection([
|
|
300
|
+
objectType([inputMember]),
|
|
301
|
+
generic("Omit", [
|
|
302
|
+
generic(optionsTypeName, [atom(fn.inputTypeName)]),
|
|
303
|
+
union([atom(`"input"`)]),
|
|
304
|
+
]),
|
|
305
|
+
]);
|
|
306
|
+
const head = `${indent(3)}opts: `;
|
|
307
|
+
return `${head}${printType(node, head.length, 3, 1)},`;
|
|
308
|
+
};
|
|
309
|
+
const invocation = (method, typeArgs, optionsTypeName) => renderArrowCall({
|
|
310
|
+
head: [`${indent(2)}${method}: (`, optsParam(optionsTypeName), `${indent(2)}) =>`].join("\n"),
|
|
311
|
+
callee: generic(`client.functions.${method}`, typeArgs.map(atom)),
|
|
312
|
+
leadingArgs: [keyLiteral],
|
|
313
|
+
objectMembers: ["...opts"],
|
|
314
|
+
level: 3,
|
|
315
|
+
tail: ",",
|
|
316
|
+
});
|
|
317
|
+
if (fn.mode === "request") {
|
|
318
|
+
lines.push(invocation("invoke", [fn.outputTypeName, fn.inputTypeName], "FunctionInvokeOptions"));
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
lines.push(invocation("start", [fn.inputTypeName], "FunctionStartOptions"));
|
|
322
|
+
lines.push(renderArrowProperty({
|
|
323
|
+
level: 2,
|
|
324
|
+
key: "getStatus",
|
|
325
|
+
params: ["runId: string"],
|
|
326
|
+
signatureTail: " =>",
|
|
327
|
+
callee: generic("client.functions.getStatus", [atom(fn.outputTypeName)]),
|
|
328
|
+
leadingArgs: ["runId"],
|
|
329
|
+
tail: ",",
|
|
330
|
+
}));
|
|
331
|
+
lines.push(renderArrowProperty({
|
|
332
|
+
level: 2,
|
|
333
|
+
key: "waitFor",
|
|
334
|
+
params: ["runId: string", "options?: WaitForWorkflowOptions"],
|
|
335
|
+
signatureTail: " =>",
|
|
336
|
+
callee: generic("client.functions.waitFor", [atom(fn.outputTypeName)]),
|
|
337
|
+
leadingArgs: ["runId", "options"],
|
|
338
|
+
tail: ",",
|
|
339
|
+
}));
|
|
340
|
+
lines.push(renderArrowProperty({
|
|
341
|
+
level: 2,
|
|
342
|
+
key: "terminate",
|
|
343
|
+
params: [`ref: Omit<FunctionRunRef, "functionKey">`],
|
|
344
|
+
signatureTail: " =>",
|
|
345
|
+
callee: generic("client.functions.terminate", [atom(fn.outputTypeName)]),
|
|
346
|
+
leadingArgs: [],
|
|
347
|
+
objectMembers: ["...ref", { key: "functionKey", value: keyLiteral }],
|
|
348
|
+
tail: ",",
|
|
349
|
+
}));
|
|
350
|
+
}
|
|
351
|
+
lines.push(` };`, `}`);
|
|
352
|
+
return lines.join("\n");
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* `import type { … } from "js-bao-wss-client"`, the way Prettier prints it:
|
|
356
|
+
* on one line when it fits, one specifier per line (trailing comma) when not.
|
|
357
|
+
*/
|
|
358
|
+
function renderImport(names) {
|
|
359
|
+
const inline = `import type { ${names.join(", ")} } from "${CLIENT_PACKAGE}";`;
|
|
360
|
+
if (inline.length <= 80)
|
|
361
|
+
return inline;
|
|
362
|
+
return `import type {\n${names.map((i) => ` ${i},`).join("\n")}\n} from "${CLIENT_PACKAGE}";`;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* The full `<key>.generated.ts` for one function. Pure — exported so tests
|
|
366
|
+
* can assert on the string directly.
|
|
367
|
+
*/
|
|
368
|
+
export function renderFunctionInvokerFile(source) {
|
|
369
|
+
const fn = describeFunctionSchemas(source);
|
|
370
|
+
const fingerprint = fingerprintToml(source.tomlContent);
|
|
371
|
+
// Only the option types the mode's verbs reference, so the file compiles
|
|
372
|
+
// under a consumer's `noUnusedLocals`.
|
|
373
|
+
const imports = fn.mode === "request"
|
|
374
|
+
? ["FunctionInvokeOptions", "JsBaoClient"]
|
|
375
|
+
: ["FunctionRunRef", "FunctionStartOptions", "JsBaoClient", "WaitForWorkflowOptions"];
|
|
376
|
+
const blocks = [
|
|
377
|
+
[
|
|
378
|
+
`// AUTO-GENERATED FROM ${fn.fileLabel} — DO NOT EDIT.`,
|
|
379
|
+
"// Run `primitive functions codegen` to regenerate.",
|
|
380
|
+
`// fingerprint: ${fingerprint}`,
|
|
381
|
+
].join("\n"),
|
|
382
|
+
renderImport(imports),
|
|
383
|
+
renderDeclaredType(fn, "inputSchema"),
|
|
384
|
+
renderDeclaredType(fn, "outputSchema"),
|
|
385
|
+
renderFactory(fn),
|
|
386
|
+
];
|
|
387
|
+
return { key: fn.key, content: blocks.join("\n\n") + "\n" };
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Every invoker for a tree, keyed by the file name the generator writes
|
|
391
|
+
* (`<key>.generated.ts`), with the identifier-collision refusal applied
|
|
392
|
+
* across the set.
|
|
393
|
+
*/
|
|
394
|
+
export function renderFunctionInvokers(sources) {
|
|
395
|
+
// `describeAll` is the collision check; the per-file render repeats the
|
|
396
|
+
// (cheap) parse rather than threading the IR through.
|
|
397
|
+
return describeAll(sources).map(({ fn, source }) => ({
|
|
398
|
+
fileName: `${fn.key}${GENERATED_FILE_SUFFIX}`,
|
|
399
|
+
content: renderFunctionInvokerFile(source).content,
|
|
400
|
+
}));
|
|
401
|
+
}
|
|
402
|
+
//# sourceMappingURL=function-schema-codegen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"function-schema-codegen.js","sourceRoot":"","sources":["../../../src/lib/function-schema-codegen.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
* directory inside the tree, so the write step resolves the real path one last
|
|
32
32
|
* time and refuses a destination that lands outside the real root.
|
|
33
33
|
*/
|
|
34
|
+
import { type FunctionMode, type TriggerDeclaration } from "./generated-config-surfaces.js";
|
|
34
35
|
import { type FunctionManifest as CollectedManifest } from "./function-collect.js";
|
|
35
36
|
/**
|
|
36
37
|
* Collect one function's manifest, or answer from this command's memo.
|
|
@@ -47,6 +48,26 @@ export declare function collectManifestForBundle(options: {
|
|
|
47
48
|
/** The built bundle's source, for the static scan (#3279). */
|
|
48
49
|
bundle?: string;
|
|
49
50
|
}): Promise<CollectedManifest>;
|
|
51
|
+
/**
|
|
52
|
+
* The server's own `[function.triggers.*]` rules, applied to a parsed
|
|
53
|
+
* `[function]` table, with "nothing declared" spelled as null so a caller can
|
|
54
|
+
* skip the work.
|
|
55
|
+
*
|
|
56
|
+
* `normalizeTriggerDeclaration` comes from `generated-config-surfaces.ts` —
|
|
57
|
+
* `src/config-surface/trigger-declaration.ts` vendored verbatim. Until #3320
|
|
58
|
+
* the CLI ran a hand-written restatement of those rules
|
|
59
|
+
* (`cli/src/lib/function-triggers.ts`), kept in step only by a paired-fixture
|
|
60
|
+
* test; the artifact's `--check` makes drift a build failure instead.
|
|
61
|
+
*
|
|
62
|
+
* One check is the CLI's OWN and is deliberately not on that path: the cron
|
|
63
|
+
* expression's field count. The authority for cron grammar is the server's
|
|
64
|
+
* `src/cron-parser.ts` (`parseCron`, run at the push boundary), which the
|
|
65
|
+
* declaration rules never call — so this is a shape precheck that turns the
|
|
66
|
+
* commonest typo into a named local error, not a second copy of a rule.
|
|
67
|
+
*/
|
|
68
|
+
export declare function normalizeFunctionTriggers(functionTable: any, options?: {
|
|
69
|
+
mode?: FunctionMode;
|
|
70
|
+
}): TriggerDeclaration | null;
|
|
50
71
|
export interface FunctionConfigPush {
|
|
51
72
|
entry: string;
|
|
52
73
|
/** base64 of the authored `functions/<key>.toml` bytes. */
|
|
@@ -65,15 +86,62 @@ export interface FunctionConfigPush {
|
|
|
65
86
|
manifest: string | null;
|
|
66
87
|
/** The number BOTH sides compare to decide "is this a no-op?". */
|
|
67
88
|
envelopeHash: string;
|
|
89
|
+
/** `mode = "request" | "task"` (#3281), resolved from the file's two spellings. */
|
|
90
|
+
mode: FunctionMode;
|
|
91
|
+
/**
|
|
92
|
+
* The same resolution as `mode`, in the alias's spelling: a new CLI against
|
|
93
|
+
* a server that predates `mode` still pushes a task function as a task.
|
|
94
|
+
*/
|
|
68
95
|
durable: boolean;
|
|
69
96
|
limits?: Record<string, unknown>;
|
|
70
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Resolve the file's mode — `mode`, its alias `durable`, or neither — through
|
|
100
|
+
* the ONE vendored rule (#3281). A disagreement or an unknown word is a
|
|
101
|
+
* `FunctionBuildError` naming the function, like every other preflight
|
|
102
|
+
* refusal, so nothing is built or sent for that file.
|
|
103
|
+
*/
|
|
104
|
+
export declare function resolveFunctionMode(functionKey: string, table: any): FunctionMode;
|
|
105
|
+
/**
|
|
106
|
+
* Everything about one `functions/<key>.toml` that `config push` can decide
|
|
107
|
+
* from the file alone (#3320).
|
|
108
|
+
*
|
|
109
|
+
* This is the seam the issue is about. These checks used to run inside the
|
|
110
|
+
* APPLY loop, so a `durable = true` beside a webhook block — or a missing
|
|
111
|
+
* `entry`, or a signed scheme with no `signingSecret` — was raised after app
|
|
112
|
+
* settings, vars, integrations, webhooks, cron triggers and database types had
|
|
113
|
+
* already been written, while the command's own framing promised that a
|
|
114
|
+
* refusal meant nothing was applied. Running them in the front-loaded pass
|
|
115
|
+
* (#976) makes that framing true for this class of error.
|
|
116
|
+
*
|
|
117
|
+
* Every rule here is the SERVER's, reached through the generated surface
|
|
118
|
+
* artifact (#3320 part 0), not a local imitation of it. What is deliberately
|
|
119
|
+
* absent is app-state-dependent by construction: whether the referenced secret
|
|
120
|
+
* exists, whether the scheme's `config` is valid under this environment's JWKS
|
|
121
|
+
* policy, per-app caps, key collisions, archived tombstones. A local guess at
|
|
122
|
+
* any of those would be a preflight that gives a false all-clear.
|
|
123
|
+
*
|
|
124
|
+
* Returns the messages the apply loop would have raised, verbatim — so the
|
|
125
|
+
* author reads the same sentence wherever it reaches them, and `config diff`
|
|
126
|
+
* can report it under Invalid (#2880 symmetry).
|
|
127
|
+
*/
|
|
128
|
+
export declare function functionTomlPreflightErrors(options: {
|
|
129
|
+
filePath: string;
|
|
130
|
+
functionKey: string;
|
|
131
|
+
/** The already-parsed document, so the file is read once. */
|
|
132
|
+
tomlData: any;
|
|
133
|
+
}): string[];
|
|
71
134
|
/**
|
|
72
135
|
* Build everything the config-version route needs for one function file.
|
|
73
136
|
*
|
|
74
137
|
* Throws `FunctionBuildError` for a missing `entry`, a missing entry file, a
|
|
75
138
|
* build error, or an import that escapes the config tree — one class, so the
|
|
76
139
|
* push loop has one thing to report and pushes nothing for that function.
|
|
140
|
+
*
|
|
141
|
+
* The file-decidable checks are `functionTomlPreflightErrors`', kept here as
|
|
142
|
+
* defense in depth (#3179's dual-validation shape): `config push` runs them in
|
|
143
|
+
* its preflight now, but `functions` commands and a direct caller reach this
|
|
144
|
+
* function without one.
|
|
77
145
|
*/
|
|
78
146
|
export declare function buildFunctionConfigPush(options: {
|
|
79
147
|
configDir: string;
|
|
@@ -93,11 +161,21 @@ export declare function buildFunctionCreatePayload(functionKey: string, table: a
|
|
|
93
161
|
* The update body. The key is NOT re-sent — it is the function's claim on the
|
|
94
162
|
* app's single key namespace and the URL already names the row — and `status`
|
|
95
163
|
* is server-owned on the sixth carrying type as on the other five.
|
|
164
|
+
*
|
|
165
|
+
* #3317 — the schemas are TOML-owned on exactly the terms `description` is
|
|
166
|
+
* (#1567), which is what prompts have sent since then: the update handler
|
|
167
|
+
* preserves a field the body omits, so dropping the key would leave a schema
|
|
168
|
+
* live that the file no longer declares, and the comparison — which reads an
|
|
169
|
+
* absent schema as `null` — would report that difference again on every run.
|
|
170
|
+
* Removing `[function.inputSchema]` clears it, and the next diff is Synced.
|
|
96
171
|
*/
|
|
97
172
|
export declare function buildFunctionUpdatePayload(table: any): Record<string, any>;
|
|
98
173
|
/** The version-carried keys, as the config-version row holds them. */
|
|
99
174
|
export interface ActiveFunctionVersion {
|
|
100
175
|
entry?: string;
|
|
176
|
+
/** #3281 — serialized beside `durable` by a server that knows the word. */
|
|
177
|
+
mode?: string;
|
|
178
|
+
/** The stored column; the only thing an older server serializes. */
|
|
101
179
|
durable?: boolean;
|
|
102
180
|
/** JSON string on the row; an object is accepted too. */
|
|
103
181
|
limits?: unknown;
|
|
@@ -109,10 +187,15 @@ export interface ActiveFunctionVersion {
|
|
|
109
187
|
* created through the API that has never had code pushed. When bytes exist,
|
|
110
188
|
* pull writes THOSE; this is the fallback that still produces a pushable file.
|
|
111
189
|
*/
|
|
112
|
-
export declare function serializeFunction(record: any, active?: ActiveFunctionVersion): string;
|
|
190
|
+
export declare function serializeFunction(record: any, active?: ActiveFunctionVersion, log?: (message: string) => void): string;
|
|
191
|
+
/**
|
|
192
|
+
* The mode a server's config-version row is in, whichever of the two fields
|
|
193
|
+
* this server serializes: `mode` since #3281, `durable` before it.
|
|
194
|
+
*/
|
|
195
|
+
export declare function activeVersionMode(active?: ActiveFunctionVersion | null): FunctionMode;
|
|
113
196
|
/**
|
|
114
197
|
* The entity both sides of `config diff` are projected onto: the header's
|
|
115
|
-
* authored fields plus the
|
|
198
|
+
* authored fields plus the keys the VERSION carries. Stated once so a
|
|
116
199
|
* local file and a server record cannot be read into different shapes.
|
|
117
200
|
*
|
|
118
201
|
* Text the server rewrites on the way in is read the same way it will come
|