primitive-admin 1.1.0-alpha.73 → 1.1.0-alpha.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +18 -25
  2. package/assets/skill/skills/primitive-platform/SKILL.md +30 -14
  3. package/dist/bin/primitive.js +25 -21
  4. package/dist/bin/primitive.js.map +1 -1
  5. package/dist/src/commands/analytics.js +117 -2
  6. package/dist/src/commands/analytics.js.map +1 -1
  7. package/dist/src/commands/auth.js +13 -107
  8. package/dist/src/commands/auth.js.map +1 -1
  9. package/dist/src/commands/collection-type-configs.js +1 -1
  10. package/dist/src/commands/collection-type-configs.js.map +1 -1
  11. package/dist/src/commands/config.js +8 -4
  12. package/dist/src/commands/config.js.map +1 -1
  13. package/dist/src/commands/database-type-configs.js +1 -1
  14. package/dist/src/commands/database-type-configs.js.map +1 -1
  15. package/dist/src/commands/databases.js +25 -31
  16. package/dist/src/commands/databases.js.map +1 -1
  17. package/dist/src/commands/documents.js +758 -53
  18. package/dist/src/commands/documents.js.map +1 -1
  19. package/dist/src/commands/env.d.ts +1 -1
  20. package/dist/src/commands/env.js +57 -16
  21. package/dist/src/commands/env.js.map +1 -1
  22. package/dist/src/commands/functions.d.ts +20 -0
  23. package/dist/src/commands/functions.js +463 -0
  24. package/dist/src/commands/functions.js.map +1 -0
  25. package/dist/src/commands/groups.js +1 -1
  26. package/dist/src/commands/groups.js.map +1 -1
  27. package/dist/src/commands/init.d.ts +12 -15
  28. package/dist/src/commands/init.js +38 -92
  29. package/dist/src/commands/init.js.map +1 -1
  30. package/dist/src/commands/integrations.js +5 -3
  31. package/dist/src/commands/integrations.js.map +1 -1
  32. package/dist/src/commands/prompts.js +5 -7
  33. package/dist/src/commands/prompts.js.map +1 -1
  34. package/dist/src/commands/rule-sets.js +1 -1
  35. package/dist/src/commands/rule-sets.js.map +1 -1
  36. package/dist/src/commands/scripts.js +23 -11
  37. package/dist/src/commands/scripts.js.map +1 -1
  38. package/dist/src/commands/sync-app-settings.js +2 -4
  39. package/dist/src/commands/sync-app-settings.js.map +1 -1
  40. package/dist/src/commands/sync.d.ts +65 -2
  41. package/dist/src/commands/sync.js +867 -21
  42. package/dist/src/commands/sync.js.map +1 -1
  43. package/dist/src/commands/workflows.js +6 -8
  44. package/dist/src/commands/workflows.js.map +1 -1
  45. package/dist/src/lib/api-client.d.ts +163 -2
  46. package/dist/src/lib/api-client.js +227 -5
  47. package/dist/src/lib/api-client.js.map +1 -1
  48. package/dist/src/lib/app-match-guard.d.ts +44 -0
  49. package/dist/src/lib/app-match-guard.js +72 -0
  50. package/dist/src/lib/app-match-guard.js.map +1 -0
  51. package/dist/src/lib/app-settings-descriptor.js +4 -0
  52. package/dist/src/lib/app-settings-descriptor.js.map +1 -1
  53. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +11 -8
  54. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +112 -60
  55. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -1
  56. package/dist/src/lib/config-object-descriptor.js +39 -0
  57. package/dist/src/lib/config-object-descriptor.js.map +1 -1
  58. package/dist/src/lib/config-surface.d.ts +10 -0
  59. package/dist/src/lib/config-surface.js +17 -0
  60. package/dist/src/lib/config-surface.js.map +1 -1
  61. package/dist/src/lib/config.d.ts +15 -4
  62. package/dist/src/lib/config.js +22 -39
  63. package/dist/src/lib/config.js.map +1 -1
  64. package/dist/src/lib/credentials-store.d.ts +7 -15
  65. package/dist/src/lib/credentials-store.js +52 -85
  66. package/dist/src/lib/credentials-store.js.map +1 -1
  67. package/dist/src/lib/document-export-permissions.d.ts +30 -0
  68. package/dist/src/lib/document-export-permissions.js +54 -0
  69. package/dist/src/lib/document-export-permissions.js.map +1 -0
  70. package/dist/src/lib/env-resolver-core.d.ts +64 -16
  71. package/dist/src/lib/env-resolver-core.js +128 -17
  72. package/dist/src/lib/env-resolver-core.js.map +1 -1
  73. package/dist/src/lib/env-resolver.d.ts +3 -3
  74. package/dist/src/lib/env-resolver.js +2 -2
  75. package/dist/src/lib/function-bundle.d.ts +141 -0
  76. package/dist/src/lib/function-bundle.js +333 -0
  77. package/dist/src/lib/function-bundle.js.map +1 -0
  78. package/dist/src/lib/function-collect.d.ts +101 -0
  79. package/dist/src/lib/function-collect.js +339 -0
  80. package/dist/src/lib/function-collect.js.map +1 -0
  81. package/dist/src/lib/function-db-types.d.ts +149 -0
  82. package/dist/src/lib/function-db-types.js +587 -0
  83. package/dist/src/lib/function-db-types.js.map +1 -0
  84. package/dist/src/lib/function-grants-preflight.d.ts +118 -0
  85. package/dist/src/lib/function-grants-preflight.js +213 -0
  86. package/dist/src/lib/function-grants-preflight.js.map +1 -0
  87. package/dist/src/lib/function-sync.d.ts +191 -0
  88. package/dist/src/lib/function-sync.js +474 -0
  89. package/dist/src/lib/function-sync.js.map +1 -0
  90. package/dist/src/lib/function-triggers.d.ts +54 -0
  91. package/dist/src/lib/function-triggers.js +223 -0
  92. package/dist/src/lib/function-triggers.js.map +1 -0
  93. package/dist/src/lib/generated-config-surfaces.d.ts +389 -0
  94. package/dist/src/lib/generated-config-surfaces.js +1030 -2
  95. package/dist/src/lib/generated-config-surfaces.js.map +1 -1
  96. package/dist/src/lib/generated-sdk-types.d.ts +12 -0
  97. package/dist/src/lib/generated-sdk-types.js +13 -0
  98. package/dist/src/lib/generated-sdk-types.js.map +1 -0
  99. package/dist/src/lib/init-adopt.js +2 -2
  100. package/dist/src/lib/init-adopt.js.map +1 -1
  101. package/dist/src/lib/init-assets.js +3 -3
  102. package/dist/src/lib/init-config.d.ts +1 -1
  103. package/dist/src/lib/init-ios-links.d.ts +6 -5
  104. package/dist/src/lib/init-ios-links.js +9 -8
  105. package/dist/src/lib/init-ios-links.js.map +1 -1
  106. package/dist/src/lib/init-plan.d.ts +1 -1
  107. package/dist/src/lib/init-plan.js +1 -1
  108. package/dist/src/lib/init-xcode.d.ts +6 -5
  109. package/dist/src/lib/init-xcode.js +34 -10
  110. package/dist/src/lib/init-xcode.js.map +1 -1
  111. package/dist/src/lib/ios-app-id.d.ts +34 -0
  112. package/dist/src/lib/ios-app-id.js +69 -0
  113. package/dist/src/lib/ios-app-id.js.map +1 -0
  114. package/dist/src/lib/local-state.d.ts +1 -1
  115. package/dist/src/lib/local-state.js +1 -1
  116. package/dist/src/lib/local-test-cases.d.ts +1 -1
  117. package/dist/src/lib/local-test-cases.js +2 -1
  118. package/dist/src/lib/local-test-cases.js.map +1 -1
  119. package/dist/src/lib/migration-nag.d.ts +2 -2
  120. package/dist/src/lib/migration-nag.js +4 -3
  121. package/dist/src/lib/migration-nag.js.map +1 -1
  122. package/dist/src/lib/project-config.d.ts +38 -21
  123. package/dist/src/lib/project-config.js +57 -47
  124. package/dist/src/lib/project-config.js.map +1 -1
  125. package/dist/src/lib/snapshots.d.ts +2 -2
  126. package/dist/src/lib/snapshots.js +2 -2
  127. package/dist/src/lib/swift-codegen/generator.d.ts +1 -1
  128. package/dist/src/lib/swift-codegen/generator.js +1 -1
  129. package/dist/src/lib/sync-dir-selector.d.ts +1 -1
  130. package/dist/src/lib/sync-dir-selector.js +1 -1
  131. package/dist/src/lib/sync-paths.d.ts +52 -16
  132. package/dist/src/lib/sync-paths.js +68 -22
  133. package/dist/src/lib/sync-paths.js.map +1 -1
  134. package/dist/src/lib/sync-resource-types.d.ts +23 -4
  135. package/dist/src/lib/sync-resource-types.js +106 -8
  136. package/dist/src/lib/sync-resource-types.js.map +1 -1
  137. package/dist/src/lib/template.d.ts +2 -2
  138. package/dist/src/lib/template.js +2 -2
  139. package/dist/src/lib/test-case-keys.d.ts +1 -1
  140. package/dist/src/lib/test-case-keys.js +1 -1
  141. package/dist/src/lib/test-case-variables.d.ts +14 -0
  142. package/dist/src/lib/test-case-variables.js +42 -0
  143. package/dist/src/lib/test-case-variables.js.map +1 -1
  144. package/dist/src/lib/workflow-codegen/generator.d.ts +1 -1
  145. package/dist/src/lib/workflow-codegen/generator.js +1 -1
  146. package/dist/src/lib/workflow-usage.d.ts +198 -0
  147. package/dist/src/lib/workflow-usage.js +312 -0
  148. package/dist/src/lib/workflow-usage.js.map +1 -0
  149. package/dist/src/types/index.d.ts +12 -2
  150. package/package.json +4 -3
@@ -0,0 +1,474 @@
1
+ /**
2
+ * `functions/<key>.toml` on the wire and back (#3179, project
3
+ * `server-functions`).
4
+ *
5
+ * A function is the one configuration object whose file is not its whole
6
+ * authored surface: the TOML states the gate, the entry and the limits, and the
7
+ * TypeScript the entry reaches is the rest of it. `config push` therefore sends
8
+ * TWO things — a header (create/update) and an immutable config VERSION
9
+ * carrying the authored TOML bytes, every source file and the built bundle —
10
+ * and `config pull` writes both halves back.
11
+ *
12
+ * ── The envelope hash is the shared answer to "changed?" ──────────────────
13
+ *
14
+ * The server decides whether a push is a no-op on `envelopeHash` (sha256 over
15
+ * the TOML bytes, the sources and the bundle), because a comment-only or
16
+ * CRLF-only edit leaves the BUNDLE identical and must still make a version
17
+ * (F-003). The CLI computes the same number to decide whether to make the call
18
+ * at all, through `function-bundle.ts`'s copy of the server's canonical
19
+ * encoding. If those two encodings ever drift, one side re-pushes forever and
20
+ * the other silently drops an edit — `function-bundle-3179.test.ts` pins them
21
+ * against each other.
22
+ *
23
+ * ── Pull writes bytes ────────────────────────────────────────────────────
24
+ *
25
+ * Canonical re-serialization cannot preserve comments, key order or line
26
+ * endings, so the envelope stores the AUTHORED bytes and pull writes those
27
+ * (F-009). It also never trusts a stored path: the files it writes are named by
28
+ * the server, so a path that normalizes outside the tree — or into
29
+ * `node_modules`, which is never authored source — is refused rather than
30
+ * written to a developer's disk. The lexical rules cannot see a symlinked
31
+ * directory inside the tree, so the write step resolves the real path one last
32
+ * time and refuses a destination that lands outside the real root.
33
+ */
34
+ import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, writeFileSync, } from "fs";
35
+ import { dirname, isAbsolute, join, posix as posixPath, relative, resolve, sep, } from "path";
36
+ import { stringifyConfigToml } from "./config-toml.js";
37
+ import { SERVER_FUNCTION_TABLE } from "./config-surface.js";
38
+ import { buildPayloadFromToml, projectRecordToToml, tomlOwned } from "./config-payload.js";
39
+ import { normalizeFunctionTriggers, TriggerDeclarationError, } from "./function-triggers.js";
40
+ import { buildFunctionBundle, FunctionBuildError, functionEnvelopeHash, FUNCTION_ENVELOPE_SCHEMA_VERSION, isDependencyPath, } from "./function-bundle.js";
41
+ import { collectFunctionManifest, FunctionCollectError, } from "./function-collect.js";
42
+ const toPosix = (value) => value.split(sep).join("/");
43
+ /**
44
+ * Collected manifests, keyed by the BUILT BUNDLE they were collected from.
45
+ *
46
+ * The preflight pass needs a function's manifest to decide the #3187 read
47
+ * relaxation, and the push then needs the same manifest for the envelope. Two
48
+ * collections would run the tree's module scope twice in one command, so the
49
+ * result is memoized against `contentHash`: the same bytes always collect the
50
+ * same way, and a tree edited mid-command hashes differently and is collected
51
+ * again rather than served a stale answer.
52
+ */
53
+ const collectedManifests = new Map();
54
+ /**
55
+ * Collect one function's manifest, or answer from this command's memo.
56
+ *
57
+ * `FunctionCollectError` is translated to the push loop's one failure class by
58
+ * the callers, so a collect failure reads like any other build failure for
59
+ * that function and lands nothing.
60
+ */
61
+ export async function collectManifestForBundle(options) {
62
+ const memo = collectedManifests.get(options.contentHash);
63
+ if (memo)
64
+ return memo;
65
+ const collected = await collectFunctionManifest({
66
+ configDir: options.configDir,
67
+ entry: options.entry,
68
+ functionKey: options.functionKey,
69
+ });
70
+ collectedManifests.set(options.contentHash, collected);
71
+ return collected;
72
+ }
73
+ /**
74
+ * Build and collect one function file, for the preflight's grant decision.
75
+ *
76
+ * The relaxation is a statement about what the tree REGISTERS, so the preflight
77
+ * cannot decide it from the TOML alone (CR3187-001). Only the functions whose
78
+ * answer depends on it pay for this — see `functionNeedsManifest`.
79
+ */
80
+ export async function collectManifestForPreflight(options) {
81
+ const entry = String(options.tomlData?.function?.entry ?? "").trim();
82
+ if (!entry) {
83
+ throw new FunctionBuildError(`function '${options.functionKey}': \`entry\` is required — name the ` +
84
+ "TypeScript entry point, relative to the config tree root.");
85
+ }
86
+ const built = await buildFunctionBundle({
87
+ configDir: options.configDir,
88
+ entry,
89
+ functionKey: options.functionKey,
90
+ });
91
+ try {
92
+ return await collectManifestForBundle({
93
+ configDir: options.configDir,
94
+ entry: built.entry,
95
+ functionKey: options.functionKey,
96
+ contentHash: built.contentHash,
97
+ });
98
+ }
99
+ catch (error) {
100
+ if (error instanceof FunctionCollectError) {
101
+ throw new FunctionBuildError(error.message);
102
+ }
103
+ throw error;
104
+ }
105
+ }
106
+ /**
107
+ * Build everything the config-version route needs for one function file.
108
+ *
109
+ * Throws `FunctionBuildError` for a missing `entry`, a missing entry file, a
110
+ * build error, or an import that escapes the config tree — one class, so the
111
+ * push loop has one thing to report and pushes nothing for that function.
112
+ */
113
+ export async function buildFunctionConfigPush(options) {
114
+ const { configDir, functionKey, filePath, tomlData } = options;
115
+ const table = tomlData?.function ?? {};
116
+ const entry = String(table.entry ?? "").trim();
117
+ if (!entry) {
118
+ throw new FunctionBuildError(`function '${functionKey}': \`entry\` is required — name the TypeScript ` +
119
+ "entry point, relative to the config tree root.");
120
+ }
121
+ // #3181 — the trigger blocks, checked before the bundle is built so an
122
+ // author with a mistyped key does not wait on esbuild first. Reported as a
123
+ // `FunctionBuildError` so the push loop keeps its one failure class per
124
+ // function and lands every unrelated change in the tree.
125
+ try {
126
+ normalizeFunctionTriggers(table, { durable: table.durable === true });
127
+ }
128
+ catch (err) {
129
+ if (err instanceof TriggerDeclarationError) {
130
+ throw new FunctionBuildError(`function '${functionKey}': ${err.message}`);
131
+ }
132
+ throw err;
133
+ }
134
+ const built = await buildFunctionBundle({ configDir, entry, functionKey });
135
+ // #3187 — the manifest, collected by RUNNING the tree's module scope in a
136
+ // spawned, scrubbed child process (D3187-SO-006). Fail-closed: a push whose
137
+ // collect fails is refused naming the error, because the manifest is inside
138
+ // the envelope and "push now, collect later" would mean a different version.
139
+ let manifest = null;
140
+ try {
141
+ // Memoized against the built bundle: the preflight already collected this
142
+ // one when its grant decision needed the manifest, and running a tree's
143
+ // module scope twice per push is a side effect nobody asked for.
144
+ const collected = await collectManifestForBundle({
145
+ configDir,
146
+ entry: built.entry,
147
+ functionKey,
148
+ contentHash: built.contentHash,
149
+ });
150
+ manifest = Buffer.from(JSON.stringify(collected), "utf-8").toString("base64");
151
+ }
152
+ catch (error) {
153
+ if (error instanceof FunctionCollectError) {
154
+ throw new FunctionBuildError(error.message);
155
+ }
156
+ throw error;
157
+ }
158
+ // The AUTHORED bytes. Read from disk rather than re-serialized, so the round
159
+ // trip is byte-identical (F-009).
160
+ const authored = readFileSync(filePath);
161
+ const limits = normalizeLimits(table.limits);
162
+ const push = {
163
+ entry: built.entry,
164
+ toml: authored.toString("base64"),
165
+ sources: built.sources.map((s) => ({
166
+ path: s.path,
167
+ content: s.content.toString("base64"),
168
+ })),
169
+ bundle: built.bundle.toString("base64"),
170
+ contentHash: built.contentHash,
171
+ manifest,
172
+ envelopeHash: "",
173
+ durable: table.durable === true,
174
+ ...(limits ? { limits } : {}),
175
+ };
176
+ push.envelopeHash = functionEnvelopeHash({
177
+ schemaVersion: FUNCTION_ENVELOPE_SCHEMA_VERSION,
178
+ entry: push.entry,
179
+ toml: push.toml,
180
+ sources: push.sources,
181
+ bundle: push.bundle,
182
+ manifest: push.manifest,
183
+ });
184
+ return push;
185
+ }
186
+ /** `[function.limits]` as the server stores it, or undefined when absent. */
187
+ function normalizeLimits(value) {
188
+ if (value === undefined || value === null)
189
+ return undefined;
190
+ if (typeof value === "string") {
191
+ try {
192
+ const parsed = JSON.parse(value);
193
+ return parsed && typeof parsed === "object" ? parsed : undefined;
194
+ }
195
+ catch {
196
+ return undefined;
197
+ }
198
+ }
199
+ if (typeof value !== "object" || Array.isArray(value))
200
+ return undefined;
201
+ return value;
202
+ }
203
+ /**
204
+ * The create body. `functionKey` is attached here rather than spread from the
205
+ * table: the identity comes from the file name, exactly as it does for every
206
+ * other keyed type.
207
+ */
208
+ export function buildFunctionCreatePayload(functionKey, table) {
209
+ const payload = buildPayloadFromToml(SERVER_FUNCTION_TABLE, table ?? {}, {
210
+ mode: "create",
211
+ values: { description: tomlOwned },
212
+ });
213
+ dropUndefined(payload);
214
+ return { functionKey, ...payload };
215
+ }
216
+ /**
217
+ * The update body. The key is NOT re-sent — it is the function's claim on the
218
+ * app's single key namespace and the URL already names the row — and `status`
219
+ * is server-owned on the sixth carrying type as on the other five.
220
+ */
221
+ export function buildFunctionUpdatePayload(table) {
222
+ const payload = buildPayloadFromToml(SERVER_FUNCTION_TABLE, table ?? {}, {
223
+ mode: "update",
224
+ values: { description: tomlOwned },
225
+ });
226
+ dropUndefined(payload);
227
+ return payload;
228
+ }
229
+ function dropUndefined(payload) {
230
+ for (const key of Object.keys(payload)) {
231
+ if (payload[key] === undefined)
232
+ delete payload[key];
233
+ }
234
+ }
235
+ /**
236
+ * The canonical TOML for a function with no stored authored bytes — a function
237
+ * created through the API that has never had code pushed. When bytes exist,
238
+ * pull writes THOSE; this is the fallback that still produces a pushable file.
239
+ */
240
+ export function serializeFunction(record, active) {
241
+ const table = {
242
+ key: record.functionKey,
243
+ ...projectRecordToToml(SERVER_FUNCTION_TABLE, record),
244
+ };
245
+ if (active?.entry)
246
+ table.entry = active.entry;
247
+ if (active?.durable === true)
248
+ table.durable = true;
249
+ // #3182 — the grants are version-carried and server-derived, so the fallback
250
+ // file has to state them or a push of it would silently drop the function's
251
+ // authority.
252
+ if (Array.isArray(active?.capabilities) && active.capabilities.length > 0) {
253
+ table.capabilities = [...active.capabilities].sort();
254
+ }
255
+ if (active?.unscopedReads === true)
256
+ table.unscopedReads = true;
257
+ const limits = normalizeLimits(active?.limits);
258
+ if (limits && Object.keys(limits).length > 0)
259
+ table.limits = limits;
260
+ for (const key of Object.keys(table)) {
261
+ if (table[key] === undefined || table[key] === null)
262
+ delete table[key];
263
+ }
264
+ return stringifyConfigToml({ function: table });
265
+ }
266
+ /**
267
+ * The tree-relative spelling of `entry` that push actually sends.
268
+ *
269
+ * The build normalizes the authored value (`resolve` + `relative`), and the
270
+ * server stores what it is sent, so a valid `./functions/greet/index.ts`
271
+ * arrives as `functions/greet/index.ts`. Comparing the authored spelling
272
+ * against the stored one would report a function as Modified the instant it
273
+ * was pushed and re-send the same update forever, so both sides are read
274
+ * through the same normalization here.
275
+ *
276
+ * Lexical only: an in-tree SYMLINK spelling is resolved by the build and not
277
+ * by this, which is the one remaining way for the two to differ.
278
+ */
279
+ function canonicalEntry(value) {
280
+ const raw = toPosix(String(value ?? "").trim());
281
+ if (!raw)
282
+ return null;
283
+ const normalized = posixPath.normalize(raw).replace(/\/+$/, "");
284
+ return normalized || null;
285
+ }
286
+ /**
287
+ * The entity both sides of `config diff` are projected onto: the header's
288
+ * authored fields plus the three keys the VERSION carries. Stated once so a
289
+ * local file and a server record cannot be read into different shapes.
290
+ *
291
+ * Text the server rewrites on the way in is read the same way it will come
292
+ * back (the DSO-003 rule the webhook comparator states): `access` is stored
293
+ * trimmed and `entry` normalized, so an authored value that differs only in
294
+ * that respect is not permanent drift.
295
+ */
296
+ export function functionDiffEntity(tomlData) {
297
+ const table = tomlData?.function ?? {};
298
+ const limits = normalizeLimits(table.limits);
299
+ const access = typeof table.access === "string" && table.access.trim()
300
+ ? table.access.trim()
301
+ : null;
302
+ return {
303
+ description: table.description ?? null,
304
+ runAs: table.runAs ?? "caller",
305
+ access,
306
+ inputSchema: table.inputSchema ?? null,
307
+ outputSchema: table.outputSchema ?? null,
308
+ entry: canonicalEntry(table.entry),
309
+ durable: table.durable === true,
310
+ limits: limits && Object.keys(limits).length > 0 ? limits : null,
311
+ // #3181 — normalized locally from the SAME rules the server applies, so a
312
+ // trigger edit reads as a named field rather than only as the code-axis
313
+ // `envelopeHash` change it also is. A file whose triggers do not parse is
314
+ // reported as drift rather than throwing out of a read-only diff: push is
315
+ // where the refusal belongs.
316
+ triggers: safeTriggers(table),
317
+ // #3182 — sorted on both sides: the row stores a SET, which has no order,
318
+ // so comparing authored order against it would report permanent drift.
319
+ capabilities: Array.isArray(table.capabilities)
320
+ ? [...new Set(table.capabilities.map((c) => String(c)))].sort()
321
+ : [],
322
+ unscopedReads: table.unscopedReads === true,
323
+ };
324
+ }
325
+ function safeTriggers(table) {
326
+ try {
327
+ return normalizeFunctionTriggers(table, { durable: table?.durable === true });
328
+ }
329
+ catch {
330
+ return null;
331
+ }
332
+ }
333
+ /**
334
+ * Why a stored source path may not be written, or null.
335
+ *
336
+ * The same rule the server applies on the way in, applied again on the way out:
337
+ * the file is written to a developer's disk from a path the SERVER chose, so a
338
+ * second check here is the one that matters.
339
+ */
340
+ export function unsafePulledPath(path) {
341
+ const raw = toPosix(String(path ?? ""));
342
+ if (!raw)
343
+ return "a stored source path is empty";
344
+ if (raw.startsWith("/") || /^[a-zA-Z]:\//.test(raw)) {
345
+ return `refused stored source path '${raw}': absolute paths are never written`;
346
+ }
347
+ if (raw.split("/").includes("..")) {
348
+ return `refused stored source path '${raw}': it normalizes outside the config tree`;
349
+ }
350
+ if (isDependencyPath(raw)) {
351
+ return `refused stored source path '${raw}': node_modules is never authored source`;
352
+ }
353
+ return null;
354
+ }
355
+ /**
356
+ * Plan the files `config pull` writes for one function: the authored TOML at
357
+ * `functions/<key>.toml`, and each stored source at its own path.
358
+ *
359
+ * Pure — the caller applies it — so the refusal rules are testable without a
360
+ * server and without touching a disk.
361
+ */
362
+ export function planFunctionPull(options) {
363
+ const { configDir, functionKey, envelope } = options;
364
+ const root = resolve(configDir);
365
+ const files = [];
366
+ const sourcePaths = [];
367
+ const refusals = [];
368
+ if (typeof envelope?.toml === "string") {
369
+ const relativePath = `functions/${functionKey}.toml`;
370
+ files.push({
371
+ relative: relativePath,
372
+ absolute: join(root, "functions", `${functionKey}.toml`),
373
+ content: Buffer.from(envelope.toml, "base64"),
374
+ });
375
+ }
376
+ for (const source of envelope?.sources ?? []) {
377
+ const path = toPosix(String(source?.path ?? ""));
378
+ const refusal = unsafePulledPath(path);
379
+ if (refusal) {
380
+ refusals.push(refusal);
381
+ continue;
382
+ }
383
+ const absolute = resolve(root, path);
384
+ // Belt and braces: the string rules above state the contract, this catches
385
+ // a spelling they did not anticipate on a platform they were not written on.
386
+ const rel = relative(root, absolute);
387
+ if (rel.startsWith("..") || isAbsolute(rel)) {
388
+ refusals.push(`refused stored source path '${path}': it normalizes outside the config tree`);
389
+ continue;
390
+ }
391
+ files.push({
392
+ relative: path,
393
+ absolute,
394
+ content: Buffer.from(String(source?.content ?? ""), "base64"),
395
+ });
396
+ sourcePaths.push(path);
397
+ }
398
+ return { configDir: root, functionKey, files, sourcePaths, refusals };
399
+ }
400
+ /**
401
+ * Why a destination may not be written even though its stored path is
402
+ * tree-relative, or null.
403
+ *
404
+ * `planFunctionPull`'s rules are lexical, and a lexical rule cannot see a
405
+ * SYMLINK: `functions/shared` pointing at `/etc` makes `functions/shared/x`
406
+ * normalize inside the tree and land outside it. So the last check before the
407
+ * write is against the real path — the deepest directory that already exists
408
+ * is resolved and must still be inside the real tree root, and an existing
409
+ * destination that is itself a symlink is refused rather than written through.
410
+ */
411
+ function unsafeDestination(realRoot, absolute) {
412
+ const contained = (path) => path === realRoot || path.startsWith(realRoot + sep);
413
+ let dir = dirname(absolute);
414
+ while (!existsSync(dir)) {
415
+ const parent = dirname(dir);
416
+ if (parent === dir)
417
+ break;
418
+ dir = parent;
419
+ }
420
+ let realDir;
421
+ try {
422
+ realDir = realpathSync(dir);
423
+ }
424
+ catch {
425
+ return `refused writing '${absolute}': its directory could not be resolved`;
426
+ }
427
+ if (!contained(realDir)) {
428
+ return (`refused writing '${absolute}': a symlinked directory takes it outside ` +
429
+ "the config tree");
430
+ }
431
+ try {
432
+ if (lstatSync(absolute).isSymbolicLink()) {
433
+ return (`refused writing '${absolute}': the destination is a symlink, and a ` +
434
+ "pull writes files, never through links");
435
+ }
436
+ }
437
+ catch {
438
+ /* the destination does not exist yet — the normal case */
439
+ }
440
+ return null;
441
+ }
442
+ /**
443
+ * Write a plan's files, creating the directories they need.
444
+ *
445
+ * Returns what was written and what was refused; a refusal is reported by the
446
+ * caller and keeps the file out of the sync state, so prune never claims to
447
+ * own a path this pull did not write.
448
+ */
449
+ export function applyFunctionPull(plan) {
450
+ const outcome = { writtenSources: [], refusals: [] };
451
+ let realRoot;
452
+ try {
453
+ realRoot = realpathSync(plan.configDir);
454
+ }
455
+ catch {
456
+ realRoot = plan.configDir;
457
+ }
458
+ const sourcePaths = new Set(plan.sourcePaths);
459
+ for (const file of plan.files) {
460
+ const refusal = unsafeDestination(realRoot, file.absolute);
461
+ if (refusal) {
462
+ outcome.refusals.push(refusal);
463
+ continue;
464
+ }
465
+ const dir = dirname(file.absolute);
466
+ if (!existsSync(dir))
467
+ mkdirSync(dir, { recursive: true });
468
+ writeFileSync(file.absolute, file.content);
469
+ if (sourcePaths.has(file.relative))
470
+ outcome.writtenSources.push(file.relative);
471
+ }
472
+ return outcome;
473
+ }
474
+ //# sourceMappingURL=function-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function-sync.js","sourceRoot":"","sources":["../../../src/lib/function-sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * `[function.triggers.*]`, read and checked locally (#3181).
3
+ *
4
+ * The SERVER is the authority: it derives the declaration from the TOML bytes
5
+ * inside the version envelope and validates it there, so a direct API push
6
+ * cannot ship a trigger the authored file does not declare (D3181-005). What
7
+ * this file buys is the other half of the `entry` dual-validation shape #3179
8
+ * established — an author who mistypes a key hears about it against their own
9
+ * file, by name, before a request is made.
10
+ *
11
+ * It is deliberately a VENDORED copy of the shape rules in
12
+ * `src/server-functions/trigger-declaration.ts` rather than an import: the CLI
13
+ * compiles with `rootDir: "."` and cannot reach the worker sources, which is
14
+ * the same constraint that made `generated-config-surfaces.ts` a vendored
15
+ * artifact. `cli/tests/unit/function-triggers-3181.test.ts` drives both copies
16
+ * from one fixture list so they cannot drift apart silently.
17
+ *
18
+ * Everything that needs the APP's state stays on the server: whether a
19
+ * referenced secret exists, whether the scheme-specific config is valid under
20
+ * this environment's JWKS policy, whether the app is at its webhook or cron
21
+ * cap, whether a standalone webhook holds the key. A local copy of those would
22
+ * be a preflight that can give a false all-clear.
23
+ */
24
+ export interface WebhookTriggerDeclaration {
25
+ verificationScheme: string;
26
+ signingSecret?: string;
27
+ toleranceSeconds?: number;
28
+ deduplicationEnabled?: boolean;
29
+ deduplicationWindowMs?: number;
30
+ maxBodyBytes?: number;
31
+ secretGracePeriodMs?: number;
32
+ verification?: Record<string, unknown>;
33
+ }
34
+ export interface CronTriggerDeclaration {
35
+ name: string;
36
+ cron: string;
37
+ timezone?: string;
38
+ overlapPolicy?: string;
39
+ rootInput?: unknown;
40
+ }
41
+ export interface TriggerDeclaration {
42
+ webhook: WebhookTriggerDeclaration | null;
43
+ cron: CronTriggerDeclaration[];
44
+ }
45
+ export declare const MAX_CRON_TRIGGERS_PER_FUNCTION = 10;
46
+ export declare class TriggerDeclarationError extends Error {
47
+ }
48
+ /**
49
+ * Normalize (and check) the `triggers` table of a parsed `[function]` table.
50
+ * Returns null when nothing is declared, so a caller can skip the work.
51
+ */
52
+ export declare function normalizeFunctionTriggers(functionTable: any, options?: {
53
+ durable?: boolean;
54
+ }): TriggerDeclaration | null;