@tinacms/cli 0.0.0-97d38ab-20241104224426 → 0.0.0-98df118-20250227044321

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.
@@ -150,7 +150,7 @@ export declare const parseSections: ({ val }: {
150
150
  }) => {
151
151
  sections?: {
152
152
  exclude?: string;
153
- type?: "heading" | "document" | "directory" | "jekyll-pages" | "jekyll-posts";
153
+ type?: "document" | "heading" | "directory" | "jekyll-pages" | "jekyll-posts";
154
154
  match?: string;
155
155
  path?: string;
156
156
  templates?: string[];
package/dist/index.js CHANGED
@@ -17,23 +17,28 @@ var __copyProps = (to, from, except, desc) => {
17
17
  return to;
18
18
  };
19
19
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
20
24
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
21
25
  mod
22
26
  ));
23
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
24
28
 
25
29
  // src/index.ts
26
- var src_exports = {};
27
- __export(src_exports, {
28
- default: () => src_default
30
+ var index_exports = {};
31
+ __export(index_exports, {
32
+ default: () => index_default
29
33
  });
30
- module.exports = __toCommonJS(src_exports);
34
+ module.exports = __toCommonJS(index_exports);
31
35
  var import_clipanion8 = require("clipanion");
32
36
 
33
37
  // package.json
34
- var version = "1.6.11";
38
+ var version = "1.9.1";
35
39
 
36
40
  // src/next/commands/dev-command/index.ts
41
+ var import_async_lock = __toESM(require("async-lock"));
37
42
  var import_clipanion2 = require("clipanion");
38
43
  var import_fs_extra6 = __toESM(require("fs-extra"));
39
44
  var import_path5 = __toESM(require("path"));
@@ -57,7 +62,10 @@ function isUnicodeSupported() {
57
62
  if (process.platform !== "win32") {
58
63
  return process.env.TERM !== "linux";
59
64
  }
60
- return Boolean(process.env.CI) || Boolean(process.env.WT_SESSION) || Boolean(process.env.TERMINUS_SUBLIME) || process.env.ConEmuTask === "{cmd::Cmder}" || process.env.TERM_PROGRAM === "Terminus-Sublime" || process.env.TERM_PROGRAM === "vscode" || process.env.TERM === "xterm-256color" || process.env.TERM === "alacritty" || process.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
65
+ return Boolean(process.env.CI) || Boolean(process.env.WT_SESSION) || // Windows Terminal
66
+ Boolean(process.env.TERMINUS_SUBLIME) || // Terminus (<0.2.27)
67
+ process.env.ConEmuTask === "{cmd::Cmder}" || // ConEmu and cmder
68
+ process.env.TERM_PROGRAM === "Terminus-Sublime" || process.env.TERM_PROGRAM === "vscode" || process.env.TERM === "xterm-256color" || process.env.TERM === "alacritty" || process.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
61
69
  }
62
70
 
63
71
  // src/logger/index.ts
@@ -212,7 +220,7 @@ var ConfigManager = class {
212
220
  this.generatedCachePath = import_path.default.join(
213
221
  this.generatedFolderPath,
214
222
  ".cache",
215
- String(new Date().getTime())
223
+ String((/* @__PURE__ */ new Date()).getTime())
216
224
  );
217
225
  this.generatedGraphQLGQLPath = import_path.default.join(
218
226
  this.generatedFolderPath,
@@ -355,17 +363,22 @@ var ConfigManager = class {
355
363
  );
356
364
  }
357
365
  getTinaGraphQLVersion() {
358
- var _a, _b;
359
366
  if (this.tinaGraphQLVersionFromCLI) {
360
- return this.tinaGraphQLVersionFromCLI;
367
+ const version2 = this.tinaGraphQLVersionFromCLI.split(".");
368
+ return {
369
+ fullVersion: this.tinaGraphQLVersionFromCLI,
370
+ major: version2[0] || "x",
371
+ minor: version2[1] || "x",
372
+ patch: version2[2] || "x"
373
+ };
361
374
  }
362
375
  const generatedSchema = import_fs_extra.default.readJSONSync(this.generatedSchemaJSONPath);
363
- if (!generatedSchema || !(typeof (generatedSchema == null ? void 0 : generatedSchema.version) !== "undefined") || !(typeof ((_a = generatedSchema == null ? void 0 : generatedSchema.version) == null ? void 0 : _a.major) === "string") || !(typeof ((_b = generatedSchema == null ? void 0 : generatedSchema.version) == null ? void 0 : _b.minor) === "string")) {
376
+ if (!generatedSchema || !(typeof (generatedSchema == null ? void 0 : generatedSchema.version) !== "undefined")) {
364
377
  throw new Error(
365
378
  `Can not find Tina GraphQL version in ${this.generatedSchemaJSONPath}`
366
379
  );
367
380
  }
368
- return `${generatedSchema.version.major}.${generatedSchema.version.minor}`;
381
+ return generatedSchema.version;
369
382
  }
370
383
  printGeneratedClientFilePath() {
371
384
  if (this.isUsingTs()) {
@@ -394,6 +407,9 @@ var ConfigManager = class {
394
407
  }
395
408
  throw `No path provided to print`;
396
409
  }
410
+ /**
411
+ * Given a filepath without an extension, find the first match (eg. tsx, ts, jsx, js)
412
+ */
397
413
  async getPathWithExtension(filepath) {
398
414
  const extensions = ["tsx", "ts", "jsx", "js"];
399
415
  let result;
@@ -427,7 +443,10 @@ var ConfigManager = class {
427
443
  }
428
444
  async loadConfigFile(generatedFolderPath, configFilePath) {
429
445
  const tmpdir = import_path.default.join(import_os.default.tmpdir(), Date.now().toString());
430
- const prebuild = import_path.default.join(this.generatedFolderPath, "config.prebuild.jsx");
446
+ const preBuildConfigPath = import_path.default.join(
447
+ this.generatedFolderPath,
448
+ "config.prebuild.jsx"
449
+ );
431
450
  const outfile = import_path.default.join(tmpdir, "config.build.jsx");
432
451
  const outfile2 = import_path.default.join(tmpdir, "config.build.js");
433
452
  const tempTSConfigFile = import_path.default.join(tmpdir, "tsconfig.json");
@@ -441,7 +460,7 @@ var ConfigManager = class {
441
460
  logLevel: "silent",
442
461
  packages: "external",
443
462
  ignoreAnnotations: true,
444
- outfile: prebuild,
463
+ outfile: preBuildConfigPath,
445
464
  loader: loaders,
446
465
  metafile: true
447
466
  });
@@ -464,6 +483,7 @@ var ConfigManager = class {
464
483
  await esbuild.build({
465
484
  entryPoints: [outfile],
466
485
  bundle: true,
486
+ // Suppress warning about comparison with -0 from client module
467
487
  logLevel: "silent",
468
488
  platform: "node",
469
489
  outfile: outfile2,
@@ -481,7 +501,7 @@ var ConfigManager = class {
481
501
  import_fs_extra.default.removeSync(outfile2);
482
502
  return {
483
503
  config: result.default,
484
- prebuildPath: prebuild,
504
+ prebuildPath: preBuildConfigPath,
485
505
  watchList: flattenedList
486
506
  };
487
507
  }
@@ -570,19 +590,19 @@ var devHTML = (port) => `<!DOCTYPE html>
570
590
  window.$RefreshReg$ = () => {}
571
591
  window.$RefreshSig$ = () => (type) => type
572
592
  window.__vite_plugin_react_preamble_installed__ = true
573
- <\/script>
574
- <script type="module" src="http://localhost:${port}/@vite/client"><\/script>
593
+ </script>
594
+ <script type="module" src="http://localhost:${port}/@vite/client"></script>
575
595
  <script>
576
596
  function handleLoadError() {
577
597
  // Assets have failed to load
578
598
  document.getElementById('root').innerHTML = '${errorHTML}';
579
599
  }
580
- <\/script>
600
+ </script>
581
601
  <script
582
602
  type="module"
583
603
  src="http://localhost:${port}/src/main.tsx"
584
604
  onerror="handleLoadError()"
585
- ><\/script>
605
+ ></script>
586
606
  <body class="tina-tailwind">
587
607
  <div id="root"></div>
588
608
  </body>
@@ -628,6 +648,7 @@ var import_defaultTheme = __toESM(require("tailwindcss/defaultTheme.js"));
628
648
  var tinaTailwind = (spaPath, prebuildFilePath) => {
629
649
  return {
630
650
  name: "vite-plugin-tina",
651
+ // @ts-ignore
631
652
  config: (viteConfig) => {
632
653
  const plugins = [];
633
654
  const content = [
@@ -939,7 +960,6 @@ async function listFilesRecursively({
939
960
  }
940
961
  var createConfig = async ({
941
962
  configManager,
942
- database,
943
963
  apiURL,
944
964
  plugins = [],
945
965
  noWatch,
@@ -999,6 +1019,8 @@ var createConfig = async ({
999
1019
  if (configManager.config.build.basePath) {
1000
1020
  basePath = configManager.config.build.basePath;
1001
1021
  }
1022
+ const fullVersion = configManager.getTinaGraphQLVersion();
1023
+ const version2 = `${fullVersion.major}.${fullVersion.minor}`;
1002
1024
  const config2 = {
1003
1025
  root: configManager.spaRootPath,
1004
1026
  base: `/${basePath ? `${(0, import_normalize_path2.default)(basePath)}/` : ""}${(0, import_normalize_path2.default)(
@@ -1010,15 +1032,33 @@ var createConfig = async ({
1010
1032
  dedupe: ["graphql", "tinacms", "react", "react-dom", "react-router-dom"]
1011
1033
  },
1012
1034
  define: {
1035
+ /**
1036
+ * Since we prebuild the config.ts, it's possible for modules to be loaded which make
1037
+ * use of `process`. The main scenario where this is an issue is when co-locating schema
1038
+ * definitions with source files, and specifically source files which impor from NextJS.
1039
+ *
1040
+ * Some examples of what NextJS uses for `process.env` are:
1041
+ * - `process.env.__NEXT_TRAILING_SLASH`
1042
+ * - `process.env.__NEXT_CROSS_ORIGIN`
1043
+ * - `process.env.__NEXT_I18N_SUPPORT`
1044
+ *
1045
+ * Also, interestingly some of the advice for handling this doesn't work, references to replacing
1046
+ * `process.env` with `{}` are problematic, because browsers don't understand the `{}.` syntax,
1047
+ * but node does. This was a surprise, but using `new Object()` seems to do the trick.
1048
+ */
1013
1049
  "process.env": `new Object(${JSON.stringify(publicEnv)})`,
1050
+ // Used by picomatch https://github.com/micromatch/picomatch/blob/master/lib/utils.js#L4
1014
1051
  "process.platform": `"${process.platform}"`,
1015
1052
  __API_URL__: `"${apiURL}"`,
1016
1053
  __BASE_PATH__: `"${((_e = (_d = configManager.config) == null ? void 0 : _d.build) == null ? void 0 : _e.basePath) || ""}"`,
1017
- __TINA_GRAPHQL_VERSION__: `"${configManager.getTinaGraphQLVersion()}"`
1054
+ __TINA_GRAPHQL_VERSION__: version2
1018
1055
  },
1019
1056
  logLevel: "error",
1057
+ // Vite import warnings are noisy
1020
1058
  optimizeDeps: {
1021
1059
  force: true,
1060
+ // Not 100% sure why this isn't being picked up automatically, this works from within the monorepo
1061
+ // but breaks externally
1022
1062
  include: ["react/jsx-runtime", "react/jsx-dev-runtime"]
1023
1063
  },
1024
1064
  server: {
@@ -1026,6 +1066,7 @@ var createConfig = async ({
1026
1066
  watch: noWatch ? {
1027
1067
  ignored: ["**/*"]
1028
1068
  } : {
1069
+ // Ignore everything except for the alias fields we specified above
1029
1070
  ignored: [
1030
1071
  `${configManager.tinaFolderPath}/**/!(config.prebuild.jsx|_graphql.json)`
1031
1072
  ]
@@ -1041,8 +1082,13 @@ var createConfig = async ({
1041
1082
  rollupOptions
1042
1083
  },
1043
1084
  plugins: [
1085
+ /**
1086
+ * `splitVendorChunkPlugin` is needed because `tinacms` is quite large,
1087
+ * Vite's chunking strategy chokes on memory issues for smaller machines (ie. on CI).
1088
+ */
1044
1089
  (0, import_plugin_react.default)({
1045
1090
  babel: {
1091
+ // Supresses the warning [NOTE] babel The code generator has deoptimised the styling of
1046
1092
  compact: true
1047
1093
  }
1048
1094
  }),
@@ -1119,8 +1165,7 @@ var createMediaRouter = (config2) => {
1119
1165
  };
1120
1166
  var parseMediaFolder = (str) => {
1121
1167
  let returnString = str;
1122
- if (returnString.startsWith("/"))
1123
- returnString = returnString.substr(1);
1168
+ if (returnString.startsWith("/")) returnString = returnString.substr(1);
1124
1169
  if (returnString.endsWith("/"))
1125
1170
  returnString = returnString.substr(0, returnString.length - 1);
1126
1171
  return returnString;
@@ -1285,7 +1330,8 @@ var devServerEndPointsPlugin = ({
1285
1330
  configManager,
1286
1331
  apiURL,
1287
1332
  database,
1288
- searchIndex
1333
+ searchIndex,
1334
+ databaseLock
1289
1335
  }) => {
1290
1336
  const plug = {
1291
1337
  name: "graphql-endpoints",
@@ -1329,14 +1375,17 @@ var devServerEndPointsPlugin = ({
1329
1375
  }
1330
1376
  if (req.url === "/graphql") {
1331
1377
  const { query, variables } = req.body;
1332
- const result = await (0, import_graphql.resolve)({
1333
- config: {
1334
- useRelativeMedia: true
1335
- },
1336
- database,
1337
- query,
1338
- variables,
1339
- verbose: false
1378
+ let result;
1379
+ await databaseLock(async () => {
1380
+ result = await (0, import_graphql.resolve)({
1381
+ config: {
1382
+ useRelativeMedia: true
1383
+ },
1384
+ database,
1385
+ query,
1386
+ variables,
1387
+ verbose: false
1388
+ });
1340
1389
  });
1341
1390
  res.end(JSON.stringify(result));
1342
1391
  return;
@@ -1387,6 +1436,7 @@ function viteTransformExtension({
1387
1436
  return {
1388
1437
  code: res.code,
1389
1438
  map: null
1439
+ // TODO:
1390
1440
  };
1391
1441
  }
1392
1442
  }
@@ -1394,10 +1444,16 @@ function viteTransformExtension({
1394
1444
  }
1395
1445
 
1396
1446
  // src/next/commands/dev-command/server/index.ts
1397
- var createDevServer = async (configManager, database, searchIndex, apiURL, noWatch) => {
1447
+ var createDevServer = async (configManager, database, searchIndex, apiURL, noWatch, databaseLock) => {
1398
1448
  const plugins = [
1399
1449
  transformTsxPlugin({ configManager }),
1400
- devServerEndPointsPlugin({ apiURL, configManager, database, searchIndex }),
1450
+ devServerEndPointsPlugin({
1451
+ apiURL,
1452
+ configManager,
1453
+ database,
1454
+ searchIndex,
1455
+ databaseLock
1456
+ }),
1401
1457
  viteTransformExtension()
1402
1458
  ];
1403
1459
  return (0, import_vite3.createServer)(
@@ -1407,6 +1463,14 @@ var createDevServer = async (configManager, database, searchIndex, apiURL, noWat
1407
1463
  apiURL,
1408
1464
  plugins,
1409
1465
  noWatch,
1466
+ /**
1467
+ * Ensure Vite's import scan uses the spaMainPath as the input
1468
+ * so it properly finds everything. This is for dev only, and when
1469
+ * running the server outside of this monorepo vite fails to find
1470
+ * and optimize the imports, so you get errors about it not being
1471
+ * able to find an export from a module, and it's always a CJS
1472
+ * module that Vite would usually transform to an ES module.
1473
+ */
1410
1474
  rollupOptions: {
1411
1475
  input: configManager.spaMainPath,
1412
1476
  onwarn(warning, warn) {
@@ -1532,6 +1596,7 @@ var GenericSdkVisitor = class extends import_visitor_plugin_common.ClientSideBas
1532
1596
  node,
1533
1597
  documentVariableName,
1534
1598
  operationType,
1599
+ // This is the only line that is different
1535
1600
  operationResultType: `{data: ${operationResultType}, errors?: { message: string, locations: { line: number, column: number }[], path: string[] }[], variables: ${operationVariablesTypes}, query: string}`,
1536
1601
  operationVariablesTypes
1537
1602
  });
@@ -1580,6 +1645,8 @@ var plugin = (schema, documents, config2) => {
1580
1645
  const visitor = new GenericSdkVisitor(schema, allFragments, config2);
1581
1646
  const visitorResult = (0, import_graphql3.visit)(allAst, { leave: visitor });
1582
1647
  return {
1648
+ // We will take care of imports
1649
+ // prepend: visitor.getImports(),
1583
1650
  content: [
1584
1651
  visitor.fragments,
1585
1652
  ...visitorResult.definitions.filter((t) => typeof t === "string"),
@@ -1595,6 +1662,7 @@ var generateTypes = async (schema, queryPathGlob = process.cwd(), fragDocPath =
1595
1662
  docs = await loadGraphQLDocuments(queryPathGlob);
1596
1663
  fragDocs = await loadGraphQLDocuments(fragDocPath);
1597
1664
  const res = await (0, import_core.codegen)({
1665
+ // Filename is not used. This is because the typescript plugin returns a string instead of writing to a file.
1598
1666
  filename: process.cwd(),
1599
1667
  schema: (0, import_graphql5.parse)((0, import_graphql5.printSchema)(schema)),
1600
1668
  documents: [...docs, ...fragDocs],
@@ -1629,9 +1697,12 @@ var loadGraphQLDocuments = async (globPath) => {
1629
1697
  loaders: [new import_graphql_file_loader.GraphQLFileLoader()]
1630
1698
  });
1631
1699
  } catch (e) {
1632
- if ((e.message || "").includes(
1633
- "Unable to find any GraphQL type definitions for the following pointers:"
1634
- )) {
1700
+ if (
1701
+ // https://www.graphql-tools.com/docs/documents-loading#no-files-found
1702
+ (e.message || "").includes(
1703
+ "Unable to find any GraphQL type definitions for the following pointers:"
1704
+ )
1705
+ ) {
1635
1706
  } else {
1636
1707
  throw e;
1637
1708
  }
@@ -1788,16 +1859,14 @@ var Codegen = class {
1788
1859
  const branch = (_a = this.configManager.config) == null ? void 0 : _a.branch;
1789
1860
  const clientId = (_b = this.configManager.config) == null ? void 0 : _b.clientId;
1790
1861
  const token = (_c = this.configManager.config) == null ? void 0 : _c.token;
1791
- const version2 = this.configManager.getTinaGraphQLVersion();
1862
+ const fullVersion = this.configManager.getTinaGraphQLVersion();
1863
+ const version2 = `${fullVersion.major}.${fullVersion.minor}`;
1792
1864
  const baseUrl = ((_d = this.configManager.config.tinaioConfig) == null ? void 0 : _d.contentApiUrlOverride) || `https://${TINA_HOST}`;
1793
1865
  if ((!branch || !clientId || !token) && !this.port && !this.configManager.config.contentApiUrlOverride) {
1794
1866
  const missing = [];
1795
- if (!branch)
1796
- missing.push("branch");
1797
- if (!clientId)
1798
- missing.push("clientId");
1799
- if (!token)
1800
- missing.push("token");
1867
+ if (!branch) missing.push("branch");
1868
+ if (!clientId) missing.push("clientId");
1869
+ if (!token) missing.push("token");
1801
1870
  throw new Error(
1802
1871
  `Client not configured properly. Missing ${missing.join(
1803
1872
  ", "
@@ -1951,7 +2020,11 @@ schema {
1951
2020
  }
1952
2021
  };
1953
2022
  var maybeWarnFragmentSize = async (filepath) => {
1954
- if ((await import_fs_extra4.default.stat(filepath)).size > 100 * 1024) {
2023
+ if (
2024
+ // is the file bigger than 100kb?
2025
+ (await import_fs_extra4.default.stat(filepath)).size > // convert to 100 kb to bytes
2026
+ 100 * 1024
2027
+ ) {
1955
2028
  console.warn(
1956
2029
  "Warning: frags.gql is very large (>100kb). Consider setting the reference depth to 1 or 0. See code snippet below."
1957
2030
  );
@@ -1979,6 +2052,7 @@ var import_many_level = require("many-level");
1979
2052
  var import_memory_level = require("memory-level");
1980
2053
  var createDBServer = (port) => {
1981
2054
  const levelHost = new import_many_level.ManyLevelHost(
2055
+ // @ts-ignore
1982
2056
  new import_memory_level.MemoryLevel({
1983
2057
  valueEncoding: "json"
1984
2058
  })
@@ -2129,7 +2203,9 @@ var BaseCommand = class extends import_clipanion.Command {
2129
2203
  let subProc;
2130
2204
  if (this.subCommand) {
2131
2205
  subProc = await startSubprocess2({ command: this.subCommand });
2132
- logger.info(`Starting subprocess: ${import_chalk4.default.cyan(this.subCommand)}`);
2206
+ logger.info(
2207
+ `Running web application with command: ${import_chalk4.default.cyan(this.subCommand)}`
2208
+ );
2133
2209
  }
2134
2210
  function exitHandler(options, exitCode) {
2135
2211
  if (subProc) {
@@ -2253,6 +2329,7 @@ var import_search = require("@tinacms/search");
2253
2329
  var DevCommand = class extends BaseCommand {
2254
2330
  constructor() {
2255
2331
  super(...arguments);
2332
+ // NOTE: camelCase commands for string options don't work if there's an `=` used https://github.com/arcanis/clipanion/issues/141
2256
2333
  this.watchFolders = import_clipanion2.Option.String("-w,--watchFolders", {
2257
2334
  description: "DEPRECATED - a list of folders (relative to where this is being run) that the cli will watch for changes"
2258
2335
  });
@@ -2262,6 +2339,10 @@ var DevCommand = class extends BaseCommand {
2262
2339
  this.outputSearchIndexPath = import_clipanion2.Option.String("--outputSearchIndexPath", {
2263
2340
  description: "Path to write the search index to"
2264
2341
  });
2342
+ this.noServer = import_clipanion2.Option.Boolean("--no-server", false, {
2343
+ description: "Do not start the dev server"
2344
+ });
2345
+ this.indexingLock = new import_async_lock.default();
2265
2346
  }
2266
2347
  async catch(error) {
2267
2348
  logger.error("Error occured during tinacms dev");
@@ -2282,10 +2363,13 @@ var DevCommand = class extends BaseCommand {
2282
2363
  rootPath: this.rootPath,
2283
2364
  legacyNoSDK: this.noSDK
2284
2365
  });
2285
- logger.info("Starting Tina Dev Server");
2366
+ logger.info("\u{1F999} TinaCMS Dev Server is initializing...");
2286
2367
  this.logDeprecationWarnings();
2287
2368
  createDBServer(Number(this.datalayerPort));
2288
2369
  let database = null;
2370
+ const dbLock = async (fn) => {
2371
+ return this.indexingLock.acquire("Key", fn);
2372
+ };
2289
2373
  const setup = async ({ firstTime }) => {
2290
2374
  try {
2291
2375
  await configManager.processConfig();
@@ -2336,9 +2420,6 @@ var DevCommand = class extends BaseCommand {
2336
2420
  await import_fs_extra6.default.outputFile(filePath, tinaLockContent);
2337
2421
  }
2338
2422
  }
2339
- if (!this.noWatch) {
2340
- this.watchQueries(configManager, async () => await codegen2.execute());
2341
- }
2342
2423
  await this.indexContentWithSpinner({
2343
2424
  database,
2344
2425
  graphQLSchema: graphQLSchema2,
@@ -2348,6 +2429,13 @@ var DevCommand = class extends BaseCommand {
2348
2429
  if (!firstTime) {
2349
2430
  logger.error("Re-index complete");
2350
2431
  }
2432
+ if (!this.noWatch) {
2433
+ this.watchQueries(
2434
+ configManager,
2435
+ dbLock,
2436
+ async () => await codegen2.execute()
2437
+ );
2438
+ }
2351
2439
  return { apiURL: apiURL2, database, graphQLSchema: graphQLSchema2, tinaSchema: tinaSchema2 };
2352
2440
  } catch (e) {
2353
2441
  logger.error(`
@@ -2382,14 +2470,6 @@ ${dangerText(e.message)}
2382
2470
  tokenSplitRegex: (_d = (_c = configManager.config.search) == null ? void 0 : _c.tina) == null ? void 0 : _d.tokenSplitRegex
2383
2471
  });
2384
2472
  await searchIndexClient.onStartIndexing();
2385
- const server = await createDevServer(
2386
- configManager,
2387
- database,
2388
- searchIndexClient.searchIndex,
2389
- apiURL,
2390
- this.noWatch
2391
- );
2392
- await server.listen(Number(this.port));
2393
2473
  const searchIndexer = new import_search.SearchIndexer({
2394
2474
  batchSize: ((_e = configManager.config.search) == null ? void 0 : _e.indexBatchSize) || 100,
2395
2475
  bridge: new import_graphql10.FilesystemBridge(
@@ -2411,16 +2491,34 @@ ${dangerText(e.message)}
2411
2491
  await searchIndexClient.export(this.outputSearchIndexPath);
2412
2492
  }
2413
2493
  }
2494
+ if (this.noServer) {
2495
+ logger.info("--no-server option specified - Dev server not started");
2496
+ process.exit(0);
2497
+ }
2414
2498
  if (!this.noWatch) {
2415
2499
  this.watchContentFiles(
2416
2500
  configManager,
2417
2501
  database,
2502
+ dbLock,
2418
2503
  configManager.config.search && searchIndexer
2419
2504
  );
2505
+ }
2506
+ const server = await createDevServer(
2507
+ configManager,
2508
+ database,
2509
+ searchIndexClient.searchIndex,
2510
+ apiURL,
2511
+ this.noWatch,
2512
+ dbLock
2513
+ );
2514
+ await server.listen(Number(this.port));
2515
+ if (!this.noWatch) {
2420
2516
  import_chokidar.default.watch(configManager.watchList).on("change", async () => {
2421
- logger.info(`Tina config change detected, rebuilding`);
2422
- await setup({ firstTime: false });
2423
- server.ws.send({ type: "full-reload", path: "*" });
2517
+ await dbLock(async () => {
2518
+ logger.info(`Tina config change detected, rebuilding`);
2519
+ await setup({ firstTime: false });
2520
+ server.ws.send({ type: "full-reload", path: "*" });
2521
+ });
2424
2522
  });
2425
2523
  }
2426
2524
  const subItems = [];
@@ -2433,7 +2531,7 @@ ${dangerText(e.message)}
2433
2531
  const summaryItems = [
2434
2532
  {
2435
2533
  emoji: "\u{1F999}",
2436
- heading: "Tina Config",
2534
+ heading: "TinaCMS URLs",
2437
2535
  subItems: [
2438
2536
  {
2439
2537
  key: "CMS",
@@ -2468,14 +2566,28 @@ ${dangerText(e.message)}
2468
2566
  });
2469
2567
  }
2470
2568
  summary({
2471
- heading: "Tina Dev Server is running...",
2569
+ heading: "\u2705 \u{1F999} TinaCMS Dev Server is active:",
2472
2570
  items: [
2473
2571
  ...summaryItems
2572
+ // {
2573
+ // emoji: '📚',
2574
+ // heading: 'Useful links',
2575
+ // subItems: [
2576
+ // {
2577
+ // key: 'Custom queries',
2578
+ // value: 'https://tina.io/querying',
2579
+ // },
2580
+ // {
2581
+ // key: 'Visual editing',
2582
+ // value: 'https://tina.io/visual-editing',
2583
+ // },
2584
+ // ],
2585
+ // },
2474
2586
  ]
2475
2587
  });
2476
2588
  await this.startSubCommand();
2477
2589
  }
2478
- watchContentFiles(configManager, database, searchIndexer) {
2590
+ watchContentFiles(configManager, database, databaseLock, searchIndexer) {
2479
2591
  const collectionContentFiles = [];
2480
2592
  configManager.config.schema.collections.forEach((collection) => {
2481
2593
  const collectionGlob = `${import_path5.default.join(
@@ -2491,39 +2603,42 @@ ${dangerText(e.message)}
2491
2603
  if (!ready) {
2492
2604
  return;
2493
2605
  }
2494
- const pathFromRoot = configManager.printContentRelativePath(addedFile);
2495
- await database.indexContentByPaths([pathFromRoot]).catch(console.error);
2496
- if (searchIndexer) {
2497
- await searchIndexer.indexContentByPaths([pathFromRoot]).catch(console.error);
2498
- }
2606
+ await databaseLock(async () => {
2607
+ const pathFromRoot = configManager.printContentRelativePath(addedFile);
2608
+ await database.indexContentByPaths([pathFromRoot]).catch(console.error);
2609
+ if (searchIndexer) {
2610
+ await searchIndexer.indexContentByPaths([pathFromRoot]).catch(console.error);
2611
+ }
2612
+ });
2499
2613
  }).on("change", async (changedFile) => {
2500
2614
  const pathFromRoot = configManager.printContentRelativePath(changedFile);
2501
- await database.indexContentByPaths([pathFromRoot]).catch(console.error);
2502
- if (searchIndexer) {
2503
- await searchIndexer.indexContentByPaths([pathFromRoot]).catch(console.error);
2504
- }
2615
+ await databaseLock(async () => {
2616
+ await database.indexContentByPaths([pathFromRoot]).catch(console.error);
2617
+ if (searchIndexer) {
2618
+ await searchIndexer.indexContentByPaths([pathFromRoot]).catch(console.error);
2619
+ }
2620
+ });
2505
2621
  }).on("unlink", async (removedFile) => {
2506
2622
  const pathFromRoot = configManager.printContentRelativePath(removedFile);
2507
- await database.deleteContentByPaths([pathFromRoot]).catch(console.error);
2508
- if (searchIndexer) {
2509
- await searchIndexer.deleteIndexContent([pathFromRoot]).catch(console.error);
2510
- }
2623
+ await databaseLock(async () => {
2624
+ await database.deleteContentByPaths([pathFromRoot]).catch(console.error);
2625
+ if (searchIndexer) {
2626
+ await searchIndexer.deleteIndexContent([pathFromRoot]).catch(console.error);
2627
+ }
2628
+ });
2511
2629
  });
2512
2630
  }
2513
- watchQueries(configManager, callback) {
2514
- let ready = false;
2515
- import_chokidar.default.watch(configManager.userQueriesAndFragmentsGlob).on("ready", () => {
2516
- ready = true;
2517
- }).on("add", async (addedFile) => {
2518
- await callback();
2519
- }).on("change", async (changedFile) => {
2520
- await callback();
2521
- }).on("unlink", async (removedFile) => {
2522
- await callback();
2523
- });
2631
+ watchQueries(configManager, databaseLock, callback) {
2632
+ const executeCallback = async (_) => {
2633
+ await databaseLock(async () => {
2634
+ await callback();
2635
+ });
2636
+ };
2637
+ import_chokidar.default.watch(configManager.userQueriesAndFragmentsGlob).on("add", executeCallback).on("change", executeCallback).on("unlink", executeCallback);
2524
2638
  }
2525
2639
  };
2526
2640
  DevCommand.paths = [["dev"], ["server:start"]];
2641
+ // Prevent indexes and reads occurring at once
2527
2642
  DevCommand.usage = import_clipanion2.Command.Usage({
2528
2643
  category: `Commands`,
2529
2644
  description: `Builds Tina and starts the dev server`,
@@ -2582,7 +2697,7 @@ var buildProductionSpa = async (configManager, database, apiURL) => {
2582
2697
  // src/next/commands/build-command/index.ts
2583
2698
  var import_schema_tools2 = require("@tinacms/schema-tools");
2584
2699
  var import_graphql12 = require("graphql");
2585
- var import_core2 = require("@graphql-inspector/core");
2700
+ var import_core3 = require("@graphql-inspector/core");
2586
2701
 
2587
2702
  // src/next/commands/build-command/waitForDB.ts
2588
2703
  var import_progress = __toESM(require("progress"));
@@ -2684,6 +2799,20 @@ var waitForDB = async (config2, apiUrl, previewName, verbose) => {
2684
2799
 
2685
2800
  // src/next/commands/build-command/index.ts
2686
2801
  var import_search2 = require("@tinacms/search");
2802
+
2803
+ // src/utils/index.ts
2804
+ var import_core2 = require("@graphql-inspector/core");
2805
+ var getFaqLink = (type) => {
2806
+ switch (type) {
2807
+ case import_core2.ChangeType.FieldRemoved: {
2808
+ return "https://tina.io/docs/introduction/faq#how-do-i-resolve-the-local-graphql-schema-doesnt-match-the-remote-graphql-schema-errors";
2809
+ }
2810
+ default:
2811
+ return null;
2812
+ }
2813
+ };
2814
+
2815
+ // src/next/commands/build-command/index.ts
2687
2816
  var BuildCommand = class extends BaseCommand {
2688
2817
  constructor() {
2689
2818
  super(...arguments);
@@ -2699,6 +2828,9 @@ var BuildCommand = class extends BaseCommand {
2699
2828
  this.tinaGraphQLVersion = import_clipanion3.Option.String("--tina-graphql-version", {
2700
2829
  description: "Specify the version of @tinacms/graphql to use (defaults to latest)"
2701
2830
  });
2831
+ /**
2832
+ * This option allows the user to skip the tina cloud checks if they want to. This could be useful for mismatched GraphQL versions or if they want to build only using the local client and never connect to Tina Cloud
2833
+ */
2702
2834
  this.skipCloudChecks = import_clipanion3.Option.Boolean("--skip-cloud-checks", false, {
2703
2835
  description: "Skips checking the provided cloud config."
2704
2836
  });
@@ -2804,14 +2936,15 @@ ${dangerText(e.message)}
2804
2936
  database,
2805
2937
  null,
2806
2938
  apiURL,
2807
- true
2939
+ true,
2940
+ (lockedFn) => lockedFn()
2808
2941
  );
2809
2942
  await server.listen(Number(this.port));
2810
2943
  console.log("server listening on port", this.port);
2811
2944
  }
2812
2945
  const skipCloudChecks = this.skipCloudChecks || configManager.hasSelfHostedConfig();
2813
2946
  if (!skipCloudChecks) {
2814
- const { hasUpstream } = await this.checkClientInfo(
2947
+ const { hasUpstream, timestamp } = await this.checkClientInfo(
2815
2948
  configManager,
2816
2949
  codegen2.productionUrl,
2817
2950
  this.previewBaseBranch
@@ -2839,14 +2972,16 @@ ${dangerText(e.message)}
2839
2972
  await this.checkGraphqlSchema(
2840
2973
  configManager,
2841
2974
  database,
2842
- codegen2.productionUrl
2975
+ codegen2.productionUrl,
2976
+ timestamp
2843
2977
  );
2844
2978
  await this.checkTinaSchema(
2845
2979
  configManager,
2846
2980
  database,
2847
2981
  codegen2.productionUrl,
2848
2982
  this.previewName,
2849
- this.verbose
2983
+ this.verbose,
2984
+ timestamp
2850
2985
  );
2851
2986
  }
2852
2987
  await buildProductionSpa(configManager, database, codegen2.productionUrl);
@@ -2965,11 +3100,13 @@ ${dangerText(e.message)}
2965
3100
  const bar2 = new import_progress2.default("Checking clientId and token. :prog", 1);
2966
3101
  let branchKnown = false;
2967
3102
  let hasUpstream = false;
3103
+ let timestamp;
2968
3104
  try {
2969
3105
  const res = await request({
2970
3106
  token,
2971
3107
  url
2972
3108
  });
3109
+ timestamp = res.timestamp || 0;
2973
3110
  bar2.tick({
2974
3111
  prog: "\u2705"
2975
3112
  });
@@ -3011,7 +3148,8 @@ ${dangerText(e.message)}
3011
3148
  prog: "\u2705"
3012
3149
  });
3013
3150
  return {
3014
- hasUpstream
3151
+ hasUpstream,
3152
+ timestamp
3015
3153
  };
3016
3154
  }
3017
3155
  for (let i = 0; i <= 5; i++) {
@@ -3101,14 +3239,14 @@ ${dangerText(e.message)}
3101
3239
  throw e;
3102
3240
  }
3103
3241
  }
3104
- async checkGraphqlSchema(configManager, database, apiURL) {
3242
+ async checkGraphqlSchema(configManager, database, apiURL, timestamp) {
3105
3243
  const bar2 = new import_progress2.default(
3106
3244
  "Checking local GraphQL Schema matches server. :prog",
3107
3245
  1
3108
3246
  );
3109
3247
  const { config: config2 } = configManager;
3110
3248
  const token = config2.token;
3111
- const remoteSchema = await fetchRemoteGraphqlSchema({
3249
+ const { remoteSchema, remoteProjectVersion } = await fetchRemoteGraphqlSchema({
3112
3250
  url: apiURL,
3113
3251
  token
3114
3252
  });
@@ -3128,7 +3266,7 @@ Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3128
3266
  const localSchemaDocument = await database.getGraphQLSchemaFromBridge();
3129
3267
  const localGraphqlSchema = (0, import_graphql12.buildASTSchema)(localSchemaDocument);
3130
3268
  try {
3131
- const diffResult = await (0, import_core2.diff)(localGraphqlSchema, remoteGqlSchema);
3269
+ const diffResult = await (0, import_core3.diff)(localGraphqlSchema, remoteGqlSchema);
3132
3270
  if (diffResult.length === 0) {
3133
3271
  bar2.tick({
3134
3272
  prog: "\u2705"
@@ -3137,12 +3275,30 @@ Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3137
3275
  bar2.tick({
3138
3276
  prog: "\u274C"
3139
3277
  });
3140
- let errorMessage = `The local GraphQL schema doesn't match the remote GraphQL schema. Please push up your changes to GitHub to update your remote GraphQL schema.`;
3141
- if (config2 == null ? void 0 : config2.branch) {
3142
- errorMessage += `
3278
+ const type = diffResult[0].type;
3279
+ const reason = diffResult[0].message;
3280
+ const errorLevel = diffResult[0].criticality.level;
3281
+ const faqLink = getFaqLink(type);
3282
+ const tinaGraphQLVersion = configManager.getTinaGraphQLVersion();
3283
+ let errorMessage = `The local GraphQL schema doesn't match the remote GraphQL schema. Please push up your changes to GitHub to update your remote GraphQL schema. ${faqLink && `
3284
+ Check out '${faqLink}' for possible solutions.`}`;
3285
+ errorMessage += `
3143
3286
 
3144
- Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3287
+ Additional info:
3288
+
3289
+ `;
3290
+ if (config2 == null ? void 0 : config2.branch) {
3291
+ errorMessage += ` Branch: ${config2.branch}, Client ID: ${config2.clientId}
3292
+ `;
3145
3293
  }
3294
+ errorMessage += ` Local GraphQL version: ${tinaGraphQLVersion.fullVersion} / Remote GraphQL version: ${remoteProjectVersion}
3295
+ `;
3296
+ errorMessage += ` Last indexed at: ${new Date(
3297
+ timestamp
3298
+ ).toUTCString()}
3299
+ `;
3300
+ errorMessage += ` Reason: [${errorLevel} - ${type}] ${reason}
3301
+ `;
3146
3302
  throw new Error(errorMessage);
3147
3303
  }
3148
3304
  } catch (e) {
@@ -3157,7 +3313,7 @@ Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3157
3313
  }
3158
3314
  }
3159
3315
  }
3160
- async checkTinaSchema(configManager, database, apiURL, previewName, verbose) {
3316
+ async checkTinaSchema(configManager, database, apiURL, previewName, verbose, timestamp) {
3161
3317
  const bar2 = new import_progress2.default(
3162
3318
  "Checking local Tina Schema matches server. :prog",
3163
3319
  1
@@ -3206,11 +3362,19 @@ Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3206
3362
  prog: "\u274C"
3207
3363
  });
3208
3364
  let errorMessage = `The local Tina schema doesn't match the remote Tina schema. Please push up your changes to GitHub to update your remote tina schema.`;
3209
- if (config2 == null ? void 0 : config2.branch) {
3210
- errorMessage += `
3365
+ errorMessage += `
3211
3366
 
3212
- Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3367
+ Additional info:
3368
+
3369
+ `;
3370
+ if (config2 == null ? void 0 : config2.branch) {
3371
+ errorMessage += ` Branch: ${config2.branch}, Client ID: ${config2.clientId}
3372
+ `;
3213
3373
  }
3374
+ errorMessage += ` Last indexed at: ${new Date(
3375
+ timestamp
3376
+ ).toUTCString()}
3377
+ `;
3214
3378
  throw new Error(errorMessage);
3215
3379
  }
3216
3380
  }
@@ -3280,7 +3444,11 @@ var fetchRemoteGraphqlSchema = async ({
3280
3444
  body
3281
3445
  });
3282
3446
  const data = await res.json();
3283
- return data == null ? void 0 : data.data;
3447
+ return {
3448
+ remoteSchema: data == null ? void 0 : data.data,
3449
+ remoteRuntimeVersion: res.headers.get("tinacms-grapqhl-version"),
3450
+ remoteProjectVersion: res.headers.get("tinacms-graphql-project-version")
3451
+ };
3284
3452
  };
3285
3453
  var fetchSchemaSha = async ({
3286
3454
  url,
@@ -3404,6 +3572,7 @@ var auditDocuments = async (args) => {
3404
3572
  logger.error(import_chalk5.default.red(err.message));
3405
3573
  if (err.originalError.originalError) {
3406
3574
  logger.error(
3575
+ // @ts-ignore FIXME: this doesn't seem right
3407
3576
  import_chalk5.default.red(` ${err.originalError.originalError.message}`)
3408
3577
  );
3409
3578
  }
@@ -3609,7 +3778,9 @@ var detectEnvironment = async ({
3609
3778
  const usingSrc = import_fs_extra8.default.pathExistsSync(import_path7.default.join(baseDir, "src")) && (import_fs_extra8.default.pathExistsSync(import_path7.default.join(baseDir, "src", "app")) || import_fs_extra8.default.pathExistsSync(import_path7.default.join(baseDir, "src", "pages")));
3610
3779
  const tinaFolder = import_path7.default.join(baseDir, "tina");
3611
3780
  const tinaConfigExists = Boolean(
3612
- await import_fs_extra8.default.pathExists(tinaFolder) && (await import_fs_extra8.default.readdir(tinaFolder)).find((x) => x.includes("config"))
3781
+ // Does the tina folder exist?
3782
+ await import_fs_extra8.default.pathExists(tinaFolder) && // Does the tina folder contain a config file?
3783
+ (await import_fs_extra8.default.readdir(tinaFolder)).find((x) => x.includes("config"))
3613
3784
  );
3614
3785
  const pagesDir = [baseDir, usingSrc ? "src" : false, "pages"].filter(
3615
3786
  Boolean
@@ -3844,6 +4015,7 @@ var supportedDatabaseAdapters = {
3844
4015
  {
3845
4016
  from: "mongodb",
3846
4017
  imported: [],
4018
+ // not explicitly imported
3847
4019
  packageName: "mongodb"
3848
4020
  }
3849
4021
  ]
@@ -3916,6 +4088,10 @@ var chooseDatabaseAdapter = async ({
3916
4088
  title: "MongoDB",
3917
4089
  value: "mongodb"
3918
4090
  }
4091
+ // {
4092
+ // title: "I'll create my own database adapter",
4093
+ // value: 'other',
4094
+ // },
3919
4095
  ]
3920
4096
  }
3921
4097
  ]);
@@ -4193,6 +4369,7 @@ async function configure(env, opts) {
4193
4369
  packageManager,
4194
4370
  forestryMigrate: false,
4195
4371
  isLocalEnvVarName: "TINA_PUBLIC_IS_LOCAL",
4372
+ // TODO: give this a better default
4196
4373
  typescript: false
4197
4374
  };
4198
4375
  if (config2.framework.name === "next") {
@@ -4296,15 +4473,25 @@ var import_js_yaml = __toESM(require("js-yaml"));
4296
4473
  var import_zod = __toESM(require("zod"));
4297
4474
 
4298
4475
  // src/cmds/forestry-migrate/util/errorSingleton.ts
4299
- var ErrorSingleton = class {
4476
+ var ErrorSingleton = class _ErrorSingleton {
4477
+ /**
4478
+ * The Singleton's constructor should always be private to prevent direct
4479
+ * construction calls with the `new` operator.
4480
+ */
4300
4481
  constructor() {
4301
4482
  }
4483
+ /**
4484
+ * The static method that controls the access to the singleton instance.
4485
+ *
4486
+ * This implementation let you subclass the Singleton class while keeping
4487
+ * just one instance of each subclass around.
4488
+ */
4302
4489
  static getInstance() {
4303
- if (!ErrorSingleton.instance) {
4304
- ErrorSingleton.instance = new ErrorSingleton();
4305
- ErrorSingleton.instance.collectionNameErrors = [];
4490
+ if (!_ErrorSingleton.instance) {
4491
+ _ErrorSingleton.instance = new _ErrorSingleton();
4492
+ _ErrorSingleton.instance.collectionNameErrors = [];
4306
4493
  }
4307
- return ErrorSingleton.instance;
4494
+ return _ErrorSingleton.instance;
4308
4495
  }
4309
4496
  addErrorName(error) {
4310
4497
  this.collectionNameErrors.push(error);
@@ -4347,8 +4534,7 @@ var makeFieldsWithInternalCode = ({
4347
4534
  if (hasBody) {
4348
4535
  return [bodyField, `__TINA_INTERNAL__:::...${field}():::`];
4349
4536
  } else {
4350
- if (spread)
4351
- return `__TINA_INTERNAL__:::...${field}():::`;
4537
+ if (spread) return `__TINA_INTERNAL__:::...${field}():::`;
4352
4538
  return `__TINA_INTERNAL__:::${field}():::`;
4353
4539
  }
4354
4540
  };
@@ -4432,6 +4618,7 @@ var forestryConfigSchema = import_zod.default.object({
4432
4618
  )
4433
4619
  });
4434
4620
  var forestryFieldWithoutField = import_zod.default.object({
4621
+ // TODO: maybe better type this?
4435
4622
  type: import_zod.default.union([
4436
4623
  import_zod.default.literal("text"),
4437
4624
  import_zod.default.literal("datetime"),
@@ -4455,6 +4642,7 @@ var forestryFieldWithoutField = import_zod.default.object({
4455
4642
  default: import_zod.default.any().optional(),
4456
4643
  template: import_zod.default.string().optional(),
4457
4644
  config: import_zod.default.object({
4645
+ // min and max are used for lists
4458
4646
  min: import_zod.default.number().optional().nullable(),
4459
4647
  max: import_zod.default.number().optional().nullable(),
4460
4648
  required: import_zod.default.boolean().optional().nullable(),
@@ -4468,6 +4656,7 @@ var forestryFieldWithoutField = import_zod.default.object({
4468
4656
  import_zod.default.literal("pages"),
4469
4657
  import_zod.default.literal("documents"),
4470
4658
  import_zod.default.literal("simple"),
4659
+ // TODO: I want to ignore this key if its invalid
4471
4660
  import_zod.default.string()
4472
4661
  ]).optional().nullable(),
4473
4662
  section: import_zod.default.string().optional().nullable()
@@ -4503,6 +4692,7 @@ var transformForestryFieldsToTinaFields = ({
4503
4692
  }
4504
4693
  let field;
4505
4694
  switch (forestryField2.type) {
4695
+ // Single filed types
4506
4696
  case "text":
4507
4697
  field = {
4508
4698
  type: "string",
@@ -4582,6 +4772,7 @@ var transformForestryFieldsToTinaFields = ({
4582
4772
  );
4583
4773
  }
4584
4774
  break;
4775
+ // List Types
4585
4776
  case "list":
4586
4777
  field = {
4587
4778
  type: "string",
@@ -4604,6 +4795,7 @@ var transformForestryFieldsToTinaFields = ({
4604
4795
  }
4605
4796
  };
4606
4797
  break;
4798
+ // Object (Group) types
4607
4799
  case "field_group":
4608
4800
  field = {
4609
4801
  type: "object",
@@ -4644,6 +4836,7 @@ var transformForestryFieldsToTinaFields = ({
4644
4836
  });
4645
4837
  const fieldsString = stringifyLabelWithField(template2.label);
4646
4838
  const t = {
4839
+ // @ts-ignore
4647
4840
  fields: makeFieldsWithInternalCode({
4648
4841
  hasBody: false,
4649
4842
  field: fieldsString
@@ -4681,6 +4874,7 @@ var transformForestryFieldsToTinaFields = ({
4681
4874
  spread: true
4682
4875
  });
4683
4876
  tinaFields.push(
4877
+ // @ts-ignore
4684
4878
  field2
4685
4879
  );
4686
4880
  break;
@@ -4740,6 +4934,7 @@ var parseSections = ({ val }) => {
4740
4934
 
4741
4935
  // src/cmds/forestry-migrate/index.ts
4742
4936
  var BODY_FIELD = {
4937
+ // This is the body field
4743
4938
  type: "rich-text",
4744
4939
  name: "body",
4745
4940
  label: "Body of Document",
@@ -4798,8 +4993,7 @@ var generateAllTemplates = async ({
4798
4993
  };
4799
4994
  var generateCollectionFromForestrySection = (args) => {
4800
4995
  const { section, templateMap } = args;
4801
- if (section.read_only)
4802
- return;
4996
+ if (section.read_only) return;
4803
4997
  let format3 = "md";
4804
4998
  if (section.new_doc_ext) {
4805
4999
  const ext = checkExt(section.new_doc_ext);
@@ -4866,12 +5060,14 @@ var generateCollectionFromForestrySection = (args) => {
4866
5060
  if (((forestryTemplates == null ? void 0 : forestryTemplates.length) || 0) > 1) {
4867
5061
  c = {
4868
5062
  ...baseCollection,
5063
+ // @ts-expect-error
4869
5064
  templates: forestryTemplates.map((tem) => {
4870
5065
  const currentTemplate = templateMap.get(tem);
4871
5066
  const fieldsString = stringifyLabelWithField(
4872
5067
  currentTemplate.templateObj.label
4873
5068
  );
4874
5069
  return {
5070
+ // fields: [BODY_FIELD],
4875
5071
  fields: makeFieldsWithInternalCode({
4876
5072
  hasBody,
4877
5073
  field: fieldsString,
@@ -4889,6 +5085,8 @@ var generateCollectionFromForestrySection = (args) => {
4889
5085
  const fieldsString = stringifyLabelWithField(template.templateObj.label);
4890
5086
  c = {
4891
5087
  ...baseCollection,
5088
+ // fields: [BODY_FIELD],
5089
+ // @ts-expect-error
4892
5090
  fields: makeFieldsWithInternalCode({
4893
5091
  field: fieldsString,
4894
5092
  hasBody,
@@ -5636,6 +5834,7 @@ var makeImportsVisitor = (sourceFile, importMap) => (ctx) => (node) => {
5636
5834
  ) : [];
5637
5835
  const newImports = [
5638
5836
  .../* @__PURE__ */ new Set([
5837
+ // we use Set to remove duplicates
5639
5838
  ...existingImports,
5640
5839
  ...imports
5641
5840
  ])
@@ -5790,6 +5989,7 @@ var addSelfHostedTinaAuthToConfig = async (config2, configFile) => {
5790
5989
  );
5791
5990
  const { configImports, configAuthProviderClass, extraTinaCollections } = config2.authProvider;
5792
5991
  const importMap = {
5992
+ // iterate over configImports and add them to the import map
5793
5993
  ...configImports.reduce((acc, { from, imported }) => {
5794
5994
  acc[from] = imported;
5795
5995
  return acc;
@@ -5964,7 +6164,13 @@ async function apply({
5964
6164
  config: config2
5965
6165
  });
5966
6166
  }
5967
- if (env.tinaConfigExists && params.isBackendInit && config2.hosting === "self-host" && (((_a = config2.authProvider) == null ? void 0 : _a.name) || "") !== "tina-cloud") {
6167
+ if (
6168
+ // if the config was just generated we do not need to update the config file because it will be generated correctly
6169
+ env.tinaConfigExists && // Are we running tinacms init backend
6170
+ params.isBackendInit && // Do the user choose the 'self-host' option
6171
+ config2.hosting === "self-host" && // the user did not choose the 'tina-cloud' auth provider
6172
+ (((_a = config2.authProvider) == null ? void 0 : _a.name) || "") !== "tina-cloud"
6173
+ ) {
5968
6174
  await addSelfHostedTinaAuthToConfig(config2, env.generatedFiles["config"]);
5969
6175
  }
5970
6176
  logNextSteps({
@@ -6257,6 +6463,7 @@ var other = ({ packageManager }) => {
6257
6463
  const packageManagers = {
6258
6464
  pnpm: `pnpm`,
6259
6465
  npm: `npx`,
6466
+ // npx is the way to run executables that aren't in your "scripts"
6260
6467
  yarn: `yarn`
6261
6468
  };
6262
6469
  return `${packageManagers[packageManager]} tinacms dev -c "<your dev command>"`;
@@ -6269,6 +6476,7 @@ var frameworkDevCmds = {
6269
6476
  const packageManagers = {
6270
6477
  pnpm: `pnpm`,
6271
6478
  npm: `npm run`,
6479
+ // npx is the way to run executables that aren't in your "scripts"
6272
6480
  yarn: `yarn`
6273
6481
  };
6274
6482
  return `${packageManagers[packageManager]} dev`;
@@ -6525,6 +6733,4 @@ cli.register(SearchIndexCommand);
6525
6733
  cli.register(import_clipanion8.Builtins.DefinitionsCommand);
6526
6734
  cli.register(import_clipanion8.Builtins.HelpCommand);
6527
6735
  cli.register(import_clipanion8.Builtins.VersionCommand);
6528
- var src_default = cli;
6529
- // Annotate the CommonJS export names for ESM import in node:
6530
- 0 && (module.exports = {});
6736
+ var index_default = cli;
@@ -21,19 +21,24 @@ export declare class BuildCommand extends BaseCommand {
21
21
  execute(): Promise<number | void>;
22
22
  checkClientInfo(configManager: ConfigManager, apiURL: string, previewBaseBranch?: string): Promise<{
23
23
  hasUpstream: boolean;
24
+ timestamp: number;
24
25
  }>;
25
26
  syncProject(configManager: ConfigManager, apiURL: string, options?: {
26
27
  upstreamBranch?: string;
27
28
  previewBaseBranch?: string;
28
29
  previewName?: string;
29
30
  }): Promise<void>;
30
- checkGraphqlSchema(configManager: ConfigManager, database: Database, apiURL: string): Promise<void>;
31
- checkTinaSchema(configManager: ConfigManager, database: Database, apiURL: string, previewName: string, verbose: boolean): Promise<void>;
31
+ checkGraphqlSchema(configManager: ConfigManager, database: Database, apiURL: string, timestamp: number): Promise<void>;
32
+ checkTinaSchema(configManager: ConfigManager, database: Database, apiURL: string, previewName: string, verbose: boolean, timestamp: number): Promise<void>;
32
33
  }
33
34
  export declare const fetchRemoteGraphqlSchema: ({ url, token, }: {
34
35
  url: string;
35
36
  token?: string;
36
- }) => Promise<any>;
37
+ }) => Promise<{
38
+ remoteSchema: any;
39
+ remoteRuntimeVersion: string;
40
+ remoteProjectVersion: string;
41
+ }>;
37
42
  export declare const fetchSchemaSha: ({ url, token, }: {
38
43
  url: string;
39
44
  token?: string;
@@ -1,3 +1,4 @@
1
+ import AsyncLock from 'async-lock';
1
2
  import { Database } from '@tinacms/graphql';
2
3
  import { ConfigManager } from '../../config-manager';
3
4
  import { BaseCommand } from '../baseCommands';
@@ -7,10 +8,12 @@ export declare class DevCommand extends BaseCommand {
7
8
  watchFolders: string;
8
9
  noWatch: boolean;
9
10
  outputSearchIndexPath: string;
11
+ noServer: boolean;
12
+ indexingLock: AsyncLock;
10
13
  static usage: import("clipanion").Usage;
11
14
  catch(error: any): Promise<void>;
12
15
  logDeprecationWarnings(): void;
13
16
  execute(): Promise<number | void>;
14
- watchContentFiles(configManager: ConfigManager, database: Database, searchIndexer?: SearchIndexer): void;
15
- watchQueries(configManager: ConfigManager, callback: () => Promise<string>): void;
17
+ watchContentFiles(configManager: ConfigManager, database: Database, databaseLock: (fn: () => Promise<void>) => Promise<void>, searchIndexer?: SearchIndexer): void;
18
+ watchQueries(configManager: ConfigManager, databaseLock: (fn: () => Promise<void>) => Promise<void>, callback: () => Promise<string>): void;
16
19
  }
@@ -1,3 +1,3 @@
1
1
  import type { Database } from '@tinacms/graphql';
2
2
  import { ConfigManager } from '../../../config-manager';
3
- export declare const createDevServer: (configManager: ConfigManager, database: Database, searchIndex: any, apiURL: string, noWatch: boolean) => Promise<import("vite").ViteDevServer>;
3
+ export declare const createDevServer: (configManager: ConfigManager, database: Database, searchIndex: any, apiURL: string, noWatch: boolean, databaseLock: (fn: () => Promise<void>) => Promise<void>) => Promise<import("vite").ViteDevServer>;
@@ -55,7 +55,12 @@ export declare class ConfigManager {
55
55
  shouldSkipSDK(): boolean;
56
56
  processConfig(): Promise<void>;
57
57
  getTinaFolderPath(rootPath: any): Promise<string>;
58
- getTinaGraphQLVersion(): string;
58
+ getTinaGraphQLVersion(): {
59
+ fullVersion: string;
60
+ major: string;
61
+ minor: string;
62
+ patch: string;
63
+ };
59
64
  printGeneratedClientFilePath(): string;
60
65
  printGeneratedTypesFilePath(): string;
61
66
  printoutputHTMLFilePath(): string;
@@ -22,7 +22,7 @@ interface StaticMediaItem {
22
22
  export interface StaticMedia {
23
23
  [offset: string]: StaticMediaItem[];
24
24
  }
25
- export declare const createConfig: ({ configManager, database, apiURL, plugins, noWatch, rollupOptions, }: {
25
+ export declare const createConfig: ({ configManager, apiURL, plugins, noWatch, rollupOptions, }: {
26
26
  configManager: ConfigManager;
27
27
  database: Database;
28
28
  apiURL: string;
@@ -7,11 +7,12 @@ import type { ConfigManager } from '../config-manager';
7
7
  export declare const transformTsxPlugin: ({ configManager: _configManager, }: {
8
8
  configManager: ConfigManager;
9
9
  }) => Plugin;
10
- export declare const devServerEndPointsPlugin: ({ configManager, apiURL, database, searchIndex, }: {
10
+ export declare const devServerEndPointsPlugin: ({ configManager, apiURL, database, searchIndex, databaseLock, }: {
11
11
  apiURL: string;
12
12
  database: Database;
13
13
  configManager: ConfigManager;
14
14
  searchIndex: any;
15
+ databaseLock: (fn: () => Promise<void>) => Promise<void>;
15
16
  }) => Plugin;
16
17
  export interface ViteSvgrOptions {
17
18
  /**
@@ -1,5 +1,5 @@
1
1
  /**
2
2
 
3
3
  */
4
- import http from 'http';
4
+ import http from 'node:http';
5
5
  export declare const gqlServer: (database: any, verbose: boolean) => Promise<http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>>;
@@ -1,4 +1,6 @@
1
1
  /**
2
2
 
3
3
  */
4
+ import { ChangeType } from '@graphql-inspector/core';
4
5
  export declare const parseMediaFolder: (str: string) => string;
6
+ export declare const getFaqLink: (type: ChangeType) => string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinacms/cli",
3
- "version": "0.0.0-97d38ab-20241104224426",
3
+ "version": "0.0.0-98df118-20250227044321",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
6
6
  "files": [
@@ -26,7 +26,6 @@
26
26
  "@types/cors": "2.8.5",
27
27
  "@types/crypto-js": "^4.2.2",
28
28
  "@types/express": "^4.17.21",
29
- "@types/express-graphql": "^0.9.0",
30
29
  "@types/figlet": "1.2.0",
31
30
  "@types/fs-extra": "^11.0.4",
32
31
  "@types/jest": "26.0.4",
@@ -38,24 +37,25 @@
38
37
  "@types/prompts": "^2.4.9",
39
38
  "@types/yup": "^0.32.0",
40
39
  "jest": "^29.7.0",
41
- "@tinacms/scripts": "1.3.0"
40
+ "@tinacms/scripts": "0.0.0-98df118-20250227044321"
42
41
  },
43
42
  "dependencies": {
44
43
  "@graphql-codegen/core": "^2.6.8",
45
44
  "@graphql-codegen/plugin-helpers": "latest",
46
- "@graphql-codegen/typescript": "^4.0.9",
47
- "@graphql-codegen/typescript-operations": "^4.2.3",
45
+ "@graphql-codegen/typescript": "^4.1.3",
46
+ "@graphql-codegen/typescript-operations": "^4.4.1",
48
47
  "@graphql-codegen/visitor-plugin-common": "^4.1.2",
49
48
  "@graphql-inspector/core": "^4.2.2",
50
49
  "@graphql-tools/graphql-file-loader": "^7.5.17",
51
50
  "@graphql-tools/load": "^7.8.14",
52
- "@rollup/pluginutils": "^5.1.2",
51
+ "@rollup/pluginutils": "^5.1.4",
53
52
  "@svgr/core": "8.1.0",
54
53
  "@tailwindcss/aspect-ratio": "^0.4.2",
55
54
  "@tailwindcss/container-queries": "^0.1.1",
56
- "@tailwindcss/typography": "^0.5.15",
55
+ "@tailwindcss/typography": "^0.5.16",
57
56
  "@vitejs/plugin-react": "3.1.0",
58
57
  "altair-express-middleware": "^7.3.6",
58
+ "async-lock": "^1.4.1",
59
59
  "auto-bind": "^4.0.0",
60
60
  "body-parser": "^1.20.3",
61
61
  "busboy": "^1.6.0",
@@ -65,9 +65,9 @@
65
65
  "clipanion": "^3.2.1",
66
66
  "cors": "^2.8.5",
67
67
  "crypto-js": "^4.2.0",
68
- "dotenv": "^16.4.5",
69
- "esbuild": "^0.18.20",
70
- "fs-extra": "^11.2.0",
68
+ "dotenv": "^16.4.7",
69
+ "esbuild": "^0.24.2",
70
+ "fs-extra": "^11.3.0",
71
71
  "graphql": "15.8.0",
72
72
  "js-yaml": "^4.1.0",
73
73
  "log4js": "^6.9.1",
@@ -78,19 +78,19 @@
78
78
  "prettier": "^2.8.8",
79
79
  "progress": "^2.0.3",
80
80
  "prompts": "^2.4.2",
81
- "readable-stream": "^4.5.2",
82
- "tailwindcss": "^3.4.13",
81
+ "readable-stream": "^4.7.0",
82
+ "tailwindcss": "^3.4.17",
83
83
  "typanion": "3.13.0",
84
- "typescript": "^5.6.2",
85
- "vite": "^4.5.5",
86
- "yup": "^1.4.0",
87
- "zod": "^3.23.8",
88
- "@tinacms/app": "0.0.0-97d38ab-20241104224426",
89
- "@tinacms/graphql": "0.0.0-97d38ab-20241104224426",
90
- "@tinacms/schema-tools": "0.0.0-97d38ab-20241104224426",
91
- "@tinacms/metrics": "1.0.7",
92
- "@tinacms/search": "0.0.0-97d38ab-20241104224426",
93
- "tinacms": "0.0.0-97d38ab-20241104224426"
84
+ "typescript": "^5.7.3",
85
+ "vite": "^4.5.9",
86
+ "yup": "^1.6.1",
87
+ "zod": "^3.24.2",
88
+ "@tinacms/app": "0.0.0-98df118-20250227044321",
89
+ "@tinacms/metrics": "1.0.9",
90
+ "@tinacms/search": "0.0.0-98df118-20250227044321",
91
+ "tinacms": "0.0.0-98df118-20250227044321",
92
+ "@tinacms/graphql": "0.0.0-98df118-20250227044321",
93
+ "@tinacms/schema-tools": "0.0.0-98df118-20250227044321"
94
94
  },
95
95
  "publishConfig": {
96
96
  "registry": "https://registry.npmjs.org"