@lunora/config 1.0.0-alpha.6 → 1.0.0-alpha.61
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/LICENSE.md +6 -0
- package/__assets__/package-og.svg +1 -1
- package/dist/index.d.mts +372 -6
- package/dist/index.d.ts +372 -6
- package/dist/index.mjs +12 -7
- package/dist/packem_shared/AGENT_MODE_ENV-B5R7jpY7.mjs +17 -0
- package/dist/packem_shared/DEV_DAEMON_ENV-FIEtW7Fz.mjs +163 -0
- package/dist/packem_shared/{PACKAGE_SECRETS_REGISTRY-CySy5vR_.mjs → PACKAGE_SECRETS_REGISTRY-BeRSvrl5.mjs} +45 -1
- package/dist/packem_shared/{POLICY_SCAFFOLD_ENDPOINT-CiC2IGKx.mjs → POLICY_SCAFFOLD_ENDPOINT-8bNMHGiu.mjs} +2 -1
- package/dist/packem_shared/{REQUIRED_COMPATIBILITY_DATE-ycqievRl.mjs → REQUIRED_COMPATIBILITY_DATE-DYYxY_If.mjs} +133 -1
- package/dist/packem_shared/assetContentType-ByZjeV3D.mjs +72 -0
- package/dist/packem_shared/{buildPackageSecretsBlock-S74dgmwy.mjs → buildPackageSecretsBlock-BDXX0mKG.mjs} +114 -20
- package/dist/packem_shared/collectWranglerSecretVariables-Red5H-4V.mjs +56 -0
- package/dist/packem_shared/{detectFramework-Br-BcPBq.mjs → detectFramework-U08038Yp.mjs} +3 -3
- package/dist/packem_shared/{discoverSchemaInfo-DWtypqpP.mjs → discoverSchemaInfo-BB-CKlTK.mjs} +1 -1
- package/dist/packem_shared/{inferLunoraBindings-XNJH4pup.mjs → inferLunoraBindings-BadOK1UZ.mjs} +77 -13
- package/dist/packem_shared/{reconcileWranglerBindings-DTHmqTbL.mjs → reconcileWranglerBindings-BZdPBnpZ.mjs} +74 -4
- package/dist/packem_shared/reconcileWranglerCompatibilityDate-CYY0rVnJ.mjs +34 -0
- package/dist/packem_shared/streamContainerLogs-BZ4cOZwH.mjs +157 -0
- package/dist/studio-host/index.d.mts +33 -1
- package/dist/studio-host/index.d.ts +33 -1
- package/dist/studio-host/index.mjs +2 -2
- package/package.json +11 -8
- package/dist/packem_shared/loadStudioAssets-Csk5RS4E.mjs +0 -28
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { relative } from 'node:path';
|
|
2
|
+
import { secretKindOf, redact } from '@lunora/codegen';
|
|
3
|
+
import { isPlaceholderValue } from './buildPackageSecretsBlock-BDXX0mKG.mjs';
|
|
4
|
+
import { findWranglerFile, readWranglerJsonc } from './WRANGLER_FILES-DwSuC-Kn.mjs';
|
|
5
|
+
|
|
6
|
+
const MIN_SECRET_NAMED_VALUE_LENGTH = 8;
|
|
7
|
+
const SECRET_WORD_TOKENS = /* @__PURE__ */ new Set(["CREDENTIAL", "CREDENTIALS", "DSN", "PASSPHRASE", "PASSWD", "PASSWORD", "SECRET", "TOKEN"]);
|
|
8
|
+
const SECRET_KEY_SUFFIXES = ["ACCESS_KEY", "API_KEY", "ENCRYPTION_KEY", "PRIVATE_KEY", "SIGNING_KEY"];
|
|
9
|
+
const PUBLIC_KEY_TOKENS = /* @__PURE__ */ new Set(["PUBLIC", "PUBLISHABLE"]);
|
|
10
|
+
const KEY_SEPARATOR_RE = /[_-]/u;
|
|
11
|
+
const keyTokens = (key) => key.toUpperCase().split(KEY_SEPARATOR_RE);
|
|
12
|
+
const isSecretKeyName = (key) => {
|
|
13
|
+
const normalized = key.toUpperCase().replaceAll("-", "_");
|
|
14
|
+
if (keyTokens(key).some((token) => SECRET_WORD_TOKENS.has(token))) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return SECRET_KEY_SUFFIXES.some((suffix) => normalized === suffix || normalized.endsWith(`_${suffix}`));
|
|
18
|
+
};
|
|
19
|
+
const isPublicKeyName = (key) => keyTokens(key).some((token) => PUBLIC_KEY_TOKENS.has(token));
|
|
20
|
+
const scanWranglerVariablesForSecrets = (variables, file) => {
|
|
21
|
+
if (variables === void 0) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
const findings = [];
|
|
25
|
+
for (const [key, rawValue] of Object.entries(variables)) {
|
|
26
|
+
if (typeof rawValue !== "string") {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (isPlaceholderValue(rawValue)) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (isPublicKeyName(key)) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const shapeKind = secretKindOf(rawValue);
|
|
36
|
+
const kind = shapeKind ?? (isSecretKeyName(key) && rawValue.length >= MIN_SECRET_NAMED_VALUE_LENGTH ? "secret_named_var" : void 0);
|
|
37
|
+
if (kind === void 0) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
findings.push({ file, key, kind, preview: redact(rawValue) });
|
|
41
|
+
}
|
|
42
|
+
return findings;
|
|
43
|
+
};
|
|
44
|
+
const collectWranglerSecretVariables = (projectRoot) => {
|
|
45
|
+
const wranglerPath = findWranglerFile(projectRoot);
|
|
46
|
+
if (wranglerPath === void 0) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
const { parsed } = readWranglerJsonc(wranglerPath);
|
|
50
|
+
if (parsed === void 0) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
return scanWranglerVariablesForSecrets(parsed.vars, relative(projectRoot, wranglerPath));
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export { collectWranglerSecretVariables, scanWranglerVariablesForSecrets };
|
|
@@ -12,7 +12,7 @@ const FRAMEWORK_SIGNATURES = [
|
|
|
12
12
|
{ class: "B", dependency: "astro", framework: "astro" }
|
|
13
13
|
];
|
|
14
14
|
const STANDALONE = { class: "C", framework: "none" };
|
|
15
|
-
const
|
|
15
|
+
const readProjectDependencyNames = (root) => {
|
|
16
16
|
const packageJsonPath = join(root, "package.json");
|
|
17
17
|
if (!existsSync(packageJsonPath)) {
|
|
18
18
|
return /* @__PURE__ */ new Set();
|
|
@@ -26,7 +26,7 @@ const readDependencyNames = (root) => {
|
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
28
|
const detectFramework = (root) => {
|
|
29
|
-
const dependencies =
|
|
29
|
+
const dependencies = readProjectDependencyNames(root);
|
|
30
30
|
if (dependencies.size === 0) {
|
|
31
31
|
return STANDALONE;
|
|
32
32
|
}
|
|
@@ -38,4 +38,4 @@ const detectFramework = (root) => {
|
|
|
38
38
|
return STANDALONE;
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
export { detectFramework };
|
|
41
|
+
export { detectFramework, readProjectDependencyNames };
|
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-XNJH4pup.mjs → inferLunoraBindings-BadOK1UZ.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 {
|
|
4
|
+
import { FLAGS_FILENAME, discoverFlags, QUEUES_FILENAME, discoverQueues } from '@lunora/codegen';
|
|
5
|
+
import { Project } from 'ts-morph';
|
|
6
|
+
import { join } from 'node:path';
|
|
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 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,20 +51,31 @@ 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
|
-
usesStorage: { pattern: /\bfrom\s+["']@lunora\/storage["']/, source: "@lunora/storage" }
|
|
72
|
+
usesStorage: { pattern: /\bfrom\s+["']@lunora\/storage["']/, source: "@lunora/storage" },
|
|
73
|
+
// x402 rails are opt-in add-on subpaths (not part of the `lunorash` umbrella),
|
|
74
|
+
// so they key off the exact `@lunora/x402/{charge,pay}` specifiers. Neither
|
|
75
|
+
// implies a `.dev.vars` secret: the charge recipient is a user-named `[vars]`
|
|
76
|
+
// entry and the pay wallet key is a Secrets Store binding — both hint-only.
|
|
77
|
+
usesX402Charge: { pattern: /\bfrom\s+["']@lunora\/x402\/charge["']/, source: "@lunora/x402/charge" },
|
|
78
|
+
usesX402Pay: { pattern: /\bfrom\s+["']@lunora\/x402\/pay["']/, source: "@lunora/x402/pay" }
|
|
40
79
|
};
|
|
41
80
|
const CAPABILITY_FLAGS = Object.keys(CAPABILITY_SOURCES);
|
|
42
81
|
const PAYMENT_PROVIDER_SECRETS = "STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET (Stripe) or POLAR_ACCESS_TOKEN + POLAR_WEBHOOK_SECRET (Polar)";
|
|
@@ -90,7 +129,12 @@ const capabilitiesFromSource = (code) => {
|
|
|
90
129
|
} catch {
|
|
91
130
|
capabilities = regexCapabilities(code);
|
|
92
131
|
}
|
|
93
|
-
return mergeCapabilities(capabilities, {
|
|
132
|
+
return mergeCapabilities(capabilities, {
|
|
133
|
+
...NO_CAPABILITIES,
|
|
134
|
+
needsD1: ENV_DB_PATTERN.test(code),
|
|
135
|
+
usesAi: ENV_AI_PATTERN.test(code),
|
|
136
|
+
usesPipelines: CTX_PIPELINES_PATTERN.test(code)
|
|
137
|
+
});
|
|
94
138
|
};
|
|
95
139
|
const collectSourceFiles = (directory, accumulator) => {
|
|
96
140
|
let entries;
|
|
@@ -237,14 +281,14 @@ const describeCapabilitySignals = (capabilities, exported) => {
|
|
|
237
281
|
// Self-describing bindings: the binding name is the whole config (no remote
|
|
238
282
|
// id to mint), so reconcile auto-writes them like the DO/D1 bindings.
|
|
239
283
|
[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 }"],
|
|
284
|
+
[capabilities.usesImages, "images (@lunora/bindings/images imported) — self-describing { binding: IMAGES }"],
|
|
285
|
+
[capabilities.usesAnalytics, "analytics_engine_datasets (@lunora/bindings/analytics imported) — self-describing { binding: ANALYTICS, dataset }"],
|
|
242
286
|
// Hint bindings: each needs a remote resource Lunora can't fabricate (a KV
|
|
243
287
|
// namespace id, a Hyperdrive id, a Pipelines pipeline name), so they surface
|
|
244
288
|
// as hints — never an auto-write — exactly like R2's user-defined bucket name.
|
|
245
289
|
[
|
|
246
290
|
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"
|
|
291
|
+
"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
292
|
],
|
|
249
293
|
[
|
|
250
294
|
capabilities.usesHyperdrive,
|
|
@@ -252,7 +296,15 @@ const describeCapabilitySignals = (capabilities, exported) => {
|
|
|
252
296
|
],
|
|
253
297
|
[
|
|
254
298
|
capabilities.usesPipelines,
|
|
255
|
-
"hint:
|
|
299
|
+
"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"
|
|
300
|
+
],
|
|
301
|
+
[
|
|
302
|
+
capabilities.usesX402Charge,
|
|
303
|
+
"hint: @lunora/x402/charge is imported; set the recipient wallet address as a [vars] entry (the var name is yours to choose) and pass it to the charge config — the x402 facilitator settles USDC to that address"
|
|
304
|
+
],
|
|
305
|
+
[
|
|
306
|
+
capabilities.usesX402Pay,
|
|
307
|
+
"hint: @lunora/x402/pay is imported (ActionCtx-only, spends real funds); add a secrets_store_secrets[] binding for the agent wallet key (name it to match signer.secretName) and pair the pay rail with a spend policy — ctx.secrets reads a Secrets Store binding, not .dev.vars, so the key can't be auto-provisioned"
|
|
256
308
|
]
|
|
257
309
|
];
|
|
258
310
|
return rules.filter(([active]) => active).map(([, signal]) => signal);
|
|
@@ -276,15 +328,27 @@ const inferLunoraBindings = async (options) => {
|
|
|
276
328
|
const needsD1 = capabilities.needsD1 || schemaNeedsD1(options.projectRoot, schemaDirectory);
|
|
277
329
|
const containers = detectContainerExports(entryPath, discoverContainerInfo(options.projectRoot, schemaDirectory).containers);
|
|
278
330
|
const workflows = detectWorkflowExports(entryPath, discoverWorkflowInfo(options.projectRoot, schemaDirectory).workflows);
|
|
331
|
+
const queues = [...discoverQueueInfo(options.projectRoot, schemaDirectory).queues];
|
|
332
|
+
const { flags } = discoverFlagsInfo(options.projectRoot, schemaDirectory);
|
|
333
|
+
const flagshipBinding = flags?.provider === "flagship" && flags.mode === "binding" ? flags.bindingName : void 0;
|
|
279
334
|
const capabilityFlags = {};
|
|
280
335
|
for (const flag of CAPABILITY_FLAGS) {
|
|
281
336
|
capabilityFlags[flag] = capabilities[flag];
|
|
282
337
|
}
|
|
338
|
+
const signals = describeSignals(durableObjects, needsD1, capabilities, containers, workflows);
|
|
339
|
+
if (flagshipBinding !== void 0) {
|
|
340
|
+
signals.push(
|
|
341
|
+
`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`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
283
344
|
return {
|
|
284
345
|
containers,
|
|
285
346
|
durableObjects,
|
|
347
|
+
flagshipBinding,
|
|
286
348
|
needsD1,
|
|
287
|
-
|
|
349
|
+
queues,
|
|
350
|
+
signals,
|
|
351
|
+
usesFlags: flags !== void 0,
|
|
288
352
|
workflows,
|
|
289
353
|
...capabilityFlags
|
|
290
354
|
};
|
|
@@ -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,24 @@ 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.`
|
|
40
|
+
]
|
|
41
|
+
];
|
|
42
|
+
return rules.filter(([active]) => active).map(([, warning]) => warning);
|
|
43
|
+
};
|
|
44
|
+
const collectX402Warnings = (inferred) => {
|
|
45
|
+
const rules = [
|
|
46
|
+
[
|
|
47
|
+
inferred.usesX402Charge,
|
|
48
|
+
"@lunora/x402/charge is used; set the recipient wallet address as a [vars] entry (the var name is your choice) and pass it to the charge config — the x402 facilitator settles USDC to that address."
|
|
49
|
+
],
|
|
50
|
+
[
|
|
51
|
+
inferred.usesX402Pay,
|
|
52
|
+
"@lunora/x402/pay is used (ActionCtx-only, spends real funds); add a secrets_store_secrets[] binding holding the agent wallet key (binding name == signer.secretName) and pair the pay rail with a spend policy — ctx.secrets reads a Secrets Store binding, not .dev.vars."
|
|
35
53
|
]
|
|
36
54
|
];
|
|
37
55
|
return rules.filter(([active]) => active).map(([, warning]) => warning);
|
|
@@ -76,7 +94,7 @@ const collectWarnings = (inferred, parsed) => {
|
|
|
76
94
|
"@lunora/payment is used; set the provider secrets in .dev.vars — STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET (Stripe) or POLAR_ACCESS_TOKEN + POLAR_WEBHOOK_SECRET (Polar)."
|
|
77
95
|
);
|
|
78
96
|
}
|
|
79
|
-
warnings.push(...collectHintBindingWarnings(inferred, parsed));
|
|
97
|
+
warnings.push(...collectX402Warnings(inferred), ...collectHintBindingWarnings(inferred, parsed));
|
|
80
98
|
return warnings;
|
|
81
99
|
};
|
|
82
100
|
const applyModify = (text, path, value) => {
|
|
@@ -222,6 +240,57 @@ const reconcileWorkflows = (text, parsed, workflows) => {
|
|
|
222
240
|
const nextText = applyModify(text, ["workflows"], [...existing, ...missing.map((workflow) => workflowEntryFor(workflow))]);
|
|
223
241
|
return { added: missing.map((workflow) => `workflows/${workflow.className}`), text: nextText };
|
|
224
242
|
};
|
|
243
|
+
const reconcileQueues = (text, parsed, queues) => {
|
|
244
|
+
const existing = parsed.queues ?? {};
|
|
245
|
+
const existingProducers = existing.producers ?? [];
|
|
246
|
+
const existingConsumers = existing.consumers ?? [];
|
|
247
|
+
const haveProducer = new Set(existingProducers.map((entry) => entry.binding));
|
|
248
|
+
const haveConsumer = new Set(existingConsumers.map((entry) => entry.queue));
|
|
249
|
+
const missingProducers = queues.filter((queue) => !haveProducer.has(queue.bindingName));
|
|
250
|
+
const missingConsumers = queues.filter((queue) => !haveConsumer.has(queue.name));
|
|
251
|
+
if (missingProducers.length === 0 && missingConsumers.length === 0) {
|
|
252
|
+
return { added: [], text };
|
|
253
|
+
}
|
|
254
|
+
const nextProducers = [
|
|
255
|
+
...existingProducers,
|
|
256
|
+
...missingProducers.map((queue) => {
|
|
257
|
+
return { binding: queue.bindingName, queue: queue.name };
|
|
258
|
+
})
|
|
259
|
+
];
|
|
260
|
+
const nextConsumers = [
|
|
261
|
+
...existingConsumers,
|
|
262
|
+
...missingConsumers.map((queue) => {
|
|
263
|
+
const consumer = { queue: queue.name };
|
|
264
|
+
if (queue.mode === "pull") {
|
|
265
|
+
consumer.type = "http_pull";
|
|
266
|
+
}
|
|
267
|
+
if (queue.tuning.maxBatchSize !== void 0) {
|
|
268
|
+
consumer.max_batch_size = queue.tuning.maxBatchSize;
|
|
269
|
+
}
|
|
270
|
+
if (queue.tuning.maxBatchTimeout !== void 0) {
|
|
271
|
+
consumer.max_batch_timeout = queue.tuning.maxBatchTimeout;
|
|
272
|
+
}
|
|
273
|
+
if (queue.tuning.maxRetries !== void 0) {
|
|
274
|
+
consumer.max_retries = queue.tuning.maxRetries;
|
|
275
|
+
}
|
|
276
|
+
if (queue.tuning.deadLetterQueue !== void 0) {
|
|
277
|
+
consumer.dead_letter_queue = queue.tuning.deadLetterQueue;
|
|
278
|
+
}
|
|
279
|
+
if (queue.tuning.retryDelay !== void 0) {
|
|
280
|
+
consumer.retry_delay = queue.tuning.retryDelay;
|
|
281
|
+
}
|
|
282
|
+
return consumer;
|
|
283
|
+
})
|
|
284
|
+
];
|
|
285
|
+
const nextText = applyModify(text, ["queues"], { consumers: nextConsumers, producers: nextProducers });
|
|
286
|
+
return {
|
|
287
|
+
added: [
|
|
288
|
+
...missingProducers.map((queue) => `queues.producers/${queue.bindingName}`),
|
|
289
|
+
...missingConsumers.map((queue) => `queues.consumers/${queue.name}`)
|
|
290
|
+
],
|
|
291
|
+
text: nextText
|
|
292
|
+
};
|
|
293
|
+
};
|
|
225
294
|
const reconcileWranglerBindings = (projectRoot, inferred) => {
|
|
226
295
|
const wranglerPath = findWranglerFile(projectRoot);
|
|
227
296
|
const exportGaps = collectExportGaps(inferred);
|
|
@@ -250,7 +319,8 @@ const reconcileWranglerBindings = (projectRoot, inferred) => {
|
|
|
250
319
|
{ enabled: inferred.usesAnalytics, run: (text2) => reconcileAnalytics(text2, parsed) },
|
|
251
320
|
{ enabled: true, run: (text2) => reconcileObservability(text2, parsed) },
|
|
252
321
|
{ enabled: exportedContainers.length > 0, run: (text2) => reconcileContainers(text2, parsed, exportedContainers) },
|
|
253
|
-
{ enabled: exportedWorkflows.length > 0, run: (text2) => reconcileWorkflows(text2, parsed, exportedWorkflows) }
|
|
322
|
+
{ enabled: exportedWorkflows.length > 0, run: (text2) => reconcileWorkflows(text2, parsed, exportedWorkflows) },
|
|
323
|
+
{ enabled: inferred.queues.length > 0, run: (text2) => reconcileQueues(text2, parsed, inferred.queues) }
|
|
254
324
|
];
|
|
255
325
|
let text = original;
|
|
256
326
|
const added = [];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { writeFileSync } from 'node:fs';
|
|
2
|
+
import { modify, applyEdits } from 'jsonc-parser';
|
|
3
|
+
import { findWranglerFile, readWranglerJsonc } from './WRANGLER_FILES-DwSuC-Kn.mjs';
|
|
4
|
+
|
|
5
|
+
const WORKERS_CACHE_MIN_DATE = "2026-05-01";
|
|
6
|
+
const FORMATTING = { formattingOptions: { insertSpaces: true, tabSize: 4 } };
|
|
7
|
+
const reconcileWranglerCompatibilityDate = (projectRoot) => {
|
|
8
|
+
const wranglerPath = findWranglerFile(projectRoot);
|
|
9
|
+
if (!wranglerPath) {
|
|
10
|
+
return { changed: false, date: void 0, reason: "wrangler.jsonc not found" };
|
|
11
|
+
}
|
|
12
|
+
const { parsed, text } = readWranglerJsonc(wranglerPath);
|
|
13
|
+
if (parsed === void 0) {
|
|
14
|
+
return { changed: false, date: void 0, reason: `failed to parse ${wranglerPath} as JSONC`, wranglerPath };
|
|
15
|
+
}
|
|
16
|
+
const currentDate = parsed.compatibility_date ?? "";
|
|
17
|
+
const cacheEnabledTopLevel = typeof parsed.cache === "object" && parsed.cache !== null && parsed.cache.enabled === true;
|
|
18
|
+
const cacheEnabledInExports = typeof parsed.exports === "object" && parsed.exports !== null && Object.values(parsed.exports).some((entry) => typeof entry === "object" && entry !== null && entry.cache?.enabled === true);
|
|
19
|
+
const needsCacheDate = cacheEnabledTopLevel || cacheEnabledInExports;
|
|
20
|
+
if (!needsCacheDate) {
|
|
21
|
+
return { changed: false, date: currentDate || void 0, reason: "cache not enabled", wranglerPath };
|
|
22
|
+
}
|
|
23
|
+
if (currentDate >= WORKERS_CACHE_MIN_DATE) {
|
|
24
|
+
return { changed: false, date: currentDate, reason: `compatibility_date already >= ${WORKERS_CACHE_MIN_DATE}`, wranglerPath };
|
|
25
|
+
}
|
|
26
|
+
const edits = modify(text, ["compatibility_date"], WORKERS_CACHE_MIN_DATE, FORMATTING);
|
|
27
|
+
if (edits.length === 0) {
|
|
28
|
+
return { changed: false, date: currentDate || void 0, reason: "no structural edit produced", wranglerPath };
|
|
29
|
+
}
|
|
30
|
+
writeFileSync(wranglerPath, applyEdits(text, edits), "utf8");
|
|
31
|
+
return { changed: true, date: WORKERS_CACHE_MIN_DATE, wranglerPath };
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export { reconcileWranglerCompatibilityDate };
|
|
@@ -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 };
|
|
@@ -81,6 +81,38 @@ declare const loadStudioAssets: (logger?: WarnLogger, resolveFrom?: string) => S
|
|
|
81
81
|
*/
|
|
82
82
|
declare const studioAssetsStamp: (resolveFrom?: string) => number | undefined;
|
|
83
83
|
/**
|
|
84
|
+
* Absolute path of the built standalone directory — `@lunora/studio`'s
|
|
85
|
+
* `dist/standalone`, where the `studio.js` entry and its code-split `chunk-*.js`
|
|
86
|
+
* siblings live — or `undefined` when the studio isn't installed/built. The
|
|
87
|
+
* standalone bundle is emitted with esbuild `splitting`, so the hosts must serve
|
|
88
|
+
* the whole directory (not two fixed paths); this resolves its root.
|
|
89
|
+
*/
|
|
90
|
+
declare const resolveStandaloneDirectory: (resolveFrom?: string) => string | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Read a single file from the standalone directory by its plain filename (the
|
|
93
|
+
* `studio.js` entry, a `chunk-*.js`, or a `.map`). **Path-traversal-safe** via
|
|
94
|
+
* {@link resolveContainedFile}: only a lone filename resolving to a direct child
|
|
95
|
+
* of the standalone directory is served — any separator, `..`, NUL, or absolute
|
|
96
|
+
* path is rejected — so a request like `../../etc/passwd` can never escape it.
|
|
97
|
+
* Returns the bytes, or `undefined` when the studio isn't built or the name
|
|
98
|
+
* doesn't resolve to a file inside the directory (the host answers that 404).
|
|
99
|
+
*/
|
|
100
|
+
declare const readStandaloneAsset: (fileName: string, resolveFrom?: string) => Buffer | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* True when `pathname` addresses a standalone JS module — the `studio.js` entry
|
|
103
|
+
* or one of its code-split `chunk-*.js` siblings (and their `.map`s). Shared by
|
|
104
|
+
* the CLI and Vite hosts so both route the same request shapes to the directory
|
|
105
|
+
* server; the stylesheet is matched separately at each host's own style path.
|
|
106
|
+
*/
|
|
107
|
+
declare const isStandaloneModulePath: (pathname: string) => boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Content-Type for a served standalone asset, by extension: `.css` → CSS,
|
|
110
|
+
* `.map` → JSON (a source map), everything else (the `.js` entry + chunks) →
|
|
111
|
+
* JavaScript. Shared by the CLI and Vite hosts so the MIME decision lives in one
|
|
112
|
+
* place.
|
|
113
|
+
*/
|
|
114
|
+
declare const assetContentType: (fileName: string) => string;
|
|
115
|
+
/**
|
|
84
116
|
* Endpoint path both dev hosts mount the handler at. A sibling of the schema
|
|
85
117
|
* editor's `/__lunora/schema-edit`; the double underscore keeps it clear of the
|
|
86
118
|
* CLI's `/_lunora/*` worker proxy (single underscore).
|
|
@@ -224,4 +256,4 @@ type LocalEndpointHandler = (request: LocalEndpointRequest) => LocalEndpointResp
|
|
|
224
256
|
* `400`; an unexpected throw (e.g. the body-size guard) is a `500`.
|
|
225
257
|
*/
|
|
226
258
|
declare const serveJsonHandler: (request: IncomingMessage, response: ServerResponse, handle: LocalEndpointHandler, projectRoot: string) => void;
|
|
227
|
-
export { type LocalEndpointHandler, type LocalEndpointRequest, type LocalEndpointResponse, POLICY_SCAFFOLD_ENDPOINT, type PolicyScaffoldBody, type PolicyScaffoldRequest, type PolicyScaffoldResponse, SCHEMA_EDIT_ENDPOINT, SEED_ENDPOINT, type SchemaEditRequest, type SchemaEditResponse, type SeedRequest, type SeedRequestBody, type SeedResponse, type StudioAssets, type StudioHtmlConfig, type WarnLogger, type WirePolicyEdit, handlePolicyScaffoldRequest, handleSchemaEditRequest, handleSeedRequest, loadStudioAssets, parseDevVariable, renderStudioHtml, resolveAdminToken, serveJsonHandler, studioAssetsStamp };
|
|
259
|
+
export { type LocalEndpointHandler, type LocalEndpointRequest, type LocalEndpointResponse, POLICY_SCAFFOLD_ENDPOINT, type PolicyScaffoldBody, type PolicyScaffoldRequest, type PolicyScaffoldResponse, SCHEMA_EDIT_ENDPOINT, SEED_ENDPOINT, type SchemaEditRequest, type SchemaEditResponse, type SeedRequest, type SeedRequestBody, type SeedResponse, type StudioAssets, type StudioHtmlConfig, type WarnLogger, type WirePolicyEdit, assetContentType, handlePolicyScaffoldRequest, handleSchemaEditRequest, handleSeedRequest, isStandaloneModulePath, loadStudioAssets, parseDevVariable, readStandaloneAsset, renderStudioHtml, resolveAdminToken, resolveStandaloneDirectory, serveJsonHandler, studioAssetsStamp };
|
|
@@ -81,6 +81,38 @@ declare const loadStudioAssets: (logger?: WarnLogger, resolveFrom?: string) => S
|
|
|
81
81
|
*/
|
|
82
82
|
declare const studioAssetsStamp: (resolveFrom?: string) => number | undefined;
|
|
83
83
|
/**
|
|
84
|
+
* Absolute path of the built standalone directory — `@lunora/studio`'s
|
|
85
|
+
* `dist/standalone`, where the `studio.js` entry and its code-split `chunk-*.js`
|
|
86
|
+
* siblings live — or `undefined` when the studio isn't installed/built. The
|
|
87
|
+
* standalone bundle is emitted with esbuild `splitting`, so the hosts must serve
|
|
88
|
+
* the whole directory (not two fixed paths); this resolves its root.
|
|
89
|
+
*/
|
|
90
|
+
declare const resolveStandaloneDirectory: (resolveFrom?: string) => string | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Read a single file from the standalone directory by its plain filename (the
|
|
93
|
+
* `studio.js` entry, a `chunk-*.js`, or a `.map`). **Path-traversal-safe** via
|
|
94
|
+
* {@link resolveContainedFile}: only a lone filename resolving to a direct child
|
|
95
|
+
* of the standalone directory is served — any separator, `..`, NUL, or absolute
|
|
96
|
+
* path is rejected — so a request like `../../etc/passwd` can never escape it.
|
|
97
|
+
* Returns the bytes, or `undefined` when the studio isn't built or the name
|
|
98
|
+
* doesn't resolve to a file inside the directory (the host answers that 404).
|
|
99
|
+
*/
|
|
100
|
+
declare const readStandaloneAsset: (fileName: string, resolveFrom?: string) => Buffer | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* True when `pathname` addresses a standalone JS module — the `studio.js` entry
|
|
103
|
+
* or one of its code-split `chunk-*.js` siblings (and their `.map`s). Shared by
|
|
104
|
+
* the CLI and Vite hosts so both route the same request shapes to the directory
|
|
105
|
+
* server; the stylesheet is matched separately at each host's own style path.
|
|
106
|
+
*/
|
|
107
|
+
declare const isStandaloneModulePath: (pathname: string) => boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Content-Type for a served standalone asset, by extension: `.css` → CSS,
|
|
110
|
+
* `.map` → JSON (a source map), everything else (the `.js` entry + chunks) →
|
|
111
|
+
* JavaScript. Shared by the CLI and Vite hosts so the MIME decision lives in one
|
|
112
|
+
* place.
|
|
113
|
+
*/
|
|
114
|
+
declare const assetContentType: (fileName: string) => string;
|
|
115
|
+
/**
|
|
84
116
|
* Endpoint path both dev hosts mount the handler at. A sibling of the schema
|
|
85
117
|
* editor's `/__lunora/schema-edit`; the double underscore keeps it clear of the
|
|
86
118
|
* CLI's `/_lunora/*` worker proxy (single underscore).
|
|
@@ -224,4 +256,4 @@ type LocalEndpointHandler = (request: LocalEndpointRequest) => LocalEndpointResp
|
|
|
224
256
|
* `400`; an unexpected throw (e.g. the body-size guard) is a `500`.
|
|
225
257
|
*/
|
|
226
258
|
declare const serveJsonHandler: (request: IncomingMessage, response: ServerResponse, handle: LocalEndpointHandler, projectRoot: string) => void;
|
|
227
|
-
export { type LocalEndpointHandler, type LocalEndpointRequest, type LocalEndpointResponse, POLICY_SCAFFOLD_ENDPOINT, type PolicyScaffoldBody, type PolicyScaffoldRequest, type PolicyScaffoldResponse, SCHEMA_EDIT_ENDPOINT, SEED_ENDPOINT, type SchemaEditRequest, type SchemaEditResponse, type SeedRequest, type SeedRequestBody, type SeedResponse, type StudioAssets, type StudioHtmlConfig, type WarnLogger, type WirePolicyEdit, handlePolicyScaffoldRequest, handleSchemaEditRequest, handleSeedRequest, loadStudioAssets, parseDevVariable, renderStudioHtml, resolveAdminToken, serveJsonHandler, studioAssetsStamp };
|
|
259
|
+
export { type LocalEndpointHandler, type LocalEndpointRequest, type LocalEndpointResponse, POLICY_SCAFFOLD_ENDPOINT, type PolicyScaffoldBody, type PolicyScaffoldRequest, type PolicyScaffoldResponse, SCHEMA_EDIT_ENDPOINT, SEED_ENDPOINT, type SchemaEditRequest, type SchemaEditResponse, type SeedRequest, type SeedRequestBody, type SeedResponse, type StudioAssets, type StudioHtmlConfig, type WarnLogger, type WirePolicyEdit, assetContentType, handlePolicyScaffoldRequest, handleSchemaEditRequest, handleSeedRequest, isStandaloneModulePath, loadStudioAssets, parseDevVariable, readStandaloneAsset, renderStudioHtml, resolveAdminToken, resolveStandaloneDirectory, serveJsonHandler, studioAssetsStamp };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { parseDevVariable, resolveAdminToken } from '../packem_shared/parseDevVariable-CJiq2IwE.mjs';
|
|
2
|
-
export {
|
|
3
|
-
export { POLICY_SCAFFOLD_ENDPOINT, handlePolicyScaffoldRequest } from '../packem_shared/POLICY_SCAFFOLD_ENDPOINT-
|
|
2
|
+
export { assetContentType, isStandaloneModulePath, loadStudioAssets, readStandaloneAsset, resolveStandaloneDirectory, studioAssetsStamp } from '../packem_shared/assetContentType-ByZjeV3D.mjs';
|
|
3
|
+
export { POLICY_SCAFFOLD_ENDPOINT, handlePolicyScaffoldRequest } from '../packem_shared/POLICY_SCAFFOLD_ENDPOINT-8bNMHGiu.mjs';
|
|
4
4
|
export { default as renderStudioHtml } from '../packem_shared/renderStudioHtml-449Ysn75.mjs';
|
|
5
5
|
export { SCHEMA_EDIT_ENDPOINT, handleSchemaEditRequest } from '../packem_shared/SCHEMA_EDIT_ENDPOINT-Df-Wrix-.mjs';
|
|
6
6
|
export { SEED_ENDPOINT, handleSeedRequest } from '../packem_shared/SEED_ENDPOINT-DVCjaGO-.mjs';
|