@amerged/ohmyhost-cli 0.1.26 → 0.1.28
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/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-YMVBC7UB.js → chunk-5FDJR2IZ.js} +86 -29
- 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 +14 -2
- package/src/apps/product-cli/src/runtime-contract.ts +9 -1
- package/src/packages/contracts/src/framework-admission.ts +3 -6
- package/src/packages/contracts/src/framework-build-script.mjs +19 -0
- package/src/packages/contracts/src/index.ts +5 -0
- package/src/packages/contracts/src/problem-policy.ts +7 -0
- package/src/packages/sdk-ts/package.json +1 -1
- package/src/packages/sdk-ts/src/generated/sdk.gen.ts +2 -2
- package/src/packages/sdk-ts/src/generated/types.gen.ts +7 -2
package/README.md
CHANGED
package/THIRD_PARTY_NOTICES.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-5FDJR2IZ.js";
|
|
6
6
|
import "./chunk-7D2RFLWM.js";
|
|
7
7
|
|
|
8
8
|
// apps/product-cli/dist/bin.js
|
|
@@ -3080,9 +3080,9 @@ var require_data = __commonJS({
|
|
|
3080
3080
|
}
|
|
3081
3081
|
});
|
|
3082
3082
|
|
|
3083
|
-
// node_modules/.pnpm/fast-uri@3.1.
|
|
3083
|
+
// node_modules/.pnpm/fast-uri@3.1.8/node_modules/fast-uri/lib/utils.js
|
|
3084
3084
|
var require_utils = __commonJS({
|
|
3085
|
-
"node_modules/.pnpm/fast-uri@3.1.
|
|
3085
|
+
"node_modules/.pnpm/fast-uri@3.1.8/node_modules/fast-uri/lib/utils.js"(exports, module) {
|
|
3086
3086
|
"use strict";
|
|
3087
3087
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
3088
3088
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
@@ -3582,9 +3582,9 @@ var require_utils = __commonJS({
|
|
|
3582
3582
|
}
|
|
3583
3583
|
});
|
|
3584
3584
|
|
|
3585
|
-
// node_modules/.pnpm/fast-uri@3.1.
|
|
3585
|
+
// node_modules/.pnpm/fast-uri@3.1.8/node_modules/fast-uri/lib/schemes.js
|
|
3586
3586
|
var require_schemes = __commonJS({
|
|
3587
|
-
"node_modules/.pnpm/fast-uri@3.1.
|
|
3587
|
+
"node_modules/.pnpm/fast-uri@3.1.8/node_modules/fast-uri/lib/schemes.js"(exports, module) {
|
|
3588
3588
|
"use strict";
|
|
3589
3589
|
var { isUUID } = require_utils();
|
|
3590
3590
|
var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
|
|
@@ -3793,9 +3793,9 @@ var require_schemes = __commonJS({
|
|
|
3793
3793
|
}
|
|
3794
3794
|
});
|
|
3795
3795
|
|
|
3796
|
-
// node_modules/.pnpm/fast-uri@3.1.
|
|
3796
|
+
// node_modules/.pnpm/fast-uri@3.1.8/node_modules/fast-uri/index.js
|
|
3797
3797
|
var require_fast_uri = __commonJS({
|
|
3798
|
-
"node_modules/.pnpm/fast-uri@3.1.
|
|
3798
|
+
"node_modules/.pnpm/fast-uri@3.1.8/node_modules/fast-uri/index.js"(exports, module) {
|
|
3799
3799
|
"use strict";
|
|
3800
3800
|
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
3801
3801
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
@@ -4125,13 +4125,14 @@ var require_fast_uri = __commonJS({
|
|
|
4125
4125
|
if (!malformedIPLiteral) {
|
|
4126
4126
|
malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
|
|
4127
4127
|
}
|
|
4128
|
-
if (
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
parsed.host = reescapeHostDelimiters(host, isIP);
|
|
4133
|
-
}
|
|
4128
|
+
if (uri.indexOf("%") !== -1 && parsed.host !== void 0 && !malformedIPLiteral) {
|
|
4129
|
+
let host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
|
|
4130
|
+
if (!isIP) {
|
|
4131
|
+
host = normalizePercentEncoding(host.toLowerCase());
|
|
4134
4132
|
}
|
|
4133
|
+
parsed.host = reescapeHostDelimiters(host, isIP);
|
|
4134
|
+
}
|
|
4135
|
+
if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
|
|
4135
4136
|
if (parsed.path) {
|
|
4136
4137
|
parsed.path = normalizePathEncoding(parsed.path);
|
|
4137
4138
|
}
|
|
@@ -17002,6 +17003,19 @@ function hasControlCharacter(value, multiline) {
|
|
|
17002
17003
|
|
|
17003
17004
|
// packages/contracts/dist/framework-build-script.mjs
|
|
17004
17005
|
var PINNED_BUN_VERSION = "1.2.22";
|
|
17006
|
+
function isAdmittedNextVersion(version2) {
|
|
17007
|
+
if (typeof version2 !== "string")
|
|
17008
|
+
return false;
|
|
17009
|
+
const match = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u.exec(version2);
|
|
17010
|
+
if (match === null)
|
|
17011
|
+
return false;
|
|
17012
|
+
const major = Number(match[1]);
|
|
17013
|
+
const minor = Number(match[2]);
|
|
17014
|
+
const patch = Number(match[3]);
|
|
17015
|
+
if (![major, minor, patch].every(Number.isSafeInteger))
|
|
17016
|
+
return false;
|
|
17017
|
+
return major === 15 && minor === 5 && patch >= 26 || major === 16 && minor === 3 && patch >= 6 && patch <= 7;
|
|
17018
|
+
}
|
|
17005
17019
|
var TYPESCRIPT_BUILD_STAGE = /^tsc(?:[ \t]+(?:--noEmit|-b|--build))?$/u;
|
|
17006
17020
|
function isAdmittedFrameworkBuildScript(framework, script) {
|
|
17007
17021
|
if (typeof script !== "string")
|
|
@@ -17110,7 +17124,7 @@ function resolveFrameworkConfig(basename2, files) {
|
|
|
17110
17124
|
var VERIFIED_VERSIONS = Object.freeze({
|
|
17111
17125
|
vite: /* @__PURE__ */ new Set(["5.4.21", "8.0.16", "8.2.2"]),
|
|
17112
17126
|
"tanstack-start": /* @__PURE__ */ new Set(["1.168.26", "1.168.49"]),
|
|
17113
|
-
nextjs: /* @__PURE__ */ new Set(["15.5.
|
|
17127
|
+
nextjs: /* @__PURE__ */ new Set(["15.5.26", "16.3.7"])
|
|
17114
17128
|
});
|
|
17115
17129
|
function classifyFrameworkVersion(framework, version2) {
|
|
17116
17130
|
const parsed = parseVersionSpec(version2);
|
|
@@ -17139,7 +17153,7 @@ function insideAdmittedWindow(framework, version2) {
|
|
|
17139
17153
|
case "tanstack-start":
|
|
17140
17154
|
return compareVersions(version2, [1, 168, 26]) >= 0 && compareVersions(version2, [1, 168, 49]) <= 0;
|
|
17141
17155
|
case "nextjs":
|
|
17142
|
-
return
|
|
17156
|
+
return isAdmittedNextVersion(version2.join("."));
|
|
17143
17157
|
}
|
|
17144
17158
|
}
|
|
17145
17159
|
function compareVersions(left, right) {
|
|
@@ -17895,6 +17909,12 @@ var PROBLEM_POLICY = {
|
|
|
17895
17909
|
restAction: "A live project connection already holds this hostname. Remove it from the project you manage with 'ohmyhost domain paid delete --project ULID --hostname HOST --yes --json', then apply it to the new project. Repeating while that connection remains cannot work; report the request_id if you cannot manage its owning project.",
|
|
17896
17910
|
title: "Domain hostname is already connected"
|
|
17897
17911
|
},
|
|
17912
|
+
domain_dns_conflict: {
|
|
17913
|
+
status: 409,
|
|
17914
|
+
retryable: false,
|
|
17915
|
+
action: "Review DNS for the requested hostname and resolve the conflicting delegation or another project's managed records. Preserve mailbox MX, TXT and CAA records. Then repeat the original domain paid apply or delete with the same hostname and idempotency key; do not create another deployment or repeatedly resubmit unchanged conflicts.",
|
|
17916
|
+
title: "Domain DNS records conflict"
|
|
17917
|
+
},
|
|
17898
17918
|
data_change_blocked: {
|
|
17899
17919
|
status: 409,
|
|
17900
17920
|
retryable: true,
|
|
@@ -17976,6 +17996,7 @@ var parsePaidDomain = (value) => {
|
|
|
17976
17996
|
const records2 = input["validation_records"];
|
|
17977
17997
|
if (![
|
|
17978
17998
|
"not_configured",
|
|
17999
|
+
"awaiting_deployment",
|
|
17979
18000
|
"pending",
|
|
17980
18001
|
"active",
|
|
17981
18002
|
"reconciliation_required",
|
|
@@ -17986,7 +18007,7 @@ var parsePaidDomain = (value) => {
|
|
|
17986
18007
|
"paid_plan_required",
|
|
17987
18008
|
"insufficient_organization_credits",
|
|
17988
18009
|
"project_budget_exceeded"
|
|
17989
|
-
].includes(input["suspension_reason"]) || status === "suspended" !== (input["suspension_reason"] !== null) || status === "suspended" && input["url"] !== null || input["environment"] !== "prod" || !isSaasCnameTarget(input["cname_target"]) || hostname !== null && !isPaidHostname(hostname) || input["custom_hostname_status"] !== null && typeof input["custom_hostname_status"] !== "string" || input["ssl_status"] !== null && typeof input["ssl_status"] !== "string" || !Array.isArray(records2) || records2.length > 16 || !records2.every(isPaidValidationRecord) || input["url"] !== null && input["url"] !== `https://${String(hostname)}`) {
|
|
18010
|
+
].includes(input["suspension_reason"]) || status === "suspended" !== (input["suspension_reason"] !== null) || status === "suspended" && input["url"] !== null || input["environment"] !== "prod" || !isSaasCnameTarget(input["cname_target"]) || hostname !== null && !isPaidHostname(hostname) || input["custom_hostname_status"] !== null && typeof input["custom_hostname_status"] !== "string" || input["ssl_status"] !== null && typeof input["ssl_status"] !== "string" || !Array.isArray(records2) || records2.length > 16 || !records2.every(isPaidValidationRecord) || input["url"] !== null && input["url"] !== `https://${String(hostname)}` || status === "awaiting_deployment" && (hostname === null || input["custom_hostname_status"] !== null || input["ssl_status"] !== null || input["url"] !== null || records2.length !== 0)) {
|
|
17990
18011
|
throw new ResponseContractError();
|
|
17991
18012
|
}
|
|
17992
18013
|
return input;
|
|
@@ -18947,7 +18968,7 @@ function exact2(v, keys) {
|
|
|
18947
18968
|
// apps/product-cli/package.json
|
|
18948
18969
|
var package_default = {
|
|
18949
18970
|
name: "@ohmyhost/product-cli",
|
|
18950
|
-
version: "0.1.
|
|
18971
|
+
version: "0.1.28",
|
|
18951
18972
|
private: true,
|
|
18952
18973
|
ohmyhost: {
|
|
18953
18974
|
deployment: "production",
|
|
@@ -24443,6 +24464,12 @@ var ohmyhost_schema_default = {
|
|
|
24443
24464
|
},
|
|
24444
24465
|
output: {
|
|
24445
24466
|
$ref: "#/$defs/relativePath"
|
|
24467
|
+
},
|
|
24468
|
+
ssg_cache_max_mib: {
|
|
24469
|
+
type: "integer",
|
|
24470
|
+
minimum: 1,
|
|
24471
|
+
maximum: 64,
|
|
24472
|
+
description: "Maximum private immutable Next.js prerender cache in MiB; defaults to 32. Cache storage costs zero credits. Public assets retain their independent limit."
|
|
24446
24473
|
}
|
|
24447
24474
|
}
|
|
24448
24475
|
},
|
|
@@ -24510,26 +24537,46 @@ var ohmyhost_schema_default = {
|
|
|
24510
24537
|
pattern: "^(?:https|wss)://"
|
|
24511
24538
|
}
|
|
24512
24539
|
},
|
|
24513
|
-
scripts: {
|
|
24514
|
-
|
|
24515
|
-
|
|
24516
|
-
|
|
24517
|
-
|
|
24518
|
-
|
|
24540
|
+
scripts: {
|
|
24541
|
+
$ref: "#/$defs/browserOrigins"
|
|
24542
|
+
},
|
|
24543
|
+
styles: {
|
|
24544
|
+
$ref: "#/$defs/browserOrigins"
|
|
24545
|
+
},
|
|
24546
|
+
images: {
|
|
24547
|
+
$ref: "#/$defs/browserOrigins"
|
|
24548
|
+
},
|
|
24549
|
+
fonts: {
|
|
24550
|
+
$ref: "#/$defs/browserOrigins"
|
|
24551
|
+
},
|
|
24552
|
+
frames: {
|
|
24553
|
+
$ref: "#/$defs/browserOrigins"
|
|
24554
|
+
},
|
|
24555
|
+
frameAncestors: {
|
|
24556
|
+
$ref: "#/$defs/browserOrigins"
|
|
24557
|
+
},
|
|
24519
24558
|
workers: {
|
|
24520
24559
|
type: "object",
|
|
24521
24560
|
additionalProperties: false,
|
|
24522
24561
|
properties: {
|
|
24523
|
-
self: {
|
|
24524
|
-
|
|
24562
|
+
self: {
|
|
24563
|
+
type: "boolean"
|
|
24564
|
+
},
|
|
24565
|
+
blob: {
|
|
24566
|
+
type: "boolean"
|
|
24567
|
+
}
|
|
24525
24568
|
}
|
|
24526
24569
|
},
|
|
24527
24570
|
cors: {
|
|
24528
24571
|
type: "object",
|
|
24529
24572
|
additionalProperties: false,
|
|
24530
24573
|
properties: {
|
|
24531
|
-
origins: {
|
|
24532
|
-
|
|
24574
|
+
origins: {
|
|
24575
|
+
$ref: "#/$defs/browserOrigins"
|
|
24576
|
+
},
|
|
24577
|
+
credentials: {
|
|
24578
|
+
type: "boolean"
|
|
24579
|
+
}
|
|
24533
24580
|
}
|
|
24534
24581
|
}
|
|
24535
24582
|
}
|
|
@@ -24736,6 +24783,9 @@ var ohmyhost_schema_default = {
|
|
|
24736
24783
|
},
|
|
24737
24784
|
output: {
|
|
24738
24785
|
$ref: "#/$defs/relativePath"
|
|
24786
|
+
},
|
|
24787
|
+
ssg_cache_max_mib: {
|
|
24788
|
+
$ref: "#/$defs/build/properties/ssg_cache_max_mib"
|
|
24739
24789
|
}
|
|
24740
24790
|
}
|
|
24741
24791
|
}
|
|
@@ -24876,7 +24926,8 @@ function parseOhmyhostConfig(value) {
|
|
|
24876
24926
|
build: input.runtime.mode === "functions" ? Object.freeze({ install: input.build.install }) : Object.freeze({
|
|
24877
24927
|
install: input.build.install,
|
|
24878
24928
|
command: input.build.command,
|
|
24879
|
-
output: input.build.output
|
|
24929
|
+
output: input.build.output,
|
|
24930
|
+
...input.build.ssg_cache_max_mib === void 0 ? {} : { ssg_cache_max_mib: input.build.ssg_cache_max_mib }
|
|
24880
24931
|
}),
|
|
24881
24932
|
runtime: Object.freeze({
|
|
24882
24933
|
mode: input.runtime.mode,
|
|
@@ -25823,6 +25874,12 @@ function projectName(explicit, packageJson) {
|
|
|
25823
25874
|
}
|
|
25824
25875
|
function repositoryBlockers(packageJson, framework, nextStandaloneOutput, tanStackRuntime, files, packageManagerAdmission, frameworkConfigs, compatibility, existingConfiguration) {
|
|
25825
25876
|
const blockers = [];
|
|
25877
|
+
if (framework !== "nextjs" && existingConfiguration !== null && "command" in existingConfiguration.build && existingConfiguration.build.ssg_cache_max_mib !== void 0) {
|
|
25878
|
+
blockers.push({
|
|
25879
|
+
code: "framework_unsupported",
|
|
25880
|
+
message: "build.ssg_cache_max_mib is supported only by Next.js; remove it from this application's configuration."
|
|
25881
|
+
});
|
|
25882
|
+
}
|
|
25826
25883
|
if (framework === "unknown") {
|
|
25827
25884
|
blockers.push({
|
|
25828
25885
|
code: "framework_unsupported",
|
|
@@ -25868,7 +25925,7 @@ function repositoryBlockers(packageJson, framework, nextStandaloneOutput, tanSta
|
|
|
25868
25925
|
const unsupported = compatibility.frameworks.filter((entry) => entry.classification === "unsupported").map((entry) => `${FRAMEWORK_PACKAGE[entry.framework]}@${entry.version || "missing"}`).join(", ");
|
|
25869
25926
|
blockers.push({
|
|
25870
25927
|
code: "framework_version_unsupported",
|
|
25871
|
-
message: `${unsupported} is outside the versions ohmyho.st builds: next 15.5.x or 16.
|
|
25928
|
+
message: `${unsupported} is outside the versions ohmyho.st builds: next 15.5.26+ (15.5.x) or 16.3.6\u201316.3.7, vite 5.4.0\u20138.2.2, @tanstack/react-start 1.168.26\u20131.168.49, as an exact version or a ^ or ~ range whose base version is inside. Pin a version in that range in package.json, update the lockfile, commit and push.`
|
|
25872
25929
|
});
|
|
25873
25930
|
}
|
|
25874
25931
|
const scripts = packageJson["scripts"];
|
|
@@ -25906,7 +25963,7 @@ function repositoryBlockers(packageJson, framework, nextStandaloneOutput, tanSta
|
|
|
25906
25963
|
if (!nextConfigured) {
|
|
25907
25964
|
blockers.push({
|
|
25908
25965
|
code: "next_adapter_unconfigured",
|
|
25909
|
-
message: 'Next.js needs scripts.build exactly "next build" or "next build --webpack", react and react-dom at exact versions such as "19.1.0" (no ^ or ~), next within 15.5.x or 16.
|
|
25966
|
+
message: 'Next.js needs scripts.build exactly "next build" or "next build --webpack", react and react-dom at exact versions such as "19.1.0" (no ^ or ~), next within 15.5.26+ (15.5.x) or 16.3.6\u201316.3.7, and exactly one next.config.js, .mjs or .ts, with at most one open-next.config file. ohmyho.st adds the OpenNext build itself; do not make it the build script.'
|
|
25910
25967
|
});
|
|
25911
25968
|
}
|
|
25912
25969
|
}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1163,6 +1163,18 @@ function repositoryBlockers(
|
|
|
1163
1163
|
existingConfiguration: OhmyhostConfig | null,
|
|
1164
1164
|
): RepositoryInitBlocker[] {
|
|
1165
1165
|
const blockers: RepositoryInitBlocker[] = [];
|
|
1166
|
+
if (
|
|
1167
|
+
framework !== "nextjs" &&
|
|
1168
|
+
existingConfiguration !== null &&
|
|
1169
|
+
"command" in existingConfiguration.build &&
|
|
1170
|
+
existingConfiguration.build.ssg_cache_max_mib !== undefined
|
|
1171
|
+
) {
|
|
1172
|
+
blockers.push({
|
|
1173
|
+
code: "framework_unsupported",
|
|
1174
|
+
message:
|
|
1175
|
+
"build.ssg_cache_max_mib is supported only by Next.js; remove it from this application's configuration.",
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1166
1178
|
if (framework === "unknown") {
|
|
1167
1179
|
blockers.push({
|
|
1168
1180
|
code: "framework_unsupported",
|
|
@@ -1230,7 +1242,7 @@ function repositoryBlockers(
|
|
|
1230
1242
|
.join(", ");
|
|
1231
1243
|
blockers.push({
|
|
1232
1244
|
code: "framework_version_unsupported",
|
|
1233
|
-
message: `${unsupported} is outside the versions ohmyho.st builds: next 15.5.x or 16.
|
|
1245
|
+
message: `${unsupported} is outside the versions ohmyho.st builds: next 15.5.26+ (15.5.x) or 16.3.6–16.3.7, vite 5.4.0–8.2.2, @tanstack/react-start 1.168.26–1.168.49, as an exact version or a ^ or ~ range whose base version is inside. Pin a version in that range in package.json, update the lockfile, commit and push.`,
|
|
1234
1246
|
});
|
|
1235
1247
|
}
|
|
1236
1248
|
const scripts = packageJson["scripts"];
|
|
@@ -1285,7 +1297,7 @@ function repositoryBlockers(
|
|
|
1285
1297
|
blockers.push({
|
|
1286
1298
|
code: "next_adapter_unconfigured",
|
|
1287
1299
|
message:
|
|
1288
|
-
'Next.js needs scripts.build exactly "next build" or "next build --webpack", react and react-dom at exact versions such as "19.1.0" (no ^ or ~), next within 15.5.x or 16.
|
|
1300
|
+
'Next.js needs scripts.build exactly "next build" or "next build --webpack", react and react-dom at exact versions such as "19.1.0" (no ^ or ~), next within 15.5.26+ (15.5.x) or 16.3.6–16.3.7, and exactly one next.config.js, .mjs or .ts, with at most one open-next.config file. ohmyho.st adds the OpenNext build itself; do not make it the build script.',
|
|
1289
1301
|
});
|
|
1290
1302
|
}
|
|
1291
1303
|
}
|
|
@@ -94,6 +94,7 @@ export interface PublicPaidDomainPlan {
|
|
|
94
94
|
export interface PublicPaidDomain {
|
|
95
95
|
readonly status:
|
|
96
96
|
| "not_configured"
|
|
97
|
+
| "awaiting_deployment"
|
|
97
98
|
| "pending"
|
|
98
99
|
| "active"
|
|
99
100
|
| "reconciliation_required"
|
|
@@ -153,6 +154,7 @@ export const parsePaidDomain = (value: unknown): PublicPaidDomain => {
|
|
|
153
154
|
if (
|
|
154
155
|
![
|
|
155
156
|
"not_configured",
|
|
157
|
+
"awaiting_deployment",
|
|
156
158
|
"pending",
|
|
157
159
|
"active",
|
|
158
160
|
"reconciliation_required",
|
|
@@ -176,7 +178,13 @@ export const parsePaidDomain = (value: unknown): PublicPaidDomain => {
|
|
|
176
178
|
!Array.isArray(records) ||
|
|
177
179
|
records.length > 16 ||
|
|
178
180
|
!records.every(isPaidValidationRecord) ||
|
|
179
|
-
(input["url"] !== null && input["url"] !== `https://${String(hostname)}`)
|
|
181
|
+
(input["url"] !== null && input["url"] !== `https://${String(hostname)}`) ||
|
|
182
|
+
(status === "awaiting_deployment" &&
|
|
183
|
+
(hostname === null ||
|
|
184
|
+
input["custom_hostname_status"] !== null ||
|
|
185
|
+
input["ssl_status"] !== null ||
|
|
186
|
+
input["url"] !== null ||
|
|
187
|
+
records.length !== 0))
|
|
180
188
|
) {
|
|
181
189
|
throw new ResponseContractError();
|
|
182
190
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PINNED_BUN_VERSION } from "./framework-build-script.mjs";
|
|
1
|
+
import { isAdmittedNextVersion, PINNED_BUN_VERSION } from "./framework-build-script.mjs";
|
|
2
2
|
import { managedCustomerAuthDatabaseMessage } from "./customer-auth-admission.js";
|
|
3
3
|
export { managedCustomerAuthAdmissionIssue } from "./customer-auth-admission.js";
|
|
4
4
|
|
|
@@ -129,7 +129,7 @@ export interface FrameworkVersionAdmission {
|
|
|
129
129
|
const VERIFIED_VERSIONS: Readonly<Record<AdmittedFramework, ReadonlySet<string>>> = Object.freeze({
|
|
130
130
|
vite: new Set(["5.4.21", "8.0.16", "8.2.2"]),
|
|
131
131
|
"tanstack-start": new Set(["1.168.26", "1.168.49"]),
|
|
132
|
-
nextjs: new Set(["15.5.
|
|
132
|
+
nextjs: new Set(["15.5.26", "16.3.7"]),
|
|
133
133
|
});
|
|
134
134
|
|
|
135
135
|
export function classifyFrameworkVersion(
|
|
@@ -173,10 +173,7 @@ function insideAdmittedWindow(framework: AdmittedFramework, version: VersionTupl
|
|
|
173
173
|
compareVersions(version, [1, 168, 26]) >= 0 && compareVersions(version, [1, 168, 49]) <= 0
|
|
174
174
|
);
|
|
175
175
|
case "nextjs":
|
|
176
|
-
return (
|
|
177
|
-
(version[0] === 15 && version[1] === 5) ||
|
|
178
|
-
(compareVersions(version, [16, 0, 0]) >= 0 && compareVersions(version, [16, 3, 4]) <= 0)
|
|
179
|
-
);
|
|
176
|
+
return isAdmittedNextVersion(version.join("."));
|
|
180
177
|
}
|
|
181
178
|
}
|
|
182
179
|
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
export const PINNED_BUN_VERSION = "1.2.22";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* The installed Next.js release must satisfy the same window as source admission.
|
|
5
|
+
* @param {unknown} version
|
|
6
|
+
* @returns {boolean}
|
|
7
|
+
*/
|
|
8
|
+
export function isAdmittedNextVersion(version) {
|
|
9
|
+
if (typeof version !== "string") return false;
|
|
10
|
+
const match = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u.exec(version);
|
|
11
|
+
if (match === null) return false;
|
|
12
|
+
const major = Number(match[1]);
|
|
13
|
+
const minor = Number(match[2]);
|
|
14
|
+
const patch = Number(match[3]);
|
|
15
|
+
if (![major, minor, patch].every(Number.isSafeInteger)) return false;
|
|
16
|
+
return (
|
|
17
|
+
(major === 15 && minor === 5 && patch >= 26) ||
|
|
18
|
+
(major === 16 && minor === 3 && patch >= 6 && patch <= 7)
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
3
22
|
const TYPESCRIPT_BUILD_STAGE = /^tsc(?:[ \t]+(?:--noEmit|-b|--build))?$/u;
|
|
4
23
|
|
|
5
24
|
/**
|
|
@@ -24,6 +24,8 @@ export type OhmyhostApplicationBuild = Readonly<{
|
|
|
24
24
|
install: string;
|
|
25
25
|
command: string;
|
|
26
26
|
output: string;
|
|
27
|
+
/** Maximum private immutable Next.js prerender cache, in MiB; defaults to 32. */
|
|
28
|
+
ssg_cache_max_mib?: number;
|
|
27
29
|
}>;
|
|
28
30
|
export type OhmyhostFunctionsBuild = Readonly<{ install: string }>;
|
|
29
31
|
|
|
@@ -88,6 +90,9 @@ export function parseOhmyhostConfig(value: unknown): OhmyhostConfig {
|
|
|
88
90
|
install: input.build.install,
|
|
89
91
|
command: (input.build as OhmyhostApplicationBuild).command,
|
|
90
92
|
output: (input.build as OhmyhostApplicationBuild).output,
|
|
93
|
+
...((input.build as OhmyhostApplicationBuild).ssg_cache_max_mib === undefined
|
|
94
|
+
? {}
|
|
95
|
+
: { ssg_cache_max_mib: (input.build as OhmyhostApplicationBuild).ssg_cache_max_mib }),
|
|
91
96
|
}),
|
|
92
97
|
runtime: Object.freeze({
|
|
93
98
|
mode: input.runtime.mode,
|
|
@@ -450,6 +450,13 @@ export const PROBLEM_POLICY = {
|
|
|
450
450
|
"A live project connection already holds this hostname. Remove it from the project you manage with 'ohmyhost domain paid delete --project ULID --hostname HOST --yes --json', then apply it to the new project. Repeating while that connection remains cannot work; report the request_id if you cannot manage its owning project.",
|
|
451
451
|
title: "Domain hostname is already connected",
|
|
452
452
|
},
|
|
453
|
+
domain_dns_conflict: {
|
|
454
|
+
status: 409,
|
|
455
|
+
retryable: false,
|
|
456
|
+
action:
|
|
457
|
+
"Review DNS for the requested hostname and resolve the conflicting delegation or another project's managed records. Preserve mailbox MX, TXT and CAA records. Then repeat the original domain paid apply or delete with the same hostname and idempotency key; do not create another deployment or repeatedly resubmit unchanged conflicts.",
|
|
458
|
+
title: "Domain DNS records conflict",
|
|
459
|
+
},
|
|
453
460
|
data_change_blocked: {
|
|
454
461
|
status: 409,
|
|
455
462
|
retryable: true,
|
|
@@ -2560,7 +2560,7 @@ export const configureProjectDomains = <ThrowOnError extends boolean = true>(
|
|
|
2560
2560
|
/**
|
|
2561
2561
|
* Plan one Paid customer-owned hostname
|
|
2562
2562
|
*
|
|
2563
|
-
*
|
|
2563
|
+
* Plan the customer's requested hostname before or after the first Prod deployment. This read-only plan explains declaration, Cloudflare consent and activation; it does not claim the hostname, create provider resources or change DNS.
|
|
2564
2564
|
*/
|
|
2565
2565
|
export const planPaidProjectDomain = <ThrowOnError extends boolean = true>(
|
|
2566
2566
|
parameters: {
|
|
@@ -2698,7 +2698,7 @@ export const getPaidProjectDomain = <ThrowOnError extends boolean = true>(
|
|
|
2698
2698
|
/**
|
|
2699
2699
|
* Apply one Paid customer-owned hostname
|
|
2700
2700
|
*
|
|
2701
|
-
* Requires Paid access (a Stripe period or a grant) or, for a Free workspace, a project that currently shows the powered-by flag, and no expired credit-exhaustion grace. Returns paid_plan_required otherwise, or insufficient_organization_credits after seven days with no available credits, without provider mutation. Top-ups lift a credit-exhaustion block but never start or extend Paid access.
|
|
2701
|
+
* Requires Paid access (a Stripe period or a grant) or, for a Free workspace, a project that currently shows the powered-by flag, and no expired credit-exhaustion grace. Returns paid_plan_required otherwise, or insufficient_organization_credits after seven days with no available credits, without provider mutation. Top-ups lift a credit-exhaustion block but never start or extend Paid access. Without an active Prod deployment, apply declares the hostname as awaiting_deployment, enabling Cloudflare consent without provider resources, DNS changes or domain charges. After a successful Prod deployment, replay the same hostname and idempotency key to activate it. A changed request under a used key returns idempotency_key_reused (409).
|
|
2702
2702
|
*/
|
|
2703
2703
|
export const applyPaidProjectDomain = <ThrowOnError extends boolean = true>(
|
|
2704
2704
|
parameters: {
|
|
@@ -351,9 +351,13 @@ export type PaidDomainPlan = {
|
|
|
351
351
|
risks: Array<string>;
|
|
352
352
|
};
|
|
353
353
|
|
|
354
|
+
/**
|
|
355
|
+
* awaiting_deployment means the requested hostname is declared but not provisioned. Its hostname is present, suspension_reason, custom_hostname_status, ssl_status and url are null, and validation_records is empty. Authorize Cloudflare, deploy to Prod, then repeat the same apply.
|
|
356
|
+
*/
|
|
354
357
|
export type PaidDomain = {
|
|
355
358
|
status:
|
|
356
359
|
| "not_configured"
|
|
360
|
+
| "awaiting_deployment"
|
|
357
361
|
| "pending"
|
|
358
362
|
| "active"
|
|
359
363
|
| "reconciliation_required"
|
|
@@ -1112,6 +1116,7 @@ export type ProblemDetails = {
|
|
|
1112
1116
|
| "service_unavailable"
|
|
1113
1117
|
| "source_commit_not_found"
|
|
1114
1118
|
| "domain_hostname_taken"
|
|
1119
|
+
| "domain_dns_conflict"
|
|
1115
1120
|
| "data_change_blocked"
|
|
1116
1121
|
| "data_change_in_progress"
|
|
1117
1122
|
| "data_change_not_applicable"
|
|
@@ -4686,7 +4691,7 @@ export type PlanPaidProjectDomainError =
|
|
|
4686
4691
|
|
|
4687
4692
|
export type PlanPaidProjectDomainResponses = {
|
|
4688
4693
|
/**
|
|
4689
|
-
*
|
|
4694
|
+
* The requested hostname, routing target and staged provider effects.
|
|
4690
4695
|
*/
|
|
4691
4696
|
200: PaidDomainPlan;
|
|
4692
4697
|
};
|
|
@@ -4880,7 +4885,7 @@ export type ApplyPaidProjectDomainError =
|
|
|
4880
4885
|
|
|
4881
4886
|
export type ApplyPaidProjectDomainResponses = {
|
|
4882
4887
|
/**
|
|
4883
|
-
*
|
|
4888
|
+
* Declared hostname or current Cloudflare for SaaS hostname and certificate state.
|
|
4884
4889
|
*/
|
|
4885
4890
|
200: PaidDomain;
|
|
4886
4891
|
};
|