@lunora/config 1.0.0-alpha.3 → 1.0.0-alpha.30
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/__assets__/package-og.svg +1 -1
- package/dist/index.d.mts +253 -6
- package/dist/index.d.ts +253 -6
- package/dist/index.mjs +13 -10
- package/dist/packem_shared/ACCENT-DW1XJn8i.mjs +40 -0
- package/dist/packem_shared/LunoraReporter-Ci-bDCK9.mjs +70 -0
- package/dist/packem_shared/{PACKAGE_SECRETS_REGISTRY-CySy5vR_.mjs → PACKAGE_SECRETS_REGISTRY-B8t_SdoZ.mjs} +9 -1
- package/dist/packem_shared/{injectRemoteFlags-C-WZAKLY.mjs → REMOTE_ELIGIBLE_KEYS-BC7_e9Bz.mjs} +1 -1
- package/dist/packem_shared/{REQUIRED_COMPATIBILITY_DATE-Dd1suoit.mjs → REQUIRED_COMPATIBILITY_DATE-2YYyWJUq.mjs} +87 -2
- package/dist/packem_shared/{buildPackageSecretsBlock-S74dgmwy.mjs → buildPackageSecretsBlock-DWDKHViT.mjs} +60 -4
- package/dist/packem_shared/{discoverSchemaInfo-DWtypqpP.mjs → discoverSchemaInfo-BB-CKlTK.mjs} +1 -1
- package/dist/packem_shared/{inferLunoraBindings-0W3eRdIP.mjs → inferLunoraBindings-ByMwG-gH.mjs} +69 -19
- package/dist/packem_shared/{reconcileWranglerBindings-ByJk3yLU.mjs → reconcileWranglerBindings-Cruwwx1M.mjs} +61 -4
- package/dist/packem_shared/streamContainerLogs-BZ4cOZwH.mjs +157 -0
- package/dist/studio-host/index.mjs +4 -4
- package/package.json +8 -6
- /package/dist/packem_shared/{interpretRemote-CtcIcB5-.mjs → LUNORA_CONFIG_FILE-CtcIcB5-.mjs} +0 -0
- /package/dist/packem_shared/{formatLunoraEvent-D2fDeGB6.mjs → LUNORA_EVENT_SOURCE-D2fDeGB6.mjs} +0 -0
- /package/dist/packem_shared/{handlePolicyScaffoldRequest-CiC2IGKx.mjs → POLICY_SCAFFOLD_ENDPOINT-CiC2IGKx.mjs} +0 -0
- /package/dist/packem_shared/{handleSchemaEditRequest-Df-Wrix-.mjs → SCHEMA_EDIT_ENDPOINT-Df-Wrix-.mjs} +0 -0
- /package/dist/packem_shared/{handleSeedRequest-DVCjaGO-.mjs → SEED_ENDPOINT-DVCjaGO-.mjs} +0 -0
- /package/dist/packem_shared/{findWranglerFile-DwSuC-Kn.mjs → WRANGLER_FILES-DwSuC-Kn.mjs} +0 -0
- /package/dist/packem_shared/{studioAssetsStamp-Csk5RS4E.mjs → loadStudioAssets-Csk5RS4E.mjs} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
|
-
import { discoverSchemaInfo } from './discoverSchemaInfo-
|
|
4
|
-
import { findWranglerFile, readWranglerJsonc } from './
|
|
3
|
+
import { discoverSchemaInfo } from './discoverSchemaInfo-BB-CKlTK.mjs';
|
|
4
|
+
import { findWranglerFile, readWranglerJsonc } from './WRANGLER_FILES-DwSuC-Kn.mjs';
|
|
5
5
|
|
|
6
6
|
const REQUIRED_COMPATIBILITY_DATE = "2026-04-07";
|
|
7
7
|
const REQUIRED_FLAG = "web_socket_auto_reply_to_close";
|
|
@@ -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
|
}
|
|
@@ -2,8 +2,9 @@ import { randomBytes } from 'node:crypto';
|
|
|
2
2
|
import { existsSync, readFileSync, writeFileSync, renameSync, rmSync } from 'node:fs';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { DEV_VARS_FILE, DEV_VARS_EXAMPLE_FILE, parseDevVariableEntries, DEV_VARS_NEWLINE, splitDevVariableLine, unquoteDevVariable } from './DEV_VARS_EXAMPLE_FILE-dJPNTEnK.mjs';
|
|
5
|
-
import { secretsForPackages } from './PACKAGE_SECRETS_REGISTRY-
|
|
5
|
+
import { CORE_SECRETS, PACKAGE_SECRETS_REGISTRY, secretsForPackages } from './PACKAGE_SECRETS_REGISTRY-B8t_SdoZ.mjs';
|
|
6
6
|
|
|
7
|
+
const requiredSecrets = (packageNames) => [...CORE_SECRETS, ...secretsForPackages(packageNames)];
|
|
7
8
|
const SECRET_BYTES = 32;
|
|
8
9
|
const SECRET_KEY = /(?:KEY|PASSWORD|SECRET|TOKEN)$/u;
|
|
9
10
|
const PLACEHOLDER_MARKERS = [
|
|
@@ -45,6 +46,11 @@ const isPlaceholderValue = (value) => {
|
|
|
45
46
|
const isPlaceholder = (rawValue) => isPlaceholderValue(unquoteDevVariable(rawValue.trim()));
|
|
46
47
|
const defaultRandomHex = (bytes) => randomBytes(bytes).toString("hex");
|
|
47
48
|
const generatedSecretFor = (key, rawValue, randomHex) => SECRET_KEY.test(key) && isPlaceholder(rawValue) ? randomHex(SECRET_BYTES) : void 0;
|
|
49
|
+
const PROVIDER_SECRET_KEYS = new Set(
|
|
50
|
+
[...CORE_SECRETS, ...Object.values(PACKAGE_SECRETS_REGISTRY).flat()].filter((entry) => SECRET_KEY.test(entry.key) && entry.placeholderValue.startsWith("<")).map((entry) => entry.key)
|
|
51
|
+
);
|
|
52
|
+
const isMintableSecretKey = (key) => SECRET_KEY.test(key) && !PROVIDER_SECRET_KEYS.has(key);
|
|
53
|
+
const generateSecretValue = (randomHex = defaultRandomHex) => randomHex(SECRET_BYTES);
|
|
48
54
|
const planDevVariablesScaffold = (input) => {
|
|
49
55
|
if (input.devVarsExists) {
|
|
50
56
|
return { status: "exists" };
|
|
@@ -155,7 +161,7 @@ const secretEntryBlock = (entry) => {
|
|
|
155
161
|
return lines.join("\n");
|
|
156
162
|
};
|
|
157
163
|
const buildPackageSecretsBlock = (packageNames, existingKeys) => {
|
|
158
|
-
const entries =
|
|
164
|
+
const entries = requiredSecrets(packageNames).filter((entry) => !existingKeys.has(entry.key));
|
|
159
165
|
if (entries.length === 0) {
|
|
160
166
|
return "";
|
|
161
167
|
}
|
|
@@ -181,7 +187,57 @@ ${block}
|
|
|
181
187
|
rmSync(temporaryPath, { force: true });
|
|
182
188
|
throw error;
|
|
183
189
|
}
|
|
184
|
-
return
|
|
190
|
+
return requiredSecrets(packageNames).filter((entry) => !existingKeys.has(entry.key)).map((entry) => entry.key);
|
|
191
|
+
};
|
|
192
|
+
const planDevSecretsFill = (input) => {
|
|
193
|
+
const randomHex = input.randomHex ?? defaultRandomHex;
|
|
194
|
+
const filledKeys = [];
|
|
195
|
+
const lines = input.existingContent.split(DEV_VARS_NEWLINE).map((line) => {
|
|
196
|
+
const parsed = splitDevVariableLine(line);
|
|
197
|
+
const secret = parsed ? generatedSecretFor(parsed.key, parsed.value, randomHex) : void 0;
|
|
198
|
+
if (!parsed || secret === void 0) {
|
|
199
|
+
return line;
|
|
200
|
+
}
|
|
201
|
+
filledKeys.push(parsed.key);
|
|
202
|
+
return `${parsed.key}="${secret}"`;
|
|
203
|
+
});
|
|
204
|
+
const present = new Set(parseDevVariableEntries(input.existingContent).map((entry) => entry.key));
|
|
205
|
+
const addedKeys = [];
|
|
206
|
+
const additions = [];
|
|
207
|
+
for (const entry of CORE_SECRETS) {
|
|
208
|
+
if (present.has(entry.key)) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
addedKeys.push(entry.key);
|
|
212
|
+
additions.push(`# ${entry.description}`, `${entry.key}="${randomHex(SECRET_BYTES)}"`);
|
|
213
|
+
}
|
|
214
|
+
const body = lines.join("\n");
|
|
215
|
+
if (additions.length === 0) {
|
|
216
|
+
return { addedKeys, content: body, filledKeys };
|
|
217
|
+
}
|
|
218
|
+
const separator = body === "" || body.endsWith("\n") ? "" : "\n";
|
|
219
|
+
return { addedKeys, content: `${body}${separator}${additions.join("\n")}
|
|
220
|
+
`, filledKeys };
|
|
221
|
+
};
|
|
222
|
+
const fillDevSecrets = (deps) => {
|
|
223
|
+
const devVariablesPath = join(deps.cwd, DEV_VARS_FILE);
|
|
224
|
+
const exists = existsSync(devVariablesPath);
|
|
225
|
+
const existingContent = exists ? readFileSync(devVariablesPath, "utf8") : "";
|
|
226
|
+
const plan = planDevSecretsFill({ existingContent, randomHex: deps.randomHex });
|
|
227
|
+
if (plan.filledKeys.length === 0 && plan.addedKeys.length === 0) {
|
|
228
|
+
return { addedKeys: [], filledKeys: [], status: "unchanged" };
|
|
229
|
+
}
|
|
230
|
+
const temporaryPath = `${devVariablesPath}.tmp-${String(process.pid)}`;
|
|
231
|
+
try {
|
|
232
|
+
writeFileSync(temporaryPath, plan.content, { encoding: "utf8", mode: 384 });
|
|
233
|
+
renameSync(temporaryPath, devVariablesPath);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
rmSync(temporaryPath, { force: true });
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
const generated = [...plan.filledKeys, ...plan.addedKeys];
|
|
239
|
+
deps.info?.(`Generated ${String(generated.length)} dev secret(s) in ${DEV_VARS_FILE}: ${generated.join(", ")}`);
|
|
240
|
+
return { addedKeys: plan.addedKeys, filledKeys: plan.filledKeys, status: exists ? "filled" : "created" };
|
|
185
241
|
};
|
|
186
242
|
|
|
187
|
-
export { buildPackageSecretsBlock, ensureDevVariables, ensureDevVariablesExample as ensureDevVarsExample, isPlaceholderValue, planDevVariablesAugment, planDevVariablesScaffold };
|
|
243
|
+
export { buildPackageSecretsBlock, ensureDevVariables, ensureDevVariablesExample as ensureDevVarsExample, fillDevSecrets, generateSecretValue, isMintableSecretKey, isPlaceholderValue, planDevSecretsFill, planDevVariablesAugment, planDevVariablesScaffold, requiredSecrets };
|
package/dist/packem_shared/{discoverSchemaInfo-DWtypqpP.mjs → discoverSchemaInfo-BB-CKlTK.mjs}
RENAMED
|
@@ -10,7 +10,7 @@ const discoverSchemaInfo = (projectRoot, schemaDirectory) => {
|
|
|
10
10
|
}
|
|
11
11
|
try {
|
|
12
12
|
const project = new Project({ skipAddingFilesFromTsConfig: true, useInMemoryFileSystem: false });
|
|
13
|
-
const schema = discoverSchema(project, schemaPath);
|
|
13
|
+
const schema = discoverSchema(project, schemaPath, projectRoot);
|
|
14
14
|
return {
|
|
15
15
|
info: {
|
|
16
16
|
hasGlobalTable: schema.tables.some((table) => table.shardMode === "global"),
|
package/dist/packem_shared/{inferLunoraBindings-0W3eRdIP.mjs → inferLunoraBindings-ByMwG-gH.mjs}
RENAMED
|
@@ -1,10 +1,38 @@
|
|
|
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 {
|
|
5
|
-
import {
|
|
6
|
-
import { WRANGLER_FILES, readWranglerJsonc } from './findWranglerFile-DwSuC-Kn.mjs';
|
|
4
|
+
import { FLAGS_FILENAME, discoverFlags, QUEUES_FILENAME, discoverQueues } from '@lunora/codegen';
|
|
5
|
+
import { Project } from 'ts-morph';
|
|
7
6
|
import { join } from 'node:path';
|
|
7
|
+
import { discoverSchemaInfo } from './discoverSchemaInfo-BB-CKlTK.mjs';
|
|
8
|
+
import { discoverWorkflowInfo } from './discoverWorkflowInfo-CedvR0mn.mjs';
|
|
9
|
+
import { WRANGLER_FILES, readWranglerJsonc } from './WRANGLER_FILES-DwSuC-Kn.mjs';
|
|
10
|
+
|
|
11
|
+
const discoverFlagsInfo = (projectRoot, schemaDirectory) => {
|
|
12
|
+
const flagsPath = join(projectRoot, schemaDirectory, FLAGS_FILENAME);
|
|
13
|
+
if (!existsSync(flagsPath)) {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const project = new Project({ skipAddingFilesFromTsConfig: true, useInMemoryFileSystem: false });
|
|
18
|
+
return { flags: discoverFlags(project, join(projectRoot, schemaDirectory)) };
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return { error: error instanceof Error ? error.message : String(error) };
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const discoverQueueInfo = (projectRoot, schemaDirectory) => {
|
|
25
|
+
const queuesPath = join(projectRoot, schemaDirectory, QUEUES_FILENAME);
|
|
26
|
+
if (!existsSync(queuesPath)) {
|
|
27
|
+
return { queues: [] };
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const project = new Project({ skipAddingFilesFromTsConfig: true, useInMemoryFileSystem: false });
|
|
31
|
+
return { queues: discoverQueues(project, join(projectRoot, schemaDirectory)) };
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return { error: error instanceof Error ? error.message : String(error), queues: [] };
|
|
34
|
+
}
|
|
35
|
+
};
|
|
8
36
|
|
|
9
37
|
const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".cts", ".js", ".jsx", ".mjs", ".mts", ".ts", ".tsx"]);
|
|
10
38
|
const IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([".git", ".lunora-cache", ".wrangler", "_generated", "dist", "node_modules"]);
|
|
@@ -23,18 +51,23 @@ const TYPE_ONLY_EXPORT_PATTERNS = {
|
|
|
23
51
|
};
|
|
24
52
|
const ENV_DB_PATTERN = /\benv\s*\.\s*DB\b/;
|
|
25
53
|
const ENV_AI_PATTERN = /\benv\s*\.\s*AI\b/;
|
|
54
|
+
const CTX_PIPELINES_PATTERN = /\bctx\s*\.\s*pipelines\b/;
|
|
26
55
|
const TYPE_ONLY_IMPORT_PATTERN = /^\s*import\s+type\b/;
|
|
27
56
|
const CAPABILITY_SOURCES = {
|
|
28
57
|
usesAi: { pattern: /\bfrom\s+["']@lunora\/ai["']/, source: "@lunora/ai" },
|
|
29
|
-
usesAnalytics: { pattern: /\bfrom\s+["']@lunora\/analytics["']/, source: "@lunora/analytics" },
|
|
58
|
+
usesAnalytics: { pattern: /\bfrom\s+["']@lunora\/bindings\/analytics["']/, source: "@lunora/bindings/analytics" },
|
|
30
59
|
usesAuth: { pattern: /\bfrom\s+["']@lunora\/auth["']/, source: "@lunora/auth" },
|
|
31
60
|
usesBrowser: { pattern: /\bfrom\s+["']@lunora\/browser["']/, source: "@lunora/browser" },
|
|
32
61
|
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" },
|
|
62
|
+
usesImages: { pattern: /\bfrom\s+["']@lunora\/bindings\/images["']/, source: "@lunora/bindings/images" },
|
|
63
|
+
usesKv: { pattern: /\bfrom\s+["']@lunora\/bindings\/kv["']/, source: "@lunora/bindings/kv" },
|
|
35
64
|
usesMail: { pattern: /\bfrom\s+["']@lunora\/mail["']/, source: "@lunora/mail" },
|
|
36
65
|
usesPayment: { pattern: /\bfrom\s+["']@lunora\/payment["']/, source: "@lunora/payment" },
|
|
37
|
-
|
|
66
|
+
// Keyed off the `ctx.pipelines` access (not an import) — see CTX_PIPELINES_PATTERN.
|
|
67
|
+
// Pipelines is codegen-wired onto ActionCtx, so apps reach it via `ctx.pipelines`
|
|
68
|
+
// rather than importing `@lunora/bindings/pipelines`; `source` names that subpath
|
|
69
|
+
// for the hint message.
|
|
70
|
+
usesPipelines: { pattern: CTX_PIPELINES_PATTERN, source: "@lunora/bindings/pipelines" },
|
|
38
71
|
usesScheduler: { pattern: /\bfrom\s+["']@lunora\/scheduler["']/, source: "@lunora/scheduler" },
|
|
39
72
|
usesStorage: { pattern: /\bfrom\s+["']@lunora\/storage["']/, source: "@lunora/storage" }
|
|
40
73
|
};
|
|
@@ -90,7 +123,12 @@ const capabilitiesFromSource = (code) => {
|
|
|
90
123
|
} catch {
|
|
91
124
|
capabilities = regexCapabilities(code);
|
|
92
125
|
}
|
|
93
|
-
return mergeCapabilities(capabilities, {
|
|
126
|
+
return mergeCapabilities(capabilities, {
|
|
127
|
+
...NO_CAPABILITIES,
|
|
128
|
+
needsD1: ENV_DB_PATTERN.test(code),
|
|
129
|
+
usesAi: ENV_AI_PATTERN.test(code),
|
|
130
|
+
usesPipelines: CTX_PIPELINES_PATTERN.test(code)
|
|
131
|
+
});
|
|
94
132
|
};
|
|
95
133
|
const collectSourceFiles = (directory, accumulator) => {
|
|
96
134
|
let entries;
|
|
@@ -137,8 +175,8 @@ const detectExportedDurableObjects = (entryPath) => {
|
|
|
137
175
|
const code = readFileSync(entryPath, "utf8");
|
|
138
176
|
let exportedNames;
|
|
139
177
|
try {
|
|
140
|
-
const [, exports
|
|
141
|
-
exportedNames = new Set(exports
|
|
178
|
+
const [, exports] = parse(code);
|
|
179
|
+
exportedNames = new Set(exports.map((entry) => entry.n));
|
|
142
180
|
} catch {
|
|
143
181
|
exportedNames = new Set(DURABLE_OBJECT_CLASSES.filter((className) => new RegExp(String.raw`\bexport\b[^\n;]*\b${className}\b`).test(code)));
|
|
144
182
|
}
|
|
@@ -163,8 +201,8 @@ const detectContainerExports = (entryPath, containers) => {
|
|
|
163
201
|
const starReexport = CONTAINERS_STAR_REEXPORT_PATTERN.test(code);
|
|
164
202
|
let exportedNames;
|
|
165
203
|
try {
|
|
166
|
-
const [, exports
|
|
167
|
-
exportedNames = new Set(exports
|
|
204
|
+
const [, exports] = parse(code);
|
|
205
|
+
exportedNames = new Set(exports.map((entry) => entry.n));
|
|
168
206
|
} catch {
|
|
169
207
|
exportedNames = new Set(
|
|
170
208
|
containers.map((container) => container.className).filter((className) => new RegExp(String.raw`\bexport\b[^\n;]*\b${className}\b`).test(code))
|
|
@@ -188,8 +226,8 @@ const detectWorkflowExports = (entryPath, workflows) => {
|
|
|
188
226
|
const starReexport = WORKFLOWS_STAR_REEXPORT_PATTERN.test(code);
|
|
189
227
|
let exportedNames;
|
|
190
228
|
try {
|
|
191
|
-
const [, exports
|
|
192
|
-
exportedNames = new Set(exports
|
|
229
|
+
const [, exports] = parse(code);
|
|
230
|
+
exportedNames = new Set(exports.map((entry) => entry.n));
|
|
193
231
|
} catch {
|
|
194
232
|
exportedNames = new Set(
|
|
195
233
|
workflows.map((workflow) => workflow.className).filter((className) => new RegExp(String.raw`\bexport\b[^\n;]*\b${className}\b`).test(code))
|
|
@@ -237,14 +275,14 @@ const describeCapabilitySignals = (capabilities, exported) => {
|
|
|
237
275
|
// Self-describing bindings: the binding name is the whole config (no remote
|
|
238
276
|
// id to mint), so reconcile auto-writes them like the DO/D1 bindings.
|
|
239
277
|
[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 }"],
|
|
278
|
+
[capabilities.usesImages, "images (@lunora/bindings/images imported) — self-describing { binding: IMAGES }"],
|
|
279
|
+
[capabilities.usesAnalytics, "analytics_engine_datasets (@lunora/bindings/analytics imported) — self-describing { binding: ANALYTICS, dataset }"],
|
|
242
280
|
// Hint bindings: each needs a remote resource Lunora can't fabricate (a KV
|
|
243
281
|
// namespace id, a Hyperdrive id, a Pipelines pipeline name), so they surface
|
|
244
282
|
// as hints — never an auto-write — exactly like R2's user-defined bucket name.
|
|
245
283
|
[
|
|
246
284
|
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"
|
|
285
|
+
"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
286
|
],
|
|
249
287
|
[
|
|
250
288
|
capabilities.usesHyperdrive,
|
|
@@ -252,7 +290,7 @@ const describeCapabilitySignals = (capabilities, exported) => {
|
|
|
252
290
|
],
|
|
253
291
|
[
|
|
254
292
|
capabilities.usesPipelines,
|
|
255
|
-
"hint:
|
|
293
|
+
"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
294
|
]
|
|
257
295
|
];
|
|
258
296
|
return rules.filter(([active]) => active).map(([, signal]) => signal);
|
|
@@ -276,15 +314,27 @@ const inferLunoraBindings = async (options) => {
|
|
|
276
314
|
const needsD1 = capabilities.needsD1 || schemaNeedsD1(options.projectRoot, schemaDirectory);
|
|
277
315
|
const containers = detectContainerExports(entryPath, discoverContainerInfo(options.projectRoot, schemaDirectory).containers);
|
|
278
316
|
const workflows = detectWorkflowExports(entryPath, discoverWorkflowInfo(options.projectRoot, schemaDirectory).workflows);
|
|
317
|
+
const queues = [...discoverQueueInfo(options.projectRoot, schemaDirectory).queues];
|
|
318
|
+
const { flags } = discoverFlagsInfo(options.projectRoot, schemaDirectory);
|
|
319
|
+
const flagshipBinding = flags?.provider === "flagship" && flags.mode === "binding" ? flags.bindingName : void 0;
|
|
279
320
|
const capabilityFlags = {};
|
|
280
321
|
for (const flag of CAPABILITY_FLAGS) {
|
|
281
322
|
capabilityFlags[flag] = capabilities[flag];
|
|
282
323
|
}
|
|
324
|
+
const signals = describeSignals(durableObjects, needsD1, capabilities, containers, workflows);
|
|
325
|
+
if (flagshipBinding !== void 0) {
|
|
326
|
+
signals.push(
|
|
327
|
+
`hint: lunora/flags.ts uses Flagship in binding mode; add a flagship binding ({ binding: "${flagshipBinding}", app_id }) — the app_id can't be auto-provisioned`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
283
330
|
return {
|
|
284
331
|
containers,
|
|
285
332
|
durableObjects,
|
|
333
|
+
flagshipBinding,
|
|
286
334
|
needsD1,
|
|
287
|
-
|
|
335
|
+
queues,
|
|
336
|
+
signals,
|
|
337
|
+
usesFlags: flags !== void 0,
|
|
288
338
|
workflows,
|
|
289
339
|
...capabilityFlags
|
|
290
340
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { writeFileSync } from 'node:fs';
|
|
2
2
|
import { containerBuildTag } from '@lunora/container';
|
|
3
3
|
import { modify, applyEdits } from 'jsonc-parser';
|
|
4
|
-
import { findWranglerFile, readWranglerJsonc } from './
|
|
4
|
+
import { findWranglerFile, readWranglerJsonc } from './WRANGLER_FILES-DwSuC-Kn.mjs';
|
|
5
5
|
|
|
6
6
|
const FORMATTING = { formattingOptions: { insertSpaces: true, tabSize: 4 } };
|
|
7
7
|
const D1_PLACEHOLDER_ID = "<replace-with-d1-create-id>";
|
|
@@ -20,10 +20,11 @@ const collectExportGaps = (inferred) => {
|
|
|
20
20
|
return gaps;
|
|
21
21
|
};
|
|
22
22
|
const collectHintBindingWarnings = (inferred, parsed) => {
|
|
23
|
+
const flagshipBindingMissing = inferred.flagshipBinding !== void 0 && !(parsed?.flagship ?? []).some((entry) => entry.binding === inferred.flagshipBinding);
|
|
23
24
|
const rules = [
|
|
24
25
|
[
|
|
25
26
|
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."
|
|
27
|
+
"@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
28
|
],
|
|
28
29
|
[
|
|
29
30
|
inferred.usesHyperdrive && (parsed?.hyperdrive?.length ?? 0) === 0,
|
|
@@ -31,7 +32,11 @@ const collectHintBindingWarnings = (inferred, parsed) => {
|
|
|
31
32
|
],
|
|
32
33
|
[
|
|
33
34
|
inferred.usesPipelines && (parsed?.pipelines?.length ?? 0) === 0,
|
|
34
|
-
"
|
|
35
|
+
"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."
|
|
36
|
+
],
|
|
37
|
+
[
|
|
38
|
+
flagshipBindingMissing,
|
|
39
|
+
`lunora/flags.ts uses Flagship in binding mode but no flagship binding "${inferred.flagshipBinding ?? ""}" exists; add a flagship entry ({ binding: "${inferred.flagshipBinding ?? ""}", app_id }) — the app_id can't be auto-provisioned.`
|
|
35
40
|
]
|
|
36
41
|
];
|
|
37
42
|
return rules.filter(([active]) => active).map(([, warning]) => warning);
|
|
@@ -222,6 +227,57 @@ const reconcileWorkflows = (text, parsed, workflows) => {
|
|
|
222
227
|
const nextText = applyModify(text, ["workflows"], [...existing, ...missing.map((workflow) => workflowEntryFor(workflow))]);
|
|
223
228
|
return { added: missing.map((workflow) => `workflows/${workflow.className}`), text: nextText };
|
|
224
229
|
};
|
|
230
|
+
const reconcileQueues = (text, parsed, queues) => {
|
|
231
|
+
const existing = parsed.queues ?? {};
|
|
232
|
+
const existingProducers = existing.producers ?? [];
|
|
233
|
+
const existingConsumers = existing.consumers ?? [];
|
|
234
|
+
const haveProducer = new Set(existingProducers.map((entry) => entry.binding));
|
|
235
|
+
const haveConsumer = new Set(existingConsumers.map((entry) => entry.queue));
|
|
236
|
+
const missingProducers = queues.filter((queue) => !haveProducer.has(queue.bindingName));
|
|
237
|
+
const missingConsumers = queues.filter((queue) => !haveConsumer.has(queue.name));
|
|
238
|
+
if (missingProducers.length === 0 && missingConsumers.length === 0) {
|
|
239
|
+
return { added: [], text };
|
|
240
|
+
}
|
|
241
|
+
const nextProducers = [
|
|
242
|
+
...existingProducers,
|
|
243
|
+
...missingProducers.map((queue) => {
|
|
244
|
+
return { binding: queue.bindingName, queue: queue.name };
|
|
245
|
+
})
|
|
246
|
+
];
|
|
247
|
+
const nextConsumers = [
|
|
248
|
+
...existingConsumers,
|
|
249
|
+
...missingConsumers.map((queue) => {
|
|
250
|
+
const consumer = { queue: queue.name };
|
|
251
|
+
if (queue.mode === "pull") {
|
|
252
|
+
consumer.type = "http_pull";
|
|
253
|
+
}
|
|
254
|
+
if (queue.tuning.maxBatchSize !== void 0) {
|
|
255
|
+
consumer.max_batch_size = queue.tuning.maxBatchSize;
|
|
256
|
+
}
|
|
257
|
+
if (queue.tuning.maxBatchTimeout !== void 0) {
|
|
258
|
+
consumer.max_batch_timeout = queue.tuning.maxBatchTimeout;
|
|
259
|
+
}
|
|
260
|
+
if (queue.tuning.maxRetries !== void 0) {
|
|
261
|
+
consumer.max_retries = queue.tuning.maxRetries;
|
|
262
|
+
}
|
|
263
|
+
if (queue.tuning.deadLetterQueue !== void 0) {
|
|
264
|
+
consumer.dead_letter_queue = queue.tuning.deadLetterQueue;
|
|
265
|
+
}
|
|
266
|
+
if (queue.tuning.retryDelay !== void 0) {
|
|
267
|
+
consumer.retry_delay = queue.tuning.retryDelay;
|
|
268
|
+
}
|
|
269
|
+
return consumer;
|
|
270
|
+
})
|
|
271
|
+
];
|
|
272
|
+
const nextText = applyModify(text, ["queues"], { consumers: nextConsumers, producers: nextProducers });
|
|
273
|
+
return {
|
|
274
|
+
added: [
|
|
275
|
+
...missingProducers.map((queue) => `queues.producers/${queue.bindingName}`),
|
|
276
|
+
...missingConsumers.map((queue) => `queues.consumers/${queue.name}`)
|
|
277
|
+
],
|
|
278
|
+
text: nextText
|
|
279
|
+
};
|
|
280
|
+
};
|
|
225
281
|
const reconcileWranglerBindings = (projectRoot, inferred) => {
|
|
226
282
|
const wranglerPath = findWranglerFile(projectRoot);
|
|
227
283
|
const exportGaps = collectExportGaps(inferred);
|
|
@@ -250,7 +306,8 @@ const reconcileWranglerBindings = (projectRoot, inferred) => {
|
|
|
250
306
|
{ enabled: inferred.usesAnalytics, run: (text2) => reconcileAnalytics(text2, parsed) },
|
|
251
307
|
{ enabled: true, run: (text2) => reconcileObservability(text2, parsed) },
|
|
252
308
|
{ enabled: exportedContainers.length > 0, run: (text2) => reconcileContainers(text2, parsed, exportedContainers) },
|
|
253
|
-
{ enabled: exportedWorkflows.length > 0, run: (text2) => reconcileWorkflows(text2, parsed, exportedWorkflows) }
|
|
309
|
+
{ enabled: exportedWorkflows.length > 0, run: (text2) => reconcileWorkflows(text2, parsed, exportedWorkflows) },
|
|
310
|
+
{ enabled: inferred.queues.length > 0, run: (text2) => reconcileQueues(text2, parsed, inferred.queues) }
|
|
254
311
|
];
|
|
255
312
|
let text = original;
|
|
256
313
|
const added = [];
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
import { StringDecoder } from 'node:string_decoder';
|
|
3
|
+
|
|
4
|
+
const DEV_CONTAINER_IMAGE_PREFIX = "cloudflare-dev/";
|
|
5
|
+
const DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
6
|
+
const createDefaultDocker = async () => {
|
|
7
|
+
const { default: Dockerode } = await import('dockerode');
|
|
8
|
+
return new Dockerode();
|
|
9
|
+
};
|
|
10
|
+
const classFromImage = (image) => {
|
|
11
|
+
if (!image.startsWith(DEV_CONTAINER_IMAGE_PREFIX)) {
|
|
12
|
+
return void 0;
|
|
13
|
+
}
|
|
14
|
+
const [segment] = image.slice(DEV_CONTAINER_IMAGE_PREFIX.length).split(":");
|
|
15
|
+
return segment !== void 0 && segment.length > 0 ? segment : void 0;
|
|
16
|
+
};
|
|
17
|
+
const lineBufferWritable = (emit) => {
|
|
18
|
+
const decoder = new StringDecoder("utf8");
|
|
19
|
+
let buffer = "";
|
|
20
|
+
const flushLine = (line) => {
|
|
21
|
+
emit(line.endsWith("\r") ? line.slice(0, -1) : line);
|
|
22
|
+
};
|
|
23
|
+
return new Writable({
|
|
24
|
+
final(callback) {
|
|
25
|
+
buffer += decoder.end();
|
|
26
|
+
if (buffer.length > 0) {
|
|
27
|
+
flushLine(buffer);
|
|
28
|
+
buffer = "";
|
|
29
|
+
}
|
|
30
|
+
callback();
|
|
31
|
+
},
|
|
32
|
+
write(chunk, _encoding, callback) {
|
|
33
|
+
buffer += decoder.write(chunk);
|
|
34
|
+
const lines = buffer.split("\n");
|
|
35
|
+
buffer = lines.pop() ?? "";
|
|
36
|
+
for (const line of lines) {
|
|
37
|
+
flushLine(line);
|
|
38
|
+
}
|
|
39
|
+
callback();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
const streamContainerLogs = (options) => {
|
|
44
|
+
const classToExport = new Map(options.containers.map((source) => [source.className.toLowerCase(), source.exportName]));
|
|
45
|
+
if (classToExport.size === 0) {
|
|
46
|
+
return { close: () => {
|
|
47
|
+
} };
|
|
48
|
+
}
|
|
49
|
+
const interval = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
50
|
+
const attached = /* @__PURE__ */ new Map();
|
|
51
|
+
let closed = false;
|
|
52
|
+
let unavailableNotified = false;
|
|
53
|
+
let timer;
|
|
54
|
+
let dockerPromise;
|
|
55
|
+
const getDocker = async () => {
|
|
56
|
+
dockerPromise ??= options.docker ? Promise.resolve(options.docker) : createDefaultDocker();
|
|
57
|
+
return dockerPromise;
|
|
58
|
+
};
|
|
59
|
+
const attach = async (docker, id, exportName) => {
|
|
60
|
+
try {
|
|
61
|
+
const stream = await docker.getContainer(id).logs({ follow: true, stderr: true, stdout: true, tail: "all", timestamps: false });
|
|
62
|
+
if (closed) {
|
|
63
|
+
stream.destroy();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const stdout = lineBufferWritable((text) => {
|
|
67
|
+
options.onLine({ level: "info", name: exportName, text });
|
|
68
|
+
});
|
|
69
|
+
const stderr = lineBufferWritable((text) => {
|
|
70
|
+
options.onLine({ level: "error", name: exportName, text });
|
|
71
|
+
});
|
|
72
|
+
docker.modem.demuxStream(stream, stdout, stderr);
|
|
73
|
+
stream.on("end", () => {
|
|
74
|
+
stdout.end();
|
|
75
|
+
stderr.end();
|
|
76
|
+
attached.delete(id);
|
|
77
|
+
});
|
|
78
|
+
stream.on("error", () => {
|
|
79
|
+
attached.delete(id);
|
|
80
|
+
});
|
|
81
|
+
attached.set(id, stream);
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const listRunning = async () => {
|
|
86
|
+
try {
|
|
87
|
+
const docker = await getDocker();
|
|
88
|
+
const running = await docker.listContainers({ filters: { status: ["running"] } });
|
|
89
|
+
unavailableNotified = false;
|
|
90
|
+
return running;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (!unavailableNotified) {
|
|
93
|
+
unavailableNotified = true;
|
|
94
|
+
options.onUnavailable?.(error instanceof Error ? error.message : String(error));
|
|
95
|
+
}
|
|
96
|
+
return void 0;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const reconcile = async (docker, running) => {
|
|
100
|
+
const live = /* @__PURE__ */ new Set();
|
|
101
|
+
for (const summary of running) {
|
|
102
|
+
const className = classFromImage(summary.Image);
|
|
103
|
+
const exportName = className === void 0 ? void 0 : classToExport.get(className);
|
|
104
|
+
if (exportName === void 0) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
live.add(summary.Id);
|
|
108
|
+
if (!attached.has(summary.Id)) {
|
|
109
|
+
await attach(docker, summary.Id, exportName);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
for (const [id, stream] of attached) {
|
|
113
|
+
if (!live.has(id)) {
|
|
114
|
+
stream.destroy();
|
|
115
|
+
attached.delete(id);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const poll = async () => {
|
|
120
|
+
if (closed) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const running = await listRunning();
|
|
124
|
+
if (running === void 0) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
await reconcile(await getDocker(), running);
|
|
128
|
+
};
|
|
129
|
+
let polling = false;
|
|
130
|
+
const onTick = () => {
|
|
131
|
+
if (polling || closed) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
polling = true;
|
|
135
|
+
poll().finally(() => {
|
|
136
|
+
polling = false;
|
|
137
|
+
}).catch(() => void 0);
|
|
138
|
+
};
|
|
139
|
+
timer = setInterval(onTick, interval);
|
|
140
|
+
timer.unref();
|
|
141
|
+
onTick();
|
|
142
|
+
return {
|
|
143
|
+
close: () => {
|
|
144
|
+
closed = true;
|
|
145
|
+
if (timer) {
|
|
146
|
+
clearInterval(timer);
|
|
147
|
+
timer = void 0;
|
|
148
|
+
}
|
|
149
|
+
for (const [id, stream] of attached) {
|
|
150
|
+
stream.destroy();
|
|
151
|
+
attached.delete(id);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export { streamContainerLogs };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { parseDevVariable, resolveAdminToken } from '../packem_shared/parseDevVariable-CJiq2IwE.mjs';
|
|
2
|
-
export { default as loadStudioAssets, studioAssetsStamp } from '../packem_shared/
|
|
3
|
-
export { POLICY_SCAFFOLD_ENDPOINT, handlePolicyScaffoldRequest } from '../packem_shared/
|
|
2
|
+
export { default as loadStudioAssets, studioAssetsStamp } from '../packem_shared/loadStudioAssets-Csk5RS4E.mjs';
|
|
3
|
+
export { POLICY_SCAFFOLD_ENDPOINT, handlePolicyScaffoldRequest } from '../packem_shared/POLICY_SCAFFOLD_ENDPOINT-CiC2IGKx.mjs';
|
|
4
4
|
export { default as renderStudioHtml } from '../packem_shared/renderStudioHtml-449Ysn75.mjs';
|
|
5
|
-
export { SCHEMA_EDIT_ENDPOINT, handleSchemaEditRequest } from '../packem_shared/
|
|
6
|
-
export { SEED_ENDPOINT, handleSeedRequest } from '../packem_shared/
|
|
5
|
+
export { SCHEMA_EDIT_ENDPOINT, handleSchemaEditRequest } from '../packem_shared/SCHEMA_EDIT_ENDPOINT-Df-Wrix-.mjs';
|
|
6
|
+
export { SEED_ENDPOINT, handleSeedRequest } from '../packem_shared/SEED_ENDPOINT-DVCjaGO-.mjs';
|
|
7
7
|
export { serveJsonHandler } from '../packem_shared/serveJsonHandler-B4OLTGLS.mjs';
|