@lunora/config 1.0.0-alpha.16 → 1.0.0-alpha.17
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.mts +39 -5
- package/dist/index.d.ts +39 -5
- package/dist/index.mjs +3 -3
- package/dist/packem_shared/{REQUIRED_COMPATIBILITY_DATE-DRSNSOOp.mjs → REQUIRED_COMPATIBILITY_DATE-USQQ7NfE.mjs} +78 -0
- package/dist/packem_shared/{inferLunoraBindings-DIku9mTN.mjs → inferLunoraBindings-b9SJwb2s.mjs} +37 -10
- package/dist/packem_shared/{reconcileWranglerBindings-DTHmqTbL.mjs → reconcileWranglerBindings-27af-Qvt.mjs} +55 -3
- package/package.json +6 -6
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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
3
|
import 'ts-morph';
|
|
4
4
|
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.mjs";
|
|
@@ -156,6 +156,13 @@ interface InferredContainer extends ContainerIR {
|
|
|
156
156
|
interface InferredWorkflow extends WorkflowIR {
|
|
157
157
|
exported: boolean;
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* A queue declared in `lunora/queues.ts`. Unlike workflows, a queue needs no
|
|
161
|
+
* worker-entry class export (its `queue()` handler rides `createWorker`), so
|
|
162
|
+
* there is no `exported` flag — every declared queue is reconcilable into the
|
|
163
|
+
* wrangler `queues.producers[]` / `queues.consumers[]`.
|
|
164
|
+
*/
|
|
165
|
+
type InferredQueue = QueueIR;
|
|
159
166
|
interface InferredBindings {
|
|
160
167
|
/** Containers declared in `lunora/containers.ts` (exported or not — see {@link InferredContainer.exported}). */
|
|
161
168
|
containers: InferredContainer[];
|
|
@@ -163,11 +170,13 @@ interface InferredBindings {
|
|
|
163
170
|
durableObjects: DurableObjectSpec[];
|
|
164
171
|
/** Schema declares a `.global()` table → needs the `DB` D1 binding. */
|
|
165
172
|
needsD1: boolean;
|
|
173
|
+
/** Queues declared in `lunora/queues.ts` → reconciled into `queues.producers[]` / `queues.consumers[]`. */
|
|
174
|
+
queues: InferredQueue[];
|
|
166
175
|
/** Human-readable provenance for each inferred binding / hint, for logging. */
|
|
167
176
|
signals: string[];
|
|
168
177
|
/** `@lunora/ai` is imported or `env.AI` is used → needs the `ai` Workers AI binding. */
|
|
169
178
|
usesAi: boolean;
|
|
170
|
-
/** `@lunora/analytics` is imported → self-describing `analytics_engine_datasets` binding (auto-writeable). */
|
|
179
|
+
/** `@lunora/bindings/analytics` is imported → self-describing `analytics_engine_datasets` binding (auto-writeable). */
|
|
171
180
|
usesAnalytics: boolean;
|
|
172
181
|
/** `@lunora/auth` is imported (sessions may be D1- or `SessionDO`-backed). */
|
|
173
182
|
usesAuth: boolean;
|
|
@@ -175,15 +184,15 @@ interface InferredBindings {
|
|
|
175
184
|
usesBrowser: boolean;
|
|
176
185
|
/** `@lunora/hyperdrive` is imported (binding needs an un-mintable remote `id`; hint-only). */
|
|
177
186
|
usesHyperdrive: boolean;
|
|
178
|
-
/** `@lunora/images` is imported → self-describing `images` binding (auto-writeable). */
|
|
187
|
+
/** `@lunora/bindings/images` is imported → self-describing `images` binding (auto-writeable). */
|
|
179
188
|
usesImages: boolean;
|
|
180
|
-
/** `@lunora/kv` is imported (namespace binding name + id are user-defined; hint-only). */
|
|
189
|
+
/** `@lunora/bindings/kv` is imported (namespace binding name + id are user-defined; hint-only). */
|
|
181
190
|
usesKv: boolean;
|
|
182
191
|
/** `@lunora/mail` is imported (Resend API key must be set in `.dev.vars`; no binding). */
|
|
183
192
|
usesMail: boolean;
|
|
184
193
|
/** `@lunora/payment` is imported (provider secrets must be set in `.dev.vars`; no binding). */
|
|
185
194
|
usesPayment: boolean;
|
|
186
|
-
/**
|
|
195
|
+
/** `ctx.pipelines` is used (binding needs an un-mintable remote pipeline name; hint-only). */
|
|
187
196
|
usesPipelines: boolean;
|
|
188
197
|
/** `@lunora/scheduler` is imported. */
|
|
189
198
|
usesScheduler: boolean;
|
|
@@ -1074,6 +1083,22 @@ interface WranglerWorkflowEntry {
|
|
|
1074
1083
|
class_name?: string;
|
|
1075
1084
|
name?: string;
|
|
1076
1085
|
}
|
|
1086
|
+
/** A wrangler `queues.producers[]` entry — a `Queue` binding sending to `queue`. */
|
|
1087
|
+
interface WranglerQueueProducer {
|
|
1088
|
+
binding?: string;
|
|
1089
|
+
delivery_delay?: number;
|
|
1090
|
+
queue?: string;
|
|
1091
|
+
}
|
|
1092
|
+
/** A wrangler `queues.consumers[]` entry — push (worker) or `type: "http_pull"`. */
|
|
1093
|
+
interface WranglerQueueConsumer {
|
|
1094
|
+
dead_letter_queue?: string;
|
|
1095
|
+
max_batch_size?: number;
|
|
1096
|
+
max_batch_timeout?: number;
|
|
1097
|
+
max_retries?: number;
|
|
1098
|
+
queue?: string;
|
|
1099
|
+
retry_delay?: number;
|
|
1100
|
+
type?: string;
|
|
1101
|
+
}
|
|
1077
1102
|
interface WranglerConfig {
|
|
1078
1103
|
analytics_engine_datasets?: ReadonlyArray<{
|
|
1079
1104
|
binding?: string;
|
|
@@ -1138,9 +1163,18 @@ interface WranglerConfig {
|
|
|
1138
1163
|
placement?: {
|
|
1139
1164
|
mode?: string;
|
|
1140
1165
|
};
|
|
1166
|
+
queues?: {
|
|
1167
|
+
consumers?: ReadonlyArray<WranglerQueueConsumer | null | undefined>;
|
|
1168
|
+
producers?: ReadonlyArray<WranglerQueueProducer | null | undefined>;
|
|
1169
|
+
};
|
|
1141
1170
|
r2_buckets?: ReadonlyArray<{
|
|
1142
1171
|
binding?: string;
|
|
1143
1172
|
}>;
|
|
1173
|
+
secrets_store_secrets?: ReadonlyArray<{
|
|
1174
|
+
binding?: string;
|
|
1175
|
+
secret_name?: string;
|
|
1176
|
+
store_id?: string;
|
|
1177
|
+
} | null | undefined>;
|
|
1144
1178
|
send_email?: ReadonlyArray<{
|
|
1145
1179
|
allowed_destination_addresses?: ReadonlyArray<string>;
|
|
1146
1180
|
destination_address?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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
3
|
import 'ts-morph';
|
|
4
4
|
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";
|
|
@@ -156,6 +156,13 @@ interface InferredContainer extends ContainerIR {
|
|
|
156
156
|
interface InferredWorkflow extends WorkflowIR {
|
|
157
157
|
exported: boolean;
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* A queue declared in `lunora/queues.ts`. Unlike workflows, a queue needs no
|
|
161
|
+
* worker-entry class export (its `queue()` handler rides `createWorker`), so
|
|
162
|
+
* there is no `exported` flag — every declared queue is reconcilable into the
|
|
163
|
+
* wrangler `queues.producers[]` / `queues.consumers[]`.
|
|
164
|
+
*/
|
|
165
|
+
type InferredQueue = QueueIR;
|
|
159
166
|
interface InferredBindings {
|
|
160
167
|
/** Containers declared in `lunora/containers.ts` (exported or not — see {@link InferredContainer.exported}). */
|
|
161
168
|
containers: InferredContainer[];
|
|
@@ -163,11 +170,13 @@ interface InferredBindings {
|
|
|
163
170
|
durableObjects: DurableObjectSpec[];
|
|
164
171
|
/** Schema declares a `.global()` table → needs the `DB` D1 binding. */
|
|
165
172
|
needsD1: boolean;
|
|
173
|
+
/** Queues declared in `lunora/queues.ts` → reconciled into `queues.producers[]` / `queues.consumers[]`. */
|
|
174
|
+
queues: InferredQueue[];
|
|
166
175
|
/** Human-readable provenance for each inferred binding / hint, for logging. */
|
|
167
176
|
signals: string[];
|
|
168
177
|
/** `@lunora/ai` is imported or `env.AI` is used → needs the `ai` Workers AI binding. */
|
|
169
178
|
usesAi: boolean;
|
|
170
|
-
/** `@lunora/analytics` is imported → self-describing `analytics_engine_datasets` binding (auto-writeable). */
|
|
179
|
+
/** `@lunora/bindings/analytics` is imported → self-describing `analytics_engine_datasets` binding (auto-writeable). */
|
|
171
180
|
usesAnalytics: boolean;
|
|
172
181
|
/** `@lunora/auth` is imported (sessions may be D1- or `SessionDO`-backed). */
|
|
173
182
|
usesAuth: boolean;
|
|
@@ -175,15 +184,15 @@ interface InferredBindings {
|
|
|
175
184
|
usesBrowser: boolean;
|
|
176
185
|
/** `@lunora/hyperdrive` is imported (binding needs an un-mintable remote `id`; hint-only). */
|
|
177
186
|
usesHyperdrive: boolean;
|
|
178
|
-
/** `@lunora/images` is imported → self-describing `images` binding (auto-writeable). */
|
|
187
|
+
/** `@lunora/bindings/images` is imported → self-describing `images` binding (auto-writeable). */
|
|
179
188
|
usesImages: boolean;
|
|
180
|
-
/** `@lunora/kv` is imported (namespace binding name + id are user-defined; hint-only). */
|
|
189
|
+
/** `@lunora/bindings/kv` is imported (namespace binding name + id are user-defined; hint-only). */
|
|
181
190
|
usesKv: boolean;
|
|
182
191
|
/** `@lunora/mail` is imported (Resend API key must be set in `.dev.vars`; no binding). */
|
|
183
192
|
usesMail: boolean;
|
|
184
193
|
/** `@lunora/payment` is imported (provider secrets must be set in `.dev.vars`; no binding). */
|
|
185
194
|
usesPayment: boolean;
|
|
186
|
-
/**
|
|
195
|
+
/** `ctx.pipelines` is used (binding needs an un-mintable remote pipeline name; hint-only). */
|
|
187
196
|
usesPipelines: boolean;
|
|
188
197
|
/** `@lunora/scheduler` is imported. */
|
|
189
198
|
usesScheduler: boolean;
|
|
@@ -1074,6 +1083,22 @@ interface WranglerWorkflowEntry {
|
|
|
1074
1083
|
class_name?: string;
|
|
1075
1084
|
name?: string;
|
|
1076
1085
|
}
|
|
1086
|
+
/** A wrangler `queues.producers[]` entry — a `Queue` binding sending to `queue`. */
|
|
1087
|
+
interface WranglerQueueProducer {
|
|
1088
|
+
binding?: string;
|
|
1089
|
+
delivery_delay?: number;
|
|
1090
|
+
queue?: string;
|
|
1091
|
+
}
|
|
1092
|
+
/** A wrangler `queues.consumers[]` entry — push (worker) or `type: "http_pull"`. */
|
|
1093
|
+
interface WranglerQueueConsumer {
|
|
1094
|
+
dead_letter_queue?: string;
|
|
1095
|
+
max_batch_size?: number;
|
|
1096
|
+
max_batch_timeout?: number;
|
|
1097
|
+
max_retries?: number;
|
|
1098
|
+
queue?: string;
|
|
1099
|
+
retry_delay?: number;
|
|
1100
|
+
type?: string;
|
|
1101
|
+
}
|
|
1077
1102
|
interface WranglerConfig {
|
|
1078
1103
|
analytics_engine_datasets?: ReadonlyArray<{
|
|
1079
1104
|
binding?: string;
|
|
@@ -1138,9 +1163,18 @@ interface WranglerConfig {
|
|
|
1138
1163
|
placement?: {
|
|
1139
1164
|
mode?: string;
|
|
1140
1165
|
};
|
|
1166
|
+
queues?: {
|
|
1167
|
+
consumers?: ReadonlyArray<WranglerQueueConsumer | null | undefined>;
|
|
1168
|
+
producers?: ReadonlyArray<WranglerQueueProducer | null | undefined>;
|
|
1169
|
+
};
|
|
1141
1170
|
r2_buckets?: ReadonlyArray<{
|
|
1142
1171
|
binding?: string;
|
|
1143
1172
|
}>;
|
|
1173
|
+
secrets_store_secrets?: ReadonlyArray<{
|
|
1174
|
+
binding?: string;
|
|
1175
|
+
secret_name?: string;
|
|
1176
|
+
store_id?: string;
|
|
1177
|
+
} | null | undefined>;
|
|
1144
1178
|
send_email?: ReadonlyArray<{
|
|
1145
1179
|
allowed_destination_addresses?: ReadonlyArray<string>;
|
|
1146
1180
|
destination_address?: string;
|
package/dist/index.mjs
CHANGED
|
@@ -2,14 +2,14 @@ export { AGENT_RULES_DIR, AGENT_RULES_HINT, AGENT_RULES_HINT_ENV, LUNORA_SKILL_N
|
|
|
2
2
|
export { discoverContainerInfo } from './packem_shared/discoverContainerInfo-BXFs6Wav.mjs';
|
|
3
3
|
export { detectFramework } from './packem_shared/detectFramework-Br-BcPBq.mjs';
|
|
4
4
|
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-
|
|
5
|
+
export { inferLunoraBindings, packageNamesFromBindings } from './packem_shared/inferLunoraBindings-b9SJwb2s.mjs';
|
|
6
6
|
export { LINKED_PROJECT_DIR, LINKED_PROJECT_FILE, readLinkedProject, writeLinkedProject } from './packem_shared/LINKED_PROJECT_DIR-CXwXzV_C.mjs';
|
|
7
7
|
export { LUNORA_EVENT_SOURCE, formatLunoraEvent } from './packem_shared/LUNORA_EVENT_SOURCE-D2fDeGB6.mjs';
|
|
8
8
|
export { default as LunoraReporter } from './packem_shared/LunoraReporter-Ci-bDCK9.mjs';
|
|
9
9
|
export { PACKAGE_SECRETS_REGISTRY, secretsForPackages } from './packem_shared/PACKAGE_SECRETS_REGISTRY-B8t_SdoZ.mjs';
|
|
10
10
|
export { LUNORA_CONFIG_FILE, interpretRemote, readProjectRemotePreference } from './packem_shared/LUNORA_CONFIG_FILE-CtcIcB5-.mjs';
|
|
11
11
|
export { createConfirm, isInteractive, promptMultiSelect, promptSelect, promptYesNo } from './packem_shared/createConfirm-fvpdgJ9s.mjs';
|
|
12
|
-
export { reconcileWranglerBindings } from './packem_shared/reconcileWranglerBindings-
|
|
12
|
+
export { reconcileWranglerBindings } from './packem_shared/reconcileWranglerBindings-27af-Qvt.mjs';
|
|
13
13
|
export { REMOTE_ELIGIBLE_KEYS, injectRemoteFlags, isRemoteEnvEnabled, materializeRemoteWranglerConfig, planRemoteBindings, resolveRemoteEnabled } from './packem_shared/REMOTE_ELIGIBLE_KEYS-BC7_e9Bz.mjs';
|
|
14
14
|
export { buildPackageSecretsBlock, ensureDevVariables, ensureDevVarsExample, fillDevSecrets, generateSecretValue, isMintableSecretKey, isPlaceholderValue, planDevSecretsFill, planDevVariablesAugment, planDevVariablesScaffold, requiredSecrets } from './packem_shared/buildPackageSecretsBlock-DWDKHViT.mjs';
|
|
15
15
|
export { applyAdditiveEdit, classifyEdit } from './packem_shared/applyAdditiveEdit-C-snTFEV.mjs';
|
|
@@ -19,4 +19,4 @@ export { discoverSchemaInfo } from './packem_shared/discoverSchemaInfo-BB-CKlTK.
|
|
|
19
19
|
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';
|
|
20
20
|
export { discoverWorkflowInfo } from './packem_shared/discoverWorkflowInfo-CedvR0mn.mjs';
|
|
21
21
|
export { WRANGLER_FILES, findWranglerFile, readWranglerJsonc } from './packem_shared/WRANGLER_FILES-DwSuC-Kn.mjs';
|
|
22
|
-
export { REQUIRED_COMPATIBILITY_DATE, REQUIRED_FLAG, validateWrangler, validateWranglerConfig, validateWranglerProject, withTailConsumer } from './packem_shared/REQUIRED_COMPATIBILITY_DATE-
|
|
22
|
+
export { REQUIRED_COMPATIBILITY_DATE, REQUIRED_FLAG, validateWrangler, validateWranglerConfig, validateWranglerProject, withTailConsumer } from './packem_shared/REQUIRED_COMPATIBILITY_DATE-USQQ7NfE.mjs';
|
|
@@ -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 = [
|
|
@@ -398,6 +474,8 @@ const validateWranglerConfig = (wrangler, schema) => {
|
|
|
398
474
|
validateTailConsumers(wrangler, errors);
|
|
399
475
|
validateContainers(wrangler, errors, warnings);
|
|
400
476
|
validateWorkflows(wrangler, errors);
|
|
477
|
+
validateQueues(wrangler, errors);
|
|
478
|
+
validateSecretsStore(wrangler, errors);
|
|
401
479
|
for (const rule of HINT_BINDING_RULES) {
|
|
402
480
|
validateHintBinding(wrangler, rule, errors, warnings);
|
|
403
481
|
}
|
package/dist/packem_shared/{inferLunoraBindings-DIku9mTN.mjs → inferLunoraBindings-b9SJwb2s.mjs}
RENAMED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import { existsSync, statSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
2
|
import { init, parse } from 'es-module-lexer';
|
|
3
3
|
import { discoverContainerInfo } from './discoverContainerInfo-BXFs6Wav.mjs';
|
|
4
|
+
import { QUEUES_FILENAME, discoverQueues } from '@lunora/codegen';
|
|
5
|
+
import { Project } from 'ts-morph';
|
|
6
|
+
import { join } from 'node:path';
|
|
4
7
|
import { discoverSchemaInfo } from './discoverSchemaInfo-BB-CKlTK.mjs';
|
|
5
8
|
import { discoverWorkflowInfo } from './discoverWorkflowInfo-CedvR0mn.mjs';
|
|
6
9
|
import { WRANGLER_FILES, readWranglerJsonc } from './WRANGLER_FILES-DwSuC-Kn.mjs';
|
|
7
|
-
|
|
10
|
+
|
|
11
|
+
const discoverQueueInfo = (projectRoot, schemaDirectory) => {
|
|
12
|
+
const queuesPath = join(projectRoot, schemaDirectory, QUEUES_FILENAME);
|
|
13
|
+
if (!existsSync(queuesPath)) {
|
|
14
|
+
return { queues: [] };
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const project = new Project({ skipAddingFilesFromTsConfig: true, useInMemoryFileSystem: false });
|
|
18
|
+
return { queues: discoverQueues(project, join(projectRoot, schemaDirectory)) };
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return { error: error instanceof Error ? error.message : String(error), queues: [] };
|
|
21
|
+
}
|
|
22
|
+
};
|
|
8
23
|
|
|
9
24
|
const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".cts", ".js", ".jsx", ".mjs", ".mts", ".ts", ".tsx"]);
|
|
10
25
|
const IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([".git", ".lunora-cache", ".wrangler", "_generated", "dist", "node_modules"]);
|
|
@@ -23,18 +38,23 @@ const TYPE_ONLY_EXPORT_PATTERNS = {
|
|
|
23
38
|
};
|
|
24
39
|
const ENV_DB_PATTERN = /\benv\s*\.\s*DB\b/;
|
|
25
40
|
const ENV_AI_PATTERN = /\benv\s*\.\s*AI\b/;
|
|
41
|
+
const CTX_PIPELINES_PATTERN = /\bctx\s*\.\s*pipelines\b/;
|
|
26
42
|
const TYPE_ONLY_IMPORT_PATTERN = /^\s*import\s+type\b/;
|
|
27
43
|
const CAPABILITY_SOURCES = {
|
|
28
44
|
usesAi: { pattern: /\bfrom\s+["']@lunora\/ai["']/, source: "@lunora/ai" },
|
|
29
|
-
usesAnalytics: { pattern: /\bfrom\s+["']@lunora\/analytics["']/, source: "@lunora/analytics" },
|
|
45
|
+
usesAnalytics: { pattern: /\bfrom\s+["']@lunora\/bindings\/analytics["']/, source: "@lunora/bindings/analytics" },
|
|
30
46
|
usesAuth: { pattern: /\bfrom\s+["']@lunora\/auth["']/, source: "@lunora/auth" },
|
|
31
47
|
usesBrowser: { pattern: /\bfrom\s+["']@lunora\/browser["']/, source: "@lunora/browser" },
|
|
32
48
|
usesHyperdrive: { pattern: /\bfrom\s+["']@lunora\/hyperdrive["']/, source: "@lunora/hyperdrive" },
|
|
33
|
-
usesImages: { pattern: /\bfrom\s+["']@lunora\/images["']/, source: "@lunora/images" },
|
|
34
|
-
usesKv: { pattern: /\bfrom\s+["']@lunora\/kv["']/, source: "@lunora/kv" },
|
|
49
|
+
usesImages: { pattern: /\bfrom\s+["']@lunora\/bindings\/images["']/, source: "@lunora/bindings/images" },
|
|
50
|
+
usesKv: { pattern: /\bfrom\s+["']@lunora\/bindings\/kv["']/, source: "@lunora/bindings/kv" },
|
|
35
51
|
usesMail: { pattern: /\bfrom\s+["']@lunora\/mail["']/, source: "@lunora/mail" },
|
|
36
52
|
usesPayment: { pattern: /\bfrom\s+["']@lunora\/payment["']/, source: "@lunora/payment" },
|
|
37
|
-
|
|
53
|
+
// Keyed off the `ctx.pipelines` access (not an import) — see CTX_PIPELINES_PATTERN.
|
|
54
|
+
// Pipelines is codegen-wired onto ActionCtx, so apps reach it via `ctx.pipelines`
|
|
55
|
+
// rather than importing `@lunora/bindings/pipelines`; `source` names that subpath
|
|
56
|
+
// for the hint message.
|
|
57
|
+
usesPipelines: { pattern: CTX_PIPELINES_PATTERN, source: "@lunora/bindings/pipelines" },
|
|
38
58
|
usesScheduler: { pattern: /\bfrom\s+["']@lunora\/scheduler["']/, source: "@lunora/scheduler" },
|
|
39
59
|
usesStorage: { pattern: /\bfrom\s+["']@lunora\/storage["']/, source: "@lunora/storage" }
|
|
40
60
|
};
|
|
@@ -90,7 +110,12 @@ const capabilitiesFromSource = (code) => {
|
|
|
90
110
|
} catch {
|
|
91
111
|
capabilities = regexCapabilities(code);
|
|
92
112
|
}
|
|
93
|
-
return mergeCapabilities(capabilities, {
|
|
113
|
+
return mergeCapabilities(capabilities, {
|
|
114
|
+
...NO_CAPABILITIES,
|
|
115
|
+
needsD1: ENV_DB_PATTERN.test(code),
|
|
116
|
+
usesAi: ENV_AI_PATTERN.test(code),
|
|
117
|
+
usesPipelines: CTX_PIPELINES_PATTERN.test(code)
|
|
118
|
+
});
|
|
94
119
|
};
|
|
95
120
|
const collectSourceFiles = (directory, accumulator) => {
|
|
96
121
|
let entries;
|
|
@@ -237,14 +262,14 @@ const describeCapabilitySignals = (capabilities, exported) => {
|
|
|
237
262
|
// Self-describing bindings: the binding name is the whole config (no remote
|
|
238
263
|
// id to mint), so reconcile auto-writes them like the DO/D1 bindings.
|
|
239
264
|
[capabilities.usesBrowser, "browser (@lunora/browser imported) — self-describing { binding: BROWSER }"],
|
|
240
|
-
[capabilities.usesImages, "images (@lunora/images imported) — self-describing { binding: IMAGES }"],
|
|
241
|
-
[capabilities.usesAnalytics, "analytics_engine_datasets (@lunora/analytics imported) — self-describing { binding: ANALYTICS, dataset }"],
|
|
265
|
+
[capabilities.usesImages, "images (@lunora/bindings/images imported) — self-describing { binding: IMAGES }"],
|
|
266
|
+
[capabilities.usesAnalytics, "analytics_engine_datasets (@lunora/bindings/analytics imported) — self-describing { binding: ANALYTICS, dataset }"],
|
|
242
267
|
// Hint bindings: each needs a remote resource Lunora can't fabricate (a KV
|
|
243
268
|
// namespace id, a Hyperdrive id, a Pipelines pipeline name), so they surface
|
|
244
269
|
// as hints — never an auto-write — exactly like R2's user-defined bucket name.
|
|
245
270
|
[
|
|
246
271
|
capabilities.usesKv,
|
|
247
|
-
"hint: @lunora/kv is imported; add a kv_namespaces binding ({ binding, id }) and pass env.<BINDING> to createKv() — the namespace id can't be auto-provisioned"
|
|
272
|
+
"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"
|
|
248
273
|
],
|
|
249
274
|
[
|
|
250
275
|
capabilities.usesHyperdrive,
|
|
@@ -252,7 +277,7 @@ const describeCapabilitySignals = (capabilities, exported) => {
|
|
|
252
277
|
],
|
|
253
278
|
[
|
|
254
279
|
capabilities.usesPipelines,
|
|
255
|
-
"hint:
|
|
280
|
+
"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"
|
|
256
281
|
]
|
|
257
282
|
];
|
|
258
283
|
return rules.filter(([active]) => active).map(([, signal]) => signal);
|
|
@@ -276,6 +301,7 @@ const inferLunoraBindings = async (options) => {
|
|
|
276
301
|
const needsD1 = capabilities.needsD1 || schemaNeedsD1(options.projectRoot, schemaDirectory);
|
|
277
302
|
const containers = detectContainerExports(entryPath, discoverContainerInfo(options.projectRoot, schemaDirectory).containers);
|
|
278
303
|
const workflows = detectWorkflowExports(entryPath, discoverWorkflowInfo(options.projectRoot, schemaDirectory).workflows);
|
|
304
|
+
const queues = [...discoverQueueInfo(options.projectRoot, schemaDirectory).queues];
|
|
279
305
|
const capabilityFlags = {};
|
|
280
306
|
for (const flag of CAPABILITY_FLAGS) {
|
|
281
307
|
capabilityFlags[flag] = capabilities[flag];
|
|
@@ -284,6 +310,7 @@ const inferLunoraBindings = async (options) => {
|
|
|
284
310
|
containers,
|
|
285
311
|
durableObjects,
|
|
286
312
|
needsD1,
|
|
313
|
+
queues,
|
|
287
314
|
signals: describeSignals(durableObjects, needsD1, capabilities, containers, workflows),
|
|
288
315
|
workflows,
|
|
289
316
|
...capabilityFlags
|
|
@@ -23,7 +23,7 @@ const collectHintBindingWarnings = (inferred, parsed) => {
|
|
|
23
23
|
const rules = [
|
|
24
24
|
[
|
|
25
25
|
inferred.usesKv && (parsed?.kv_namespaces?.length ?? 0) === 0,
|
|
26
|
-
"@lunora/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."
|
|
26
|
+
"@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."
|
|
27
27
|
],
|
|
28
28
|
[
|
|
29
29
|
inferred.usesHyperdrive && (parsed?.hyperdrive?.length ?? 0) === 0,
|
|
@@ -31,7 +31,7 @@ const collectHintBindingWarnings = (inferred, parsed) => {
|
|
|
31
31
|
],
|
|
32
32
|
[
|
|
33
33
|
inferred.usesPipelines && (parsed?.pipelines?.length ?? 0) === 0,
|
|
34
|
-
"
|
|
34
|
+
"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."
|
|
35
35
|
]
|
|
36
36
|
];
|
|
37
37
|
return rules.filter(([active]) => active).map(([, warning]) => warning);
|
|
@@ -222,6 +222,57 @@ const reconcileWorkflows = (text, parsed, workflows) => {
|
|
|
222
222
|
const nextText = applyModify(text, ["workflows"], [...existing, ...missing.map((workflow) => workflowEntryFor(workflow))]);
|
|
223
223
|
return { added: missing.map((workflow) => `workflows/${workflow.className}`), text: nextText };
|
|
224
224
|
};
|
|
225
|
+
const reconcileQueues = (text, parsed, queues) => {
|
|
226
|
+
const existing = parsed.queues ?? {};
|
|
227
|
+
const existingProducers = existing.producers ?? [];
|
|
228
|
+
const existingConsumers = existing.consumers ?? [];
|
|
229
|
+
const haveProducer = new Set(existingProducers.map((entry) => entry.binding));
|
|
230
|
+
const haveConsumer = new Set(existingConsumers.map((entry) => entry.queue));
|
|
231
|
+
const missingProducers = queues.filter((queue) => !haveProducer.has(queue.bindingName));
|
|
232
|
+
const missingConsumers = queues.filter((queue) => !haveConsumer.has(queue.name));
|
|
233
|
+
if (missingProducers.length === 0 && missingConsumers.length === 0) {
|
|
234
|
+
return { added: [], text };
|
|
235
|
+
}
|
|
236
|
+
const nextProducers = [
|
|
237
|
+
...existingProducers,
|
|
238
|
+
...missingProducers.map((queue) => {
|
|
239
|
+
return { binding: queue.bindingName, queue: queue.name };
|
|
240
|
+
})
|
|
241
|
+
];
|
|
242
|
+
const nextConsumers = [
|
|
243
|
+
...existingConsumers,
|
|
244
|
+
...missingConsumers.map((queue) => {
|
|
245
|
+
const consumer = { queue: queue.name };
|
|
246
|
+
if (queue.mode === "pull") {
|
|
247
|
+
consumer.type = "http_pull";
|
|
248
|
+
}
|
|
249
|
+
if (queue.tuning.maxBatchSize !== void 0) {
|
|
250
|
+
consumer.max_batch_size = queue.tuning.maxBatchSize;
|
|
251
|
+
}
|
|
252
|
+
if (queue.tuning.maxBatchTimeout !== void 0) {
|
|
253
|
+
consumer.max_batch_timeout = queue.tuning.maxBatchTimeout;
|
|
254
|
+
}
|
|
255
|
+
if (queue.tuning.maxRetries !== void 0) {
|
|
256
|
+
consumer.max_retries = queue.tuning.maxRetries;
|
|
257
|
+
}
|
|
258
|
+
if (queue.tuning.deadLetterQueue !== void 0) {
|
|
259
|
+
consumer.dead_letter_queue = queue.tuning.deadLetterQueue;
|
|
260
|
+
}
|
|
261
|
+
if (queue.tuning.retryDelay !== void 0) {
|
|
262
|
+
consumer.retry_delay = queue.tuning.retryDelay;
|
|
263
|
+
}
|
|
264
|
+
return consumer;
|
|
265
|
+
})
|
|
266
|
+
];
|
|
267
|
+
const nextText = applyModify(text, ["queues"], { consumers: nextConsumers, producers: nextProducers });
|
|
268
|
+
return {
|
|
269
|
+
added: [
|
|
270
|
+
...missingProducers.map((queue) => `queues.producers/${queue.bindingName}`),
|
|
271
|
+
...missingConsumers.map((queue) => `queues.consumers/${queue.name}`)
|
|
272
|
+
],
|
|
273
|
+
text: nextText
|
|
274
|
+
};
|
|
275
|
+
};
|
|
225
276
|
const reconcileWranglerBindings = (projectRoot, inferred) => {
|
|
226
277
|
const wranglerPath = findWranglerFile(projectRoot);
|
|
227
278
|
const exportGaps = collectExportGaps(inferred);
|
|
@@ -250,7 +301,8 @@ const reconcileWranglerBindings = (projectRoot, inferred) => {
|
|
|
250
301
|
{ enabled: inferred.usesAnalytics, run: (text2) => reconcileAnalytics(text2, parsed) },
|
|
251
302
|
{ enabled: true, run: (text2) => reconcileObservability(text2, parsed) },
|
|
252
303
|
{ enabled: exportedContainers.length > 0, run: (text2) => reconcileContainers(text2, parsed, exportedContainers) },
|
|
253
|
-
{ enabled: exportedWorkflows.length > 0, run: (text2) => reconcileWorkflows(text2, parsed, exportedWorkflows) }
|
|
304
|
+
{ enabled: exportedWorkflows.length > 0, run: (text2) => reconcileWorkflows(text2, parsed, exportedWorkflows) },
|
|
305
|
+
{ enabled: inferred.queues.length > 0, run: (text2) => reconcileQueues(text2, parsed, inferred.queues) }
|
|
254
306
|
];
|
|
255
307
|
let text = original;
|
|
256
308
|
const added = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/config",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.17",
|
|
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",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"directory": "packages/config"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
|
-
"dist",
|
|
28
|
+
"./dist",
|
|
29
29
|
"__assets__",
|
|
30
30
|
"README.md",
|
|
31
31
|
"LICENSE.md"
|
|
@@ -50,16 +50,16 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@lunora/codegen": "1.0.0-alpha.
|
|
54
|
-
"@lunora/container": "1.0.0-alpha.
|
|
55
|
-
"@lunora/seed": "1.0.0-alpha.
|
|
53
|
+
"@lunora/codegen": "1.0.0-alpha.11",
|
|
54
|
+
"@lunora/container": "1.0.0-alpha.3",
|
|
55
|
+
"@lunora/seed": "1.0.0-alpha.5",
|
|
56
56
|
"@visulima/colorize": "2.0.0-alpha.14",
|
|
57
57
|
"es-module-lexer": "^2.1.0",
|
|
58
58
|
"jsonc-parser": "^3.3.1",
|
|
59
59
|
"ts-morph": "^28.0.0"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
|
-
"@lunora/studio": "1.0.0-alpha.
|
|
62
|
+
"@lunora/studio": "1.0.0-alpha.8"
|
|
63
63
|
},
|
|
64
64
|
"peerDependenciesMeta": {
|
|
65
65
|
"@lunora/studio": {
|