@amerged/ohmyhost-cli 0.1.32 → 0.1.34
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-EPW2O2ZL.js → chunk-SRN6L765.js} +26 -10
- 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/runtime-contract.ts +26 -2
- package/src/packages/contracts/src/framework-admission-corpus.ts +97 -0
- package/src/packages/contracts/src/framework-admission.ts +2 -2
- package/src/packages/contracts/src/framework-source-rules.ts +22 -5
- 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-SRN6L765.js";
|
|
6
6
|
import "./chunk-7D2RFLWM.js";
|
|
7
7
|
|
|
8
8
|
// apps/product-cli/dist/bin.js
|
|
@@ -34783,9 +34783,9 @@ var FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
34783
34783
|
paths: ["framework_config"],
|
|
34784
34784
|
template: `"{{path}}" does not follow the TanStack Start plugin contract: import tanstackStart from "@tanstack/react-start/plugin/vite"; on runtime edge also import cloudflare from "@cloudflare/vite-plugin" and call cloudflare({ viteEnvironment: { name: "ssr" } }) before tanstackStart(); on runtime static do not import the Cloudflare plugin. ${PUSH_AND_PLAN}`
|
|
34785
34785
|
},
|
|
34786
|
-
|
|
34786
|
+
next_tailwind_turbopack_only: {
|
|
34787
34787
|
paths: ["framework_config"],
|
|
34788
|
-
template: `"{{path}}"
|
|
34788
|
+
template: `"{{path}}" loads Tailwind CSS through the Turbopack rule "@tailwindcss/turbopack", which the Webpack build on ohmyho.st ignores, and the application root has no PostCSS configuration that Webpack reads, so the site would deploy without its Tailwind classes. Add postcss.config.mjs to the application root with export default { plugins: { "@tailwindcss/postcss": {} } } and remove the Turbopack rule. Use the package manager to add @tailwindcss/postcss to devDependencies at the same version as tailwindcss and to remove @tailwindcss/turbopack, so the lockfile records both. ${PUSH_AND_PLAN}`
|
|
34789
34789
|
},
|
|
34790
34790
|
framework_version_unsupported: {
|
|
34791
34791
|
paths: ["manifest", "lockfile"],
|
|
@@ -37142,14 +37142,25 @@ function parseProjectCreditBudget(value) {
|
|
|
37142
37142
|
return input;
|
|
37143
37143
|
}
|
|
37144
37144
|
var parseCurrentIdentity = (value) => {
|
|
37145
|
-
const input = exactRecord2(value, ["actor_id", "organization_ids"]);
|
|
37145
|
+
const input = exactRecord2(value, ["actor_id", "email", "organization_ids", "organizations"]);
|
|
37146
|
+
const email = input["email"];
|
|
37146
37147
|
const organizationIds = input["organization_ids"];
|
|
37148
|
+
const organizations = input["organizations"];
|
|
37147
37149
|
if (typeof input["actor_id"] !== "string" || input["actor_id"].length === 0 || input["actor_id"].length > 256 || [...input["actor_id"]].some((character) => {
|
|
37148
37150
|
const codePoint = character.codePointAt(0) ?? 0;
|
|
37149
37151
|
return codePoint <= 31 || codePoint === 127;
|
|
37150
|
-
}) || !Array.isArray(organizationIds) || organizationIds.some((organizationId) => !isUlid(organizationId)) || new Set(organizationIds).size !== organizationIds.length) {
|
|
37152
|
+
}) || 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
37153
|
throw new ResponseContractError();
|
|
37152
37154
|
}
|
|
37155
|
+
organizations.forEach((organization, index) => {
|
|
37156
|
+
const entry = exactRecord2(organization, ["id", "name"]);
|
|
37157
|
+
if (entry["id"] !== organizationIds[index] || !boundedString(entry["name"], 1, 128) || entry["name"].trim() !== entry["name"] || [...entry["name"]].some((character) => {
|
|
37158
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
37159
|
+
return codePoint <= 31 || codePoint === 127;
|
|
37160
|
+
})) {
|
|
37161
|
+
throw new ResponseContractError();
|
|
37162
|
+
}
|
|
37163
|
+
});
|
|
37153
37164
|
return input;
|
|
37154
37165
|
};
|
|
37155
37166
|
var parseAccountProfile = (value) => {
|
|
@@ -40628,7 +40639,7 @@ function exact3(v, keys) {
|
|
|
40628
40639
|
// apps/product-cli/package.json
|
|
40629
40640
|
var package_default = {
|
|
40630
40641
|
name: "@ohmyhost/product-cli",
|
|
40631
|
-
version: "0.1.
|
|
40642
|
+
version: "0.1.34",
|
|
40632
40643
|
private: true,
|
|
40633
40644
|
ohmyhost: {
|
|
40634
40645
|
deployment: "production",
|
|
@@ -40965,7 +40976,7 @@ var HELP_USAGE = Object.freeze({
|
|
|
40965
40976
|
"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
40977
|
"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
40978
|
"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
|
|
40979
|
+
"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
40980
|
"database compute get": "ohmyhost database compute get --project ULID [--environment dev|prod] --json",
|
|
40970
40981
|
"database write": "ohmyhost database write --project ULID --environment dev|prod --statement-file PATH --idempotency-key KEY [--parameters-json JSON] --yes --json",
|
|
40971
40982
|
"database query": "ohmyhost database query --project ULID --environment dev|prod --statement SQL [--parameters-json JSON] --json",
|
|
@@ -47191,6 +47202,8 @@ var BUILD_OUTPUTS = Object.freeze({
|
|
|
47191
47202
|
"tanstack-start": "dist/client"
|
|
47192
47203
|
});
|
|
47193
47204
|
var REQUIRED_CONFIG_PATHS = Object.freeze({ nextjs: "next.config.ts", "tanstack-start": "vite.config.ts" });
|
|
47205
|
+
var POSTCSS_CONFIG_PATH = /^(?:postcss\.config\.(?:[cm]?js|json)|\.postcssrc\.(?:js|json))$/u;
|
|
47206
|
+
var TAILWIND_TURBOPACK_LOADER = "@tailwindcss/turbopack";
|
|
47194
47207
|
var MAXIMUM_LOCKFILE_LENGTH = 5 * 1024 * 1024;
|
|
47195
47208
|
var MAXIMUM_PNPM_LOCKFILE_HEAD = 256 * 1024;
|
|
47196
47209
|
var PNPM_LOCKFILE_BODY = /^(?:packages|snapshots):/mu;
|
|
@@ -47327,7 +47340,7 @@ function repositorySourceFindings(files) {
|
|
|
47327
47340
|
versions: result.versions
|
|
47328
47341
|
});
|
|
47329
47342
|
}
|
|
47330
|
-
function nextConfigFindings(text, path2) {
|
|
47343
|
+
function nextConfigFindings(text, path2, postcss) {
|
|
47331
47344
|
const lexed = lexFrameworkConfig(text, path2);
|
|
47332
47345
|
if ("finding" in lexed)
|
|
47333
47346
|
return Object.freeze([lexed.finding]);
|
|
@@ -47337,8 +47350,8 @@ function nextConfigFindings(text, path2) {
|
|
|
47337
47350
|
findings.push(diagnostic({ code: "next_base_path_unsupported", path: path2 }));
|
|
47338
47351
|
if (hasProperty(tokens, "output", "export") || hasProperty(tokens, "output", "standalone"))
|
|
47339
47352
|
findings.push(diagnostic({ code: "next_output_unsupported", path: path2 }));
|
|
47340
|
-
if (
|
|
47341
|
-
findings.push(diagnostic({ code: "
|
|
47353
|
+
if (!postcss && tokens.some(({ kind, value }) => kind === "string" && value === TAILWIND_TURBOPACK_LOADER))
|
|
47354
|
+
findings.push(diagnostic({ code: "next_tailwind_turbopack_only", path: path2 }));
|
|
47342
47355
|
if (!hasExportDefault(tokens) && !(path2.slice(path2.lastIndexOf("/") + 1) === "next.config.js" && hasModuleExports(tokens)))
|
|
47343
47356
|
findings.push(diagnostic({ code: "framework_config_default_export_required", path: path2 }));
|
|
47344
47357
|
return Object.freeze(findings);
|
|
@@ -47509,12 +47522,15 @@ function frameworkConfigFindings(input) {
|
|
|
47509
47522
|
return [];
|
|
47510
47523
|
const { path: path2, text } = frameworkConfig;
|
|
47511
47524
|
if (framework === "nextjs")
|
|
47512
|
-
return nextConfigFindings(text, path2);
|
|
47525
|
+
return nextConfigFindings(text, path2, hasPostcssConfiguration(input));
|
|
47513
47526
|
if (framework === "vite-static")
|
|
47514
47527
|
return viteConfigFindings(text, path2);
|
|
47515
47528
|
const mode = input.configuration.runtime.mode;
|
|
47516
47529
|
return tanStackViteConfigFindings(text, path2, mode === "edge" || mode === "static" ? mode : null);
|
|
47517
47530
|
}
|
|
47531
|
+
function hasPostcssConfiguration({ files, manifest: manifest2 }) {
|
|
47532
|
+
return isRecord4(ownValue(manifest2, "postcss")) || files.some((path2) => POSTCSS_CONFIG_PATH.test(path2));
|
|
47533
|
+
}
|
|
47518
47534
|
function repositoryConfiguration(text) {
|
|
47519
47535
|
if (typeof text !== "string")
|
|
47520
47536
|
return null;
|
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":
|
|
@@ -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
|
|
|
@@ -48,6 +48,47 @@ const CORPUS_NEXT_PAGE = `export default function Home() {
|
|
|
48
48
|
return <main>Hello from ohmyho.st</main>;
|
|
49
49
|
}
|
|
50
50
|
`;
|
|
51
|
+
// The config `create-next-app@16.4.0 --yes --no-tailwind` writes: Cache Components with partial
|
|
52
|
+
// prefetching.
|
|
53
|
+
const CREATE_NEXT_APP_CONFIG = `import type { NextConfig } from "next";
|
|
54
|
+
|
|
55
|
+
const nextConfig: NextConfig = {
|
|
56
|
+
/* config options here */
|
|
57
|
+
cacheComponents: true,
|
|
58
|
+
partialPrefetching: true,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default nextConfig;
|
|
62
|
+
`;
|
|
63
|
+
// With Tailwind CSS, which --yes selects, create-next-app on its default Turbopack bundler adds this
|
|
64
|
+
// rule instead of a postcss.config.mjs; the Webpack build ignores turbopack.rules.
|
|
65
|
+
const CREATE_NEXT_APP_TAILWIND_RULE = ` turbopack: {
|
|
66
|
+
rules: {
|
|
67
|
+
"*.css": {
|
|
68
|
+
loaders: ["@tailwindcss/turbopack"],
|
|
69
|
+
as: "*.css",
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
`;
|
|
74
|
+
const CREATE_NEXT_APP_POSTCSS_CONFIG = `const config = {
|
|
75
|
+
plugins: {
|
|
76
|
+
"@tailwindcss/postcss": {},
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export default config;
|
|
81
|
+
`;
|
|
82
|
+
const CREATE_NEXT_APP_LAYOUT = `import "./globals.css";
|
|
83
|
+
|
|
84
|
+
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
|
85
|
+
return (
|
|
86
|
+
<html lang="en">
|
|
87
|
+
<body>{children}</body>
|
|
88
|
+
</html>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
`;
|
|
51
92
|
const CORPUS_TANSTACK_CONFIG = `import { tanstackStart } from "@tanstack/react-start/plugin/vite";
|
|
52
93
|
import viteReact from "@vitejs/plugin-react";
|
|
53
94
|
import { defineConfig } from "vite";
|
|
@@ -93,6 +134,14 @@ export const FRAMEWORK_ADMISSION_CONFORMANCE_CORPUS: Readonly<{
|
|
|
93
134
|
viteSource({ declared: "^8.2.0", resolved: "8.3.4" }),
|
|
94
135
|
),
|
|
95
136
|
corpusCase("TanStack Start 1.168.60 prerendered for the static runtime", tanStackSource()),
|
|
137
|
+
corpusCase(
|
|
138
|
+
"create-next-app 16.4 --yes --no-tailwind: Cache Components with partial prefetching",
|
|
139
|
+
createNextAppSource({ tailwind: false }),
|
|
140
|
+
),
|
|
141
|
+
corpusCase(
|
|
142
|
+
"create-next-app 16.4 --yes with a postcss.config.mjs added beside its Turbopack rule",
|
|
143
|
+
createNextAppSource({ tailwind: true, postcss: true }),
|
|
144
|
+
),
|
|
96
145
|
]),
|
|
97
146
|
pending: Object.freeze([
|
|
98
147
|
Object.freeze({
|
|
@@ -148,6 +197,11 @@ export const FRAMEWORK_ADMISSION_CONFORMANCE_CORPUS: Readonly<{
|
|
|
148
197
|
}),
|
|
149
198
|
{ code: "next_base_path_unsupported", path: "next.config.ts" },
|
|
150
199
|
),
|
|
200
|
+
refusedCase(
|
|
201
|
+
"create-next-app 16.4 --yes: Tailwind CSS only in a Turbopack rule",
|
|
202
|
+
createNextAppSource({ tailwind: true }),
|
|
203
|
+
{ code: "next_tailwind_turbopack_only", path: "next.config.ts" },
|
|
204
|
+
),
|
|
151
205
|
refusedCase(
|
|
152
206
|
"Next.js build script with a second step",
|
|
153
207
|
nextSource({ build: "next build && next-sitemap" }),
|
|
@@ -325,6 +379,49 @@ function nextSource(
|
|
|
325
379
|
});
|
|
326
380
|
}
|
|
327
381
|
|
|
382
|
+
/**
|
|
383
|
+
* The next.config.ts and Tailwind CSS files and packages `create-next-app@16.4.0 --yes` writes, in
|
|
384
|
+
* an App Router source with the packageManager, lockfile and ohmyhost.yaml ohmyho.st requires;
|
|
385
|
+
* `tailwind: false` is its --no-tailwind output. On Turbopack, its default bundler, it adds only the
|
|
386
|
+
* Turbopack rule for Tailwind CSS; `postcss` adds the postcss.config.mjs and @tailwindcss/postcss it
|
|
387
|
+
* writes for any other bundler.
|
|
388
|
+
*/
|
|
389
|
+
function createNextAppSource(
|
|
390
|
+
options: Readonly<{ tailwind: boolean; postcss?: boolean }>,
|
|
391
|
+
): Readonly<Record<string, string>> {
|
|
392
|
+
const [packageManager, lockfile] = CORPUS_MANAGERS.npm;
|
|
393
|
+
const runtime = { next: "16.4.0", react: "19.3.0", "react-dom": "19.3.0" };
|
|
394
|
+
const postcss = options.postcss === true;
|
|
395
|
+
return Object.freeze({
|
|
396
|
+
"ohmyhost.yaml": corpusConfiguration("npm", ".open-next/assets", "edge"),
|
|
397
|
+
"package.json": corpusJson({
|
|
398
|
+
name: "website",
|
|
399
|
+
version: "0.1.0",
|
|
400
|
+
private: true,
|
|
401
|
+
packageManager,
|
|
402
|
+
scripts: { dev: "next dev", build: "next build", start: "next start" },
|
|
403
|
+
dependencies: runtime,
|
|
404
|
+
...(options.tailwind
|
|
405
|
+
? {
|
|
406
|
+
devDependencies: {
|
|
407
|
+
...(postcss ? { "@tailwindcss/postcss": "^4" } : {}),
|
|
408
|
+
"@tailwindcss/turbopack": "^4",
|
|
409
|
+
tailwindcss: "^4",
|
|
410
|
+
},
|
|
411
|
+
}
|
|
412
|
+
: {}),
|
|
413
|
+
}),
|
|
414
|
+
[lockfile]: corpusLockfile("npm", runtime, runtime),
|
|
415
|
+
"next.config.ts": options.tailwind
|
|
416
|
+
? CREATE_NEXT_APP_CONFIG.replace("};\n", `${CREATE_NEXT_APP_TAILWIND_RULE}};\n`)
|
|
417
|
+
: CREATE_NEXT_APP_CONFIG,
|
|
418
|
+
...(postcss ? { "postcss.config.mjs": CREATE_NEXT_APP_POSTCSS_CONFIG } : {}),
|
|
419
|
+
"app/globals.css": options.tailwind ? '@import "tailwindcss";\n' : "body {\n margin: 0;\n}\n",
|
|
420
|
+
"app/layout.tsx": CREATE_NEXT_APP_LAYOUT,
|
|
421
|
+
"app/page.tsx": CORPUS_NEXT_PAGE,
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
|
|
328
425
|
function viteSource(
|
|
329
426
|
options: Readonly<{ declared?: string; resolved?: string; config?: string }> = {},
|
|
330
427
|
): Readonly<Record<string, string>> {
|
|
@@ -373,9 +373,9 @@ const FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
373
373
|
paths: ["framework_config"],
|
|
374
374
|
template: `"{{path}}" does not follow the TanStack Start plugin contract: import tanstackStart from "@tanstack/react-start/plugin/vite"; on runtime edge also import cloudflare from "@cloudflare/vite-plugin" and call cloudflare({ viteEnvironment: { name: "ssr" } }) before tanstackStart(); on runtime static do not import the Cloudflare plugin. ${PUSH_AND_PLAN}`,
|
|
375
375
|
},
|
|
376
|
-
|
|
376
|
+
next_tailwind_turbopack_only: {
|
|
377
377
|
paths: ["framework_config"],
|
|
378
|
-
template: `"{{path}}"
|
|
378
|
+
template: `"{{path}}" loads Tailwind CSS through the Turbopack rule "@tailwindcss/turbopack", which the Webpack build on ohmyho.st ignores, and the application root has no PostCSS configuration that Webpack reads, so the site would deploy without its Tailwind classes. Add postcss.config.mjs to the application root with export default { plugins: { "@tailwindcss/postcss": {} } } and remove the Turbopack rule. Use the package manager to add @tailwindcss/postcss to devDependencies at the same version as tailwindcss and to remove @tailwindcss/turbopack, so the lockfile records both. ${PUSH_AND_PLAN}`,
|
|
379
379
|
},
|
|
380
380
|
framework_version_unsupported: {
|
|
381
381
|
paths: ["manifest", "lockfile"],
|
|
@@ -119,6 +119,10 @@ const BUILD_OUTPUTS: Readonly<Partial<Record<FrameworkSourceFramework, string>>>
|
|
|
119
119
|
});
|
|
120
120
|
const REQUIRED_CONFIG_PATHS: Readonly<Partial<Record<FrameworkSourceFramework, string>>> =
|
|
121
121
|
Object.freeze({ nextjs: "next.config.ts", "tanstack-start": "vite.config.ts" });
|
|
122
|
+
// The PostCSS configuration the Next.js Webpack build reads: package.json "postcss" or one of these
|
|
123
|
+
// files at the application root. It never reads a TypeScript one such as postcss.config.ts.
|
|
124
|
+
const POSTCSS_CONFIG_PATH = /^(?:postcss\.config\.(?:[cm]?js|json)|\.postcssrc\.(?:js|json))$/u;
|
|
125
|
+
const TAILWIND_TURBOPACK_LOADER = "@tailwindcss/turbopack";
|
|
122
126
|
const MAXIMUM_LOCKFILE_LENGTH = 5 * 1024 * 1024;
|
|
123
127
|
const MAXIMUM_PNPM_LOCKFILE_HEAD = 256 * 1024;
|
|
124
128
|
const PNPM_LOCKFILE_BODY = /^(?:packages|snapshots):/mu;
|
|
@@ -327,12 +331,15 @@ export function repositorySourceFindings(
|
|
|
327
331
|
|
|
328
332
|
/**
|
|
329
333
|
* The Next.js config rules: inspection size, comment and string syntax, the root origin
|
|
330
|
-
* (basePath, assetPrefix), output,
|
|
331
|
-
* assign module.exports instead.
|
|
334
|
+
* (basePath, assetPrefix), output, the "@tailwindcss/turbopack" loader and the default export;
|
|
335
|
+
* next.config.js may assign module.exports instead. ohmyho.st builds with Webpack, which ignores
|
|
336
|
+
* Turbopack rules and applies Tailwind CSS only through PostCSS, so that loader is refused unless
|
|
337
|
+
* `postcss` reports a PostCSS configuration Webpack reads at the application root.
|
|
332
338
|
*/
|
|
333
339
|
export function nextConfigFindings(
|
|
334
340
|
text: string,
|
|
335
341
|
path: string,
|
|
342
|
+
postcss: boolean,
|
|
336
343
|
): readonly FrameworkConversionDiagnostic[] {
|
|
337
344
|
const lexed = lexFrameworkConfig(text, path);
|
|
338
345
|
if ("finding" in lexed) return Object.freeze([lexed.finding]);
|
|
@@ -342,8 +349,11 @@ export function nextConfigFindings(
|
|
|
342
349
|
findings.push(diagnostic({ code: "next_base_path_unsupported", path }));
|
|
343
350
|
if (hasProperty(tokens, "output", "export") || hasProperty(tokens, "output", "standalone"))
|
|
344
351
|
findings.push(diagnostic({ code: "next_output_unsupported", path }));
|
|
345
|
-
if (
|
|
346
|
-
|
|
352
|
+
if (
|
|
353
|
+
!postcss &&
|
|
354
|
+
tokens.some(({ kind, value }) => kind === "string" && value === TAILWIND_TURBOPACK_LOADER)
|
|
355
|
+
)
|
|
356
|
+
findings.push(diagnostic({ code: "next_tailwind_turbopack_only", path }));
|
|
347
357
|
if (
|
|
348
358
|
!hasExportDefault(tokens) &&
|
|
349
359
|
!(path.slice(path.lastIndexOf("/") + 1) === "next.config.js" && hasModuleExports(tokens))
|
|
@@ -619,12 +629,19 @@ function frameworkConfigFindings(
|
|
|
619
629
|
const { frameworkConfig, framework } = input;
|
|
620
630
|
if (frameworkConfig === null || framework === "functions") return [];
|
|
621
631
|
const { path, text } = frameworkConfig;
|
|
622
|
-
if (framework === "nextjs") return nextConfigFindings(text, path);
|
|
632
|
+
if (framework === "nextjs") return nextConfigFindings(text, path, hasPostcssConfiguration(input));
|
|
623
633
|
if (framework === "vite-static") return viteConfigFindings(text, path);
|
|
624
634
|
const mode = input.configuration.runtime.mode;
|
|
625
635
|
return tanStackViteConfigFindings(text, path, mode === "edge" || mode === "static" ? mode : null);
|
|
626
636
|
}
|
|
627
637
|
|
|
638
|
+
/** Whether package.json or a file at the application root configures PostCSS for Webpack. */
|
|
639
|
+
function hasPostcssConfiguration({ files, manifest }: FrameworkSourceRuleInput): boolean {
|
|
640
|
+
return (
|
|
641
|
+
isRecord(ownValue(manifest, "postcss")) || files.some((path) => POSTCSS_CONFIG_PATH.test(path))
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
|
|
628
645
|
function repositoryConfiguration(text: string | null | undefined): OhmyhostConfig | null {
|
|
629
646
|
if (typeof text !== "string") return null;
|
|
630
647
|
try {
|
|
@@ -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 = {
|