@amerged/ohmyhost-cli 0.1.33 → 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-3RDHFA76.js → chunk-ZQSLRNH6.js} +89 -27
- 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/cli.ts +1 -1
- package/src/apps/product-cli/src/repository-init.ts +45 -10
- package/src/apps/product-cli/src/runtime-contract.ts +26 -2
- 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/src/packages/sdk-ts/src/generated/sdk.gen.ts +1 -1
- package/src/packages/sdk-ts/src/generated/types.gen.ts +15 -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,
|
|
@@ -37142,14 +37169,25 @@ function parseProjectCreditBudget(value) {
|
|
|
37142
37169
|
return input;
|
|
37143
37170
|
}
|
|
37144
37171
|
var parseCurrentIdentity = (value) => {
|
|
37145
|
-
const input = exactRecord2(value, ["actor_id", "organization_ids"]);
|
|
37172
|
+
const input = exactRecord2(value, ["actor_id", "email", "organization_ids", "organizations"]);
|
|
37173
|
+
const email = input["email"];
|
|
37146
37174
|
const organizationIds = input["organization_ids"];
|
|
37175
|
+
const organizations = input["organizations"];
|
|
37147
37176
|
if (typeof input["actor_id"] !== "string" || input["actor_id"].length === 0 || input["actor_id"].length > 256 || [...input["actor_id"]].some((character) => {
|
|
37148
37177
|
const codePoint = character.codePointAt(0) ?? 0;
|
|
37149
37178
|
return codePoint <= 31 || codePoint === 127;
|
|
37150
|
-
}) || !Array.isArray(organizationIds) || organizationIds.some((organizationId) => !isUlid(organizationId)) || new Set(organizationIds).size !== organizationIds.length) {
|
|
37179
|
+
}) || email !== null && (!boundedString(email, 3, 254) || !/^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$/u.test(email) || /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u.test(email)) || !Array.isArray(organizationIds) || organizationIds.some((organizationId) => !isUlid(organizationId)) || new Set(organizationIds).size !== organizationIds.length || !Array.isArray(organizations) || organizations.length !== organizationIds.length) {
|
|
37151
37180
|
throw new ResponseContractError();
|
|
37152
37181
|
}
|
|
37182
|
+
organizations.forEach((organization, index) => {
|
|
37183
|
+
const entry = exactRecord2(organization, ["id", "name"]);
|
|
37184
|
+
if (entry["id"] !== organizationIds[index] || !boundedString(entry["name"], 1, 128) || entry["name"].trim() !== entry["name"] || [...entry["name"]].some((character) => {
|
|
37185
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
37186
|
+
return codePoint <= 31 || codePoint === 127;
|
|
37187
|
+
})) {
|
|
37188
|
+
throw new ResponseContractError();
|
|
37189
|
+
}
|
|
37190
|
+
});
|
|
37153
37191
|
return input;
|
|
37154
37192
|
};
|
|
37155
37193
|
var parseAccountProfile = (value) => {
|
|
@@ -40628,7 +40666,7 @@ function exact3(v, keys) {
|
|
|
40628
40666
|
// apps/product-cli/package.json
|
|
40629
40667
|
var package_default = {
|
|
40630
40668
|
name: "@ohmyhost/product-cli",
|
|
40631
|
-
version: "0.1.
|
|
40669
|
+
version: "0.1.35",
|
|
40632
40670
|
private: true,
|
|
40633
40671
|
ohmyhost: {
|
|
40634
40672
|
deployment: "production",
|
|
@@ -40965,7 +41003,7 @@ var HELP_USAGE = Object.freeze({
|
|
|
40965
41003
|
"project flag set": "ohmyhost project flag set --project ULID --enabled true|false --idempotency-key KEY --json (shows the small Powered by ohmyho.st flag on the production site; while it shows, this project's custom domain uses no domain credits and also works on Free, and each Paid period bought through Stripe adds 250 credits to the workspace, however many projects show the flag)",
|
|
40966
41004
|
"project handle check": "ohmyhost project handle check --handle HANDLE --json (is this address free? answers with a reason and free alternatives; the address becomes HANDLE.check.omh.st)",
|
|
40967
41005
|
"project handle set": "ohmyhost project handle set --project ULID --handle HANDLE --if-match ETAG --idempotency-key KEY --json (moves the project to a free address; the old one stops working and anyone may claim it)",
|
|
40968
|
-
"database compute set": "ohmyhost database compute set --project ULID --environment dev|prod --profile standard|performance --idempotency-key KEY --yes [--wait] --json\n standard: Free 0.25 CU/1 GB
|
|
41006
|
+
"database compute set": "ohmyhost database compute set --project ULID --environment dev|prod --profile standard|performance --idempotency-key KEY --yes [--wait] --json\n standard: Free 0.25 CU/1 GB, Paid 0.5 CU/2 GB. performance: Paid 1 CU/4 GB, 2.5x database compute credits per equal active minute. All profiles use the provider-default idle suspension.",
|
|
40969
41007
|
"database compute get": "ohmyhost database compute get --project ULID [--environment dev|prod] --json",
|
|
40970
41008
|
"database write": "ohmyhost database write --project ULID --environment dev|prod --statement-file PATH --idempotency-key KEY [--parameters-json JSON] --yes --json",
|
|
40971
41009
|
"database query": "ohmyhost database query --project ULID --environment dev|prod --statement SQL [--parameters-json JSON] --json",
|
|
@@ -47136,9 +47174,14 @@ var import_yaml2 = __toESM(require_dist(), 1);
|
|
|
47136
47174
|
|
|
47137
47175
|
// packages/contracts/dist/framework-family.js
|
|
47138
47176
|
function classifyFrameworkFamily(dependencies) {
|
|
47177
|
+
const astro = dependencies.has("astro");
|
|
47139
47178
|
const next = dependencies.has("next");
|
|
47140
47179
|
const tanStack = dependencies.has("@tanstack/react-start");
|
|
47141
47180
|
const vite = dependencies.has("vite");
|
|
47181
|
+
if (astro && (next || tanStack))
|
|
47182
|
+
return "ambiguous";
|
|
47183
|
+
if (astro)
|
|
47184
|
+
return "astro";
|
|
47142
47185
|
if (next && (tanStack || vite))
|
|
47143
47186
|
return "ambiguous";
|
|
47144
47187
|
if (next)
|
|
@@ -47164,6 +47207,7 @@ var DEPENDENCY_FIELDS = Object.freeze({
|
|
|
47164
47207
|
any: Object.freeze(["dependencies", "devDependencies", "optionalDependencies"])
|
|
47165
47208
|
});
|
|
47166
47209
|
var REQUIRED_DEPENDENCIES = Object.freeze({
|
|
47210
|
+
astro: Object.freeze([["astro", "build"]]),
|
|
47167
47211
|
nextjs: Object.freeze([
|
|
47168
47212
|
["next", "runtime"],
|
|
47169
47213
|
["react", "runtime"],
|
|
@@ -47182,6 +47226,7 @@ var REQUIRED_DEPENDENCIES = Object.freeze({
|
|
|
47182
47226
|
});
|
|
47183
47227
|
var TANSTACK_EDGE_DEPENDENCY = Object.freeze([CLOUDFLARE_PLUGIN, "build"]);
|
|
47184
47228
|
var BUILD_SCRIPT_FRAMEWORKS = Object.freeze({
|
|
47229
|
+
astro: "astro",
|
|
47185
47230
|
nextjs: "nextjs",
|
|
47186
47231
|
"vite-static": "vite",
|
|
47187
47232
|
"tanstack-start": "tanstack-start"
|
|
@@ -47190,7 +47235,11 @@ var BUILD_OUTPUTS = Object.freeze({
|
|
|
47190
47235
|
"vite-static": "dist",
|
|
47191
47236
|
"tanstack-start": "dist/client"
|
|
47192
47237
|
});
|
|
47193
|
-
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
|
+
});
|
|
47194
47243
|
var POSTCSS_CONFIG_PATH = /^(?:postcss\.config\.(?:[cm]?js|json)|\.postcssrc\.(?:js|json))$/u;
|
|
47195
47244
|
var TAILWIND_TURBOPACK_LOADER = "@tailwindcss/turbopack";
|
|
47196
47245
|
var MAXIMUM_LOCKFILE_LENGTH = 5 * 1024 * 1024;
|
|
@@ -47252,7 +47301,7 @@ function viteCompanionRequired(configuration) {
|
|
|
47252
47301
|
function frameworkVersionAdmissions(framework, manifest2, lockfile) {
|
|
47253
47302
|
const admissions = [];
|
|
47254
47303
|
let locked;
|
|
47255
|
-
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]) {
|
|
47256
47305
|
if (!isFrameworkVersionPackage(name))
|
|
47257
47306
|
continue;
|
|
47258
47307
|
const declared = declaredDependency(manifest2, name, placement);
|
|
@@ -47440,14 +47489,14 @@ function sourceWithoutComments(source) {
|
|
|
47440
47489
|
return result;
|
|
47441
47490
|
}
|
|
47442
47491
|
function isDatabaseContractModule(path2) {
|
|
47443
|
-
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);
|
|
47444
47493
|
}
|
|
47445
47494
|
function manifestFindings(input, versions) {
|
|
47446
47495
|
const { configuration, framework, manifest: manifest2 } = input;
|
|
47447
47496
|
const findings = [];
|
|
47448
47497
|
if (framework !== "functions" && !isAdmittedFrameworkBuildScript(BUILD_SCRIPT_FRAMEWORKS[framework], ownValue(manifest2["scripts"], "build")))
|
|
47449
47498
|
findings.push(diagnostic({ code: "build_script_unsupported", path: PACKAGE_MANIFEST2, framework }));
|
|
47450
|
-
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];
|
|
47451
47500
|
for (const [name, placement] of required)
|
|
47452
47501
|
if (declaredDependency(manifest2, name, placement) === null)
|
|
47453
47502
|
findings.push(diagnostic({
|
|
@@ -47481,14 +47530,14 @@ function configurationFindings(input) {
|
|
|
47481
47530
|
findings.push(diagnostic({ code: "runtime_mode_unsupported", path: REPOSITORY_CONFIG, framework }));
|
|
47482
47531
|
if (build !== null && framework !== "nextjs" && build.ssg_cache_max_mib !== void 0)
|
|
47483
47532
|
findings.push(diagnostic({ code: "build_option_unsupported", path: REPOSITORY_CONFIG }));
|
|
47484
|
-
const output = BUILD_OUTPUTS[framework];
|
|
47533
|
+
const output = framework === "astro" ? configuration.runtime.mode === "edge" ? "dist/client" : "dist" : BUILD_OUTPUTS[framework];
|
|
47485
47534
|
if (build !== null && output !== void 0 && build.output !== output)
|
|
47486
47535
|
findings.push(diagnostic({ code: "build_output_unsupported", path: REPOSITORY_CONFIG, framework }));
|
|
47487
47536
|
if (packageManager !== null && framework !== "nextjs" && (configuration.build.install !== packageManager.installCommand || build !== null && build.command !== packageManager.buildCommand))
|
|
47488
47537
|
findings.push(diagnostic({ code: "build_command_mismatch", path: REPOSITORY_CONFIG }));
|
|
47489
47538
|
if (framework === "vite-static" && viteCompanionRequired(configuration) && !files.includes(VITE_COMPANION_ENTRY_PATH))
|
|
47490
47539
|
findings.push(diagnostic({ code: "companion_entry_required", path: VITE_COMPANION_ENTRY_PATH }));
|
|
47491
|
-
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))
|
|
47492
47541
|
findings.push(diagnostic({ code: "worker_module_required", path: WORKER_MODULE_PATH }));
|
|
47493
47542
|
if (managedCustomerAuthAdmissionIssue(configuration) !== null)
|
|
47494
47543
|
findings.push(diagnostic({ code: "managed_auth_database_required", path: REPOSITORY_CONFIG }));
|
|
@@ -47496,6 +47545,8 @@ function configurationFindings(input) {
|
|
|
47496
47545
|
}
|
|
47497
47546
|
function runtimeModeAdmitted(framework, configuration, crons) {
|
|
47498
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";
|
|
47499
47550
|
if (framework === "nextjs")
|
|
47500
47551
|
return mode === "edge";
|
|
47501
47552
|
if (framework === "vite-static")
|
|
@@ -47510,6 +47561,8 @@ function frameworkConfigFindings(input) {
|
|
|
47510
47561
|
if (frameworkConfig === null || framework === "functions")
|
|
47511
47562
|
return [];
|
|
47512
47563
|
const { path: path2, text } = frameworkConfig;
|
|
47564
|
+
if (framework === "astro")
|
|
47565
|
+
return astroConfigFindings(text, path2, input.configuration.runtime.mode);
|
|
47513
47566
|
if (framework === "nextjs")
|
|
47514
47567
|
return nextConfigFindings(text, path2, hasPostcssConfiguration(input));
|
|
47515
47568
|
if (framework === "vite-static")
|
|
@@ -47534,7 +47587,7 @@ function repositoryConfiguration(text) {
|
|
|
47534
47587
|
function frameworkConfigPath(framework, files, findings) {
|
|
47535
47588
|
if (framework === "functions")
|
|
47536
47589
|
return null;
|
|
47537
|
-
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));
|
|
47538
47591
|
if (framework === "nextjs")
|
|
47539
47592
|
admitted(findings, () => resolveFrameworkConfig("open-next.config", files));
|
|
47540
47593
|
const required = REQUIRED_CONFIG_PATHS[framework];
|
|
@@ -47836,6 +47889,15 @@ function hasNamedImport(tokens, name, moduleName) {
|
|
|
47836
47889
|
function hasModuleImport(tokens, moduleName) {
|
|
47837
47890
|
return tokens.some((token, index) => token.value === "from" && tokens[index + 1]?.kind === "string" && tokens[index + 1]?.value === moduleName);
|
|
47838
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
|
+
}
|
|
47839
47901
|
|
|
47840
47902
|
// packages/contracts/dist/database-migration-errors.js
|
|
47841
47903
|
var DatabaseMigrationAdmissionError = class extends Error {
|
|
@@ -48288,7 +48350,7 @@ async function initializeRepository(input) {
|
|
|
48288
48350
|
const match = path2.match(/^supabase\/functions\/([^/]+)\//u);
|
|
48289
48351
|
return match?.[1] === void 0 || match[1].startsWith("_") ? [] : [match[1]];
|
|
48290
48352
|
}));
|
|
48291
|
-
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;
|
|
48292
48354
|
const supabase = dependencies.has("@supabase/supabase-js") || dependencies.has("@supabase/ssr");
|
|
48293
48355
|
const configuredDatabase = existingConfiguration?.database?.enabled === true;
|
|
48294
48356
|
const databaseProvider = supabaseMigrationCount > 0 ? "supabase" : postgresMigrationCount > 0 || configuredDatabase ? "postgresql" : "none";
|
|
@@ -48328,14 +48390,14 @@ async function initializeRepository(input) {
|
|
|
48328
48390
|
const targetBetterAuth = existingConfiguration?.auth?.provider === "better-auth";
|
|
48329
48391
|
const targetMail = existingConfiguration?.mail?.enabled === true;
|
|
48330
48392
|
const targetStorage = r2 || supabaseStorage;
|
|
48331
|
-
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);
|
|
48332
48394
|
const companionRequired = framework === "vite" && (existingConfiguration === null ? databaseProvider !== "none" || targetBetterAuth || targetMail || targetStorage || edgeFunctionNames.size > 0 || applicationFiles.includes(VITE_COMPANION_ENTRY_PATH) : viteCompanionRequired(existingConfiguration));
|
|
48333
48395
|
const generatedConfigurationYaml = renderConfiguration({
|
|
48334
48396
|
project,
|
|
48335
48397
|
framework,
|
|
48336
48398
|
packageManager,
|
|
48337
48399
|
databaseProvider,
|
|
48338
|
-
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)),
|
|
48339
48401
|
mailEnabled: targetMail,
|
|
48340
48402
|
betterAuthEnabled: targetBetterAuth,
|
|
48341
48403
|
storageEnabled: targetStorage,
|
|
@@ -48453,7 +48515,7 @@ function requiredCatalogBlocker(diagnostic2, applicationRoot) {
|
|
|
48453
48515
|
async function workerModuleBlockers(context) {
|
|
48454
48516
|
const { config, framework, files } = context;
|
|
48455
48517
|
const mode = config?.runtime.mode;
|
|
48456
|
-
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");
|
|
48457
48519
|
const path2 = framework === "vite" ? VITE_COMPANION_ENTRY_PATH : WORKER_MODULE_PATH;
|
|
48458
48520
|
if (framework !== "functions" && !scheduled || !files.includes(path2))
|
|
48459
48521
|
return [];
|
|
@@ -48726,7 +48788,7 @@ function hasDirectSafeBuildCommand(manifest2, framework) {
|
|
|
48726
48788
|
const scripts = manifest2["scripts"];
|
|
48727
48789
|
if (!isRecord5(scripts) || typeof scripts["build"] !== "string")
|
|
48728
48790
|
return false;
|
|
48729
|
-
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"]);
|
|
48730
48792
|
}
|
|
48731
48793
|
async function assertRepositoryRoot(root) {
|
|
48732
48794
|
let information;
|
|
@@ -48832,11 +48894,11 @@ async function readResolvingLockfile(applicationDirectory, admission) {
|
|
|
48832
48894
|
return text === null ? null : Object.freeze({ name: admission.lockfile, text });
|
|
48833
48895
|
}
|
|
48834
48896
|
async function readFrameworkConfig(applicationDirectory, files, framework) {
|
|
48835
|
-
if (framework !== "nextjs" && framework !== "vite" && framework !== "tanstack-start")
|
|
48897
|
+
if (framework !== "astro" && framework !== "nextjs" && framework !== "vite" && framework !== "tanstack-start")
|
|
48836
48898
|
return null;
|
|
48837
48899
|
let path2;
|
|
48838
48900
|
try {
|
|
48839
|
-
path2 = resolveFrameworkConfig(framework === "nextjs" ? "next.config" : "vite.config", files);
|
|
48901
|
+
path2 = resolveFrameworkConfig(framework === "astro" ? "astro.config" : framework === "nextjs" ? "next.config" : "vite.config", files);
|
|
48840
48902
|
} catch (error) {
|
|
48841
48903
|
if (error instanceof FrameworkAdmissionError)
|
|
48842
48904
|
return null;
|
|
@@ -48902,7 +48964,7 @@ function renderConfiguration(input) {
|
|
|
48902
48964
|
let output = "dist";
|
|
48903
48965
|
if (input.framework === "nextjs")
|
|
48904
48966
|
output = ".open-next/assets";
|
|
48905
|
-
else if (input.framework === "tanstack-start")
|
|
48967
|
+
else if (input.framework === "tanstack-start" || input.framework === "astro" && input.tanStackRuntime === "edge")
|
|
48906
48968
|
output = "dist/client";
|
|
48907
48969
|
let mode = "auto";
|
|
48908
48970
|
if (input.framework === "functions")
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -399,7 +399,7 @@ const HELP_USAGE = Object.freeze({
|
|
|
399
399
|
"ohmyhost project handle set --project ULID --handle HANDLE --if-match ETAG --idempotency-key KEY --json (moves the project to a free address; the old one stops working and anyone may claim it)",
|
|
400
400
|
"database compute set":
|
|
401
401
|
"ohmyhost database compute set --project ULID --environment dev|prod --profile standard|performance --idempotency-key KEY --yes [--wait] --json\n" +
|
|
402
|
-
" standard: Free 0.25 CU/1 GB
|
|
402
|
+
" standard: Free 0.25 CU/1 GB, Paid 0.5 CU/2 GB. performance: Paid 1 CU/4 GB, 2.5x database compute credits per equal active minute. All profiles use the provider-default idle suspension.",
|
|
403
403
|
"database compute get":
|
|
404
404
|
"ohmyhost database compute get --project ULID [--environment dev|prod] --json",
|
|
405
405
|
"database write":
|
|
@@ -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";
|
|
@@ -63,7 +63,9 @@ export interface SafeProblem {
|
|
|
63
63
|
|
|
64
64
|
export interface PublicCurrentIdentity {
|
|
65
65
|
readonly actor_id: string;
|
|
66
|
+
readonly email: string | null;
|
|
66
67
|
readonly organization_ids: readonly string[];
|
|
68
|
+
readonly organizations: readonly { readonly id: string; readonly name: string }[];
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
/** One workspace the signed-in user belongs to, with the provider identity a selection needs. */
|
|
@@ -635,8 +637,10 @@ export function parseProjectCreditBudget(value: unknown): ProjectCreditBudget {
|
|
|
635
637
|
}
|
|
636
638
|
|
|
637
639
|
export const parseCurrentIdentity = (value: unknown): PublicCurrentIdentity => {
|
|
638
|
-
const input = exactRecord(value, ["actor_id", "organization_ids"]);
|
|
640
|
+
const input = exactRecord(value, ["actor_id", "email", "organization_ids", "organizations"]);
|
|
641
|
+
const email = input["email"];
|
|
639
642
|
const organizationIds = input["organization_ids"];
|
|
643
|
+
const organizations = input["organizations"];
|
|
640
644
|
if (
|
|
641
645
|
typeof input["actor_id"] !== "string" ||
|
|
642
646
|
input["actor_id"].length === 0 ||
|
|
@@ -645,12 +649,32 @@ export const parseCurrentIdentity = (value: unknown): PublicCurrentIdentity => {
|
|
|
645
649
|
const codePoint = character.codePointAt(0) ?? 0;
|
|
646
650
|
return codePoint <= 31 || codePoint === 127;
|
|
647
651
|
}) ||
|
|
652
|
+
(email !== null &&
|
|
653
|
+
(!boundedString(email, 3, 254) ||
|
|
654
|
+
!/^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$/u.test(email) ||
|
|
655
|
+
/[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u.test(email))) ||
|
|
648
656
|
!Array.isArray(organizationIds) ||
|
|
649
657
|
organizationIds.some((organizationId) => !isUlid(organizationId)) ||
|
|
650
|
-
new Set(organizationIds).size !== organizationIds.length
|
|
658
|
+
new Set(organizationIds).size !== organizationIds.length ||
|
|
659
|
+
!Array.isArray(organizations) ||
|
|
660
|
+
organizations.length !== organizationIds.length
|
|
651
661
|
) {
|
|
652
662
|
throw new ResponseContractError();
|
|
653
663
|
}
|
|
664
|
+
organizations.forEach((organization: unknown, index) => {
|
|
665
|
+
const entry = exactRecord(organization, ["id", "name"]);
|
|
666
|
+
if (
|
|
667
|
+
entry["id"] !== organizationIds[index] ||
|
|
668
|
+
!boundedString(entry["name"], 1, 128) ||
|
|
669
|
+
entry["name"].trim() !== entry["name"] ||
|
|
670
|
+
[...entry["name"]].some((character) => {
|
|
671
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
672
|
+
return codePoint <= 31 || codePoint === 127;
|
|
673
|
+
})
|
|
674
|
+
) {
|
|
675
|
+
throw new ResponseContractError();
|
|
676
|
+
}
|
|
677
|
+
});
|
|
654
678
|
return input as unknown as PublicCurrentIdentity;
|
|
655
679
|
};
|
|
656
680
|
|
|
@@ -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
|
+
}
|
|
@@ -945,7 +945,7 @@ export const completeCloudflareDnsAuthorization = <ThrowOnError extends boolean
|
|
|
945
945
|
/**
|
|
946
946
|
* Get the current authenticated identity
|
|
947
947
|
*
|
|
948
|
-
* Returns the stable ohmyhost actor and
|
|
948
|
+
* Returns the stable ohmyhost actor, the current user's or API-key owner's email, and the credential's organization scope with current display names. Machine-to-machine credentials have a null email. Organizations match organization_ids in the same order.
|
|
949
949
|
*/
|
|
950
950
|
export const getCurrentIdentity = <ThrowOnError extends boolean = true>(
|
|
951
951
|
parameters?: {
|
|
@@ -1148,11 +1148,25 @@ export type OrganizationAccount = {
|
|
|
1148
1148
|
};
|
|
1149
1149
|
|
|
1150
1150
|
/**
|
|
1151
|
-
*
|
|
1151
|
+
* Customer-visible current account and credential organization scope for authenticated agent clients.
|
|
1152
1152
|
*/
|
|
1153
1153
|
export type CurrentIdentity = {
|
|
1154
1154
|
actor_id: string;
|
|
1155
|
+
/**
|
|
1156
|
+
* Email of the current user or user API-key owner; null for machine-to-machine credentials.
|
|
1157
|
+
*/
|
|
1158
|
+
email: string | null;
|
|
1155
1159
|
organization_ids: Array<Ulid>;
|
|
1160
|
+
/**
|
|
1161
|
+
* Current names for exactly the organization_ids scope, in the same order.
|
|
1162
|
+
*/
|
|
1163
|
+
organizations: Array<{
|
|
1164
|
+
id: Ulid;
|
|
1165
|
+
/**
|
|
1166
|
+
* Current organization display name without surrounding whitespace or ASCII control characters.
|
|
1167
|
+
*/
|
|
1168
|
+
name: string;
|
|
1169
|
+
}>;
|
|
1156
1170
|
};
|
|
1157
1171
|
|
|
1158
1172
|
export type Project = {
|