@solcreek/cli 0.4.26 → 0.4.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.
@@ -13,7 +13,7 @@ import { prepareDeployBundle } from "../utils/prepare-bundle.js";
13
13
  import { BuildLogEmitter } from "../utils/build-log.js";
14
14
  import { isTTY, jsonOutput, resolveJsonMode, globalArgs, shouldAutoConfirm, AUTH_BREADCRUMBS, NO_PROJECT_BREADCRUMBS } from "../utils/output.js";
15
15
  import { ensureTosAccepted } from "../utils/tos.js";
16
- import { hasAdapterOutput } from "../utils/nextjs.js";
16
+ import { hasAdapterOutput, readAdapterCompat } from "../utils/nextjs.js";
17
17
  import { isRepoUrl, parseRepoUrl, validateRepoUrl, validateSubpath, RepoUrlError } from "../utils/repo-url.js";
18
18
  import { checkGitInstalled, cloneRepo, detectPackageManager, installDependencies, cleanupDir as cleanupCloneDir, GitCloneError } from "../utils/git-clone.js";
19
19
  import { CreekdClient, getCreekdUrl } from "../utils/creekd-client.js";
@@ -991,6 +991,14 @@ async function deploySandbox(cwd, skipBuild, jsonMode = false, resolved, tos) {
991
991
  section("Deploy");
992
992
  consola.start(" Deploying to edge...");
993
993
  }
994
+ // An adapter build records the exact compat it was built against in its
995
+ // manifest; deploy with that so the worker validates at upload (e.g.
996
+ // node:http server modules need nodejs_compat + compatibility_date
997
+ // >= 2025-09-01). Fall back to the resolved config for non-adapter builds.
998
+ const sandboxAdapterCompat = readAdapterCompat(cwd);
999
+ const sandboxCompatDate = sandboxAdapterCompat?.compatibilityDate ?? resolved?.compatibilityDate;
1000
+ const sandboxCompatFlags = sandboxAdapterCompat?.compatibilityFlags ??
1001
+ (resolved && resolved.compatibilityFlags.length > 0 ? resolved.compatibilityFlags : undefined);
994
1002
  try {
995
1003
  const result = await sandboxDeploy({
996
1004
  manifest: {
@@ -1006,11 +1014,9 @@ async function deploySandbox(cwd, skipBuild, jsonMode = false, resolved, tos) {
1006
1014
  ...(resolved
1007
1015
  ? { bindings: resolvedConfigToBindingRequirements(resolved) }
1008
1016
  : {}),
1009
- ...(resolved?.compatibilityDate
1010
- ? { compatibilityDate: resolved.compatibilityDate }
1011
- : {}),
1012
- ...(resolved && resolved.compatibilityFlags.length > 0
1013
- ? { compatibilityFlags: resolved.compatibilityFlags }
1017
+ ...(sandboxCompatDate ? { compatibilityDate: sandboxCompatDate } : {}),
1018
+ ...(sandboxCompatFlags && sandboxCompatFlags.length > 0
1019
+ ? { compatibilityFlags: sandboxCompatFlags }
1014
1020
  : {}),
1015
1021
  }, { tos });
1016
1022
  const status = await pollSandboxStatus(result.statusUrl);
@@ -1234,6 +1240,16 @@ async function deployAuthenticated(cwd, resolved, token, skipBuild, jsonMode = f
1234
1240
  buildLog.info("bundle", `${fileList.length} assets (${assetSummary(fileList)})`);
1235
1241
  consola.start(" Uploading bundle...");
1236
1242
  const effectiveHasWorker = serverFiles !== undefined;
1243
+ // Prefer the compat the adapter built the worker against (recorded in its
1244
+ // manifest) so the deploy matches the build — node:http server modules
1245
+ // need nodejs_compat + compatibility_date >= 2025-09-01. Falls back to the
1246
+ // resolved config + a framework-aware default for non-adapter builds.
1247
+ const prodAdapterCompat = readAdapterCompat(cwd);
1248
+ const prodCompatDate = prodAdapterCompat?.compatibilityDate ?? resolved.compatibilityDate;
1249
+ const prodCompatFlags = prodAdapterCompat?.compatibilityFlags ??
1250
+ (hasAdapterOutput(cwd)
1251
+ ? ["nodejs_compat"]
1252
+ : ["nodejs_compat", ...resolved.compatibilityFlags.filter((f) => f !== "nodejs_compat")]);
1237
1253
  const bundle = {
1238
1254
  manifest: {
1239
1255
  assets: fileList,
@@ -1249,15 +1265,8 @@ async function deployAuthenticated(cwd, resolved, token, skipBuild, jsonMode = f
1249
1265
  bindings: resolvedConfigToBindingRequirements(resolved),
1250
1266
  // Pass through wrangler vars and compat settings
1251
1267
  ...(Object.keys(resolved.vars).length > 0 ? { vars: resolved.vars } : {}),
1252
- ...(resolved.compatibilityDate ? { compatibilityDate: resolved.compatibilityDate } : {}),
1253
- // nodejs_compat required for Creek runtime (AsyncLocalStorage).
1254
- // Adapter path uses nodejs_compat_v2 for full Node.js APIs.
1255
- ...(hasAdapterOutput(cwd)
1256
- ? { compatibilityFlags: ["nodejs_compat_v2"] }
1257
- : { compatibilityFlags: [
1258
- "nodejs_compat",
1259
- ...resolved.compatibilityFlags.filter((f) => f !== "nodejs_compat"),
1260
- ] }),
1268
+ ...(prodCompatDate ? { compatibilityDate: prodCompatDate } : {}),
1269
+ compatibilityFlags: prodCompatFlags,
1261
1270
  ...(resolved.cron.length > 0 ? { cron: resolved.cron } : {}),
1262
1271
  ...(resolved.queue ? { queue: true } : {}),
1263
1272
  };
@@ -26,6 +26,18 @@ export declare function getNextVersion(cwd: string): string | null;
26
26
  export declare function buildNextjs(cwd: string, isMonorepo: boolean, projectName?: string): void;
27
27
  /** Check if the adapter output exists (vs legacy opennext output). */
28
28
  export declare function hasAdapterOutput(cwd: string): boolean;
29
+ /**
30
+ * Read the compat settings the adapter built the worker with from
31
+ * `.creek/adapter-output/manifest.json`. The worker is validated at upload
32
+ * against the date/flags it ships with (e.g. node:http server modules need
33
+ * `nodejs_compat` + compatibility_date >= 2025-09-01), so the deploy must
34
+ * use exactly what the adapter built against rather than a hardcoded default
35
+ * that can drift. Returns null when absent/unparseable (caller falls back).
36
+ */
37
+ export declare function readAdapterCompat(cwd: string): {
38
+ compatibilityDate?: string;
39
+ compatibilityFlags?: string[];
40
+ } | null;
29
41
  /**
30
42
  * Patch the bundled worker to fix opennext's dynamic require issues.
31
43
  *
@@ -33,6 +45,22 @@ export declare function hasAdapterOutput(cwd: string): boolean;
33
45
  * the Creek adapter handles middleware via typed AdapterOutputs.
34
46
  */
35
47
  export declare function patchBundledWorker(bundleDir: string, openNextDir: string): void;
48
+ /**
49
+ * Ensure @prisma/adapter-d1 is resolvable at build time for the zero-change
50
+ * Prisma-on-D1 swap. adapter-creek aliases `@prisma/adapter-better-sqlite3` to
51
+ * a PrismaD1-backed shim that imports `@prisma/adapter-d1`; that package is an
52
+ * OPTIONAL peer of the adapter (not shipped to non-Prisma projects), so it is
53
+ * lazily installed into .creek only when the project actually uses the
54
+ * better-sqlite3 Prisma adapter. Installed matching the project's Prisma
55
+ * version — the adapter packages release in lockstep with @prisma/client, so a
56
+ * matching driver-adapter interface avoids subtle version skew.
57
+ *
58
+ * No-op unless @prisma/adapter-better-sqlite3 is present, or if adapter-d1 is
59
+ * already resolvable (project dep or a prior .creek install).
60
+ *
61
+ * Exported for tests.
62
+ */
63
+ export declare function ensurePrismaD1(cwd: string): void;
36
64
  /**
37
65
  * Fix the standalone output path for monorepo builds.
38
66
  *
@@ -128,6 +128,7 @@ export function buildNextjs(cwd, isMonorepo, projectName) {
128
128
  if (version && semverGte(version, "16.2.3")) {
129
129
  const adapterPath = ensureAdapter(cwd);
130
130
  if (adapterPath) {
131
+ ensurePrismaD1(cwd);
131
132
  buildWithAdapter(cwd, adapterPath);
132
133
  return;
133
134
  }
@@ -142,6 +143,31 @@ export function buildNextjs(cwd, isMonorepo, projectName) {
142
143
  export function hasAdapterOutput(cwd) {
143
144
  return existsSync(join(cwd, ".creek/adapter-output/manifest.json"));
144
145
  }
146
+ /**
147
+ * Read the compat settings the adapter built the worker with from
148
+ * `.creek/adapter-output/manifest.json`. The worker is validated at upload
149
+ * against the date/flags it ships with (e.g. node:http server modules need
150
+ * `nodejs_compat` + compatibility_date >= 2025-09-01), so the deploy must
151
+ * use exactly what the adapter built against rather than a hardcoded default
152
+ * that can drift. Returns null when absent/unparseable (caller falls back).
153
+ */
154
+ export function readAdapterCompat(cwd) {
155
+ const manifestPath = join(cwd, ".creek/adapter-output/manifest.json");
156
+ if (!existsSync(manifestPath))
157
+ return null;
158
+ try {
159
+ const m = JSON.parse(readFileSync(manifestPath, "utf-8"));
160
+ const out = {};
161
+ if (typeof m.compatibilityDate === "string")
162
+ out.compatibilityDate = m.compatibilityDate;
163
+ if (Array.isArray(m.compatibilityFlags))
164
+ out.compatibilityFlags = m.compatibilityFlags;
165
+ return out;
166
+ }
167
+ catch {
168
+ return null;
169
+ }
170
+ }
145
171
  /**
146
172
  * Patch the bundled worker to fix opennext's dynamic require issues.
147
173
  *
@@ -180,6 +206,10 @@ const OPENNEXT_PKG = "@opennextjs/cloudflare";
180
206
  const OPENNEXT_VERSION = "^1.18.0";
181
207
  const ADAPTER_PKG = "@solcreek/adapter-creek";
182
208
  const ADAPTER_VERSION = "^0.2.2";
209
+ // Zero-change Prisma-on-D1: the adapter's build-time swap targets this
210
+ // adapter and imports @prisma/adapter-d1 (an optional peer it doesn't ship).
211
+ const PRISMA_BSQLITE_PKG = "@prisma/adapter-better-sqlite3";
212
+ const PRISMA_D1_PKG = "@prisma/adapter-d1";
183
213
  // Adapter < 0.2.2 resolves its dependencies against paths that don't exist
184
214
  // under the .creek lazy install (0.2.0: the cache handler; 0.2.1: the
185
215
  // wrangler bin) — npm hoists them to the top of the tree, so the adapter's
@@ -258,6 +288,56 @@ function ensureAdapter(cwd) {
258
288
  consola.success(` ${ADAPTER_PKG} installed`);
259
289
  return resolved;
260
290
  }
291
+ /**
292
+ * Ensure @prisma/adapter-d1 is resolvable at build time for the zero-change
293
+ * Prisma-on-D1 swap. adapter-creek aliases `@prisma/adapter-better-sqlite3` to
294
+ * a PrismaD1-backed shim that imports `@prisma/adapter-d1`; that package is an
295
+ * OPTIONAL peer of the adapter (not shipped to non-Prisma projects), so it is
296
+ * lazily installed into .creek only when the project actually uses the
297
+ * better-sqlite3 Prisma adapter. Installed matching the project's Prisma
298
+ * version — the adapter packages release in lockstep with @prisma/client, so a
299
+ * matching driver-adapter interface avoids subtle version skew.
300
+ *
301
+ * No-op unless @prisma/adapter-better-sqlite3 is present, or if adapter-d1 is
302
+ * already resolvable (project dep or a prior .creek install).
303
+ *
304
+ * Exported for tests.
305
+ */
306
+ export function ensurePrismaD1(cwd) {
307
+ const projectRequire = createRequire(join(cwd, "noop.js"));
308
+ try {
309
+ projectRequire.resolve(PRISMA_BSQLITE_PKG);
310
+ }
311
+ catch {
312
+ return; // Not a Prisma-on-D1 (better-sqlite3 adapter) project.
313
+ }
314
+ // createRequire from .creek walks up into the project's node_modules too, so
315
+ // this single check covers both a prior .creek install and a project dep.
316
+ const creekDir = join(cwd, CREEK_DIR);
317
+ try {
318
+ createRequire(join(creekDir, "noop.js")).resolve(PRISMA_D1_PKG);
319
+ return; // Already available.
320
+ }
321
+ catch {
322
+ // Fall through to install.
323
+ }
324
+ let version = "latest";
325
+ try {
326
+ const clientPkg = JSON.parse(readFileSync(projectRequire.resolve("@prisma/client/package.json"), "utf-8"));
327
+ if (clientPkg.version)
328
+ version = clientPkg.version;
329
+ }
330
+ catch {
331
+ // No @prisma/client version readable — fall back to latest.
332
+ }
333
+ consola.start(` Installing ${PRISMA_D1_PKG}@${version} (Prisma on D1)...`);
334
+ if (installCreekDep(creekDir, PRISMA_D1_PKG, version)) {
335
+ consola.success(` ${PRISMA_D1_PKG} installed`);
336
+ }
337
+ else {
338
+ consola.warn(` Could not install ${PRISMA_D1_PKG} — Prisma build may fail`);
339
+ }
340
+ }
261
341
  /**
262
342
  * Ensure @opennextjs/cloudflare is available in .creek/node_modules.
263
343
  * Returns the path to the opennextjs-cloudflare CLI binary.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solcreek/cli",
3
- "version": "0.4.26",
3
+ "version": "0.4.28",
4
4
  "description": "CLI for the Creek deployment platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -44,6 +44,7 @@
44
44
  "hono": "^4.7.4",
45
45
  "jsdom": "^29.0.1",
46
46
  "miniflare": "^4.20260317.3",
47
+ "msw": "^2.12.14",
47
48
  "react": "^19.2.4",
48
49
  "react-dom": "^19.2.4",
49
50
  "typescript": "^5.8.2",