@amerged/ohmyhost-cli 0.1.34 → 0.1.35
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/README.md +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-SRN6L765.js → chunk-ZQSLRNH6.js} +75 -24
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/apps/product-cli/package.json +1 -1
- package/src/apps/product-cli/src/repository-init.ts +45 -10
- package/src/packages/contracts/src/framework-admission.ts +32 -6
- package/src/packages/contracts/src/framework-build-script.mjs +8 -2
- package/src/packages/contracts/src/framework-family.ts +4 -0
- package/src/packages/contracts/src/framework-source-rules.ts +78 -9
- package/src/packages/sdk-ts/package.json +1 -1
package/README.md
CHANGED
package/dist/bin.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createRequire as __ohmyhostCreateRequire } from "node:module"; const require = __ohmyhostCreateRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
runProductionCli
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ZQSLRNH6.js";
|
|
6
6
|
import "./chunk-7D2RFLWM.js";
|
|
7
7
|
|
|
8
8
|
// apps/product-cli/dist/bin.js
|
|
@@ -34462,6 +34462,11 @@ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
|
34462
34462
|
// packages/contracts/dist/framework-build-script.mjs
|
|
34463
34463
|
var PINNED_BUN_VERSION = "1.2.22";
|
|
34464
34464
|
var FRAMEWORK_VERSION_POLICY = Object.freeze({
|
|
34465
|
+
astro: Object.freeze({ floors: Object.freeze(["7.4.0"]), denied: Object.freeze([]) }),
|
|
34466
|
+
"@astrojs/cloudflare": Object.freeze({
|
|
34467
|
+
floors: Object.freeze(["14.4.0"]),
|
|
34468
|
+
denied: Object.freeze([])
|
|
34469
|
+
}),
|
|
34465
34470
|
next: Object.freeze({ floors: Object.freeze(["15.5.27", "16.3.8"]), denied: Object.freeze([]) }),
|
|
34466
34471
|
vite: Object.freeze({ floors: Object.freeze(["5.4.6"]), denied: Object.freeze([]) }),
|
|
34467
34472
|
"@tanstack/react-start": Object.freeze({
|
|
@@ -34539,6 +34544,8 @@ var TYPESCRIPT_BUILD_STAGE = /^tsc(?:[ \t]+(?:--noEmit|-b|--build))?$/u;
|
|
|
34539
34544
|
function isAdmittedFrameworkBuildScript(framework, script) {
|
|
34540
34545
|
if (typeof script !== "string")
|
|
34541
34546
|
return false;
|
|
34547
|
+
if (framework === "astro")
|
|
34548
|
+
return script === "astro build";
|
|
34542
34549
|
if (framework === "nextjs")
|
|
34543
34550
|
return script === "next build" || script === "next build --webpack";
|
|
34544
34551
|
if (framework !== "vite" && framework !== "tanstack-start")
|
|
@@ -34728,11 +34735,15 @@ function frameworkVersionDiagnostic(admission, lockfile) {
|
|
|
34728
34735
|
});
|
|
34729
34736
|
}
|
|
34730
34737
|
var FRAMEWORK_VERSION_PACKAGES = Object.freeze([
|
|
34738
|
+
"astro",
|
|
34739
|
+
"@astrojs/cloudflare",
|
|
34731
34740
|
"next",
|
|
34732
34741
|
"vite",
|
|
34733
34742
|
"@tanstack/react-start"
|
|
34734
34743
|
]);
|
|
34735
34744
|
var FRAMEWORK_DEPENDENCY_PACKAGES = Object.freeze([
|
|
34745
|
+
"astro",
|
|
34746
|
+
"@astrojs/cloudflare",
|
|
34736
34747
|
"next",
|
|
34737
34748
|
"react",
|
|
34738
34749
|
"react-dom",
|
|
@@ -34743,10 +34754,23 @@ var FRAMEWORK_DEPENDENCY_PACKAGES = Object.freeze([
|
|
|
34743
34754
|
"@cloudflare/vite-plugin"
|
|
34744
34755
|
]);
|
|
34745
34756
|
var REACT_PACKAGES = Object.freeze(["react", "react-dom"]);
|
|
34746
|
-
var BUILD_FRAMEWORKS = Object.freeze([
|
|
34757
|
+
var BUILD_FRAMEWORKS = Object.freeze([
|
|
34758
|
+
"astro",
|
|
34759
|
+
"nextjs",
|
|
34760
|
+
"vite-static",
|
|
34761
|
+
"tanstack-start"
|
|
34762
|
+
]);
|
|
34747
34763
|
var PUSH_AND_PLAN = "Commit and push the change, then plan the new commit.";
|
|
34748
34764
|
var VITE_BUILD_SCRIPT = '"vite build", optionally joined with && to one "tsc", "tsc -b", "tsc --build" or "tsc --noEmit" stage';
|
|
34749
34765
|
var FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
34766
|
+
astro_template_import_unsupported: {
|
|
34767
|
+
paths: ["module"],
|
|
34768
|
+
template: '"{{path}}" uses a dynamic import, import.meta or require in an Astro template. Move server imports into frontmatter and dynamic browser imports into a normal statically imported browser module, then commit and push the change and plan the new commit.'
|
|
34769
|
+
},
|
|
34770
|
+
astro_config_unsupported: {
|
|
34771
|
+
paths: ["framework_config"],
|
|
34772
|
+
template: '"{{path}}" must use the standard Astro output directories and root base. For edge use output: "server", @astrojs/cloudflare with imageService: "passthrough", and session: false. Static hosting must omit a server adapter. Additional Cloudflare bindings, custom sessions and provider cache are not supported. Commit and push the change, then plan the new commit.'
|
|
34773
|
+
},
|
|
34750
34774
|
managed_auth_database_required: {
|
|
34751
34775
|
paths: ["repository_config"],
|
|
34752
34776
|
template: managedCustomerAuthDatabaseMessage("{{path}}")
|
|
@@ -34821,7 +34845,8 @@ var FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
34821
34845
|
text: {
|
|
34822
34846
|
nextjs: 'exactly "next build" or "next build --webpack"; ohmyho.st adds the OpenNext build itself',
|
|
34823
34847
|
"vite-static": VITE_BUILD_SCRIPT,
|
|
34824
|
-
"tanstack-start": VITE_BUILD_SCRIPT
|
|
34848
|
+
"tanstack-start": VITE_BUILD_SCRIPT,
|
|
34849
|
+
astro: 'exactly "astro build"'
|
|
34825
34850
|
}
|
|
34826
34851
|
}
|
|
34827
34852
|
},
|
|
@@ -34837,11 +34862,11 @@ var FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
34837
34862
|
},
|
|
34838
34863
|
framework_unsupported: {
|
|
34839
34864
|
paths: ["manifest"],
|
|
34840
|
-
template: `"{{path}}" declares none of next, vite or @tanstack/react-start. Add the app's framework to dependencies, or set runtime.mode: functions in ohmyhost.yaml and add src/ohmyhost/worker.ts. ${PUSH_AND_PLAN}`
|
|
34865
|
+
template: `"{{path}}" declares none of astro, next, vite or @tanstack/react-start. Add the app's framework to dependencies, or set runtime.mode: functions in ohmyhost.yaml and add src/ohmyhost/worker.ts. ${PUSH_AND_PLAN}`
|
|
34841
34866
|
},
|
|
34842
34867
|
framework_ambiguous: {
|
|
34843
34868
|
paths: ["manifest"],
|
|
34844
|
-
template: '"{{path}}" declares
|
|
34869
|
+
template: '"{{path}}" declares competing application framework packages, so ohmyho.st cannot choose one framework. Remove the packages of the framework this application does not use, commit and push the change, then plan the new commit.'
|
|
34845
34870
|
},
|
|
34846
34871
|
lockfile_missing: {
|
|
34847
34872
|
paths: ["manifest"],
|
|
@@ -34880,7 +34905,8 @@ var FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
34880
34905
|
text: {
|
|
34881
34906
|
nextjs: "runtime.mode: edge",
|
|
34882
34907
|
"vite-static": "runtime.mode: edge with src/ohmyhost/companion.ts when database, auth, mail, storage or functions.crons is set, and static otherwise",
|
|
34883
|
-
"tanstack-start": "runtime.mode: edge, or static without functions.crons and storage"
|
|
34908
|
+
"tanstack-start": "runtime.mode: edge, or static without functions.crons and storage",
|
|
34909
|
+
astro: "runtime.mode: static for prerendered sites, or edge with the Cloudflare adapter"
|
|
34884
34910
|
}
|
|
34885
34911
|
}
|
|
34886
34912
|
},
|
|
@@ -34895,7 +34921,8 @@ var FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
34895
34921
|
text: {
|
|
34896
34922
|
nextjs: ".open-next/assets",
|
|
34897
34923
|
"vite-static": "dist",
|
|
34898
|
-
"tanstack-start": "dist/client"
|
|
34924
|
+
"tanstack-start": "dist/client",
|
|
34925
|
+
astro: "dist for static, or dist/client for edge"
|
|
34899
34926
|
}
|
|
34900
34927
|
}
|
|
34901
34928
|
},
|
|
@@ -34954,8 +34981,8 @@ var DETAIL_DEFINITIONS = FRAMEWORK_CONVERSION_DETAILS;
|
|
|
34954
34981
|
var PLACEHOLDER = /\{\{([a-z]+)\}\}/gu;
|
|
34955
34982
|
var PATH_PATTERN = "[A-Za-z0-9_@()[\\]./${}-]{1,240}";
|
|
34956
34983
|
var SAFE_PATH = new RegExp(`^${PATH_PATTERN}$`, "u");
|
|
34957
|
-
var MODULE_PATH = /^[A-Za-z0-9_@()[\]./${}-]+\.(?:[cm]?[jt]sx?)$/u;
|
|
34958
|
-
var FRAMEWORK_CONFIG_NAME = /^(?:next|open-next|vite)\.config\.(?:js|mjs|ts)$/u;
|
|
34984
|
+
var MODULE_PATH = /^[A-Za-z0-9_@()[\]./${}-]+\.(?:astro|[cm]?[jt]sx?)$/u;
|
|
34985
|
+
var FRAMEWORK_CONFIG_NAME = /^(?:astro|next|open-next|vite)\.config\.(?:js|mjs|ts)$/u;
|
|
34959
34986
|
var MAXIMUM_DETAIL_LENGTH = 2e3;
|
|
34960
34987
|
var DETAIL_PATTERNS = Object.freeze(Object.entries(DETAIL_DEFINITIONS).map(([code, definition]) => Object.freeze({
|
|
34961
34988
|
code,
|
|
@@ -40639,7 +40666,7 @@ function exact3(v, keys) {
|
|
|
40639
40666
|
// apps/product-cli/package.json
|
|
40640
40667
|
var package_default = {
|
|
40641
40668
|
name: "@ohmyhost/product-cli",
|
|
40642
|
-
version: "0.1.
|
|
40669
|
+
version: "0.1.35",
|
|
40643
40670
|
private: true,
|
|
40644
40671
|
ohmyhost: {
|
|
40645
40672
|
deployment: "production",
|
|
@@ -47147,9 +47174,14 @@ var import_yaml2 = __toESM(require_dist(), 1);
|
|
|
47147
47174
|
|
|
47148
47175
|
// packages/contracts/dist/framework-family.js
|
|
47149
47176
|
function classifyFrameworkFamily(dependencies) {
|
|
47177
|
+
const astro = dependencies.has("astro");
|
|
47150
47178
|
const next = dependencies.has("next");
|
|
47151
47179
|
const tanStack = dependencies.has("@tanstack/react-start");
|
|
47152
47180
|
const vite = dependencies.has("vite");
|
|
47181
|
+
if (astro && (next || tanStack))
|
|
47182
|
+
return "ambiguous";
|
|
47183
|
+
if (astro)
|
|
47184
|
+
return "astro";
|
|
47153
47185
|
if (next && (tanStack || vite))
|
|
47154
47186
|
return "ambiguous";
|
|
47155
47187
|
if (next)
|
|
@@ -47175,6 +47207,7 @@ var DEPENDENCY_FIELDS = Object.freeze({
|
|
|
47175
47207
|
any: Object.freeze(["dependencies", "devDependencies", "optionalDependencies"])
|
|
47176
47208
|
});
|
|
47177
47209
|
var REQUIRED_DEPENDENCIES = Object.freeze({
|
|
47210
|
+
astro: Object.freeze([["astro", "build"]]),
|
|
47178
47211
|
nextjs: Object.freeze([
|
|
47179
47212
|
["next", "runtime"],
|
|
47180
47213
|
["react", "runtime"],
|
|
@@ -47193,6 +47226,7 @@ var REQUIRED_DEPENDENCIES = Object.freeze({
|
|
|
47193
47226
|
});
|
|
47194
47227
|
var TANSTACK_EDGE_DEPENDENCY = Object.freeze([CLOUDFLARE_PLUGIN, "build"]);
|
|
47195
47228
|
var BUILD_SCRIPT_FRAMEWORKS = Object.freeze({
|
|
47229
|
+
astro: "astro",
|
|
47196
47230
|
nextjs: "nextjs",
|
|
47197
47231
|
"vite-static": "vite",
|
|
47198
47232
|
"tanstack-start": "tanstack-start"
|
|
@@ -47201,7 +47235,11 @@ var BUILD_OUTPUTS = Object.freeze({
|
|
|
47201
47235
|
"vite-static": "dist",
|
|
47202
47236
|
"tanstack-start": "dist/client"
|
|
47203
47237
|
});
|
|
47204
|
-
var REQUIRED_CONFIG_PATHS = Object.freeze({
|
|
47238
|
+
var REQUIRED_CONFIG_PATHS = Object.freeze({
|
|
47239
|
+
astro: "astro.config.mjs",
|
|
47240
|
+
nextjs: "next.config.ts",
|
|
47241
|
+
"tanstack-start": "vite.config.ts"
|
|
47242
|
+
});
|
|
47205
47243
|
var POSTCSS_CONFIG_PATH = /^(?:postcss\.config\.(?:[cm]?js|json)|\.postcssrc\.(?:js|json))$/u;
|
|
47206
47244
|
var TAILWIND_TURBOPACK_LOADER = "@tailwindcss/turbopack";
|
|
47207
47245
|
var MAXIMUM_LOCKFILE_LENGTH = 5 * 1024 * 1024;
|
|
@@ -47263,7 +47301,7 @@ function viteCompanionRequired(configuration) {
|
|
|
47263
47301
|
function frameworkVersionAdmissions(framework, manifest2, lockfile) {
|
|
47264
47302
|
const admissions = [];
|
|
47265
47303
|
let locked;
|
|
47266
|
-
for (const [name, placement] of REQUIRED_DEPENDENCIES[framework]) {
|
|
47304
|
+
for (const [name, placement] of framework === "astro" && declaredDependency(manifest2, "@astrojs/cloudflare", "build") !== null ? [...REQUIRED_DEPENDENCIES.astro, ["@astrojs/cloudflare", "build"]] : REQUIRED_DEPENDENCIES[framework]) {
|
|
47267
47305
|
if (!isFrameworkVersionPackage(name))
|
|
47268
47306
|
continue;
|
|
47269
47307
|
const declared = declaredDependency(manifest2, name, placement);
|
|
@@ -47451,14 +47489,14 @@ function sourceWithoutComments(source) {
|
|
|
47451
47489
|
return result;
|
|
47452
47490
|
}
|
|
47453
47491
|
function isDatabaseContractModule(path2) {
|
|
47454
|
-
return /\.(?:ts|tsx|js|jsx|mjs|mts)$/u.test(path2) && !/\.d\.[cm]?ts$/u.test(path2);
|
|
47492
|
+
return /\.(?:astro|ts|tsx|js|jsx|mjs|mts)$/u.test(path2) && !/\.d\.[cm]?ts$/u.test(path2);
|
|
47455
47493
|
}
|
|
47456
47494
|
function manifestFindings(input, versions) {
|
|
47457
47495
|
const { configuration, framework, manifest: manifest2 } = input;
|
|
47458
47496
|
const findings = [];
|
|
47459
47497
|
if (framework !== "functions" && !isAdmittedFrameworkBuildScript(BUILD_SCRIPT_FRAMEWORKS[framework], ownValue(manifest2["scripts"], "build")))
|
|
47460
47498
|
findings.push(diagnostic({ code: "build_script_unsupported", path: PACKAGE_MANIFEST2, framework }));
|
|
47461
|
-
const required = framework === "tanstack-start" && configuration.runtime.mode === "edge" ? [...REQUIRED_DEPENDENCIES[framework], TANSTACK_EDGE_DEPENDENCY] : REQUIRED_DEPENDENCIES[framework];
|
|
47499
|
+
const required = framework === "astro" && configuration.runtime.mode === "edge" ? [...REQUIRED_DEPENDENCIES.astro, ["@astrojs/cloudflare", "build"]] : framework === "tanstack-start" && configuration.runtime.mode === "edge" ? [...REQUIRED_DEPENDENCIES[framework], TANSTACK_EDGE_DEPENDENCY] : REQUIRED_DEPENDENCIES[framework];
|
|
47462
47500
|
for (const [name, placement] of required)
|
|
47463
47501
|
if (declaredDependency(manifest2, name, placement) === null)
|
|
47464
47502
|
findings.push(diagnostic({
|
|
@@ -47492,14 +47530,14 @@ function configurationFindings(input) {
|
|
|
47492
47530
|
findings.push(diagnostic({ code: "runtime_mode_unsupported", path: REPOSITORY_CONFIG, framework }));
|
|
47493
47531
|
if (build !== null && framework !== "nextjs" && build.ssg_cache_max_mib !== void 0)
|
|
47494
47532
|
findings.push(diagnostic({ code: "build_option_unsupported", path: REPOSITORY_CONFIG }));
|
|
47495
|
-
const output = BUILD_OUTPUTS[framework];
|
|
47533
|
+
const output = framework === "astro" ? configuration.runtime.mode === "edge" ? "dist/client" : "dist" : BUILD_OUTPUTS[framework];
|
|
47496
47534
|
if (build !== null && output !== void 0 && build.output !== output)
|
|
47497
47535
|
findings.push(diagnostic({ code: "build_output_unsupported", path: REPOSITORY_CONFIG, framework }));
|
|
47498
47536
|
if (packageManager !== null && framework !== "nextjs" && (configuration.build.install !== packageManager.installCommand || build !== null && build.command !== packageManager.buildCommand))
|
|
47499
47537
|
findings.push(diagnostic({ code: "build_command_mismatch", path: REPOSITORY_CONFIG }));
|
|
47500
47538
|
if (framework === "vite-static" && viteCompanionRequired(configuration) && !files.includes(VITE_COMPANION_ENTRY_PATH))
|
|
47501
47539
|
findings.push(diagnostic({ code: "companion_entry_required", path: VITE_COMPANION_ENTRY_PATH }));
|
|
47502
|
-
if ((framework === "functions" || crons && (framework === "nextjs" || framework === "tanstack-start" && configuration.runtime.mode === "edge")) && !files.includes(WORKER_MODULE_PATH))
|
|
47540
|
+
if ((framework === "functions" || crons && (framework === "nextjs" || framework === "astro" && configuration.runtime.mode === "edge" || framework === "tanstack-start" && configuration.runtime.mode === "edge")) && !files.includes(WORKER_MODULE_PATH))
|
|
47503
47541
|
findings.push(diagnostic({ code: "worker_module_required", path: WORKER_MODULE_PATH }));
|
|
47504
47542
|
if (managedCustomerAuthAdmissionIssue(configuration) !== null)
|
|
47505
47543
|
findings.push(diagnostic({ code: "managed_auth_database_required", path: REPOSITORY_CONFIG }));
|
|
@@ -47507,6 +47545,8 @@ function configurationFindings(input) {
|
|
|
47507
47545
|
}
|
|
47508
47546
|
function runtimeModeAdmitted(framework, configuration, crons) {
|
|
47509
47547
|
const mode = configuration.runtime.mode;
|
|
47548
|
+
if (framework === "astro")
|
|
47549
|
+
return mode === "edge" || mode === "static" && !crons && configuration.storage === void 0 && configuration.database?.enabled !== true && configuration.mail?.enabled !== true && configuration.auth?.provider !== "better-auth";
|
|
47510
47550
|
if (framework === "nextjs")
|
|
47511
47551
|
return mode === "edge";
|
|
47512
47552
|
if (framework === "vite-static")
|
|
@@ -47521,6 +47561,8 @@ function frameworkConfigFindings(input) {
|
|
|
47521
47561
|
if (frameworkConfig === null || framework === "functions")
|
|
47522
47562
|
return [];
|
|
47523
47563
|
const { path: path2, text } = frameworkConfig;
|
|
47564
|
+
if (framework === "astro")
|
|
47565
|
+
return astroConfigFindings(text, path2, input.configuration.runtime.mode);
|
|
47524
47566
|
if (framework === "nextjs")
|
|
47525
47567
|
return nextConfigFindings(text, path2, hasPostcssConfiguration(input));
|
|
47526
47568
|
if (framework === "vite-static")
|
|
@@ -47545,7 +47587,7 @@ function repositoryConfiguration(text) {
|
|
|
47545
47587
|
function frameworkConfigPath(framework, files, findings) {
|
|
47546
47588
|
if (framework === "functions")
|
|
47547
47589
|
return null;
|
|
47548
|
-
const path2 = admitted(findings, () => resolveFrameworkConfig(framework === "nextjs" ? "next.config" : "vite.config", files));
|
|
47590
|
+
const path2 = admitted(findings, () => resolveFrameworkConfig(framework === "astro" ? "astro.config" : framework === "nextjs" ? "next.config" : "vite.config", files));
|
|
47549
47591
|
if (framework === "nextjs")
|
|
47550
47592
|
admitted(findings, () => resolveFrameworkConfig("open-next.config", files));
|
|
47551
47593
|
const required = REQUIRED_CONFIG_PATHS[framework];
|
|
@@ -47847,6 +47889,15 @@ function hasNamedImport(tokens, name, moduleName) {
|
|
|
47847
47889
|
function hasModuleImport(tokens, moduleName) {
|
|
47848
47890
|
return tokens.some((token, index) => token.value === "from" && tokens[index + 1]?.kind === "string" && tokens[index + 1]?.value === moduleName);
|
|
47849
47891
|
}
|
|
47892
|
+
function astroConfigFindings(text, path2, mode) {
|
|
47893
|
+
const lexed = lexFrameworkConfig(text, path2);
|
|
47894
|
+
if ("finding" in lexed)
|
|
47895
|
+
return [lexed.finding];
|
|
47896
|
+
const tokens = lexed.tokens;
|
|
47897
|
+
const hasPropertyKey = (items, name) => items.some((token, index) => token.value === name && items[index + 1]?.value === ":");
|
|
47898
|
+
const invalid6 = hasNonRootProperty(tokens, ["base"], ["", "/"]) || ["srcDir", "outDir", "serverEntry", "client", "server", "assetsPrefix"].some((name) => hasPropertyKey(tokens, name)) || (mode === "edge" ? !text.includes("@astrojs/cloudflare") || !hasProperty(tokens, "output", "server") || !hasProperty(tokens, "session", "false") || !hasProperty(tokens, "imageService", "passthrough") || hasPropertyKey(tokens, "cache") : text.includes("@astrojs/cloudflare") || hasPropertyKey(tokens, "adapter") || hasProperty(tokens, "output", "server"));
|
|
47899
|
+
return invalid6 ? [diagnostic({ code: "astro_config_unsupported", path: path2 })] : [];
|
|
47900
|
+
}
|
|
47850
47901
|
|
|
47851
47902
|
// packages/contracts/dist/database-migration-errors.js
|
|
47852
47903
|
var DatabaseMigrationAdmissionError = class extends Error {
|
|
@@ -48299,7 +48350,7 @@ async function initializeRepository(input) {
|
|
|
48299
48350
|
const match = path2.match(/^supabase\/functions\/([^/]+)\//u);
|
|
48300
48351
|
return match?.[1] === void 0 || match[1].startsWith("_") ? [] : [match[1]];
|
|
48301
48352
|
}));
|
|
48302
|
-
const apiRouteCount = applicationFiles.filter((path2) => /^(?:src\/)?app\/api\/.+\/route\.(?:js|jsx|ts|tsx)$/u.test(path2)).length;
|
|
48353
|
+
const apiRouteCount = applicationFiles.filter((path2) => /^(?:src\/)?app\/api\/.+\/route\.(?:js|jsx|ts|tsx)$/u.test(path2) || framework === "astro" && /^src\/pages\/.+\.(?:js|ts)$/u.test(path2) && !path2.endsWith(".d.ts")).length;
|
|
48303
48354
|
const supabase = dependencies.has("@supabase/supabase-js") || dependencies.has("@supabase/ssr");
|
|
48304
48355
|
const configuredDatabase = existingConfiguration?.database?.enabled === true;
|
|
48305
48356
|
const databaseProvider = supabaseMigrationCount > 0 ? "supabase" : postgresMigrationCount > 0 || configuredDatabase ? "postgresql" : "none";
|
|
@@ -48339,14 +48390,14 @@ async function initializeRepository(input) {
|
|
|
48339
48390
|
const targetBetterAuth = existingConfiguration?.auth?.provider === "better-auth";
|
|
48340
48391
|
const targetMail = existingConfiguration?.mail?.enabled === true;
|
|
48341
48392
|
const targetStorage = r2 || supabaseStorage;
|
|
48342
|
-
const tanStackRuntime = framework !== "tanstack-start" ? null : targetStorage ? "edge" : proposedTanStackRuntime(frameworkConfig, dependencies);
|
|
48393
|
+
const tanStackRuntime = framework !== "tanstack-start" && framework !== "astro" ? null : targetStorage ? "edge" : framework === "astro" ? dependencies.has("@astrojs/cloudflare") ? "edge" : "static" : proposedTanStackRuntime(frameworkConfig, dependencies);
|
|
48343
48394
|
const companionRequired = framework === "vite" && (existingConfiguration === null ? databaseProvider !== "none" || targetBetterAuth || targetMail || targetStorage || edgeFunctionNames.size > 0 || applicationFiles.includes(VITE_COMPANION_ENTRY_PATH) : viteCompanionRequired(existingConfiguration));
|
|
48344
48395
|
const generatedConfigurationYaml = renderConfiguration({
|
|
48345
48396
|
project,
|
|
48346
48397
|
framework,
|
|
48347
48398
|
packageManager,
|
|
48348
48399
|
databaseProvider,
|
|
48349
|
-
hasHealthcheck: applicationFiles.includes("src/app/api/health/route.ts") || applicationFiles.includes("app/api/health/route.ts"),
|
|
48400
|
+
hasHealthcheck: applicationFiles.includes("src/app/api/health/route.ts") || applicationFiles.includes("app/api/health/route.ts") || framework === "astro" && applicationFiles.some((path2) => /^src\/pages\/api\/health(?:\/index)?\.(?:js|ts)$/u.test(path2)),
|
|
48350
48401
|
mailEnabled: targetMail,
|
|
48351
48402
|
betterAuthEnabled: targetBetterAuth,
|
|
48352
48403
|
storageEnabled: targetStorage,
|
|
@@ -48464,7 +48515,7 @@ function requiredCatalogBlocker(diagnostic2, applicationRoot) {
|
|
|
48464
48515
|
async function workerModuleBlockers(context) {
|
|
48465
48516
|
const { config, framework, files } = context;
|
|
48466
48517
|
const mode = config?.runtime.mode;
|
|
48467
|
-
const scheduled = (config?.functions?.crons.length ?? 0) > 0 && (mode === "edge" && (framework === "vite" || framework === "nextjs" || framework === "tanstack-start") || mode === "functions" && framework === "functions");
|
|
48518
|
+
const scheduled = (config?.functions?.crons.length ?? 0) > 0 && (mode === "edge" && (framework === "astro" || framework === "vite" || framework === "nextjs" || framework === "tanstack-start") || mode === "functions" && framework === "functions");
|
|
48468
48519
|
const path2 = framework === "vite" ? VITE_COMPANION_ENTRY_PATH : WORKER_MODULE_PATH;
|
|
48469
48520
|
if (framework !== "functions" && !scheduled || !files.includes(path2))
|
|
48470
48521
|
return [];
|
|
@@ -48737,7 +48788,7 @@ function hasDirectSafeBuildCommand(manifest2, framework) {
|
|
|
48737
48788
|
const scripts = manifest2["scripts"];
|
|
48738
48789
|
if (!isRecord5(scripts) || typeof scripts["build"] !== "string")
|
|
48739
48790
|
return false;
|
|
48740
|
-
return (framework === "nextjs" || framework === "vite" || framework === "tanstack-start") && isAdmittedFrameworkBuildScript(framework, scripts["build"]);
|
|
48791
|
+
return (framework === "astro" || framework === "nextjs" || framework === "vite" || framework === "tanstack-start") && isAdmittedFrameworkBuildScript(framework, scripts["build"]);
|
|
48741
48792
|
}
|
|
48742
48793
|
async function assertRepositoryRoot(root) {
|
|
48743
48794
|
let information;
|
|
@@ -48843,11 +48894,11 @@ async function readResolvingLockfile(applicationDirectory, admission) {
|
|
|
48843
48894
|
return text === null ? null : Object.freeze({ name: admission.lockfile, text });
|
|
48844
48895
|
}
|
|
48845
48896
|
async function readFrameworkConfig(applicationDirectory, files, framework) {
|
|
48846
|
-
if (framework !== "nextjs" && framework !== "vite" && framework !== "tanstack-start")
|
|
48897
|
+
if (framework !== "astro" && framework !== "nextjs" && framework !== "vite" && framework !== "tanstack-start")
|
|
48847
48898
|
return null;
|
|
48848
48899
|
let path2;
|
|
48849
48900
|
try {
|
|
48850
|
-
path2 = resolveFrameworkConfig(framework === "nextjs" ? "next.config" : "vite.config", files);
|
|
48901
|
+
path2 = resolveFrameworkConfig(framework === "astro" ? "astro.config" : framework === "nextjs" ? "next.config" : "vite.config", files);
|
|
48851
48902
|
} catch (error) {
|
|
48852
48903
|
if (error instanceof FrameworkAdmissionError)
|
|
48853
48904
|
return null;
|
|
@@ -48913,7 +48964,7 @@ function renderConfiguration(input) {
|
|
|
48913
48964
|
let output = "dist";
|
|
48914
48965
|
if (input.framework === "nextjs")
|
|
48915
48966
|
output = ".open-next/assets";
|
|
48916
|
-
else if (input.framework === "tanstack-start")
|
|
48967
|
+
else if (input.framework === "tanstack-start" || input.framework === "astro" && input.tanStackRuntime === "edge")
|
|
48917
48968
|
output = "dist/client";
|
|
48918
48969
|
let mode = "auto";
|
|
48919
48970
|
if (input.framework === "functions")
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -310,8 +310,12 @@ export async function initializeRepository(
|
|
|
310
310
|
return match?.[1] === undefined || match[1].startsWith("_") ? [] : [match[1]];
|
|
311
311
|
}),
|
|
312
312
|
);
|
|
313
|
-
const apiRouteCount = applicationFiles.filter(
|
|
314
|
-
|
|
313
|
+
const apiRouteCount = applicationFiles.filter(
|
|
314
|
+
(path) =>
|
|
315
|
+
/^(?:src\/)?app\/api\/.+\/route\.(?:js|jsx|ts|tsx)$/u.test(path) ||
|
|
316
|
+
(framework === "astro" &&
|
|
317
|
+
/^src\/pages\/.+\.(?:js|ts)$/u.test(path) &&
|
|
318
|
+
!path.endsWith(".d.ts")),
|
|
315
319
|
).length;
|
|
316
320
|
const supabase = dependencies.has("@supabase/supabase-js") || dependencies.has("@supabase/ssr");
|
|
317
321
|
const configuredDatabase = existingConfiguration?.database?.enabled === true;
|
|
@@ -368,11 +372,15 @@ export async function initializeRepository(
|
|
|
368
372
|
const targetStorage = r2 || supabaseStorage;
|
|
369
373
|
// TanStack Start binds storage only on edge, as a Vite app does through its companion.
|
|
370
374
|
const tanStackRuntime =
|
|
371
|
-
framework !== "tanstack-start"
|
|
375
|
+
framework !== "tanstack-start" && framework !== "astro"
|
|
372
376
|
? null
|
|
373
377
|
: targetStorage
|
|
374
378
|
? "edge"
|
|
375
|
-
:
|
|
379
|
+
: framework === "astro"
|
|
380
|
+
? dependencies.has("@astrojs/cloudflare")
|
|
381
|
+
? "edge"
|
|
382
|
+
: "static"
|
|
383
|
+
: proposedTanStackRuntime(frameworkConfig, dependencies);
|
|
376
384
|
const companionRequired =
|
|
377
385
|
framework === "vite" &&
|
|
378
386
|
(existingConfiguration === null
|
|
@@ -390,7 +398,11 @@ export async function initializeRepository(
|
|
|
390
398
|
databaseProvider,
|
|
391
399
|
hasHealthcheck:
|
|
392
400
|
applicationFiles.includes("src/app/api/health/route.ts") ||
|
|
393
|
-
applicationFiles.includes("app/api/health/route.ts")
|
|
401
|
+
applicationFiles.includes("app/api/health/route.ts") ||
|
|
402
|
+
(framework === "astro" &&
|
|
403
|
+
applicationFiles.some((path) =>
|
|
404
|
+
/^src\/pages\/api\/health(?:\/index)?\.(?:js|ts)$/u.test(path),
|
|
405
|
+
)),
|
|
394
406
|
mailEnabled: targetMail,
|
|
395
407
|
betterAuthEnabled: targetBetterAuth,
|
|
396
408
|
storageEnabled: targetStorage,
|
|
@@ -596,7 +608,10 @@ async function workerModuleBlockers(context: SourceCheckContext): Promise<Reposi
|
|
|
596
608
|
const scheduled =
|
|
597
609
|
(config?.functions?.crons.length ?? 0) > 0 &&
|
|
598
610
|
((mode === "edge" &&
|
|
599
|
-
(framework === "
|
|
611
|
+
(framework === "astro" ||
|
|
612
|
+
framework === "vite" ||
|
|
613
|
+
framework === "nextjs" ||
|
|
614
|
+
framework === "tanstack-start")) ||
|
|
600
615
|
(mode === "functions" && framework === "functions"));
|
|
601
616
|
const path = framework === "vite" ? VITE_COMPANION_ENTRY_PATH : WORKER_MODULE_PATH;
|
|
602
617
|
if ((framework !== "functions" && !scheduled) || !files.includes(path)) return [];
|
|
@@ -989,7 +1004,10 @@ function hasDirectSafeBuildCommand(
|
|
|
989
1004
|
const scripts = manifest["scripts"];
|
|
990
1005
|
if (!isRecord(scripts) || typeof scripts["build"] !== "string") return false;
|
|
991
1006
|
return (
|
|
992
|
-
(framework === "
|
|
1007
|
+
(framework === "astro" ||
|
|
1008
|
+
framework === "nextjs" ||
|
|
1009
|
+
framework === "vite" ||
|
|
1010
|
+
framework === "tanstack-start") &&
|
|
993
1011
|
isAdmittedFrameworkBuildScript(framework, scripts["build"])
|
|
994
1012
|
);
|
|
995
1013
|
}
|
|
@@ -1144,10 +1162,23 @@ async function readFrameworkConfig(
|
|
|
1144
1162
|
files: readonly string[],
|
|
1145
1163
|
framework: RepositoryFramework,
|
|
1146
1164
|
): Promise<FrameworkConfigText | null> {
|
|
1147
|
-
if (
|
|
1165
|
+
if (
|
|
1166
|
+
framework !== "astro" &&
|
|
1167
|
+
framework !== "nextjs" &&
|
|
1168
|
+
framework !== "vite" &&
|
|
1169
|
+
framework !== "tanstack-start"
|
|
1170
|
+
)
|
|
1171
|
+
return null;
|
|
1148
1172
|
let path: string | null;
|
|
1149
1173
|
try {
|
|
1150
|
-
path = resolveFrameworkConfig(
|
|
1174
|
+
path = resolveFrameworkConfig(
|
|
1175
|
+
framework === "astro"
|
|
1176
|
+
? "astro.config"
|
|
1177
|
+
: framework === "nextjs"
|
|
1178
|
+
? "next.config"
|
|
1179
|
+
: "vite.config",
|
|
1180
|
+
files,
|
|
1181
|
+
);
|
|
1151
1182
|
} catch (error) {
|
|
1152
1183
|
// The shared rules name the ambiguous variants; none of them is judged.
|
|
1153
1184
|
if (error instanceof FrameworkAdmissionError) return null;
|
|
@@ -1266,7 +1297,11 @@ function renderConfiguration(input: {
|
|
|
1266
1297
|
|
|
1267
1298
|
let output = "dist";
|
|
1268
1299
|
if (input.framework === "nextjs") output = ".open-next/assets";
|
|
1269
|
-
else if (
|
|
1300
|
+
else if (
|
|
1301
|
+
input.framework === "tanstack-start" ||
|
|
1302
|
+
(input.framework === "astro" && input.tanStackRuntime === "edge")
|
|
1303
|
+
)
|
|
1304
|
+
output = "dist/client";
|
|
1270
1305
|
|
|
1271
1306
|
let mode = "auto";
|
|
1272
1307
|
if (input.framework === "functions") mode = "functions";
|
|
@@ -19,7 +19,11 @@ export type LockfileName =
|
|
|
19
19
|
| "package-lock.json"
|
|
20
20
|
| "pnpm-lock.yaml"
|
|
21
21
|
| "yarn.lock";
|
|
22
|
-
export type FrameworkConfigBasename =
|
|
22
|
+
export type FrameworkConfigBasename =
|
|
23
|
+
| "astro.config"
|
|
24
|
+
| "next.config"
|
|
25
|
+
| "open-next.config"
|
|
26
|
+
| "vite.config";
|
|
23
27
|
|
|
24
28
|
export type FrameworkAdmissionReason =
|
|
25
29
|
| "ambiguous_config"
|
|
@@ -311,11 +315,15 @@ interface DetailDefinition {
|
|
|
311
315
|
}
|
|
312
316
|
|
|
313
317
|
const FRAMEWORK_VERSION_PACKAGES = Object.freeze([
|
|
318
|
+
"astro",
|
|
319
|
+
"@astrojs/cloudflare",
|
|
314
320
|
"next",
|
|
315
321
|
"vite",
|
|
316
322
|
"@tanstack/react-start",
|
|
317
323
|
] as const satisfies readonly FrameworkVersionPackage[]);
|
|
318
324
|
const FRAMEWORK_DEPENDENCY_PACKAGES = Object.freeze([
|
|
325
|
+
"astro",
|
|
326
|
+
"@astrojs/cloudflare",
|
|
319
327
|
"next",
|
|
320
328
|
"react",
|
|
321
329
|
"react-dom",
|
|
@@ -326,7 +334,12 @@ const FRAMEWORK_DEPENDENCY_PACKAGES = Object.freeze([
|
|
|
326
334
|
"@cloudflare/vite-plugin",
|
|
327
335
|
] as const);
|
|
328
336
|
const REACT_PACKAGES = Object.freeze(["react", "react-dom"] as const);
|
|
329
|
-
const BUILD_FRAMEWORKS = Object.freeze([
|
|
337
|
+
const BUILD_FRAMEWORKS = Object.freeze([
|
|
338
|
+
"astro",
|
|
339
|
+
"nextjs",
|
|
340
|
+
"vite-static",
|
|
341
|
+
"tanstack-start",
|
|
342
|
+
] as const);
|
|
330
343
|
|
|
331
344
|
const PUSH_AND_PLAN = "Commit and push the change, then plan the new commit.";
|
|
332
345
|
const VITE_BUILD_SCRIPT =
|
|
@@ -335,6 +348,16 @@ const VITE_BUILD_SCRIPT =
|
|
|
335
348
|
// Each sentence names the file, the rule and the exact change. Render and parse both derive from
|
|
336
349
|
// the template, so a client maps a detail back to exactly one typed diagnostic.
|
|
337
350
|
const FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
351
|
+
astro_template_import_unsupported: {
|
|
352
|
+
paths: ["module"],
|
|
353
|
+
template:
|
|
354
|
+
'"{{path}}" uses a dynamic import, import.meta or require in an Astro template. Move server imports into frontmatter and dynamic browser imports into a normal statically imported browser module, then commit and push the change and plan the new commit.',
|
|
355
|
+
},
|
|
356
|
+
astro_config_unsupported: {
|
|
357
|
+
paths: ["framework_config"],
|
|
358
|
+
template:
|
|
359
|
+
'"{{path}}" must use the standard Astro output directories and root base. For edge use output: "server", @astrojs/cloudflare with imageService: "passthrough", and session: false. Static hosting must omit a server adapter. Additional Cloudflare bindings, custom sessions and provider cache are not supported. Commit and push the change, then plan the new commit.',
|
|
360
|
+
},
|
|
338
361
|
managed_auth_database_required: {
|
|
339
362
|
paths: ["repository_config"],
|
|
340
363
|
template: managedCustomerAuthDatabaseMessage("{{path}}"),
|
|
@@ -417,6 +440,7 @@ const FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
417
440
|
'exactly "next build" or "next build --webpack"; ohmyho.st adds the OpenNext build itself',
|
|
418
441
|
"vite-static": VITE_BUILD_SCRIPT,
|
|
419
442
|
"tanstack-start": VITE_BUILD_SCRIPT,
|
|
443
|
+
astro: 'exactly "astro build"',
|
|
420
444
|
},
|
|
421
445
|
},
|
|
422
446
|
},
|
|
@@ -435,12 +459,12 @@ const FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
435
459
|
},
|
|
436
460
|
framework_unsupported: {
|
|
437
461
|
paths: ["manifest"],
|
|
438
|
-
template: `"{{path}}" declares none of next, vite or @tanstack/react-start. Add the app's framework to dependencies, or set runtime.mode: functions in ohmyhost.yaml and add src/ohmyhost/worker.ts. ${PUSH_AND_PLAN}`,
|
|
462
|
+
template: `"{{path}}" declares none of astro, next, vite or @tanstack/react-start. Add the app's framework to dependencies, or set runtime.mode: functions in ohmyhost.yaml and add src/ohmyhost/worker.ts. ${PUSH_AND_PLAN}`,
|
|
439
463
|
},
|
|
440
464
|
framework_ambiguous: {
|
|
441
465
|
paths: ["manifest"],
|
|
442
466
|
template:
|
|
443
|
-
'"{{path}}" declares
|
|
467
|
+
'"{{path}}" declares competing application framework packages, so ohmyho.st cannot choose one framework. Remove the packages of the framework this application does not use, commit and push the change, then plan the new commit.',
|
|
444
468
|
},
|
|
445
469
|
lockfile_missing: {
|
|
446
470
|
paths: ["manifest"],
|
|
@@ -487,6 +511,7 @@ const FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
487
511
|
"vite-static":
|
|
488
512
|
"runtime.mode: edge with src/ohmyhost/companion.ts when database, auth, mail, storage or functions.crons is set, and static otherwise",
|
|
489
513
|
"tanstack-start": "runtime.mode: edge, or static without functions.crons and storage",
|
|
514
|
+
astro: "runtime.mode: static for prerendered sites, or edge with the Cloudflare adapter",
|
|
490
515
|
},
|
|
491
516
|
},
|
|
492
517
|
},
|
|
@@ -502,6 +527,7 @@ const FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
502
527
|
nextjs: ".open-next/assets",
|
|
503
528
|
"vite-static": "dist",
|
|
504
529
|
"tanstack-start": "dist/client",
|
|
530
|
+
astro: "dist for static, or dist/client for edge",
|
|
505
531
|
},
|
|
506
532
|
},
|
|
507
533
|
},
|
|
@@ -585,8 +611,8 @@ const DETAIL_DEFINITIONS: Readonly<Record<FrameworkConversionDiagnosticCode, Det
|
|
|
585
611
|
const PLACEHOLDER = /\{\{([a-z]+)\}\}/gu;
|
|
586
612
|
const PATH_PATTERN = "[A-Za-z0-9_@()[\\]./${}-]{1,240}";
|
|
587
613
|
const SAFE_PATH = new RegExp(`^${PATH_PATTERN}$`, "u");
|
|
588
|
-
const MODULE_PATH = /^[A-Za-z0-9_@()[\]./${}-]+\.(?:[cm]?[jt]sx?)$/u;
|
|
589
|
-
const FRAMEWORK_CONFIG_NAME = /^(?:next|open-next|vite)\.config\.(?:js|mjs|ts)$/u;
|
|
614
|
+
const MODULE_PATH = /^[A-Za-z0-9_@()[\]./${}-]+\.(?:astro|[cm]?[jt]sx?)$/u;
|
|
615
|
+
const FRAMEWORK_CONFIG_NAME = /^(?:astro|next|open-next|vite)\.config\.(?:js|mjs|ts)$/u;
|
|
590
616
|
// The public problem detail bound; every rendered sentence stays far below it.
|
|
591
617
|
const MAXIMUM_DETAIL_LENGTH = 2_000;
|
|
592
618
|
const DETAIL_PATTERNS = Object.freeze(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const PINNED_BUN_VERSION = "1.2.22";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @typedef {"next" | "vite" | "@tanstack/react-start"} FrameworkVersionPackage
|
|
4
|
+
* @typedef {"next" | "vite" | "astro" | "@astrojs/cloudflare" | "@tanstack/react-start"} FrameworkVersionPackage
|
|
5
5
|
* @typedef {Readonly<{
|
|
6
6
|
* floors: readonly string[];
|
|
7
7
|
* denied: readonly (readonly [string, string | null])[];
|
|
@@ -22,6 +22,11 @@ export const PINNED_BUN_VERSION = "1.2.22";
|
|
|
22
22
|
* @type {FrameworkVersionPolicy}
|
|
23
23
|
*/
|
|
24
24
|
export const FRAMEWORK_VERSION_POLICY = Object.freeze({
|
|
25
|
+
astro: Object.freeze({ floors: Object.freeze(["7.4.0"]), denied: Object.freeze([]) }),
|
|
26
|
+
"@astrojs/cloudflare": Object.freeze({
|
|
27
|
+
floors: Object.freeze(["14.4.0"]),
|
|
28
|
+
denied: Object.freeze([]),
|
|
29
|
+
}),
|
|
25
30
|
next: Object.freeze({ floors: Object.freeze(["15.5.27", "16.3.8"]), denied: Object.freeze([]) }),
|
|
26
31
|
vite: Object.freeze({ floors: Object.freeze(["5.4.6"]), denied: Object.freeze([]) }),
|
|
27
32
|
"@tanstack/react-start": Object.freeze({
|
|
@@ -164,12 +169,13 @@ const TYPESCRIPT_BUILD_STAGE = /^tsc(?:[ \t]+(?:--noEmit|-b|--build))?$/u;
|
|
|
164
169
|
|
|
165
170
|
/**
|
|
166
171
|
* The same source is consumed by local admission, framework adapters and the build sandbox.
|
|
167
|
-
* @param {"nextjs" | "tanstack-start" | "vite"} framework
|
|
172
|
+
* @param {"astro" | "nextjs" | "tanstack-start" | "vite"} framework
|
|
168
173
|
* @param {unknown} script
|
|
169
174
|
* @returns {boolean}
|
|
170
175
|
*/
|
|
171
176
|
export function isAdmittedFrameworkBuildScript(framework, script) {
|
|
172
177
|
if (typeof script !== "string") return false;
|
|
178
|
+
if (framework === "astro") return script === "astro build";
|
|
173
179
|
if (framework === "nextjs") return script === "next build" || script === "next build --webpack";
|
|
174
180
|
if (framework !== "vite" && framework !== "tanstack-start") return false;
|
|
175
181
|
const stages = script.trim().split(/[ \t]*&&[ \t]*/u);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type FrameworkFamilyClassification =
|
|
2
|
+
| "astro"
|
|
2
3
|
| "ambiguous"
|
|
3
4
|
| "nextjs"
|
|
4
5
|
| "tanstack-start"
|
|
@@ -8,9 +9,12 @@ export type FrameworkFamilyClassification =
|
|
|
8
9
|
export function classifyFrameworkFamily(
|
|
9
10
|
dependencies: ReadonlySet<string>,
|
|
10
11
|
): FrameworkFamilyClassification {
|
|
12
|
+
const astro = dependencies.has("astro");
|
|
11
13
|
const next = dependencies.has("next");
|
|
12
14
|
const tanStack = dependencies.has("@tanstack/react-start");
|
|
13
15
|
const vite = dependencies.has("vite");
|
|
16
|
+
if (astro && (next || tanStack)) return "ambiguous";
|
|
17
|
+
if (astro) return "astro";
|
|
14
18
|
if (next && (tanStack || vite)) return "ambiguous";
|
|
15
19
|
if (next) return "nextjs";
|
|
16
20
|
if (tanStack) return "tanstack-start";
|
|
@@ -40,7 +40,12 @@ export const WORKER_MODULE_PATH = "src/ohmyhost/worker.ts" as const;
|
|
|
40
40
|
/** The Worker module of a Vite application with a server runtime. */
|
|
41
41
|
export const VITE_COMPANION_ENTRY_PATH = "src/ohmyhost/companion.ts" as const;
|
|
42
42
|
|
|
43
|
-
export type FrameworkSourceFramework =
|
|
43
|
+
export type FrameworkSourceFramework =
|
|
44
|
+
| "astro"
|
|
45
|
+
| "functions"
|
|
46
|
+
| "nextjs"
|
|
47
|
+
| "tanstack-start"
|
|
48
|
+
| "vite-static";
|
|
44
49
|
export type PackageManifest = Readonly<Record<string, unknown>>;
|
|
45
50
|
/**
|
|
46
51
|
* Where package.json may declare a dependency: `runtime` only in dependencies, `build` also in
|
|
@@ -91,6 +96,7 @@ const DEPENDENCY_FIELDS = Object.freeze({
|
|
|
91
96
|
// Next.js and TanStack Start load their runtime packages in the server bundle, so package.json
|
|
92
97
|
// declares them in dependencies; Vite and its plugins only build, so devDependencies suffice.
|
|
93
98
|
const REQUIRED_DEPENDENCIES = Object.freeze({
|
|
99
|
+
astro: Object.freeze([["astro", "build"]] as const),
|
|
94
100
|
nextjs: Object.freeze([
|
|
95
101
|
["next", "runtime"],
|
|
96
102
|
["react", "runtime"],
|
|
@@ -109,6 +115,7 @@ const REQUIRED_DEPENDENCIES = Object.freeze({
|
|
|
109
115
|
} satisfies Record<FrameworkSourceFramework, readonly (readonly [string, DependencyPlacement])[]>);
|
|
110
116
|
const TANSTACK_EDGE_DEPENDENCY = Object.freeze([CLOUDFLARE_PLUGIN, "build"] as const);
|
|
111
117
|
const BUILD_SCRIPT_FRAMEWORKS = Object.freeze({
|
|
118
|
+
astro: "astro",
|
|
112
119
|
nextjs: "nextjs",
|
|
113
120
|
"vite-static": "vite",
|
|
114
121
|
"tanstack-start": "tanstack-start",
|
|
@@ -118,7 +125,11 @@ const BUILD_OUTPUTS: Readonly<Partial<Record<FrameworkSourceFramework, string>>>
|
|
|
118
125
|
"tanstack-start": "dist/client",
|
|
119
126
|
});
|
|
120
127
|
const REQUIRED_CONFIG_PATHS: Readonly<Partial<Record<FrameworkSourceFramework, string>>> =
|
|
121
|
-
Object.freeze({
|
|
128
|
+
Object.freeze({
|
|
129
|
+
astro: "astro.config.mjs",
|
|
130
|
+
nextjs: "next.config.ts",
|
|
131
|
+
"tanstack-start": "vite.config.ts",
|
|
132
|
+
});
|
|
122
133
|
// The PostCSS configuration the Next.js Webpack build reads: package.json "postcss" or one of these
|
|
123
134
|
// files at the application root. It never reads a TypeScript one such as postcss.config.ts.
|
|
124
135
|
const POSTCSS_CONFIG_PATH = /^(?:postcss\.config\.(?:[cm]?js|json)|\.postcssrc\.(?:js|json))$/u;
|
|
@@ -214,7 +225,10 @@ export function frameworkVersionAdmissions(
|
|
|
214
225
|
): readonly FrameworkVersionAdmission[] {
|
|
215
226
|
const admissions: FrameworkVersionAdmission[] = [];
|
|
216
227
|
let locked: ((packageName: string) => string | null) | undefined;
|
|
217
|
-
for (const [name, placement] of
|
|
228
|
+
for (const [name, placement] of framework === "astro" &&
|
|
229
|
+
declaredDependency(manifest, "@astrojs/cloudflare", "build") !== null
|
|
230
|
+
? [...REQUIRED_DEPENDENCIES.astro, ["@astrojs/cloudflare", "build"] as const]
|
|
231
|
+
: REQUIRED_DEPENDENCIES[framework]) {
|
|
218
232
|
if (!isFrameworkVersionPackage(name)) continue;
|
|
219
233
|
const declared = declaredDependency(manifest, name, placement);
|
|
220
234
|
if (declared === null) continue;
|
|
@@ -504,7 +518,7 @@ export function sourceWithoutComments(source: string): string {
|
|
|
504
518
|
* extensions planning reads, without TypeScript declaration files, which never run.
|
|
505
519
|
*/
|
|
506
520
|
export function isDatabaseContractModule(path: string): boolean {
|
|
507
|
-
return /\.(?:ts|tsx|js|jsx|mjs|mts)$/u.test(path) && !/\.d\.[cm]?ts$/u.test(path);
|
|
521
|
+
return /\.(?:astro|ts|tsx|js|jsx|mjs|mts)$/u.test(path) && !/\.d\.[cm]?ts$/u.test(path);
|
|
508
522
|
}
|
|
509
523
|
|
|
510
524
|
function manifestFindings(
|
|
@@ -524,9 +538,11 @@ function manifestFindings(
|
|
|
524
538
|
diagnostic({ code: "build_script_unsupported", path: PACKAGE_MANIFEST, framework }),
|
|
525
539
|
);
|
|
526
540
|
const required =
|
|
527
|
-
framework === "
|
|
528
|
-
? [...REQUIRED_DEPENDENCIES[
|
|
529
|
-
:
|
|
541
|
+
framework === "astro" && configuration.runtime.mode === "edge"
|
|
542
|
+
? [...REQUIRED_DEPENDENCIES.astro, ["@astrojs/cloudflare", "build"] as const]
|
|
543
|
+
: framework === "tanstack-start" && configuration.runtime.mode === "edge"
|
|
544
|
+
? [...REQUIRED_DEPENDENCIES[framework], TANSTACK_EDGE_DEPENDENCY]
|
|
545
|
+
: REQUIRED_DEPENDENCIES[framework];
|
|
530
546
|
for (const [name, placement] of required)
|
|
531
547
|
if (declaredDependency(manifest, name, placement) === null)
|
|
532
548
|
findings.push(
|
|
@@ -567,7 +583,12 @@ function configurationFindings(input: FrameworkSourceRuleInput): FrameworkConver
|
|
|
567
583
|
);
|
|
568
584
|
if (build !== null && framework !== "nextjs" && build.ssg_cache_max_mib !== undefined)
|
|
569
585
|
findings.push(diagnostic({ code: "build_option_unsupported", path: REPOSITORY_CONFIG }));
|
|
570
|
-
const output =
|
|
586
|
+
const output =
|
|
587
|
+
framework === "astro"
|
|
588
|
+
? configuration.runtime.mode === "edge"
|
|
589
|
+
? "dist/client"
|
|
590
|
+
: "dist"
|
|
591
|
+
: BUILD_OUTPUTS[framework];
|
|
571
592
|
if (build !== null && output !== undefined && build.output !== output)
|
|
572
593
|
findings.push(
|
|
573
594
|
diagnostic({ code: "build_output_unsupported", path: REPOSITORY_CONFIG, framework }),
|
|
@@ -592,6 +613,7 @@ function configurationFindings(input: FrameworkSourceRuleInput): FrameworkConver
|
|
|
592
613
|
(framework === "functions" ||
|
|
593
614
|
(crons &&
|
|
594
615
|
(framework === "nextjs" ||
|
|
616
|
+
(framework === "astro" && configuration.runtime.mode === "edge") ||
|
|
595
617
|
(framework === "tanstack-start" && configuration.runtime.mode === "edge")))) &&
|
|
596
618
|
!files.includes(WORKER_MODULE_PATH)
|
|
597
619
|
)
|
|
@@ -607,6 +629,16 @@ function runtimeModeAdmitted(
|
|
|
607
629
|
crons: boolean,
|
|
608
630
|
): boolean {
|
|
609
631
|
const mode = configuration.runtime.mode;
|
|
632
|
+
if (framework === "astro")
|
|
633
|
+
return (
|
|
634
|
+
mode === "edge" ||
|
|
635
|
+
(mode === "static" &&
|
|
636
|
+
!crons &&
|
|
637
|
+
configuration.storage === undefined &&
|
|
638
|
+
configuration.database?.enabled !== true &&
|
|
639
|
+
configuration.mail?.enabled !== true &&
|
|
640
|
+
configuration.auth?.provider !== "better-auth")
|
|
641
|
+
);
|
|
610
642
|
if (framework === "nextjs") return mode === "edge";
|
|
611
643
|
if (framework === "vite-static")
|
|
612
644
|
return mode === (viteCompanionRequired(configuration) ? "edge" : "static");
|
|
@@ -629,6 +661,8 @@ function frameworkConfigFindings(
|
|
|
629
661
|
const { frameworkConfig, framework } = input;
|
|
630
662
|
if (frameworkConfig === null || framework === "functions") return [];
|
|
631
663
|
const { path, text } = frameworkConfig;
|
|
664
|
+
if (framework === "astro")
|
|
665
|
+
return astroConfigFindings(text, path, input.configuration.runtime.mode);
|
|
632
666
|
if (framework === "nextjs") return nextConfigFindings(text, path, hasPostcssConfiguration(input));
|
|
633
667
|
if (framework === "vite-static") return viteConfigFindings(text, path);
|
|
634
668
|
const mode = input.configuration.runtime.mode;
|
|
@@ -660,7 +694,14 @@ function frameworkConfigPath(
|
|
|
660
694
|
): string | null {
|
|
661
695
|
if (framework === "functions") return null;
|
|
662
696
|
const path = admitted(findings, () =>
|
|
663
|
-
resolveFrameworkConfig(
|
|
697
|
+
resolveFrameworkConfig(
|
|
698
|
+
framework === "astro"
|
|
699
|
+
? "astro.config"
|
|
700
|
+
: framework === "nextjs"
|
|
701
|
+
? "next.config"
|
|
702
|
+
: "vite.config",
|
|
703
|
+
files,
|
|
704
|
+
),
|
|
664
705
|
);
|
|
665
706
|
if (framework === "nextjs")
|
|
666
707
|
admitted(findings, () => resolveFrameworkConfig("open-next.config", files));
|
|
@@ -1116,3 +1157,31 @@ function hasModuleImport(tokens: readonly ConfigToken[], moduleName: string): bo
|
|
|
1116
1157
|
tokens[index + 1]?.value === moduleName,
|
|
1117
1158
|
);
|
|
1118
1159
|
}
|
|
1160
|
+
|
|
1161
|
+
/** Astro's build validates executable config; admission rejects known incompatible contracts. */
|
|
1162
|
+
function astroConfigFindings(
|
|
1163
|
+
text: string,
|
|
1164
|
+
path: string,
|
|
1165
|
+
mode: string,
|
|
1166
|
+
): readonly FrameworkConversionDiagnostic[] {
|
|
1167
|
+
const lexed = lexFrameworkConfig(text, path);
|
|
1168
|
+
if ("finding" in lexed) return [lexed.finding];
|
|
1169
|
+
const tokens = lexed.tokens;
|
|
1170
|
+
const hasPropertyKey = (items: readonly ConfigToken[], name: string) =>
|
|
1171
|
+
items.some((token, index) => token.value === name && items[index + 1]?.value === ":");
|
|
1172
|
+
const invalid =
|
|
1173
|
+
hasNonRootProperty(tokens, ["base"], ["", "/"]) ||
|
|
1174
|
+
["srcDir", "outDir", "serverEntry", "client", "server", "assetsPrefix"].some((name) =>
|
|
1175
|
+
hasPropertyKey(tokens, name),
|
|
1176
|
+
) ||
|
|
1177
|
+
(mode === "edge"
|
|
1178
|
+
? !text.includes("@astrojs/cloudflare") ||
|
|
1179
|
+
!hasProperty(tokens, "output", "server") ||
|
|
1180
|
+
!hasProperty(tokens, "session", "false") ||
|
|
1181
|
+
!hasProperty(tokens, "imageService", "passthrough") ||
|
|
1182
|
+
hasPropertyKey(tokens, "cache")
|
|
1183
|
+
: text.includes("@astrojs/cloudflare") ||
|
|
1184
|
+
hasPropertyKey(tokens, "adapter") ||
|
|
1185
|
+
hasProperty(tokens, "output", "server"));
|
|
1186
|
+
return invalid ? [diagnostic({ code: "astro_config_unsupported", path })] : [];
|
|
1187
|
+
}
|