dineway 0.1.35 → 0.1.36

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.
Files changed (52) hide show
  1. package/README.md +15 -3
  2. package/dist/api/route-utils.d.mts +2 -2
  3. package/dist/api/schemas/index.d.mts +1 -1
  4. package/dist/{api-Ow6RbraA.mjs → api-K0U9SYx7.mjs} +1 -1
  5. package/dist/astro/index.d.mts +2 -2
  6. package/dist/astro/index.mjs +1 -1
  7. package/dist/astro/middleware/auth.d.mts +2 -2
  8. package/dist/astro/middleware/seed.mjs +1 -1
  9. package/dist/astro/middleware.mjs +4 -4
  10. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +1 -1
  11. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +1 -1
  12. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +1 -1
  13. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +1 -1
  14. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +1 -1
  15. package/dist/astro/routes/api/admin/plugins/index.mjs +1 -1
  16. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +1 -1
  17. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +1 -1
  18. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +1 -1
  19. package/dist/astro/routes/api/admin/plugins/updates.mjs +1 -1
  20. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +1 -1
  21. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +1 -1
  22. package/dist/astro/routes/api/auth/dev-bypass.mjs +1 -1
  23. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +1 -1
  24. package/dist/astro/routes/api/health.mjs +1 -1
  25. package/dist/astro/routes/api/manifest.mjs +1 -1
  26. package/dist/astro/routes/api/mcp.mjs +1 -1
  27. package/dist/astro/routes/api/openapi.json.mjs +1 -1
  28. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +1 -1
  29. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +1 -1
  30. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +1 -1
  31. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +1 -1
  32. package/dist/astro/routes/api/schema/collections/index.mjs +1 -1
  33. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +1 -1
  34. package/dist/astro/routes/api/schema/orphans/index.mjs +1 -1
  35. package/dist/astro/routes/api/setup/dev-bypass.mjs +1 -1
  36. package/dist/astro/routes/api/setup/index.mjs +1 -1
  37. package/dist/astro/routes/api/well-known/auth.mjs +1 -1
  38. package/dist/astro/types.d.mts +2 -2
  39. package/dist/{bylines-CtD_p_1z.d.mts → bylines-C8EfvtqH.d.mts} +19 -19
  40. package/dist/cli/index.mjs +216 -27
  41. package/dist/db/index.mjs +1 -1
  42. package/dist/index.d.mts +2 -2
  43. package/dist/index.mjs +3 -3
  44. package/dist/media/local-runtime.d.mts +2 -2
  45. package/dist/plugins/adapt-sandbox-entry.d.mts +2 -2
  46. package/dist/{preview-5HuX6fjF.mjs → preview-BhgxNRWI.mjs} +1 -1
  47. package/dist/{runner-lqEiJbO-.mjs → runner-S3smkgdc.mjs} +15 -2
  48. package/dist/{runtime-CP8eY2L-.d.mts → runtime-BM9sqnzO.d.mts} +2 -2
  49. package/dist/runtime.d.mts +2 -2
  50. package/dist/version-BCYrkQqz.mjs +6 -0
  51. package/package.json +1 -1
  52. package/dist/version-q9Wd8cwL.mjs +0 -6
@@ -2,7 +2,7 @@
2
2
  import { t as __exportAll } from "../chunk-ClPoSABd.mjs";
3
3
  import { n as createDatabase } from "../connection-BCNICDWN.mjs";
4
4
  import { c as listTablesLike } from "../dialect-helpers-TkdbkFad.mjs";
5
- import { r as runMigrations, t as getMigrationStatus } from "../runner-lqEiJbO-.mjs";
5
+ import { i as runMigrations, n as getMigrationStatus, t as getMigrationFingerprint } from "../runner-S3smkgdc.mjs";
6
6
  import { r as isI18nEnabled } from "../config-XW5tMrH8.mjs";
7
7
  import { n as slugify } from "../slugify-BzGxlOFx.mjs";
8
8
  import { t as ContentRepository } from "../content-DvpMad_N.mjs";
@@ -27,9 +27,9 @@ import { createHeaderAwareFetch, customHeadersInterceptor, isRedirectResponse, r
27
27
  import { o as convertDataForRead } from "../transport-B7kO-4ee.mjs";
28
28
  import { DinewayClient } from "../client/index.mjs";
29
29
  import { LocalStorage } from "../storage/local.mjs";
30
+ import { createHash } from "node:crypto";
30
31
  import { imageSize } from "image-size";
31
32
  import { createGzipDecoder, unpackTar } from "modern-tar";
32
- import { createHash } from "node:crypto";
33
33
  import { createReadStream, createWriteStream, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
34
34
  import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
35
35
  import { defineCommand, runCommand, runMain } from "citty";
@@ -190,7 +190,7 @@ function removeMarketplaceCredential(registryUrl) {
190
190
  //#region src/cli/project-env.ts
191
191
  const DEFAULT_DINEWAY_URL = "http://localhost:4321";
192
192
  const ENV_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
193
- const LINE_SPLIT_PATTERN = /\r?\n/;
193
+ const LINE_SPLIT_PATTERN$1 = /\r?\n/;
194
194
  const NEWLINE_PATTERN = /\r?\n/g;
195
195
  function parseDotenvValue(value) {
196
196
  const trimmed = value.trim();
@@ -199,7 +199,7 @@ function parseDotenvValue(value) {
199
199
  }
200
200
  function parseDotenv(text) {
201
201
  const env = {};
202
- for (const line of text.split(LINE_SPLIT_PATTERN)) {
202
+ for (const line of text.split(LINE_SPLIT_PATTERN$1)) {
203
203
  const trimmed = line.trim();
204
204
  if (!trimmed || trimmed.startsWith("#")) continue;
205
205
  const normalized = trimmed.startsWith("export ") ? trimmed.slice(7).trim() : trimmed;
@@ -233,7 +233,7 @@ function formatEnvValue(value) {
233
233
  async function upsertProjectEnv(cwd, values) {
234
234
  const envPath = join(cwd, ".env");
235
235
  const existing = await readFile(envPath, "utf-8").catch(() => "");
236
- const lines = existing ? existing.split(LINE_SPLIT_PATTERN) : [];
236
+ const lines = existing ? existing.split(LINE_SPLIT_PATTERN$1) : [];
237
237
  const seen = /* @__PURE__ */ new Set();
238
238
  const nextLines = lines.map((line) => {
239
239
  const trimmed = line.trim();
@@ -255,7 +255,7 @@ async function upsertProjectEnv(cwd, values) {
255
255
  async function ensureProjectGitignoreEntry(cwd, entry) {
256
256
  const gitignorePath = join(cwd, ".gitignore");
257
257
  const existing = await readFile(gitignorePath, "utf-8").catch(() => "");
258
- if (existing.split(LINE_SPLIT_PATTERN).map((line) => line.trim()).includes(entry)) return;
258
+ if (existing.split(LINE_SPLIT_PATTERN$1).map((line) => line.trim()).includes(entry)) return;
259
259
  await writeFile(gitignorePath, `${existing}${existing && !existing.endsWith("\n") ? "\n" : ""}${entry}\n`, "utf-8");
260
260
  }
261
261
 
@@ -1665,6 +1665,7 @@ const DATABASE_ENV_VAR_NAMES = ["DINEWAY_DATABASE_URL", "DINEWAY_DATABASE_AUTH_T
1665
1665
  const POLL_INTERVAL_MS$1 = 5e3;
1666
1666
  const POLL_TIMEOUT_MS$1 = 3e5;
1667
1667
  const DIRECT_UPLOAD_CONCURRENCY = 8;
1668
+ const FILE_HASH_CONCURRENCY = 8;
1668
1669
  const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
1669
1670
  const PLACE_ID_PATTERN = /^[A-Za-z0-9_-]{10,}$/;
1670
1671
  const SLUG_SEPARATOR_PATTERN = /[^a-z0-9]+/g;
@@ -1675,6 +1676,10 @@ const LOCATION_PARTS_PATTERN = /[,;|/]+|\s+-\s+/u;
1675
1676
  const JWT_PATTERN = /[A-Za-z0-9_-]{32,}\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}/g;
1676
1677
  const TOKEN_ASSIGNMENT_PATTERN = /(DINEWAY_DATABASE_AUTH_TOKEN|DATABASE_AUTH_TOKEN|AUTH_TOKEN)=\S+/gi;
1677
1678
  const TRAILING_SLASH_PATTERN = /\/$/;
1679
+ const LEADING_SLASHES_PATTERN = /^\/+/;
1680
+ const TRAILING_SLASHES_PATTERN = /\/+$/;
1681
+ const REGEXP_ESCAPE_PATTERN = /[|\\{}()[\]^$+?.]/g;
1682
+ const LINE_SPLIT_PATTERN = /\r?\n/;
1678
1683
  const BACKSLASH_PATTERN = /\\/g;
1679
1684
  const SHADOW_EMAIL_PATTERN = /^shadow_[a-f0-9]{16}@dineway\.ai$/i;
1680
1685
  const FOOD_TYPES = new Set([
@@ -1689,6 +1694,8 @@ const EXCLUDE_PATTERNS = [
1689
1694
  "node_modules",
1690
1695
  ".git",
1691
1696
  ".next",
1697
+ ".astro",
1698
+ ".plan",
1692
1699
  ".env",
1693
1700
  ".env.local",
1694
1701
  "dist",
@@ -1710,7 +1717,11 @@ const EXCLUDE_PATTERNS = [
1710
1717
  ".turbo",
1711
1718
  ".cache",
1712
1719
  "skills",
1713
- "coverage"
1720
+ "coverage",
1721
+ "uploads",
1722
+ "data.db",
1723
+ "data.db-shm",
1724
+ "data.db-wal"
1714
1725
  ];
1715
1726
  var ForgewayApiError = class extends Error {
1716
1727
  constructor(message, status) {
@@ -1746,6 +1757,39 @@ function getEnv(name) {
1746
1757
  const value = process.env[name];
1747
1758
  return value && value.trim() ? value.trim() : void 0;
1748
1759
  }
1760
+ function isVerboseDeploy(options) {
1761
+ return options?.verbose === true || getEnv("DINEWAY_DEPLOY_VERBOSE") === "1";
1762
+ }
1763
+ function formatDuration(ms) {
1764
+ if (ms < 1e3) return `${ms}ms`;
1765
+ return `${Math.round(ms / 100) / 10}s`;
1766
+ }
1767
+ function formatBytes$1(bytes) {
1768
+ if (bytes < 1024) return `${bytes} B`;
1769
+ const units = [
1770
+ "KB",
1771
+ "MB",
1772
+ "GB"
1773
+ ];
1774
+ let value = bytes / 1024;
1775
+ for (let index = 0; index < units.length; index++) {
1776
+ const unit = units[index];
1777
+ if (value < 1024 || index === units.length - 1) return `${value.toFixed(value >= 10 ? 0 : 1)} ${unit}`;
1778
+ value /= 1024;
1779
+ }
1780
+ return `${bytes} B`;
1781
+ }
1782
+ function deploymentFileSize(files) {
1783
+ return files.reduce((total, file) => total + file.size, 0);
1784
+ }
1785
+ function formatSeedSummary(seed) {
1786
+ if (!seed) return "no seed";
1787
+ return [
1788
+ `collections ${seed.collections.created}/${seed.collections.skipped}/${seed.collections.updated}`,
1789
+ `content ${seed.content.created}/${seed.content.skipped}/${seed.content.updated}`,
1790
+ `media ${seed.media.created}/${seed.media.skipped}`
1791
+ ].join(", ");
1792
+ }
1749
1793
  async function readJsonResponse(response) {
1750
1794
  return await response.json().catch(() => null);
1751
1795
  }
@@ -2422,20 +2466,52 @@ function redactDatabaseOutput(value, secrets) {
2422
2466
  for (const secret of secrets) if (secret.length > 0) redacted = redacted.split(secret).join("[redacted]");
2423
2467
  return redacted.replace(JWT_PATTERN, "[redacted-token]").replace(TOKEN_ASSIGNMENT_PATTERN, "$1=[redacted]");
2424
2468
  }
2469
+ async function hashFileSha256(filePath) {
2470
+ const hash = createHash("sha256");
2471
+ for await (const chunk of createReadStream(filePath)) hash.update(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
2472
+ return `sha256:${hash.digest("hex")}`;
2473
+ }
2474
+ async function buildDinewayInitializationFingerprint(seedPath) {
2475
+ const migration = getMigrationFingerprint();
2476
+ return {
2477
+ version: 1,
2478
+ migrationHash: migration.migrationHash,
2479
+ migrationCount: migration.migrationCount,
2480
+ seedHash: seedPath ? await hashFileSha256(seedPath) : null
2481
+ };
2482
+ }
2483
+ function initializationFingerprintsMatch(left, right) {
2484
+ return left?.version === right.version && left.migrationHash === right.migrationHash && left.migrationCount === right.migrationCount && left.seedHash === right.seedHash;
2485
+ }
2486
+ function localDatabaseInitializationMatches(metadata, siteId, databaseId, fingerprint) {
2487
+ return metadata?.status === "succeeded" && metadata.siteId === siteId && metadata.databaseId === databaseId && initializationFingerprintsMatch(metadata.fingerprint, fingerprint);
2488
+ }
2489
+ async function readLocalDatabaseInitializationMetadata(cwd) {
2490
+ const pkg = await readDeployPackageJson(cwd).catch(() => null);
2491
+ if (!pkg) return void 0;
2492
+ return getSavedForgewayMetadata(pkg).databaseInitialization;
2493
+ }
2494
+ async function writeLocalDatabaseInitializationMetadata(cwd, metadata) {
2495
+ await writeForgewayDeployMetadata(cwd, { databaseInitialization: {
2496
+ ...metadata,
2497
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2498
+ } });
2499
+ }
2425
2500
  async function runDinewayInitialization(options) {
2426
2501
  const db = createDatabase({
2427
2502
  url: options.credentials.databaseUrl,
2428
2503
  authToken: options.credentials.authToken
2429
2504
  });
2430
2505
  try {
2431
- await runMigrations(db);
2506
+ const migrations = await runMigrations(db);
2507
+ let seedResult = null;
2432
2508
  if (options.seedPath) {
2433
2509
  const seed = JSON.parse(await readFile(options.seedPath, "utf-8"));
2434
2510
  const validation = validateSeed(seed);
2435
2511
  if (!validation.valid) throw new Error(`Seed validation failed: ${validation.errors.join("; ")}`);
2436
2512
  const uploadsDir = resolve(options.cwd, "uploads");
2437
2513
  await mkdir(uploadsDir, { recursive: true });
2438
- await applySeed(db, seed, {
2514
+ seedResult = await applySeed(db, seed, {
2439
2515
  includeContent: true,
2440
2516
  onConflict: "skip",
2441
2517
  storage: new LocalStorage({
@@ -2444,6 +2520,10 @@ async function runDinewayInitialization(options) {
2444
2520
  })
2445
2521
  });
2446
2522
  }
2523
+ return {
2524
+ migrations,
2525
+ seed: seedResult
2526
+ };
2447
2527
  } catch (error) {
2448
2528
  const message = error instanceof Error ? error.message : String(error);
2449
2529
  throw new Error(redactDatabaseOutput(message, [options.credentials.authToken, options.credentials.databaseUrl]), { cause: error });
@@ -2474,25 +2554,75 @@ async function recordSiteDatabaseInitialization(context, siteId, databaseId, sta
2474
2554
  });
2475
2555
  }
2476
2556
  async function initializeSiteDatabaseBeforeDeploy(options) {
2557
+ const fingerprint = await buildDinewayInitializationFingerprint(options.seedPath);
2558
+ const bindStart = Date.now();
2477
2559
  const databaseId = (await bindSiteDatabase(options.context, options.siteId, options.database, options.deps)).binding.database.id;
2560
+ if (options.verbose) consola.info(`Database bound in ${formatDuration(Date.now() - bindStart)}`);
2561
+ const localInitialization = await readLocalDatabaseInitializationMetadata(options.cwd);
2562
+ if (!options.force && localDatabaseInitializationMatches(localInitialization, options.siteId, databaseId, fingerprint)) return {
2563
+ status: "skipped",
2564
+ databaseId,
2565
+ fingerprint
2566
+ };
2567
+ const revealStart = Date.now();
2478
2568
  const credentials = await revealDatabaseRuntimeCredentials(options.context, databaseId, options.deps);
2569
+ if (options.verbose) consola.info(`Database credentials revealed in ${formatDuration(Date.now() - revealStart)}`);
2479
2570
  try {
2480
- await (options.deps.runDinewayInitialization ?? runDinewayInitialization)({
2571
+ const result = await (options.deps.runDinewayInitialization ?? runDinewayInitialization)({
2481
2572
  cwd: options.cwd,
2482
2573
  credentials,
2483
2574
  seedPath: options.seedPath
2484
2575
  });
2485
2576
  await recordSiteDatabaseInitialization(options.context, options.siteId, credentials.databaseId || databaseId, "succeeded", void 0, options.deps);
2577
+ await writeLocalDatabaseInitializationMetadata(options.cwd, {
2578
+ siteId: options.siteId,
2579
+ databaseId: credentials.databaseId || databaseId,
2580
+ status: "succeeded",
2581
+ fingerprint
2582
+ });
2583
+ return {
2584
+ status: "initialized",
2585
+ databaseId: credentials.databaseId || databaseId,
2586
+ fingerprint,
2587
+ result
2588
+ };
2486
2589
  } catch (error) {
2487
2590
  const message = redactDatabaseOutput(error instanceof Error ? error.message : String(error), [credentials.authToken, credentials.databaseUrl]);
2488
2591
  await recordSiteDatabaseInitialization(options.context, options.siteId, credentials.databaseId || databaseId, "failed", message, options.deps).catch(() => void 0);
2592
+ await writeLocalDatabaseInitializationMetadata(options.cwd, {
2593
+ siteId: options.siteId,
2594
+ databaseId: credentials.databaseId || databaseId,
2595
+ status: "failed",
2596
+ fingerprint,
2597
+ error: message.slice(0, 2e3)
2598
+ }).catch(() => void 0);
2489
2599
  throw new Error(message, { cause: error });
2490
2600
  }
2491
2601
  }
2492
- function shouldExclude(name) {
2602
+ function normalizeIgnorePattern(pattern) {
2603
+ return pattern.trim().replace(BACKSLASH_PATTERN, "/").replace(LEADING_SLASHES_PATTERN, "").replace(TRAILING_SLASHES_PATTERN, "");
2604
+ }
2605
+ function wildcardPatternToRegExp(pattern) {
2606
+ const source = pattern.split("**").map((part) => part.split("*").map((segment) => segment.replace(REGEXP_ESCAPE_PATTERN, "\\$&")).join("[^/]*")).join(".*");
2607
+ return new RegExp(`^${source}$`);
2608
+ }
2609
+ function matchesIgnorePattern(path, rawPattern) {
2610
+ const pattern = normalizeIgnorePattern(rawPattern);
2611
+ if (!pattern || pattern.startsWith("#")) return false;
2612
+ if (pattern.includes("*")) return wildcardPatternToRegExp(pattern).test(path);
2613
+ if (!pattern.includes("/")) return path === pattern || path.startsWith(`${pattern}/`) || basename(path) === pattern;
2614
+ return path === pattern || path.startsWith(`${pattern}/`);
2615
+ }
2616
+ async function readDeploymentIgnorePatterns(sourceDir) {
2617
+ const ignorePath = join(sourceDir, ".dinewayignore");
2618
+ if (!await fileExists$8(ignorePath)) return [];
2619
+ return (await readFile(ignorePath, "utf-8")).split(LINE_SPLIT_PATTERN).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
2620
+ }
2621
+ function shouldExclude(name, customPatterns = []) {
2493
2622
  const normalized = name.replace(BACKSLASH_PATTERN, "/");
2494
2623
  for (const pattern of EXCLUDE_PATTERNS) if (normalized === pattern || normalized.startsWith(`${pattern}/`) || normalized.endsWith(`/${pattern}`) || normalized.includes(`/${pattern}/`)) return true;
2495
- return normalized.endsWith(".log");
2624
+ if (normalized.endsWith(".log")) return true;
2625
+ return customPatterns.some((pattern) => matchesIgnorePattern(normalized, pattern));
2496
2626
  }
2497
2627
  function normalizeRelativePath(sourceDir, absolutePath) {
2498
2628
  return relative(sourceDir, absolutePath).replace(BACKSLASH_PATTERN, "/");
@@ -2511,6 +2641,8 @@ async function hashFile(filePath) {
2511
2641
  };
2512
2642
  }
2513
2643
  async function collectDeploymentFiles(sourceDir) {
2644
+ const customIgnorePatterns = await readDeploymentIgnorePatterns(sourceDir);
2645
+ const candidates = [];
2514
2646
  const files = [];
2515
2647
  async function walk(currentDir) {
2516
2648
  const entries = await readdir(currentDir, { withFileTypes: true });
@@ -2518,22 +2650,29 @@ async function collectDeploymentFiles(sourceDir) {
2518
2650
  for (const entry of entries) {
2519
2651
  const absolutePath = join(currentDir, entry.name);
2520
2652
  const normalizedPath = normalizeRelativePath(sourceDir, absolutePath);
2521
- if (!normalizedPath || shouldExclude(normalizedPath)) continue;
2653
+ if (!normalizedPath || shouldExclude(normalizedPath, customIgnorePatterns)) continue;
2522
2654
  if (entry.isDirectory()) {
2523
2655
  await walk(absolutePath);
2524
2656
  continue;
2525
2657
  }
2526
2658
  if (!entry.isFile()) continue;
2527
- const { sha, size } = await hashFile(absolutePath);
2528
- files.push({
2659
+ candidates.push({
2529
2660
  absolutePath,
2530
- path: normalizedPath,
2531
- sha,
2532
- size
2661
+ path: normalizedPath
2533
2662
  });
2534
2663
  }
2535
2664
  }
2536
2665
  await walk(sourceDir);
2666
+ await runWithConcurrency(candidates, FILE_HASH_CONCURRENCY, async ({ absolutePath, path }) => {
2667
+ const { sha, size } = await hashFile(absolutePath);
2668
+ files.push({
2669
+ absolutePath,
2670
+ path,
2671
+ sha,
2672
+ size
2673
+ });
2674
+ });
2675
+ files.sort((a, b) => a.path.localeCompare(b.path));
2537
2676
  return files;
2538
2677
  }
2539
2678
  async function runWithConcurrency(items, concurrency, worker) {
@@ -2571,16 +2710,23 @@ function getDeploymentError(metadata) {
2571
2710
  if (!metadata || typeof metadata.error !== "object" || metadata.error === null) return null;
2572
2711
  return metadata.error.errorMessage ?? null;
2573
2712
  }
2574
- async function pollDeployment(context, deploymentId, deps) {
2713
+ async function pollDeployment(context, deploymentId, deps, verbose) {
2575
2714
  const pollIntervalMs = deps.pollIntervalMs ?? POLL_INTERVAL_MS$1;
2576
2715
  const pollTimeoutMs = deps.pollTimeoutMs ?? POLL_TIMEOUT_MS$1;
2577
2716
  const startTime = Date.now();
2578
2717
  let deployment = null;
2718
+ let firstPoll = true;
2719
+ let lastStatus = null;
2579
2720
  while (Date.now() - startTime < pollTimeoutMs) {
2580
- if (pollIntervalMs > 0) await new Promise((done) => setTimeout(done, pollIntervalMs));
2721
+ if (!firstPoll && pollIntervalMs > 0) await new Promise((done) => setTimeout(done, pollIntervalMs));
2722
+ firstPoll = false;
2581
2723
  await ossFetch(context, `/api/deployments/${encodeURIComponent(deploymentId)}/sync`, deps, { method: "POST" }).catch(() => void 0);
2582
2724
  deployment = await ossFetch(context, `/api/deployments/${encodeURIComponent(deploymentId)}`, deps);
2583
2725
  const status = deployment.status.toUpperCase();
2726
+ if (verbose || status !== lastStatus) {
2727
+ consola.info(`Deployment status: ${status} (${formatDuration(Date.now() - startTime)} elapsed)`);
2728
+ lastStatus = status;
2729
+ }
2584
2730
  if (status === "READY") break;
2585
2731
  if (status === "ERROR" || status === "CANCELED") throw new Error(getDeploymentError(deployment.metadata) ?? `Deployment failed with status: ${deployment.status}`);
2586
2732
  if (pollIntervalMs === 0) break;
@@ -2594,8 +2740,13 @@ async function pollDeployment(context, deploymentId, deps) {
2594
2740
  }
2595
2741
  async function deploySiteProject(options) {
2596
2742
  options.deps.onEvent?.("scan");
2743
+ const scanStart = Date.now();
2744
+ consola.start("Scanning deploy files");
2597
2745
  const localFiles = await (options.deps.collectDeploymentFiles ?? collectDeploymentFiles)(options.sourceDir);
2598
2746
  if (localFiles.length === 0) throw new Error("No deployable files found in the source directory.");
2747
+ consola.success(`Scanned ${localFiles.length} files (${formatBytes$1(deploymentFileSize(localFiles))}) in ${formatDuration(Date.now() - scanStart)}`);
2748
+ const createStart = Date.now();
2749
+ consola.start("Creating Forgeway deployment");
2599
2750
  const createResult = await ossFetch(options.context, `/api/deployments/sites/${encodeURIComponent(options.siteId)}/deploy`, options.deps, {
2600
2751
  method: "POST",
2601
2752
  body: JSON.stringify({
@@ -2607,15 +2758,25 @@ async function deploySiteProject(options) {
2607
2758
  }))
2608
2759
  })
2609
2760
  });
2761
+ if (options.verbose) consola.info(`Deployment manifest accepted in ${formatDuration(Date.now() - createStart)}`);
2610
2762
  const localFileByPath = new Map(localFiles.map((file) => [file.path, file]));
2611
- await runWithConcurrency(createResult.files.filter((file) => !file.uploadedAt), DIRECT_UPLOAD_CONCURRENCY, async (manifestFile) => {
2763
+ const pendingFiles = createResult.files.filter((file) => !file.uploadedAt);
2764
+ const pendingSize = pendingFiles.reduce((total, file) => total + file.size, 0);
2765
+ if (pendingFiles.length === 0) consola.success("No file uploads needed");
2766
+ else consola.start(`Uploading ${pendingFiles.length} changed files (${formatBytes$1(pendingSize)})`);
2767
+ let uploadedCount = 0;
2768
+ await runWithConcurrency(pendingFiles, DIRECT_UPLOAD_CONCURRENCY, async (manifestFile) => {
2612
2769
  const localFile = localFileByPath.get(manifestFile.path);
2613
2770
  if (!localFile) throw new Error(`Forgeway returned an unknown file path: ${manifestFile.path}`);
2614
2771
  if (localFile.sha !== manifestFile.sha || localFile.size !== manifestFile.size) throw new Error(`Forgeway file metadata mismatch for: ${manifestFile.path}`);
2615
2772
  await uploadDirectDeploymentFile(options.context, createResult.id, manifestFile, localFile, options.deps);
2773
+ uploadedCount += 1;
2774
+ if (options.verbose || uploadedCount === pendingFiles.length || uploadedCount % 10 === 0) consola.info(`Uploaded ${uploadedCount}/${pendingFiles.length} files`);
2616
2775
  });
2776
+ consola.start("Starting Forgeway deployment");
2617
2777
  await startDirectDeployment(options.context, createResult.id, options.startBody, options.deps);
2618
- const result = await pollDeployment(options.context, createResult.id, options.deps);
2778
+ consola.start("Waiting for Forgeway deployment");
2779
+ const result = await pollDeployment(options.context, createResult.id, options.deps, options.verbose);
2619
2780
  return {
2620
2781
  deploymentId: createResult.id,
2621
2782
  ...result,
@@ -2645,7 +2806,9 @@ async function deployForgeway(cwd, options, deps = {}) {
2645
2806
  const sourceDir = resolve(cwd);
2646
2807
  if (!(await stat(sourceDir).catch(() => null))?.isDirectory()) throw new Error(`"${sourceDir}" is not a valid directory.`);
2647
2808
  if (EXCLUDE_PATTERNS.includes(basename(sourceDir))) throw new Error(`"${basename(sourceDir)}" is an excluded directory and cannot be deployed.`);
2648
- const seedPath = await resolveSeedPath$1(cwd, options.seed);
2809
+ const verbose = isVerboseDeploy(options);
2810
+ const seedPath = options.skipSeed ? null : await resolveSeedPath$1(cwd, options.seed);
2811
+ if (options.skipSeed) consola.info("Skipping seed initialization by request");
2649
2812
  const { context, restaurant } = await resolveProjectContext(cwd, options, deps);
2650
2813
  await ensureRestaurantClaim(context, restaurant, deps);
2651
2814
  const { site } = await resolveDeploymentSite(cwd, context, options, seedPath, deps, restaurant);
@@ -2654,15 +2817,22 @@ async function deployForgeway(cwd, options, deps = {}) {
2654
2817
  consola.start("Initializing Forgeway managed database");
2655
2818
  try {
2656
2819
  deps.onEvent?.("initialize");
2657
- await initializeSiteDatabaseBeforeDeploy({
2820
+ const initialization = await initializeSiteDatabaseBeforeDeploy({
2658
2821
  context,
2659
2822
  siteId: site.id,
2660
2823
  database,
2661
2824
  cwd,
2662
2825
  seedPath,
2826
+ force: options.forceDbInit === true,
2827
+ verbose,
2663
2828
  deps
2664
2829
  });
2665
- consola.success("Database initialized");
2830
+ if (initialization.status === "skipped") consola.success("Database already initialized for current schema and seed (local metadata)");
2831
+ else {
2832
+ const applied = initialization.result?.migrations.applied.length ?? 0;
2833
+ const seedSummary = formatSeedSummary(initialization.result?.seed);
2834
+ consola.success(`Database initialized: ${applied} migrations applied, ${seedSummary}`);
2835
+ }
2666
2836
  } catch (error) {
2667
2837
  consola.error("Database initialization failed");
2668
2838
  throw error;
@@ -2674,7 +2844,8 @@ async function deployForgeway(cwd, options, deps = {}) {
2674
2844
  siteId: site.id,
2675
2845
  sourceDir,
2676
2846
  startBody: {},
2677
- deps
2847
+ deps,
2848
+ verbose
2678
2849
  });
2679
2850
  const url = deployment.liveUrl ?? `https://${site.domain}`;
2680
2851
  await (deps.writeProjectEnv ?? persistForgewayCliEnv)(cwd, {
@@ -3246,6 +3417,21 @@ const deployCommand = defineCommand({
3246
3417
  type: "string",
3247
3418
  description: "Seed file path for Forgeway Dineway initialization",
3248
3419
  required: false
3420
+ },
3421
+ "skip-seed": {
3422
+ type: "boolean",
3423
+ description: "Skip applying seed data during Forgeway database initialization",
3424
+ default: false
3425
+ },
3426
+ "force-db-init": {
3427
+ type: "boolean",
3428
+ description: "Force Forgeway database migrations and seed even when initialization fingerprints match",
3429
+ default: false
3430
+ },
3431
+ verbose: {
3432
+ type: "boolean",
3433
+ description: "Show detailed Forgeway deploy progress and timing logs",
3434
+ default: false
3249
3435
  }
3250
3436
  },
3251
3437
  async run({ args }) {
@@ -3262,7 +3448,10 @@ const deployCommand = defineCommand({
3262
3448
  restaurantName: args["restaurant-name"],
3263
3449
  city: args.city,
3264
3450
  database: args.database,
3265
- seed: args.seed
3451
+ seed: args.seed,
3452
+ skipSeed: args["skip-seed"],
3453
+ forceDbInit: args["force-db-init"],
3454
+ verbose: args.verbose
3266
3455
  };
3267
3456
  consola.start(`Preparing ${target.label} deploy`);
3268
3457
  await ensureTargetCli(target, cwd, {
package/dist/db/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import "../dialect-helpers-TkdbkFad.mjs";
2
- import { n as rollbackMigration, r as runMigrations, t as getMigrationStatus } from "../runner-lqEiJbO-.mjs";
2
+ import { i as runMigrations, n as getMigrationStatus, r as rollbackMigration } from "../runner-S3smkgdc.mjs";
3
3
 
4
4
  //#region src/db/adapters.ts
5
5
  /**
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as ContentSeoInput, c as FindManyOptions, i as ContentSeo, l as FindManyResult, n as ContentBylineCredit, o as CreateContentInput, r as ContentItem, s as DinewayValidationError, t as BylineSummary, u as UpdateContentInput } from "./types-DvwHUku7.mjs";
2
- import { $ as createPluginManager, $t as SandboxOptions, A as dropSessionDatabaseTables, An as handleContentDelete, At as verifyPreviewSignature, B as GeneratePreviewTokenOptions, Bn as handleContentSchedule, Bt as prosemirrorToPortableText, C as getByline, Cn as handleRevisionList, Ct as SessionOpenOrCreateOptions, D as AppliedSnapshotMeta, Dn as handleContentCountScheduled, Dt as defaultPreviewSidecarClient, E as renderPreviewToolbar, En as handleContentCompare, Et as buildPreviewSignatureHeader, F as getPreviewToken, Fn as handleContentList, Ft as AfterCallback, G as parseContentId, Gn as CreateMediaInput, Gt as PortableTextSpan, H as VerifyPreviewTokenOptions, Hn as handleContentUnpublish, Ht as PortableTextImageBlock, I as isPreviewRequest, In as handleContentListTrashed, It as after, J as createNodeSandboxRunner, Jn as ContentRepository, Jt as ProseMirrorDocument, K as verifyPreviewToken, Kn as MediaItem, Kt as PortableTextTextBlock, L as GetPreviewUrlOptions, Ln as handleContentPermanentDelete, Lt as computeContentHash, M as Snapshot, Mn as handleContentDuplicate, Mt as getFallbackChain, N as renderPreviewLoadingPage, Nn as handleContentGet, Nt as getI18nConfig, O as ApplySnapshotToDatabaseOptions, On as handleContentCountTrashed, Ot as parsePreviewSignatureHeader, P as isBlockedInPreview, Pn as handleContentGetIncludingTrashed, Pt as isI18nEnabled, Q as PluginManager, Qt as SandboxEmailSendCallback, R as buildPreviewUrl, Rn as handleContentPublish, Rt as hashString, S as Suggestion, Sn as handleRevisionGet, St as SessionOpenOptions, T as PreviewToolbarConfig, Tn as generateManifest, Tt as PreviewSidecarSignature, U as VerifyPreviewTokenResult, Un as handleContentUnschedule, Ut as PortableTextLinkMark, V as PreviewTokenPayload, Vn as handleContentTranslations, Vt as PortableTextCodeBlock, W as generatePreviewToken, Wn as handleContentUpdate, Wt as PortableTextMarkDef, X as SandboxNotAvailableError, Xn as DinewayDatabaseError, Xt as ProseMirrorNode, Y as NoopSandboxRunner, Yn as DatabaseConfig, Yt as ProseMirrorMark, Z as createNoopSandboxRunner, Zt as SandboxEmailMessage, _ as SearchOptions, _n as handleMediaGet, _t as SessionCleanupResult, an as getSections, ar as ApiContext, at as ValidatedPluginManifest, b as SearchStats, bn as RevisionListResponse, bt as SessionDatabaseInfo, c as extractSearchableFields, cn as Section, cr as FieldDescriptor, ct as CollectionFilter$1, d as search, dn as SchemaError, en as SandboxRunner, et as PluginRouteError, f as searchCollection, fn as SchemaRegistry, g as SearchConfig, gn as handleMediaDelete, gt as FileSessionDatabaseFactoryOptions, h as CollectionSearchOptions, hn as handleMediaCreate, ht as FileSessionDatabaseFactory, in as getSection, it as createHookPipeline, j as getAppliedSnapshotMeta, jn as handleContentDiscardDraft, jt as I18nConfig, k as applySnapshotToDatabase, kn as handleContentCreate, kt as signPreviewUrl, l as getSearchStats, ln as SectionSource, lr as ListResponse, lt as EntryData, m as FTSManager, mn as MediaResponse, mt as createFilePreviewMiddleware, n as PluginDescriptor, nn as SandboxedPlugin, nt as HookPipeline, on as CreateSectionInput, or as ContentListResponse, ot as pluginManifestSchema, p as searchWithDb, pn as MediaListResponse, pt as FilePreviewMiddlewareConfig, q as NodeSandboxRunner, qn as MediaRepository, qt as PortableTextUnknownBlock, rn as SerializedRequest, rt as HookResult, s as extractPlainText, sn as GetSectionsOptions, sr as ContentResponse, st as definePlugin, tn as SandboxRunnerFactory, u as getSuggestions, un as UpdateSectionInput, ur as ManifestResponse, ut as EntryFilter, v as SearchResponse, vn as handleMediaList, vt as SessionDatabaseFactory, w as getBylineBySlug, wn as handleRevisionRestore, wt as PreviewSidecarClient, x as SuggestOptions, xn as RevisionResponse, xt as SessionDatabaseLimitError, y as SearchResult, yn as handleMediaUpdate, yt as SessionDatabaseHandle, z as getPreviewUrl, zn as handleContentRestore, zt as portableTextToProsemirror } from "./runtime-CP8eY2L-.mjs";
2
+ import { $ as createPluginManager, $t as SandboxOptions, A as dropSessionDatabaseTables, An as handleContentDelete, At as verifyPreviewSignature, B as GeneratePreviewTokenOptions, Bn as handleContentSchedule, Bt as prosemirrorToPortableText, C as getByline, Cn as handleRevisionList, Ct as SessionOpenOrCreateOptions, D as AppliedSnapshotMeta, Dn as handleContentCountScheduled, Dt as defaultPreviewSidecarClient, E as renderPreviewToolbar, En as handleContentCompare, Et as buildPreviewSignatureHeader, F as getPreviewToken, Fn as handleContentList, Ft as AfterCallback, G as parseContentId, Gn as CreateMediaInput, Gt as PortableTextSpan, H as VerifyPreviewTokenOptions, Hn as handleContentUnpublish, Ht as PortableTextImageBlock, I as isPreviewRequest, In as handleContentListTrashed, It as after, J as createNodeSandboxRunner, Jn as ContentRepository, Jt as ProseMirrorDocument, K as verifyPreviewToken, Kn as MediaItem, Kt as PortableTextTextBlock, L as GetPreviewUrlOptions, Ln as handleContentPermanentDelete, Lt as computeContentHash, M as Snapshot, Mn as handleContentDuplicate, Mt as getFallbackChain, N as renderPreviewLoadingPage, Nn as handleContentGet, Nt as getI18nConfig, O as ApplySnapshotToDatabaseOptions, On as handleContentCountTrashed, Ot as parsePreviewSignatureHeader, P as isBlockedInPreview, Pn as handleContentGetIncludingTrashed, Pt as isI18nEnabled, Q as PluginManager, Qt as SandboxEmailSendCallback, R as buildPreviewUrl, Rn as handleContentPublish, Rt as hashString, S as Suggestion, Sn as handleRevisionGet, St as SessionOpenOptions, T as PreviewToolbarConfig, Tn as generateManifest, Tt as PreviewSidecarSignature, U as VerifyPreviewTokenResult, Un as handleContentUnschedule, Ut as PortableTextLinkMark, V as PreviewTokenPayload, Vn as handleContentTranslations, Vt as PortableTextCodeBlock, W as generatePreviewToken, Wn as handleContentUpdate, Wt as PortableTextMarkDef, X as SandboxNotAvailableError, Xn as DinewayDatabaseError, Xt as ProseMirrorNode, Y as NoopSandboxRunner, Yn as DatabaseConfig, Yt as ProseMirrorMark, Z as createNoopSandboxRunner, Zt as SandboxEmailMessage, _ as SearchOptions, _n as handleMediaGet, _t as SessionCleanupResult, an as getSections, ar as ApiContext, at as ValidatedPluginManifest, b as SearchStats, bn as RevisionListResponse, bt as SessionDatabaseInfo, c as extractSearchableFields, cn as Section, cr as FieldDescriptor, ct as CollectionFilter$1, d as search, dn as SchemaError, en as SandboxRunner, et as PluginRouteError, f as searchCollection, fn as SchemaRegistry, g as SearchConfig, gn as handleMediaDelete, gt as FileSessionDatabaseFactoryOptions, h as CollectionSearchOptions, hn as handleMediaCreate, ht as FileSessionDatabaseFactory, in as getSection, it as createHookPipeline, j as getAppliedSnapshotMeta, jn as handleContentDiscardDraft, jt as I18nConfig, k as applySnapshotToDatabase, kn as handleContentCreate, kt as signPreviewUrl, l as getSearchStats, ln as SectionSource, lr as ListResponse, lt as EntryData, m as FTSManager, mn as MediaResponse, mt as createFilePreviewMiddleware, n as PluginDescriptor, nn as SandboxedPlugin, nt as HookPipeline, on as CreateSectionInput, or as ContentListResponse, ot as pluginManifestSchema, p as searchWithDb, pn as MediaListResponse, pt as FilePreviewMiddlewareConfig, q as NodeSandboxRunner, qn as MediaRepository, qt as PortableTextUnknownBlock, rn as SerializedRequest, rt as HookResult, s as extractPlainText, sn as GetSectionsOptions, sr as ContentResponse, st as definePlugin, tn as SandboxRunnerFactory, u as getSuggestions, un as UpdateSectionInput, ur as ManifestResponse, ut as EntryFilter, v as SearchResponse, vn as handleMediaList, vt as SessionDatabaseFactory, w as getBylineBySlug, wn as handleRevisionRestore, wt as PreviewSidecarClient, x as SuggestOptions, xn as RevisionResponse, xt as SessionDatabaseLimitError, y as SearchResult, yn as handleMediaUpdate, yt as SessionDatabaseHandle, z as getPreviewUrl, zn as handleContentRestore, zt as portableTextToProsemirror } from "./runtime-BM9sqnzO.mjs";
3
3
  import { n as MediaTable, r as UserTable, t as Database } from "./types-B1NksXAb.mjs";
4
4
  import { $ as StandardHookEntry, A as PageMetadataContribution, B as PluginDefinition, C as MediaAccess, D as PageFragmentContribution, E as ModerationDecision, F as PluginAdminConfig, G as PortableTextBlockConfig, H as PluginManifest, I as PluginAdminExports, K as PortableTextBlockField, L as PluginAdminPage, M as PageMetadataHandler, O as PageFragmentEvent, P as PagePlacement, Q as RouteContext, R as PluginCapability, S as LogAccess, T as MediaUploadEvent, U as PluginRoute, V as PluginHooks, W as PluginStorageConfig, X as ResolvedPlugin, Y as ResolvedHook, Z as ResolvedPluginHooks, _ as FieldWidgetConfig, a as CommentAfterModerateEvent, b as HttpAccess, c as CommentBeforeCreateHandler, d as ContentAccess, et as StandardHookHandler, f as ContentDeleteEvent, i as CommentAfterCreateHandler, it as StorageCollection, j as PageMetadataEvent, k as PageFragmentHandler, l as CommentModerateEvent, m as ContentPublishStateChangeEvent, n as CollectionCommentSettings, nt as StandardRouteEntry, o as CommentAfterModerateHandler, ot as StoredComment, p as ContentHookEvent, q as PublicPageContext, r as CommentAfterCreateEvent, rt as StandardRouteHandler, s as CommentBeforeCreateEvent, st as isStandardPluginDefinition, t as BreadcrumbItem, tt as StandardPluginDefinition, u as CommentModerateHandler, v as HookConfig, x as KVAccess, y as HookName, z as PluginContext } from "./types-BIM7jwxr.mjs";
5
5
  import { _ as RESERVED_COLLECTION_SLUGS, a as Collection, b as UpdateFieldInput, c as CollectionWithFields, d as CreateFieldInput, f as FIELD_TYPE_TO_COLUMN, g as FieldWidgetOptions, h as FieldValidation, i as SiteSettings, l as ColumnType, m as FieldType, n as SeoSettings, o as CollectionSource, p as Field, r as SiteSettingKey, s as CollectionSupport, t as MediaReference, u as CreateCollectionInput, v as RESERVED_FIELD_SLUGS, y as UpdateCollectionInput } from "./types-t7_nCCA9.mjs";
@@ -11,7 +11,7 @@ import { $ as TranslationSummary, A as MenuItem, B as getPluginSettings, C as Ta
11
11
  import { _ as WxrSite, a as getAllSources, b as parseWxrString, c as getUrlSources, d as importReusableBlocksAsSections, f as WxrAttachment, g as WxrPost, h as WxrData, i as clearSources, l as probeUrl, m as WxrCategory, n as parseWxrDate, o as getFileSources, p as WxrAuthor, r as wxrSource, s as getSource, t as wordpressRestSource, u as registerSource, v as WxrTag, x as decodeSlug, y as parseWxr } from "./index-CpbixmRL.mjs";
12
12
  import { n as generatePlaceholder, r as normalizeMediaValue, t as PlaceholderData } from "./placeholder-BZpCpid_.mjs";
13
13
  import { a as ListOptions, c as S3StorageConfig, d as Storage, f as StorageDescriptor, i as FileInfo, l as SignedUploadOptions, n as DinewayStorageError, o as ListResult, p as UploadResult, r as DownloadResult, s as LocalStorageConfig, t as CreateStorageFn, u as SignedUploadUrl } from "./types-BYjPylrZ.mjs";
14
- import "./bylines-CtD_p_1z.mjs";
14
+ import "./bylines-C8EfvtqH.mjs";
15
15
  import { DinewayRequestContext, getRequestContext, runWithContext } from "./request-context.mjs";
16
16
  import { adaptSandboxEntry } from "./plugins/adapt-sandbox-entry.mjs";
17
17
  import { S as UrlInput, _ as SourceAuth, a as FileInput, b as SourceProbeResult, c as ImportContext, d as ImportSource, f as NormalizedItem, g as ProbeResult, h as PostTypeMapping, i as FieldCompatibility, l as ImportFieldDef, m as PostTypeAnalysis, n as CollectionSchemaStatus, o as ImportAnalysis, p as OAuthInput, r as FetchOptions, s as ImportConfig, t as AttachmentInfo, u as ImportResult, v as SourceCapabilities, x as SuggestedAction, y as SourceInput } from "./types-BBETcziA.mjs";
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { getRequestContext, runWithContext } from "./request-context.mjs";
2
2
  import { t as DinewayDatabaseError } from "./connection-BCNICDWN.mjs";
3
3
  import "./dialect-helpers-TkdbkFad.mjs";
4
- import { t as getMigrationStatus } from "./runner-lqEiJbO-.mjs";
4
+ import { n as getMigrationStatus } from "./runner-S3smkgdc.mjs";
5
5
  import { n as getI18nConfig, r as isI18nEnabled, t as getFallbackChain } from "./config-XW5tMrH8.mjs";
6
6
  import { _ as portableTextToProsemirror, a as SandboxNotAvailableError, b as reference, c as createPluginManager, f as HookPipeline, g as after, h as definePlugin, i as NoopSandboxRunner, l as PluginRouteError, n as NodeSandboxRunner, o as createNoopSandboxRunner, p as createHookPipeline, r as createNodeSandboxRunner, s as PluginManager, t as isStandardPluginDefinition, v as prosemirrorToPortableText, x as image, y as portableText } from "./plugins-DCDVDF4B.mjs";
7
7
  import { t as decodeSlug } from "./slugify-BzGxlOFx.mjs";
@@ -24,7 +24,7 @@ import "./byline-DpNNSjET.mjs";
24
24
  import { t as normalizeMediaValue } from "./normalize-BY_EJnd9.mjs";
25
25
  import { t as generatePlaceholder } from "./placeholder-b0Ufu0La.mjs";
26
26
  import "./seo-BPb_reaG.mjs";
27
- import { A as handleRevisionGet, B as handleContentDuplicate, D as handleMediaGet, E as handleMediaDelete, F as handleContentCountScheduled, G as handleContentPermanentDelete, H as handleContentGetIncludingTrashed, I as handleContentCountTrashed, J as handleContentSchedule, K as handleContentPublish, L as handleContentCreate, M as handleRevisionRestore, N as generateManifest, O as handleMediaList, P as handleContentCompare, Q as handleContentUpdate, R as handleContentDelete, T as handleMediaCreate, U as handleContentList, V as handleContentGet, W as handleContentListTrashed, X as handleContentUnpublish, Y as handleContentTranslations, Z as handleContentUnschedule, j as handleRevisionList, k as handleMediaUpdate, q as handleContentRestore, z as handleContentDiscardDraft } from "./api-Ow6RbraA.mjs";
27
+ import { A as handleRevisionGet, B as handleContentDuplicate, D as handleMediaGet, E as handleMediaDelete, F as handleContentCountScheduled, G as handleContentPermanentDelete, H as handleContentGetIncludingTrashed, I as handleContentCountTrashed, J as handleContentSchedule, K as handleContentPublish, L as handleContentCreate, M as handleRevisionRestore, N as generateManifest, O as handleMediaList, P as handleContentCompare, Q as handleContentUpdate, R as handleContentDelete, T as handleMediaCreate, U as handleContentList, V as handleContentGet, W as handleContentListTrashed, X as handleContentUnpublish, Y as handleContentTranslations, Z as handleContentUnschedule, j as handleRevisionList, k as handleMediaUpdate, q as handleContentRestore, z as handleContentDiscardDraft } from "./api-K0U9SYx7.mjs";
28
28
  import "./request-cache-BpwuE2ix.mjs";
29
29
  import "./dashboard-BC9bgPOH.mjs";
30
30
  import "./briefing-Jsxs587i.mjs";
@@ -53,7 +53,7 @@ import "./import-Br7aP9yh.mjs";
53
53
  import { n as sanitizeHref, t as isSafeHref } from "./url-BzhfYtRn.mjs";
54
54
  import { c as createEditable, i as getTranslations, l as createNoop, n as getDinewayEntry, r as getEditMeta, s as resolveDinewayPath, t as getDinewayCollection } from "./query-DHvNhBhi.mjs";
55
55
  import { a as verifyPreviewSignature, i as signPreviewUrl, n as defaultPreviewSidecarClient, r as parsePreviewSignatureHeader, t as buildPreviewSignatureHeader } from "./sidecar-client-lrf7ErYJ.mjs";
56
- import { a as createFilePreviewMiddleware, c as dropSessionDatabaseTables, d as SessionDatabaseLimitError, f as isBlockedInPreview, i as getPreviewUrl, l as getAppliedSnapshotMeta, n as isPreviewRequest, o as renderPreviewToolbar, p as renderPreviewLoadingPage, r as buildPreviewUrl, s as applySnapshotToDatabase, t as getPreviewToken, u as FileSessionDatabaseFactory } from "./preview-5HuX6fjF.mjs";
56
+ import { a as createFilePreviewMiddleware, c as dropSessionDatabaseTables, d as SessionDatabaseLimitError, f as isBlockedInPreview, i as getPreviewUrl, l as getAppliedSnapshotMeta, n as isPreviewRequest, o as renderPreviewToolbar, p as renderPreviewLoadingPage, r as buildPreviewUrl, s as applySnapshotToDatabase, t as getPreviewToken, u as FileSessionDatabaseFactory } from "./preview-BhgxNRWI.mjs";
57
57
  import { n as parseWxrString, t as parseWxr } from "./parser-egIGEco-.mjs";
58
58
  import { adaptSandboxEntry } from "./plugins/adapt-sandbox-entry.mjs";
59
59
  import "./ssrf-KAIQS48_.mjs";
@@ -1,4 +1,4 @@
1
- import "../runtime-CP8eY2L-.mjs";
1
+ import "../runtime-BM9sqnzO.mjs";
2
2
  import { t as Database } from "../types-B1NksXAb.mjs";
3
3
  import "../types-BIM7jwxr.mjs";
4
4
  import "../types-BgE6gMFI.mjs";
@@ -7,7 +7,7 @@ import "../runner-pAnQS6iI.mjs";
7
7
  import "../index-2tBfB_8X.mjs";
8
8
  import "../index-CpbixmRL.mjs";
9
9
  import { d as Storage } from "../types-BYjPylrZ.mjs";
10
- import "../bylines-CtD_p_1z.mjs";
10
+ import "../bylines-C8EfvtqH.mjs";
11
11
  import "../types-BBETcziA.mjs";
12
12
  import "../validate-BzUCAU2a.mjs";
13
13
  import "../index.mjs";
@@ -1,11 +1,11 @@
1
- import { n as PluginDescriptor } from "../runtime-CP8eY2L-.mjs";
1
+ import { n as PluginDescriptor } from "../runtime-BM9sqnzO.mjs";
2
2
  import "../types-B1NksXAb.mjs";
3
3
  import { X as ResolvedPlugin, tt as StandardPluginDefinition } from "../types-BIM7jwxr.mjs";
4
4
  import "../types-BgE6gMFI.mjs";
5
5
  import "../runner-pAnQS6iI.mjs";
6
6
  import "../index-2tBfB_8X.mjs";
7
7
  import "../index-CpbixmRL.mjs";
8
- import "../bylines-CtD_p_1z.mjs";
8
+ import "../bylines-C8EfvtqH.mjs";
9
9
  import "../types-BBETcziA.mjs";
10
10
  import "../validate-BzUCAU2a.mjs";
11
11
 
@@ -4,8 +4,8 @@ import { a as verifyPreviewSignature, t as buildPreviewSignatureHeader } from ".
4
4
  import { t as generatePreviewToken } from "./tokens-CsP8Se8S.mjs";
5
5
  import BetterSqlite3 from "better-sqlite3";
6
6
  import { sql } from "kysely";
7
- import { ulid } from "ulidx";
8
7
  import { createHash } from "node:crypto";
8
+ import { ulid } from "ulidx";
9
9
  import { existsSync, mkdirSync, readdirSync, rmSync, statSync } from "node:fs";
10
10
  import { join } from "node:path";
11
11
 
@@ -3,6 +3,7 @@ import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
3
3
  import { c as listTablesLike, i as currentTimestampValue, n as columnExists, o as isSqlite, r as currentTimestamp, t as binaryType } from "./dialect-helpers-TkdbkFad.mjs";
4
4
  import { n as getI18nConfig } from "./config-XW5tMrH8.mjs";
5
5
  import { Migrator, sql } from "kysely";
6
+ import { createHash } from "node:crypto";
6
7
 
7
8
  //#region src/database/migrations/001_initial.ts
8
9
  var _001_initial_exports = /* @__PURE__ */ __exportAll({
@@ -2221,8 +2222,20 @@ const MIGRATIONS = Object.freeze({
2221
2222
  "044_credential_algorithm": _044_credential_algorithm_exports,
2222
2223
  "045_i18n_menus_and_taxonomies": _045_i18n_menus_and_taxonomies_exports
2223
2224
  });
2225
+ const MIGRATION_NAMES = Object.freeze(Object.keys(MIGRATIONS).toSorted());
2224
2226
  /** Total number of registered migrations. Exported for use in tests. */
2225
- const MIGRATION_COUNT = Object.keys(MIGRATIONS).length;
2227
+ const MIGRATION_COUNT = MIGRATION_NAMES.length;
2228
+ function getMigrationFingerprint() {
2229
+ const hash = createHash("sha256");
2230
+ for (const name of MIGRATION_NAMES) {
2231
+ hash.update(name);
2232
+ hash.update("\0");
2233
+ }
2234
+ return {
2235
+ migrationHash: `sha256:${hash.digest("hex")}`,
2236
+ migrationCount: MIGRATION_COUNT
2237
+ };
2238
+ }
2226
2239
  /**
2227
2240
  * Migration provider that uses statically imported migrations.
2228
2241
  * This approach works well with bundlers and avoids filesystem access.
@@ -2293,4 +2306,4 @@ async function rollbackMigration(db) {
2293
2306
  }
2294
2307
 
2295
2308
  //#endregion
2296
- export { rollbackMigration as n, runMigrations as r, getMigrationStatus as t };
2309
+ export { runMigrations as i, getMigrationStatus as n, rollbackMigration as r, getMigrationFingerprint as t };
@@ -1787,14 +1787,14 @@ declare const pluginManifestSchema: z.ZodObject<{
1787
1787
  number: "number";
1788
1788
  boolean: "boolean";
1789
1789
  file: "file";
1790
+ image: "image";
1790
1791
  slug: "slug";
1792
+ datetime: "datetime";
1791
1793
  text: "text";
1792
1794
  integer: "integer";
1793
- datetime: "datetime";
1794
1795
  select: "select";
1795
1796
  multiSelect: "multiSelect";
1796
1797
  portableText: "portableText";
1797
- image: "image";
1798
1798
  reference: "reference";
1799
1799
  json: "json";
1800
1800
  repeater: "repeater";
@@ -1,11 +1,11 @@
1
- import { ct as CollectionFilter, dt as dinewayLoader, ft as getDb, lt as EntryData, ut as EntryFilter } from "./runtime-CP8eY2L-.mjs";
1
+ import { ct as CollectionFilter, dt as dinewayLoader, ft as getDb, lt as EntryData, ut as EntryFilter } from "./runtime-BM9sqnzO.mjs";
2
2
  import "./types-B1NksXAb.mjs";
3
3
  import "./types-BIM7jwxr.mjs";
4
4
  import "./types-BgE6gMFI.mjs";
5
5
  import "./runner-pAnQS6iI.mjs";
6
6
  import "./index-2tBfB_8X.mjs";
7
7
  import "./index-CpbixmRL.mjs";
8
- import "./bylines-CtD_p_1z.mjs";
8
+ import "./bylines-C8EfvtqH.mjs";
9
9
  import "./types-BBETcziA.mjs";
10
10
  import "./validate-BzUCAU2a.mjs";
11
11
  import { t as getMediaProvider } from "./provider-loader-BaZhx7E3.mjs";