@lunora/config 1.0.0-alpha.4 → 1.0.0-alpha.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { ContainerIR, WorkflowIR } from '@lunora/codegen';
1
+ import { ContainerIR, WorkflowIR, QueueIR } from '@lunora/codegen';
2
2
  export type { ContainerIR, WorkflowIR } from '@lunora/codegen';
3
+ import { Writable } from 'node:stream';
3
4
  import 'ts-morph';
4
5
  export { type A as AdditivePolicyEdit, type D as DestructivePolicyEdit, type P as PolicyEdit, type a as PolicyScaffoldFailureReason, type b as ScaffoldFileResult, type S as ScaffoldPolicyEdit, type c as WireResult, type W as WireRlsEdit, d as classifyPolicyEdit, s as scaffoldPolicyFile, w as wireRlsIntoProcedure } from "./packem_shared/policy-scaffold.d-DCmwn7zQ.js";
5
6
  /**
@@ -65,6 +66,77 @@ interface DiscoverContainerInfoResult {
65
66
  * (inference).
66
67
  */
67
68
  declare const discoverContainerInfo: (projectRoot: string, schemaDirectory: string) => DiscoverContainerInfoResult;
69
+ /** Severity a container output line is surfaced at: `stderr` → `error`, `stdout` → `info`. */
70
+ type ContainerLogLevel = "error" | "info";
71
+ /** One declared container to follow, identified by the names codegen lifts from `defineContainer`. */
72
+ interface ContainerLogSource {
73
+ /** Generated Durable Object class name, e.g. `TranscoderContainer`. Wrangler's dev image is `cloudflare-dev/<lowercased>`. */
74
+ className: string;
75
+ /** The `lunora/containers.ts` export name, e.g. `transcoder` — used as the display tag. */
76
+ exportName: string;
77
+ }
78
+ /** A single line of container output handed back to the caller. */
79
+ interface ContainerLogLine {
80
+ /** `"error"` for the container's stderr, `"info"` for its stdout. */
81
+ level: ContainerLogLevel;
82
+ /** The container's export name (`transcoder`), for tagging the line. */
83
+ name: string;
84
+ /** One output line, with the trailing newline (and any `\r`) stripped. */
85
+ text: string;
86
+ }
87
+ interface ContainerLogStreamOptions {
88
+ /** The declared containers to follow. An empty list yields an inert handle. */
89
+ containers: ReadonlyArray<ContainerLogSource>;
90
+ /** Injected Docker client — defaults to a real lazily-imported `dockerode` instance. Tests pass a stub. */
91
+ docker?: DockerLike;
92
+ /** Called once per container output line. */
93
+ onLine: (line: ContainerLogLine) => void;
94
+ /** Called once when the Docker engine can't be reached (re-armed after it recovers). Defaults to silent. */
95
+ onUnavailable?: (message: string) => void;
96
+ /** Poll interval override, in ms. */
97
+ pollIntervalMs?: number;
98
+ }
99
+ /** Handle controlling a running log stream. */
100
+ interface ContainerLogStreamHandle {
101
+ /** Stop polling and tear down every attached log stream. Idempotent. */
102
+ close: () => void;
103
+ }
104
+ /** The minimal structural slice of a `dockerode` log stream this module consumes. */
105
+ interface DockerLogStream {
106
+ destroy: () => void;
107
+ on: (event: "data" | "end" | "error", listener: (chunk?: Buffer) => void) => void;
108
+ }
109
+ /** The minimal structural slice of a `dockerode` instance this module consumes. */
110
+ interface DockerLike {
111
+ getContainer: (id: string) => {
112
+ logs: (options: {
113
+ follow: true;
114
+ stderr: true;
115
+ stdout: true;
116
+ tail: "all";
117
+ timestamps: false;
118
+ }) => Promise<DockerLogStream>;
119
+ };
120
+ listContainers: (options: {
121
+ filters: {
122
+ status: ["running"];
123
+ };
124
+ }) => Promise<{
125
+ Id: string;
126
+ Image: string;
127
+ }[]>;
128
+ modem: {
129
+ demuxStream: (stream: DockerLogStream, stdout: Writable, stderr: Writable) => void;
130
+ };
131
+ }
132
+ /**
133
+ * Follow the local Docker logs of every declared container, emitting each output
134
+ * line through `onLine` tagged with its export name. Polls for containers (they
135
+ * start lazily on first request and may be replaced on restart), attaches once
136
+ * per container id, and drops streams whose container has gone. Returns
137
+ * immediately with a `close()` handle; all work happens asynchronously.
138
+ */
139
+ declare const streamContainerLogs: (options: ContainerLogStreamOptions) => ContainerLogStreamHandle;
68
140
  /**
69
141
  * The meta-frameworks Lunora can compose with, plus `"none"` for a standalone
70
142
  * SPA / SSR-less project (the current default). Mirrors PLAN4 §2.4.
@@ -156,34 +228,52 @@ interface InferredContainer extends ContainerIR {
156
228
  interface InferredWorkflow extends WorkflowIR {
157
229
  exported: boolean;
158
230
  }
231
+ /**
232
+ * A queue declared in `lunora/queues.ts`. Unlike workflows, a queue needs no
233
+ * worker-entry class export (its `queue()` handler rides `createWorker`), so
234
+ * there is no `exported` flag — every declared queue is reconcilable into the
235
+ * wrangler `queues.producers[]` / `queues.consumers[]`.
236
+ */
237
+ type InferredQueue = QueueIR;
159
238
  interface InferredBindings {
160
239
  /** Containers declared in `lunora/containers.ts` (exported or not — see {@link InferredContainer.exported}). */
161
240
  containers: InferredContainer[];
162
241
  /** Durable Objects the worker entry exports → safe to bind. */
163
242
  durableObjects: DurableObjectSpec[];
243
+ /**
244
+ * The wrangler `flagship[].binding` name implied by `lunora/flags.ts` when it
245
+ * uses the Flagship provider in binding mode — `undefined` for HTTP-mode
246
+ * Flagship, a custom OpenFeature provider, or no flags. The binding needs an
247
+ * un-mintable `app_id`, so it is reconciled as a hint, not auto-written.
248
+ */
249
+ flagshipBinding?: string;
164
250
  /** Schema declares a `.global()` table → needs the `DB` D1 binding. */
165
251
  needsD1: boolean;
252
+ /** Queues declared in `lunora/queues.ts` → reconciled into `queues.producers[]` / `queues.consumers[]`. */
253
+ queues: InferredQueue[];
166
254
  /** Human-readable provenance for each inferred binding / hint, for logging. */
167
255
  signals: string[];
168
256
  /** `@lunora/ai` is imported or `env.AI` is used → needs the `ai` Workers AI binding. */
169
257
  usesAi: boolean;
170
- /** `@lunora/analytics` is imported → self-describing `analytics_engine_datasets` binding (auto-writeable). */
258
+ /** `@lunora/bindings/analytics` is imported → self-describing `analytics_engine_datasets` binding (auto-writeable). */
171
259
  usesAnalytics: boolean;
172
260
  /** `@lunora/auth` is imported (sessions may be D1- or `SessionDO`-backed). */
173
261
  usesAuth: boolean;
174
262
  /** `@lunora/browser` is imported → self-describing `browser` binding (auto-writeable). */
175
263
  usesBrowser: boolean;
264
+ /** `lunora/flags.ts` declares a feature-flag provider (any OpenFeature provider — Flagship or custom). */
265
+ usesFlags: boolean;
176
266
  /** `@lunora/hyperdrive` is imported (binding needs an un-mintable remote `id`; hint-only). */
177
267
  usesHyperdrive: boolean;
178
- /** `@lunora/images` is imported → self-describing `images` binding (auto-writeable). */
268
+ /** `@lunora/bindings/images` is imported → self-describing `images` binding (auto-writeable). */
179
269
  usesImages: boolean;
180
- /** `@lunora/kv` is imported (namespace binding name + id are user-defined; hint-only). */
270
+ /** `@lunora/bindings/kv` is imported (namespace binding name + id are user-defined; hint-only). */
181
271
  usesKv: boolean;
182
272
  /** `@lunora/mail` is imported (Resend API key must be set in `.dev.vars`; no binding). */
183
273
  usesMail: boolean;
184
274
  /** `@lunora/payment` is imported (provider secrets must be set in `.dev.vars`; no binding). */
185
275
  usesPayment: boolean;
186
- /** `@lunora/pipelines` is imported (binding needs an un-mintable remote pipeline name; hint-only). */
276
+ /** `ctx.pipelines` is used (binding needs an un-mintable remote pipeline name; hint-only). */
187
277
  usesPipelines: boolean;
188
278
  /** `@lunora/scheduler` is imported. */
189
279
  usesScheduler: boolean;
@@ -288,6 +378,12 @@ declare const LUNORA_EVENT_SOURCE = "lunora";
288
378
  * — so the caller passes the original line through untouched. Pure and total.
289
379
  */
290
380
  declare const formatLunoraEvent: (line: string) => LunoraFormattedLine | undefined;
381
+ declare class LunoraReporter {
382
+ #private;
383
+ setStdout(stdout: NodeJS.WriteStream): void;
384
+ setStderr(stderr: NodeJS.WriteStream): void;
385
+ log(meta: unknown): void;
386
+ }
291
387
  /**
292
388
  * Per-package secret-requirements registry for `.dev.vars` scaffolding.
293
389
  *
@@ -332,6 +428,15 @@ interface SecretEntry {
332
428
  */
333
429
  placeholderValue: string;
334
430
  }
431
+ /**
432
+ * Secrets every Lunora project needs regardless of which capability packages are
433
+ * installed — scaffolded into `.dev.vars` always. `LUNORA_ADMIN_TOKEN` is the
434
+ * bearer the local Studio uses to call the worker's admin endpoints (the data
435
+ * browser, schema edits) in dev; the worker reads the SAME `.dev.vars` value via
436
+ * its admin gate, so both agree and the Studio authenticates without a prompt.
437
+ * Without it, every `/_lunora/admin/*` call is `ADMIN_FORBIDDEN` (403).
438
+ */
439
+
335
440
  /**
336
441
  * The canonical registry of per-package secret requirements.
337
442
  *
@@ -653,6 +758,8 @@ interface RemoteEnableInputs {
653
758
  * is still overridable per-run by `--remote` or `LUNORA_REMOTE=1`.
654
759
  */
655
760
  declare const resolveRemoteEnabled: (inputs: RemoteEnableInputs) => boolean;
761
+ /** Core (always-scaffolded) secrets followed by the package-specific ones for the detected capabilities. */
762
+ declare const requiredSecrets: (packageNames: ReadonlyArray<string>) => SecretEntry[];
656
763
  /**
657
764
  * Whether an (already-unquoted) value looks like a fill-me-in placeholder —
658
765
  * empty, angle-bracketed, or containing a known marker — rather than a real
@@ -661,6 +768,15 @@ declare const resolveRemoteEnabled: (inputs: RemoteEnableInputs) => boolean;
661
768
  */
662
769
  declare const isPlaceholderValue: (value: string) => boolean;
663
770
  /**
771
+ * True for a secret-looking key whose value Lunora can mint locally (a random
772
+ * 32-byte hex, like `openssl rand -hex 32`) — e.g. `AUTH_SECRET`,
773
+ * `LUNORA_ADMIN_TOKEN`, `STORAGE_SIGNING_SECRET`. False for provider-issued keys
774
+ * ({@link PROVIDER_SECRET_KEYS}) and any non-secret key.
775
+ */
776
+ declare const isMintableSecretKey: (key: string) => boolean;
777
+ /** Mint a fresh strong secret value — 64 hex chars (32 bytes), like `openssl rand -hex 32`. */
778
+ declare const generateSecretValue: (randomHex?: (bytes: number) => string) => string;
779
+ /**
664
780
  * The outcome of planning a scaffold — a discriminated union so the orchestrator
665
781
  * never has to re-derive whether `content` is present.
666
782
  *
@@ -762,6 +878,58 @@ declare const buildPackageSecretsBlock: (packageNames: ReadonlyArray<string>, ex
762
878
  * **Safety invariant:** only placeholder values are written — no real secrets.
763
879
  */
764
880
  declare const ensureDevVariablesExample: (cwd: string, packageNames: ReadonlyArray<string>) => string[];
881
+ interface DevSecretsFillPlan {
882
+ /** {@link CORE_SECRETS} keys appended because they were absent (each generated). */
883
+ addedKeys: string[];
884
+ /** The full new file content to write. */
885
+ content: string;
886
+ /** Existing empty/placeholder secret-keyed entries filled with fresh values. */
887
+ filledKeys: string[];
888
+ }
889
+ /**
890
+ * Plan the in-place generation of dev secrets for a `.dev.vars`. First, every
891
+ * line whose KEY looks like a secret (`*_SECRET`, `*_TOKEN`, `*_KEY`,
892
+ * `*_PASSWORD`) and whose value is empty or a placeholder gets a freshly
893
+ * generated value — so a `lunora add`-scaffolded `.dev.vars` (which writes each
894
+ * secret blank) becomes usable on `lunora dev` / `vite dev` without the user
895
+ * running `openssl` by hand. Second, any {@link CORE_SECRETS} key absent from
896
+ * the file is appended (generated) — notably `LUNORA_ADMIN_TOKEN`, which the
897
+ * local Studio needs to call the worker's admin gate in dev (without it the
898
+ * Studio shows its login gate).
899
+ *
900
+ * Pure (given `randomHex`): real (non-placeholder) values are never touched, and
901
+ * comments + non-secret entries are preserved verbatim.
902
+ */
903
+ declare const planDevSecretsFill: (input: {
904
+ existingContent: string;
905
+ randomHex?: (bytes: number) => string;
906
+ }) => DevSecretsFillPlan;
907
+ interface FillDevSecretsResult {
908
+ /** Core secret keys appended (generated) because they were missing. */
909
+ addedKeys: string[];
910
+ /** Existing empty/placeholder secrets filled with generated values. */
911
+ filledKeys: string[];
912
+ /** `created` = no `.dev.vars` existed; `filled` = topped up an existing one; `unchanged` = nothing to do. */
913
+ status: "created" | "filled" | "unchanged";
914
+ }
915
+ /**
916
+ * Generate any missing/empty dev secrets in the project's `.dev.vars`, in place.
917
+ *
918
+ * Complements {@link ensureDevVariables} (which scaffolds `.dev.vars` from
919
+ * `.dev.vars.example`). A `lunora add`-scaffolded project writes secrets blank
920
+ * straight into `.dev.vars` (no example) and never includes `LUNORA_ADMIN_TOKEN`
921
+ * — so the worker boots with empty secrets and the Studio shows its login gate.
922
+ * This fills those gaps at dev startup, so both `lunora dev` and the
923
+ * `@lunora/vite` dev server give a working project with zero manual `openssl`.
924
+ *
925
+ * Never overwrites a real (non-placeholder) value. The write is atomic + owner-
926
+ * only (temp + rename, `mode: 0o600`), matching the other `.dev.vars` writers.
927
+ */
928
+ declare const fillDevSecrets: (deps: {
929
+ cwd: string;
930
+ info?: (message: string) => void;
931
+ randomHex?: (bytes: number) => string;
932
+ }) => FillDevSecretsResult;
765
933
  /** Add a new table to `defineSchema({ ... })`. */
766
934
  interface AddTableEdit {
767
935
  readonly kind: "addTable";
@@ -891,6 +1059,56 @@ interface DiscoverSchemaInfoResult {
891
1059
  * parse failure is a warning (validator) or simply ignorable (inference).
892
1060
  */
893
1061
  declare const discoverSchemaInfo: (projectRoot: string, schemaDirectory: string) => DiscoverSchemaInfoResult;
1062
+ /**
1063
+ * A badge: the short colored label that prefixes a line. `bg`/`fg` are hex so the
1064
+ * same value drives both colorize's `bgHex().hex()` and the tui `&lt;Text>` props.
1065
+ */
1066
+ interface BadgeSpec {
1067
+ bg: `#${string}`;
1068
+ fg: `#${string}`;
1069
+ text: string;
1070
+ }
1071
+ /** Lunora purple — the accent shared with the CLI prompt frames. */
1072
+ declare const ACCENT: `#${string}`;
1073
+ /** Standard log-level badge names (the restyled base output). */
1074
+ type LevelBadgeName = "debug" | "error" | "info" | "success" | "warn";
1075
+ /** Step-phase badge names (the create-astro-style flow transcript). */
1076
+ type StepBadgeName = "add" | "deps" | "dir" | "git" | "lunora" | "next" | "tmpl";
1077
+ type BadgeName = LevelBadgeName | StepBadgeName;
1078
+ /** The ordered step-phase names, used to register custom pail log types. */
1079
+ declare const STEP_BADGE_NAMES: ReadonlyArray<StepBadgeName>;
1080
+ /**
1081
+ * Every badge, keyed by name. Levels get their conventional colors (red/amber/
1082
+ * green/blue/grey); step phases follow create-astro's green→purple→cyan rhythm.
1083
+ */
1084
+ declare const BADGES: Record<BadgeName, BadgeSpec>;
1085
+ /**
1086
+ * Luna, the mascot: the folklore rabbit-in-the-moon — a bunny tucked inside the
1087
+ * moon disc. Pure ASCII so it renders the same everywhere (including piped logs).
1088
+ * The CLI signs off the `init` flow with it, the way create-astro closes with
1089
+ * Houston.
1090
+ */
1091
+ declare const LUNA_NAME = "Luna";
1092
+ declare const LUNA_SIGNOFF = "Safe travels, voyager.";
1093
+ declare const LUNA_BUNNY: string;
1094
+ /**
1095
+ * {@link LUNA_BUNNY} with its leading newline stripped, ready to render inline
1096
+ * (beside the name + sign-off). Both render paths — the tui mascot frame and the
1097
+ * pail off-TTY fallback — use this so neither re-implements the strip.
1098
+ */
1099
+ declare const LUNA_ART: string;
1100
+ /** The colored part of a badge — the word with one space of padding each side. */
1101
+ declare const padBadge: (text: string) => string;
1102
+ /** Leading spaces that right-align a badge's box within the gutter. */
1103
+ declare const badgeLead: (text: string) => string;
1104
+ /** Total columns a rendered badge column occupies (lead + box), constant across badges. */
1105
+ declare const BADGE_COLUMN_WIDTH: number;
1106
+ /** Columns a rendered badge occupies — the gutter-aligned column width. */
1107
+ declare const badgeWidth: (_spec: BadgeSpec) => number;
1108
+ /** Paint a badge as an ANSI string (the non-tui path): right-aligning spaces + the colored box. */
1109
+ declare const paintBadge: (spec: BadgeSpec) => string;
1110
+ /** Dim continuation text (a step's chosen answer, shown under the question). */
1111
+ declare const paintAnswer: (text: string) => string;
894
1112
  /** Candidate wrangler config filenames, in the order every consumer probes them. */
895
1113
  declare const WRANGLER_FILES: readonly ["wrangler.jsonc", "wrangler.json"];
896
1114
  /** Locate the project's wrangler config, or `undefined` when none exists. */
@@ -946,6 +1164,22 @@ interface WranglerWorkflowEntry {
946
1164
  class_name?: string;
947
1165
  name?: string;
948
1166
  }
1167
+ /** A wrangler `queues.producers[]` entry — a `Queue` binding sending to `queue`. */
1168
+ interface WranglerQueueProducer {
1169
+ binding?: string;
1170
+ delivery_delay?: number;
1171
+ queue?: string;
1172
+ }
1173
+ /** A wrangler `queues.consumers[]` entry — push (worker) or `type: "http_pull"`. */
1174
+ interface WranglerQueueConsumer {
1175
+ dead_letter_queue?: string;
1176
+ max_batch_size?: number;
1177
+ max_batch_timeout?: number;
1178
+ max_retries?: number;
1179
+ queue?: string;
1180
+ retry_delay?: number;
1181
+ type?: string;
1182
+ }
949
1183
  interface WranglerConfig {
950
1184
  analytics_engine_datasets?: ReadonlyArray<{
951
1185
  binding?: string;
@@ -974,6 +1208,10 @@ interface WranglerConfig {
974
1208
  durable_objects?: {
975
1209
  bindings?: ReadonlyArray<WranglerDurableObjectBinding>;
976
1210
  };
1211
+ flagship?: ReadonlyArray<{
1212
+ app_id?: string;
1213
+ binding?: string;
1214
+ } | null | undefined>;
977
1215
  hyperdrive?: ReadonlyArray<{
978
1216
  binding?: string;
979
1217
  id?: string;
@@ -1010,9 +1248,18 @@ interface WranglerConfig {
1010
1248
  placement?: {
1011
1249
  mode?: string;
1012
1250
  };
1251
+ queues?: {
1252
+ consumers?: ReadonlyArray<WranglerQueueConsumer | null | undefined>;
1253
+ producers?: ReadonlyArray<WranglerQueueProducer | null | undefined>;
1254
+ };
1013
1255
  r2_buckets?: ReadonlyArray<{
1014
1256
  binding?: string;
1015
1257
  }>;
1258
+ secrets_store_secrets?: ReadonlyArray<{
1259
+ binding?: string;
1260
+ secret_name?: string;
1261
+ store_id?: string;
1262
+ } | null | undefined>;
1016
1263
  send_email?: ReadonlyArray<{
1017
1264
  allowed_destination_addresses?: ReadonlyArray<string>;
1018
1265
  destination_address?: string;
@@ -1072,4 +1319,4 @@ interface WranglerProjectValidationResult {
1072
1319
  * `{ problems, wranglerPath }` shape plus the structured `report`.
1073
1320
  */
1074
1321
  declare const validateWranglerProject: (options: WranglerProjectValidationOptions) => WranglerProjectValidationResult;
1075
- export { AGENT_RULES_DIR, AGENT_RULES_HINT, AGENT_RULES_HINT_ENV, type AddIndexEdit, type AddOptionalColumnEdit, type AddTableEdit, type AdditiveEdit, type AgentRulesStatus, type ApplyEditResult, type ApplyFailureReason, type AugmentPlan, DEV_VARS_EXAMPLE_FILE, DEV_VARS_FILE, DEV_VARS_KEY_PATTERN, type DestructiveEdit, type DetectedFramework, type DiscoverContainerInfoResult, type DiscoverSchemaInfoResult, type DiscoverWorkflowInfoResult, type EnsureDevVariablesDeps, type EnsureDevVariablesResult, type EnsureDevVariablesStatus, type ExportGap, type FrameworkClass, type FrameworkDetection, type InferOptions, type InferredBindings, type InferredContainer, type InferredWorkflow, LINKED_PROJECT_DIR, LINKED_PROJECT_FILE, LUNORA_CONFIG_FILE, LUNORA_EVENT_SOURCE, LUNORA_SKILL_NAMES, type LinkedProject, type LunoraFormattedLine, type LunoraLineLevel, type LunoraProjectConfig, type MaterializeOptions, type MaterializeResult, type MultiSelectOption, PACKAGE_SECRETS_REGISTRY, type ParseSchemaResult, REMOTE_ELIGIBLE_KEYS, REQUIRED_COMPATIBILITY_DATE, REQUIRED_FLAG, ROOT_SKILL_NAME, type ReadWranglerResult, type ReconcileBindingsResult, type RemoteBindingPlan, type RemoteEnableInputs, type RemotePreference, type RemoteWranglerShape, type ScaffoldPlan, type SchemaColumn, type SchemaEdit, type SchemaIndex, type SchemaInfo, type SchemaTable, type SecretEntry, type SelectOption, type TailConsumer, WRANGLER_FILES, type WranglerConfig, type WranglerContainerEntry, type WranglerProjectValidationOptions, type WranglerProjectValidationResult, type WranglerValidationReport, type WranglerWorkflowEntry, applyAdditiveEdit, buildPackageSecretsBlock, claimAgentRulesHint, classifyEdit, createConfirm, detectAgentRules, detectFramework, discoverContainerInfo, discoverSchemaInfo, discoverWorkflowInfo, ensureDevVariables, ensureDevVariablesExample as ensureDevVarsExample, findWranglerFile, formatLunoraEvent, inferLunoraBindings, injectRemoteFlags, interpretRemote, isInteractive, isPlaceholderValue, isRemoteEnvEnabled, materializeRemoteWranglerConfig, packageNamesFromBindings, parseDevVariableEntries, parseSchema, planDevVariablesAugment, planDevVariablesScaffold, planRemoteBindings, promptMultiSelect, promptSelect, promptYesNo, readLinkedProject, readProjectRemotePreference, readWranglerJsonc, reconcileWranglerBindings, resolveRemoteEnabled, secretsForPackages, validateWrangler, validateWranglerConfig, validateWranglerProject, withTailConsumer, writeLinkedProject };
1322
+ export { ACCENT, AGENT_RULES_DIR, AGENT_RULES_HINT, AGENT_RULES_HINT_ENV, type AddIndexEdit, type AddOptionalColumnEdit, type AddTableEdit, type AdditiveEdit, type AgentRulesStatus, type ApplyEditResult, type ApplyFailureReason, type AugmentPlan, BADGES, BADGE_COLUMN_WIDTH, type BadgeName, type BadgeSpec, type ContainerLogLevel, type ContainerLogLine, type ContainerLogSource, type ContainerLogStreamHandle, type ContainerLogStreamOptions, DEV_VARS_EXAMPLE_FILE, DEV_VARS_FILE, DEV_VARS_KEY_PATTERN, type DestructiveEdit, type DetectedFramework, type DevSecretsFillPlan, type DiscoverContainerInfoResult, type DiscoverSchemaInfoResult, type DiscoverWorkflowInfoResult, type DockerLike, type EnsureDevVariablesDeps, type EnsureDevVariablesResult, type EnsureDevVariablesStatus, type ExportGap, type FillDevSecretsResult, type FrameworkClass, type FrameworkDetection, type InferOptions, type InferredBindings, type InferredContainer, type InferredWorkflow, LINKED_PROJECT_DIR, LINKED_PROJECT_FILE, LUNA_ART, LUNA_BUNNY, LUNA_NAME, LUNA_SIGNOFF, LUNORA_CONFIG_FILE, LUNORA_EVENT_SOURCE, LUNORA_SKILL_NAMES, type LevelBadgeName, type LinkedProject, type LunoraFormattedLine, type LunoraLineLevel, type LunoraProjectConfig, LunoraReporter, type MaterializeOptions, type MaterializeResult, type MultiSelectOption, PACKAGE_SECRETS_REGISTRY, type ParseSchemaResult, REMOTE_ELIGIBLE_KEYS, REQUIRED_COMPATIBILITY_DATE, REQUIRED_FLAG, ROOT_SKILL_NAME, type ReadWranglerResult, type ReconcileBindingsResult, type RemoteBindingPlan, type RemoteEnableInputs, type RemotePreference, type RemoteWranglerShape, STEP_BADGE_NAMES, type ScaffoldPlan, type SchemaColumn, type SchemaEdit, type SchemaIndex, type SchemaInfo, type SchemaTable, type SecretEntry, type SelectOption, type StepBadgeName, type TailConsumer, WRANGLER_FILES, type WranglerConfig, type WranglerContainerEntry, type WranglerProjectValidationOptions, type WranglerProjectValidationResult, type WranglerValidationReport, type WranglerWorkflowEntry, applyAdditiveEdit, badgeLead, badgeWidth, buildPackageSecretsBlock, claimAgentRulesHint, classifyEdit, createConfirm, detectAgentRules, detectFramework, discoverContainerInfo, discoverSchemaInfo, discoverWorkflowInfo, ensureDevVariables, ensureDevVariablesExample as ensureDevVarsExample, fillDevSecrets, findWranglerFile, formatLunoraEvent, generateSecretValue, inferLunoraBindings, injectRemoteFlags, interpretRemote, isInteractive, isMintableSecretKey, isPlaceholderValue, isRemoteEnvEnabled, materializeRemoteWranglerConfig, packageNamesFromBindings, padBadge, paintAnswer, paintBadge, parseDevVariableEntries, parseSchema, planDevSecretsFill, planDevVariablesAugment, planDevVariablesScaffold, planRemoteBindings, promptMultiSelect, promptSelect, promptYesNo, readLinkedProject, readProjectRemotePreference, readWranglerJsonc, reconcileWranglerBindings, requiredSecrets, resolveRemoteEnabled, secretsForPackages, streamContainerLogs, validateWrangler, validateWranglerConfig, validateWranglerProject, withTailConsumer, writeLinkedProject };
package/dist/index.mjs CHANGED
@@ -1,20 +1,23 @@
1
1
  export { AGENT_RULES_DIR, AGENT_RULES_HINT, AGENT_RULES_HINT_ENV, LUNORA_SKILL_NAMES, ROOT_SKILL_NAME, claimAgentRulesHint, detectAgentRules } from './packem_shared/AGENT_RULES_DIR-lcgC08aE.mjs';
2
2
  export { discoverContainerInfo } from './packem_shared/discoverContainerInfo-BXFs6Wav.mjs';
3
+ export { streamContainerLogs } from './packem_shared/streamContainerLogs-BZ4cOZwH.mjs';
3
4
  export { detectFramework } from './packem_shared/detectFramework-Br-BcPBq.mjs';
4
5
  export { DEV_VARS_EXAMPLE_FILE, DEV_VARS_FILE, DEV_VARS_KEY_PATTERN, parseDevVariableEntries } from './packem_shared/DEV_VARS_EXAMPLE_FILE-dJPNTEnK.mjs';
5
- export { inferLunoraBindings, packageNamesFromBindings } from './packem_shared/inferLunoraBindings-XNJH4pup.mjs';
6
+ export { inferLunoraBindings, packageNamesFromBindings } from './packem_shared/inferLunoraBindings-ByMwG-gH.mjs';
6
7
  export { LINKED_PROJECT_DIR, LINKED_PROJECT_FILE, readLinkedProject, writeLinkedProject } from './packem_shared/LINKED_PROJECT_DIR-CXwXzV_C.mjs';
7
8
  export { LUNORA_EVENT_SOURCE, formatLunoraEvent } from './packem_shared/LUNORA_EVENT_SOURCE-D2fDeGB6.mjs';
8
- export { PACKAGE_SECRETS_REGISTRY, secretsForPackages } from './packem_shared/PACKAGE_SECRETS_REGISTRY-CySy5vR_.mjs';
9
+ export { default as LunoraReporter } from './packem_shared/LunoraReporter-Ci-bDCK9.mjs';
10
+ export { PACKAGE_SECRETS_REGISTRY, secretsForPackages } from './packem_shared/PACKAGE_SECRETS_REGISTRY-B8t_SdoZ.mjs';
9
11
  export { LUNORA_CONFIG_FILE, interpretRemote, readProjectRemotePreference } from './packem_shared/LUNORA_CONFIG_FILE-CtcIcB5-.mjs';
10
12
  export { createConfirm, isInteractive, promptMultiSelect, promptSelect, promptYesNo } from './packem_shared/createConfirm-fvpdgJ9s.mjs';
11
- export { reconcileWranglerBindings } from './packem_shared/reconcileWranglerBindings-DTHmqTbL.mjs';
13
+ export { reconcileWranglerBindings } from './packem_shared/reconcileWranglerBindings-Cruwwx1M.mjs';
12
14
  export { REMOTE_ELIGIBLE_KEYS, injectRemoteFlags, isRemoteEnvEnabled, materializeRemoteWranglerConfig, planRemoteBindings, resolveRemoteEnabled } from './packem_shared/REMOTE_ELIGIBLE_KEYS-BC7_e9Bz.mjs';
13
- export { buildPackageSecretsBlock, ensureDevVariables, ensureDevVarsExample, isPlaceholderValue, planDevVariablesAugment, planDevVariablesScaffold } from './packem_shared/buildPackageSecretsBlock-S74dgmwy.mjs';
15
+ export { buildPackageSecretsBlock, ensureDevVariables, ensureDevVarsExample, fillDevSecrets, generateSecretValue, isMintableSecretKey, isPlaceholderValue, planDevSecretsFill, planDevVariablesAugment, planDevVariablesScaffold, requiredSecrets } from './packem_shared/buildPackageSecretsBlock-BCHtfQ2A.mjs';
14
16
  export { applyAdditiveEdit, classifyEdit } from './packem_shared/applyAdditiveEdit-C-snTFEV.mjs';
15
17
  export { parseSchema } from './packem_shared/parseSchema-DSeyktvG.mjs';
16
18
  export { classifyPolicyEdit, scaffoldPolicyFile, wireRlsIntoProcedure } from './packem_shared/classifyPolicyEdit-BHeAqF8P.mjs';
17
- export { discoverSchemaInfo } from './packem_shared/discoverSchemaInfo-DWtypqpP.mjs';
19
+ export { discoverSchemaInfo } from './packem_shared/discoverSchemaInfo-BB-CKlTK.mjs';
20
+ export { ACCENT, BADGES, BADGE_COLUMN_WIDTH, LUNA_ART, LUNA_BUNNY, LUNA_NAME, LUNA_SIGNOFF, STEP_BADGE_NAMES, badgeLead, badgeWidth, padBadge, paintAnswer, paintBadge } from './packem_shared/ACCENT-DW1XJn8i.mjs';
18
21
  export { discoverWorkflowInfo } from './packem_shared/discoverWorkflowInfo-CedvR0mn.mjs';
19
22
  export { WRANGLER_FILES, findWranglerFile, readWranglerJsonc } from './packem_shared/WRANGLER_FILES-DwSuC-Kn.mjs';
20
- export { REQUIRED_COMPATIBILITY_DATE, REQUIRED_FLAG, validateWrangler, validateWranglerConfig, validateWranglerProject, withTailConsumer } from './packem_shared/REQUIRED_COMPATIBILITY_DATE-ycqievRl.mjs';
23
+ export { REQUIRED_COMPATIBILITY_DATE, REQUIRED_FLAG, validateWrangler, validateWranglerConfig, validateWranglerProject, withTailConsumer } from './packem_shared/REQUIRED_COMPATIBILITY_DATE-2YYyWJUq.mjs';
@@ -0,0 +1,40 @@
1
+ import colorize from '@visulima/colorize';
2
+
3
+ const ACCENT = "#a855f7";
4
+ const INK = "#0b0b0b";
5
+ const STEP_BADGE_NAMES = ["lunora", "dir", "tmpl", "add", "deps", "git", "next"];
6
+ const BADGES = {
7
+ add: { bg: ACCENT, fg: INK, text: "add" },
8
+ debug: { bg: "#6b7280", fg: "#f3f4f6", text: "debug" },
9
+ deps: { bg: ACCENT, fg: INK, text: "deps" },
10
+ dir: { bg: ACCENT, fg: INK, text: "dir" },
11
+ error: { bg: "#ef4444", fg: INK, text: "error" },
12
+ git: { bg: "#f59e0b", fg: INK, text: "git" },
13
+ info: { bg: "#3b82f6", fg: INK, text: "info" },
14
+ lunora: { bg: "#22c55e", fg: INK, text: "lunora" },
15
+ next: { bg: "#06b6d4", fg: INK, text: "next" },
16
+ success: { bg: "#22c55e", fg: INK, text: "ok" },
17
+ tmpl: { bg: ACCENT, fg: INK, text: "tmpl" },
18
+ warn: { bg: "#f59e0b", fg: INK, text: "warn" }
19
+ };
20
+ const LUNA_NAME = "Luna";
21
+ const LUNA_SIGNOFF = "Safe travels, voyager.";
22
+ const LUNA_BUNNY = String.raw`
23
+ .-"""""-.
24
+ / (\(\ \
25
+ | ( -.-) |
26
+ \ o(")(") /
27
+ '-._____.-'`;
28
+ const LUNA_ART = LUNA_BUNNY.startsWith("\n") ? LUNA_BUNNY.slice(1) : LUNA_BUNNY;
29
+ const BADGE_GUTTER = 6;
30
+ const padBadge = (text) => ` ${text} `;
31
+ const badgeLead = (text) => " ".repeat(Math.max(0, BADGE_GUTTER - text.length));
32
+ const BADGE_COLUMN_WIDTH = BADGE_GUTTER + 2;
33
+ const badgeWidth = (_spec) => BADGE_COLUMN_WIDTH;
34
+ const paintBadge = (spec) => (
35
+ // eslint-disable-next-line import/no-named-as-default-member -- see file header.
36
+ badgeLead(spec.text) + colorize.bgHex(spec.bg).hex(spec.fg).bold(padBadge(spec.text))
37
+ );
38
+ const paintAnswer = (text) => colorize.dim(text);
39
+
40
+ export { ACCENT, BADGES, BADGE_COLUMN_WIDTH, LUNA_ART, LUNA_BUNNY, LUNA_NAME, LUNA_SIGNOFF, STEP_BADGE_NAMES, badgeLead, badgeWidth, padBadge, paintAnswer, paintBadge };
@@ -0,0 +1,70 @@
1
+ import { paintBadge, badgeWidth, BADGES } from './ACCENT-DW1XJn8i.mjs';
2
+
3
+ const NAME_ALIASES = {
4
+ informational: "info",
5
+ warning: "warn"
6
+ };
7
+ const STDERR_LEVELS = /* @__PURE__ */ new Set(["alert", "critical", "emergency", "error", "warn", "warning"]);
8
+ const resolveBadge = (name) => {
9
+ if (name in BADGES) {
10
+ return BADGES[name];
11
+ }
12
+ const alias = NAME_ALIASES[name];
13
+ return alias === void 0 ? void 0 : BADGES[alias];
14
+ };
15
+ const renderContextArgument = (value) => {
16
+ if (value instanceof Error) {
17
+ return `
18
+ ${value.stack ?? value.message}`;
19
+ }
20
+ if (typeof value === "object" && value !== null) {
21
+ try {
22
+ return ` ${JSON.stringify(value)}`;
23
+ } catch {
24
+ return " [unserializable]";
25
+ }
26
+ }
27
+ return ` ${String(value)}`;
28
+ };
29
+ const composeMessage = (meta) => {
30
+ const base = typeof meta.message === "string" ? meta.message : String(meta.message);
31
+ const context = meta.context ?? [];
32
+ return context.length === 0 ? base : base + context.map((value) => renderContextArgument(value)).join("");
33
+ };
34
+ class LunoraReporter {
35
+ #stdout = process.stdout;
36
+ #stderr = process.stderr;
37
+ setStdout(stdout) {
38
+ this.#stdout = stdout;
39
+ }
40
+ setStderr(stderr) {
41
+ this.#stderr = stderr;
42
+ }
43
+ // Note: pail's other reporter setters (setLoggerTypes / setInteractiveManager /
44
+ // setIsInteractive) are optional and intentionally omitted — this reporter keeps
45
+ // no type or interactive state; it only needs the two stream setters above.
46
+ log(meta) {
47
+ const data = meta;
48
+ const badge = resolveBadge(data.type.name);
49
+ const stream = STDERR_LEVELS.has(data.type.level ?? data.type.name) ? this.#stderr : this.#stdout;
50
+ stream.write(LunoraReporter.#render(badge, composeMessage(data)));
51
+ }
52
+ /**
53
+ * Frame `text` under `badge`: `&lt;badge> &lt;first line>`, with any further lines
54
+ * indented to align beneath the message. Without a badge (unknown type) the
55
+ * message is written plain.
56
+ */
57
+ static #render(badge, text) {
58
+ if (badge === void 0) {
59
+ return `${text}
60
+ `;
61
+ }
62
+ const [first = "", ...rest] = text.split("\n");
63
+ const indent = " ".repeat(badgeWidth() + 1);
64
+ const lines = [`${paintBadge(badge)} ${first}`, ...rest.map((line) => `${indent}${line}`)];
65
+ return `${lines.join("\n")}
66
+ `;
67
+ }
68
+ }
69
+
70
+ export { LunoraReporter as default };
@@ -1,3 +1,11 @@
1
+ const CORE_SECRETS = [
2
+ {
3
+ 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",
4
+ docsUrl: "https://lunora.sh/docs/packages/studio",
5
+ key: "LUNORA_ADMIN_TOKEN",
6
+ placeholderValue: "replace-with-openssl-rand-hex-32"
7
+ }
8
+ ];
1
9
  const PACKAGE_SECRETS_REGISTRY = {
2
10
  "@lunora/auth": [
3
11
  {
@@ -59,4 +67,4 @@ const secretsForPackages = (packageNames) => {
59
67
  return result;
60
68
  };
61
69
 
62
- export { PACKAGE_SECRETS_REGISTRY, secretsForPackages };
70
+ export { CORE_SECRETS, PACKAGE_SECRETS_REGISTRY, secretsForPackages };
@@ -1,6 +1,6 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { dirname, join } from 'node:path';
3
- import { discoverSchemaInfo } from './discoverSchemaInfo-DWtypqpP.mjs';
3
+ import { discoverSchemaInfo } from './discoverSchemaInfo-BB-CKlTK.mjs';
4
4
  import { findWranglerFile, readWranglerJsonc } from './WRANGLER_FILES-DwSuC-Kn.mjs';
5
5
 
6
6
  const REQUIRED_COMPATIBILITY_DATE = "2026-04-07";
@@ -127,6 +127,82 @@ const validateWorkflows = (wrangler, errors) => {
127
127
  }
128
128
  }
129
129
  };
130
+ const validateQueueProducers = (producers, errors) => {
131
+ if (producers === void 0) {
132
+ return;
133
+ }
134
+ if (!Array.isArray(producers)) {
135
+ errors.push("queues.producers must be an array of { binding, queue } entries");
136
+ return;
137
+ }
138
+ const entries = producers;
139
+ for (const [index, entry] of entries.entries()) {
140
+ const label = `queues.producers[${String(index)}]`;
141
+ if (!entry || typeof entry !== "object") {
142
+ errors.push(`${label} must be a { binding, queue } object`);
143
+ continue;
144
+ }
145
+ if (typeof entry.binding !== "string" || entry.binding.length === 0) {
146
+ errors.push(`${label} must have a non-empty "binding" naming the Queue producer (e.g. QUEUE_EMAIL)`);
147
+ }
148
+ if (typeof entry.queue !== "string" || entry.queue.length === 0) {
149
+ errors.push(`${label} must have a non-empty "queue" naming the deployed queue`);
150
+ }
151
+ }
152
+ };
153
+ const validateQueueConsumers = (consumers, errors) => {
154
+ if (consumers === void 0) {
155
+ return;
156
+ }
157
+ if (!Array.isArray(consumers)) {
158
+ errors.push("queues.consumers must be an array of { queue } entries");
159
+ return;
160
+ }
161
+ const entries = consumers;
162
+ for (const [index, entry] of entries.entries()) {
163
+ const label = `queues.consumers[${String(index)}]`;
164
+ if (!entry || typeof entry !== "object") {
165
+ errors.push(`${label} must be a { queue } object`);
166
+ continue;
167
+ }
168
+ if (typeof entry.queue !== "string" || entry.queue.length === 0) {
169
+ errors.push(`${label} must have a non-empty "queue" naming the consumed queue`);
170
+ }
171
+ }
172
+ };
173
+ const validateQueues = (wrangler, errors) => {
174
+ if (wrangler.queues === void 0) {
175
+ return;
176
+ }
177
+ if (typeof wrangler.queues !== "object" || Array.isArray(wrangler.queues)) {
178
+ errors.push("queues must be a { producers, consumers } object");
179
+ return;
180
+ }
181
+ validateQueueProducers(wrangler.queues.producers, errors);
182
+ validateQueueConsumers(wrangler.queues.consumers, errors);
183
+ };
184
+ const validateSecretsStore = (wrangler, errors) => {
185
+ if (wrangler.secrets_store_secrets === void 0) {
186
+ return;
187
+ }
188
+ if (!Array.isArray(wrangler.secrets_store_secrets)) {
189
+ errors.push("secrets_store_secrets must be an array of { binding, store_id, secret_name } entries");
190
+ return;
191
+ }
192
+ const entries = wrangler.secrets_store_secrets;
193
+ for (const [index, entry] of entries.entries()) {
194
+ const label = `secrets_store_secrets[${String(index)}]`;
195
+ if (!entry || typeof entry !== "object") {
196
+ errors.push(`${label} must be a { binding, store_id, secret_name } object`);
197
+ continue;
198
+ }
199
+ for (const field of ["binding", "store_id", "secret_name"]) {
200
+ if (typeof entry[field] !== "string" || entry[field].length === 0) {
201
+ errors.push(`${label} must have a non-empty "${field}"`);
202
+ }
203
+ }
204
+ }
205
+ };
130
206
  const isNonEmptyString = (value) => typeof value === "string" && value.length > 0;
131
207
  const asBindingEntries = (value) => value;
132
208
  const HINT_BINDING_RULES = [
@@ -137,6 +213,13 @@ const HINT_BINDING_RULES = [
137
213
  hintMessage: (label, binding) => `${label} ("${binding}") has no "id" — run \`wrangler kv namespace create\` and set the namespace id, or the binding can't resolve`,
138
214
  key: "kv_namespaces"
139
215
  },
216
+ {
217
+ arrayMessage: "flagship must be an array of { binding, app_id } entries",
218
+ bindingMessage: (label) => `${label} must have a non-empty "binding" naming the Flagship binding`,
219
+ hintField: "app_id",
220
+ hintMessage: (label, binding) => `${label} ("${binding}") has no "app_id" — create a Flagship app and set its id, or the binding can't resolve`,
221
+ key: "flagship"
222
+ },
140
223
  {
141
224
  arrayMessage: "hyperdrive must be an array of { binding, id } entries",
142
225
  bindingMessage: (label) => `${label} must have a non-empty "binding" naming the Hyperdrive binding`,
@@ -398,6 +481,8 @@ const validateWranglerConfig = (wrangler, schema) => {
398
481
  validateTailConsumers(wrangler, errors);
399
482
  validateContainers(wrangler, errors, warnings);
400
483
  validateWorkflows(wrangler, errors);
484
+ validateQueues(wrangler, errors);
485
+ validateSecretsStore(wrangler, errors);
401
486
  for (const rule of HINT_BINDING_RULES) {
402
487
  validateHintBinding(wrangler, rule, errors, warnings);
403
488
  }