@lunora/config 1.0.0-alpha.192 → 1.0.0-alpha.194

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 (40) hide show
  1. package/dist/cloudflare/index.d.mts +17 -13
  2. package/dist/cloudflare/index.d.ts +17 -13
  3. package/dist/cloudflare/index.mjs +1 -1
  4. package/dist/index.d.mts +15 -7
  5. package/dist/index.d.ts +15 -7
  6. package/dist/index.mjs +1 -1
  7. package/dist/packem_shared/AGENT_RULES_DIR-C54Ta_vz.mjs +1 -0
  8. package/dist/packem_shared/{BINDING_MANIFEST_VERSION-Cd00jVOf.mjs → BINDING_MANIFEST_VERSION-B8dwEKLn.mjs} +1 -1
  9. package/dist/packem_shared/CLOUDFLARE_DRIVER-Ci9oJMYb.mjs +1 -0
  10. package/dist/packem_shared/COMPOSED_WORKER_ENTRY-CbtPPFQK.mjs +1 -0
  11. package/dist/packem_shared/DEFAULT_DEPLOY_TARGET-B-e9mqgX.mjs +1 -0
  12. package/dist/packem_shared/{LUNORA_CONFIG_FILE-DFoqHCyP.mjs → LUNORA_CONFIG_FILE-D0F9TWxc.mjs} +1 -1
  13. package/dist/packem_shared/{PACKAGE_SECRETS_REGISTRY-CYrVk48t.mjs → PACKAGE_SECRETS_REGISTRY-De7gLGIy.mjs} +1 -1
  14. package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-0QiGKazX.mjs +1 -0
  15. package/dist/packem_shared/{REQUIRED_COMPATIBILITY_DATE-iWKnSx2C.mjs → REQUIRED_COMPATIBILITY_DATE-vJI8hq20.mjs} +1 -1
  16. package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-Dbt0faMd.mjs +1 -0
  17. package/dist/packem_shared/addArgsFor-CWb4cPij.mjs +1 -0
  18. package/dist/packem_shared/{buildPackageSecretsBlock-8PWr25wv.mjs → buildPackageSecretsBlock-yv9mjKEW.mjs} +1 -1
  19. package/dist/packem_shared/collectExportGaps-BtNtwL7x.mjs +1 -0
  20. package/dist/packem_shared/{collectWranglerSecretVariables-DSTHPYsC.mjs → collectWranglerSecretVariables-D-usPfT8.mjs} +1 -1
  21. package/dist/packem_shared/package-secrets-registry-DvtTiK4b.mjs +1 -0
  22. package/dist/packem_shared/{runPostCodegenHook-BF3XTBFz.mjs → runPostCodegenHook-CVrOTiGB.mjs} +1 -1
  23. package/dist/packem_shared/{schema-info.d-BRnrGpR1.d.ts → schema-info.d-BuD84EiT.d.mts} +31 -120
  24. package/dist/packem_shared/{schema-info.d-BRnrGpR1.d.mts → schema-info.d-BuD84EiT.d.ts} +31 -120
  25. package/dist/packem_shared/wranglerToAlchemy-SDoS_XY0.mjs +6 -0
  26. package/dist/packem_shared/write-atomic-9d9xs5ON.mjs +1 -0
  27. package/dist/studio-host/index.mjs +1 -1
  28. package/package.json +5 -5
  29. package/dist/packem_shared/AGENT_RULES_DIR-3-Sx1gHU.mjs +0 -1
  30. package/dist/packem_shared/CLOUDFLARE_DRIVER-CoS6u6zD.mjs +0 -1
  31. package/dist/packem_shared/COMPOSED_WORKER_ENTRY-CAPCs3GJ.mjs +0 -1
  32. package/dist/packem_shared/DEFAULT_DEPLOY_TARGET-De4Ps8C8.mjs +0 -1
  33. package/dist/packem_shared/POLICY_SCAFFOLD_ENDPOINT-DL4UFAeK.mjs +0 -1
  34. package/dist/packem_shared/SCHEMA_EDIT_ENDPOINT-IkAx-ScX.mjs +0 -1
  35. package/dist/packem_shared/addArgsFor-B4D4zvM0.mjs +0 -1
  36. package/dist/packem_shared/cloudflare-driver-CWf_lB-q.mjs +0 -1
  37. package/dist/packem_shared/collectExportGaps-CHgJxlgR.mjs +0 -1
  38. package/dist/packem_shared/package-secrets-registry-CFZ5bA8L.mjs +0 -1
  39. package/dist/packem_shared/wranglerToAlchemy-CX9nCwtu.mjs +0 -6
  40. package/dist/packem_shared/write-atomic-D88PwWJc.mjs +0 -1
@@ -1,26 +1,10 @@
1
1
  import { AgentIR, ContainerIR, QueueIR, WorkflowIR } from '@lunora/codegen';
2
2
  /**
3
- * `DeployDriver` — the provider-neutral seam between what an app needs and
4
- * how a host provides it (plan 114, §5.3).
3
+ * `DeployDriver` — the provider-neutral seam between a Lunora command and the
4
+ * host CLI that carries it out (plan 114, §5.3).
5
5
  *
6
- * Configuration inference is two jobs welded together today. Deciding that an
7
- * app needs a shard namespace, a queue, and an object-storage bucket is
8
- * host-neutral: it falls out of the app's schema and imports, and every target
9
- * reaches the same conclusion. Writing `durable_objects.bindings[]` into a
10
- * `wrangler.jsonc` is not — it is one host's encoding of that conclusion.
11
- *
12
- * The split here names both halves. {@link ResourceGraph} is the neutral answer
13
- * to "what does this app need?"; a {@link DeployDriver} turns that graph into
14
- * one host's configuration and owns the host's toolchain surface. A second
15
- * target implements the driver rather than forking the inference.
16
- *
17
- * Only the Cloudflare driver exists today (`cloudflare-driver.ts`), and it is
18
- * deliberately thin: it delegates to the same `inferLunoraBindings` /
19
- * `reconcileWrangler*` functions the CLI called directly before, so routing a
20
- * command through the driver is behavior-preserving by construction.
21
- *
22
- * The second half is the **toolchain surface**: which command a host runs to
23
- * deploy, serve, tail, or set a secret. A driver only *describes* that command
6
+ * The seam is the **toolchain surface**: which command a host runs to deploy,
7
+ * serve, tail, or set a secret. A driver only *describes* that command
24
8
  * ({@link ToolchainCommand}); it never spawns. The CLI keeps ownership of
25
9
  * running it — package-manager resolution (`pnpm exec` / `npx --` / `bun x`)
26
10
  * and the injected spawner its tests substitute — so the driver stays free of
@@ -29,65 +13,25 @@ import { AgentIR, ContainerIR, QueueIR, WorkflowIR } from '@lunora/codegen';
29
13
  * Each request type below is deliberately neutral: `preview`, `environment`,
30
14
  * `temporary` are concepts, not wrangler flags. A second host maps the same
31
15
  * request onto its own CLI without the caller changing.
16
+ *
17
+ * Two drivers are registered: Cloudflare (`cloudflare/cloudflare-driver.ts`),
18
+ * which is the only one with a toolchain, and Node (`node/node-driver.ts`),
19
+ * which has none — it is a codegen target, and `lunora deploy` / `lunora dev`
20
+ * refuse it at selection.
21
+ *
22
+ * **What this seam deliberately does NOT carry: configuration inference.** It
23
+ * used to, through an `infer`/`provision` pair over a provider-neutral
24
+ * `ResourceGraph`. Nothing ever called either one — every consumer reads
25
+ * `.toolchain` or just validates the target — and the arm rotted in place: the
26
+ * Node driver was *only* `infer` + `provision`, so its report of what that
27
+ * target cannot serve (containers, undispatched crons) could not reach an
28
+ * operator however wrong the app was. The reason it never got wired is worth
29
+ * keeping: writing real host configuration needs the host's own encodings —
30
+ * binding names, DO class wiring, migration tags — which a neutral graph
31
+ * necessarily discards, so `provision` re-derived them anyway and the graph was
32
+ * decorative. A second target that needs to share inference should grow the
33
+ * seam back with a caller attached, and with an encoding escape hatch.
32
34
  */
33
- /** A durable, single-writer shard namespace (a Durable Object namespace on Cloudflare). */
34
- interface ShardNamespaceResource {
35
- /** The implementing class name the host binds to. */
36
- className: string;
37
- /** Whether the worker entry re-exports the class — an unexported class cannot be bound. */
38
- exported: boolean;
39
- /** The binding name the app reaches it through (e.g. `SHARD`). */
40
- name: string;
41
- }
42
- /** A named resource the app declares and the host must provision (queue, workflow, container). */
43
- interface NamedResource {
44
- /** Whether the declaration is re-exported from the worker entry, where that applies. */
45
- exported?: boolean;
46
- /** The declared name. */
47
- name: string;
48
- }
49
- /**
50
- * The provider-neutral statement of what an app needs, derived from its schema
51
- * and imports. Every field is a *requirement*, not a host encoding: a driver
52
- * decides what `objectStorage: true` means for its target.
53
- */
54
- interface ResourceGraph {
55
- /** Container images the app declares. */
56
- containers: ReadonlyArray<NamedResource>;
57
- /** Cron expressions the app schedules. */
58
- crons: ReadonlyArray<string>;
59
- /**
60
- * The app declares a `.global()` table, so it needs a replicated SQL store
61
- * (D1 on Cloudflare; Aurora/RDS elsewhere).
62
- */
63
- globalDatabase: boolean;
64
- /** The app reads or writes a key-value store. */
65
- keyValueStore: boolean;
66
- /** The app needs object storage (R2 on Cloudflare; S3-compatible elsewhere). */
67
- objectStorage: boolean;
68
- /** Queues the app declares. */
69
- queues: ReadonlyArray<NamedResource>;
70
- /** Shard namespaces the app needs. */
71
- shardNamespaces: ReadonlyArray<ShardNamespaceResource>;
72
- /**
73
- * Human-readable provenance for each requirement — why inference concluded
74
- * the app needs it. Surfaced in CLI logs; never load-bearing.
75
- */
76
- signals: ReadonlyArray<string>;
77
- /** Workflows the app declares. */
78
- workflows: ReadonlyArray<NamedResource>;
79
- }
80
- /** The outcome of writing a {@link ResourceGraph} into a host's configuration. */
81
- interface ProvisionResult {
82
- /** Short labels for each resource written, for logging. */
83
- added: ReadonlyArray<string>;
84
- /** Whether the host's configuration file was rewritten. */
85
- changed: boolean;
86
- /** Resolved configuration path, when the host has one. */
87
- configPath?: string;
88
- /** Non-fatal hints for requirements the driver cannot auto-provision. */
89
- warnings: ReadonlyArray<string>;
90
- }
91
35
  /**
92
36
  * A host CLI invocation, described but not run.
93
37
  *
@@ -150,9 +94,9 @@ interface SecretRequest {
150
94
  temporary?: boolean;
151
95
  }
152
96
  /**
153
- * The host's command-line surface. Optional as a whole: a host with no CLI (a
154
- * hypothetical API-driven target) implements `infer`/`provision` only, and the
155
- * caller falls back to its own handling.
97
+ * The host's command-line surface. Optional as a whole: a host with no vendor
98
+ * CLI (the Node target; a hypothetical API-driven one) declares none, and
99
+ * `isRunnableTarget` refuses it for the commands that would have to shell out.
156
100
  */
157
101
  interface DriverToolchain {
158
102
  /** The command that deploys the app. */
@@ -166,49 +110,12 @@ interface DriverToolchain {
166
110
  /** The command that tails live logs. */
167
111
  tail: (request: TailRequest) => ToolchainCommand;
168
112
  }
169
- /** Options every driver method receives. */
170
- interface DriverContext {
171
- /** Cron expressions codegen discovered, threaded in because they come from the app's code rather than its config. */
172
- crons?: ReadonlyArray<string>;
173
- /** Project root containing the `lunora/` directory. */
174
- projectRoot: string;
175
- }
176
- /**
177
- * A deploy target's implementation: report what the app needs, and encode it
178
- * into that host's configuration.
179
- *
180
- * **Why `provision` does not take a {@link ResourceGraph}.** The obvious
181
- * signature is `provision(graph, context)`, and it is wrong. Writing real host
182
- * configuration needs the host's own encodings — binding names, DO class
183
- * wiring, migration tags — which the neutral graph deliberately discards. A
184
- * driver handed only the graph would have to re-derive them, so passing it
185
- * would be decorative. `infer` is therefore the *reporting* surface (a portable
186
- * picture of the app's requirements, for logs, diagnostics, and cross-target
187
- * comparison) and `provision` is the *doing* surface, which owns its own
188
- * inference end-to-end.
189
- *
190
- * That asymmetry is a genuine finding about this seam, not a shortcut: it says
191
- * the neutral graph is not a sufficient intermediate representation for config
192
- * emission. If a future target needs one, the graph must grow a host-extension
193
- * escape hatch rather than pretend it already carries the detail.
194
- */
113
+ /** A deploy target's implementation: an identity the registry resolves, and the host CLI surface (if any) behind it. */
195
114
  interface DeployDriver {
196
115
  /** The target id this driver serves (`"cloudflare"`, …) — matches codegen's `target`. */
197
116
  readonly id: string;
198
- /**
199
- * Read the app and report what it needs, in provider-neutral terms. Pure
200
- * with respect to the project: it never writes configuration.
201
- */
202
- infer: (context: DriverContext) => Promise<ResourceGraph>;
203
117
  /** Human-readable target name, for logs. */
204
118
  readonly name: string;
205
- /**
206
- * Write the app's requirements into the host's configuration, adding what is
207
- * missing and leaving existing entries alone. Must be idempotent:
208
- * provisioning an already-provisioned project reports `changed: false`, and
209
- * must fold a failed step into a warning rather than throwing.
210
- */
211
- provision: (context: DriverContext) => Promise<ProvisionResult>;
212
119
  /**
213
120
  * The host's command-line surface, or `undefined` for a host that has none.
214
121
  * Pure: these build argv, they never spawn.
@@ -294,10 +201,14 @@ interface InferredBindings {
294
201
  usesKv: boolean;
295
202
  /** `@lunora/mail` is imported (Resend API key must be set in `.dev.vars`; no binding). */
296
203
  usesMail: boolean;
204
+ /** `@lunora/notify` is imported (Web Push needs VAPID/FCM secrets in `.dev.vars`; no binding). */
205
+ usesNotify: boolean;
297
206
  /** `@lunora/payment` is imported (provider secrets must be set in `.dev.vars`; no binding). */
298
207
  usesPayment: boolean;
299
208
  /** `ctx.pipelines` is used (binding needs an un-mintable remote pipeline name; hint-only). */
300
209
  usesPipelines: boolean;
210
+ /** `ctx.r2sql` is used (needs the `R2_SQL_*` secrets in `.dev.vars`; no binding). */
211
+ usesR2sql: boolean;
301
212
  /** `@lunora/scheduler` is imported. */
302
213
  usesScheduler: boolean;
303
214
  /** `@lunora/storage` is imported (R2 bucket binding name is user-defined). */
@@ -387,4 +298,4 @@ interface DiscoverSchemaInfoResult {
387
298
  * parse failure is a warning (validator) or simply ignorable (inference).
388
299
  */
389
300
  declare const discoverSchemaInfo: (projectRoot: string, schemaDirectory: string) => DiscoverSchemaInfoResult;
390
- export { COMPOSED_WORKER_ENTRY as C, DeployDriver as D, InferredBindings as I, NamedResource as N, ProvisionResult as P, ResourceGraph as R, SchemaInfo as S, TailRequest as T, DeployRequest as a, DevRequest as b, DiscoverSchemaInfoResult as c, DriverContext as d, DriverToolchain as e, InferOptions as f, InferredAgent as g, InferredContainer as h, InferredWorkflow as i, SecretRequest as j, ShardNamespaceResource as k, ToolchainCommand as l, discoverSchemaInfo as m, inferLunoraBindings as n, packageNamesFromBindings as p };
301
+ export { COMPOSED_WORKER_ENTRY as C, DeployDriver as D, InferredBindings as I, SchemaInfo as S, TailRequest as T, DeployRequest as a, DevRequest as b, DiscoverSchemaInfoResult as c, DriverToolchain as d, InferOptions as e, InferredAgent as f, InferredContainer as g, InferredWorkflow as h, SecretRequest as i, ToolchainCommand as j, discoverSchemaInfo as k, inferLunoraBindings as l, packageNamesFromBindings as p };
@@ -1,26 +1,10 @@
1
1
  import { AgentIR, ContainerIR, QueueIR, WorkflowIR } from '@lunora/codegen';
2
2
  /**
3
- * `DeployDriver` — the provider-neutral seam between what an app needs and
4
- * how a host provides it (plan 114, §5.3).
3
+ * `DeployDriver` — the provider-neutral seam between a Lunora command and the
4
+ * host CLI that carries it out (plan 114, §5.3).
5
5
  *
6
- * Configuration inference is two jobs welded together today. Deciding that an
7
- * app needs a shard namespace, a queue, and an object-storage bucket is
8
- * host-neutral: it falls out of the app's schema and imports, and every target
9
- * reaches the same conclusion. Writing `durable_objects.bindings[]` into a
10
- * `wrangler.jsonc` is not — it is one host's encoding of that conclusion.
11
- *
12
- * The split here names both halves. {@link ResourceGraph} is the neutral answer
13
- * to "what does this app need?"; a {@link DeployDriver} turns that graph into
14
- * one host's configuration and owns the host's toolchain surface. A second
15
- * target implements the driver rather than forking the inference.
16
- *
17
- * Only the Cloudflare driver exists today (`cloudflare-driver.ts`), and it is
18
- * deliberately thin: it delegates to the same `inferLunoraBindings` /
19
- * `reconcileWrangler*` functions the CLI called directly before, so routing a
20
- * command through the driver is behavior-preserving by construction.
21
- *
22
- * The second half is the **toolchain surface**: which command a host runs to
23
- * deploy, serve, tail, or set a secret. A driver only *describes* that command
6
+ * The seam is the **toolchain surface**: which command a host runs to deploy,
7
+ * serve, tail, or set a secret. A driver only *describes* that command
24
8
  * ({@link ToolchainCommand}); it never spawns. The CLI keeps ownership of
25
9
  * running it — package-manager resolution (`pnpm exec` / `npx --` / `bun x`)
26
10
  * and the injected spawner its tests substitute — so the driver stays free of
@@ -29,65 +13,25 @@ import { AgentIR, ContainerIR, QueueIR, WorkflowIR } from '@lunora/codegen';
29
13
  * Each request type below is deliberately neutral: `preview`, `environment`,
30
14
  * `temporary` are concepts, not wrangler flags. A second host maps the same
31
15
  * request onto its own CLI without the caller changing.
16
+ *
17
+ * Two drivers are registered: Cloudflare (`cloudflare/cloudflare-driver.ts`),
18
+ * which is the only one with a toolchain, and Node (`node/node-driver.ts`),
19
+ * which has none — it is a codegen target, and `lunora deploy` / `lunora dev`
20
+ * refuse it at selection.
21
+ *
22
+ * **What this seam deliberately does NOT carry: configuration inference.** It
23
+ * used to, through an `infer`/`provision` pair over a provider-neutral
24
+ * `ResourceGraph`. Nothing ever called either one — every consumer reads
25
+ * `.toolchain` or just validates the target — and the arm rotted in place: the
26
+ * Node driver was *only* `infer` + `provision`, so its report of what that
27
+ * target cannot serve (containers, undispatched crons) could not reach an
28
+ * operator however wrong the app was. The reason it never got wired is worth
29
+ * keeping: writing real host configuration needs the host's own encodings —
30
+ * binding names, DO class wiring, migration tags — which a neutral graph
31
+ * necessarily discards, so `provision` re-derived them anyway and the graph was
32
+ * decorative. A second target that needs to share inference should grow the
33
+ * seam back with a caller attached, and with an encoding escape hatch.
32
34
  */
33
- /** A durable, single-writer shard namespace (a Durable Object namespace on Cloudflare). */
34
- interface ShardNamespaceResource {
35
- /** The implementing class name the host binds to. */
36
- className: string;
37
- /** Whether the worker entry re-exports the class — an unexported class cannot be bound. */
38
- exported: boolean;
39
- /** The binding name the app reaches it through (e.g. `SHARD`). */
40
- name: string;
41
- }
42
- /** A named resource the app declares and the host must provision (queue, workflow, container). */
43
- interface NamedResource {
44
- /** Whether the declaration is re-exported from the worker entry, where that applies. */
45
- exported?: boolean;
46
- /** The declared name. */
47
- name: string;
48
- }
49
- /**
50
- * The provider-neutral statement of what an app needs, derived from its schema
51
- * and imports. Every field is a *requirement*, not a host encoding: a driver
52
- * decides what `objectStorage: true` means for its target.
53
- */
54
- interface ResourceGraph {
55
- /** Container images the app declares. */
56
- containers: ReadonlyArray<NamedResource>;
57
- /** Cron expressions the app schedules. */
58
- crons: ReadonlyArray<string>;
59
- /**
60
- * The app declares a `.global()` table, so it needs a replicated SQL store
61
- * (D1 on Cloudflare; Aurora/RDS elsewhere).
62
- */
63
- globalDatabase: boolean;
64
- /** The app reads or writes a key-value store. */
65
- keyValueStore: boolean;
66
- /** The app needs object storage (R2 on Cloudflare; S3-compatible elsewhere). */
67
- objectStorage: boolean;
68
- /** Queues the app declares. */
69
- queues: ReadonlyArray<NamedResource>;
70
- /** Shard namespaces the app needs. */
71
- shardNamespaces: ReadonlyArray<ShardNamespaceResource>;
72
- /**
73
- * Human-readable provenance for each requirement — why inference concluded
74
- * the app needs it. Surfaced in CLI logs; never load-bearing.
75
- */
76
- signals: ReadonlyArray<string>;
77
- /** Workflows the app declares. */
78
- workflows: ReadonlyArray<NamedResource>;
79
- }
80
- /** The outcome of writing a {@link ResourceGraph} into a host's configuration. */
81
- interface ProvisionResult {
82
- /** Short labels for each resource written, for logging. */
83
- added: ReadonlyArray<string>;
84
- /** Whether the host's configuration file was rewritten. */
85
- changed: boolean;
86
- /** Resolved configuration path, when the host has one. */
87
- configPath?: string;
88
- /** Non-fatal hints for requirements the driver cannot auto-provision. */
89
- warnings: ReadonlyArray<string>;
90
- }
91
35
  /**
92
36
  * A host CLI invocation, described but not run.
93
37
  *
@@ -150,9 +94,9 @@ interface SecretRequest {
150
94
  temporary?: boolean;
151
95
  }
152
96
  /**
153
- * The host's command-line surface. Optional as a whole: a host with no CLI (a
154
- * hypothetical API-driven target) implements `infer`/`provision` only, and the
155
- * caller falls back to its own handling.
97
+ * The host's command-line surface. Optional as a whole: a host with no vendor
98
+ * CLI (the Node target; a hypothetical API-driven one) declares none, and
99
+ * `isRunnableTarget` refuses it for the commands that would have to shell out.
156
100
  */
157
101
  interface DriverToolchain {
158
102
  /** The command that deploys the app. */
@@ -166,49 +110,12 @@ interface DriverToolchain {
166
110
  /** The command that tails live logs. */
167
111
  tail: (request: TailRequest) => ToolchainCommand;
168
112
  }
169
- /** Options every driver method receives. */
170
- interface DriverContext {
171
- /** Cron expressions codegen discovered, threaded in because they come from the app's code rather than its config. */
172
- crons?: ReadonlyArray<string>;
173
- /** Project root containing the `lunora/` directory. */
174
- projectRoot: string;
175
- }
176
- /**
177
- * A deploy target's implementation: report what the app needs, and encode it
178
- * into that host's configuration.
179
- *
180
- * **Why `provision` does not take a {@link ResourceGraph}.** The obvious
181
- * signature is `provision(graph, context)`, and it is wrong. Writing real host
182
- * configuration needs the host's own encodings — binding names, DO class
183
- * wiring, migration tags — which the neutral graph deliberately discards. A
184
- * driver handed only the graph would have to re-derive them, so passing it
185
- * would be decorative. `infer` is therefore the *reporting* surface (a portable
186
- * picture of the app's requirements, for logs, diagnostics, and cross-target
187
- * comparison) and `provision` is the *doing* surface, which owns its own
188
- * inference end-to-end.
189
- *
190
- * That asymmetry is a genuine finding about this seam, not a shortcut: it says
191
- * the neutral graph is not a sufficient intermediate representation for config
192
- * emission. If a future target needs one, the graph must grow a host-extension
193
- * escape hatch rather than pretend it already carries the detail.
194
- */
113
+ /** A deploy target's implementation: an identity the registry resolves, and the host CLI surface (if any) behind it. */
195
114
  interface DeployDriver {
196
115
  /** The target id this driver serves (`"cloudflare"`, …) — matches codegen's `target`. */
197
116
  readonly id: string;
198
- /**
199
- * Read the app and report what it needs, in provider-neutral terms. Pure
200
- * with respect to the project: it never writes configuration.
201
- */
202
- infer: (context: DriverContext) => Promise<ResourceGraph>;
203
117
  /** Human-readable target name, for logs. */
204
118
  readonly name: string;
205
- /**
206
- * Write the app's requirements into the host's configuration, adding what is
207
- * missing and leaving existing entries alone. Must be idempotent:
208
- * provisioning an already-provisioned project reports `changed: false`, and
209
- * must fold a failed step into a warning rather than throwing.
210
- */
211
- provision: (context: DriverContext) => Promise<ProvisionResult>;
212
119
  /**
213
120
  * The host's command-line surface, or `undefined` for a host that has none.
214
121
  * Pure: these build argv, they never spawn.
@@ -294,10 +201,14 @@ interface InferredBindings {
294
201
  usesKv: boolean;
295
202
  /** `@lunora/mail` is imported (Resend API key must be set in `.dev.vars`; no binding). */
296
203
  usesMail: boolean;
204
+ /** `@lunora/notify` is imported (Web Push needs VAPID/FCM secrets in `.dev.vars`; no binding). */
205
+ usesNotify: boolean;
297
206
  /** `@lunora/payment` is imported (provider secrets must be set in `.dev.vars`; no binding). */
298
207
  usesPayment: boolean;
299
208
  /** `ctx.pipelines` is used (binding needs an un-mintable remote pipeline name; hint-only). */
300
209
  usesPipelines: boolean;
210
+ /** `ctx.r2sql` is used (needs the `R2_SQL_*` secrets in `.dev.vars`; no binding). */
211
+ usesR2sql: boolean;
301
212
  /** `@lunora/scheduler` is imported. */
302
213
  usesScheduler: boolean;
303
214
  /** `@lunora/storage` is imported (R2 bucket binding name is user-defined). */
@@ -387,4 +298,4 @@ interface DiscoverSchemaInfoResult {
387
298
  * parse failure is a warning (validator) or simply ignorable (inference).
388
299
  */
389
300
  declare const discoverSchemaInfo: (projectRoot: string, schemaDirectory: string) => DiscoverSchemaInfoResult;
390
- export { COMPOSED_WORKER_ENTRY as C, DeployDriver as D, InferredBindings as I, NamedResource as N, ProvisionResult as P, ResourceGraph as R, SchemaInfo as S, TailRequest as T, DeployRequest as a, DevRequest as b, DiscoverSchemaInfoResult as c, DriverContext as d, DriverToolchain as e, InferOptions as f, InferredAgent as g, InferredContainer as h, InferredWorkflow as i, SecretRequest as j, ShardNamespaceResource as k, ToolchainCommand as l, discoverSchemaInfo as m, inferLunoraBindings as n, packageNamesFromBindings as p };
301
+ export { COMPOSED_WORKER_ENTRY as C, DeployDriver as D, InferredBindings as I, SchemaInfo as S, TailRequest as T, DeployRequest as a, DevRequest as b, DiscoverSchemaInfoResult as c, DriverToolchain as d, InferOptions as e, InferredAgent as f, InferredContainer as g, InferredWorkflow as h, SecretRequest as i, ToolchainCommand as j, discoverSchemaInfo as k, inferLunoraBindings as l, packageNamesFromBindings as p };
@@ -0,0 +1,6 @@
1
+ const o=e=>JSON.stringify(e),$=/^[A-Z_a-z][\w$]*$/u,d=e=>$.test(e),u=e=>d(e)?e:`binding_${e.replaceAll(/\W/gu,"_")}`,m=(e,s=u(e))=>{const n=d(e);return n&&s===e?`${e},`:`${n?e:o(e)}: ${s},`},g=e=>{const s=new Set;for(const n of e.migrations??[])for(const r of n.new_sqlite_classes??[])s.add(r);return s},v=(e,s,n,r,c)=>{for(const a of e.durable_objects?.bindings??[])if(!(a.name===void 0||a.class_name===void 0)){if(a.script_name!==void 0){c.push(`durable_objects.${a.name} (external script_name "${a.script_name}")`);continue}n.add("DurableObjectNamespace"),r.push(m(a.name,`DurableObjectNamespace(${o(a.name)}, { className: ${o(a.class_name)}, sqlite: ${String(s.has(a.class_name))} })`))}},h=(e,s)=>{for(const[n,r]of Object.entries(e.vars??{}))s.push(m(n,o(r)))},f=["ai","analytics_engine_datasets","assets","browser","containers","flagship","hyperdrive","images","pipelines","secrets_store_secrets","send_email","services","tail_consumers","vectorize","workflows"],w=(e,s)=>{for(const n of f){const r=e[n];r!==void 0&&(!Array.isArray(r)||r.length>0)&&s.push(n)}(e.queues?.consumers?.length??0)>0&&s.push("queues.consumers")},k=e=>{const s=e.name??"worker",n=[],r=new Set(["Worker"]),c=[],a=[],p=g(e),b=[{construct:"D1Database",entries:(e.d1_databases??[]).map(t=>({binding:t.binding,name:t.database_name})),nameKey:"name"},{construct:"R2Bucket",entries:(e.r2_buckets??[]).map(t=>({binding:t.binding,name:t.bucket_name})),nameKey:"name"},{construct:"KVNamespace",entries:(e.kv_namespaces??[]).map(t=>({binding:t.binding,name:t.binding})),nameKey:"title"},{construct:"Queue",entries:(e.queues?.producers??[]).map(t=>({binding:t.binding,name:t.queue})),nameKey:"name"}];for(const{construct:t,entries:l,nameKey:y}of b)for(const i of l)i.binding!==void 0&&(r.add(t),c.push(`const ${u(i.binding)} = await ${t}(${o(i.binding)}, { adopt: true, ${y}: ${o(i.name??i.binding)} });`),a.push(m(i.binding)));v(e,p,r,a,n),h(e,a),w(e,n);const _=["adopt: true,",a.length===0?void 0:`bindings: {
2
+ ${a.join(`
3
+ `)}
4
+ },`,e.compatibility_date===void 0?void 0:`compatibilityDate: ${o(e.compatibility_date)},`,e.compatibility_flags===void 0||e.compatibility_flags.length===0?void 0:`compatibilityFlags: ${o([...e.compatibility_flags])},`,e.triggers?.crons===void 0||e.triggers.crons.length===0?void 0:`crons: ${o([...e.triggers.crons])},`,e.main===void 0?void 0:`entrypoint: ${o(e.main)},`,`name: ${o(s)},`].filter(t=>t!==void 0);return{source:["// GENERATED by @lunora/config from wrangler.jsonc — do not edit.","// Re-generated on every `lunora deploy`; edit wrangler.jsonc instead.","",'import alchemy from "alchemy";',`import { ${[...r].toSorted((t,l)=>t.localeCompare(l)).join(", ")} } from "alchemy/cloudflare";`,"",`const app = await alchemy(${o(s)});`,"",...c.length===0?[]:[...c,""],`export const worker = await Worker(${o(s)}, {`,` ${_.join(`
5
+ `)}`,"});","","await app.finalize();",""].join(`
6
+ `),unsupported:n}};export{g as sqliteClasses,k as wranglerToAlchemy};
@@ -0,0 +1 @@
1
+ import{runCodegen as c,CodegenDiagnosticError as a}from"@lunora/codegen";import{collectWranglerSecretVariables as i}from"./collectWranglerSecretVariables-D-usPfT8.mjs";import{isCodegenDisabled as s,CODEGEN_ENV as t}from"./CODEGEN_ENV-ZsCxV1kP.mjs";import{writeFileSync as m,renameSync as p,rmSync as d}from"node:fs";const g=r=>({apiSpec:r.apiSpec,lunoraDirectory:r.schemaDirectory??"lunora",projectRoot:r.projectRoot,wranglerVariables:i(r.projectRoot)}),y=r=>{if(s(process.env[t]))return[`codegen is off (${t}=0 / \`lunora dev --no-codegen\`) — the source was written but \`_generated/\` was NOT regenerated`];try{c(g(r))}catch(e){if(e instanceof a)return[e.message];throw e}return[]},S=(r,e)=>{const o=`${r}.lunora-tmp`;try{m(o,e,"utf8"),p(o,r)}catch(n){throw d(o,{force:!0}),n}};export{y as r,S as w};
@@ -1 +1 @@
1
- import{parseDevVariable as t,resolveAdminToken as r}from"../packem_shared/parseDevVariable-teAAahVD.mjs";import{applyStudioAssetCache as s,sendStudioDocument as d}from"../packem_shared/applyStudioAssetCache-DHQEJuuv.mjs";import{assetContentType as l,isStandaloneModulePath as p,loadStudioAssets as m,readStandaloneAsset as S,resolveStandaloneDirectory as i,studioAssetsStamp as f}from"../packem_shared/assetContentType-CUb5bpbI.mjs";import{POLICY_SCAFFOLD_ENDPOINT as D,handlePolicyScaffoldRequest as A}from"../packem_shared/POLICY_SCAFFOLD_ENDPOINT-DL4UFAeK.mjs";import{default as x}from"../packem_shared/renderStudioHtml-ByowDtMl.mjs";import{SCHEMA_EDIT_ENDPOINT as h,handleSchemaEditRequest as N}from"../packem_shared/SCHEMA_EDIT_ENDPOINT-IkAx-ScX.mjs";import{SEED_ENDPOINT as R,handleSeedRequest as _}from"../packem_shared/SEED_ENDPOINT-2B56PN_H.mjs";import{serveJsonHandler as T}from"../packem_shared/serveJsonHandler-Dv0EdCb9.mjs";import{ALLOW_FORWARDED_ENV as I,headerValue as L,isLoopbackAddress as v,transportRejectionReason as y}from"../packem_shared/ALLOW_FORWARDED_ENV-BUndghJx.mjs";export{I as ALLOW_FORWARDED_ENV,D as POLICY_SCAFFOLD_ENDPOINT,h as SCHEMA_EDIT_ENDPOINT,R as SEED_ENDPOINT,s as applyStudioAssetCache,l as assetContentType,A as handlePolicyScaffoldRequest,N as handleSchemaEditRequest,_ as handleSeedRequest,L as headerValue,v as isLoopbackAddress,p as isStandaloneModulePath,m as loadStudioAssets,t as parseDevVariable,S as readStandaloneAsset,x as renderStudioHtml,r as resolveAdminToken,i as resolveStandaloneDirectory,d as sendStudioDocument,T as serveJsonHandler,f as studioAssetsStamp,y as transportRejectionReason};
1
+ import{parseDevVariable as t,resolveAdminToken as r}from"../packem_shared/parseDevVariable-teAAahVD.mjs";import{applyStudioAssetCache as s,sendStudioDocument as d}from"../packem_shared/applyStudioAssetCache-DHQEJuuv.mjs";import{assetContentType as l,isStandaloneModulePath as p,loadStudioAssets as m,readStandaloneAsset as S,resolveStandaloneDirectory as i,studioAssetsStamp as f}from"../packem_shared/assetContentType-CUb5bpbI.mjs";import{POLICY_SCAFFOLD_ENDPOINT as D,handlePolicyScaffoldRequest as A}from"../packem_shared/POLICY_SCAFFOLD_ENDPOINT-0QiGKazX.mjs";import{default as x}from"../packem_shared/renderStudioHtml-ByowDtMl.mjs";import{SCHEMA_EDIT_ENDPOINT as h,handleSchemaEditRequest as N}from"../packem_shared/SCHEMA_EDIT_ENDPOINT-Dbt0faMd.mjs";import{SEED_ENDPOINT as R,handleSeedRequest as _}from"../packem_shared/SEED_ENDPOINT-2B56PN_H.mjs";import{serveJsonHandler as T}from"../packem_shared/serveJsonHandler-Dv0EdCb9.mjs";import{ALLOW_FORWARDED_ENV as I,headerValue as L,isLoopbackAddress as v,transportRejectionReason as y}from"../packem_shared/ALLOW_FORWARDED_ENV-BUndghJx.mjs";export{I as ALLOW_FORWARDED_ENV,D as POLICY_SCAFFOLD_ENDPOINT,h as SCHEMA_EDIT_ENDPOINT,R as SEED_ENDPOINT,s as applyStudioAssetCache,l as assetContentType,A as handlePolicyScaffoldRequest,N as handleSchemaEditRequest,_ as handleSeedRequest,L as headerValue,v as isLoopbackAddress,p as isStandaloneModulePath,m as loadStudioAssets,t as parseDevVariable,S as readStandaloneAsset,x as renderStudioHtml,r as resolveAdminToken,i as resolveStandaloneDirectory,d as sendStudioDocument,T as serveJsonHandler,f as studioAssetsStamp,y as transportRejectionReason};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/config",
3
- "version": "1.0.0-alpha.192",
3
+ "version": "1.0.0-alpha.194",
4
4
  "description": "Internal shared CLI + Vite config layer for Lunora: wrangler.jsonc validation, binding inference, and .dev.vars scaffolding",
5
5
  "keywords": [
6
6
  "bindings",
@@ -54,10 +54,10 @@
54
54
  "access": "public"
55
55
  },
56
56
  "dependencies": {
57
- "@lunora/codegen": "1.0.0-alpha.157",
58
- "@lunora/container": "1.0.0-alpha.44",
59
- "@lunora/errors": "1.0.0-alpha.31",
60
- "@lunora/seed": "1.0.0-alpha.107",
57
+ "@lunora/codegen": "1.0.0-alpha.158",
58
+ "@lunora/container": "1.0.0-alpha.45",
59
+ "@lunora/errors": "1.0.0-alpha.32",
60
+ "@lunora/seed": "1.0.0-alpha.108",
61
61
  "@visulima/colorize": "2.1.1",
62
62
  "@visulima/find-ai-runner": "1.0.1",
63
63
  "@visulima/package": "5.0.12",
@@ -1 +0,0 @@
1
- import{existsSync as r}from"node:fs";import{join as u}from"node:path";const a=".agents/skills",t="LUNORA_RULES_HINT_SHOWN",i=["lunora","lunora-quickstart","lunora-functions","lunora-realtime","lunora-setup-auth","lunora-create-package","lunora-migration-helper","lunora-deploy","lunora-performance-audit"],c="lunora",p="Lunora AI rules not installed — run `lunora rules install` so your coding agent knows how to use Lunora.",N=()=>process.env[t]==="1"?!1:(process.env[t]="1",!0),l=(n,o)=>u(n,a,o,"SKILL.md"),m=n=>{const o=[],e=[];for(const s of i)r(l(n,s))?o.push(s):e.push(s);return{installed:r(l(n,c)),missing:e,present:o}};export{a as AGENT_RULES_DIR,p as AGENT_RULES_HINT,t as AGENT_RULES_HINT_ENV,i as LUNORA_SKILL_NAMES,c as ROOT_SKILL_NAME,N as claimAgentRulesHint,m as detectAgentRules};
@@ -1 +0,0 @@
1
- import"./COMPOSED_WORKER_ENTRY-CAPCs3GJ.mjs";import{C as a}from"./cloudflare-driver-CWf_lB-q.mjs";import"./collectExportGaps-CHgJxlgR.mjs";import"./reconcileWranglerCompatibilityDate-7OO_xaKR.mjs";import"./reconcileWranglerCrons-COMb6ICf.mjs";export{a as default};
@@ -1 +0,0 @@
1
- import{existsSync as d,statSync as v,readFileSync as f,readdirSync as B}from"node:fs";import{init as k,parse as g}from"es-module-lexer";import{discoverAgentInfo as $}from"./discoverAgentInfo-CTdCSfYM.mjs";import{WRANGLER_FILES as F,readWranglerJsonc as Y}from"./WRANGLER_FILES-UNW-xY5u.mjs";import{discoverContainerInfo as U}from"./discoverContainerInfo-EhZtEBQs.mjs";import{escapeRegExp as T}from"./DEV_VARS_EXAMPLE_FILE-CqLorAxT.mjs";import{discoverFlags as j,FLAGS_FILENAME as K,discoverQueues as W,QUEUES_FILENAME as M}from"@lunora/codegen";import{d as w}from"./discover-info-Vj9d4qYt.mjs";import{discoverSchemaInfo as X}from"./discoverSchemaInfo-Bg2CUZXG.mjs";import{discoverWorkflowInfo as G}from"./discoverWorkflowInfo-BsPvlo6O.mjs";import{join as c}from"node:path";const H=(e,s)=>{const{error:t,value:r}=w(e,s,K,j);return t===void 0?{flags:r}:{error:t}},V=(e,s)=>{const{error:t,value:r}=w(e,s,M,W);return t===void 0?{queues:r??[]}:{error:t,queues:[]}},q=new Set([".cjs",".cts",".js",".jsx",".mjs",".mts",".ts",".tsx"]),J=new Set([".git",".lunora-cache",".wrangler","_generated","dist","node_modules"]),Q=["lunora","src"],z=["src/server/index.ts","src/server/index.tsx","src/index.ts","src/worker.ts"],_={SchedulerDO:"SCHEDULER",SessionDO:"SESSION",ShardDO:"SHARD"},N=Object.keys(_),Z={SchedulerDO:/\btype\s+SchedulerDO\b/,SessionDO:/\btype\s+SessionDO\b/,ShardDO:/\btype\s+ShardDO\b/},ee=/\benv\s*\.\s*DB\b/,se=/\benv\s*\.\s*AI\b/,D=/\bctx\s*\.\s*pipelines\b/,P=/^\s*import\s+type\b/,re=new Set(["@lunora/agent","@lunora/agent/sandbox"]),te=e=>{const s=e.indexOf("{");if(s===-1)return"";const t=e.indexOf("}",s+1);return t===-1?e.slice(s+1):e.slice(s+1,t)},ne=/\btype\s+browserTool\b/,oe=/\bbrowserTool\b/,ae=/import\s+\{[^}]*\bbrowserTool\b[^}]*\}\s+from\s+["']@lunora\/agent(?:\/sandbox)?["']/,ie=e=>{if(P.test(e))return!1;const s=te(e);return oe.test(s)&&!ne.test(s)},ce=e=>{try{const[s]=g(e);return s.some(t=>t.n!==void 0&&re.has(t.n)&&ie(e.slice(t.ss,t.se)))}catch{return ae.test(e)}},h={usesAi:{pattern:/\bfrom\s+["']@lunora\/ai["']/,source:"@lunora/ai"},usesAnalytics:{pattern:/\bfrom\s+["']@lunora\/bindings\/analytics["']/,source:"@lunora/bindings/analytics"},usesAuth:{pattern:/\bfrom\s+["']@lunora\/auth["']/,source:"@lunora/auth"},usesBrowser:{pattern:/\bfrom\s+["']@lunora\/browser["']/,source:"@lunora/browser"},usesHyperdrive:{pattern:/\bfrom\s+["']@lunora\/hyperdrive["']/,source:"@lunora/hyperdrive"},usesImages:{pattern:/\bfrom\s+["']@lunora\/bindings\/images["']/,source:"@lunora/bindings/images"},usesKv:{pattern:/\bfrom\s+["']@lunora\/bindings\/kv["']/,source:"@lunora/bindings/kv"},usesMail:{pattern:/\bfrom\s+["']@lunora\/mail["']/,source:"@lunora/mail"},usesPayment:{pattern:/\bfrom\s+["']@lunora\/payment["']/,source:"@lunora/payment"},usesPipelines:{pattern:D,source:"@lunora/bindings/pipelines"},usesScheduler:{pattern:/\bfrom\s+["']@lunora\/scheduler["']/,source:"@lunora/scheduler"},usesStorage:{pattern:/\bfrom\s+["']@lunora\/storage["']/,source:"@lunora/storage"},usesX402Charge:{pattern:/\bfrom\s+["']@lunora\/x402\/charge["']/,source:"@lunora/x402/charge"},usesX402Pay:{pattern:/\bfrom\s+["']@lunora\/x402\/pay["']/,source:"@lunora/x402/pay"}},m=Object.keys(h),ue="STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET (Stripe) or POLAR_ACCESS_TOKEN + POLAR_WEBHOOK_SECRET (Polar)",C=[...m,"needsD1"],de=()=>{const e={};for(const s of C)e[s]=!1;return e},l=Object.freeze(de()),x=(e,s)=>{const t={};for(const r of C)t[r]=e[r]||s[r];return t},le=e=>{for(const s of m)if(h[s].source===e)return{...l,[s]:!0};return l},pe=e=>{const[s]=g(e);let t=l;for(const r of s){const n=r.n;!n||P.test(e.slice(r.ss,r.se))||(t=x(t,le(n)))}return t},me=e=>{const s={...l};for(const t of m)s[t]=h[t].pattern.test(e);return s},be=e=>{let s;try{s=pe(e)}catch{s=me(e)}return x(s,{...l,needsD1:ee.test(e),usesAi:se.test(e),usesPipelines:D.test(e)})},y=(e,s)=>{let t;try{t=B(e,{withFileTypes:!0})}catch{return}for(const r of t){if(r.isDirectory()){J.has(r.name)||y(c(e,r.name),s);continue}const n=r.name.lastIndexOf(".");n!==-1&&q.has(r.name.slice(n))&&s.push(c(e,r.name))}},fe="virtual:lunora/worker",ge=["ShardDO"],he="src/worker.ts",Ee=e=>{for(const s of F){const t=c(e,s);if(!d(t))continue;const{parsed:r}=Y(t),n=r?.main;if(n===fe)return{composed:!0};const a=c(e,he);if(d(a))return{composed:!1,path:a};if(typeof n=="string"&&d(c(e,n)))return{composed:!1,path:c(e,n)};break}for(const s of z){const t=c(e,s);if(d(t))return{composed:!1,path:t}}return{composed:!1}},Se=e=>{const s=f(e,"utf8");let t;try{const[,r]=g(s);t=new Set(r.map(n=>n.n))}catch{t=new Set(N.filter(r=>new RegExp(String.raw`\bexport\b[^\n;]*\b${r}\b`).test(s)))}return N.filter(r=>t.has(r)&&!Z[r].test(s)).map(r=>({binding:_[r],className:r}))},_e=/(?:^|[\s,{])type$/u,xe=(e,s)=>{const t=s.ls>=0?s.ls:s.s;return _e.test(e.slice(0,t).trimEnd())},ye=(e,s)=>{const t=T(s);return new RegExp(String.raw`\bexport\s+type\s+${t}\b`,"u").test(e)||new RegExp(String.raw`\bexport\s+type\s*\{[^}]*\b${t}\b`,"u").test(e)||new RegExp(String.raw`\bexport\s+\{[^}]*\btype\s+${t}\b`,"u").test(e)},S=(e,s,t)=>{if(s.length===0)return[];if(e.composed)return s.map(o=>({...o,exported:!0}));if(e.path===void 0)return s.map(o=>({...o,exported:!1}));const r=f(e.path,"utf8"),n=new RegExp(String.raw`\bexport\s*\*\s*from\s*["'][^"']*_generated\/${t}(?:\.js)?["']`).test(r);let a;try{const[,o]=g(r);a=new Set(o.filter(i=>!xe(r,i)).map(i=>i.n))}catch{a=new Set(s.map(o=>o.className).filter(o=>new RegExp(String.raw`\bexport\b[^\n;]*\b${T(o)}\b`,"u").test(r)&&!ye(r,o)))}return s.map(o=>{const i=n||a.has(o.className);return{...o,exported:i}})},Re=(e,s)=>X(e,s).info?.hasGlobalTable??!1,Oe=(e,s)=>{let t=l;for(const r of s){const n=c(e,r);if(!d(n)||!v(n).isDirectory())continue;const a=[];y(n,a);for(const o of a)t=x(t,be(f(o,"utf8")))}return t},Ie=(e,s)=>{const t=c(e,s);if(!d(t)||!v(t).isDirectory())return!1;const r=[];return y(t,r),r.some(n=>ce(f(n,"utf8")))},Ae=(e,s,t)=>[...e.map(r=>r.exported?`${r.bindingName}/${r.className} (container "${r.exportName}" declared and exported)`:`hint: container "${r.exportName}" is declared but ${r.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/containers"\``),...s.map(r=>r.exported?`${r.bindingName}/${r.className} (workflow "${r.exportName}" declared and exported)`:`hint: workflow "${r.exportName}" is declared but ${r.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/workflows"\``),...t.map(r=>r.exported?`${r.bindingName}/${r.className} (agent "${r.exportName}" declared and exported)`:`hint: agent "${r.exportName}" is declared but ${r.className} is not exported by the worker entry — add \`export * from "./lunora/_generated/agents"\``)],Ne=(e,s)=>[[e.usesAi,"AI (@lunora/ai imported or env.AI used)"],[e.usesAuth&&!s.has("SessionDO"),"hint: @lunora/auth is imported; its tables are D1-backed by default. For DO-backed auth (what @better-auth/scim needs), pass `namespace` to .auth() and export the generated auth DO class"],[e.usesScheduler&&!s.has("SchedulerDO"),"hint: @lunora/scheduler is imported but no SchedulerDO is exported by the worker entry"],[e.usesStorage,"hint: @lunora/storage is imported; add an r2_buckets binding (bucket binding names are user-defined)"],[e.usesMail,"hint: @lunora/mail is imported; set RESEND_API_KEY in .dev.vars (obtain at https://resend.com/api-keys)"],[e.usesPayment,`hint: @lunora/payment is imported; set the provider secrets in .dev.vars — ${ue}`],[e.usesBrowser,"browser (@lunora/browser imported) — self-describing { binding: BROWSER }"],[e.usesImages,"images (@lunora/bindings/images imported) — self-describing { binding: IMAGES }"],[e.usesAnalytics,"analytics_engine_datasets (@lunora/bindings/analytics imported) — self-describing { binding: ANALYTICS, dataset }"],[e.usesKv,"hint: @lunora/bindings/kv is imported; add a kv_namespaces binding ({ binding, id }) and pass env.<BINDING> to createKv() — the namespace id can't be auto-provisioned"],[e.usesHyperdrive,"hint: @lunora/hyperdrive is imported; run 'wrangler hyperdrive create' and add a 'hyperdrive' binding ({ binding, id }) — the id can't be auto-provisioned"],[e.usesPipelines,"hint: ctx.pipelines is used; run 'wrangler pipelines create <name>' and add a 'pipelines' binding ({ binding, pipeline }) — the pipeline resource can't be auto-provisioned"],[e.usesX402Charge,"hint: @lunora/x402/charge is imported; set the recipient wallet address as a [vars] entry (the var name is yours to choose) and pass it to the charge config — the x402 facilitator settles USDC to that address"],[e.usesX402Pay,"hint: @lunora/x402/pay is imported (ActionCtx-only, spends real funds); add a secrets_store_secrets[] binding for the agent wallet key (name it to match signer.secretName) and pair the pay rail with a spend policy — ctx.secrets reads a Secrets Store binding, not .dev.vars, so the key can't be auto-provisioned"]].filter(([r])=>r).map(([,r])=>r),ve=(e,s,t,r=[],n=[],a=[])=>{const o=new Set(e.map(u=>u.className)),i=e.map(u=>`${u.binding}/${u.className} (exported by worker entry)`);return s&&i.push("DB (.global() table declared)"),i.push(...Ae(r,n,a),...Ne(t,o)),i},Ue=async e=>{await k;const s=e.schemaDir??"lunora",t=e.scanDirs??Q,r=Oe(e.projectRoot,t),n={...r,usesBrowser:r.usesBrowser||Ie(e.projectRoot,s)},a=Ee(e.projectRoot);let o;a.composed?o=ge.map(p=>({binding:_[p],className:p})):o=a.path===void 0?[]:Se(a.path);const i=n.needsD1||Re(e.projectRoot,s),u=S(a,U(e.projectRoot,s).containers,"containers"),R=S(a,G(e.projectRoot,s).workflows,"workflows"),O=S(a,$(e.projectRoot,s).agents,"agents"),L=[...V(e.projectRoot,s).queues],{flags:b}=H(e.projectRoot,s),E=b?.provider==="flagship"&&b.mode==="binding"?b.bindingName:void 0,I={};for(const p of m)I[p]=n[p];const A=ve(o,i,n,u,R,O);return E!==void 0&&A.push(`hint: lunora/flags.ts uses Flagship in binding mode; add a flagship binding ({ binding: "${E}", app_id }) — the app_id can't be auto-provisioned`),{agents:O,containers:u,durableObjects:o,flagshipBinding:E,needsD1:i,queues:L,signals:A,usesFlags:b!==void 0,workflows:R,...I}},je=e=>{const s=[];for(const t of m)e[t]&&s.push(h[t].source);return s};export{he as COMPOSED_WORKER_ENTRY,fe as LUNORA_WORKER_VIRTUAL_ID,z as WORKER_ENTRY_FALLBACKS,Ue as inferLunoraBindings,xe as isTypeOnlyExportEntry,je as packageNamesFromBindings,Ee as resolveWorkerEntry};
@@ -1 +0,0 @@
1
- import{t as a,C as d}from"./cloudflare-driver-CWf_lB-q.mjs";import{inferLunoraBindings as s}from"./COMPOSED_WORKER_ENTRY-CAPCs3GJ.mjs";const l=[{detect:e=>e.containers.length>0,warning:"containers have no Node equivalent in @lunora/platform-node — ctx.containers will be unavailable"}],p={id:"node",infer:async e=>a(await s({projectRoot:e.projectRoot}),e.crons??[]),name:"Node",provision:async e=>{let n;try{n=a(await s({projectRoot:e.projectRoot}),e.crons??[])}catch(r){const i=r instanceof Error?r.message:String(r);return{added:[],changed:!1,warnings:[`requirement inference skipped: ${i}`]}}const t=l.filter(r=>r.detect(n)).map(r=>r.warning);return n.crons.length>0&&t.push(`${String(n.crons.length)} cron expression(s) declared, and NOTHING dispatches them on this target: no runtime walks the generated LUNORA_CRONS map into SchedulerHost.cron. Schedule the work explicitly (ctx.scheduler.runAfter/runAt) or deploy to a target with cron dispatch`),{added:[],changed:!1,warnings:t}}},h="cloudflare",o={cloudflare:d,node:p},c=()=>Object.keys(o).toSorted((e,n)=>e.localeCompare(n)),g=(e=h)=>{const n=o[e];if(n===void 0)throw new Error(`unknown deploy target "${e}" — available targets: ${c().join(", ")}`);return n},u=e=>Object.hasOwn(o,e)&&g(e).toolchain!==void 0,m=()=>c().filter(e=>u(e));export{h as DEFAULT_DEPLOY_TARGET,c as deployTargetIds,u as isRunnableTarget,g as resolveDeployDriver,m as runnableTargetIds};
@@ -1 +0,0 @@
1
- import{existsSync as d,readFileSync as y}from"node:fs";import{join as s,isAbsolute as a,relative as m}from"node:path";import{runCodegen as p,CodegenDiagnosticError as g}from"@lunora/codegen";import{LunoraError as k}from"@lunora/errors";import{classifyPolicyEdit as v,scaffoldPolicyFile as b,resolveServerModule as l,wireRlsIntoProcedure as h}from"./classifyPolicyEdit-D8NwrHxR.mjs";import{w as c,s as w}from"./write-atomic-D88PwWJc.mjs";const O="/__lunora/policy-scaffold",u=o=>o==="unknown-procedure"?404:o==="already-wired"||o==="destructive"?409:422,f=(o,r)=>{let e=[];try{p(w(o))}catch(t){if(t instanceof g)e=[t.message];else return{body:{error:t instanceof Error?t.message:String(t),ok:!1},status:500}}return{body:{...r,diagnostics:e,ok:!0},status:200}},R=o=>({body:{edit:o,message:"Rewriting an existing policy predicate changes evaluation semantics and must be done by hand. The scaffolder only adds new, deny-by-default rules.",needsManualEdit:!0,ok:!1},status:409}),N=(o,r)=>{const e=b(r,l(o.projectRoot));if(!e.ok)return{body:{error:e.reason,ok:!1},status:u(e.reason)};const t=o.schemaDirectory??"lunora",n=s(o.projectRoot,t,e.fileName);return d(n)?{body:{error:"file-exists",fileName:e.fileName,ok:!1},status:409}:(c(n,e.source),f(o,{fileName:e.fileName}))},P=(o,r,e)=>{if(typeof e!="string"||e.length===0||a(e)||e.includes("\\"))return;const t=s(o,r),n=s(t,`${e}.ts`),i=m(t,n);if(!(i.startsWith("..")||a(i)))return n},F=(o,r)=>{const e=P(o.projectRoot,o.schemaDirectory??"lunora",r.filePath);if(e===void 0||!d(e))return{body:{error:"unknown-procedure",ok:!1},status:404};const t=h(y(e,"utf8"),r,l(o.projectRoot));return t.ok?(c(e,t.text),f(o,{exportName:r.exportName})):{body:{error:t.reason,ok:!1},status:u(t.reason)}},A=o=>{if(o.method!=="POST")return{body:{error:"method-not-allowed",ok:!1},status:405};const{body:r}=o;if(r==null||typeof r!="object"||typeof r.kind!="string")return{body:{error:"invalid-edit",ok:!1},status:400};const e=r;if(v(e)==="destructive")return R(e);if(e.kind==="scaffoldPolicy")return N(o,e);if(e.kind==="wireRls")return F(o,e);throw new k("INTERNAL",`unhandled additive policy edit kind: ${String(e.kind)}`)};export{O as POLICY_SCAFFOLD_ENDPOINT,A as handlePolicyScaffoldRequest};
@@ -1 +0,0 @@
1
- import{existsSync as a,readFileSync as d}from"node:fs";import{runCodegen as l,CodegenDiagnosticError as c}from"@lunora/codegen";import{classifyEdit as f,applyAdditiveEdit as p}from"./applyAdditiveEdit-CH0VhMJ2.mjs";import{parseSchema as u}from"./parseSchema-D1Wbr1qv.mjs";import{w as m,s as b}from"./write-atomic-D88PwWJc.mjs";import{join as y}from"node:path";const C="/__lunora/schema-edit",g=e=>e==="destructive"||e==="duplicate-table"||e==="duplicate-column"||e==="duplicate-index"?409:e==="unknown-table"?404:e==="invalid-identifier"||e==="invalid-validator"?400:422,h=e=>({body:{error:e.reason,ok:!1},status:422}),k=e=>{if(!a(e))return{response:{body:{error:"no-schema-file",ok:!1},status:404}};const r=u(d(e,"utf8"));return r.ok?{tables:r.tables}:{response:h(r)}},v=e=>({body:{edit:e,message:"This edit changes stored data and must go through a migration. Review the migration before applying.",needsMigration:!0,ok:!1},status:409}),E=(e,r)=>{const t=e.body;if(t==null||typeof t!="object"||typeof t.kind!="string")return{body:{error:"invalid-edit",ok:!1},status:400};if(f(t)==="destructive")return v(t);if(!a(r))return{body:{error:"no-schema-file",ok:!1},status:404};const o=p(d(r,"utf8"),t);if(!o.ok)return{body:{error:o.reason,ok:!1},status:g(o.reason)};m(r,o.text);let i=[];try{l(b(e))}catch(s){if(s instanceof c)i=[s.message];else return{body:{error:s instanceof Error?s.message:String(s),ok:!1},status:500}}const n=u(o.text);return{body:{diagnostics:i,ok:!0,tables:n.ok?n.tables:[]},status:200}},D=e=>{const r=y(e.projectRoot,e.schemaDirectory??"lunora","schema.ts");if(e.method==="GET"){const t=k(r);return"response"in t?t.response:{body:{ok:!0,tables:t.tables},status:200}}return e.method==="POST"?E(e,r):{body:{error:"method-not-allowed",ok:!1},status:405}};export{C as SCHEMA_EDIT_ENDPOINT,D as handleSchemaEditRequest};
@@ -1 +0,0 @@
1
- import{spawnSync as o}from"node:child_process";import{LunoraError as s}from"@lunora/errors";import{findPackageManagerSync as i,identifyInitiatingPackageManager as c}from"@visulima/package/package-manager";const a=["pnpm","bun","yarn","npm"],u=new Set(a),d=n=>u.has(n),m=n=>{try{return o(n,["--version"],{stdio:"ignore",timeout:5e3}).status===0}catch{return!1}},p=(n=m)=>a.filter(r=>n(r)),A=n=>({args:["install"],command:n}),y=(n,r,t={})=>{const e=t.dev===!0;return n==="npm"?{args:["install",...e?["--save-dev"]:[],...r],command:"npm"}:n==="bun"?{args:["add",...e?["-d"]:[],...r],command:"bun"}:{args:["add",...e?["-D"]:[],...r],command:n}},M=n=>{try{return i(n).packageManager}catch{}const r=c();if(r!==void 0){const e=r.name==="cnpm"?"npm":r.name;if(d(e))return e}const[t]=p();if(t!==void 0)return t;throw new s("INTERNAL","Could not detect a package manager: no lock file or `packageManager` field was found, and none (pnpm, bun, yarn, npm) is installed on PATH.")},b=(n,r,t)=>n==="yarn"?{args:[r,...t],command:"yarn"}:n==="bun"?{args:["x",r,...t],command:"bun"}:n==="npm"?{args:["--",r,...t],command:"npx"}:{args:["exec",r,...t],command:"pnpm"},E=(n,r)=>({args:["run",r],command:n}),v=(n,r)=>n==="npm"?`npm run ${r}`:n==="bun"?`bun run ${r}`:`${n} ${r}`;export{y as addArgsFor,p as detectInstalledManagers,M as detectPackageManager,b as execArgsFor,A as installArgsFor,E as runScriptArgsFor,v as runScriptCommand};
@@ -1 +0,0 @@
1
- import{inferLunoraBindings as c}from"./COMPOSED_WORKER_ENTRY-CAPCs3GJ.mjs";import{reconcileWranglerBindings as p}from"./collectExportGaps-CHgJxlgR.mjs";import{reconcileWranglerCompatibilityDate as g}from"./reconcileWranglerCompatibilityDate-7OO_xaKR.mjs";import{reconcileWranglerCrons as m}from"./reconcileWranglerCrons-COMb6ICf.mjs";const l=(n,r)=>{const e=n.durableObjects.map(o=>({className:o.className,exported:!0,name:o.binding})),a=n.queues.map(o=>({name:o.name})),i=n.workflows.map(o=>({exported:o.exported,name:o.exportName}));return{containers:n.containers.map(o=>({exported:o.exported,name:o.exportName})),crons:[...r],globalDatabase:n.needsD1,keyValueStore:n.usesKv,objectStorage:n.usesStorage,queues:a,shardNamespaces:e,signals:[...n.signals],workflows:i}},s=(n,r)=>{try{const e=r();return{added:e.added??[],changed:e.changed,configPath:e.wranglerPath,warnings:e.warnings??[]}}catch(e){const a=e instanceof Error?e.message:String(e);return{added:[],changed:!1,warnings:[`${n} skipped: ${a}`]}}},f={deploy:n=>{const r=n.preview===!0?["versions","upload"]:["deploy"];return n.entry!==void 0&&r.push(n.entry),n.environment!==void 0&&r.push("--env",n.environment),n.temporary===!0&&r.push("--temporary"),n.dryRun===!0&&r.push("--dry-run"),n.outDir!==void 0&&r.push("--outdir",n.outDir,"--metafile"),{args:r,tool:"wrangler"}},dev:n=>{const r=["dev"];return n.configPath!==void 0&&r.push("--config",n.configPath),n.environment!==void 0&&r.push("--env",n.environment),r.push(...n.extraArgs??[]),{args:r,tool:"wrangler"}},secretList:n=>{const r=["secret","list","--format","json"];return n.environment!==void 0&&r.push("--env",n.environment),n.temporary===!0&&r.push("--temporary"),{args:r,tool:"wrangler"}},secretPut:n=>{const r=["secret","put",n.key??""];return n.environment!==void 0&&r.push("--env",n.environment),n.temporary===!0&&r.push("--temporary"),{args:r,tool:"wrangler"}},tail:n=>{const r=["tail"];return n.worker!==void 0&&r.push(n.worker),n.environment!==void 0&&r.push("--env",n.environment),n.format!==void 0&&r.push("--format",n.format),n.status!==void 0&&r.push("--status",n.status),n.search!==void 0&&r.push("--search",n.search),n.temporary===!0&&r.push("--temporary"),{args:r,tool:"wrangler"}}},w={id:"cloudflare",infer:async n=>{const r=await c({projectRoot:n.projectRoot});return l(r,n.crons??[])},name:"Cloudflare",provision:async n=>{const r=n.crons??[],e=await(async()=>{try{const o=await c({projectRoot:n.projectRoot});return s("binding inference",()=>p(n.projectRoot,o))}catch(o){const d=o instanceof Error?o.message:String(o);return{added:[],changed:!1,warnings:[`binding inference skipped: ${d}`]}}})(),a=s("compatibility date sync",()=>g(n.projectRoot)),i=s("cron trigger sync",()=>m(n.projectRoot,r)),t=[e,{...a,added:a.changed?["compatibility_date"]:[]},{...i,added:i.changed?[`${String(r.length)} cron trigger(s)`]:[]}];return{added:t.flatMap(o=>o.added),changed:t.some(o=>o.changed),configPath:t.find(o=>o.configPath!==void 0)?.configPath,warnings:t.flatMap(o=>o.warnings)}},toolchain:f};export{w as C,l as t};
@@ -1 +0,0 @@
1
- import{writeFileSync as D,readFileSync as B}from"node:fs";import{join as C}from"node:path";import{containerBuildTag as A}from"@lunora/container";import{DEV_VARS_FILE as O,parseDevVariableEntries as P}from"./DEV_VARS_EXAMPLE_FILE-CqLorAxT.mjs";import{a as b}from"./jsonc-edit-BZgQIdAH.mjs";import{findWranglerFile as R,readWranglerJsonc as $}from"./WRANGLER_FILES-UNW-xY5u.mjs";import{objectBindingEntries as w,stringEntries as v}from"./REQUIRED_COMPATIBILITY_DATE-iWKnSx2C.mjs";const N="<replace-with-d1-create-id>",I=e=>[["container","containers",e.containers],["workflow","workflows",e.workflows],["agent","agents",e.agents]].flatMap(([n,t,i])=>i.filter(o=>!o.exported).map(({className:o,exportName:c})=>({className:o,exportName:c,kind:n,module:t}))),T=(e,s)=>{const n=e.flagshipBinding!==void 0&&!(s?.flagship??[]).some(i=>i.binding===e.flagshipBinding);return[[e.usesKv&&(s?.kv_namespaces?.length??0)===0,"@lunora/bindings/kv is used but no kv_namespaces binding exists; add a kv_namespaces entry ({ binding, id }) and pass env.<BINDING> to createKv() — the namespace id can't be auto-provisioned."],[e.usesHyperdrive&&(s?.hyperdrive?.length??0)===0,"@lunora/hyperdrive is used but no hyperdrive binding exists; run 'wrangler hyperdrive create' and add a 'hyperdrive' binding ({ binding, id }) — the id can't be auto-provisioned."],[e.usesPipelines&&(s?.pipelines?.length??0)===0,"ctx.pipelines is used but no pipelines binding exists; run 'wrangler pipelines create <name>' and add a 'pipelines' binding ({ binding, pipeline }) — the pipeline resource can't be auto-provisioned."],[n,`lunora/flags.ts uses Flagship in binding mode but no flagship binding "${e.flagshipBinding??""}" exists; add a flagship entry ({ binding: "${e.flagshipBinding??""}", app_id }) — the app_id can't be auto-provisioned.`]].filter(([i])=>i).map(([,i])=>i)},M=e=>[[e.usesX402Charge,"@lunora/x402/charge is used; set the recipient wallet address as a [vars] entry (the var name is your choice) and pass it to the charge config — the x402 facilitator settles USDC to that address."],[e.usesX402Pay,"@lunora/x402/pay is used (ActionCtx-only, spends real funds); add a secrets_store_secrets[] binding holding the agent wallet key (binding name == signer.secretName) and pair the pay rail with a spend policy — ctx.secrets reads a Secrets Store binding, not .dev.vars."]].filter(([n])=>n).map(([,n])=>n),_=(e,s,n)=>n.filter(t=>!t.exported).map(t=>`${e} "${t.exportName}" is declared but ${t.className} is not exported by the worker entry; add \`export * from "./lunora/_generated/${s}"\` so its binding can be provisioned.`),k=[{keys:["STRIPE_SECRET_KEY","STRIPE_WEBHOOK_SECRET"],label:"Stripe"},{keys:["POLAR_ACCESS_TOKEN","POLAR_WEBHOOK_SECRET"],label:"Polar"},{keys:["CREEM_API_KEY","CREEM_WEBHOOK_SECRET"],label:"Creem"},{keys:["AUTUMN_SECRET_KEY","AUTUMN_WEBHOOK_SECRET"],label:"Autumn"},{keys:["DODO_PAYMENTS_API_KEY","DODO_PAYMENTS_WEBHOOK_KEY"],label:"Dodo Payments"}],W=()=>k.map(({keys:e,label:s})=>`${e[0]} + ${e[1]} (${s})`).join(" or "),K=e=>{let s;try{s=B(C(e,O),"utf8")}catch{return!1}const n=new Map(P(s).map(t=>[t.key,t.value]));return k.some(({keys:t})=>t.every(i=>(n.get(i)??"")!==""))},x=(e,s,n)=>{const t=new Set(e.durableObjects.map(d=>d.className)),i=[],o=(n?.r2_buckets?.length??0)>0,c=(n?.d1_databases?.some(d=>d.binding==="DB")??!1)||e.needsD1;return e.usesStorage&&!o&&i.push("@lunora/storage is used but R2 bucket bindings have user-defined names; add an r2_buckets entry and pass env.<BINDING> to createStorage()."),e.usesAuth&&!t.has("SessionDO")&&!c&&i.push("@lunora/auth is used but the worker entry exports no SessionDO; sessions are D1-backed, or export SessionDO to enable DO-backed sessions."),e.usesScheduler&&!t.has("SchedulerDO")&&i.push("@lunora/scheduler is used but the worker entry exports no SchedulerDO; export it so the SCHEDULER binding can be provisioned."),i.push(..._("container","containers",e.containers),..._("workflow","workflows",e.workflows),..._("agent","agents",e.agents)),e.containers.length>0&&n?.observability?.enabled===!1&&i.push("containers are declared but observability is explicitly disabled in wrangler.jsonc — container logs will not be captured."),e.usesPayment&&!K(s)&&i.push(`@lunora/payment is used; set one provider's secret pair in .dev.vars — ${W()}.`),i.push(...M(e),...T(e,n)),i},L=e=>{const s=new Set(w(e).map(t=>t.tag));let n=1;for(;s.has(`v${String(n)}`);)n+=1;return`v${String(n)}`},Y=e=>{const s=new Set;for(const n of w(e)){for(const t of v(n.deleted_classes))s.delete(t);for(const{from:t,to:i}of w(n.renamed_classes))t!==void 0&&s.delete(t),i!==void 0&&s.add(i);for(const t of[...v(n.new_classes),...v(n.new_sqlite_classes)])s.add(t)}return s},H=(e,s,n)=>{const t=s.durable_objects?.bindings??[],i=new Set(t.map(u=>u.name)),o=n.filter(u=>!i.has(u.binding));let c=e;const d=[];if(o.length>0){const u=[...t,...o.map(p=>({class_name:p.className,name:p.binding}))];c=b(c,["durable_objects","bindings"],u),d.push(...o.map(p=>`${p.binding}/${p.className}`))}const g=s.migrations??[],l=n.map(u=>u.className).filter(u=>!Y(g).has(u));if(l.length>0){const u=[...g,{new_sqlite_classes:l,tag:L(g)}];c=b(c,["migrations"],u)}return{added:d,text:c}},j=(e,s)=>{const n=s.d1_databases??[];if(n.some(o=>o.binding==="DB"))return{added:[],text:e};const t=typeof s.name=="string"&&s.name.length>0?s.name:"lunora",i=[...n,{binding:"DB",database_id:N,database_name:t}];return{added:["DB (D1)"],text:b(e,["d1_databases"],i)}},y=(e,s,n,t,i)=>{const o=s[n]?.binding;return typeof o=="string"&&o.length>0?{added:[],text:e}:{added:[i],text:b(e,[n],{binding:t})}},F=(e,s)=>(s.analytics_engine_datasets?.length??0)>0?{added:[],text:e}:{added:["ANALYTICS (Analytics Engine)"],text:b(e,["analytics_engine_datasets"],[{binding:"ANALYTICS",dataset:"ANALYTICS"}])},G=e=>{if(typeof e=="string")return e;const s={};return e.diskMb!==void 0&&(s.disk_mb=e.diskMb),e.memoryMib!==void 0&&(s.memory_mib=e.memoryMib),e.vcpu!==void 0&&(s.vcpu=e.vcpu),s},U=e=>e.image.kind==="dockerfile"?e.image.dockerfilePath:e.image.kind==="registry"?e.image.reference:A(e.exportName),V=e=>{const s={class_name:e.className,image:U(e)};return e.image.kind==="dockerfile"&&(s.image_build_context=e.image.buildContext),e.buildArgs!==void 0&&e.image.kind!=="registry"&&(s.image_vars=e.buildArgs),e.instanceType!==void 0&&(s.instance_type=G(e.instanceType)),e.maxInstances!==void 0&&(s.max_instances=e.maxInstances),e.name!==void 0&&(s.name=e.name),e.rollout?.stepPercentage!==void 0&&(s.rollout_step_percentage=e.rollout.stepPercentage),e.rollout?.gracePeriodSeconds!==void 0&&(s.rollout_active_grace_period=e.rollout.gracePeriodSeconds),s},z=(e,s,n)=>{const t=s.containers??[],i=new Set(t.map(d=>d.class_name)),o=n.filter(d=>!i.has(d.className));if(o.length===0)return{added:[],text:e};const c=b(e,["containers"],[...t,...o.map(d=>V(d))]);return{added:o.map(d=>`containers/${d.className}`),text:c}},Q=(e,s)=>{if(s.observability!==void 0)return{added:[],text:e};const n=b(e,["observability"],{enabled:!0,head_sampling_rate:1});return{added:["observability"],text:n}},E=e=>({binding:e.bindingName,class_name:e.className,name:e.name}),X=(e,s,n,t=[])=>{const i=s.workflows??[],o=new Set(i.map(l=>l.class_name)),c=n.filter(l=>!o.has(l.className)),d=t.filter(l=>!o.has(l.className));if(c.length===0&&d.length===0)return{added:[],text:e};const g=b(e,["workflows"],[...i,...c.map(l=>E(l)),...d.map(l=>E(l))]);return{added:[...c.map(l=>`workflows/${l.className}`),...d.map(l=>`workflows/${l.className}`)],text:g}},J=(e,s,n)=>{const t=s.queues??{},i=t.producers??[],o=t.consumers??[],c=new Set(i.map(r=>r.binding)),d=new Set(o.map(r=>r.queue)),g=n.filter(r=>!c.has(r.bindingName)),l=n.filter(r=>!d.has(r.name));if(g.length===0&&l.length===0)return{added:[],text:e};const u=[...i,...g.map(r=>({binding:r.bindingName,queue:r.name}))],p=[...o,...l.map(r=>{const m={queue:r.name};return r.mode==="pull"&&(m.type="http_pull"),r.tuning.maxBatchSize!==void 0&&(m.max_batch_size=r.tuning.maxBatchSize),r.tuning.maxBatchTimeout!==void 0&&(m.max_batch_timeout=r.tuning.maxBatchTimeout),r.tuning.maxRetries!==void 0&&(m.max_retries=r.tuning.maxRetries),r.tuning.deadLetterQueue!==void 0&&(m.dead_letter_queue=r.tuning.deadLetterQueue),r.tuning.retryDelay!==void 0&&(m.retry_delay=r.tuning.retryDelay),m})],h=b(e,["queues"],{consumers:p,producers:u});return{added:[...g.map(r=>`queues.producers/${r.bindingName}`),...l.map(r=>`queues.consumers/${r.name}`)],text:h}},ie=(e,s,n)=>{const t=R(e),i=I(s);if(!t)return{added:[],changed:!1,exportGaps:i,reason:"wrangler.jsonc not found",warnings:x(s,e)};const{parsed:o,text:c}=$(t);if(o===void 0)return{added:[],changed:!1,exportGaps:i,reason:`failed to parse ${t} as JSONC`,warnings:x(s,e),wranglerPath:t};const d=x(s,e,o);if(n!==void 0){const a=o.env?.[n]!==void 0;d.push(a?`auto-provisioned bindings are written to the top level of wrangler.jsonc only — "env.${n}" has its own (non-inheritable) bindings and must be reconciled by hand; \`lunora deploy --env ${n}\` now validates them, so a gap here will be reported at deploy time.`:`--env "${n}" was requested but wrangler.jsonc declares no "env.${n}" block — auto-provisioned bindings are written to the top level only and will not apply to that environment.`)}const g=s.containers.filter(a=>a.exported),l=s.agents.filter(a=>a.exported&&a.voice===!0&&a.voiceBindingName!==void 0&&a.voiceClassName!==void 0),u=[...s.durableObjects,...g.map(a=>({binding:a.bindingName,className:a.className})),...l.map(a=>({binding:a.voiceBindingName,className:a.voiceClassName}))],p=s.workflows.filter(a=>a.exported),h=s.agents.filter(a=>a.exported),r=[{enabled:!0,run:a=>H(a,o,u)},{enabled:s.needsD1,run:a=>j(a,o)},{enabled:s.usesAi,run:a=>y(a,o,"ai","AI","AI (Workers AI)")},{enabled:s.usesBrowser,run:a=>y(a,o,"browser","BROWSER","BROWSER (Browser Rendering)")},{enabled:s.usesImages,run:a=>y(a,o,"images","IMAGES","IMAGES (Cloudflare Images)")},{enabled:s.usesAnalytics,run:a=>F(a,o)},{enabled:!0,run:a=>Q(a,o)},{enabled:g.length>0,run:a=>z(a,o,g)},{enabled:p.length>0||h.length>0,run:a=>X(a,o,p,h)},{enabled:s.queues.length>0,run:a=>J(a,o,s.queues)}];let m=c;const f=[];for(const a of r){if(!a.enabled)continue;const S=a.run(m);m=S.text,f.push(...S.added)}return f.includes("DB (D1)")&&d.push(`wrote a DB binding with a placeholder database_id ("${N}") — run \`wrangler d1 create <name>\` and replace it before deploying.`),m===c?{added:[],changed:!1,exportGaps:i,reason:"bindings already in sync",warnings:d,wranglerPath:t}:(D(t,m,"utf8"),{added:f,changed:!0,exportGaps:i,warnings:d,wranglerPath:t})};export{I as collectExportGaps,ie as reconcileWranglerBindings};
@@ -1 +0,0 @@
1
- const a=e=>e.endsWith("S")?e.slice(0,-1):e,r=e=>e.replaceAll(/([a-z\d])([A-Z])/gu,"$1_$2").toUpperCase().split(/[_-]+/u).filter(s=>s.length>0),n=new Set(["CREDENTIAL","DSN","PASSPHRASE","PASSWD","PASSWORD","SECRET","TOKEN"]),c=["ACCESS_KEY","API_KEY","ENCRYPTION_KEY","PRIVATE_KEY","SIGNING_KEY"],i=new RegExp(`(?:${[...n,...c.map(e=>e.replaceAll("_",""))].join("|")})S?$`,"iu"),l=e=>r(e).some(s=>s==="PUBLIC"||s==="PUBLISHABLE"),d=e=>{if(l(e))return!1;const s=r(e);if(s.some(o=>n.has(a(o))))return!0;const t=a(s.join("_"));return c.some(o=>t===o||t.endsWith(`_${o}`))||i.test(e)},h=[{description:"Bearer token the local Lunora Studio uses to call the worker's admin endpoints (data browser, schema edits) in dev. Generate with: openssl rand -hex 32",docsUrl:"https://lunora.sh/docs/packages/studio",key:"LUNORA_ADMIN_TOKEN",placeholderValue:"replace-with-openssl-rand-hex-32"}],u=["BETTER_AUTH_SECRET","STORAGE_SIGNING_SECRET"],p={"@lunora/auth":[{description:"32-byte random secret used to sign sessions and tokens. Generate with: openssl rand -hex 32",docsUrl:"https://lunora.sh/docs/packages/auth#secrets",key:"AUTH_SECRET",placeholderValue:"replace-with-openssl-rand-hex-32"},{description:"Public base URL of your worker (used by better-auth for redirects and cookie domain). For local dev this is typically http://localhost:8787",docsUrl:"https://lunora.sh/docs/packages/auth#secrets",key:"AUTH_URL",placeholderValue:"http://localhost:8787"}],"@lunora/mail":[{description:"Resend API key for sending transactional email via @lunora/mail. Obtain at https://resend.com/api-keys",docsUrl:"https://lunora.sh/docs/packages/mail#secrets",key:"RESEND_API_KEY",placeholderValue:"<your-resend-api-key>"}],"@lunora/notify":[{description:"Public VAPID key (base64url) for Web Push. Generate a keypair once with: npx web-push generate-vapid-keys — the public key is also shipped to the browser to subscribe.",docsUrl:"https://lunora.sh/docs/packages/notify#web-push",key:"VAPID_PUBLIC_KEY",placeholderValue:"<your-vapid-public-key>"},{description:"Private VAPID key (base64url) for Web Push — the application-server signing key. Generate with: npx web-push generate-vapid-keys",docsUrl:"https://lunora.sh/docs/packages/notify#web-push",key:"VAPID_PRIVATE_KEY",placeholderValue:"<your-vapid-private-key>"},{description:"VAPID `sub` contact — a mailto: or https: URL identifying the application server (e.g. mailto:you@example.com).",docsUrl:"https://lunora.sh/docs/packages/notify#web-push",key:"VAPID_SUBJECT",placeholderValue:"mailto:you@example.com"},{description:"Firebase project id for FCM (HTTP v1) push. Found in the Firebase console project settings.",docsUrl:"https://lunora.sh/docs/packages/notify#fcm",key:"FCM_PROJECT_ID",placeholderValue:"<your-firebase-project-id>"},{description:"OAuth2 access token for FCM (HTTP v1). Convenient for dev but expires — in production supply a getAccessToken() in defineNotify instead. Obtain via the Google Cloud SDK / a service account.",docsUrl:"https://lunora.sh/docs/packages/notify#fcm",key:"FCM_ACCESS_TOKEN",placeholderValue:"<your-fcm-access-token>"}],"@lunora/payment":[{description:"Stripe secret key (sk_test_…). Required when using the Stripe adapter. Obtain at https://dashboard.stripe.com/apikeys",docsUrl:"https://lunora.sh/docs/packages/payment#stripe",key:"STRIPE_SECRET_KEY",placeholderValue:"<your-stripe-secret-key>"},{description:"Stripe webhook signing secret (whsec_…) for verifying event payloads. Obtain at https://dashboard.stripe.com/webhooks",docsUrl:"https://lunora.sh/docs/packages/payment#stripe",key:"STRIPE_WEBHOOK_SECRET",placeholderValue:"<your-stripe-webhook-secret>"},{description:"Polar access token for the Polar payment adapter. Obtain at https://polar.sh/settings/tokens",docsUrl:"https://lunora.sh/docs/packages/payment#polar",key:"POLAR_ACCESS_TOKEN",placeholderValue:"<your-polar-access-token>"},{description:"Polar webhook secret for verifying event payloads from Polar. Obtain at https://polar.sh/settings/webhooks",docsUrl:"https://lunora.sh/docs/packages/payment#polar",key:"POLAR_WEBHOOK_SECRET",placeholderValue:"<your-polar-webhook-secret>"},{description:"Autumn secret key (am_sk_…) for the Autumn payment adapter. Obtain at https://app.useautumn.com/dev",docsUrl:"https://lunora.sh/docs/packages/payment#autumn",key:"AUTUMN_SECRET_KEY",placeholderValue:"<your-autumn-secret-key>"},{description:"Autumn webhook signing secret for verifying Standard Webhooks event payloads. Obtain from your Autumn dashboard webhook settings.",docsUrl:"https://lunora.sh/docs/packages/payment#autumn",key:"AUTUMN_WEBHOOK_SECRET",placeholderValue:"<your-autumn-webhook-secret>"},{description:"Dodo Payments API key (bearer token) for the Dodo Payments adapter. Obtain at https://app.dodopayments.com/developer/api-keys",docsUrl:"https://lunora.sh/docs/packages/payment#dodo-payments",key:"DODO_PAYMENTS_API_KEY",placeholderValue:"<your-dodo-payments-api-key>"},{description:"Dodo Payments webhook signing secret (whsec_…) for verifying event payloads. Obtain at https://app.dodopayments.com/developer/webhooks",docsUrl:"https://lunora.sh/docs/packages/payment#dodo-payments",key:"DODO_PAYMENTS_WEBHOOK_KEY",placeholderValue:"<your-dodo-payments-webhook-secret>"},{description:"Creem API key for the Creem payment adapter. Obtain at https://www.creem.io/dashboard/developers",docsUrl:"https://lunora.sh/docs/packages/payment#creem",key:"CREEM_API_KEY",placeholderValue:"<your-creem-api-key>"},{description:"Creem webhook signing secret for verifying the creem-signature header. Obtain from your Creem dashboard webhook settings.",docsUrl:"https://lunora.sh/docs/packages/payment#creem",key:"CREEM_WEBHOOK_SECRET",placeholderValue:"<your-creem-webhook-secret>"}]},y=new Set([...u,...[...h,...Object.values(p).flat()].filter(e=>d(e.key)&&!e.placeholderValue.startsWith("<")).map(e=>e.key)]),E=e=>{const s=[];for(const t of e){const o=p[t];o!==void 0&&s.push(...o)}return s};export{h as C,y as M,p as P,d as a,l as i,E as s};
@@ -1,6 +0,0 @@
1
- const r=e=>JSON.stringify(e),$=/^[A-Z_a-z][\w$]*$/u,d=e=>$.test(e),p=e=>d(e)?e:`binding_${e.replaceAll(/\W/gu,"_")}`,m=(e,n=p(e))=>{const s=d(e);return s&&n===e?`${e},`:`${s?e:r(e)}: ${n},`},g=e=>{const n=new Set;for(const s of e.migrations??[])for(const o of s.new_sqlite_classes??[])n.add(o);return n},v=(e,n,s,o,i)=>{for(const a of e.durable_objects?.bindings??[])if(!(a.name===void 0||a.class_name===void 0)){if(a.script_name!==void 0){i.push(`durable_objects.${a.name} (external script_name "${a.script_name}")`);continue}s.add("DurableObjectNamespace"),o.push(m(a.name,`DurableObjectNamespace(${r(a.name)}, { className: ${r(a.class_name)}, sqlite: ${String(n.has(a.class_name))} })`))}},w=(e,n)=>{for(const[s,o]of Object.entries(e.vars??{}))n.push(m(s,r(String(o))))},h=(e,n)=>{for(const[s,o]of[["ai","ai"],["analytics_engine_datasets","analytics_engine_datasets"],["browser","browser"],["containers","containers"],["hyperdrive","hyperdrive"],["images","images"],["pipelines","pipelines"],["vectorize","vectorize"],["workflows","workflows"]]){const i=e[s];i!==void 0&&(!Array.isArray(i)||i.length>0)&&n.push(o)}},j=e=>{const n=e.name??"worker",s=[],o=new Set(["Worker"]),i=[],a=[],u=g(e),b=[{construct:"D1Database",entries:(e.d1_databases??[]).map(t=>({binding:t.binding,name:t.database_name})),nameKey:"name"},{construct:"R2Bucket",entries:(e.r2_buckets??[]).map(t=>({binding:t.binding,name:t.bucket_name})),nameKey:"name"},{construct:"KVNamespace",entries:(e.kv_namespaces??[]).map(t=>({binding:t.binding,name:t.binding})),nameKey:"title"},{construct:"Queue",entries:(e.queues?.producers??[]).map(t=>({binding:t.binding,name:t.queue})),nameKey:"name"}];for(const{construct:t,entries:l,nameKey:_}of b)for(const c of l)c.binding!==void 0&&(o.add(t),i.push(`const ${p(c.binding)} = await ${t}(${r(c.binding)}, { adopt: true, ${_}: ${r(c.name??c.binding)} });`),a.push(m(c.binding)));v(e,u,o,a,s),w(e,a),h(e,s);const y=["adopt: true,",a.length===0?void 0:`bindings: {
2
- ${a.join(`
3
- `)}
4
- },`,e.compatibility_date===void 0?void 0:`compatibilityDate: ${r(e.compatibility_date)},`,e.compatibility_flags===void 0||e.compatibility_flags.length===0?void 0:`compatibilityFlags: ${r([...e.compatibility_flags])},`,e.triggers?.crons===void 0||e.triggers.crons.length===0?void 0:`crons: ${r([...e.triggers.crons])},`,e.main===void 0?void 0:`entrypoint: ${r(e.main)},`,`name: ${r(n)},`].filter(t=>t!==void 0);return{source:["// GENERATED by @lunora/config from wrangler.jsonc — do not edit.","// Re-generated on every `lunora deploy`; edit wrangler.jsonc instead.","",'import alchemy from "alchemy";',`import { ${[...o].toSorted((t,l)=>t.localeCompare(l)).join(", ")} } from "alchemy/cloudflare";`,"",`const app = await alchemy(${r(n)});`,"",...i.length===0?[]:[...i,""],`export const worker = await Worker(${r(n)}, {`,` ${y.join(`
5
- `)}`,"});","","await app.finalize();",""].join(`
6
- `),unsupported:s}};export{g as sqliteClasses,j as wranglerToAlchemy};
@@ -1 +0,0 @@
1
- import{collectWranglerSecretVariables as c}from"./collectWranglerSecretVariables-DSTHPYsC.mjs";import{writeFileSync as a,renameSync as i,rmSync as n}from"node:fs";const m=r=>({apiSpec:r.apiSpec,lunoraDirectory:r.schemaDirectory??"lunora",projectRoot:r.projectRoot,wranglerVariables:c(r.projectRoot)}),s=(r,t)=>{const o=`${r}.lunora-tmp`;try{a(o,t,"utf8"),i(o,r)}catch(e){throw n(o,{force:!0}),e}};export{m as s,s as w};