@tinacms/cli 0.0.0-d69e892-20241003042309 → 0.0.0-d79e661-20250217013436

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -17,6 +17,10 @@ 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
  ));
@@ -31,12 +35,13 @@ module.exports = __toCommonJS(src_exports);
31
35
  var import_clipanion8 = require("clipanion");
32
36
 
33
37
  // package.json
34
- var version = "1.6.8";
38
+ var version = "1.8.4";
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
- var import_path6 = __toESM(require("path"));
44
+ var import_path5 = __toESM(require("path"));
40
45
  var import_chokidar = __toESM(require("chokidar"));
41
46
  var import_graphql10 = require("@tinacms/graphql");
42
47
 
@@ -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>
@@ -612,20 +632,23 @@ var CONFIRMATION_TEXT = import_chalk3.default.dim("enter to confirm");
612
632
  var import_vite3 = require("vite");
613
633
 
614
634
  // src/next/vite/index.ts
615
- var import_path2 = __toESM(require("path"));
635
+ var import_node_path2 = __toESM(require("path"));
636
+ var import_plugin_react = __toESM(require("@vitejs/plugin-react"));
616
637
  var import_fs_extra2 = __toESM(require("fs-extra"));
638
+ var import_normalize_path2 = __toESM(require("normalize-path"));
617
639
  var import_vite = require("vite");
618
- var import_plugin_react = __toESM(require("@vitejs/plugin-react"));
619
640
 
620
641
  // src/next/vite/tailwind.ts
642
+ var import_node_path = __toESM(require("path"));
643
+ var import_aspect_ratio = __toESM(require("@tailwindcss/aspect-ratio"));
644
+ var import_container_queries = __toESM(require("@tailwindcss/container-queries"));
645
+ var import_typography = __toESM(require("@tailwindcss/typography"));
621
646
  var import_tailwindcss = __toESM(require("tailwindcss"));
622
647
  var import_defaultTheme = __toESM(require("tailwindcss/defaultTheme.js"));
623
- var import_typography = __toESM(require("@tailwindcss/typography"));
624
- var import_aspect_ratio = __toESM(require("@tailwindcss/aspect-ratio"));
625
- var import_node_path = __toESM(require("path"));
626
648
  var tinaTailwind = (spaPath, prebuildFilePath) => {
627
649
  return {
628
650
  name: "vite-plugin-tina",
651
+ // @ts-ignore
629
652
  config: (viteConfig) => {
630
653
  const plugins = [];
631
654
  const content = [
@@ -866,7 +889,11 @@ var tinaTailwind = (spaPath, prebuildFilePath) => {
866
889
  }
867
890
  },
868
891
  content,
869
- plugins: [(0, import_typography.default)({ className: "tina-prose" }), import_aspect_ratio.default]
892
+ plugins: [
893
+ (0, import_typography.default)({ className: "tina-prose" }),
894
+ import_aspect_ratio.default,
895
+ import_container_queries.default
896
+ ]
870
897
  });
871
898
  plugins.push(tw);
872
899
  return {
@@ -881,13 +908,12 @@ var tinaTailwind = (spaPath, prebuildFilePath) => {
881
908
  };
882
909
 
883
910
  // src/next/vite/index.ts
884
- var import_normalize_path2 = __toESM(require("normalize-path"));
885
911
  async function listFilesRecursively({
886
912
  directoryPath,
887
913
  config: config2,
888
914
  roothPath
889
915
  }) {
890
- const fullDirectoryPath = import_path2.default.join(
916
+ const fullDirectoryPath = import_node_path2.default.join(
891
917
  roothPath,
892
918
  config2.publicFolder,
893
919
  directoryPath
@@ -899,23 +925,23 @@ async function listFilesRecursively({
899
925
  const items = await import_fs_extra2.default.readdir(fullDirectoryPath);
900
926
  const staticMediaItems = [];
901
927
  for (const item of items) {
902
- const itemPath = import_path2.default.join(fullDirectoryPath, item);
928
+ const itemPath = import_node_path2.default.join(fullDirectoryPath, item);
903
929
  const stats = await import_fs_extra2.default.promises.lstat(itemPath);
904
930
  const staticMediaItem = {
905
931
  id: item,
906
932
  filename: item,
907
933
  type: stats.isDirectory() ? "dir" : "file",
908
934
  directory: `${directoryPath.replace(config2.mediaRoot, "")}`,
909
- src: `/${import_path2.default.join(directoryPath, item)}`,
935
+ src: `/${import_node_path2.default.join(directoryPath, item)}`,
910
936
  thumbnails: {
911
- "75x75": `/${import_path2.default.join(directoryPath, item)}`,
912
- "400x400": `/${import_path2.default.join(directoryPath, item)}`,
913
- "1000x1000": `/${import_path2.default.join(directoryPath, item)}`
937
+ "75x75": `/${import_node_path2.default.join(directoryPath, item)}`,
938
+ "400x400": `/${import_node_path2.default.join(directoryPath, item)}`,
939
+ "1000x1000": `/${import_node_path2.default.join(directoryPath, item)}`
914
940
  }
915
941
  };
916
942
  if (stats.isDirectory()) {
917
943
  staticMediaItem.children = await listFilesRecursively({
918
- directoryPath: import_path2.default.join(directoryPath, item),
944
+ directoryPath: import_node_path2.default.join(directoryPath, item),
919
945
  config: config2,
920
946
  roothPath
921
947
  });
@@ -934,7 +960,6 @@ async function listFilesRecursively({
934
960
  }
935
961
  var createConfig = async ({
936
962
  configManager,
937
- database,
938
963
  apiURL,
939
964
  plugins = [],
940
965
  noWatch,
@@ -958,7 +983,7 @@ var createConfig = async ({
958
983
  }
959
984
  }
960
985
  });
961
- const staticMediaPath = import_path2.default.join(
986
+ const staticMediaPath = import_node_path2.default.join(
962
987
  configManager.generatedFolderPath,
963
988
  "static-media.json"
964
989
  );
@@ -976,13 +1001,13 @@ var createConfig = async ({
976
1001
  TINA_IMPORT: configManager.prebuildFilePath,
977
1002
  SCHEMA_IMPORT: configManager.generatedGraphQLJSONPath,
978
1003
  STATIC_MEDIA_IMPORT: staticMediaPath,
979
- crypto: import_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts"),
980
- fs: import_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts"),
981
- os: import_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts"),
982
- path: import_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts")
1004
+ crypto: import_node_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts"),
1005
+ fs: import_node_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts"),
1006
+ os: import_node_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts"),
1007
+ path: import_node_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts")
983
1008
  };
984
1009
  if (configManager.shouldSkipSDK()) {
985
- alias["CLIENT_IMPORT"] = import_path2.default.join(
1010
+ alias["CLIENT_IMPORT"] = import_node_path2.default.join(
986
1011
  configManager.spaRootPath,
987
1012
  "src",
988
1013
  "dummy-client.ts"
@@ -994,6 +1019,8 @@ var createConfig = async ({
994
1019
  if (configManager.config.build.basePath) {
995
1020
  basePath = configManager.config.build.basePath;
996
1021
  }
1022
+ const fullVersion = configManager.getTinaGraphQLVersion();
1023
+ const version2 = `${fullVersion.major}.${fullVersion.minor}`;
997
1024
  const config2 = {
998
1025
  root: configManager.spaRootPath,
999
1026
  base: `/${basePath ? `${(0, import_normalize_path2.default)(basePath)}/` : ""}${(0, import_normalize_path2.default)(
@@ -1005,15 +1032,33 @@ var createConfig = async ({
1005
1032
  dedupe: ["graphql", "tinacms", "react", "react-dom", "react-router-dom"]
1006
1033
  },
1007
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
+ */
1008
1049
  "process.env": `new Object(${JSON.stringify(publicEnv)})`,
1050
+ // Used by picomatch https://github.com/micromatch/picomatch/blob/master/lib/utils.js#L4
1009
1051
  "process.platform": `"${process.platform}"`,
1010
1052
  __API_URL__: `"${apiURL}"`,
1011
1053
  __BASE_PATH__: `"${((_e = (_d = configManager.config) == null ? void 0 : _d.build) == null ? void 0 : _e.basePath) || ""}"`,
1012
- __TINA_GRAPHQL_VERSION__: `"${configManager.getTinaGraphQLVersion()}"`
1054
+ __TINA_GRAPHQL_VERSION__: version2
1013
1055
  },
1014
1056
  logLevel: "error",
1057
+ // Vite import warnings are noisy
1015
1058
  optimizeDeps: {
1016
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
1017
1062
  include: ["react/jsx-runtime", "react/jsx-dev-runtime"]
1018
1063
  },
1019
1064
  server: {
@@ -1021,6 +1066,7 @@ var createConfig = async ({
1021
1066
  watch: noWatch ? {
1022
1067
  ignored: ["**/*"]
1023
1068
  } : {
1069
+ // Ignore everything except for the alias fields we specified above
1024
1070
  ignored: [
1025
1071
  `${configManager.tinaFolderPath}/**/!(config.prebuild.jsx|_graphql.json)`
1026
1072
  ]
@@ -1036,8 +1082,13 @@ var createConfig = async ({
1036
1082
  rollupOptions
1037
1083
  },
1038
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
+ */
1039
1089
  (0, import_plugin_react.default)({
1040
1090
  babel: {
1091
+ // Supresses the warning [NOTE] babel The code generator has deoptimised the styling of
1041
1092
  compact: true
1042
1093
  }
1043
1094
  }),
@@ -1054,17 +1105,17 @@ var import_pluginutils = require("@rollup/pluginutils");
1054
1105
  var import_fs = __toESM(require("fs"));
1055
1106
  var import_vite2 = require("vite");
1056
1107
  var import_esbuild = require("esbuild");
1057
- var import_path4 = __toESM(require("path"));
1108
+ var import_path3 = __toESM(require("path"));
1058
1109
  var import_body_parser = __toESM(require("body-parser"));
1059
1110
  var import_cors = __toESM(require("cors"));
1060
1111
  var import_graphql = require("@tinacms/graphql");
1061
1112
 
1062
1113
  // src/next/commands/dev-command/server/media.ts
1063
1114
  var import_fs_extra3 = __toESM(require("fs-extra"));
1064
- var import_path3 = __toESM(require("path"));
1115
+ var import_path2 = __toESM(require("path"));
1065
1116
  var import_busboy = __toESM(require("busboy"));
1066
1117
  var createMediaRouter = (config2) => {
1067
- const mediaFolder = import_path3.default.join(
1118
+ const mediaFolder = import_path2.default.join(
1068
1119
  config2.rootPath,
1069
1120
  config2.publicFolder,
1070
1121
  config2.mediaRoot
@@ -1092,8 +1143,8 @@ var createMediaRouter = (config2) => {
1092
1143
  bb.on("file", async (_name, file, _info) => {
1093
1144
  var _a;
1094
1145
  const fullPath = decodeURI((_a = req.url) == null ? void 0 : _a.slice("/media/upload/".length));
1095
- const saveTo = import_path3.default.join(mediaFolder, ...fullPath.split("/"));
1096
- await import_fs_extra3.default.ensureDir(import_path3.default.dirname(saveTo));
1146
+ const saveTo = import_path2.default.join(mediaFolder, ...fullPath.split("/"));
1147
+ await import_fs_extra3.default.ensureDir(import_path2.default.dirname(saveTo));
1097
1148
  file.pipe(import_fs_extra3.default.createWriteStream(saveTo));
1098
1149
  });
1099
1150
  bb.on("error", (error) => {
@@ -1114,8 +1165,7 @@ var createMediaRouter = (config2) => {
1114
1165
  };
1115
1166
  var parseMediaFolder = (str) => {
1116
1167
  let returnString = str;
1117
- if (returnString.startsWith("/"))
1118
- returnString = returnString.substr(1);
1168
+ if (returnString.startsWith("/")) returnString = returnString.substr(1);
1119
1169
  if (returnString.endsWith("/"))
1120
1170
  returnString = returnString.substr(0, returnString.length - 1);
1121
1171
  return returnString;
@@ -1128,7 +1178,7 @@ var MediaModel = class {
1128
1178
  }
1129
1179
  async listMedia(args) {
1130
1180
  try {
1131
- const folderPath = (0, import_path3.join)(
1181
+ const folderPath = (0, import_path2.join)(
1132
1182
  this.rootPath,
1133
1183
  this.publicFolder,
1134
1184
  this.mediaRoot,
@@ -1143,7 +1193,7 @@ var MediaModel = class {
1143
1193
  }
1144
1194
  const filesStr = await import_fs_extra3.default.readdir(folderPath);
1145
1195
  const filesProm = filesStr.map(async (file) => {
1146
- const filePath = (0, import_path3.join)(folderPath, file);
1196
+ const filePath = (0, import_path2.join)(folderPath, file);
1147
1197
  const stat = await import_fs_extra3.default.stat(filePath);
1148
1198
  let src = `/${file}`;
1149
1199
  const isFile = stat.isFile();
@@ -1200,7 +1250,7 @@ var MediaModel = class {
1200
1250
  }
1201
1251
  async deleteMedia(args) {
1202
1252
  try {
1203
- const file = (0, import_path3.join)(
1253
+ const file = (0, import_path2.join)(
1204
1254
  this.rootPath,
1205
1255
  this.publicFolder,
1206
1256
  this.mediaRoot,
@@ -1265,7 +1315,7 @@ var transformTsxPlugin = ({
1265
1315
  const plug = {
1266
1316
  name: "transform-tsx",
1267
1317
  async transform(code, id) {
1268
- const extName = import_path4.default.extname(id);
1318
+ const extName = import_path3.default.extname(id);
1269
1319
  if (extName.startsWith(".tsx") || extName.startsWith(".ts")) {
1270
1320
  const result = await (0, import_esbuild.transform)(code, { loader: "tsx" });
1271
1321
  return {
@@ -1280,7 +1330,8 @@ var devServerEndPointsPlugin = ({
1280
1330
  configManager,
1281
1331
  apiURL,
1282
1332
  database,
1283
- searchIndex
1333
+ searchIndex,
1334
+ databaseLock
1284
1335
  }) => {
1285
1336
  const plug = {
1286
1337
  name: "graphql-endpoints",
@@ -1324,14 +1375,17 @@ var devServerEndPointsPlugin = ({
1324
1375
  }
1325
1376
  if (req.url === "/graphql") {
1326
1377
  const { query, variables } = req.body;
1327
- const result = await (0, import_graphql.resolve)({
1328
- config: {
1329
- useRelativeMedia: true
1330
- },
1331
- database,
1332
- query,
1333
- variables,
1334
- 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
+ });
1335
1389
  });
1336
1390
  res.end(JSON.stringify(result));
1337
1391
  return;
@@ -1382,6 +1436,7 @@ function viteTransformExtension({
1382
1436
  return {
1383
1437
  code: res.code,
1384
1438
  map: null
1439
+ // TODO:
1385
1440
  };
1386
1441
  }
1387
1442
  }
@@ -1389,10 +1444,16 @@ function viteTransformExtension({
1389
1444
  }
1390
1445
 
1391
1446
  // src/next/commands/dev-command/server/index.ts
1392
- var createDevServer = async (configManager, database, searchIndex, apiURL, noWatch) => {
1447
+ var createDevServer = async (configManager, database, searchIndex, apiURL, noWatch, databaseLock) => {
1393
1448
  const plugins = [
1394
1449
  transformTsxPlugin({ configManager }),
1395
- devServerEndPointsPlugin({ apiURL, configManager, database, searchIndex }),
1450
+ devServerEndPointsPlugin({
1451
+ apiURL,
1452
+ configManager,
1453
+ database,
1454
+ searchIndex,
1455
+ databaseLock
1456
+ }),
1396
1457
  viteTransformExtension()
1397
1458
  ];
1398
1459
  return (0, import_vite3.createServer)(
@@ -1402,6 +1463,14 @@ var createDevServer = async (configManager, database, searchIndex, apiURL, noWat
1402
1463
  apiURL,
1403
1464
  plugins,
1404
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
+ */
1405
1474
  rollupOptions: {
1406
1475
  input: configManager.spaMainPath,
1407
1476
  onwarn(warning, warn) {
@@ -1417,7 +1486,7 @@ var createDevServer = async (configManager, database, searchIndex, apiURL, noWat
1417
1486
 
1418
1487
  // src/next/codegen/index.ts
1419
1488
  var import_fs_extra4 = __toESM(require("fs-extra"));
1420
- var import_path5 = __toESM(require("path"));
1489
+ var import_path4 = __toESM(require("path"));
1421
1490
  var import_graphql6 = require("graphql");
1422
1491
 
1423
1492
  // src/next/codegen/codegen/index.ts
@@ -1527,6 +1596,7 @@ var GenericSdkVisitor = class extends import_visitor_plugin_common.ClientSideBas
1527
1596
  node,
1528
1597
  documentVariableName,
1529
1598
  operationType,
1599
+ // This is the only line that is different
1530
1600
  operationResultType: `{data: ${operationResultType}, errors?: { message: string, locations: { line: number, column: number }[], path: string[] }[], variables: ${operationVariablesTypes}, query: string}`,
1531
1601
  operationVariablesTypes
1532
1602
  });
@@ -1575,6 +1645,8 @@ var plugin = (schema, documents, config2) => {
1575
1645
  const visitor = new GenericSdkVisitor(schema, allFragments, config2);
1576
1646
  const visitorResult = (0, import_graphql3.visit)(allAst, { leave: visitor });
1577
1647
  return {
1648
+ // We will take care of imports
1649
+ // prepend: visitor.getImports(),
1578
1650
  content: [
1579
1651
  visitor.fragments,
1580
1652
  ...visitorResult.definitions.filter((t) => typeof t === "string"),
@@ -1590,6 +1662,7 @@ var generateTypes = async (schema, queryPathGlob = process.cwd(), fragDocPath =
1590
1662
  docs = await loadGraphQLDocuments(queryPathGlob);
1591
1663
  fragDocs = await loadGraphQLDocuments(fragDocPath);
1592
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.
1593
1666
  filename: process.cwd(),
1594
1667
  schema: (0, import_graphql5.parse)((0, import_graphql5.printSchema)(schema)),
1595
1668
  documents: [...docs, ...fragDocs],
@@ -1624,9 +1697,12 @@ var loadGraphQLDocuments = async (globPath) => {
1624
1697
  loaders: [new import_graphql_file_loader.GraphQLFileLoader()]
1625
1698
  });
1626
1699
  } catch (e) {
1627
- if ((e.message || "").includes(
1628
- "Unable to find any GraphQL type definitions for the following pointers:"
1629
- )) {
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
+ ) {
1630
1706
  } else {
1631
1707
  throw e;
1632
1708
  }
@@ -1663,11 +1739,11 @@ var Codegen = class {
1663
1739
  this.noClientBuildCache = noClientBuildCache;
1664
1740
  }
1665
1741
  async writeConfigFile(fileName, data) {
1666
- const filePath = import_path5.default.join(this.configManager.generatedFolderPath, fileName);
1742
+ const filePath = import_path4.default.join(this.configManager.generatedFolderPath, fileName);
1667
1743
  await import_fs_extra4.default.ensureFile(filePath);
1668
1744
  await import_fs_extra4.default.outputFile(filePath, data);
1669
1745
  if (this.configManager.hasSeparateContentRoot()) {
1670
- const filePath2 = import_path5.default.join(
1746
+ const filePath2 = import_path4.default.join(
1671
1747
  this.configManager.generatedFolderPathContentRepo,
1672
1748
  fileName
1673
1749
  );
@@ -1783,16 +1859,14 @@ var Codegen = class {
1783
1859
  const branch = (_a = this.configManager.config) == null ? void 0 : _a.branch;
1784
1860
  const clientId = (_b = this.configManager.config) == null ? void 0 : _b.clientId;
1785
1861
  const token = (_c = this.configManager.config) == null ? void 0 : _c.token;
1786
- const version2 = this.configManager.getTinaGraphQLVersion();
1862
+ const fullVersion = this.configManager.getTinaGraphQLVersion();
1863
+ const version2 = `${fullVersion.major}.${fullVersion.minor}`;
1787
1864
  const baseUrl = ((_d = this.configManager.config.tinaioConfig) == null ? void 0 : _d.contentApiUrlOverride) || `https://${TINA_HOST}`;
1788
1865
  if ((!branch || !clientId || !token) && !this.port && !this.configManager.config.contentApiUrlOverride) {
1789
1866
  const missing = [];
1790
- if (!branch)
1791
- missing.push("branch");
1792
- if (!clientId)
1793
- missing.push("clientId");
1794
- if (!token)
1795
- missing.push("token");
1867
+ if (!branch) missing.push("branch");
1868
+ if (!clientId) missing.push("clientId");
1869
+ if (!token) missing.push("token");
1796
1870
  throw new Error(
1797
1871
  `Client not configured properly. Missing ${missing.join(
1798
1872
  ", "
@@ -1946,7 +2020,11 @@ schema {
1946
2020
  }
1947
2021
  };
1948
2022
  var maybeWarnFragmentSize = async (filepath) => {
1949
- 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
+ ) {
1950
2028
  console.warn(
1951
2029
  "Warning: frags.gql is very large (>100kb). Consider setting the reference depth to 1 or 0. See code snippet below."
1952
2030
  );
@@ -1974,6 +2052,7 @@ var import_many_level = require("many-level");
1974
2052
  var import_memory_level = require("memory-level");
1975
2053
  var createDBServer = (port) => {
1976
2054
  const levelHost = new import_many_level.ManyLevelHost(
2055
+ // @ts-ignore
1977
2056
  new import_memory_level.MemoryLevel({
1978
2057
  valueEncoding: "json"
1979
2058
  })
@@ -2124,7 +2203,9 @@ var BaseCommand = class extends import_clipanion.Command {
2124
2203
  let subProc;
2125
2204
  if (this.subCommand) {
2126
2205
  subProc = await startSubprocess2({ command: this.subCommand });
2127
- 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
+ );
2128
2209
  }
2129
2210
  function exitHandler(options, exitCode) {
2130
2211
  if (subProc) {
@@ -2204,7 +2285,7 @@ var BaseCommand = class extends import_clipanion.Command {
2204
2285
  pathFilter
2205
2286
  });
2206
2287
  const tinaPathUpdates = modified.filter(
2207
- (path13) => path13.startsWith(".tina/__generated__/_schema.json") || path13.startsWith("tina/tina-lock.json")
2288
+ (path14) => path14.startsWith(".tina/__generated__/_schema.json") || path14.startsWith("tina/tina-lock.json")
2208
2289
  );
2209
2290
  if (tinaPathUpdates.length > 0) {
2210
2291
  res = await database.indexContent({
@@ -2248,6 +2329,7 @@ var import_search = require("@tinacms/search");
2248
2329
  var DevCommand = class extends BaseCommand {
2249
2330
  constructor() {
2250
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
2251
2333
  this.watchFolders = import_clipanion2.Option.String("-w,--watchFolders", {
2252
2334
  description: "DEPRECATED - a list of folders (relative to where this is being run) that the cli will watch for changes"
2253
2335
  });
@@ -2257,6 +2339,7 @@ var DevCommand = class extends BaseCommand {
2257
2339
  this.outputSearchIndexPath = import_clipanion2.Option.String("--outputSearchIndexPath", {
2258
2340
  description: "Path to write the search index to"
2259
2341
  });
2342
+ this.indexingLock = new import_async_lock.default();
2260
2343
  }
2261
2344
  async catch(error) {
2262
2345
  logger.error("Error occured during tinacms dev");
@@ -2277,10 +2360,13 @@ var DevCommand = class extends BaseCommand {
2277
2360
  rootPath: this.rootPath,
2278
2361
  legacyNoSDK: this.noSDK
2279
2362
  });
2280
- logger.info("Starting Tina Dev Server");
2363
+ logger.info("\u{1F999} TinaCMS Dev Server is initializing...");
2281
2364
  this.logDeprecationWarnings();
2282
2365
  createDBServer(Number(this.datalayerPort));
2283
2366
  let database = null;
2367
+ const dbLock = async (fn) => {
2368
+ return this.indexingLock.acquire("Key", fn);
2369
+ };
2284
2370
  const setup = async ({ firstTime }) => {
2285
2371
  try {
2286
2372
  await configManager.processConfig();
@@ -2319,21 +2405,18 @@ var DevCommand = class extends BaseCommand {
2319
2405
  graphql: graphqlSchemaObject
2320
2406
  });
2321
2407
  import_fs_extra6.default.writeFileSync(
2322
- import_path6.default.join(configManager.tinaFolderPath, tinaLockFilename),
2408
+ import_path5.default.join(configManager.tinaFolderPath, tinaLockFilename),
2323
2409
  tinaLockContent
2324
2410
  );
2325
2411
  if (configManager.hasSeparateContentRoot()) {
2326
2412
  const rootPath = await configManager.getTinaFolderPath(
2327
2413
  configManager.contentRootPath
2328
2414
  );
2329
- const filePath = import_path6.default.join(rootPath, tinaLockFilename);
2415
+ const filePath = import_path5.default.join(rootPath, tinaLockFilename);
2330
2416
  await import_fs_extra6.default.ensureFile(filePath);
2331
2417
  await import_fs_extra6.default.outputFile(filePath, tinaLockContent);
2332
2418
  }
2333
2419
  }
2334
- if (!this.noWatch) {
2335
- this.watchQueries(configManager, async () => await codegen2.execute());
2336
- }
2337
2420
  await this.indexContentWithSpinner({
2338
2421
  database,
2339
2422
  graphQLSchema: graphQLSchema2,
@@ -2343,6 +2426,13 @@ var DevCommand = class extends BaseCommand {
2343
2426
  if (!firstTime) {
2344
2427
  logger.error("Re-index complete");
2345
2428
  }
2429
+ if (!this.noWatch) {
2430
+ this.watchQueries(
2431
+ configManager,
2432
+ dbLock,
2433
+ async () => await codegen2.execute()
2434
+ );
2435
+ }
2346
2436
  return { apiURL: apiURL2, database, graphQLSchema: graphQLSchema2, tinaSchema: tinaSchema2 };
2347
2437
  } catch (e) {
2348
2438
  logger.error(`
@@ -2377,14 +2467,6 @@ ${dangerText(e.message)}
2377
2467
  tokenSplitRegex: (_d = (_c = configManager.config.search) == null ? void 0 : _c.tina) == null ? void 0 : _d.tokenSplitRegex
2378
2468
  });
2379
2469
  await searchIndexClient.onStartIndexing();
2380
- const server = await createDevServer(
2381
- configManager,
2382
- database,
2383
- searchIndexClient.searchIndex,
2384
- apiURL,
2385
- this.noWatch
2386
- );
2387
- await server.listen(Number(this.port));
2388
2470
  const searchIndexer = new import_search.SearchIndexer({
2389
2471
  batchSize: ((_e = configManager.config.search) == null ? void 0 : _e.indexBatchSize) || 100,
2390
2472
  bridge: new import_graphql10.FilesystemBridge(
@@ -2410,12 +2492,26 @@ ${dangerText(e.message)}
2410
2492
  this.watchContentFiles(
2411
2493
  configManager,
2412
2494
  database,
2495
+ dbLock,
2413
2496
  configManager.config.search && searchIndexer
2414
2497
  );
2498
+ }
2499
+ const server = await createDevServer(
2500
+ configManager,
2501
+ database,
2502
+ searchIndexClient.searchIndex,
2503
+ apiURL,
2504
+ this.noWatch,
2505
+ dbLock
2506
+ );
2507
+ await server.listen(Number(this.port));
2508
+ if (!this.noWatch) {
2415
2509
  import_chokidar.default.watch(configManager.watchList).on("change", async () => {
2416
- logger.info(`Tina config change detected, rebuilding`);
2417
- await setup({ firstTime: false });
2418
- server.ws.send({ type: "full-reload", path: "*" });
2510
+ await dbLock(async () => {
2511
+ logger.info(`Tina config change detected, rebuilding`);
2512
+ await setup({ firstTime: false });
2513
+ server.ws.send({ type: "full-reload", path: "*" });
2514
+ });
2419
2515
  });
2420
2516
  }
2421
2517
  const subItems = [];
@@ -2428,7 +2524,7 @@ ${dangerText(e.message)}
2428
2524
  const summaryItems = [
2429
2525
  {
2430
2526
  emoji: "\u{1F999}",
2431
- heading: "Tina Config",
2527
+ heading: "TinaCMS URLs",
2432
2528
  subItems: [
2433
2529
  {
2434
2530
  key: "CMS",
@@ -2463,17 +2559,31 @@ ${dangerText(e.message)}
2463
2559
  });
2464
2560
  }
2465
2561
  summary({
2466
- heading: "Tina Dev Server is running...",
2562
+ heading: "\u2705 \u{1F999} TinaCMS Dev Server is active:",
2467
2563
  items: [
2468
2564
  ...summaryItems
2565
+ // {
2566
+ // emoji: '📚',
2567
+ // heading: 'Useful links',
2568
+ // subItems: [
2569
+ // {
2570
+ // key: 'Custom queries',
2571
+ // value: 'https://tina.io/querying',
2572
+ // },
2573
+ // {
2574
+ // key: 'Visual editing',
2575
+ // value: 'https://tina.io/visual-editing',
2576
+ // },
2577
+ // ],
2578
+ // },
2469
2579
  ]
2470
2580
  });
2471
2581
  await this.startSubCommand();
2472
2582
  }
2473
- watchContentFiles(configManager, database, searchIndexer) {
2583
+ watchContentFiles(configManager, database, databaseLock, searchIndexer) {
2474
2584
  const collectionContentFiles = [];
2475
2585
  configManager.config.schema.collections.forEach((collection) => {
2476
- const collectionGlob = `${import_path6.default.join(
2586
+ const collectionGlob = `${import_path5.default.join(
2477
2587
  configManager.contentRootPath,
2478
2588
  collection.path
2479
2589
  )}/**/*.${collection.format || "md"}`;
@@ -2486,39 +2596,42 @@ ${dangerText(e.message)}
2486
2596
  if (!ready) {
2487
2597
  return;
2488
2598
  }
2489
- const pathFromRoot = configManager.printContentRelativePath(addedFile);
2490
- await database.indexContentByPaths([pathFromRoot]).catch(console.error);
2491
- if (searchIndexer) {
2492
- await searchIndexer.indexContentByPaths([pathFromRoot]).catch(console.error);
2493
- }
2599
+ await databaseLock(async () => {
2600
+ const pathFromRoot = configManager.printContentRelativePath(addedFile);
2601
+ await database.indexContentByPaths([pathFromRoot]).catch(console.error);
2602
+ if (searchIndexer) {
2603
+ await searchIndexer.indexContentByPaths([pathFromRoot]).catch(console.error);
2604
+ }
2605
+ });
2494
2606
  }).on("change", async (changedFile) => {
2495
2607
  const pathFromRoot = configManager.printContentRelativePath(changedFile);
2496
- await database.indexContentByPaths([pathFromRoot]).catch(console.error);
2497
- if (searchIndexer) {
2498
- await searchIndexer.indexContentByPaths([pathFromRoot]).catch(console.error);
2499
- }
2608
+ await databaseLock(async () => {
2609
+ await database.indexContentByPaths([pathFromRoot]).catch(console.error);
2610
+ if (searchIndexer) {
2611
+ await searchIndexer.indexContentByPaths([pathFromRoot]).catch(console.error);
2612
+ }
2613
+ });
2500
2614
  }).on("unlink", async (removedFile) => {
2501
2615
  const pathFromRoot = configManager.printContentRelativePath(removedFile);
2502
- await database.deleteContentByPaths([pathFromRoot]).catch(console.error);
2503
- if (searchIndexer) {
2504
- await searchIndexer.deleteIndexContent([pathFromRoot]).catch(console.error);
2505
- }
2616
+ await databaseLock(async () => {
2617
+ await database.deleteContentByPaths([pathFromRoot]).catch(console.error);
2618
+ if (searchIndexer) {
2619
+ await searchIndexer.deleteIndexContent([pathFromRoot]).catch(console.error);
2620
+ }
2621
+ });
2506
2622
  });
2507
2623
  }
2508
- watchQueries(configManager, callback) {
2509
- let ready = false;
2510
- import_chokidar.default.watch(configManager.userQueriesAndFragmentsGlob).on("ready", () => {
2511
- ready = true;
2512
- }).on("add", async (addedFile) => {
2513
- await callback();
2514
- }).on("change", async (changedFile) => {
2515
- await callback();
2516
- }).on("unlink", async (removedFile) => {
2517
- await callback();
2518
- });
2624
+ watchQueries(configManager, databaseLock, callback) {
2625
+ const executeCallback = async (_) => {
2626
+ await databaseLock(async () => {
2627
+ await callback();
2628
+ });
2629
+ };
2630
+ import_chokidar.default.watch(configManager.userQueriesAndFragmentsGlob).on("add", executeCallback).on("change", executeCallback).on("unlink", executeCallback);
2519
2631
  }
2520
2632
  };
2521
2633
  DevCommand.paths = [["dev"], ["server:start"]];
2634
+ // Prevent indexes and reads occurring at once
2522
2635
  DevCommand.usage = import_clipanion2.Command.Usage({
2523
2636
  category: `Commands`,
2524
2637
  description: `Builds Tina and starts the dev server`,
@@ -2532,6 +2645,8 @@ DevCommand.usage = import_clipanion2.Command.Usage({
2532
2645
  var import_clipanion3 = require("clipanion");
2533
2646
  var import_progress2 = __toESM(require("progress"));
2534
2647
  var import_fs_extra7 = __toESM(require("fs-extra"));
2648
+ var import_crypto = __toESM(require("crypto"));
2649
+ var import_path6 = __toESM(require("path"));
2535
2650
  var import_graphql11 = require("@tinacms/graphql");
2536
2651
 
2537
2652
  // src/next/commands/build-command/server.ts
@@ -2575,7 +2690,7 @@ var buildProductionSpa = async (configManager, database, apiURL) => {
2575
2690
  // src/next/commands/build-command/index.ts
2576
2691
  var import_schema_tools2 = require("@tinacms/schema-tools");
2577
2692
  var import_graphql12 = require("graphql");
2578
- var import_core2 = require("@graphql-inspector/core");
2693
+ var import_core3 = require("@graphql-inspector/core");
2579
2694
 
2580
2695
  // src/next/commands/build-command/waitForDB.ts
2581
2696
  var import_progress = __toESM(require("progress"));
@@ -2677,6 +2792,20 @@ var waitForDB = async (config2, apiUrl, previewName, verbose) => {
2677
2792
 
2678
2793
  // src/next/commands/build-command/index.ts
2679
2794
  var import_search2 = require("@tinacms/search");
2795
+
2796
+ // src/utils/index.ts
2797
+ var import_core2 = require("@graphql-inspector/core");
2798
+ var getFaqLink = (type) => {
2799
+ switch (type) {
2800
+ case import_core2.ChangeType.FieldRemoved: {
2801
+ return "https://tina.io/docs/introduction/faq#how-do-i-resolve-the-local-graphql-schema-doesnt-match-the-remote-graphql-schema-errors";
2802
+ }
2803
+ default:
2804
+ return null;
2805
+ }
2806
+ };
2807
+
2808
+ // src/next/commands/build-command/index.ts
2680
2809
  var BuildCommand = class extends BaseCommand {
2681
2810
  constructor() {
2682
2811
  super(...arguments);
@@ -2692,6 +2821,9 @@ var BuildCommand = class extends BaseCommand {
2692
2821
  this.tinaGraphQLVersion = import_clipanion3.Option.String("--tina-graphql-version", {
2693
2822
  description: "Specify the version of @tinacms/graphql to use (defaults to latest)"
2694
2823
  });
2824
+ /**
2825
+ * 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
2826
+ */
2695
2827
  this.skipCloudChecks = import_clipanion3.Option.Boolean("--skip-cloud-checks", false, {
2696
2828
  description: "Skips checking the provided cloud config."
2697
2829
  });
@@ -2797,14 +2929,15 @@ ${dangerText(e.message)}
2797
2929
  database,
2798
2930
  null,
2799
2931
  apiURL,
2800
- true
2932
+ true,
2933
+ (lockedFn) => lockedFn()
2801
2934
  );
2802
2935
  await server.listen(Number(this.port));
2803
2936
  console.log("server listening on port", this.port);
2804
2937
  }
2805
2938
  const skipCloudChecks = this.skipCloudChecks || configManager.hasSelfHostedConfig();
2806
2939
  if (!skipCloudChecks) {
2807
- const { hasUpstream } = await this.checkClientInfo(
2940
+ const { hasUpstream, timestamp } = await this.checkClientInfo(
2808
2941
  configManager,
2809
2942
  codegen2.productionUrl,
2810
2943
  this.previewBaseBranch
@@ -2832,7 +2965,16 @@ ${dangerText(e.message)}
2832
2965
  await this.checkGraphqlSchema(
2833
2966
  configManager,
2834
2967
  database,
2835
- codegen2.productionUrl
2968
+ codegen2.productionUrl,
2969
+ timestamp
2970
+ );
2971
+ await this.checkTinaSchema(
2972
+ configManager,
2973
+ database,
2974
+ codegen2.productionUrl,
2975
+ this.previewName,
2976
+ this.verbose,
2977
+ timestamp
2836
2978
  );
2837
2979
  }
2838
2980
  await buildProductionSpa(configManager, database, codegen2.productionUrl);
@@ -2951,11 +3093,13 @@ ${dangerText(e.message)}
2951
3093
  const bar2 = new import_progress2.default("Checking clientId and token. :prog", 1);
2952
3094
  let branchKnown = false;
2953
3095
  let hasUpstream = false;
3096
+ let timestamp;
2954
3097
  try {
2955
3098
  const res = await request({
2956
3099
  token,
2957
3100
  url
2958
3101
  });
3102
+ timestamp = res.timestamp || 0;
2959
3103
  bar2.tick({
2960
3104
  prog: "\u2705"
2961
3105
  });
@@ -2997,7 +3141,8 @@ ${dangerText(e.message)}
2997
3141
  prog: "\u2705"
2998
3142
  });
2999
3143
  return {
3000
- hasUpstream
3144
+ hasUpstream,
3145
+ timestamp
3001
3146
  };
3002
3147
  }
3003
3148
  for (let i = 0; i <= 5; i++) {
@@ -3087,14 +3232,14 @@ ${dangerText(e.message)}
3087
3232
  throw e;
3088
3233
  }
3089
3234
  }
3090
- async checkGraphqlSchema(configManager, database, apiURL) {
3235
+ async checkGraphqlSchema(configManager, database, apiURL, timestamp) {
3091
3236
  const bar2 = new import_progress2.default(
3092
3237
  "Checking local GraphQL Schema matches server. :prog",
3093
3238
  1
3094
3239
  );
3095
3240
  const { config: config2 } = configManager;
3096
3241
  const token = config2.token;
3097
- const remoteSchema = await fetchRemoteGraphqlSchema({
3242
+ const { remoteSchema, remoteProjectVersion } = await fetchRemoteGraphqlSchema({
3098
3243
  url: apiURL,
3099
3244
  token
3100
3245
  });
@@ -3114,7 +3259,7 @@ Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3114
3259
  const localSchemaDocument = await database.getGraphQLSchemaFromBridge();
3115
3260
  const localGraphqlSchema = (0, import_graphql12.buildASTSchema)(localSchemaDocument);
3116
3261
  try {
3117
- const diffResult = await (0, import_core2.diff)(localGraphqlSchema, remoteGqlSchema);
3262
+ const diffResult = await (0, import_core3.diff)(localGraphqlSchema, remoteGqlSchema);
3118
3263
  if (diffResult.length === 0) {
3119
3264
  bar2.tick({
3120
3265
  prog: "\u2705"
@@ -3123,12 +3268,30 @@ Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3123
3268
  bar2.tick({
3124
3269
  prog: "\u274C"
3125
3270
  });
3126
- 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.`;
3127
- if (config2 == null ? void 0 : config2.branch) {
3128
- errorMessage += `
3271
+ const type = diffResult[0].type;
3272
+ const reason = diffResult[0].message;
3273
+ const errorLevel = diffResult[0].criticality.level;
3274
+ const faqLink = getFaqLink(type);
3275
+ const tinaGraphQLVersion = configManager.getTinaGraphQLVersion();
3276
+ 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 && `
3277
+ Check out '${faqLink}' for possible solutions.`}`;
3278
+ errorMessage += `
3129
3279
 
3130
- Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3280
+ Additional info:
3281
+
3282
+ `;
3283
+ if (config2 == null ? void 0 : config2.branch) {
3284
+ errorMessage += ` Branch: ${config2.branch}, Client ID: ${config2.clientId}
3285
+ `;
3131
3286
  }
3287
+ errorMessage += ` Local GraphQL version: ${tinaGraphQLVersion.fullVersion} / Remote GraphQL version: ${remoteProjectVersion}
3288
+ `;
3289
+ errorMessage += ` Last indexed at: ${new Date(
3290
+ timestamp
3291
+ ).toUTCString()}
3292
+ `;
3293
+ errorMessage += ` Reason: [${errorLevel} - ${type}] ${reason}
3294
+ `;
3132
3295
  throw new Error(errorMessage);
3133
3296
  }
3134
3297
  } catch (e) {
@@ -3143,6 +3306,71 @@ Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3143
3306
  }
3144
3307
  }
3145
3308
  }
3309
+ async checkTinaSchema(configManager, database, apiURL, previewName, verbose, timestamp) {
3310
+ const bar2 = new import_progress2.default(
3311
+ "Checking local Tina Schema matches server. :prog",
3312
+ 1
3313
+ );
3314
+ const { config: config2 } = configManager;
3315
+ const token = config2.token;
3316
+ const { clientId, branch, isLocalClient, host } = (0, import_schema_tools2.parseURL)(apiURL);
3317
+ if (isLocalClient || !host || !clientId || !branch) {
3318
+ if (verbose) {
3319
+ logger.info(logText("Not using Tina Cloud, skipping Tina Schema check"));
3320
+ }
3321
+ return;
3322
+ }
3323
+ const { tinaSchema: remoteTinaSchemaSha } = await fetchSchemaSha({
3324
+ url: `https://${host}/db/${clientId}/${previewName || branch}/schemaSha`,
3325
+ token
3326
+ });
3327
+ if (!remoteTinaSchemaSha) {
3328
+ bar2.tick({
3329
+ prog: "\u274C"
3330
+ });
3331
+ let errorMessage = `The remote Tina schema does not exist. Check indexing for this branch.`;
3332
+ if (config2 == null ? void 0 : config2.branch) {
3333
+ errorMessage += `
3334
+
3335
+ Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3336
+ }
3337
+ throw new Error(errorMessage);
3338
+ }
3339
+ if (!database.bridge) {
3340
+ throw new Error(`No bridge configured`);
3341
+ }
3342
+ const localTinaSchema = JSON.parse(
3343
+ await database.bridge.get(
3344
+ import_path6.default.join(database.tinaDirectory, "__generated__", "_schema.json")
3345
+ )
3346
+ );
3347
+ localTinaSchema.version = void 0;
3348
+ const localTinaSchemaSha = import_crypto.default.createHash("sha256").update(JSON.stringify(localTinaSchema)).digest("hex");
3349
+ if (localTinaSchemaSha === remoteTinaSchemaSha) {
3350
+ bar2.tick({
3351
+ prog: "\u2705"
3352
+ });
3353
+ } else {
3354
+ bar2.tick({
3355
+ prog: "\u274C"
3356
+ });
3357
+ 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.`;
3358
+ errorMessage += `
3359
+
3360
+ Additional info:
3361
+
3362
+ `;
3363
+ if (config2 == null ? void 0 : config2.branch) {
3364
+ errorMessage += ` Branch: ${config2.branch}, Client ID: ${config2.clientId}
3365
+ `;
3366
+ }
3367
+ errorMessage += ` Last indexed at: ${new Date(
3368
+ timestamp
3369
+ ).toUTCString()}
3370
+ `;
3371
+ throw new Error(errorMessage);
3372
+ }
3373
+ }
3146
3374
  };
3147
3375
  BuildCommand.paths = [["build"]];
3148
3376
  BuildCommand.usage = import_clipanion3.Command.Usage({
@@ -3209,7 +3437,26 @@ var fetchRemoteGraphqlSchema = async ({
3209
3437
  body
3210
3438
  });
3211
3439
  const data = await res.json();
3212
- return data == null ? void 0 : data.data;
3440
+ return {
3441
+ remoteSchema: data == null ? void 0 : data.data,
3442
+ remoteRuntimeVersion: res.headers.get("tinacms-grapqhl-version"),
3443
+ remoteProjectVersion: res.headers.get("tinacms-graphql-project-version")
3444
+ };
3445
+ };
3446
+ var fetchSchemaSha = async ({
3447
+ url,
3448
+ token
3449
+ }) => {
3450
+ const headers = new Headers();
3451
+ if (token) {
3452
+ headers.append("X-API-KEY", token);
3453
+ }
3454
+ const res = await fetch(url, {
3455
+ method: "GET",
3456
+ headers,
3457
+ cache: "no-cache"
3458
+ });
3459
+ return res.json();
3213
3460
  };
3214
3461
 
3215
3462
  // src/next/commands/audit-command/index.ts
@@ -3318,6 +3565,7 @@ var auditDocuments = async (args) => {
3318
3565
  logger.error(import_chalk5.default.red(err.message));
3319
3566
  if (err.originalError.originalError) {
3320
3567
  logger.error(
3568
+ // @ts-ignore FIXME: this doesn't seem right
3321
3569
  import_chalk5.default.red(` ${err.originalError.originalError.message}`)
3322
3570
  );
3323
3571
  }
@@ -3523,7 +3771,9 @@ var detectEnvironment = async ({
3523
3771
  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")));
3524
3772
  const tinaFolder = import_path7.default.join(baseDir, "tina");
3525
3773
  const tinaConfigExists = Boolean(
3526
- await import_fs_extra8.default.pathExists(tinaFolder) && (await import_fs_extra8.default.readdir(tinaFolder)).find((x) => x.includes("config"))
3774
+ // Does the tina folder exist?
3775
+ await import_fs_extra8.default.pathExists(tinaFolder) && // Does the tina folder contain a config file?
3776
+ (await import_fs_extra8.default.readdir(tinaFolder)).find((x) => x.includes("config"))
3527
3777
  );
3528
3778
  const pagesDir = [baseDir, usingSrc ? "src" : false, "pages"].filter(
3529
3779
  Boolean
@@ -3758,6 +4008,7 @@ var supportedDatabaseAdapters = {
3758
4008
  {
3759
4009
  from: "mongodb",
3760
4010
  imported: [],
4011
+ // not explicitly imported
3761
4012
  packageName: "mongodb"
3762
4013
  }
3763
4014
  ]
@@ -3830,6 +4081,10 @@ var chooseDatabaseAdapter = async ({
3830
4081
  title: "MongoDB",
3831
4082
  value: "mongodb"
3832
4083
  }
4084
+ // {
4085
+ // title: "I'll create my own database adapter",
4086
+ // value: 'other',
4087
+ // },
3833
4088
  ]
3834
4089
  }
3835
4090
  ]);
@@ -4107,6 +4362,7 @@ async function configure(env, opts) {
4107
4362
  packageManager,
4108
4363
  forestryMigrate: false,
4109
4364
  isLocalEnvVarName: "TINA_PUBLIC_IS_LOCAL",
4365
+ // TODO: give this a better default
4110
4366
  typescript: false
4111
4367
  };
4112
4368
  if (config2.framework.name === "next") {
@@ -4210,15 +4466,25 @@ var import_js_yaml = __toESM(require("js-yaml"));
4210
4466
  var import_zod = __toESM(require("zod"));
4211
4467
 
4212
4468
  // src/cmds/forestry-migrate/util/errorSingleton.ts
4213
- var ErrorSingleton = class {
4469
+ var ErrorSingleton = class _ErrorSingleton {
4470
+ /**
4471
+ * The Singleton's constructor should always be private to prevent direct
4472
+ * construction calls with the `new` operator.
4473
+ */
4214
4474
  constructor() {
4215
4475
  }
4476
+ /**
4477
+ * The static method that controls the access to the singleton instance.
4478
+ *
4479
+ * This implementation let you subclass the Singleton class while keeping
4480
+ * just one instance of each subclass around.
4481
+ */
4216
4482
  static getInstance() {
4217
- if (!ErrorSingleton.instance) {
4218
- ErrorSingleton.instance = new ErrorSingleton();
4219
- ErrorSingleton.instance.collectionNameErrors = [];
4483
+ if (!_ErrorSingleton.instance) {
4484
+ _ErrorSingleton.instance = new _ErrorSingleton();
4485
+ _ErrorSingleton.instance.collectionNameErrors = [];
4220
4486
  }
4221
- return ErrorSingleton.instance;
4487
+ return _ErrorSingleton.instance;
4222
4488
  }
4223
4489
  addErrorName(error) {
4224
4490
  this.collectionNameErrors.push(error);
@@ -4261,8 +4527,7 @@ var makeFieldsWithInternalCode = ({
4261
4527
  if (hasBody) {
4262
4528
  return [bodyField, `__TINA_INTERNAL__:::...${field}():::`];
4263
4529
  } else {
4264
- if (spread)
4265
- return `__TINA_INTERNAL__:::...${field}():::`;
4530
+ if (spread) return `__TINA_INTERNAL__:::...${field}():::`;
4266
4531
  return `__TINA_INTERNAL__:::${field}():::`;
4267
4532
  }
4268
4533
  };
@@ -4346,6 +4611,7 @@ var forestryConfigSchema = import_zod.default.object({
4346
4611
  )
4347
4612
  });
4348
4613
  var forestryFieldWithoutField = import_zod.default.object({
4614
+ // TODO: maybe better type this?
4349
4615
  type: import_zod.default.union([
4350
4616
  import_zod.default.literal("text"),
4351
4617
  import_zod.default.literal("datetime"),
@@ -4369,6 +4635,7 @@ var forestryFieldWithoutField = import_zod.default.object({
4369
4635
  default: import_zod.default.any().optional(),
4370
4636
  template: import_zod.default.string().optional(),
4371
4637
  config: import_zod.default.object({
4638
+ // min and max are used for lists
4372
4639
  min: import_zod.default.number().optional().nullable(),
4373
4640
  max: import_zod.default.number().optional().nullable(),
4374
4641
  required: import_zod.default.boolean().optional().nullable(),
@@ -4382,6 +4649,7 @@ var forestryFieldWithoutField = import_zod.default.object({
4382
4649
  import_zod.default.literal("pages"),
4383
4650
  import_zod.default.literal("documents"),
4384
4651
  import_zod.default.literal("simple"),
4652
+ // TODO: I want to ignore this key if its invalid
4385
4653
  import_zod.default.string()
4386
4654
  ]).optional().nullable(),
4387
4655
  section: import_zod.default.string().optional().nullable()
@@ -4417,6 +4685,7 @@ var transformForestryFieldsToTinaFields = ({
4417
4685
  }
4418
4686
  let field;
4419
4687
  switch (forestryField2.type) {
4688
+ // Single filed types
4420
4689
  case "text":
4421
4690
  field = {
4422
4691
  type: "string",
@@ -4496,6 +4765,7 @@ var transformForestryFieldsToTinaFields = ({
4496
4765
  );
4497
4766
  }
4498
4767
  break;
4768
+ // List Types
4499
4769
  case "list":
4500
4770
  field = {
4501
4771
  type: "string",
@@ -4518,6 +4788,7 @@ var transformForestryFieldsToTinaFields = ({
4518
4788
  }
4519
4789
  };
4520
4790
  break;
4791
+ // Object (Group) types
4521
4792
  case "field_group":
4522
4793
  field = {
4523
4794
  type: "object",
@@ -4558,6 +4829,7 @@ var transformForestryFieldsToTinaFields = ({
4558
4829
  });
4559
4830
  const fieldsString = stringifyLabelWithField(template2.label);
4560
4831
  const t = {
4832
+ // @ts-ignore
4561
4833
  fields: makeFieldsWithInternalCode({
4562
4834
  hasBody: false,
4563
4835
  field: fieldsString
@@ -4595,6 +4867,7 @@ var transformForestryFieldsToTinaFields = ({
4595
4867
  spread: true
4596
4868
  });
4597
4869
  tinaFields.push(
4870
+ // @ts-ignore
4598
4871
  field2
4599
4872
  );
4600
4873
  break;
@@ -4654,6 +4927,7 @@ var parseSections = ({ val }) => {
4654
4927
 
4655
4928
  // src/cmds/forestry-migrate/index.ts
4656
4929
  var BODY_FIELD = {
4930
+ // This is the body field
4657
4931
  type: "rich-text",
4658
4932
  name: "body",
4659
4933
  label: "Body of Document",
@@ -4712,8 +4986,7 @@ var generateAllTemplates = async ({
4712
4986
  };
4713
4987
  var generateCollectionFromForestrySection = (args) => {
4714
4988
  const { section, templateMap } = args;
4715
- if (section.read_only)
4716
- return;
4989
+ if (section.read_only) return;
4717
4990
  let format3 = "md";
4718
4991
  if (section.new_doc_ext) {
4719
4992
  const ext = checkExt(section.new_doc_ext);
@@ -4780,12 +5053,14 @@ var generateCollectionFromForestrySection = (args) => {
4780
5053
  if (((forestryTemplates == null ? void 0 : forestryTemplates.length) || 0) > 1) {
4781
5054
  c = {
4782
5055
  ...baseCollection,
5056
+ // @ts-expect-error
4783
5057
  templates: forestryTemplates.map((tem) => {
4784
5058
  const currentTemplate = templateMap.get(tem);
4785
5059
  const fieldsString = stringifyLabelWithField(
4786
5060
  currentTemplate.templateObj.label
4787
5061
  );
4788
5062
  return {
5063
+ // fields: [BODY_FIELD],
4789
5064
  fields: makeFieldsWithInternalCode({
4790
5065
  hasBody,
4791
5066
  field: fieldsString,
@@ -4803,6 +5078,8 @@ var generateCollectionFromForestrySection = (args) => {
4803
5078
  const fieldsString = stringifyLabelWithField(template.templateObj.label);
4804
5079
  c = {
4805
5080
  ...baseCollection,
5081
+ // fields: [BODY_FIELD],
5082
+ // @ts-expect-error
4806
5083
  fields: makeFieldsWithInternalCode({
4807
5084
  field: fieldsString,
4808
5085
  hasBody,
@@ -5550,6 +5827,7 @@ var makeImportsVisitor = (sourceFile, importMap) => (ctx) => (node) => {
5550
5827
  ) : [];
5551
5828
  const newImports = [
5552
5829
  .../* @__PURE__ */ new Set([
5830
+ // we use Set to remove duplicates
5553
5831
  ...existingImports,
5554
5832
  ...imports
5555
5833
  ])
@@ -5704,6 +5982,7 @@ var addSelfHostedTinaAuthToConfig = async (config2, configFile) => {
5704
5982
  );
5705
5983
  const { configImports, configAuthProviderClass, extraTinaCollections } = config2.authProvider;
5706
5984
  const importMap = {
5985
+ // iterate over configImports and add them to the import map
5707
5986
  ...configImports.reduce((acc, { from, imported }) => {
5708
5987
  acc[from] = imported;
5709
5988
  return acc;
@@ -5878,7 +6157,13 @@ async function apply({
5878
6157
  config: config2
5879
6158
  });
5880
6159
  }
5881
- if (env.tinaConfigExists && params.isBackendInit && config2.hosting === "self-host" && (((_a = config2.authProvider) == null ? void 0 : _a.name) || "") !== "tina-cloud") {
6160
+ if (
6161
+ // if the config was just generated we do not need to update the config file because it will be generated correctly
6162
+ env.tinaConfigExists && // Are we running tinacms init backend
6163
+ params.isBackendInit && // Do the user choose the 'self-host' option
6164
+ config2.hosting === "self-host" && // the user did not choose the 'tina-cloud' auth provider
6165
+ (((_a = config2.authProvider) == null ? void 0 : _a.name) || "") !== "tina-cloud"
6166
+ ) {
5882
6167
  await addSelfHostedTinaAuthToConfig(config2, env.generatedFiles["config"]);
5883
6168
  }
5884
6169
  logNextSteps({
@@ -6012,22 +6297,22 @@ var writeGeneratedFile = async ({
6012
6297
  content,
6013
6298
  typescript
6014
6299
  }) => {
6015
- const { exists, path: path13, parentPath } = generatedFile.resolve(typescript);
6300
+ const { exists, path: path14, parentPath } = generatedFile.resolve(typescript);
6016
6301
  if (exists) {
6017
6302
  if (overwrite) {
6018
- logger.info(`Overwriting file at ${path13}... \u2705`);
6019
- import_fs_extra13.default.outputFileSync(path13, content);
6303
+ logger.info(`Overwriting file at ${path14}... \u2705`);
6304
+ import_fs_extra13.default.outputFileSync(path14, content);
6020
6305
  } else {
6021
- logger.info(`Not overwriting file at ${path13}.`);
6306
+ logger.info(`Not overwriting file at ${path14}.`);
6022
6307
  logger.info(
6023
- logText(`Please add the following to ${path13}:
6308
+ logText(`Please add the following to ${path14}:
6024
6309
  ${indentText(content)}}`)
6025
6310
  );
6026
6311
  }
6027
6312
  } else {
6028
- logger.info(`Adding file at ${path13}... \u2705`);
6313
+ logger.info(`Adding file at ${path14}... \u2705`);
6029
6314
  await import_fs_extra13.default.ensureDir(parentPath);
6030
- import_fs_extra13.default.outputFileSync(path13, content);
6315
+ import_fs_extra13.default.outputFileSync(path14, content);
6031
6316
  }
6032
6317
  };
6033
6318
  var addConfigFile = async ({
@@ -6171,6 +6456,7 @@ var other = ({ packageManager }) => {
6171
6456
  const packageManagers = {
6172
6457
  pnpm: `pnpm`,
6173
6458
  npm: `npx`,
6459
+ // npx is the way to run executables that aren't in your "scripts"
6174
6460
  yarn: `yarn`
6175
6461
  };
6176
6462
  return `${packageManagers[packageManager]} tinacms dev -c "<your dev command>"`;
@@ -6183,6 +6469,7 @@ var frameworkDevCmds = {
6183
6469
  const packageManagers = {
6184
6470
  pnpm: `pnpm`,
6185
6471
  npm: `npm run`,
6472
+ // npx is the way to run executables that aren't in your "scripts"
6186
6473
  yarn: `yarn`
6187
6474
  };
6188
6475
  return `${packageManagers[packageManager]} dev`;
@@ -6440,5 +6727,3 @@ cli.register(import_clipanion8.Builtins.DefinitionsCommand);
6440
6727
  cli.register(import_clipanion8.Builtins.HelpCommand);
6441
6728
  cli.register(import_clipanion8.Builtins.VersionCommand);
6442
6729
  var src_default = cli;
6443
- // Annotate the CommonJS export names for ESM import in node:
6444
- 0 && (module.exports = {});