@tinacms/cli 0.0.0-c45ac5d-20241213020122 → 0.0.0-c6a6335-20250416234606

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,37 +17,34 @@ 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.13";
38
+ var version = "1.9.5";
35
39
 
36
40
  // src/next/commands/dev-command/index.ts
37
- var import_clipanion2 = require("clipanion");
38
- var import_fs_extra6 = __toESM(require("fs-extra"));
39
41
  var import_path5 = __toESM(require("path"));
40
- var import_chokidar = __toESM(require("chokidar"));
41
42
  var import_graphql10 = require("@tinacms/graphql");
42
-
43
- // src/next/config-manager.ts
44
- var import_fs_extra = __toESM(require("fs-extra"));
45
- var import_path = __toESM(require("path"));
46
- var import_os = __toESM(require("os"));
47
- var esbuild = __toESM(require("esbuild"));
48
- var dotenv = __toESM(require("dotenv"));
49
- var import_normalize_path = __toESM(require("normalize-path"));
50
- var import_chalk2 = __toESM(require("chalk"));
43
+ var import_search = require("@tinacms/search");
44
+ var import_async_lock = __toESM(require("async-lock"));
45
+ var import_chokidar = __toESM(require("chokidar"));
46
+ var import_clipanion2 = require("clipanion");
47
+ var import_fs_extra6 = __toESM(require("fs-extra"));
51
48
 
52
49
  // src/logger/index.ts
53
50
  var import_chalk = __toESM(require("chalk"));
@@ -57,7 +54,10 @@ function isUnicodeSupported() {
57
54
  if (process.platform !== "win32") {
58
55
  return process.env.TERM !== "linux";
59
56
  }
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";
57
+ return Boolean(process.env.CI) || Boolean(process.env.WT_SESSION) || // Windows Terminal
58
+ Boolean(process.env.TERMINUS_SUBLIME) || // Terminus (<0.2.27)
59
+ process.env.ConEmuTask === "{cmd::Cmder}" || // ConEmu and cmder
60
+ 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
61
  }
62
62
 
63
63
  // src/logger/index.ts
@@ -157,2102 +157,2180 @@ var S_SUCCESS = s("\u25C6", "*");
157
157
  var S_WARN = s("\u25B2", "!");
158
158
  var S_ERROR = s("\u25A0", "x");
159
159
 
160
- // src/next/config-manager.ts
161
- var TINA_FOLDER = "tina";
162
- var LEGACY_TINA_FOLDER = ".tina";
163
- var GENERATED_FOLDER = "__generated__";
164
- var GRAPHQL_JSON_FILE = "_graphql.json";
165
- var GRAPHQL_GQL_FILE = "schema.gql";
166
- var SCHEMA_JSON_FILE = "_schema.json";
167
- var LOOKUP_JSON_FILE = "_lookup.json";
168
- var ConfigManager = class {
169
- constructor({
170
- rootPath = process.cwd(),
171
- tinaGraphQLVersion,
172
- legacyNoSDK
173
- }) {
174
- this.rootPath = (0, import_normalize_path.default)(rootPath);
175
- this.tinaGraphQLVersionFromCLI = tinaGraphQLVersion;
176
- this.legacyNoSDK = legacyNoSDK;
177
- }
178
- isUsingTs() {
179
- return [".ts", ".tsx"].includes(import_path.default.extname(this.tinaConfigFilePath));
180
- }
181
- hasSelfHostedConfig() {
182
- return !!this.selfHostedDatabaseFilePath;
160
+ // src/utils/spinner.ts
161
+ var import_cli_spinner = require("cli-spinner");
162
+ async function localSpin({
163
+ waitFor,
164
+ text
165
+ }) {
166
+ const spinner = new import_cli_spinner.Spinner({
167
+ text: `${text} %s`,
168
+ stream: process.stderr,
169
+ onTick: function(msg) {
170
+ this.clearLine(this.stream);
171
+ this.stream.write(msg);
172
+ }
173
+ });
174
+ spinner.setSpinnerString("\u280B\u2819\u2839\u2838\u283C\u2834\u2826\u2827\u2807\u280F");
175
+ spinner.start();
176
+ const res = await waitFor();
177
+ spinner.stop();
178
+ console.log("");
179
+ return res;
180
+ }
181
+ function spin({
182
+ waitFor,
183
+ text
184
+ }) {
185
+ if (process.env.CI) {
186
+ console.log(text);
187
+ return waitFor();
188
+ } else {
189
+ return localSpin({
190
+ text,
191
+ waitFor
192
+ });
183
193
  }
184
- hasSeparateContentRoot() {
185
- return this.rootPath !== this.contentRootPath;
194
+ }
195
+
196
+ // src/utils/theme.ts
197
+ var import_chalk2 = __toESM(require("chalk"));
198
+ var successText = import_chalk2.default.bold.green;
199
+ var focusText = import_chalk2.default.bold;
200
+ var dangerText = import_chalk2.default.bold.red;
201
+ var neutralText = import_chalk2.default.bold.cyan;
202
+ var linkText = import_chalk2.default.bold.cyan;
203
+ var labelText = import_chalk2.default.bold;
204
+ var cmdText = import_chalk2.default.inverse;
205
+ var indentedCmd = (str) => {
206
+ return ` \u2503 ` + str;
207
+ };
208
+ var indentText = (str) => {
209
+ return String(str).split("\n").map((line) => ` ${line}`).join("\n");
210
+ };
211
+ var logText = import_chalk2.default.italic.gray;
212
+ var warnText = import_chalk2.default.yellowBright.bgBlack;
213
+ var titleText = import_chalk2.default.bgHex("d2f1f8").hex("ec4816");
214
+ var CONFIRMATION_TEXT = import_chalk2.default.dim("enter to confirm");
215
+
216
+ // src/next/codegen/index.ts
217
+ var import_fs_extra = __toESM(require("fs-extra"));
218
+ var import_path = __toESM(require("path"));
219
+ var import_graphql5 = require("graphql");
220
+
221
+ // src/next/codegen/codegen/index.ts
222
+ var import_graphql4 = require("graphql");
223
+
224
+ // src/next/codegen/codegen/plugin.ts
225
+ var AddGeneratedClientFunc = (apiURL) => {
226
+ return (_schema, _documents, _config, _info) => {
227
+ return `
228
+ // TinaSDK generated code
229
+ import { createClient, TinaClient } from "tinacms/dist/client";
230
+
231
+ const generateRequester = (
232
+ client: TinaClient,
233
+ ) => {
234
+ const requester: (
235
+ doc: any,
236
+ vars?: any,
237
+ options?: {
238
+ branch?: string,
239
+ /**
240
+ * Aside from \`method\` and \`body\`, all fetch options are passed
241
+ * through to underlying fetch request
242
+ */
243
+ fetchOptions?: Omit<Parameters<typeof fetch>[1], 'body' | 'method'>,
244
+ },
245
+ client
246
+ ) => Promise<any> = async (doc, vars, options) => {
247
+ let url = client.apiUrl
248
+ if (options?.branch) {
249
+ const index = client.apiUrl.lastIndexOf('/')
250
+ url = client.apiUrl.substring(0, index + 1) + options.branch
251
+ }
252
+ const data = await client.request({
253
+ query: doc,
254
+ variables: vars,
255
+ url,
256
+ }, options)
257
+
258
+ return { data: data?.data, errors: data?.errors, query: doc, variables: vars || {} }
186
259
  }
187
- shouldSkipSDK() {
188
- var _a;
189
- if (this.legacyNoSDK) {
190
- return this.legacyNoSDK;
260
+
261
+ return requester
262
+ }
263
+
264
+ /**
265
+ * @experimental this class can be used but may change in the future
266
+ **/
267
+ export const ExperimentalGetTinaClient = () =>
268
+ getSdk(
269
+ generateRequester(
270
+ createClient({
271
+ url: "${apiURL}",
272
+ queries,
273
+ })
274
+ )
275
+ )
276
+
277
+ export const queries = (
278
+ client: TinaClient,
279
+ ) => {
280
+ const requester = generateRequester(client)
281
+ return getSdk(requester)
282
+ }
283
+ `;
284
+ };
285
+ };
286
+ var AddGeneratedClient = (apiURL) => ({
287
+ plugin: AddGeneratedClientFunc(apiURL)
288
+ });
289
+
290
+ // src/next/codegen/codegen/index.ts
291
+ var import_graphql_file_loader = require("@graphql-tools/graphql-file-loader");
292
+ var import_core = require("@graphql-codegen/core");
293
+ var import_load = require("@graphql-tools/load");
294
+ var import_typescript_operations = require("@graphql-codegen/typescript-operations");
295
+ var import_typescript = require("@graphql-codegen/typescript");
296
+
297
+ // src/next/codegen/codegen/sdkPlugin/index.ts
298
+ var import_graphql2 = require("graphql");
299
+ var import_graphql3 = require("graphql");
300
+
301
+ // src/next/codegen/codegen/sdkPlugin/visitor.ts
302
+ var import_visitor_plugin_common = require("@graphql-codegen/visitor-plugin-common");
303
+ var import_auto_bind = __toESM(require("auto-bind"));
304
+ var import_graphql = require("graphql");
305
+ var GenericSdkVisitor = class extends import_visitor_plugin_common.ClientSideBaseVisitor {
306
+ constructor(schema, fragments, rawConfig) {
307
+ super(schema, fragments, rawConfig, {
308
+ usingObservableFrom: rawConfig.usingObservableFrom
309
+ });
310
+ this._operationsToInclude = [];
311
+ (0, import_auto_bind.default)(this);
312
+ if (this.config.usingObservableFrom) {
313
+ this._additionalImports.push(this.config.usingObservableFrom);
314
+ }
315
+ if (this.config.documentMode !== import_visitor_plugin_common.DocumentMode.string) {
191
316
  }
192
- return ((_a = this.config.client) == null ? void 0 : _a.skip) || false;
193
317
  }
194
- async processConfig() {
195
- this.tinaFolderPath = await this.getTinaFolderPath(this.rootPath);
196
- this.envFilePath = import_path.default.resolve(
197
- import_path.default.join(this.tinaFolderPath, "..", ".env")
198
- );
199
- dotenv.config({ path: this.envFilePath });
200
- this.tinaConfigFilePath = await this.getPathWithExtension(
201
- import_path.default.join(this.tinaFolderPath, "config")
202
- );
203
- if (!this.tinaConfigFilePath) {
318
+ buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes) {
319
+ if (node.name == null) {
204
320
  throw new Error(
205
- `Unable to find config file in ${this.tinaFolderPath}. Looking for a file named "config.{ts,tsx,js,jsx}"`
321
+ "Plugin 'generic-sdk' cannot generate SDK for unnamed operation.\n\n" + (0, import_graphql.print)(node)
206
322
  );
323
+ } else {
324
+ this._operationsToInclude.push({
325
+ node,
326
+ documentVariableName,
327
+ operationType,
328
+ // This is the only line that is different
329
+ operationResultType: `{data: ${operationResultType}, errors?: { message: string, locations: { line: number, column: number }[], path: string[] }[], variables: ${operationVariablesTypes}, query: string}`,
330
+ operationVariablesTypes
331
+ });
207
332
  }
208
- this.selfHostedDatabaseFilePath = await this.getPathWithExtension(
209
- import_path.default.join(this.tinaFolderPath, "database")
210
- );
211
- this.generatedFolderPath = import_path.default.join(this.tinaFolderPath, GENERATED_FOLDER);
212
- this.generatedCachePath = import_path.default.join(
213
- this.generatedFolderPath,
214
- ".cache",
215
- String(new Date().getTime())
216
- );
217
- this.generatedGraphQLGQLPath = import_path.default.join(
218
- this.generatedFolderPath,
219
- GRAPHQL_GQL_FILE
220
- );
221
- this.generatedGraphQLJSONPath = import_path.default.join(
222
- this.generatedFolderPath,
223
- GRAPHQL_JSON_FILE
224
- );
225
- this.generatedSchemaJSONPath = import_path.default.join(
226
- this.generatedFolderPath,
227
- SCHEMA_JSON_FILE
228
- );
229
- this.generatedLookupJSONPath = import_path.default.join(
230
- this.generatedFolderPath,
231
- LOOKUP_JSON_FILE
232
- );
233
- this.generatedQueriesFilePath = import_path.default.join(
234
- this.generatedFolderPath,
235
- "queries.gql"
236
- );
237
- this.generatedFragmentsFilePath = import_path.default.join(
238
- this.generatedFolderPath,
239
- "frags.gql"
240
- );
241
- this.generatedTypesTSFilePath = import_path.default.join(
242
- this.generatedFolderPath,
243
- "types.ts"
244
- );
245
- this.generatedTypesJSFilePath = import_path.default.join(
246
- this.generatedFolderPath,
247
- "types.js"
248
- );
249
- this.generatedTypesDFilePath = import_path.default.join(
250
- this.generatedFolderPath,
251
- "types.d.ts"
252
- );
253
- this.userQueriesAndFragmentsGlob = import_path.default.join(
254
- this.tinaFolderPath,
255
- "queries/**/*.{graphql,gql}"
256
- );
257
- this.generatedQueriesAndFragmentsGlob = import_path.default.join(
258
- this.generatedFolderPath,
259
- "*.{graphql,gql}"
260
- );
261
- this.generatedClientTSFilePath = import_path.default.join(
262
- this.generatedFolderPath,
263
- "client.ts"
264
- );
265
- this.generatedClientJSFilePath = import_path.default.join(
266
- this.generatedFolderPath,
267
- "client.js"
268
- );
269
- this.generatedClientDFilePath = import_path.default.join(
270
- this.generatedFolderPath,
271
- "client.d.ts"
272
- );
273
- this.generatedDatabaseClientDFilePath = import_path.default.join(
274
- this.generatedFolderPath,
275
- "databaseClient.d.ts"
276
- );
277
- this.generatedDatabaseClientTSFilePath = import_path.default.join(
278
- this.generatedFolderPath,
279
- "databaseClient.ts"
280
- );
281
- this.generatedDatabaseClientJSFilePath = import_path.default.join(
282
- this.generatedFolderPath,
283
- "databaseClient.js"
284
- );
285
- const clientExists = this.isUsingTs() ? await import_fs_extra.default.pathExists(this.generatedClientTSFilePath) : await import_fs_extra.default.pathExists(this.generatedClientJSFilePath);
286
- if (!clientExists) {
287
- const file = "export default ()=>({})\nexport const client = ()=>({})";
288
- if (this.isUsingTs()) {
289
- await import_fs_extra.default.outputFile(this.generatedClientTSFilePath, file);
290
- } else {
291
- await import_fs_extra.default.outputFile(this.generatedClientJSFilePath, file);
292
- }
293
- }
294
- const { config: config2, prebuildPath, watchList } = await this.loadConfigFile(
295
- this.generatedFolderPath,
296
- this.tinaConfigFilePath
297
- );
298
- this.watchList = watchList;
299
- this.config = config2;
300
- this.prebuildFilePath = prebuildPath;
301
- this.publicFolderPath = import_path.default.join(
302
- this.rootPath,
303
- this.config.build.publicFolder
304
- );
305
- this.outputFolderPath = import_path.default.join(
306
- this.publicFolderPath,
307
- this.config.build.outputFolder
308
- );
309
- this.outputHTMLFilePath = import_path.default.join(this.outputFolderPath, "index.html");
310
- this.outputGitignorePath = import_path.default.join(this.outputFolderPath, ".gitignore");
311
- const fullLocalContentPath = import_path.default.join(
312
- this.tinaFolderPath,
313
- this.config.localContentPath || ""
314
- );
315
- if (this.config.localContentPath) {
316
- const localContentPathExists = await import_fs_extra.default.pathExists(fullLocalContentPath);
317
- if (localContentPathExists) {
318
- logger.info(`Using separate content repo at ${fullLocalContentPath}`);
319
- this.contentRootPath = fullLocalContentPath;
320
- } else {
321
- logger.warn(
322
- `${import_chalk2.default.yellow("Warning:")} The localContentPath ${import_chalk2.default.cyan(
323
- fullLocalContentPath
324
- )} does not exist. Please create it or remove the localContentPath from your config file at ${import_chalk2.default.cyan(
325
- this.tinaConfigFilePath
326
- )}`
327
- );
328
- }
329
- }
330
- if (!this.contentRootPath) {
331
- this.contentRootPath = this.rootPath;
332
- }
333
- this.generatedFolderPathContentRepo = import_path.default.join(
334
- await this.getTinaFolderPath(this.contentRootPath),
335
- GENERATED_FOLDER
336
- );
337
- this.spaMainPath = require.resolve("@tinacms/app");
338
- this.spaRootPath = import_path.default.join(this.spaMainPath, "..", "..");
339
- }
340
- async getTinaFolderPath(rootPath) {
341
- const tinaFolderPath = import_path.default.join(rootPath, TINA_FOLDER);
342
- const tinaFolderExists = await import_fs_extra.default.pathExists(tinaFolderPath);
343
- if (tinaFolderExists) {
344
- this.isUsingLegacyFolder = false;
345
- return tinaFolderPath;
346
- }
347
- const legacyFolderPath = import_path.default.join(rootPath, LEGACY_TINA_FOLDER);
348
- const legacyFolderExists = await import_fs_extra.default.pathExists(legacyFolderPath);
349
- if (legacyFolderExists) {
350
- this.isUsingLegacyFolder = true;
351
- return legacyFolderPath;
352
- }
353
- throw new Error(
354
- `Unable to find Tina folder, if you're working in folder outside of the Tina config be sure to specify --rootPath`
355
- );
333
+ return null;
356
334
  }
357
- getTinaGraphQLVersion() {
358
- var _a, _b;
359
- if (this.tinaGraphQLVersionFromCLI) {
360
- return this.tinaGraphQLVersionFromCLI;
361
- }
362
- 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")) {
364
- throw new Error(
365
- `Can not find Tina GraphQL version in ${this.generatedSchemaJSONPath}`
335
+ get sdkContent() {
336
+ const usingObservable = !!this.config.usingObservableFrom;
337
+ const allPossibleActions = this._operationsToInclude.map((o) => {
338
+ const optionalVariables = !o.node.variableDefinitions || o.node.variableDefinitions.length === 0 || o.node.variableDefinitions.every(
339
+ (v) => v.type.kind !== import_graphql.Kind.NON_NULL_TYPE || v.defaultValue
366
340
  );
367
- }
368
- return `${generatedSchema.version.major}.${generatedSchema.version.minor}`;
341
+ const returnType = usingObservable && o.operationType === "Subscription" ? "Observable" : "Promise";
342
+ return `${o.node.name.value}(variables${optionalVariables ? "?" : ""}: ${o.operationVariablesTypes}, options?: C): ${returnType}<${o.operationResultType}> {
343
+ return requester<${o.operationResultType}, ${o.operationVariablesTypes}>(${o.documentVariableName}, variables, options);
344
+ }`;
345
+ }).map((s2) => (0, import_visitor_plugin_common.indentMultiline)(s2, 2));
346
+ return `export type Requester<C= {}> = <R, V>(doc: ${this.config.documentMode === import_visitor_plugin_common.DocumentMode.string ? "string" : "DocumentNode"}, vars?: V, options?: C) => ${usingObservable ? "Promise<R> & Observable<R>" : "Promise<R>"}
347
+ export function getSdk<C>(requester: Requester<C>) {
348
+ return {
349
+ ${allPossibleActions.join(",\n")}
350
+ };
369
351
  }
370
- printGeneratedClientFilePath() {
371
- if (this.isUsingTs()) {
372
- return this.generatedClientTSFilePath.replace(`${this.rootPath}/`, "");
373
- }
374
- return this.generatedClientJSFilePath.replace(`${this.rootPath}/`, "");
352
+ export type Sdk = ReturnType<typeof getSdk>;`;
375
353
  }
376
- printGeneratedTypesFilePath() {
377
- return this.generatedTypesTSFilePath.replace(`${this.rootPath}/`, "");
354
+ };
355
+
356
+ // src/next/codegen/codegen/sdkPlugin/index.ts
357
+ var plugin = (schema, documents, config2) => {
358
+ const allAst = (0, import_graphql3.concatAST)(
359
+ documents.reduce((prev, v) => {
360
+ return [...prev, v.document];
361
+ }, [])
362
+ );
363
+ const allFragments = [
364
+ ...allAst.definitions.filter(
365
+ (d) => d.kind === import_graphql3.Kind.FRAGMENT_DEFINITION
366
+ ).map((fragmentDef) => ({
367
+ node: fragmentDef,
368
+ name: fragmentDef.name.value,
369
+ onType: fragmentDef.typeCondition.name.value,
370
+ isExternal: false
371
+ })),
372
+ ...config2.externalFragments || []
373
+ ];
374
+ const visitor = new GenericSdkVisitor(schema, allFragments, config2);
375
+ const visitorResult = (0, import_graphql2.visit)(allAst, { leave: visitor });
376
+ return {
377
+ // We will take care of imports
378
+ // prepend: visitor.getImports(),
379
+ content: [
380
+ visitor.fragments,
381
+ ...visitorResult.definitions.filter((t) => typeof t === "string"),
382
+ visitor.sdkContent
383
+ ].join("\n")
384
+ };
385
+ };
386
+
387
+ // src/next/codegen/codegen/index.ts
388
+ var generateTypes = async (schema, queryPathGlob = process.cwd(), fragDocPath = process.cwd(), apiURL) => {
389
+ let docs = [];
390
+ let fragDocs = [];
391
+ docs = await loadGraphQLDocuments(queryPathGlob);
392
+ fragDocs = await loadGraphQLDocuments(fragDocPath);
393
+ const res = await (0, import_core.codegen)({
394
+ // Filename is not used. This is because the typescript plugin returns a string instead of writing to a file.
395
+ filename: process.cwd(),
396
+ schema: (0, import_graphql4.parse)((0, import_graphql4.printSchema)(schema)),
397
+ documents: [...docs, ...fragDocs],
398
+ config: {},
399
+ plugins: [
400
+ { typescript: {} },
401
+ { typescriptOperations: {} },
402
+ {
403
+ typescriptSdk: {}
404
+ },
405
+ { AddGeneratedClient: {} }
406
+ ],
407
+ pluginMap: {
408
+ typescript: {
409
+ plugin: import_typescript.plugin
410
+ },
411
+ typescriptOperations: {
412
+ plugin: import_typescript_operations.plugin
413
+ },
414
+ typescriptSdk: {
415
+ plugin
416
+ },
417
+ AddGeneratedClient: AddGeneratedClient(apiURL)
418
+ }
419
+ });
420
+ return res;
421
+ };
422
+ var loadGraphQLDocuments = async (globPath) => {
423
+ let result = [];
424
+ try {
425
+ result = await (0, import_load.loadDocuments)(globPath, {
426
+ loaders: [new import_graphql_file_loader.GraphQLFileLoader()]
427
+ });
428
+ } catch (e) {
429
+ if (
430
+ // https://www.graphql-tools.com/docs/documents-loading#no-files-found
431
+ (e.message || "").includes(
432
+ "Unable to find any GraphQL type definitions for the following pointers:"
433
+ )
434
+ ) {
435
+ } else {
436
+ throw e;
437
+ }
378
438
  }
379
- printoutputHTMLFilePath() {
380
- return this.outputHTMLFilePath.replace(`${this.publicFolderPath}/`, "");
439
+ return result;
440
+ };
441
+
442
+ // src/next/codegen/index.ts
443
+ var import_esbuild = require("esbuild");
444
+ var import_graphql6 = require("@tinacms/graphql");
445
+ var import_normalize_path = __toESM(require("normalize-path"));
446
+ var TINA_HOST = "content.tinajs.io";
447
+ var Codegen = class {
448
+ constructor({
449
+ configManager,
450
+ port,
451
+ queryDoc,
452
+ fragDoc,
453
+ isLocal,
454
+ graphqlSchemaDoc,
455
+ tinaSchema,
456
+ lookup,
457
+ noClientBuildCache
458
+ }) {
459
+ this.isLocal = isLocal;
460
+ this.graphqlSchemaDoc = graphqlSchemaDoc;
461
+ this.configManager = configManager;
462
+ this.port = port;
463
+ this.schema = (0, import_graphql5.buildASTSchema)(graphqlSchemaDoc);
464
+ this.tinaSchema = tinaSchema;
465
+ this.queryDoc = queryDoc;
466
+ this.fragDoc = fragDoc;
467
+ this.lookup = lookup;
468
+ this.noClientBuildCache = noClientBuildCache;
381
469
  }
382
- printRelativePath(filename) {
383
- if (filename) {
384
- return filename.replace(/\\/g, "/").replace(`${this.rootPath}/`, "");
470
+ async writeConfigFile(fileName, data) {
471
+ const filePath = import_path.default.join(
472
+ this.configManager.generatedFolderPath,
473
+ fileName
474
+ );
475
+ await import_fs_extra.default.ensureFile(filePath);
476
+ await import_fs_extra.default.outputFile(filePath, data);
477
+ if (this.configManager.hasSeparateContentRoot()) {
478
+ const filePath2 = import_path.default.join(
479
+ this.configManager.generatedFolderPathContentRepo,
480
+ fileName
481
+ );
482
+ await import_fs_extra.default.ensureFile(filePath2);
483
+ await import_fs_extra.default.outputFile(filePath2, data);
385
484
  }
386
- throw `No path provided to print`;
387
485
  }
388
- printPrebuildFilePath() {
389
- return this.prebuildFilePath.replace(/\\/g, "/").replace(`${this.rootPath}/${this.tinaFolderPath}/`, "");
486
+ async removeGeneratedFilesIfExists() {
487
+ await unlinkIfExists(this.configManager.generatedClientJSFilePath);
488
+ await unlinkIfExists(this.configManager.generatedTypesDFilePath);
489
+ await unlinkIfExists(this.configManager.generatedTypesJSFilePath);
490
+ await unlinkIfExists(this.configManager.generatedTypesTSFilePath);
491
+ await unlinkIfExists(this.configManager.generatedClientTSFilePath);
492
+ await unlinkIfExists(this.configManager.generatedQueriesFilePath);
493
+ await unlinkIfExists(this.configManager.generatedFragmentsFilePath);
390
494
  }
391
- printContentRelativePath(filename) {
392
- if (filename) {
393
- return filename.replace(/\\/g, "/").replace(`${this.contentRootPath}/`, "");
495
+ async execute() {
496
+ await this.writeConfigFile(
497
+ "_graphql.json",
498
+ JSON.stringify(this.graphqlSchemaDoc)
499
+ );
500
+ const { search, ...rest } = this.tinaSchema.schema.config;
501
+ this.tinaSchema.schema.config = rest;
502
+ await this.writeConfigFile(
503
+ "_schema.json",
504
+ JSON.stringify(this.tinaSchema.schema)
505
+ );
506
+ await this.writeConfigFile("_lookup.json", JSON.stringify(this.lookup));
507
+ const { apiURL, localUrl, tinaCloudUrl } = this._createApiUrl();
508
+ this.apiURL = apiURL;
509
+ this.localUrl = localUrl;
510
+ this.productionUrl = tinaCloudUrl;
511
+ if (this.configManager.shouldSkipSDK()) {
512
+ await this.removeGeneratedFilesIfExists();
513
+ return apiURL;
394
514
  }
395
- throw `No path provided to print`;
396
- }
397
- async getPathWithExtension(filepath) {
398
- const extensions = ["tsx", "ts", "jsx", "js"];
399
- let result;
400
- await Promise.all(
401
- extensions.map(async (ext) => {
402
- if (result) {
403
- return;
404
- }
405
- const filepathWithExtension = `${filepath}.${ext}`;
406
- const exists = import_fs_extra.default.existsSync(filepathWithExtension);
407
- if (exists) {
408
- result = filepathWithExtension;
409
- }
410
- })
515
+ await import_fs_extra.default.outputFile(
516
+ this.configManager.generatedQueriesFilePath,
517
+ this.queryDoc
411
518
  );
412
- return result;
413
- }
414
- async loadDatabaseFile() {
415
- const tmpdir = import_path.default.join(import_os.default.tmpdir(), Date.now().toString());
416
- const outfile = import_path.default.join(tmpdir, "database.build.js");
417
- await esbuild.build({
418
- entryPoints: [this.selfHostedDatabaseFilePath],
419
- bundle: true,
420
- platform: "node",
421
- outfile,
422
- loader: loaders
423
- });
424
- const result = require(outfile);
425
- import_fs_extra.default.removeSync(outfile);
426
- return result.default;
427
- }
428
- async loadConfigFile(generatedFolderPath, configFilePath) {
429
- 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");
431
- const outfile = import_path.default.join(tmpdir, "config.build.jsx");
432
- const outfile2 = import_path.default.join(tmpdir, "config.build.js");
433
- const tempTSConfigFile = import_path.default.join(tmpdir, "tsconfig.json");
434
- import_fs_extra.default.outputFileSync(tempTSConfigFile, "{}");
435
- const result2 = await esbuild.build({
436
- entryPoints: [configFilePath],
437
- bundle: true,
438
- target: ["es2020"],
439
- platform: "browser",
440
- format: "esm",
441
- logLevel: "silent",
442
- packages: "external",
443
- ignoreAnnotations: true,
444
- outfile: prebuild,
445
- loader: loaders,
446
- metafile: true
447
- });
448
- const flattenedList = [];
449
- Object.keys(result2.metafile.inputs).forEach((key) => {
450
- if (key.includes("node_modules") || key.includes("__generated__")) {
451
- return;
519
+ await import_fs_extra.default.outputFile(
520
+ this.configManager.generatedFragmentsFilePath,
521
+ this.fragDoc
522
+ );
523
+ await maybeWarnFragmentSize(this.configManager.generatedFragmentsFilePath);
524
+ const { clientString } = await this.genClient();
525
+ const databaseClientString = this.configManager.hasSelfHostedConfig() ? await this.genDatabaseClient() : "";
526
+ const { codeString, schemaString } = await this.genTypes();
527
+ await import_fs_extra.default.outputFile(
528
+ this.configManager.generatedGraphQLGQLPath,
529
+ schemaString
530
+ );
531
+ if (this.configManager.isUsingTs()) {
532
+ await import_fs_extra.default.outputFile(
533
+ this.configManager.generatedTypesTSFilePath,
534
+ codeString
535
+ );
536
+ await import_fs_extra.default.outputFile(
537
+ this.configManager.generatedClientTSFilePath,
538
+ clientString
539
+ );
540
+ if (this.configManager.hasSelfHostedConfig()) {
541
+ await import_fs_extra.default.outputFile(
542
+ this.configManager.generatedDatabaseClientTSFilePath,
543
+ databaseClientString
544
+ );
545
+ }
546
+ await unlinkIfExists(this.configManager.generatedClientJSFilePath);
547
+ await unlinkIfExists(this.configManager.generatedTypesDFilePath);
548
+ await unlinkIfExists(this.configManager.generatedTypesJSFilePath);
549
+ } else {
550
+ await import_fs_extra.default.outputFile(
551
+ this.configManager.generatedTypesDFilePath,
552
+ codeString
553
+ );
554
+ const jsTypes = await (0, import_esbuild.transform)(codeString, { loader: "ts" });
555
+ await import_fs_extra.default.outputFile(
556
+ this.configManager.generatedTypesJSFilePath,
557
+ jsTypes.code
558
+ );
559
+ await import_fs_extra.default.outputFile(
560
+ this.configManager.generatedClientDFilePath,
561
+ clientString
562
+ );
563
+ const jsClient = await (0, import_esbuild.transform)(clientString, { loader: "ts" });
564
+ await import_fs_extra.default.outputFile(
565
+ this.configManager.generatedClientJSFilePath,
566
+ jsClient.code
567
+ );
568
+ await unlinkIfExists(this.configManager.generatedTypesTSFilePath);
569
+ await unlinkIfExists(this.configManager.generatedClientTSFilePath);
570
+ if (this.configManager.hasSelfHostedConfig()) {
571
+ const jsDatabaseClient = await (0, import_esbuild.transform)(databaseClientString, {
572
+ loader: "ts"
573
+ });
574
+ await import_fs_extra.default.outputFile(
575
+ this.configManager.generatedDatabaseClientJSFilePath,
576
+ jsDatabaseClient.code
577
+ );
578
+ await import_fs_extra.default.outputFile(
579
+ this.configManager.generatedDatabaseClientDFilePath,
580
+ databaseClientString
581
+ );
582
+ await unlinkIfExists(
583
+ this.configManager.generatedDatabaseClientTSFilePath
584
+ );
452
585
  }
453
- flattenedList.push(key);
454
- });
455
- await esbuild.build({
456
- entryPoints: [configFilePath],
457
- bundle: true,
458
- target: ["es2020"],
459
- logLevel: "silent",
460
- platform: "node",
461
- outfile,
462
- loader: loaders
463
- });
464
- await esbuild.build({
465
- entryPoints: [outfile],
466
- bundle: true,
467
- logLevel: "silent",
468
- platform: "node",
469
- outfile: outfile2,
470
- loader: loaders
471
- });
472
- let result;
473
- try {
474
- result = require(outfile2);
475
- } catch (e) {
476
- console.error("Unexpected error loading config");
477
- console.error(e);
478
- throw e;
479
586
  }
480
- import_fs_extra.default.removeSync(outfile);
481
- import_fs_extra.default.removeSync(outfile2);
482
- return {
483
- config: result.default,
484
- prebuildPath: prebuild,
485
- watchList: flattenedList
486
- };
587
+ return apiURL;
487
588
  }
488
- };
489
- var loaders = {
490
- ".aac": "file",
491
- ".css": "file",
492
- ".eot": "file",
493
- ".flac": "file",
494
- ".gif": "file",
495
- ".jpeg": "file",
496
- ".jpg": "file",
497
- ".json": "json",
498
- ".mp3": "file",
499
- ".mp4": "file",
500
- ".ogg": "file",
501
- ".otf": "file",
502
- ".png": "file",
503
- ".svg": "file",
504
- ".ttf": "file",
505
- ".wav": "file",
506
- ".webm": "file",
507
- ".webp": "file",
508
- ".woff": "file",
509
- ".woff2": "file",
510
- ".js": "jsx",
511
- ".jsx": "jsx",
512
- ".tsx": "tsx"
513
- };
589
+ _createApiUrl() {
590
+ var _a, _b, _c, _d;
591
+ const branch = (_a = this.configManager.config) == null ? void 0 : _a.branch;
592
+ const clientId = (_b = this.configManager.config) == null ? void 0 : _b.clientId;
593
+ const token = (_c = this.configManager.config) == null ? void 0 : _c.token;
594
+ const fullVersion = this.configManager.getTinaGraphQLVersion();
595
+ const version2 = `${fullVersion.major}.${fullVersion.minor}`;
596
+ const baseUrl = ((_d = this.configManager.config.tinaioConfig) == null ? void 0 : _d.contentApiUrlOverride) || `https://${TINA_HOST}`;
597
+ if ((!branch || !clientId || !token) && !this.port && !this.configManager.config.contentApiUrlOverride) {
598
+ const missing = [];
599
+ if (!branch) missing.push("branch");
600
+ if (!clientId) missing.push("clientId");
601
+ if (!token) missing.push("token");
602
+ throw new Error(
603
+ `Client not configured properly. Missing ${missing.join(
604
+ ", "
605
+ )}. Please visit https://tina.io/docs/tina-cloud/overview for more information`
606
+ );
607
+ }
608
+ let localUrl = `http://localhost:${this.port}/graphql`;
609
+ let tinaCloudUrl = `${baseUrl}/${version2}/content/${clientId}/github/${branch}`;
610
+ let apiURL = this.isLocal ? `http://localhost:${this.port}/graphql` : `${baseUrl}/${version2}/content/${clientId}/github/${branch}`;
611
+ if (this.configManager.config.contentApiUrlOverride) {
612
+ apiURL = this.configManager.config.contentApiUrlOverride;
613
+ localUrl = apiURL;
614
+ tinaCloudUrl = apiURL;
615
+ }
616
+ return { apiURL, localUrl, tinaCloudUrl };
617
+ }
618
+ getApiURL() {
619
+ if (!this.apiURL)
620
+ throw new Error("apiURL not set. Please run execute() first");
621
+ return this.apiURL;
622
+ }
623
+ async genDatabaseClient() {
624
+ var _a, _b;
625
+ const authCollection = this.tinaSchema.getCollections().find((c) => c.isAuthCollection);
626
+ let authFields = [];
627
+ if (authCollection) {
628
+ const usersFields = (0, import_graphql6.mapUserFields)(authCollection, []);
629
+ if (usersFields.length === 0) {
630
+ throw new Error("No user field found");
631
+ }
632
+ if (usersFields.length > 1) {
633
+ throw new Error("Only one user field is allowed");
634
+ }
635
+ authFields = (_b = (_a = usersFields[0]) == null ? void 0 : _a.collectable) == null ? void 0 : _b.fields.map((f) => {
636
+ if (f.type !== "password" && f.type !== "object") {
637
+ if (f.uid) {
638
+ return `id:${f.name}`;
639
+ } else {
640
+ return `${f.name}`;
641
+ }
642
+ } else if (f.type === "password") {
643
+ return `_password: ${f.name} { passwordChangeRequired }`;
644
+ }
645
+ });
646
+ }
647
+ return `// @ts-nocheck
648
+ import { resolve } from "@tinacms/datalayer";
649
+ import type { TinaClient } from "tinacms/dist/client";
514
650
 
515
- // src/next/commands/dev-command/html.ts
516
- var errorHTML = `<style type="text/css">
517
- #no-assets-placeholder body {
518
- font-family: sans-serif;
519
- font-size: 16px;
520
- line-height: 1.4;
521
- color: #333;
522
- background-color: #f5f5f5;
651
+ import { queries } from "./types";
652
+ import database from "../database";
653
+
654
+ export async function databaseRequest({ query, variables, user }) {
655
+ const result = await resolve({
656
+ config: {
657
+ useRelativeMedia: true,
658
+ },
659
+ database,
660
+ query,
661
+ variables,
662
+ verbose: true,
663
+ ctxUser: user,
664
+ });
665
+
666
+ return result;
523
667
  }
524
- #no-assets-placeholder {
525
- max-width: 600px;
526
- margin: 0 auto;
527
- padding: 40px;
528
- text-align: center;
529
- background-color: #fff;
530
- box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.1);
668
+
669
+ export async function authenticate({ username, password }) {
670
+ return databaseRequest({
671
+ query: \`query auth($username:String!, $password:String!) {
672
+ authenticate(sub:$username, password:$password) {
673
+ ${authFields.join(" ")}
674
+ }
675
+ }\`,
676
+ variables: { username, password },
677
+ })
531
678
  }
532
- #no-assets-placeholder h1 {
533
- font-size: 24px;
534
- margin-bottom: 20px;
679
+
680
+ export async function authorize(user: { sub: string }) {
681
+ return databaseRequest({
682
+ query: \`query authz { authorize { ${authFields.join(" ")}} }\`,
683
+ variables: {},
684
+ user
685
+ })
535
686
  }
536
- #no-assets-placeholder p {
537
- margin-bottom: 10px;
687
+
688
+ function createDatabaseClient<GenQueries = Record<string, unknown>>({
689
+ queries,
690
+ }: {
691
+ queries: (client: {
692
+ request: TinaClient<GenQueries>["request"];
693
+ }) => GenQueries;
694
+ }) {
695
+ const request = async ({ query, variables, user }) => {
696
+ const data = await databaseRequest({ query, variables, user });
697
+ return { data: data.data as any, query, variables, errors: data.errors || null };
698
+ };
699
+ const q = queries({
700
+ request,
701
+ });
702
+ return { queries: q, request, authenticate, authorize };
538
703
  }
539
- #no-assets-placeholder a {
540
- color: #0077cc;
541
- text-decoration: none;
542
- }
543
- #no-assets-placeholder a:hover {
544
- text-decoration: underline;
545
- }
546
- </style>
547
- <div id="no-assets-placeholder">
548
- <h1>Failed loading TinaCMS assets</h1>
549
- <p>
550
- Your TinaCMS configuration may be misconfigured, and we could not load
551
- the assets for this page.
552
- </p>
553
- <p>
554
- Please visit <a href="https://tina.io/docs/tina-cloud/faq/#how-do-i-resolve-failed-loading-tinacms-assets-error">this doc</a> for help.
555
- </p>
556
- </div>
557
- </div>`.trim().replace(/[\r\n\s]+/g, " ");
558
- var devHTML = (port) => `<!DOCTYPE html>
559
- <html lang="en">
560
- <head>
561
- <meta charset="UTF-8" />
562
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
563
- <title>TinaCMS</title>
564
- </head>
565
704
 
566
- <!-- if development -->
567
- <script type="module">
568
- import RefreshRuntime from 'http://localhost:${port}/@react-refresh'
569
- RefreshRuntime.injectIntoGlobalHook(window)
570
- window.$RefreshReg$ = () => {}
571
- window.$RefreshSig$ = () => (type) => type
572
- window.__vite_plugin_react_preamble_installed__ = true
573
- <\/script>
574
- <script type="module" src="http://localhost:${port}/@vite/client"><\/script>
575
- <script>
576
- function handleLoadError() {
577
- // Assets have failed to load
578
- document.getElementById('root').innerHTML = '${errorHTML}';
579
- }
580
- <\/script>
581
- <script
582
- type="module"
583
- src="http://localhost:${port}/src/main.tsx"
584
- onerror="handleLoadError()"
585
- ><\/script>
586
- <body class="tina-tailwind">
587
- <div id="root"></div>
588
- </body>
589
- </html>`;
705
+ export const databaseClient = createDatabaseClient({ queries });
590
706
 
591
- // src/utils/theme.ts
592
- var import_chalk3 = __toESM(require("chalk"));
593
- var successText = import_chalk3.default.bold.green;
594
- var focusText = import_chalk3.default.bold;
595
- var dangerText = import_chalk3.default.bold.red;
596
- var neutralText = import_chalk3.default.bold.cyan;
597
- var linkText = import_chalk3.default.bold.cyan;
598
- var labelText = import_chalk3.default.bold;
599
- var cmdText = import_chalk3.default.inverse;
600
- var indentedCmd = (str) => {
601
- return ` \u2503 ` + str;
707
+ export const client = databaseClient;
708
+
709
+ export default databaseClient;
710
+ `;
711
+ }
712
+ async genClient() {
713
+ var _a, _b, _c;
714
+ const token = (_a = this.configManager.config) == null ? void 0 : _a.token;
715
+ const errorPolicy = (_c = (_b = this.configManager.config) == null ? void 0 : _b.client) == null ? void 0 : _c.errorPolicy;
716
+ const apiURL = this.getApiURL();
717
+ const clientString = `import { createClient } from "tinacms/dist/client";
718
+ import { queries } from "./types";
719
+ export const client = createClient({ ${this.noClientBuildCache === false ? `cacheDir: '${(0, import_normalize_path.default)(
720
+ this.configManager.generatedCachePath
721
+ )}', ` : ""}url: '${apiURL}', token: '${token}', queries, ${errorPolicy ? `errorPolicy: '${errorPolicy}'` : ""} });
722
+ export default client;
723
+ `;
724
+ return { apiURL, clientString };
725
+ }
726
+ async genTypes() {
727
+ const typescriptTypes = await generateTypes(
728
+ this.schema,
729
+ this.configManager.userQueriesAndFragmentsGlob,
730
+ this.configManager.generatedQueriesAndFragmentsGlob,
731
+ this.getApiURL()
732
+ );
733
+ const codeString = `//@ts-nocheck
734
+ // DO NOT MODIFY THIS FILE. This file is automatically generated by Tina
735
+ export function gql(strings: TemplateStringsArray, ...args: string[]): string {
736
+ let str = ''
737
+ strings.forEach((string, i) => {
738
+ str += string + (args[i] || '')
739
+ })
740
+ return str
741
+ }
742
+ ${typescriptTypes}
743
+ `;
744
+ const schemaString = `# DO NOT MODIFY THIS FILE. This file is automatically generated by Tina
745
+ ${(0, import_graphql5.printSchema)(this.schema)}
746
+ schema {
747
+ query: Query
748
+ mutation: Mutation
749
+ }
750
+ `;
751
+ return { codeString, schemaString };
752
+ }
602
753
  };
603
- var indentText = (str) => {
604
- return String(str).split("\n").map((line) => ` ${line}`).join("\n");
754
+ var maybeWarnFragmentSize = async (filepath) => {
755
+ if (
756
+ // is the file bigger than 100kb?
757
+ (await import_fs_extra.default.stat(filepath)).size > // convert to 100 kb to bytes
758
+ 100 * 1024
759
+ ) {
760
+ console.warn(
761
+ "Warning: frags.gql is very large (>100kb). Consider setting the reference depth to 1 or 0. See code snippet below."
762
+ );
763
+ console.log(
764
+ `const schema = defineSchema({
765
+ client: {
766
+ referenceDepth: 1,
767
+ },
768
+ // ...
769
+ })`
770
+ );
771
+ }
772
+ };
773
+ var unlinkIfExists = async (filepath) => {
774
+ if (import_fs_extra.default.existsSync(filepath)) {
775
+ import_fs_extra.default.unlinkSync(filepath);
776
+ }
605
777
  };
606
- var logText = import_chalk3.default.italic.gray;
607
- var warnText = import_chalk3.default.yellowBright.bgBlack;
608
- var titleText = import_chalk3.default.bgHex("d2f1f8").hex("ec4816");
609
- var CONFIRMATION_TEXT = import_chalk3.default.dim("enter to confirm");
610
-
611
- // src/next/commands/dev-command/server/index.ts
612
- var import_vite3 = require("vite");
613
778
 
614
- // src/next/vite/index.ts
615
- var import_node_path2 = __toESM(require("path"));
616
- var import_plugin_react = __toESM(require("@vitejs/plugin-react"));
779
+ // src/next/config-manager.ts
617
780
  var import_fs_extra2 = __toESM(require("fs-extra"));
781
+ var import_path2 = __toESM(require("path"));
782
+ var import_os = __toESM(require("os"));
783
+ var esbuild = __toESM(require("esbuild"));
784
+ var dotenv = __toESM(require("dotenv"));
618
785
  var import_normalize_path2 = __toESM(require("normalize-path"));
619
- var import_vite = require("vite");
620
-
621
- // src/next/vite/tailwind.ts
622
- var import_node_path = __toESM(require("path"));
623
- var import_aspect_ratio = __toESM(require("@tailwindcss/aspect-ratio"));
624
- var import_container_queries = __toESM(require("@tailwindcss/container-queries"));
625
- var import_typography = __toESM(require("@tailwindcss/typography"));
626
- var import_tailwindcss = __toESM(require("tailwindcss"));
627
- var import_defaultTheme = __toESM(require("tailwindcss/defaultTheme.js"));
628
- var tinaTailwind = (spaPath, prebuildFilePath) => {
629
- return {
630
- name: "vite-plugin-tina",
631
- config: (viteConfig) => {
632
- const plugins = [];
633
- const content = [
634
- import_node_path.default.join(spaPath, "src/**/*.{vue,js,ts,jsx,tsx,svelte}"),
635
- prebuildFilePath,
636
- require.resolve("tinacms")
637
- ];
638
- const tw = (0, import_tailwindcss.default)({
639
- theme: {
640
- columns: {
641
- auto: "auto",
642
- 1: "1",
643
- 2: "2",
644
- 3: "3",
645
- 4: "4",
646
- 5: "5",
647
- 6: "6",
648
- 7: "7",
649
- 8: "8",
650
- 9: "9",
651
- 10: "10",
652
- 11: "11",
653
- 12: "12",
654
- "3xs": "256px",
655
- "2xs": "288px",
656
- xs: "320px",
657
- sm: "384px",
658
- md: "448px",
659
- lg: "512px",
660
- xl: "576px",
661
- "2xl": "672px",
662
- "3xl": "768px",
663
- "4xl": "896px",
664
- "5xl": "1024px",
665
- "6xl": "1152px",
666
- "7xl": "1280px"
667
- },
668
- spacing: {
669
- px: "1px",
670
- 0: "0px",
671
- 0.5: "2px",
672
- 1: "4px",
673
- 1.5: "6px",
674
- 2: "8px",
675
- 2.5: "10px",
676
- 3: "12px",
677
- 3.5: "14px",
678
- 4: "16px",
679
- 5: "20px",
680
- 6: "24px",
681
- 7: "28px",
682
- 8: "32px",
683
- 9: "36px",
684
- 10: "40px",
685
- 11: "44px",
686
- 12: "48px",
687
- 14: "56px",
688
- 16: "64px",
689
- 18: "72px",
690
- 20: "80px",
691
- 24: "96px",
692
- 28: "114px",
693
- 32: "128px",
694
- 36: "144px",
695
- 40: "160px",
696
- 44: "176px",
697
- 48: "192px",
698
- 52: "208px",
699
- 56: "224px",
700
- 60: "240px",
701
- 64: "256px",
702
- 72: "288px",
703
- 80: "320px",
704
- 96: "384px"
705
- },
706
- borderRadius: {
707
- none: "0px",
708
- sm: "2px",
709
- DEFAULT: "4px",
710
- md: "6px",
711
- lg: "8px",
712
- xl: "12px",
713
- "2xl": "16px",
714
- "3xl": "24px",
715
- full: "9999px"
716
- },
717
- borderWidth: {
718
- DEFAULT: "1px",
719
- 0: "0",
720
- 2: "2px",
721
- 3: "3px",
722
- 4: "4px",
723
- 6: "6px",
724
- 8: "8px"
725
- },
726
- fontSize: {
727
- xs: ["13px", { lineHeight: "1.33" }],
728
- sm: ["14px", { lineHeight: "1.43" }],
729
- base: ["16px", { lineHeight: "1.5" }],
730
- md: ["16px", { lineHeight: "1.5" }],
731
- lg: ["18px", { lineHeight: "1.55" }],
732
- xl: ["20px", { lineHeight: "1.4" }],
733
- "2xl": ["24px", { lineHeight: "1.33" }],
734
- "3xl": ["30px", { lineHeight: "1.2" }],
735
- "4xl": ["36px", { lineHeight: "1.1" }],
736
- "5xl": ["48px", { lineHeight: "1" }],
737
- "6xl": ["60px", { lineHeight: "1" }],
738
- "7xl": ["72px", { lineHeight: "1" }],
739
- "8xl": ["96px", { lineHeight: "1" }],
740
- "9xl": ["128px", { lineHeight: "1" }]
741
- },
742
- opacity: {
743
- 0: "0",
744
- 5: ".05",
745
- 7: ".07",
746
- 10: ".1",
747
- 15: ".15",
748
- 20: ".2",
749
- 25: ".25",
750
- 30: ".3",
751
- 40: ".4",
752
- 50: ".5",
753
- 60: ".6",
754
- 70: ".7",
755
- 75: ".75",
756
- 80: ".8",
757
- 90: ".9",
758
- 100: "1"
759
- },
760
- zIndex: {
761
- "-1": "-1",
762
- base: "9000",
763
- panel: "9400",
764
- menu: "9800",
765
- chrome: "10200",
766
- overlay: "10600",
767
- modal: "10800",
768
- 0: "0",
769
- 10: "10",
770
- 20: "20",
771
- 30: "30",
772
- 40: "40",
773
- 25: "25",
774
- 50: "50",
775
- 75: "75",
776
- 100: "100",
777
- auto: "auto"
778
- },
779
- extend: {
780
- scale: {
781
- 97: ".97",
782
- 103: "1.03"
783
- },
784
- transitionDuration: {
785
- 0: "0ms",
786
- 2e3: "2000ms"
787
- },
788
- boxShadow: {
789
- xs: "0 0 0 1px rgba(0, 0, 0, 0.05)",
790
- outline: "0 0 0 3px rgba(66, 153, 225, 0.5)"
791
- },
792
- colors: {
793
- blue: {
794
- 50: "#DCEEFF",
795
- 100: "#B4DBFF",
796
- 200: "#85C5FE",
797
- 300: "#4EABFE",
798
- 400: "#2296fe",
799
- 500: "#0084FF",
800
- 600: "#0574e4",
801
- 700: "#0D5DBD",
802
- 800: "#144696",
803
- 900: "#1D2C6C",
804
- 1e3: "#241748"
805
- },
806
- gray: {
807
- 50: "#F6F6F9",
808
- 100: "#EDECF3",
809
- 150: "#E6E3EF",
810
- 200: "#E1DDEC",
811
- 250: "#C9C5D5",
812
- 300: "#b2adbe",
813
- 400: "#918c9e",
814
- 500: "#716c7f",
815
- 600: "#565165",
816
- 700: "#433e52",
817
- 800: "#363145",
818
- 900: "#252336",
819
- 1e3: "#1c1b2e"
820
- },
821
- orange: {
822
- 400: "#EB6337",
823
- 500: "#EC4815",
824
- 600: "#DC4419"
825
- },
826
- background: "#FFFFFF",
827
- foreground: "#0A0A0A",
828
- muted: "#F5F5F5",
829
- "muted-foreground": "#737373",
830
- popover: "#FFFFFF",
831
- "popover-foreground": "#0A0A0A",
832
- card: "#FFFFFF",
833
- "card-foreground": "#0A0A0A",
834
- border: "#E5E5E5",
835
- input: "#E5E5E5",
836
- primary: "#171717",
837
- "primary-foreground": "#FAFAFA",
838
- secondary: "#F5F5F5",
839
- "secondary-foreground": "#171717",
840
- accent: "#F5F5F5",
841
- "accent-foreground": "#171717",
842
- destructive: "#FF3B3B",
843
- "destructive-foreground": "#FAFAFA",
844
- ring: "#0A0A0A"
845
- },
846
- fontFamily: {
847
- sans: ["Inter", ...import_defaultTheme.default.fontFamily.sans]
848
- },
849
- lineHeight: {
850
- 3: "12px",
851
- 4: "16px",
852
- 5: "20px",
853
- 6: "24px",
854
- 7: "28px",
855
- 8: "32px",
856
- 9: "36px",
857
- 10: "40px"
858
- },
859
- maxWidth: {
860
- form: "900px"
861
- },
862
- screens: {
863
- xs: "320px",
864
- sm: "560px",
865
- md: "720px",
866
- lg: "1030px"
867
- }
868
- }
869
- },
870
- content,
871
- plugins: [
872
- (0, import_typography.default)({ className: "tina-prose" }),
873
- import_aspect_ratio.default,
874
- import_container_queries.default
875
- ]
876
- });
877
- plugins.push(tw);
878
- return {
879
- css: {
880
- postcss: {
881
- plugins
882
- }
883
- }
884
- };
885
- }
886
- };
887
- };
888
-
889
- // src/next/vite/index.ts
890
- async function listFilesRecursively({
891
- directoryPath,
892
- config: config2,
893
- roothPath
894
- }) {
895
- const fullDirectoryPath = import_node_path2.default.join(
896
- roothPath,
897
- config2.publicFolder,
898
- directoryPath
899
- );
900
- const exists = await import_fs_extra2.default.pathExists(fullDirectoryPath);
901
- if (!exists) {
902
- return { "0": [] };
786
+ var import_chalk3 = __toESM(require("chalk"));
787
+ var TINA_FOLDER = "tina";
788
+ var LEGACY_TINA_FOLDER = ".tina";
789
+ var GENERATED_FOLDER = "__generated__";
790
+ var GRAPHQL_JSON_FILE = "_graphql.json";
791
+ var GRAPHQL_GQL_FILE = "schema.gql";
792
+ var SCHEMA_JSON_FILE = "_schema.json";
793
+ var LOOKUP_JSON_FILE = "_lookup.json";
794
+ var ConfigManager = class {
795
+ constructor({
796
+ rootPath = process.cwd(),
797
+ tinaGraphQLVersion,
798
+ legacyNoSDK
799
+ }) {
800
+ this.rootPath = (0, import_normalize_path2.default)(rootPath);
801
+ this.tinaGraphQLVersionFromCLI = tinaGraphQLVersion;
802
+ this.legacyNoSDK = legacyNoSDK;
903
803
  }
904
- const items = await import_fs_extra2.default.readdir(fullDirectoryPath);
905
- const staticMediaItems = [];
906
- for (const item of items) {
907
- const itemPath = import_node_path2.default.join(fullDirectoryPath, item);
908
- const stats = await import_fs_extra2.default.promises.lstat(itemPath);
909
- const staticMediaItem = {
910
- id: item,
911
- filename: item,
912
- type: stats.isDirectory() ? "dir" : "file",
913
- directory: `${directoryPath.replace(config2.mediaRoot, "")}`,
914
- src: `/${import_node_path2.default.join(directoryPath, item)}`,
915
- thumbnails: {
916
- "75x75": `/${import_node_path2.default.join(directoryPath, item)}`,
917
- "400x400": `/${import_node_path2.default.join(directoryPath, item)}`,
918
- "1000x1000": `/${import_node_path2.default.join(directoryPath, item)}`
919
- }
920
- };
921
- if (stats.isDirectory()) {
922
- staticMediaItem.children = await listFilesRecursively({
923
- directoryPath: import_node_path2.default.join(directoryPath, item),
924
- config: config2,
925
- roothPath
926
- });
927
- }
928
- staticMediaItems.push(staticMediaItem);
804
+ isUsingTs() {
805
+ return [".ts", ".tsx"].includes(import_path2.default.extname(this.tinaConfigFilePath));
929
806
  }
930
- function chunkArrayIntoObject(array, chunkSize) {
931
- const result = {};
932
- for (let i = 0; i < array.length; i += chunkSize) {
933
- const chunkKey = `${i / chunkSize * 20}`;
934
- result[chunkKey] = array.slice(i, i + chunkSize);
935
- }
936
- return result;
807
+ hasSelfHostedConfig() {
808
+ return !!this.selfHostedDatabaseFilePath;
937
809
  }
938
- return chunkArrayIntoObject(staticMediaItems, 20);
939
- }
940
- var createConfig = async ({
941
- configManager,
942
- database,
943
- apiURL,
944
- plugins = [],
945
- noWatch,
946
- rollupOptions
947
- }) => {
948
- var _a, _b, _c, _d, _e, _f, _g, _h;
949
- const publicEnv = {};
950
- Object.keys(process.env).forEach((key) => {
951
- if (key.startsWith("TINA_PUBLIC_") || key.startsWith("NEXT_PUBLIC_") || key === "NODE_ENV" || key === "HEAD") {
952
- try {
953
- if (typeof process.env[key] === "string") {
954
- publicEnv[key] = process.env[key];
955
- } else {
956
- publicEnv[key] = JSON.stringify(process.env[key]);
957
- }
958
- } catch (error) {
959
- console.warn(
960
- `Could not stringify public env process.env.${key} env variable`
961
- );
962
- console.warn(error);
963
- }
810
+ hasSeparateContentRoot() {
811
+ return this.rootPath !== this.contentRootPath;
812
+ }
813
+ shouldSkipSDK() {
814
+ var _a;
815
+ if (this.legacyNoSDK) {
816
+ return this.legacyNoSDK;
964
817
  }
965
- });
966
- const staticMediaPath = import_node_path2.default.join(
967
- configManager.generatedFolderPath,
968
- "static-media.json"
969
- );
970
- if ((_b = (_a = configManager.config.media) == null ? void 0 : _a.tina) == null ? void 0 : _b.static) {
971
- const staticMedia = await listFilesRecursively({
972
- directoryPath: ((_c = configManager.config.media.tina) == null ? void 0 : _c.mediaRoot) || "",
973
- config: configManager.config.media.tina,
974
- roothPath: configManager.rootPath
975
- });
976
- await import_fs_extra2.default.outputFile(staticMediaPath, JSON.stringify(staticMedia, null, 2));
977
- } else {
978
- await import_fs_extra2.default.outputFile(staticMediaPath, `[]`);
818
+ return ((_a = this.config.client) == null ? void 0 : _a.skip) || false;
979
819
  }
980
- const alias = {
981
- TINA_IMPORT: configManager.prebuildFilePath,
982
- SCHEMA_IMPORT: configManager.generatedGraphQLJSONPath,
983
- STATIC_MEDIA_IMPORT: staticMediaPath,
984
- crypto: import_node_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts"),
985
- fs: import_node_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts"),
986
- os: import_node_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts"),
987
- path: import_node_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts")
988
- };
989
- if (configManager.shouldSkipSDK()) {
990
- alias["CLIENT_IMPORT"] = import_node_path2.default.join(
991
- configManager.spaRootPath,
992
- "src",
993
- "dummy-client.ts"
820
+ async processConfig() {
821
+ this.tinaFolderPath = await this.getTinaFolderPath(this.rootPath);
822
+ this.envFilePath = import_path2.default.resolve(
823
+ import_path2.default.join(this.tinaFolderPath, "..", ".env")
994
824
  );
995
- } else {
996
- alias["CLIENT_IMPORT"] = configManager.isUsingTs() ? configManager.generatedTypesTSFilePath : configManager.generatedTypesJSFilePath;
997
- }
998
- let basePath;
999
- if (configManager.config.build.basePath) {
1000
- basePath = configManager.config.build.basePath;
1001
- }
1002
- const config2 = {
1003
- root: configManager.spaRootPath,
1004
- base: `/${basePath ? `${(0, import_normalize_path2.default)(basePath)}/` : ""}${(0, import_normalize_path2.default)(
1005
- configManager.config.build.outputFolder
1006
- )}/`,
1007
- appType: "spa",
1008
- resolve: {
1009
- alias,
1010
- dedupe: ["graphql", "tinacms", "react", "react-dom", "react-router-dom"]
1011
- },
1012
- define: {
1013
- "process.env": `new Object(${JSON.stringify(publicEnv)})`,
1014
- "process.platform": `"${process.platform}"`,
1015
- __API_URL__: `"${apiURL}"`,
1016
- __BASE_PATH__: `"${((_e = (_d = configManager.config) == null ? void 0 : _d.build) == null ? void 0 : _e.basePath) || ""}"`,
1017
- __TINA_GRAPHQL_VERSION__: `"${configManager.getTinaGraphQLVersion()}"`
1018
- },
1019
- logLevel: "error",
1020
- optimizeDeps: {
1021
- force: true,
1022
- include: ["react/jsx-runtime", "react/jsx-dev-runtime"]
1023
- },
1024
- server: {
1025
- host: (_h = (_g = (_f = configManager.config) == null ? void 0 : _f.build) == null ? void 0 : _g.host) != null ? _h : false,
1026
- watch: noWatch ? {
1027
- ignored: ["**/*"]
1028
- } : {
1029
- ignored: [
1030
- `${configManager.tinaFolderPath}/**/!(config.prebuild.jsx|_graphql.json)`
1031
- ]
1032
- },
1033
- fs: {
1034
- strict: false
825
+ dotenv.config({ path: this.envFilePath });
826
+ this.tinaConfigFilePath = await this.getPathWithExtension(
827
+ import_path2.default.join(this.tinaFolderPath, "config")
828
+ );
829
+ if (!this.tinaConfigFilePath) {
830
+ throw new Error(
831
+ `Unable to find config file in ${this.tinaFolderPath}. Looking for a file named "config.{ts,tsx,js,jsx}"`
832
+ );
833
+ }
834
+ this.selfHostedDatabaseFilePath = await this.getPathWithExtension(
835
+ import_path2.default.join(this.tinaFolderPath, "database")
836
+ );
837
+ this.generatedFolderPath = import_path2.default.join(this.tinaFolderPath, GENERATED_FOLDER);
838
+ this.generatedCachePath = import_path2.default.join(
839
+ this.generatedFolderPath,
840
+ ".cache",
841
+ String((/* @__PURE__ */ new Date()).getTime())
842
+ );
843
+ this.generatedGraphQLGQLPath = import_path2.default.join(
844
+ this.generatedFolderPath,
845
+ GRAPHQL_GQL_FILE
846
+ );
847
+ this.generatedGraphQLJSONPath = import_path2.default.join(
848
+ this.generatedFolderPath,
849
+ GRAPHQL_JSON_FILE
850
+ );
851
+ this.generatedSchemaJSONPath = import_path2.default.join(
852
+ this.generatedFolderPath,
853
+ SCHEMA_JSON_FILE
854
+ );
855
+ this.generatedLookupJSONPath = import_path2.default.join(
856
+ this.generatedFolderPath,
857
+ LOOKUP_JSON_FILE
858
+ );
859
+ this.generatedQueriesFilePath = import_path2.default.join(
860
+ this.generatedFolderPath,
861
+ "queries.gql"
862
+ );
863
+ this.generatedFragmentsFilePath = import_path2.default.join(
864
+ this.generatedFolderPath,
865
+ "frags.gql"
866
+ );
867
+ this.generatedTypesTSFilePath = import_path2.default.join(
868
+ this.generatedFolderPath,
869
+ "types.ts"
870
+ );
871
+ this.generatedTypesJSFilePath = import_path2.default.join(
872
+ this.generatedFolderPath,
873
+ "types.js"
874
+ );
875
+ this.generatedTypesDFilePath = import_path2.default.join(
876
+ this.generatedFolderPath,
877
+ "types.d.ts"
878
+ );
879
+ this.userQueriesAndFragmentsGlob = import_path2.default.join(
880
+ this.tinaFolderPath,
881
+ "queries/**/*.{graphql,gql}"
882
+ );
883
+ this.generatedQueriesAndFragmentsGlob = import_path2.default.join(
884
+ this.generatedFolderPath,
885
+ "*.{graphql,gql}"
886
+ );
887
+ this.generatedClientTSFilePath = import_path2.default.join(
888
+ this.generatedFolderPath,
889
+ "client.ts"
890
+ );
891
+ this.generatedClientJSFilePath = import_path2.default.join(
892
+ this.generatedFolderPath,
893
+ "client.js"
894
+ );
895
+ this.generatedClientDFilePath = import_path2.default.join(
896
+ this.generatedFolderPath,
897
+ "client.d.ts"
898
+ );
899
+ this.generatedDatabaseClientDFilePath = import_path2.default.join(
900
+ this.generatedFolderPath,
901
+ "databaseClient.d.ts"
902
+ );
903
+ this.generatedDatabaseClientTSFilePath = import_path2.default.join(
904
+ this.generatedFolderPath,
905
+ "databaseClient.ts"
906
+ );
907
+ this.generatedDatabaseClientJSFilePath = import_path2.default.join(
908
+ this.generatedFolderPath,
909
+ "databaseClient.js"
910
+ );
911
+ const clientExists = this.isUsingTs() ? await import_fs_extra2.default.pathExists(this.generatedClientTSFilePath) : await import_fs_extra2.default.pathExists(this.generatedClientJSFilePath);
912
+ if (!clientExists) {
913
+ const file = "export default ()=>({})\nexport const client = ()=>({})";
914
+ if (this.isUsingTs()) {
915
+ await import_fs_extra2.default.outputFile(this.generatedClientTSFilePath, file);
916
+ } else {
917
+ await import_fs_extra2.default.outputFile(this.generatedClientJSFilePath, file);
1035
918
  }
1036
- },
1037
- build: {
1038
- sourcemap: false,
1039
- outDir: configManager.outputFolderPath,
1040
- emptyOutDir: true,
1041
- rollupOptions
1042
- },
1043
- plugins: [
1044
- (0, import_plugin_react.default)({
1045
- babel: {
1046
- compact: true
1047
- }
1048
- }),
1049
- (0, import_vite.splitVendorChunkPlugin)(),
1050
- tinaTailwind(configManager.spaRootPath, configManager.prebuildFilePath),
1051
- ...plugins
1052
- ]
1053
- };
1054
- return config2;
1055
- };
1056
-
1057
- // src/next/vite/plugins.ts
1058
- var import_pluginutils = require("@rollup/pluginutils");
1059
- var import_fs = __toESM(require("fs"));
1060
- var import_vite2 = require("vite");
1061
- var import_esbuild = require("esbuild");
1062
- var import_path3 = __toESM(require("path"));
1063
- var import_body_parser = __toESM(require("body-parser"));
1064
- var import_cors = __toESM(require("cors"));
1065
- var import_graphql = require("@tinacms/graphql");
1066
-
1067
- // src/next/commands/dev-command/server/media.ts
1068
- var import_fs_extra3 = __toESM(require("fs-extra"));
1069
- var import_path2 = __toESM(require("path"));
1070
- var import_busboy = __toESM(require("busboy"));
1071
- var createMediaRouter = (config2) => {
1072
- const mediaFolder = import_path2.default.join(
1073
- config2.rootPath,
1074
- config2.publicFolder,
1075
- config2.mediaRoot
1076
- );
1077
- const mediaModel = new MediaModel(config2);
1078
- const handleList = async (req, res) => {
1079
- const requestURL = new URL(req.url, config2.apiURL);
1080
- const folder = requestURL.pathname.replace("/media/list/", "");
1081
- const limit = requestURL.searchParams.get("limit");
1082
- const cursor = requestURL.searchParams.get("cursor");
1083
- const media = await mediaModel.listMedia({
1084
- searchPath: folder,
1085
- cursor,
1086
- limit
1087
- });
1088
- res.end(JSON.stringify(media));
1089
- };
1090
- const handleDelete = async (req, res) => {
1091
- const file = decodeURIComponent(req.url.slice("/media/".length));
1092
- const didDelete = await mediaModel.deleteMedia({ searchPath: file });
1093
- res.end(JSON.stringify(didDelete));
1094
- };
1095
- const handlePost = async function(req, res) {
1096
- const bb = (0, import_busboy.default)({ headers: req.headers });
1097
- bb.on("file", async (_name, file, _info) => {
1098
- var _a;
1099
- const fullPath = decodeURI((_a = req.url) == null ? void 0 : _a.slice("/media/upload/".length));
1100
- const saveTo = import_path2.default.join(mediaFolder, ...fullPath.split("/"));
1101
- await import_fs_extra3.default.ensureDir(import_path2.default.dirname(saveTo));
1102
- file.pipe(import_fs_extra3.default.createWriteStream(saveTo));
1103
- });
1104
- bb.on("error", (error) => {
1105
- res.statusCode = 500;
1106
- if (error instanceof Error) {
1107
- res.end(JSON.stringify({ message: error }));
919
+ }
920
+ const { config: config2, prebuildPath, watchList } = await this.loadConfigFile(
921
+ this.generatedFolderPath,
922
+ this.tinaConfigFilePath
923
+ );
924
+ this.watchList = watchList;
925
+ this.config = config2;
926
+ this.prebuildFilePath = prebuildPath;
927
+ this.publicFolderPath = import_path2.default.join(
928
+ this.rootPath,
929
+ this.config.build.publicFolder
930
+ );
931
+ this.outputFolderPath = import_path2.default.join(
932
+ this.publicFolderPath,
933
+ this.config.build.outputFolder
934
+ );
935
+ this.outputHTMLFilePath = import_path2.default.join(this.outputFolderPath, "index.html");
936
+ this.outputGitignorePath = import_path2.default.join(this.outputFolderPath, ".gitignore");
937
+ const fullLocalContentPath = import_path2.default.join(
938
+ this.tinaFolderPath,
939
+ this.config.localContentPath || ""
940
+ );
941
+ if (this.config.localContentPath) {
942
+ const localContentPathExists = await import_fs_extra2.default.pathExists(fullLocalContentPath);
943
+ if (localContentPathExists) {
944
+ logger.info(`Using separate content repo at ${fullLocalContentPath}`);
945
+ this.contentRootPath = fullLocalContentPath;
1108
946
  } else {
1109
- res.end(JSON.stringify({ message: "Unknown error while uploading" }));
947
+ logger.warn(
948
+ `${import_chalk3.default.yellow("Warning:")} The localContentPath ${import_chalk3.default.cyan(
949
+ fullLocalContentPath
950
+ )} does not exist. Please create it or remove the localContentPath from your config file at ${import_chalk3.default.cyan(
951
+ this.tinaConfigFilePath
952
+ )}`
953
+ );
1110
954
  }
1111
- });
1112
- bb.on("close", () => {
1113
- res.statusCode = 200;
1114
- res.end(JSON.stringify({ success: true }));
1115
- });
1116
- req.pipe(bb);
1117
- };
1118
- return { handleList, handleDelete, handlePost };
1119
- };
1120
- var parseMediaFolder = (str) => {
1121
- let returnString = str;
1122
- if (returnString.startsWith("/"))
1123
- returnString = returnString.substr(1);
1124
- if (returnString.endsWith("/"))
1125
- returnString = returnString.substr(0, returnString.length - 1);
1126
- return returnString;
1127
- };
1128
- var MediaModel = class {
1129
- constructor({ rootPath, publicFolder, mediaRoot }) {
1130
- this.rootPath = rootPath;
1131
- this.mediaRoot = mediaRoot;
1132
- this.publicFolder = publicFolder;
955
+ }
956
+ if (!this.contentRootPath) {
957
+ this.contentRootPath = this.rootPath;
958
+ }
959
+ this.generatedFolderPathContentRepo = import_path2.default.join(
960
+ await this.getTinaFolderPath(this.contentRootPath),
961
+ GENERATED_FOLDER
962
+ );
963
+ this.spaMainPath = require.resolve("@tinacms/app");
964
+ this.spaRootPath = import_path2.default.join(this.spaMainPath, "..", "..");
1133
965
  }
1134
- async listMedia(args) {
1135
- try {
1136
- const folderPath = (0, import_path2.join)(
1137
- this.rootPath,
1138
- this.publicFolder,
1139
- this.mediaRoot,
1140
- args.searchPath
1141
- );
1142
- const searchPath = parseMediaFolder(args.searchPath);
1143
- if (!await import_fs_extra3.default.pathExists(folderPath)) {
1144
- return {
1145
- files: [],
1146
- directories: []
1147
- };
1148
- }
1149
- const filesStr = await import_fs_extra3.default.readdir(folderPath);
1150
- const filesProm = filesStr.map(async (file) => {
1151
- const filePath = (0, import_path2.join)(folderPath, file);
1152
- const stat = await import_fs_extra3.default.stat(filePath);
1153
- let src = `/${file}`;
1154
- const isFile = stat.isFile();
1155
- if (!isFile) {
1156
- return {
1157
- isFile,
1158
- size: stat.size,
1159
- src,
1160
- filename: file
1161
- };
1162
- }
1163
- if (searchPath) {
1164
- src = `/${searchPath}${src}`;
1165
- }
1166
- if (this.mediaRoot) {
1167
- src = `/${this.mediaRoot}${src}`;
1168
- }
1169
- return {
1170
- isFile,
1171
- size: stat.size,
1172
- src,
1173
- filename: file
1174
- };
1175
- });
1176
- const offset = Number(args.cursor) || 0;
1177
- const limit = Number(args.limit) || 20;
1178
- const rawItems = await Promise.all(filesProm);
1179
- const sortedItems = rawItems.sort((a, b) => {
1180
- if (a.isFile && !b.isFile) {
1181
- return 1;
1182
- }
1183
- if (!a.isFile && b.isFile) {
1184
- return -1;
1185
- }
1186
- return 0;
1187
- });
1188
- const limitItems = sortedItems.slice(offset, offset + limit);
1189
- const files = limitItems.filter((x) => x.isFile);
1190
- const directories = limitItems.filter((x) => !x.isFile).map((x) => x.src);
1191
- const cursor = rawItems.length > offset + limit ? String(offset + limit) : null;
1192
- return {
1193
- files,
1194
- directories,
1195
- cursor
1196
- };
1197
- } catch (error) {
1198
- console.error(error);
966
+ async getTinaFolderPath(rootPath) {
967
+ const tinaFolderPath = import_path2.default.join(rootPath, TINA_FOLDER);
968
+ const tinaFolderExists = await import_fs_extra2.default.pathExists(tinaFolderPath);
969
+ if (tinaFolderExists) {
970
+ this.isUsingLegacyFolder = false;
971
+ return tinaFolderPath;
972
+ }
973
+ const legacyFolderPath = import_path2.default.join(rootPath, LEGACY_TINA_FOLDER);
974
+ const legacyFolderExists = await import_fs_extra2.default.pathExists(legacyFolderPath);
975
+ if (legacyFolderExists) {
976
+ this.isUsingLegacyFolder = true;
977
+ return legacyFolderPath;
978
+ }
979
+ throw new Error(
980
+ `Unable to find Tina folder, if you're working in folder outside of the Tina config be sure to specify --rootPath`
981
+ );
982
+ }
983
+ getTinaGraphQLVersion() {
984
+ if (this.tinaGraphQLVersionFromCLI) {
985
+ const version2 = this.tinaGraphQLVersionFromCLI.split(".");
1199
986
  return {
1200
- files: [],
1201
- directories: [],
1202
- error: error == null ? void 0 : error.toString()
987
+ fullVersion: this.tinaGraphQLVersionFromCLI,
988
+ major: version2[0] || "x",
989
+ minor: version2[1] || "x",
990
+ patch: version2[2] || "x"
1203
991
  };
1204
992
  }
1205
- }
1206
- async deleteMedia(args) {
1207
- try {
1208
- const file = (0, import_path2.join)(
1209
- this.rootPath,
1210
- this.publicFolder,
1211
- this.mediaRoot,
1212
- args.searchPath
993
+ const generatedSchema = import_fs_extra2.default.readJSONSync(this.generatedSchemaJSONPath);
994
+ if (!generatedSchema || !(typeof (generatedSchema == null ? void 0 : generatedSchema.version) !== "undefined")) {
995
+ throw new Error(
996
+ `Can not find Tina GraphQL version in ${this.generatedSchemaJSONPath}`
1213
997
  );
1214
- await import_fs_extra3.default.stat(file);
1215
- await import_fs_extra3.default.remove(file);
1216
- return { ok: true };
1217
- } catch (error) {
1218
- console.error(error);
1219
- return { ok: false, message: error == null ? void 0 : error.toString() };
1220
998
  }
999
+ return generatedSchema.version;
1221
1000
  }
1222
- };
1223
-
1224
- // src/next/commands/dev-command/server/searchIndex.ts
1225
- var createSearchIndexRouter = ({
1226
- config: config2,
1227
- searchIndex
1228
- }) => {
1229
- const put = async (req, res) => {
1230
- const { docs } = req.body;
1231
- const result = await searchIndex.PUT(docs);
1232
- res.writeHead(200, { "Content-Type": "application/json" });
1233
- res.end(JSON.stringify({ result }));
1234
- };
1235
- const get = async (req, res) => {
1236
- const requestURL = new URL(req.url, config2.apiURL);
1237
- const query = requestURL.searchParams.get("q");
1238
- const optionsParam = requestURL.searchParams.get("options");
1239
- let options = {
1240
- DOCUMENTS: false
1241
- };
1242
- if (optionsParam) {
1243
- options = {
1244
- ...options,
1245
- ...JSON.parse(optionsParam)
1246
- };
1001
+ printGeneratedClientFilePath() {
1002
+ if (this.isUsingTs()) {
1003
+ return this.generatedClientTSFilePath.replace(`${this.rootPath}/`, "");
1247
1004
  }
1248
- res.writeHead(200, { "Content-Type": "application/json" });
1249
- if (query) {
1250
- const result = await searchIndex.QUERY(JSON.parse(query), options);
1251
- res.end(JSON.stringify(result));
1252
- } else {
1253
- res.end(JSON.stringify({ RESULT: [] }));
1005
+ return this.generatedClientJSFilePath.replace(`${this.rootPath}/`, "");
1006
+ }
1007
+ printGeneratedTypesFilePath() {
1008
+ return this.generatedTypesTSFilePath.replace(`${this.rootPath}/`, "");
1009
+ }
1010
+ printoutputHTMLFilePath() {
1011
+ return this.outputHTMLFilePath.replace(`${this.publicFolderPath}/`, "");
1012
+ }
1013
+ printRelativePath(filename) {
1014
+ if (filename) {
1015
+ return filename.replace(/\\/g, "/").replace(`${this.rootPath}/`, "");
1254
1016
  }
1255
- };
1256
- const del = async (req, res) => {
1257
- const requestURL = new URL(req.url, config2.apiURL);
1258
- const docId = requestURL.pathname.split("/").filter(Boolean).slice(1).join("/");
1259
- const result = await searchIndex.DELETE(docId);
1260
- res.writeHead(200, { "Content-Type": "application/json" });
1261
- res.end(JSON.stringify({ result }));
1262
- };
1263
- return { del, get, put };
1264
- };
1265
-
1266
- // src/next/vite/plugins.ts
1267
- var transformTsxPlugin = ({
1268
- configManager: _configManager
1269
- }) => {
1270
- const plug = {
1271
- name: "transform-tsx",
1272
- async transform(code, id) {
1273
- const extName = import_path3.default.extname(id);
1274
- if (extName.startsWith(".tsx") || extName.startsWith(".ts")) {
1275
- const result = await (0, import_esbuild.transform)(code, { loader: "tsx" });
1276
- return {
1277
- code: result.code
1278
- };
1279
- }
1017
+ throw `No path provided to print`;
1018
+ }
1019
+ printPrebuildFilePath() {
1020
+ return this.prebuildFilePath.replace(/\\/g, "/").replace(`${this.rootPath}/${this.tinaFolderPath}/`, "");
1021
+ }
1022
+ printContentRelativePath(filename) {
1023
+ if (filename) {
1024
+ return filename.replace(/\\/g, "/").replace(`${this.contentRootPath}/`, "");
1280
1025
  }
1281
- };
1282
- return plug;
1283
- };
1284
- var devServerEndPointsPlugin = ({
1285
- configManager,
1286
- apiURL,
1287
- database,
1288
- searchIndex
1289
- }) => {
1290
- const plug = {
1291
- name: "graphql-endpoints",
1292
- configureServer(server) {
1293
- server.middlewares.use((0, import_cors.default)());
1294
- server.middlewares.use(import_body_parser.default.json({ limit: "5mb" }));
1295
- server.middlewares.use(async (req, res, next) => {
1296
- var _a;
1297
- const mediaPaths = (_a = configManager.config.media) == null ? void 0 : _a.tina;
1298
- const mediaRouter = createMediaRouter({
1299
- rootPath: configManager.rootPath,
1300
- apiURL,
1301
- publicFolder: parseMediaFolder((mediaPaths == null ? void 0 : mediaPaths.publicFolder) || ""),
1302
- mediaRoot: parseMediaFolder((mediaPaths == null ? void 0 : mediaPaths.mediaRoot) || "")
1303
- });
1304
- const searchIndexRouter = createSearchIndexRouter({
1305
- config: { apiURL, searchPath: "searchIndex" },
1306
- searchIndex
1307
- });
1308
- if (req.url.startsWith("/media/upload")) {
1309
- await mediaRouter.handlePost(req, res);
1310
- return;
1311
- }
1312
- if (req.url.startsWith("/media")) {
1313
- if (req.method === "DELETE") {
1314
- await mediaRouter.handleDelete(req, res);
1315
- return;
1316
- }
1317
- }
1318
- if (req.url.startsWith("/media/list")) {
1319
- await mediaRouter.handleList(req, res);
1320
- return;
1321
- }
1322
- if (req.url === "/altair") {
1323
- res.end(
1324
- JSON.stringify({
1325
- status: "The GraphQL playground has moved to <your-dev-url>/index.html#/graphql"
1326
- })
1327
- );
1328
- return;
1329
- }
1330
- if (req.url === "/graphql") {
1331
- 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
1340
- });
1341
- res.end(JSON.stringify(result));
1026
+ throw `No path provided to print`;
1027
+ }
1028
+ /**
1029
+ * Given a filepath without an extension, find the first match (eg. tsx, ts, jsx, js)
1030
+ */
1031
+ async getPathWithExtension(filepath) {
1032
+ const extensions = ["tsx", "ts", "jsx", "js"];
1033
+ let result;
1034
+ await Promise.all(
1035
+ extensions.map(async (ext) => {
1036
+ if (result) {
1342
1037
  return;
1343
1038
  }
1344
- if (req.url.startsWith("/searchIndex")) {
1345
- if (req.method === "POST") {
1346
- await searchIndexRouter.put(req, res);
1347
- } else if (req.method === "GET") {
1348
- await searchIndexRouter.get(req, res);
1349
- } else if (req.method === "DELETE") {
1350
- await searchIndexRouter.del(req, res);
1351
- }
1352
- return;
1353
- }
1354
- next();
1355
- });
1356
- }
1357
- };
1358
- return plug;
1359
- };
1360
- function viteTransformExtension({
1361
- exportAsDefault = true,
1362
- svgrOptions,
1363
- esbuildOptions,
1364
- include = "**/*.svg",
1365
- exclude
1366
- } = {}) {
1367
- const filter = (0, import_pluginutils.createFilter)(include, exclude);
1368
- return {
1369
- name: "vite-plugin-svgr",
1370
- async transform(code, id) {
1371
- if (filter(id)) {
1372
- const { transform: transform2 } = await Promise.resolve().then(() => __toESM(require("@svgr/core")));
1373
- const svgCode = await import_fs.default.promises.readFile(
1374
- id.replace(/\?.*$/, ""),
1375
- "utf8"
1376
- );
1377
- const componentCode = await transform2(svgCode, svgrOptions, {
1378
- filePath: id,
1379
- caller: {
1380
- previousExport: exportAsDefault ? null : code
1381
- }
1382
- });
1383
- const res = await (0, import_vite2.transformWithEsbuild)(componentCode, id, {
1384
- loader: "jsx",
1385
- ...esbuildOptions
1386
- });
1387
- return {
1388
- code: res.code,
1389
- map: null
1390
- };
1391
- }
1392
- }
1393
- };
1394
- }
1395
-
1396
- // src/next/commands/dev-command/server/index.ts
1397
- var createDevServer = async (configManager, database, searchIndex, apiURL, noWatch) => {
1398
- const plugins = [
1399
- transformTsxPlugin({ configManager }),
1400
- devServerEndPointsPlugin({ apiURL, configManager, database, searchIndex }),
1401
- viteTransformExtension()
1402
- ];
1403
- return (0, import_vite3.createServer)(
1404
- await createConfig({
1405
- configManager,
1406
- database,
1407
- apiURL,
1408
- plugins,
1409
- noWatch,
1410
- rollupOptions: {
1411
- input: configManager.spaMainPath,
1412
- onwarn(warning, warn) {
1413
- if (warning.code === "MODULE_LEVEL_DIRECTIVE") {
1414
- return;
1415
- }
1416
- warn(warning);
1039
+ const filepathWithExtension = `${filepath}.${ext}`;
1040
+ const exists = import_fs_extra2.default.existsSync(filepathWithExtension);
1041
+ if (exists) {
1042
+ result = filepathWithExtension;
1417
1043
  }
1044
+ })
1045
+ );
1046
+ return result;
1047
+ }
1048
+ async loadDatabaseFile() {
1049
+ const tmpdir = import_path2.default.join(import_os.default.tmpdir(), Date.now().toString());
1050
+ const outfile = import_path2.default.join(tmpdir, "database.build.js");
1051
+ await esbuild.build({
1052
+ entryPoints: [this.selfHostedDatabaseFilePath],
1053
+ bundle: true,
1054
+ platform: "node",
1055
+ outfile,
1056
+ loader: loaders
1057
+ });
1058
+ const result = require(outfile);
1059
+ import_fs_extra2.default.removeSync(outfile);
1060
+ return result.default;
1061
+ }
1062
+ async loadConfigFile(generatedFolderPath, configFilePath) {
1063
+ const tmpdir = import_path2.default.join(import_os.default.tmpdir(), Date.now().toString());
1064
+ const preBuildConfigPath = import_path2.default.join(
1065
+ this.generatedFolderPath,
1066
+ "config.prebuild.jsx"
1067
+ );
1068
+ const outfile = import_path2.default.join(tmpdir, "config.build.jsx");
1069
+ const outfile2 = import_path2.default.join(tmpdir, "config.build.js");
1070
+ const tempTSConfigFile = import_path2.default.join(tmpdir, "tsconfig.json");
1071
+ import_fs_extra2.default.outputFileSync(tempTSConfigFile, "{}");
1072
+ const result2 = await esbuild.build({
1073
+ entryPoints: [configFilePath],
1074
+ bundle: true,
1075
+ target: ["es2020"],
1076
+ platform: "browser",
1077
+ format: "esm",
1078
+ logLevel: "silent",
1079
+ packages: "external",
1080
+ ignoreAnnotations: true,
1081
+ outfile: preBuildConfigPath,
1082
+ loader: loaders,
1083
+ metafile: true
1084
+ });
1085
+ const flattenedList = [];
1086
+ Object.keys(result2.metafile.inputs).forEach((key) => {
1087
+ if (key.includes("node_modules") || key.includes("__generated__")) {
1088
+ return;
1418
1089
  }
1090
+ flattenedList.push(key);
1091
+ });
1092
+ await esbuild.build({
1093
+ entryPoints: [configFilePath],
1094
+ bundle: true,
1095
+ target: ["es2020"],
1096
+ logLevel: "silent",
1097
+ platform: "node",
1098
+ outfile,
1099
+ loader: loaders
1100
+ });
1101
+ await esbuild.build({
1102
+ entryPoints: [outfile],
1103
+ bundle: true,
1104
+ // Suppress warning about comparison with -0 from client module
1105
+ logLevel: "silent",
1106
+ platform: "node",
1107
+ outfile: outfile2,
1108
+ loader: loaders
1109
+ });
1110
+ let result;
1111
+ try {
1112
+ result = require(outfile2);
1113
+ } catch (e) {
1114
+ console.error("Unexpected error loading config");
1115
+ console.error(e);
1116
+ throw e;
1117
+ }
1118
+ import_fs_extra2.default.removeSync(outfile);
1119
+ import_fs_extra2.default.removeSync(outfile2);
1120
+ return {
1121
+ config: result.default,
1122
+ prebuildPath: preBuildConfigPath,
1123
+ watchList: flattenedList
1124
+ };
1125
+ }
1126
+ };
1127
+ var loaders = {
1128
+ ".aac": "file",
1129
+ ".css": "file",
1130
+ ".eot": "file",
1131
+ ".flac": "file",
1132
+ ".gif": "file",
1133
+ ".jpeg": "file",
1134
+ ".jpg": "file",
1135
+ ".json": "json",
1136
+ ".mp3": "file",
1137
+ ".mp4": "file",
1138
+ ".ogg": "file",
1139
+ ".otf": "file",
1140
+ ".png": "file",
1141
+ ".svg": "file",
1142
+ ".ttf": "file",
1143
+ ".wav": "file",
1144
+ ".webm": "file",
1145
+ ".webp": "file",
1146
+ ".woff": "file",
1147
+ ".woff2": "file",
1148
+ ".js": "jsx",
1149
+ ".jsx": "jsx",
1150
+ ".tsx": "tsx"
1151
+ };
1152
+
1153
+ // src/next/database.ts
1154
+ var import_graphql7 = require("@tinacms/graphql");
1155
+ var import_readable_stream = require("readable-stream");
1156
+ var import_net = require("net");
1157
+ var import_many_level = require("many-level");
1158
+ var import_memory_level = require("memory-level");
1159
+ var createDBServer = (port) => {
1160
+ const levelHost = new import_many_level.ManyLevelHost(
1161
+ // @ts-ignore
1162
+ new import_memory_level.MemoryLevel({
1163
+ valueEncoding: "json"
1419
1164
  })
1420
1165
  );
1166
+ const dbServer = (0, import_net.createServer)(function(socket) {
1167
+ return (0, import_readable_stream.pipeline)(socket, levelHost.createRpcStream(), socket, () => {
1168
+ });
1169
+ });
1170
+ dbServer.once("error", (err) => {
1171
+ if ((err == null ? void 0 : err.code) === "EADDRINUSE") {
1172
+ throw new Error(
1173
+ `Tina Dev server is already in use. Datalayer server is busy on port ${port}`
1174
+ );
1175
+ }
1176
+ });
1177
+ dbServer.listen(port);
1421
1178
  };
1422
-
1423
- // src/next/codegen/index.ts
1424
- var import_fs_extra4 = __toESM(require("fs-extra"));
1425
- var import_path4 = __toESM(require("path"));
1426
- var import_graphql6 = require("graphql");
1427
-
1428
- // src/next/codegen/codegen/index.ts
1429
- var import_graphql5 = require("graphql");
1430
-
1431
- // src/next/codegen/codegen/plugin.ts
1432
- var AddGeneratedClientFunc = (apiURL) => {
1433
- return (_schema, _documents, _config, _info) => {
1434
- return `
1435
- // TinaSDK generated code
1436
- import { createClient, TinaClient } from "tinacms/dist/client";
1437
-
1438
- const generateRequester = (
1439
- client: TinaClient,
1440
- ) => {
1441
- const requester: (
1442
- doc: any,
1443
- vars?: any,
1444
- options?: {
1445
- branch?: string,
1446
- /**
1447
- * Aside from \`method\` and \`body\`, all fetch options are passed
1448
- * through to underlying fetch request
1449
- */
1450
- fetchOptions?: Omit<Parameters<typeof fetch>[1], 'body' | 'method'>,
1451
- },
1452
- client
1453
- ) => Promise<any> = async (doc, vars, options) => {
1454
- let url = client.apiUrl
1455
- if (options?.branch) {
1456
- const index = client.apiUrl.lastIndexOf('/')
1457
- url = client.apiUrl.substring(0, index + 1) + options.branch
1179
+ async function createAndInitializeDatabase(configManager, datalayerPort, bridgeOverride) {
1180
+ let database;
1181
+ const bridge = bridgeOverride || new import_graphql7.FilesystemBridge(configManager.rootPath, configManager.contentRootPath);
1182
+ if (configManager.hasSelfHostedConfig() && configManager.config.contentApiUrlOverride) {
1183
+ database = await configManager.loadDatabaseFile();
1184
+ database.bridge = bridge;
1185
+ } else {
1186
+ if (configManager.hasSelfHostedConfig() && !configManager.config.contentApiUrlOverride) {
1187
+ logger.warn(
1188
+ `Found a database config file at ${configManager.printRelativePath(
1189
+ configManager.selfHostedDatabaseFilePath
1190
+ )} but there was no "contentApiUrlOverride" set. Falling back to built-in datalayer`
1191
+ );
1458
1192
  }
1459
- const data = await client.request({
1460
- query: doc,
1461
- variables: vars,
1462
- url,
1463
- }, options)
1464
-
1465
- return { data: data?.data, errors: data?.errors, query: doc, variables: vars || {} }
1193
+ const level = new import_graphql7.TinaLevelClient(datalayerPort);
1194
+ level.openConnection();
1195
+ database = (0, import_graphql7.createDatabaseInternal)({
1196
+ bridge,
1197
+ level,
1198
+ tinaDirectory: configManager.isUsingLegacyFolder ? LEGACY_TINA_FOLDER : TINA_FOLDER
1199
+ });
1466
1200
  }
1467
-
1468
- return requester
1201
+ return database;
1469
1202
  }
1470
1203
 
1471
- /**
1472
- * @experimental this class can be used but may change in the future
1473
- **/
1474
- export const ExperimentalGetTinaClient = () =>
1475
- getSdk(
1476
- generateRequester(
1477
- createClient({
1478
- url: "${apiURL}",
1479
- queries,
1480
- })
1481
- )
1482
- )
1204
+ // src/next/commands/baseCommands.ts
1205
+ var import_clipanion = require("clipanion");
1206
+ var import_chalk4 = __toESM(require("chalk"));
1483
1207
 
1484
- export const queries = (
1485
- client: TinaClient,
1486
- ) => {
1487
- const requester = generateRequester(client)
1488
- return getSdk(requester)
1489
- }
1490
- `;
1491
- };
1208
+ // src/utils/start-subprocess.ts
1209
+ var import_child_process = __toESM(require("child_process"));
1210
+ var startSubprocess2 = async ({ command: command2 }) => {
1211
+ if (typeof command2 === "string") {
1212
+ const commands = command2.split(" ");
1213
+ const firstCommand = commands[0];
1214
+ const args = commands.slice(1) || [];
1215
+ const ps = import_child_process.default.spawn(firstCommand, args, {
1216
+ stdio: "inherit",
1217
+ shell: true
1218
+ });
1219
+ ps.on("error", (code) => {
1220
+ logger.error(
1221
+ dangerText(
1222
+ `An error has occurred in the Next.js child process. Error message below`
1223
+ )
1224
+ );
1225
+ logger.error(`name: ${code.name}
1226
+ message: ${code.message}
1227
+
1228
+ stack: ${code.stack || "No stack was provided"}`);
1229
+ });
1230
+ ps.on("close", (code) => {
1231
+ logger.info(`child process exited with code ${code}`);
1232
+ process.exit(code);
1233
+ });
1234
+ return ps;
1235
+ }
1492
1236
  };
1493
- var AddGeneratedClient = (apiURL) => ({
1494
- plugin: AddGeneratedClientFunc(apiURL)
1495
- });
1496
1237
 
1497
- // src/next/codegen/codegen/index.ts
1498
- var import_graphql_file_loader = require("@graphql-tools/graphql-file-loader");
1499
- var import_core = require("@graphql-codegen/core");
1500
- var import_load = require("@graphql-tools/load");
1501
- var import_typescript_operations = require("@graphql-codegen/typescript-operations");
1502
- var import_typescript = require("@graphql-codegen/typescript");
1503
-
1504
- // src/next/codegen/codegen/sdkPlugin/index.ts
1505
- var import_graphql3 = require("graphql");
1506
- var import_graphql4 = require("graphql");
1507
-
1508
- // src/next/codegen/codegen/sdkPlugin/visitor.ts
1509
- var import_visitor_plugin_common = require("@graphql-codegen/visitor-plugin-common");
1510
- var import_auto_bind = __toESM(require("auto-bind"));
1511
- var import_graphql2 = require("graphql");
1512
- var GenericSdkVisitor = class extends import_visitor_plugin_common.ClientSideBaseVisitor {
1513
- constructor(schema, fragments, rawConfig) {
1514
- super(schema, fragments, rawConfig, {
1515
- usingObservableFrom: rawConfig.usingObservableFrom
1238
+ // src/next/commands/baseCommands.ts
1239
+ var import_graphql8 = require("@tinacms/graphql");
1240
+ var import_fs_extra3 = __toESM(require("fs-extra"));
1241
+ var BaseCommand = class extends import_clipanion.Command {
1242
+ constructor() {
1243
+ super(...arguments);
1244
+ this.experimentalDataLayer = import_clipanion.Option.Boolean("--experimentalData", {
1245
+ description: "DEPRECATED - Build the server with additional data querying capabilities"
1246
+ });
1247
+ this.isomorphicGitBridge = import_clipanion.Option.Boolean("--isomorphicGitBridge", {
1248
+ description: "DEPRECATED - Enable Isomorphic Git Bridge Implementation"
1249
+ });
1250
+ this.port = import_clipanion.Option.String("-p,--port", "4001", {
1251
+ description: "Specify a port to run the server on. (default 4001)"
1252
+ });
1253
+ this.datalayerPort = import_clipanion.Option.String("--datalayer-port", "9000", {
1254
+ description: "Specify a port to run the datalayer server on. (default 9000)"
1255
+ });
1256
+ this.subCommand = import_clipanion.Option.String("-c,--command", {
1257
+ description: "The sub-command to run"
1258
+ });
1259
+ this.rootPath = import_clipanion.Option.String("--rootPath", {
1260
+ description: "Specify the root directory to run the CLI from (defaults to current working directory)"
1261
+ });
1262
+ this.verbose = import_clipanion.Option.Boolean("-v,--verbose", false, {
1263
+ description: "increase verbosity of logged output"
1264
+ });
1265
+ this.noSDK = import_clipanion.Option.Boolean("--noSDK", false, {
1266
+ description: "DEPRECATED - This should now be set in the config at client.skip = true'. Don't generate the generated client SDK"
1267
+ });
1268
+ this.noTelemetry = import_clipanion.Option.Boolean("--noTelemetry", false, {
1269
+ description: "Disable anonymous telemetry that is collected"
1516
1270
  });
1517
- this._operationsToInclude = [];
1518
- (0, import_auto_bind.default)(this);
1519
- if (this.config.usingObservableFrom) {
1520
- this._additionalImports.push(this.config.usingObservableFrom);
1521
- }
1522
- if (this.config.documentMode !== import_visitor_plugin_common.DocumentMode.string) {
1523
- }
1524
1271
  }
1525
- buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes) {
1526
- if (node.name == null) {
1527
- throw new Error(
1528
- "Plugin 'generic-sdk' cannot generate SDK for unnamed operation.\n\n" + (0, import_graphql2.print)(node)
1272
+ async startSubCommand() {
1273
+ let subProc;
1274
+ if (this.subCommand) {
1275
+ subProc = await startSubprocess2({ command: this.subCommand });
1276
+ logger.info(
1277
+ `Running web application with command: ${import_chalk4.default.cyan(this.subCommand)}`
1529
1278
  );
1530
- } else {
1531
- this._operationsToInclude.push({
1532
- node,
1533
- documentVariableName,
1534
- operationType,
1535
- operationResultType: `{data: ${operationResultType}, errors?: { message: string, locations: { line: number, column: number }[], path: string[] }[], variables: ${operationVariablesTypes}, query: string}`,
1536
- operationVariablesTypes
1537
- });
1538
1279
  }
1539
- return null;
1280
+ function exitHandler(options, exitCode) {
1281
+ if (subProc) {
1282
+ subProc.kill();
1283
+ }
1284
+ process.exit();
1285
+ }
1286
+ process.on("exit", exitHandler);
1287
+ process.on("SIGINT", exitHandler);
1288
+ process.on("SIGUSR1", exitHandler);
1289
+ process.on("SIGUSR2", exitHandler);
1290
+ process.on("uncaughtException", (error) => {
1291
+ logger.error(`Uncaught exception ${error.name}`);
1292
+ console.error(error);
1293
+ });
1540
1294
  }
1541
- get sdkContent() {
1542
- const usingObservable = !!this.config.usingObservableFrom;
1543
- const allPossibleActions = this._operationsToInclude.map((o) => {
1544
- const optionalVariables = !o.node.variableDefinitions || o.node.variableDefinitions.length === 0 || o.node.variableDefinitions.every(
1545
- (v) => v.type.kind !== import_graphql2.Kind.NON_NULL_TYPE || v.defaultValue
1295
+ logDeprecationWarnings() {
1296
+ if (this.isomorphicGitBridge) {
1297
+ logger.warn("--isomorphicGitBridge has been deprecated");
1298
+ }
1299
+ if (this.experimentalDataLayer) {
1300
+ logger.warn(
1301
+ "--experimentalDataLayer has been deprecated, the data layer is now built-in automatically"
1546
1302
  );
1547
- const returnType = usingObservable && o.operationType === "Subscription" ? "Observable" : "Promise";
1548
- return `${o.node.name.value}(variables${optionalVariables ? "?" : ""}: ${o.operationVariablesTypes}, options?: C): ${returnType}<${o.operationResultType}> {
1549
- return requester<${o.operationResultType}, ${o.operationVariablesTypes}>(${o.documentVariableName}, variables, options);
1550
- }`;
1551
- }).map((s2) => (0, import_visitor_plugin_common.indentMultiline)(s2, 2));
1552
- return `export type Requester<C= {}> = <R, V>(doc: ${this.config.documentMode === import_visitor_plugin_common.DocumentMode.string ? "string" : "DocumentNode"}, vars?: V, options?: C) => ${usingObservable ? "Promise<R> & Observable<R>" : "Promise<R>"}
1553
- export function getSdk<C>(requester: Requester<C>) {
1554
- return {
1555
- ${allPossibleActions.join(",\n")}
1556
- };
1557
- }
1558
- export type Sdk = ReturnType<typeof getSdk>;`;
1559
- }
1560
- };
1561
-
1562
- // src/next/codegen/codegen/sdkPlugin/index.ts
1563
- var plugin = (schema, documents, config2) => {
1564
- const allAst = (0, import_graphql4.concatAST)(
1565
- documents.reduce((prev, v) => {
1566
- return [...prev, v.document];
1567
- }, [])
1568
- );
1569
- const allFragments = [
1570
- ...allAst.definitions.filter(
1571
- (d) => d.kind === import_graphql4.Kind.FRAGMENT_DEFINITION
1572
- ).map((fragmentDef) => ({
1573
- node: fragmentDef,
1574
- name: fragmentDef.name.value,
1575
- onType: fragmentDef.typeCondition.name.value,
1576
- isExternal: false
1577
- })),
1578
- ...config2.externalFragments || []
1579
- ];
1580
- const visitor = new GenericSdkVisitor(schema, allFragments, config2);
1581
- const visitorResult = (0, import_graphql3.visit)(allAst, { leave: visitor });
1582
- return {
1583
- content: [
1584
- visitor.fragments,
1585
- ...visitorResult.definitions.filter((t) => typeof t === "string"),
1586
- visitor.sdkContent
1587
- ].join("\n")
1588
- };
1589
- };
1590
-
1591
- // src/next/codegen/codegen/index.ts
1592
- var generateTypes = async (schema, queryPathGlob = process.cwd(), fragDocPath = process.cwd(), apiURL) => {
1593
- let docs = [];
1594
- let fragDocs = [];
1595
- docs = await loadGraphQLDocuments(queryPathGlob);
1596
- fragDocs = await loadGraphQLDocuments(fragDocPath);
1597
- const res = await (0, import_core.codegen)({
1598
- filename: process.cwd(),
1599
- schema: (0, import_graphql5.parse)((0, import_graphql5.printSchema)(schema)),
1600
- documents: [...docs, ...fragDocs],
1601
- config: {},
1602
- plugins: [
1603
- { typescript: {} },
1604
- { typescriptOperations: {} },
1605
- {
1606
- typescriptSdk: {}
1607
- },
1608
- { AddGeneratedClient: {} }
1609
- ],
1610
- pluginMap: {
1611
- typescript: {
1612
- plugin: import_typescript.plugin
1613
- },
1614
- typescriptOperations: {
1615
- plugin: import_typescript_operations.plugin
1616
- },
1617
- typescriptSdk: {
1618
- plugin
1619
- },
1620
- AddGeneratedClient: AddGeneratedClient(apiURL)
1621
1303
  }
1622
- });
1623
- return res;
1624
- };
1625
- var loadGraphQLDocuments = async (globPath) => {
1626
- let result = [];
1627
- try {
1628
- result = await (0, import_load.loadDocuments)(globPath, {
1629
- loaders: [new import_graphql_file_loader.GraphQLFileLoader()]
1630
- });
1631
- } catch (e) {
1632
- if ((e.message || "").includes(
1633
- "Unable to find any GraphQL type definitions for the following pointers:"
1634
- )) {
1635
- } else {
1636
- throw e;
1304
+ if (this.noSDK) {
1305
+ logger.warn(
1306
+ "--noSDK has been deprecated, and will be unsupported in a future release. This should be set in the config at client.skip = true"
1307
+ );
1637
1308
  }
1638
1309
  }
1639
- return result;
1640
- };
1641
-
1642
- // src/next/codegen/index.ts
1643
- var import_esbuild2 = require("esbuild");
1644
- var import_graphql7 = require("@tinacms/graphql");
1645
- var import_normalize_path3 = __toESM(require("normalize-path"));
1646
- var TINA_HOST = "content.tinajs.io";
1647
- var Codegen = class {
1648
- constructor({
1649
- configManager,
1650
- port,
1651
- queryDoc,
1652
- fragDoc,
1653
- isLocal,
1654
- graphqlSchemaDoc,
1310
+ async indexContentWithSpinner({
1311
+ database,
1312
+ graphQLSchema,
1655
1313
  tinaSchema,
1656
- lookup,
1657
- noClientBuildCache
1314
+ configManager,
1315
+ partialReindex,
1316
+ text
1658
1317
  }) {
1659
- this.isLocal = isLocal;
1660
- this.graphqlSchemaDoc = graphqlSchemaDoc;
1661
- this.configManager = configManager;
1662
- this.port = port;
1663
- this.schema = (0, import_graphql6.buildASTSchema)(graphqlSchemaDoc);
1664
- this.tinaSchema = tinaSchema;
1665
- this.queryDoc = queryDoc;
1666
- this.fragDoc = fragDoc;
1667
- this.lookup = lookup;
1668
- this.noClientBuildCache = noClientBuildCache;
1669
- }
1670
- async writeConfigFile(fileName, data) {
1671
- const filePath = import_path4.default.join(this.configManager.generatedFolderPath, fileName);
1672
- await import_fs_extra4.default.ensureFile(filePath);
1673
- await import_fs_extra4.default.outputFile(filePath, data);
1674
- if (this.configManager.hasSeparateContentRoot()) {
1675
- const filePath2 = import_path4.default.join(
1676
- this.configManager.generatedFolderPathContentRepo,
1677
- fileName
1678
- );
1679
- await import_fs_extra4.default.ensureFile(filePath2);
1680
- await import_fs_extra4.default.outputFile(filePath2, data);
1681
- }
1682
- }
1683
- async removeGeneratedFilesIfExists() {
1684
- await unlinkIfExists(this.configManager.generatedClientJSFilePath);
1685
- await unlinkIfExists(this.configManager.generatedTypesDFilePath);
1686
- await unlinkIfExists(this.configManager.generatedTypesJSFilePath);
1687
- await unlinkIfExists(this.configManager.generatedTypesTSFilePath);
1688
- await unlinkIfExists(this.configManager.generatedClientTSFilePath);
1689
- await unlinkIfExists(this.configManager.generatedQueriesFilePath);
1690
- await unlinkIfExists(this.configManager.generatedFragmentsFilePath);
1691
- }
1692
- async execute() {
1693
- await this.writeConfigFile(
1694
- "_graphql.json",
1695
- JSON.stringify(this.graphqlSchemaDoc)
1696
- );
1697
- const { search, ...rest } = this.tinaSchema.schema.config;
1698
- this.tinaSchema.schema.config = rest;
1699
- await this.writeConfigFile(
1700
- "_schema.json",
1701
- JSON.stringify(this.tinaSchema.schema)
1702
- );
1703
- await this.writeConfigFile("_lookup.json", JSON.stringify(this.lookup));
1704
- const { apiURL, localUrl, tinaCloudUrl } = this._createApiUrl();
1705
- this.apiURL = apiURL;
1706
- this.localUrl = localUrl;
1707
- this.productionUrl = tinaCloudUrl;
1708
- if (this.configManager.shouldSkipSDK()) {
1709
- await this.removeGeneratedFilesIfExists();
1710
- return apiURL;
1711
- }
1712
- await import_fs_extra4.default.outputFile(
1713
- this.configManager.generatedQueriesFilePath,
1714
- this.queryDoc
1715
- );
1716
- await import_fs_extra4.default.outputFile(
1717
- this.configManager.generatedFragmentsFilePath,
1718
- this.fragDoc
1719
- );
1720
- await maybeWarnFragmentSize(this.configManager.generatedFragmentsFilePath);
1721
- const { clientString } = await this.genClient();
1722
- const databaseClientString = this.configManager.hasSelfHostedConfig() ? await this.genDatabaseClient() : "";
1723
- const { codeString, schemaString } = await this.genTypes();
1724
- await import_fs_extra4.default.outputFile(
1725
- this.configManager.generatedGraphQLGQLPath,
1726
- schemaString
1727
- );
1728
- if (this.configManager.isUsingTs()) {
1729
- await import_fs_extra4.default.outputFile(
1730
- this.configManager.generatedTypesTSFilePath,
1731
- codeString
1732
- );
1733
- await import_fs_extra4.default.outputFile(
1734
- this.configManager.generatedClientTSFilePath,
1735
- clientString
1736
- );
1737
- if (this.configManager.hasSelfHostedConfig()) {
1738
- await import_fs_extra4.default.outputFile(
1739
- this.configManager.generatedDatabaseClientTSFilePath,
1740
- databaseClientString
1741
- );
1742
- }
1743
- await unlinkIfExists(this.configManager.generatedClientJSFilePath);
1744
- await unlinkIfExists(this.configManager.generatedTypesDFilePath);
1745
- await unlinkIfExists(this.configManager.generatedTypesJSFilePath);
1746
- } else {
1747
- await import_fs_extra4.default.outputFile(
1748
- this.configManager.generatedTypesDFilePath,
1749
- codeString
1750
- );
1751
- const jsTypes = await (0, import_esbuild2.transform)(codeString, { loader: "ts" });
1752
- await import_fs_extra4.default.outputFile(
1753
- this.configManager.generatedTypesJSFilePath,
1754
- jsTypes.code
1755
- );
1756
- await import_fs_extra4.default.outputFile(
1757
- this.configManager.generatedClientDFilePath,
1758
- clientString
1759
- );
1760
- const jsClient = await (0, import_esbuild2.transform)(clientString, { loader: "ts" });
1761
- await import_fs_extra4.default.outputFile(
1762
- this.configManager.generatedClientJSFilePath,
1763
- jsClient.code
1764
- );
1765
- await unlinkIfExists(this.configManager.generatedTypesTSFilePath);
1766
- await unlinkIfExists(this.configManager.generatedClientTSFilePath);
1767
- if (this.configManager.hasSelfHostedConfig()) {
1768
- const jsDatabaseClient = await (0, import_esbuild2.transform)(databaseClientString, {
1769
- loader: "ts"
1770
- });
1771
- await import_fs_extra4.default.outputFile(
1772
- this.configManager.generatedDatabaseClientJSFilePath,
1773
- jsDatabaseClient.code
1774
- );
1775
- await import_fs_extra4.default.outputFile(
1776
- this.configManager.generatedDatabaseClientDFilePath,
1777
- databaseClientString
1778
- );
1779
- await unlinkIfExists(
1780
- this.configManager.generatedDatabaseClientTSFilePath
1781
- );
1782
- }
1783
- }
1784
- return apiURL;
1785
- }
1786
- _createApiUrl() {
1787
- var _a, _b, _c, _d;
1788
- const branch = (_a = this.configManager.config) == null ? void 0 : _a.branch;
1789
- const clientId = (_b = this.configManager.config) == null ? void 0 : _b.clientId;
1790
- const token = (_c = this.configManager.config) == null ? void 0 : _c.token;
1791
- const version2 = this.configManager.getTinaGraphQLVersion();
1792
- const baseUrl = ((_d = this.configManager.config.tinaioConfig) == null ? void 0 : _d.contentApiUrlOverride) || `https://${TINA_HOST}`;
1793
- if ((!branch || !clientId || !token) && !this.port && !this.configManager.config.contentApiUrlOverride) {
1794
- const missing = [];
1795
- if (!branch)
1796
- missing.push("branch");
1797
- if (!clientId)
1798
- missing.push("clientId");
1799
- if (!token)
1800
- missing.push("token");
1801
- throw new Error(
1802
- `Client not configured properly. Missing ${missing.join(
1803
- ", "
1804
- )}. Please visit https://tina.io/docs/tina-cloud/overview for more information`
1805
- );
1806
- }
1807
- let localUrl = `http://localhost:${this.port}/graphql`;
1808
- let tinaCloudUrl = `${baseUrl}/${version2}/content/${clientId}/github/${branch}`;
1809
- let apiURL = this.isLocal ? `http://localhost:${this.port}/graphql` : `${baseUrl}/${version2}/content/${clientId}/github/${branch}`;
1810
- if (this.configManager.config.contentApiUrlOverride) {
1811
- apiURL = this.configManager.config.contentApiUrlOverride;
1812
- localUrl = apiURL;
1813
- tinaCloudUrl = apiURL;
1814
- }
1815
- return { apiURL, localUrl, tinaCloudUrl };
1816
- }
1817
- getApiURL() {
1818
- if (!this.apiURL)
1819
- throw new Error("apiURL not set. Please run execute() first");
1820
- return this.apiURL;
1821
- }
1822
- async genDatabaseClient() {
1823
- var _a, _b;
1824
- const authCollection = this.tinaSchema.getCollections().find((c) => c.isAuthCollection);
1825
- let authFields = [];
1826
- if (authCollection) {
1827
- const usersFields = (0, import_graphql7.mapUserFields)(authCollection, []);
1828
- if (usersFields.length === 0) {
1829
- throw new Error("No user field found");
1830
- }
1831
- if (usersFields.length > 1) {
1832
- throw new Error("Only one user field is allowed");
1833
- }
1834
- authFields = (_b = (_a = usersFields[0]) == null ? void 0 : _a.collectable) == null ? void 0 : _b.fields.map((f) => {
1835
- if (f.type !== "password" && f.type !== "object") {
1836
- if (f.uid) {
1837
- return `id:${f.name}`;
1318
+ const textToUse = text || "Indexing local files";
1319
+ const warnings = [];
1320
+ await spin({
1321
+ waitFor: async () => {
1322
+ var _a, _b;
1323
+ const rootPath = configManager.rootPath;
1324
+ let sha;
1325
+ try {
1326
+ sha = await (0, import_graphql8.getSha)({ fs: import_fs_extra3.default, dir: rootPath });
1327
+ } catch (e) {
1328
+ if (partialReindex) {
1329
+ console.error(
1330
+ "Failed to get sha. NOTE: `--partial-reindex` only supported for git repositories"
1331
+ );
1332
+ throw e;
1333
+ }
1334
+ }
1335
+ const lastSha = await database.getMetadata("lastSha");
1336
+ const exists = lastSha && await (0, import_graphql8.shaExists)({ fs: import_fs_extra3.default, dir: rootPath, sha: lastSha });
1337
+ let res;
1338
+ if (partialReindex && lastSha && exists && sha) {
1339
+ const pathFilter = {};
1340
+ if (configManager.isUsingLegacyFolder) {
1341
+ pathFilter[".tina/__generated__/_schema.json"] = {};
1838
1342
  } else {
1839
- return `${f.name}`;
1343
+ pathFilter["tina/tina-lock.json"] = {};
1840
1344
  }
1841
- } else if (f.type === "password") {
1842
- return `_password: ${f.name} { passwordChangeRequired }`;
1345
+ for (const collection of tinaSchema.getCollections()) {
1346
+ pathFilter[collection.path] = {
1347
+ matches: ((_a = collection.match) == null ? void 0 : _a.exclude) || ((_b = collection.match) == null ? void 0 : _b.include) ? tinaSchema.getMatches({ collection }) : void 0
1348
+ };
1349
+ }
1350
+ const { added, modified, deleted } = await (0, import_graphql8.getChangedFiles)({
1351
+ fs: import_fs_extra3.default,
1352
+ dir: rootPath,
1353
+ from: lastSha,
1354
+ to: sha,
1355
+ pathFilter
1356
+ });
1357
+ const tinaPathUpdates = modified.filter(
1358
+ (path14) => path14.startsWith(".tina/__generated__/_schema.json") || path14.startsWith("tina/tina-lock.json")
1359
+ );
1360
+ if (tinaPathUpdates.length > 0) {
1361
+ res = await database.indexContent({
1362
+ graphQLSchema,
1363
+ tinaSchema
1364
+ });
1365
+ } else {
1366
+ if (added.length > 0 || modified.length > 0) {
1367
+ await database.indexContentByPaths([...added, ...modified]);
1368
+ }
1369
+ if (deleted.length > 0) {
1370
+ await database.deleteContentByPaths(deleted);
1371
+ }
1372
+ }
1373
+ } else {
1374
+ res = await database.indexContent({
1375
+ graphQLSchema,
1376
+ tinaSchema
1377
+ });
1378
+ }
1379
+ if (sha) {
1380
+ await database.setMetadata("lastSha", sha);
1381
+ }
1382
+ if (res == null ? void 0 : res.warnings) {
1383
+ warnings.push(...res.warnings);
1843
1384
  }
1385
+ },
1386
+ text: textToUse
1387
+ });
1388
+ if (warnings.length > 0) {
1389
+ logger.warn(`Indexing completed with ${warnings.length} warning(s)`);
1390
+ warnings.forEach((warning) => {
1391
+ logger.warn(warnText(`${warning}`));
1844
1392
  });
1845
1393
  }
1846
- return `// @ts-nocheck
1847
- import { resolve } from "@tinacms/datalayer";
1848
- import type { TinaClient } from "tinacms/dist/client";
1849
-
1850
- import { queries } from "./types";
1851
- import database from "../database";
1852
-
1853
- export async function databaseRequest({ query, variables, user }) {
1854
- const result = await resolve({
1855
- config: {
1856
- useRelativeMedia: true,
1857
- },
1858
- database,
1859
- query,
1860
- variables,
1861
- verbose: true,
1862
- ctxUser: user,
1863
- });
1394
+ }
1395
+ };
1864
1396
 
1865
- return result;
1397
+ // src/next/commands/dev-command/html.ts
1398
+ var errorHTML = `<style type="text/css">
1399
+ #no-assets-placeholder body {
1400
+ font-family: sans-serif;
1401
+ font-size: 16px;
1402
+ line-height: 1.4;
1403
+ color: #333;
1404
+ background-color: #f5f5f5;
1866
1405
  }
1867
-
1868
- export async function authenticate({ username, password }) {
1869
- return databaseRequest({
1870
- query: \`query auth($username:String!, $password:String!) {
1871
- authenticate(sub:$username, password:$password) {
1872
- ${authFields.join(" ")}
1873
- }
1874
- }\`,
1875
- variables: { username, password },
1876
- })
1406
+ #no-assets-placeholder {
1407
+ max-width: 600px;
1408
+ margin: 0 auto;
1409
+ padding: 40px;
1410
+ text-align: center;
1411
+ background-color: #fff;
1412
+ box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.1);
1877
1413
  }
1878
-
1879
- export async function authorize(user: { sub: string }) {
1880
- return databaseRequest({
1881
- query: \`query authz { authorize { ${authFields.join(" ")}} }\`,
1882
- variables: {},
1883
- user
1884
- })
1414
+ #no-assets-placeholder h1 {
1415
+ font-size: 24px;
1416
+ margin-bottom: 20px;
1885
1417
  }
1886
-
1887
- function createDatabaseClient<GenQueries = Record<string, unknown>>({
1888
- queries,
1889
- }: {
1890
- queries: (client: {
1891
- request: TinaClient<GenQueries>["request"];
1892
- }) => GenQueries;
1893
- }) {
1894
- const request = async ({ query, variables, user }) => {
1895
- const data = await databaseRequest({ query, variables, user });
1896
- return { data: data.data as any, query, variables, errors: data.errors || null };
1897
- };
1898
- const q = queries({
1899
- request,
1900
- });
1901
- return { queries: q, request, authenticate, authorize };
1418
+ #no-assets-placeholder p {
1419
+ margin-bottom: 10px;
1902
1420
  }
1903
-
1904
- export const databaseClient = createDatabaseClient({ queries });
1905
-
1906
- export const client = databaseClient;
1907
-
1908
- export default databaseClient;
1909
- `;
1910
- }
1911
- async genClient() {
1912
- var _a, _b, _c;
1913
- const token = (_a = this.configManager.config) == null ? void 0 : _a.token;
1914
- const errorPolicy = (_c = (_b = this.configManager.config) == null ? void 0 : _b.client) == null ? void 0 : _c.errorPolicy;
1915
- const apiURL = this.getApiURL();
1916
- const clientString = `import { createClient } from "tinacms/dist/client";
1917
- import { queries } from "./types";
1918
- export const client = createClient({ ${this.noClientBuildCache === false ? `cacheDir: '${(0, import_normalize_path3.default)(
1919
- this.configManager.generatedCachePath
1920
- )}', ` : ""}url: '${apiURL}', token: '${token}', queries, ${errorPolicy ? `errorPolicy: '${errorPolicy}'` : ""} });
1921
- export default client;
1922
- `;
1923
- return { apiURL, clientString };
1924
- }
1925
- async genTypes() {
1926
- const typescriptTypes = await generateTypes(
1927
- this.schema,
1928
- this.configManager.userQueriesAndFragmentsGlob,
1929
- this.configManager.generatedQueriesAndFragmentsGlob,
1930
- this.getApiURL()
1931
- );
1932
- const codeString = `//@ts-nocheck
1933
- // DO NOT MODIFY THIS FILE. This file is automatically generated by Tina
1934
- export function gql(strings: TemplateStringsArray, ...args: string[]): string {
1935
- let str = ''
1936
- strings.forEach((string, i) => {
1937
- str += string + (args[i] || '')
1938
- })
1939
- return str
1940
- }
1941
- ${typescriptTypes}
1942
- `;
1943
- const schemaString = `# DO NOT MODIFY THIS FILE. This file is automatically generated by Tina
1944
- ${(0, import_graphql6.printSchema)(this.schema)}
1945
- schema {
1946
- query: Query
1947
- mutation: Mutation
1421
+ #no-assets-placeholder a {
1422
+ color: #0077cc;
1423
+ text-decoration: none;
1948
1424
  }
1949
- `;
1950
- return { codeString, schemaString };
1951
- }
1952
- };
1953
- var maybeWarnFragmentSize = async (filepath) => {
1954
- if ((await import_fs_extra4.default.stat(filepath)).size > 100 * 1024) {
1955
- console.warn(
1956
- "Warning: frags.gql is very large (>100kb). Consider setting the reference depth to 1 or 0. See code snippet below."
1957
- );
1958
- console.log(
1959
- `const schema = defineSchema({
1960
- client: {
1961
- referenceDepth: 1,
1962
- },
1963
- // ...
1964
- })`
1965
- );
1966
- }
1967
- };
1968
- var unlinkIfExists = async (filepath) => {
1969
- if (import_fs_extra4.default.existsSync(filepath)) {
1970
- import_fs_extra4.default.unlinkSync(filepath);
1971
- }
1972
- };
1425
+ #no-assets-placeholder a:hover {
1426
+ text-decoration: underline;
1427
+ }
1428
+ </style>
1429
+ <div id="no-assets-placeholder">
1430
+ <h1>Failed loading TinaCMS assets</h1>
1431
+ <p>
1432
+ Your TinaCMS configuration may be misconfigured, and we could not load
1433
+ the assets for this page.
1434
+ </p>
1435
+ <p>
1436
+ Please visit <a href="https://tina.io/docs/tina-cloud/faq/#how-do-i-resolve-failed-loading-tinacms-assets-error">this doc</a> for help.
1437
+ </p>
1438
+ </div>
1439
+ </div>`.trim().replace(/[\r\n\s]+/g, " ");
1440
+ var devHTML = (port) => `<!DOCTYPE html>
1441
+ <html lang="en">
1442
+ <head>
1443
+ <meta charset="UTF-8" />
1444
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
1445
+ <title>TinaCMS</title>
1446
+ </head>
1973
1447
 
1974
- // src/next/database.ts
1975
- var import_graphql8 = require("@tinacms/graphql");
1976
- var import_readable_stream = require("readable-stream");
1977
- var import_net = require("net");
1978
- var import_many_level = require("many-level");
1979
- var import_memory_level = require("memory-level");
1980
- var createDBServer = (port) => {
1981
- const levelHost = new import_many_level.ManyLevelHost(
1982
- new import_memory_level.MemoryLevel({
1983
- valueEncoding: "json"
1984
- })
1985
- );
1986
- const dbServer = (0, import_net.createServer)(function(socket) {
1987
- return (0, import_readable_stream.pipeline)(socket, levelHost.createRpcStream(), socket, () => {
1988
- });
1989
- });
1990
- dbServer.once("error", (err) => {
1991
- if ((err == null ? void 0 : err.code) === "EADDRINUSE") {
1992
- throw new Error(
1993
- `Tina Dev server is already in use. Datalayer server is busy on port ${port}`
1994
- );
1995
- }
1996
- });
1997
- dbServer.listen(port);
1998
- };
1999
- async function createAndInitializeDatabase(configManager, datalayerPort, bridgeOverride) {
2000
- let database;
2001
- const bridge = bridgeOverride || new import_graphql8.FilesystemBridge(configManager.rootPath, configManager.contentRootPath);
2002
- if (configManager.hasSelfHostedConfig() && configManager.config.contentApiUrlOverride) {
2003
- database = await configManager.loadDatabaseFile();
2004
- database.bridge = bridge;
2005
- } else {
2006
- if (configManager.hasSelfHostedConfig() && !configManager.config.contentApiUrlOverride) {
2007
- logger.warn(
2008
- `Found a database config file at ${configManager.printRelativePath(
2009
- configManager.selfHostedDatabaseFilePath
2010
- )} but there was no "contentApiUrlOverride" set. Falling back to built-in datalayer`
2011
- );
2012
- }
2013
- const level = new import_graphql8.TinaLevelClient(datalayerPort);
2014
- level.openConnection();
2015
- database = (0, import_graphql8.createDatabaseInternal)({
2016
- bridge,
2017
- level,
2018
- tinaDirectory: configManager.isUsingLegacyFolder ? LEGACY_TINA_FOLDER : TINA_FOLDER
2019
- });
1448
+ <!-- if development -->
1449
+ <script type="module">
1450
+ import RefreshRuntime from 'http://localhost:${port}/@react-refresh'
1451
+ RefreshRuntime.injectIntoGlobalHook(window)
1452
+ window.$RefreshReg$ = () => {}
1453
+ window.$RefreshSig$ = () => (type) => type
1454
+ window.__vite_plugin_react_preamble_installed__ = true
1455
+ </script>
1456
+ <script type="module" src="http://localhost:${port}/@vite/client"></script>
1457
+ <script>
1458
+ function handleLoadError() {
1459
+ // Assets have failed to load
1460
+ document.getElementById('root').innerHTML = '${errorHTML}';
2020
1461
  }
2021
- return database;
2022
- }
1462
+ </script>
1463
+ <script
1464
+ type="module"
1465
+ src="http://localhost:${port}/src/main.tsx"
1466
+ onerror="handleLoadError()"
1467
+ ></script>
1468
+ <body class="tina-tailwind">
1469
+ <div id="root"></div>
1470
+ </body>
1471
+ </html>`;
2023
1472
 
2024
- // src/next/commands/baseCommands.ts
2025
- var import_clipanion = require("clipanion");
2026
- var import_chalk4 = __toESM(require("chalk"));
1473
+ // src/next/commands/dev-command/server/index.ts
1474
+ var import_vite3 = require("vite");
2027
1475
 
2028
- // src/utils/start-subprocess.ts
2029
- var import_child_process = __toESM(require("child_process"));
2030
- var startSubprocess2 = async ({ command: command2 }) => {
2031
- if (typeof command2 === "string") {
2032
- const commands = command2.split(" ");
2033
- const firstCommand = commands[0];
2034
- const args = commands.slice(1) || [];
2035
- const ps = import_child_process.default.spawn(firstCommand, args, {
2036
- stdio: "inherit",
2037
- shell: true
2038
- });
2039
- ps.on("error", (code) => {
2040
- logger.error(
2041
- dangerText(
2042
- `An error has occurred in the Next.js child process. Error message below`
2043
- )
2044
- );
2045
- logger.error(`name: ${code.name}
2046
- message: ${code.message}
1476
+ // src/next/vite/index.ts
1477
+ var import_node_path2 = __toESM(require("path"));
1478
+ var import_plugin_react = __toESM(require("@vitejs/plugin-react"));
1479
+ var import_fs_extra4 = __toESM(require("fs-extra"));
1480
+ var import_normalize_path3 = __toESM(require("normalize-path"));
1481
+ var import_vite = require("vite");
2047
1482
 
2048
- stack: ${code.stack || "No stack was provided"}`);
2049
- });
2050
- ps.on("close", (code) => {
2051
- logger.info(`child process exited with code ${code}`);
2052
- process.exit(code);
2053
- });
2054
- return ps;
2055
- }
1483
+ // src/next/vite/tailwind.ts
1484
+ var import_node_path = __toESM(require("path"));
1485
+ var import_aspect_ratio = __toESM(require("@tailwindcss/aspect-ratio"));
1486
+ var import_container_queries = __toESM(require("@tailwindcss/container-queries"));
1487
+ var import_typography = __toESM(require("@tailwindcss/typography"));
1488
+ var import_tailwindcss = __toESM(require("tailwindcss"));
1489
+ var import_defaultTheme = __toESM(require("tailwindcss/defaultTheme.js"));
1490
+ var tinaTailwind = (spaPath, prebuildFilePath) => {
1491
+ return {
1492
+ name: "vite-plugin-tina",
1493
+ // @ts-ignore
1494
+ config: (viteConfig) => {
1495
+ const plugins = [];
1496
+ const content = [
1497
+ import_node_path.default.join(spaPath, "src/**/*.{vue,js,ts,jsx,tsx,svelte}"),
1498
+ prebuildFilePath,
1499
+ require.resolve("tinacms")
1500
+ ];
1501
+ const tw = (0, import_tailwindcss.default)({
1502
+ theme: {
1503
+ columns: {
1504
+ auto: "auto",
1505
+ 1: "1",
1506
+ 2: "2",
1507
+ 3: "3",
1508
+ 4: "4",
1509
+ 5: "5",
1510
+ 6: "6",
1511
+ 7: "7",
1512
+ 8: "8",
1513
+ 9: "9",
1514
+ 10: "10",
1515
+ 11: "11",
1516
+ 12: "12",
1517
+ "3xs": "256px",
1518
+ "2xs": "288px",
1519
+ xs: "320px",
1520
+ sm: "384px",
1521
+ md: "448px",
1522
+ lg: "512px",
1523
+ xl: "576px",
1524
+ "2xl": "672px",
1525
+ "3xl": "768px",
1526
+ "4xl": "896px",
1527
+ "5xl": "1024px",
1528
+ "6xl": "1152px",
1529
+ "7xl": "1280px"
1530
+ },
1531
+ spacing: {
1532
+ px: "1px",
1533
+ 0: "0px",
1534
+ 0.5: "2px",
1535
+ 1: "4px",
1536
+ 1.5: "6px",
1537
+ 2: "8px",
1538
+ 2.5: "10px",
1539
+ 3: "12px",
1540
+ 3.5: "14px",
1541
+ 4: "16px",
1542
+ 5: "20px",
1543
+ 6: "24px",
1544
+ 7: "28px",
1545
+ 8: "32px",
1546
+ 9: "36px",
1547
+ 10: "40px",
1548
+ 11: "44px",
1549
+ 12: "48px",
1550
+ 14: "56px",
1551
+ 16: "64px",
1552
+ 18: "72px",
1553
+ 20: "80px",
1554
+ 24: "96px",
1555
+ 28: "114px",
1556
+ 32: "128px",
1557
+ 36: "144px",
1558
+ 40: "160px",
1559
+ 44: "176px",
1560
+ 48: "192px",
1561
+ 52: "208px",
1562
+ 56: "224px",
1563
+ 60: "240px",
1564
+ 64: "256px",
1565
+ 72: "288px",
1566
+ 80: "320px",
1567
+ 96: "384px"
1568
+ },
1569
+ borderRadius: {
1570
+ none: "0px",
1571
+ sm: "2px",
1572
+ DEFAULT: "4px",
1573
+ md: "6px",
1574
+ lg: "8px",
1575
+ xl: "12px",
1576
+ "2xl": "16px",
1577
+ "3xl": "24px",
1578
+ full: "9999px"
1579
+ },
1580
+ borderWidth: {
1581
+ DEFAULT: "1px",
1582
+ 0: "0",
1583
+ 2: "2px",
1584
+ 3: "3px",
1585
+ 4: "4px",
1586
+ 6: "6px",
1587
+ 8: "8px"
1588
+ },
1589
+ fontSize: {
1590
+ xs: ["13px", { lineHeight: "1.33" }],
1591
+ sm: ["14px", { lineHeight: "1.43" }],
1592
+ base: ["16px", { lineHeight: "1.5" }],
1593
+ md: ["16px", { lineHeight: "1.5" }],
1594
+ lg: ["18px", { lineHeight: "1.55" }],
1595
+ xl: ["20px", { lineHeight: "1.4" }],
1596
+ "2xl": ["24px", { lineHeight: "1.33" }],
1597
+ "3xl": ["30px", { lineHeight: "1.2" }],
1598
+ "4xl": ["36px", { lineHeight: "1.1" }],
1599
+ "5xl": ["48px", { lineHeight: "1" }],
1600
+ "6xl": ["60px", { lineHeight: "1" }],
1601
+ "7xl": ["72px", { lineHeight: "1" }],
1602
+ "8xl": ["96px", { lineHeight: "1" }],
1603
+ "9xl": ["128px", { lineHeight: "1" }]
1604
+ },
1605
+ opacity: {
1606
+ 0: "0",
1607
+ 5: ".05",
1608
+ 7: ".07",
1609
+ 10: ".1",
1610
+ 15: ".15",
1611
+ 20: ".2",
1612
+ 25: ".25",
1613
+ 30: ".3",
1614
+ 40: ".4",
1615
+ 50: ".5",
1616
+ 60: ".6",
1617
+ 70: ".7",
1618
+ 75: ".75",
1619
+ 80: ".8",
1620
+ 90: ".9",
1621
+ 100: "1"
1622
+ },
1623
+ zIndex: {
1624
+ "-1": "-1",
1625
+ base: "9000",
1626
+ panel: "9400",
1627
+ menu: "9800",
1628
+ chrome: "10200",
1629
+ overlay: "10600",
1630
+ modal: "10800",
1631
+ 0: "0",
1632
+ 10: "10",
1633
+ 20: "20",
1634
+ 30: "30",
1635
+ 40: "40",
1636
+ 25: "25",
1637
+ 50: "50",
1638
+ 75: "75",
1639
+ 100: "100",
1640
+ auto: "auto"
1641
+ },
1642
+ extend: {
1643
+ scale: {
1644
+ 97: ".97",
1645
+ 103: "1.03"
1646
+ },
1647
+ transitionDuration: {
1648
+ 0: "0ms",
1649
+ 2e3: "2000ms"
1650
+ },
1651
+ boxShadow: {
1652
+ xs: "0 0 0 1px rgba(0, 0, 0, 0.05)",
1653
+ outline: "0 0 0 3px rgba(66, 153, 225, 0.5)"
1654
+ },
1655
+ colors: {
1656
+ blue: {
1657
+ 50: "#DCEEFF",
1658
+ 100: "#B4DBFF",
1659
+ 200: "#85C5FE",
1660
+ 300: "#4EABFE",
1661
+ 400: "#2296fe",
1662
+ 500: "#0084FF",
1663
+ 600: "#0574e4",
1664
+ 700: "#0D5DBD",
1665
+ 800: "#144696",
1666
+ 900: "#1D2C6C",
1667
+ 1e3: "#241748"
1668
+ },
1669
+ gray: {
1670
+ 50: "#F6F6F9",
1671
+ 100: "#EDECF3",
1672
+ 150: "#E6E3EF",
1673
+ 200: "#E1DDEC",
1674
+ 250: "#C9C5D5",
1675
+ 300: "#b2adbe",
1676
+ 400: "#918c9e",
1677
+ 500: "#716c7f",
1678
+ 600: "#565165",
1679
+ 700: "#433e52",
1680
+ 800: "#363145",
1681
+ 900: "#252336",
1682
+ 1e3: "#1c1b2e"
1683
+ },
1684
+ orange: {
1685
+ 400: "#EB6337",
1686
+ 500: "#EC4815",
1687
+ 600: "#DC4419"
1688
+ },
1689
+ background: "#FFFFFF",
1690
+ foreground: "#0A0A0A",
1691
+ muted: "#F5F5F5",
1692
+ "muted-foreground": "#737373",
1693
+ popover: "#FFFFFF",
1694
+ "popover-foreground": "#0A0A0A",
1695
+ card: "#FFFFFF",
1696
+ "card-foreground": "#0A0A0A",
1697
+ border: "#E5E5E5",
1698
+ input: "#E5E5E5",
1699
+ primary: "#171717",
1700
+ "primary-foreground": "#FAFAFA",
1701
+ secondary: "#F5F5F5",
1702
+ "secondary-foreground": "#171717",
1703
+ accent: "#F5F5F5",
1704
+ "accent-foreground": "#171717",
1705
+ destructive: "#FF3B3B",
1706
+ "destructive-foreground": "#FAFAFA",
1707
+ ring: "#0A0A0A"
1708
+ },
1709
+ fontFamily: {
1710
+ sans: ["Inter", ...import_defaultTheme.default.fontFamily.sans]
1711
+ },
1712
+ lineHeight: {
1713
+ 3: "12px",
1714
+ 4: "16px",
1715
+ 5: "20px",
1716
+ 6: "24px",
1717
+ 7: "28px",
1718
+ 8: "32px",
1719
+ 9: "36px",
1720
+ 10: "40px"
1721
+ },
1722
+ maxWidth: {
1723
+ form: "900px"
1724
+ },
1725
+ screens: {
1726
+ xs: "320px",
1727
+ sm: "560px",
1728
+ md: "720px",
1729
+ lg: "1030px"
1730
+ }
1731
+ }
1732
+ },
1733
+ content,
1734
+ plugins: [
1735
+ (0, import_typography.default)({ className: "tina-prose" }),
1736
+ import_aspect_ratio.default,
1737
+ import_container_queries.default
1738
+ ]
1739
+ });
1740
+ plugins.push(tw);
1741
+ return {
1742
+ css: {
1743
+ postcss: {
1744
+ plugins
1745
+ }
1746
+ }
1747
+ };
1748
+ }
1749
+ };
2056
1750
  };
2057
1751
 
2058
- // src/utils/spinner.ts
2059
- var import_cli_spinner = require("cli-spinner");
2060
- async function localSpin({
2061
- waitFor,
2062
- text
1752
+ // src/next/vite/index.ts
1753
+ async function listFilesRecursively({
1754
+ directoryPath,
1755
+ config: config2,
1756
+ roothPath
2063
1757
  }) {
2064
- const spinner = new import_cli_spinner.Spinner({
2065
- text: `${text} %s`,
2066
- stream: process.stderr,
2067
- onTick: function(msg) {
2068
- this.clearLine(this.stream);
2069
- this.stream.write(msg);
1758
+ const fullDirectoryPath = import_node_path2.default.join(
1759
+ roothPath,
1760
+ config2.publicFolder,
1761
+ directoryPath
1762
+ );
1763
+ const exists = await import_fs_extra4.default.pathExists(fullDirectoryPath);
1764
+ if (!exists) {
1765
+ return { "0": [] };
1766
+ }
1767
+ const items = await import_fs_extra4.default.readdir(fullDirectoryPath);
1768
+ const staticMediaItems = [];
1769
+ for (const item of items) {
1770
+ const itemPath = import_node_path2.default.join(fullDirectoryPath, item);
1771
+ const stats = await import_fs_extra4.default.promises.lstat(itemPath);
1772
+ const staticMediaItem = {
1773
+ id: item,
1774
+ filename: item,
1775
+ type: stats.isDirectory() ? "dir" : "file",
1776
+ directory: `${directoryPath.replace(config2.mediaRoot, "")}`,
1777
+ src: `/${import_node_path2.default.join(directoryPath, item)}`,
1778
+ thumbnails: {
1779
+ "75x75": `/${import_node_path2.default.join(directoryPath, item)}`,
1780
+ "400x400": `/${import_node_path2.default.join(directoryPath, item)}`,
1781
+ "1000x1000": `/${import_node_path2.default.join(directoryPath, item)}`
1782
+ }
1783
+ };
1784
+ if (stats.isDirectory()) {
1785
+ staticMediaItem.children = await listFilesRecursively({
1786
+ directoryPath: import_node_path2.default.join(directoryPath, item),
1787
+ config: config2,
1788
+ roothPath
1789
+ });
2070
1790
  }
2071
- });
2072
- spinner.setSpinnerString("\u280B\u2819\u2839\u2838\u283C\u2834\u2826\u2827\u2807\u280F");
2073
- spinner.start();
2074
- const res = await waitFor();
2075
- spinner.stop();
2076
- console.log("");
2077
- return res;
1791
+ staticMediaItems.push(staticMediaItem);
1792
+ }
1793
+ function chunkArrayIntoObject(array, chunkSize) {
1794
+ const result = {};
1795
+ for (let i = 0; i < array.length; i += chunkSize) {
1796
+ const chunkKey = `${i / chunkSize * 20}`;
1797
+ result[chunkKey] = array.slice(i, i + chunkSize);
1798
+ }
1799
+ return result;
1800
+ }
1801
+ return chunkArrayIntoObject(staticMediaItems, 20);
2078
1802
  }
2079
- function spin({
2080
- waitFor,
2081
- text
2082
- }) {
2083
- if (process.env.CI) {
2084
- console.log(text);
2085
- return waitFor();
2086
- } else {
2087
- return localSpin({
2088
- text,
2089
- waitFor
1803
+ var createConfig = async ({
1804
+ configManager,
1805
+ apiURL,
1806
+ plugins = [],
1807
+ noWatch,
1808
+ rollupOptions
1809
+ }) => {
1810
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1811
+ const publicEnv = {};
1812
+ Object.keys(process.env).forEach((key) => {
1813
+ if (key.startsWith("TINA_PUBLIC_") || key.startsWith("NEXT_PUBLIC_") || key === "NODE_ENV" || key === "HEAD") {
1814
+ try {
1815
+ if (typeof process.env[key] === "string") {
1816
+ publicEnv[key] = process.env[key];
1817
+ } else {
1818
+ publicEnv[key] = JSON.stringify(process.env[key]);
1819
+ }
1820
+ } catch (error) {
1821
+ console.warn(
1822
+ `Could not stringify public env process.env.${key} env variable`
1823
+ );
1824
+ console.warn(error);
1825
+ }
1826
+ }
1827
+ });
1828
+ const staticMediaPath = import_node_path2.default.join(
1829
+ configManager.generatedFolderPath,
1830
+ "static-media.json"
1831
+ );
1832
+ if ((_b = (_a = configManager.config.media) == null ? void 0 : _a.tina) == null ? void 0 : _b.static) {
1833
+ const staticMedia = await listFilesRecursively({
1834
+ directoryPath: ((_c = configManager.config.media.tina) == null ? void 0 : _c.mediaRoot) || "",
1835
+ config: configManager.config.media.tina,
1836
+ roothPath: configManager.rootPath
2090
1837
  });
1838
+ await import_fs_extra4.default.outputFile(staticMediaPath, JSON.stringify(staticMedia, null, 2));
1839
+ } else {
1840
+ await import_fs_extra4.default.outputFile(staticMediaPath, `[]`);
2091
1841
  }
2092
- }
1842
+ const alias = {
1843
+ TINA_IMPORT: configManager.prebuildFilePath,
1844
+ SCHEMA_IMPORT: configManager.generatedGraphQLJSONPath,
1845
+ STATIC_MEDIA_IMPORT: staticMediaPath,
1846
+ crypto: import_node_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts"),
1847
+ fs: import_node_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts"),
1848
+ os: import_node_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts"),
1849
+ path: import_node_path2.default.join(configManager.spaRootPath, "src", "dummy-client.ts")
1850
+ };
1851
+ if (configManager.shouldSkipSDK()) {
1852
+ alias["CLIENT_IMPORT"] = import_node_path2.default.join(
1853
+ configManager.spaRootPath,
1854
+ "src",
1855
+ "dummy-client.ts"
1856
+ );
1857
+ } else {
1858
+ alias["CLIENT_IMPORT"] = configManager.isUsingTs() ? configManager.generatedTypesTSFilePath : configManager.generatedTypesJSFilePath;
1859
+ }
1860
+ let basePath;
1861
+ if (configManager.config.build.basePath) {
1862
+ basePath = configManager.config.build.basePath;
1863
+ }
1864
+ const fullVersion = configManager.getTinaGraphQLVersion();
1865
+ const version2 = `${fullVersion.major}.${fullVersion.minor}`;
1866
+ const config2 = {
1867
+ root: configManager.spaRootPath,
1868
+ base: `/${basePath ? `${(0, import_normalize_path3.default)(basePath)}/` : ""}${(0, import_normalize_path3.default)(
1869
+ configManager.config.build.outputFolder
1870
+ )}/`,
1871
+ appType: "spa",
1872
+ resolve: {
1873
+ alias,
1874
+ dedupe: ["graphql", "tinacms", "react", "react-dom", "react-router-dom"]
1875
+ },
1876
+ define: {
1877
+ /**
1878
+ * Since we prebuild the config.ts, it's possible for modules to be loaded which make
1879
+ * use of `process`. The main scenario where this is an issue is when co-locating schema
1880
+ * definitions with source files, and specifically source files which impor from NextJS.
1881
+ *
1882
+ * Some examples of what NextJS uses for `process.env` are:
1883
+ * - `process.env.__NEXT_TRAILING_SLASH`
1884
+ * - `process.env.__NEXT_CROSS_ORIGIN`
1885
+ * - `process.env.__NEXT_I18N_SUPPORT`
1886
+ *
1887
+ * Also, interestingly some of the advice for handling this doesn't work, references to replacing
1888
+ * `process.env` with `{}` are problematic, because browsers don't understand the `{}.` syntax,
1889
+ * but node does. This was a surprise, but using `new Object()` seems to do the trick.
1890
+ */
1891
+ "process.env": `new Object(${JSON.stringify(publicEnv)})`,
1892
+ // Used by picomatch https://github.com/micromatch/picomatch/blob/master/lib/utils.js#L4
1893
+ "process.platform": `"${process.platform}"`,
1894
+ __API_URL__: `"${apiURL}"`,
1895
+ __BASE_PATH__: `"${((_e = (_d = configManager.config) == null ? void 0 : _d.build) == null ? void 0 : _e.basePath) || ""}"`,
1896
+ __TINA_GRAPHQL_VERSION__: version2
1897
+ },
1898
+ logLevel: "error",
1899
+ // Vite import warnings are noisy
1900
+ optimizeDeps: {
1901
+ force: true,
1902
+ // Not 100% sure why this isn't being picked up automatically, this works from within the monorepo
1903
+ // but breaks externally
1904
+ include: ["react/jsx-runtime", "react/jsx-dev-runtime"]
1905
+ },
1906
+ server: {
1907
+ host: (_h = (_g = (_f = configManager.config) == null ? void 0 : _f.build) == null ? void 0 : _g.host) != null ? _h : false,
1908
+ watch: noWatch ? {
1909
+ ignored: ["**/*"]
1910
+ } : {
1911
+ // Ignore everything except for the alias fields we specified above
1912
+ ignored: [
1913
+ `${configManager.tinaFolderPath}/**/!(config.prebuild.jsx|_graphql.json)`
1914
+ ]
1915
+ },
1916
+ fs: {
1917
+ strict: false
1918
+ }
1919
+ },
1920
+ build: {
1921
+ sourcemap: false,
1922
+ outDir: configManager.outputFolderPath,
1923
+ emptyOutDir: true,
1924
+ rollupOptions
1925
+ },
1926
+ plugins: [
1927
+ /**
1928
+ * `splitVendorChunkPlugin` is needed because `tinacms` is quite large,
1929
+ * Vite's chunking strategy chokes on memory issues for smaller machines (ie. on CI).
1930
+ */
1931
+ (0, import_plugin_react.default)({
1932
+ babel: {
1933
+ // Supresses the warning [NOTE] babel The code generator has deoptimised the styling of
1934
+ compact: true
1935
+ }
1936
+ }),
1937
+ (0, import_vite.splitVendorChunkPlugin)(),
1938
+ tinaTailwind(configManager.spaRootPath, configManager.prebuildFilePath),
1939
+ ...plugins
1940
+ ]
1941
+ };
1942
+ return config2;
1943
+ };
2093
1944
 
2094
- // src/next/commands/baseCommands.ts
1945
+ // src/next/vite/plugins.ts
1946
+ var import_pluginutils = require("@rollup/pluginutils");
1947
+ var import_fs = __toESM(require("fs"));
1948
+ var import_vite2 = require("vite");
1949
+ var import_esbuild2 = require("esbuild");
1950
+ var import_path4 = __toESM(require("path"));
1951
+ var import_body_parser = __toESM(require("body-parser"));
1952
+ var import_cors = __toESM(require("cors"));
2095
1953
  var import_graphql9 = require("@tinacms/graphql");
1954
+
1955
+ // src/next/commands/dev-command/server/media.ts
2096
1956
  var import_fs_extra5 = __toESM(require("fs-extra"));
2097
- var BaseCommand = class extends import_clipanion.Command {
2098
- constructor() {
2099
- super(...arguments);
2100
- this.experimentalDataLayer = import_clipanion.Option.Boolean("--experimentalData", {
2101
- description: "DEPRECATED - Build the server with additional data querying capabilities"
2102
- });
2103
- this.isomorphicGitBridge = import_clipanion.Option.Boolean("--isomorphicGitBridge", {
2104
- description: "DEPRECATED - Enable Isomorphic Git Bridge Implementation"
2105
- });
2106
- this.port = import_clipanion.Option.String("-p,--port", "4001", {
2107
- description: "Specify a port to run the server on. (default 4001)"
2108
- });
2109
- this.datalayerPort = import_clipanion.Option.String("--datalayer-port", "9000", {
2110
- description: "Specify a port to run the datalayer server on. (default 9000)"
2111
- });
2112
- this.subCommand = import_clipanion.Option.String("-c,--command", {
2113
- description: "The sub-command to run"
2114
- });
2115
- this.rootPath = import_clipanion.Option.String("--rootPath", {
2116
- description: "Specify the root directory to run the CLI from (defaults to current working directory)"
1957
+ var import_path3 = __toESM(require("path"));
1958
+ var import_busboy = __toESM(require("busboy"));
1959
+ var createMediaRouter = (config2) => {
1960
+ const mediaFolder = import_path3.default.join(
1961
+ config2.rootPath,
1962
+ config2.publicFolder,
1963
+ config2.mediaRoot
1964
+ );
1965
+ const mediaModel = new MediaModel(config2);
1966
+ const handleList = async (req, res) => {
1967
+ const requestURL = new URL(req.url, config2.apiURL);
1968
+ const folder = requestURL.pathname.replace("/media/list/", "");
1969
+ const limit = requestURL.searchParams.get("limit");
1970
+ const cursor = requestURL.searchParams.get("cursor");
1971
+ const media = await mediaModel.listMedia({
1972
+ searchPath: folder,
1973
+ cursor,
1974
+ limit
2117
1975
  });
2118
- this.verbose = import_clipanion.Option.Boolean("-v,--verbose", false, {
2119
- description: "increase verbosity of logged output"
1976
+ res.end(JSON.stringify(media));
1977
+ };
1978
+ const handleDelete = async (req, res) => {
1979
+ const file = decodeURIComponent(req.url.slice("/media/".length));
1980
+ const didDelete = await mediaModel.deleteMedia({ searchPath: file });
1981
+ res.end(JSON.stringify(didDelete));
1982
+ };
1983
+ const handlePost = async function(req, res) {
1984
+ const bb = (0, import_busboy.default)({ headers: req.headers });
1985
+ bb.on("file", async (_name, file, _info) => {
1986
+ var _a;
1987
+ const fullPath = decodeURI((_a = req.url) == null ? void 0 : _a.slice("/media/upload/".length));
1988
+ const saveTo = import_path3.default.join(mediaFolder, ...fullPath.split("/"));
1989
+ await import_fs_extra5.default.ensureDir(import_path3.default.dirname(saveTo));
1990
+ file.pipe(import_fs_extra5.default.createWriteStream(saveTo));
2120
1991
  });
2121
- this.noSDK = import_clipanion.Option.Boolean("--noSDK", false, {
2122
- description: "DEPRECATED - This should now be set in the config at client.skip = true'. Don't generate the generated client SDK"
1992
+ bb.on("error", (error) => {
1993
+ res.statusCode = 500;
1994
+ if (error instanceof Error) {
1995
+ res.end(JSON.stringify({ message: error }));
1996
+ } else {
1997
+ res.end(JSON.stringify({ message: "Unknown error while uploading" }));
1998
+ }
2123
1999
  });
2124
- this.noTelemetry = import_clipanion.Option.Boolean("--noTelemetry", false, {
2125
- description: "Disable anonymous telemetry that is collected"
2000
+ bb.on("close", () => {
2001
+ res.statusCode = 200;
2002
+ res.end(JSON.stringify({ success: true }));
2126
2003
  });
2004
+ req.pipe(bb);
2005
+ };
2006
+ return { handleList, handleDelete, handlePost };
2007
+ };
2008
+ var parseMediaFolder = (str) => {
2009
+ let returnString = str;
2010
+ if (returnString.startsWith("/")) returnString = returnString.substr(1);
2011
+ if (returnString.endsWith("/"))
2012
+ returnString = returnString.substr(0, returnString.length - 1);
2013
+ return returnString;
2014
+ };
2015
+ var MediaModel = class {
2016
+ constructor({ rootPath, publicFolder, mediaRoot }) {
2017
+ this.rootPath = rootPath;
2018
+ this.mediaRoot = mediaRoot;
2019
+ this.publicFolder = publicFolder;
2127
2020
  }
2128
- async startSubCommand() {
2129
- let subProc;
2130
- if (this.subCommand) {
2131
- subProc = await startSubprocess2({ command: this.subCommand });
2132
- logger.info(`Starting subprocess: ${import_chalk4.default.cyan(this.subCommand)}`);
2133
- }
2134
- function exitHandler(options, exitCode) {
2135
- if (subProc) {
2136
- subProc.kill();
2021
+ async listMedia(args) {
2022
+ try {
2023
+ const folderPath = (0, import_path3.join)(
2024
+ this.rootPath,
2025
+ this.publicFolder,
2026
+ this.mediaRoot,
2027
+ decodeURIComponent(args.searchPath)
2028
+ );
2029
+ const searchPath = parseMediaFolder(args.searchPath);
2030
+ if (!await import_fs_extra5.default.pathExists(folderPath)) {
2031
+ return {
2032
+ files: [],
2033
+ directories: []
2034
+ };
2137
2035
  }
2138
- process.exit();
2036
+ const filesStr = await import_fs_extra5.default.readdir(folderPath);
2037
+ const filesProm = filesStr.map(async (file) => {
2038
+ const filePath = (0, import_path3.join)(folderPath, file);
2039
+ const stat = await import_fs_extra5.default.stat(filePath);
2040
+ let src = `/${file}`;
2041
+ const isFile = stat.isFile();
2042
+ if (!isFile) {
2043
+ return {
2044
+ isFile,
2045
+ size: stat.size,
2046
+ src,
2047
+ filename: file
2048
+ };
2049
+ }
2050
+ if (searchPath) {
2051
+ src = `/${searchPath}${src}`;
2052
+ }
2053
+ if (this.mediaRoot) {
2054
+ src = `/${this.mediaRoot}${src}`;
2055
+ }
2056
+ return {
2057
+ isFile,
2058
+ size: stat.size,
2059
+ src,
2060
+ filename: file
2061
+ };
2062
+ });
2063
+ const offset = Number(args.cursor) || 0;
2064
+ const limit = Number(args.limit) || 20;
2065
+ const rawItems = await Promise.all(filesProm);
2066
+ const sortedItems = rawItems.sort((a, b) => {
2067
+ if (a.isFile && !b.isFile) {
2068
+ return 1;
2069
+ }
2070
+ if (!a.isFile && b.isFile) {
2071
+ return -1;
2072
+ }
2073
+ return 0;
2074
+ });
2075
+ const limitItems = sortedItems.slice(offset, offset + limit);
2076
+ const files = limitItems.filter((x) => x.isFile);
2077
+ const directories = limitItems.filter((x) => !x.isFile).map((x) => x.src);
2078
+ const cursor = rawItems.length > offset + limit ? String(offset + limit) : null;
2079
+ return {
2080
+ files,
2081
+ directories,
2082
+ cursor
2083
+ };
2084
+ } catch (error) {
2085
+ console.error(error);
2086
+ return {
2087
+ files: [],
2088
+ directories: [],
2089
+ error: error == null ? void 0 : error.toString()
2090
+ };
2139
2091
  }
2140
- process.on("exit", exitHandler);
2141
- process.on("SIGINT", exitHandler);
2142
- process.on("SIGUSR1", exitHandler);
2143
- process.on("SIGUSR2", exitHandler);
2144
- process.on("uncaughtException", (error) => {
2145
- logger.error(`Uncaught exception ${error.name}`);
2092
+ }
2093
+ async deleteMedia(args) {
2094
+ try {
2095
+ const file = (0, import_path3.join)(
2096
+ this.rootPath,
2097
+ this.publicFolder,
2098
+ this.mediaRoot,
2099
+ decodeURIComponent(args.searchPath)
2100
+ );
2101
+ await import_fs_extra5.default.stat(file);
2102
+ await import_fs_extra5.default.remove(file);
2103
+ return { ok: true };
2104
+ } catch (error) {
2146
2105
  console.error(error);
2147
- });
2106
+ return { ok: false, message: error == null ? void 0 : error.toString() };
2107
+ }
2148
2108
  }
2149
- logDeprecationWarnings() {
2150
- if (this.isomorphicGitBridge) {
2151
- logger.warn("--isomorphicGitBridge has been deprecated");
2109
+ };
2110
+
2111
+ // src/next/commands/dev-command/server/searchIndex.ts
2112
+ var createSearchIndexRouter = ({
2113
+ config: config2,
2114
+ searchIndex
2115
+ }) => {
2116
+ const put = async (req, res) => {
2117
+ const { docs } = req.body;
2118
+ const result = await searchIndex.PUT(docs);
2119
+ res.writeHead(200, { "Content-Type": "application/json" });
2120
+ res.end(JSON.stringify({ result }));
2121
+ };
2122
+ const get = async (req, res) => {
2123
+ const requestURL = new URL(req.url, config2.apiURL);
2124
+ const query = requestURL.searchParams.get("q");
2125
+ const optionsParam = requestURL.searchParams.get("options");
2126
+ let options = {
2127
+ DOCUMENTS: false
2128
+ };
2129
+ if (optionsParam) {
2130
+ options = {
2131
+ ...options,
2132
+ ...JSON.parse(optionsParam)
2133
+ };
2152
2134
  }
2153
- if (this.experimentalDataLayer) {
2154
- logger.warn(
2155
- "--experimentalDataLayer has been deprecated, the data layer is now built-in automatically"
2156
- );
2135
+ res.writeHead(200, { "Content-Type": "application/json" });
2136
+ if (query) {
2137
+ const result = await searchIndex.QUERY(JSON.parse(query), options);
2138
+ res.end(JSON.stringify(result));
2139
+ } else {
2140
+ res.end(JSON.stringify({ RESULT: [] }));
2157
2141
  }
2158
- if (this.noSDK) {
2159
- logger.warn(
2160
- "--noSDK has been deprecated, and will be unsupported in a future release. This should be set in the config at client.skip = true"
2161
- );
2142
+ };
2143
+ const del = async (req, res) => {
2144
+ const requestURL = new URL(req.url, config2.apiURL);
2145
+ const docId = requestURL.pathname.split("/").filter(Boolean).slice(1).join("/");
2146
+ const result = await searchIndex.DELETE(docId);
2147
+ res.writeHead(200, { "Content-Type": "application/json" });
2148
+ res.end(JSON.stringify({ result }));
2149
+ };
2150
+ return { del, get, put };
2151
+ };
2152
+
2153
+ // src/next/vite/plugins.ts
2154
+ var transformTsxPlugin = ({
2155
+ configManager: _configManager
2156
+ }) => {
2157
+ const plug = {
2158
+ name: "transform-tsx",
2159
+ async transform(code, id) {
2160
+ const extName = import_path4.default.extname(id);
2161
+ if (extName.startsWith(".tsx") || extName.startsWith(".ts")) {
2162
+ const result = await (0, import_esbuild2.transform)(code, { loader: "tsx" });
2163
+ return {
2164
+ code: result.code
2165
+ };
2166
+ }
2162
2167
  }
2163
- }
2164
- async indexContentWithSpinner({
2165
- database,
2166
- graphQLSchema,
2167
- tinaSchema,
2168
- configManager,
2169
- partialReindex,
2170
- text
2171
- }) {
2172
- const textToUse = text || "Indexing local files";
2173
- const warnings = [];
2174
- await spin({
2175
- waitFor: async () => {
2176
- var _a, _b;
2177
- const rootPath = configManager.rootPath;
2178
- let sha;
2179
- try {
2180
- sha = await (0, import_graphql9.getSha)({ fs: import_fs_extra5.default, dir: rootPath });
2181
- } catch (e) {
2182
- if (partialReindex) {
2183
- console.error(
2184
- "Failed to get sha. NOTE: `--partial-reindex` only supported for git repositories"
2185
- );
2186
- throw e;
2187
- }
2188
- }
2189
- const lastSha = await database.getMetadata("lastSha");
2190
- const exists = lastSha && await (0, import_graphql9.shaExists)({ fs: import_fs_extra5.default, dir: rootPath, sha: lastSha });
2191
- let res;
2192
- if (partialReindex && lastSha && exists && sha) {
2193
- const pathFilter = {};
2194
- if (configManager.isUsingLegacyFolder) {
2195
- pathFilter[".tina/__generated__/_schema.json"] = {};
2196
- } else {
2197
- pathFilter["tina/tina-lock.json"] = {};
2198
- }
2199
- for (const collection of tinaSchema.getCollections()) {
2200
- pathFilter[collection.path] = {
2201
- matches: ((_a = collection.match) == null ? void 0 : _a.exclude) || ((_b = collection.match) == null ? void 0 : _b.include) ? tinaSchema.getMatches({ collection }) : void 0
2202
- };
2203
- }
2204
- const { added, modified, deleted } = await (0, import_graphql9.getChangedFiles)({
2205
- fs: import_fs_extra5.default,
2206
- dir: rootPath,
2207
- from: lastSha,
2208
- to: sha,
2209
- pathFilter
2210
- });
2211
- const tinaPathUpdates = modified.filter(
2212
- (path14) => path14.startsWith(".tina/__generated__/_schema.json") || path14.startsWith("tina/tina-lock.json")
2168
+ };
2169
+ return plug;
2170
+ };
2171
+ var devServerEndPointsPlugin = ({
2172
+ configManager,
2173
+ apiURL,
2174
+ database,
2175
+ searchIndex,
2176
+ databaseLock
2177
+ }) => {
2178
+ const plug = {
2179
+ name: "graphql-endpoints",
2180
+ configureServer(server) {
2181
+ server.middlewares.use((0, import_cors.default)());
2182
+ server.middlewares.use(import_body_parser.default.json({ limit: "5mb" }));
2183
+ server.middlewares.use(async (req, res, next) => {
2184
+ var _a;
2185
+ const mediaPaths = (_a = configManager.config.media) == null ? void 0 : _a.tina;
2186
+ const mediaRouter = createMediaRouter({
2187
+ rootPath: configManager.rootPath,
2188
+ apiURL,
2189
+ publicFolder: parseMediaFolder((mediaPaths == null ? void 0 : mediaPaths.publicFolder) || ""),
2190
+ mediaRoot: parseMediaFolder((mediaPaths == null ? void 0 : mediaPaths.mediaRoot) || "")
2191
+ });
2192
+ const searchIndexRouter = createSearchIndexRouter({
2193
+ config: { apiURL, searchPath: "searchIndex" },
2194
+ searchIndex
2195
+ });
2196
+ if (req.url.startsWith("/media/upload")) {
2197
+ await mediaRouter.handlePost(req, res);
2198
+ return;
2199
+ }
2200
+ if (req.url.startsWith("/media")) {
2201
+ if (req.method === "DELETE") {
2202
+ await mediaRouter.handleDelete(req, res);
2203
+ return;
2204
+ }
2205
+ }
2206
+ if (req.url.startsWith("/media/list")) {
2207
+ await mediaRouter.handleList(req, res);
2208
+ return;
2209
+ }
2210
+ if (req.url === "/altair") {
2211
+ res.end(
2212
+ JSON.stringify({
2213
+ status: "The GraphQL playground has moved to <your-dev-url>/index.html#/graphql"
2214
+ })
2213
2215
  );
2214
- if (tinaPathUpdates.length > 0) {
2215
- res = await database.indexContent({
2216
- graphQLSchema,
2217
- tinaSchema
2216
+ return;
2217
+ }
2218
+ if (req.url === "/graphql") {
2219
+ const { query, variables } = req.body;
2220
+ let result;
2221
+ await databaseLock(async () => {
2222
+ result = await (0, import_graphql9.resolve)({
2223
+ config: {
2224
+ useRelativeMedia: true
2225
+ },
2226
+ database,
2227
+ query,
2228
+ variables,
2229
+ verbose: false
2218
2230
  });
2219
- } else {
2220
- if (added.length > 0 || modified.length > 0) {
2221
- await database.indexContentByPaths([...added, ...modified]);
2222
- }
2223
- if (deleted.length > 0) {
2224
- await database.deleteContentByPaths(deleted);
2225
- }
2226
- }
2227
- } else {
2228
- res = await database.indexContent({
2229
- graphQLSchema,
2230
- tinaSchema
2231
2231
  });
2232
+ res.end(JSON.stringify(result));
2233
+ return;
2232
2234
  }
2233
- if (sha) {
2234
- await database.setMetadata("lastSha", sha);
2235
- }
2236
- if (res == null ? void 0 : res.warnings) {
2237
- warnings.push(...res.warnings);
2235
+ if (req.url.startsWith("/searchIndex")) {
2236
+ if (req.method === "POST") {
2237
+ await searchIndexRouter.put(req, res);
2238
+ } else if (req.method === "GET") {
2239
+ await searchIndexRouter.get(req, res);
2240
+ } else if (req.method === "DELETE") {
2241
+ await searchIndexRouter.del(req, res);
2242
+ }
2243
+ return;
2238
2244
  }
2239
- },
2240
- text: textToUse
2241
- });
2242
- if (warnings.length > 0) {
2243
- logger.warn(`Indexing completed with ${warnings.length} warning(s)`);
2244
- warnings.forEach((warning) => {
2245
- logger.warn(warnText(`${warning}`));
2245
+ next();
2246
2246
  });
2247
2247
  }
2248
- }
2248
+ };
2249
+ return plug;
2250
+ };
2251
+ function viteTransformExtension({
2252
+ exportAsDefault = true,
2253
+ svgrOptions,
2254
+ esbuildOptions,
2255
+ include = "**/*.svg",
2256
+ exclude
2257
+ } = {}) {
2258
+ const filter = (0, import_pluginutils.createFilter)(include, exclude);
2259
+ return {
2260
+ name: "vite-plugin-svgr",
2261
+ async transform(code, id) {
2262
+ if (filter(id)) {
2263
+ const { transform: transform2 } = await Promise.resolve().then(() => __toESM(require("@svgr/core")));
2264
+ const svgCode = await import_fs.default.promises.readFile(
2265
+ id.replace(/\?.*$/, ""),
2266
+ "utf8"
2267
+ );
2268
+ const componentCode = await transform2(svgCode, svgrOptions, {
2269
+ filePath: id,
2270
+ caller: {
2271
+ previousExport: exportAsDefault ? null : code
2272
+ }
2273
+ });
2274
+ const res = await (0, import_vite2.transformWithEsbuild)(componentCode, id, {
2275
+ loader: "jsx",
2276
+ ...esbuildOptions
2277
+ });
2278
+ return {
2279
+ code: res.code,
2280
+ map: null
2281
+ // TODO:
2282
+ };
2283
+ }
2284
+ }
2285
+ };
2286
+ }
2287
+
2288
+ // src/next/commands/dev-command/server/index.ts
2289
+ var createDevServer = async (configManager, database, searchIndex, apiURL, noWatch, databaseLock) => {
2290
+ const plugins = [
2291
+ transformTsxPlugin({ configManager }),
2292
+ devServerEndPointsPlugin({
2293
+ apiURL,
2294
+ configManager,
2295
+ database,
2296
+ searchIndex,
2297
+ databaseLock
2298
+ }),
2299
+ viteTransformExtension()
2300
+ ];
2301
+ return (0, import_vite3.createServer)(
2302
+ await createConfig({
2303
+ configManager,
2304
+ database,
2305
+ apiURL,
2306
+ plugins,
2307
+ noWatch,
2308
+ /**
2309
+ * Ensure Vite's import scan uses the spaMainPath as the input
2310
+ * so it properly finds everything. This is for dev only, and when
2311
+ * running the server outside of this monorepo vite fails to find
2312
+ * and optimize the imports, so you get errors about it not being
2313
+ * able to find an export from a module, and it's always a CJS
2314
+ * module that Vite would usually transform to an ES module.
2315
+ */
2316
+ rollupOptions: {
2317
+ input: configManager.spaMainPath,
2318
+ onwarn(warning, warn) {
2319
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE") {
2320
+ return;
2321
+ }
2322
+ warn(warning);
2323
+ }
2324
+ }
2325
+ })
2326
+ );
2249
2327
  };
2250
2328
 
2251
2329
  // src/next/commands/dev-command/index.ts
2252
- var import_search = require("@tinacms/search");
2253
2330
  var DevCommand = class extends BaseCommand {
2254
2331
  constructor() {
2255
2332
  super(...arguments);
2333
+ // NOTE: camelCase commands for string options don't work if there's an `=` used https://github.com/arcanis/clipanion/issues/141
2256
2334
  this.watchFolders = import_clipanion2.Option.String("-w,--watchFolders", {
2257
2335
  description: "DEPRECATED - a list of folders (relative to where this is being run) that the cli will watch for changes"
2258
2336
  });
@@ -2262,6 +2340,10 @@ var DevCommand = class extends BaseCommand {
2262
2340
  this.outputSearchIndexPath = import_clipanion2.Option.String("--outputSearchIndexPath", {
2263
2341
  description: "Path to write the search index to"
2264
2342
  });
2343
+ this.noServer = import_clipanion2.Option.Boolean("--no-server", false, {
2344
+ description: "Do not start the dev server"
2345
+ });
2346
+ this.indexingLock = new import_async_lock.default();
2265
2347
  }
2266
2348
  async catch(error) {
2267
2349
  logger.error("Error occured during tinacms dev");
@@ -2282,10 +2364,13 @@ var DevCommand = class extends BaseCommand {
2282
2364
  rootPath: this.rootPath,
2283
2365
  legacyNoSDK: this.noSDK
2284
2366
  });
2285
- logger.info("Starting Tina Dev Server");
2367
+ logger.info("\u{1F999} TinaCMS Dev Server is initializing...");
2286
2368
  this.logDeprecationWarnings();
2287
2369
  createDBServer(Number(this.datalayerPort));
2288
2370
  let database = null;
2371
+ const dbLock = async (fn) => {
2372
+ return this.indexingLock.acquire("Key", fn);
2373
+ };
2289
2374
  const setup = async ({ firstTime }) => {
2290
2375
  try {
2291
2376
  await configManager.processConfig();
@@ -2336,9 +2421,6 @@ var DevCommand = class extends BaseCommand {
2336
2421
  await import_fs_extra6.default.outputFile(filePath, tinaLockContent);
2337
2422
  }
2338
2423
  }
2339
- if (!this.noWatch) {
2340
- this.watchQueries(configManager, async () => await codegen2.execute());
2341
- }
2342
2424
  await this.indexContentWithSpinner({
2343
2425
  database,
2344
2426
  graphQLSchema: graphQLSchema2,
@@ -2348,6 +2430,13 @@ var DevCommand = class extends BaseCommand {
2348
2430
  if (!firstTime) {
2349
2431
  logger.error("Re-index complete");
2350
2432
  }
2433
+ if (!this.noWatch) {
2434
+ this.watchQueries(
2435
+ configManager,
2436
+ dbLock,
2437
+ async () => await codegen2.execute()
2438
+ );
2439
+ }
2351
2440
  return { apiURL: apiURL2, database, graphQLSchema: graphQLSchema2, tinaSchema: tinaSchema2 };
2352
2441
  } catch (e) {
2353
2442
  logger.error(`
@@ -2382,14 +2471,6 @@ ${dangerText(e.message)}
2382
2471
  tokenSplitRegex: (_d = (_c = configManager.config.search) == null ? void 0 : _c.tina) == null ? void 0 : _d.tokenSplitRegex
2383
2472
  });
2384
2473
  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
2474
  const searchIndexer = new import_search.SearchIndexer({
2394
2475
  batchSize: ((_e = configManager.config.search) == null ? void 0 : _e.indexBatchSize) || 100,
2395
2476
  bridge: new import_graphql10.FilesystemBridge(
@@ -2411,16 +2492,34 @@ ${dangerText(e.message)}
2411
2492
  await searchIndexClient.export(this.outputSearchIndexPath);
2412
2493
  }
2413
2494
  }
2495
+ if (this.noServer) {
2496
+ logger.info("--no-server option specified - Dev server not started");
2497
+ process.exit(0);
2498
+ }
2414
2499
  if (!this.noWatch) {
2415
2500
  this.watchContentFiles(
2416
2501
  configManager,
2417
2502
  database,
2503
+ dbLock,
2418
2504
  configManager.config.search && searchIndexer
2419
2505
  );
2506
+ }
2507
+ const server = await createDevServer(
2508
+ configManager,
2509
+ database,
2510
+ searchIndexClient.searchIndex,
2511
+ apiURL,
2512
+ this.noWatch,
2513
+ dbLock
2514
+ );
2515
+ await server.listen(Number(this.port));
2516
+ if (!this.noWatch) {
2420
2517
  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: "*" });
2518
+ await dbLock(async () => {
2519
+ logger.info(`Tina config change detected, rebuilding`);
2520
+ await setup({ firstTime: false });
2521
+ server.ws.send({ type: "full-reload", path: "*" });
2522
+ });
2424
2523
  });
2425
2524
  }
2426
2525
  const subItems = [];
@@ -2433,7 +2532,7 @@ ${dangerText(e.message)}
2433
2532
  const summaryItems = [
2434
2533
  {
2435
2534
  emoji: "\u{1F999}",
2436
- heading: "Tina Config",
2535
+ heading: "TinaCMS URLs",
2437
2536
  subItems: [
2438
2537
  {
2439
2538
  key: "CMS",
@@ -2468,14 +2567,28 @@ ${dangerText(e.message)}
2468
2567
  });
2469
2568
  }
2470
2569
  summary({
2471
- heading: "Tina Dev Server is running...",
2570
+ heading: "\u2705 \u{1F999} TinaCMS Dev Server is active:",
2472
2571
  items: [
2473
2572
  ...summaryItems
2573
+ // {
2574
+ // emoji: '📚',
2575
+ // heading: 'Useful links',
2576
+ // subItems: [
2577
+ // {
2578
+ // key: 'Custom queries',
2579
+ // value: 'https://tina.io/querying',
2580
+ // },
2581
+ // {
2582
+ // key: 'Visual editing',
2583
+ // value: 'https://tina.io/visual-editing',
2584
+ // },
2585
+ // ],
2586
+ // },
2474
2587
  ]
2475
2588
  });
2476
2589
  await this.startSubCommand();
2477
2590
  }
2478
- watchContentFiles(configManager, database, searchIndexer) {
2591
+ watchContentFiles(configManager, database, databaseLock, searchIndexer) {
2479
2592
  const collectionContentFiles = [];
2480
2593
  configManager.config.schema.collections.forEach((collection) => {
2481
2594
  const collectionGlob = `${import_path5.default.join(
@@ -2491,39 +2604,42 @@ ${dangerText(e.message)}
2491
2604
  if (!ready) {
2492
2605
  return;
2493
2606
  }
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
- }
2607
+ await databaseLock(async () => {
2608
+ const pathFromRoot = configManager.printContentRelativePath(addedFile);
2609
+ await database.indexContentByPaths([pathFromRoot]).catch(console.error);
2610
+ if (searchIndexer) {
2611
+ await searchIndexer.indexContentByPaths([pathFromRoot]).catch(console.error);
2612
+ }
2613
+ });
2499
2614
  }).on("change", async (changedFile) => {
2500
2615
  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
- }
2616
+ await databaseLock(async () => {
2617
+ await database.indexContentByPaths([pathFromRoot]).catch(console.error);
2618
+ if (searchIndexer) {
2619
+ await searchIndexer.indexContentByPaths([pathFromRoot]).catch(console.error);
2620
+ }
2621
+ });
2505
2622
  }).on("unlink", async (removedFile) => {
2506
2623
  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
- }
2624
+ await databaseLock(async () => {
2625
+ await database.deleteContentByPaths([pathFromRoot]).catch(console.error);
2626
+ if (searchIndexer) {
2627
+ await searchIndexer.deleteIndexContent([pathFromRoot]).catch(console.error);
2628
+ }
2629
+ });
2511
2630
  });
2512
2631
  }
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
- });
2632
+ watchQueries(configManager, databaseLock, callback) {
2633
+ const executeCallback = async (_) => {
2634
+ await databaseLock(async () => {
2635
+ await callback();
2636
+ });
2637
+ };
2638
+ import_chokidar.default.watch(configManager.userQueriesAndFragmentsGlob).on("add", executeCallback).on("change", executeCallback).on("unlink", executeCallback);
2524
2639
  }
2525
2640
  };
2526
2641
  DevCommand.paths = [["dev"], ["server:start"]];
2642
+ // Prevent indexes and reads occurring at once
2527
2643
  DevCommand.usage = import_clipanion2.Command.Usage({
2528
2644
  category: `Commands`,
2529
2645
  description: `Builds Tina and starts the dev server`,
@@ -2534,12 +2650,41 @@ DevCommand.usage = import_clipanion2.Command.Usage({
2534
2650
  });
2535
2651
 
2536
2652
  // src/next/commands/build-command/index.ts
2537
- var import_clipanion3 = require("clipanion");
2538
- var import_progress2 = __toESM(require("progress"));
2539
- var import_fs_extra7 = __toESM(require("fs-extra"));
2540
2653
  var import_crypto = __toESM(require("crypto"));
2541
2654
  var import_path6 = __toESM(require("path"));
2655
+ var import_core3 = require("@graphql-inspector/core");
2542
2656
  var import_graphql11 = require("@tinacms/graphql");
2657
+ var import_schema_tools2 = require("@tinacms/schema-tools");
2658
+ var import_search2 = require("@tinacms/search");
2659
+ var import_clipanion3 = require("clipanion");
2660
+ var import_fs_extra7 = __toESM(require("fs-extra"));
2661
+ var import_graphql12 = require("graphql");
2662
+ var import_progress2 = __toESM(require("progress"));
2663
+
2664
+ // src/utils/index.ts
2665
+ var import_core2 = require("@graphql-inspector/core");
2666
+ var getFaqLink = (type) => {
2667
+ switch (type) {
2668
+ case import_core2.ChangeType.FieldRemoved: {
2669
+ return "https://tina.io/docs/introduction/faq#how-do-i-resolve-the-local-graphql-schema-doesnt-match-the-remote-graphql-schema-errors";
2670
+ }
2671
+ default:
2672
+ return null;
2673
+ }
2674
+ };
2675
+
2676
+ // src/utils/sleep.ts
2677
+ function timeout(ms) {
2678
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
2679
+ }
2680
+ async function sleepAndCallFunc({
2681
+ fn,
2682
+ ms
2683
+ }) {
2684
+ await timeout(ms);
2685
+ const res = await fn();
2686
+ return res;
2687
+ }
2543
2688
 
2544
2689
  // src/next/commands/build-command/server.ts
2545
2690
  var import_vite5 = require("vite");
@@ -2579,29 +2724,9 @@ var buildProductionSpa = async (configManager, database, apiURL) => {
2579
2724
  return (0, import_vite5.build)(config2);
2580
2725
  };
2581
2726
 
2582
- // src/next/commands/build-command/index.ts
2583
- var import_schema_tools2 = require("@tinacms/schema-tools");
2584
- var import_graphql12 = require("graphql");
2585
- var import_core3 = require("@graphql-inspector/core");
2586
-
2587
2727
  // src/next/commands/build-command/waitForDB.ts
2588
- var import_progress = __toESM(require("progress"));
2589
2728
  var import_schema_tools = require("@tinacms/schema-tools");
2590
-
2591
- // src/utils/sleep.ts
2592
- function timeout(ms) {
2593
- return new Promise((resolve2) => setTimeout(resolve2, ms));
2594
- }
2595
- async function sleepAndCallFunc({
2596
- fn,
2597
- ms
2598
- }) {
2599
- await timeout(ms);
2600
- const res = await fn();
2601
- return res;
2602
- }
2603
-
2604
- // src/next/commands/build-command/waitForDB.ts
2729
+ var import_progress = __toESM(require("progress"));
2605
2730
  var POLLING_INTERVAL = 5e3;
2606
2731
  var STATUS_INPROGRESS = "inprogress";
2607
2732
  var STATUS_COMPLETE = "complete";
@@ -2617,12 +2742,12 @@ var waitForDB = async (config2, apiUrl, previewName, verbose) => {
2617
2742
  const { clientId, branch, isLocalClient, host } = (0, import_schema_tools.parseURL)(apiUrl);
2618
2743
  if (isLocalClient || !host || !clientId || !branch) {
2619
2744
  if (verbose) {
2620
- logger.info(logText("Not using Tina Cloud, skipping DB check"));
2745
+ logger.info(logText("Not using TinaCloud, skipping DB check"));
2621
2746
  }
2622
2747
  return;
2623
2748
  }
2624
2749
  const bar2 = new import_progress.default(
2625
- "Checking indexing process in Tina Cloud... :prog",
2750
+ "Checking indexing process in TinaCloud... :prog",
2626
2751
  1
2627
2752
  );
2628
2753
  const pollForStatus = async () => {
@@ -2656,11 +2781,11 @@ var waitForDB = async (config2, apiUrl, previewName, verbose) => {
2656
2781
  await sleepAndCallFunc({ fn: pollForStatus, ms: POLLING_INTERVAL });
2657
2782
  } else if (status === STATUS_FAILED) {
2658
2783
  throw new IndexFailedError(
2659
- `Attempting to index but responded with status 'failed'. To retry the indexing process, click the "Reindex" button for '${previewName || branch}' in the Tina Cloud configuration for this project. ${error}`
2784
+ `Attempting to index but responded with status 'failed'. To retry the indexing process, click the "Reindex" button for '${previewName || branch}' in the TinaCloud configuration for this project. ${error}`
2660
2785
  );
2661
2786
  } else {
2662
2787
  throw new IndexFailedError(
2663
- `Attempting to index but responded with status 'unknown'. To retry the indexing process, click the "Reindex" button for '${previewName || branch}' in the Tina Cloud configuration for this project. ${error}`
2788
+ `Attempting to index but responded with status 'unknown'. To retry the indexing process, click the "Reindex" button for '${previewName || branch}' in the TinaCloud configuration for this project. ${error}`
2664
2789
  );
2665
2790
  }
2666
2791
  } catch (e) {
@@ -2677,26 +2802,11 @@ var waitForDB = async (config2, apiUrl, previewName, verbose) => {
2677
2802
  }
2678
2803
  };
2679
2804
  await spin({
2680
- text: "Checking indexing process in Tina Cloud...",
2805
+ text: "Checking indexing process in TinaCloud...",
2681
2806
  waitFor: pollForStatus
2682
2807
  });
2683
2808
  };
2684
2809
 
2685
- // src/next/commands/build-command/index.ts
2686
- var import_search2 = require("@tinacms/search");
2687
-
2688
- // src/utils/index.ts
2689
- var import_core2 = require("@graphql-inspector/core");
2690
- var getFaqLink = (type) => {
2691
- switch (type) {
2692
- case import_core2.ChangeType.FieldRemoved: {
2693
- return "https://tina.io/docs/introduction/faq#how-do-i-resolve-the-local-graphql-schema-doesnt-match-the-remote-graphql-schema-errors";
2694
- }
2695
- default:
2696
- return null;
2697
- }
2698
- };
2699
-
2700
2810
  // src/next/commands/build-command/index.ts
2701
2811
  var BuildCommand = class extends BaseCommand {
2702
2812
  constructor() {
@@ -2713,6 +2823,9 @@ var BuildCommand = class extends BaseCommand {
2713
2823
  this.tinaGraphQLVersion = import_clipanion3.Option.String("--tina-graphql-version", {
2714
2824
  description: "Specify the version of @tinacms/graphql to use (defaults to latest)"
2715
2825
  });
2826
+ /**
2827
+ * This option allows the user to skip the TinaCloud 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 TinaCloud
2828
+ */
2716
2829
  this.skipCloudChecks = import_clipanion3.Option.Boolean("--skip-cloud-checks", false, {
2717
2830
  description: "Skips checking the provided cloud config."
2718
2831
  });
@@ -2818,7 +2931,8 @@ ${dangerText(e.message)}
2818
2931
  database,
2819
2932
  null,
2820
2933
  apiURL,
2821
- true
2934
+ true,
2935
+ (lockedFn) => lockedFn()
2822
2936
  );
2823
2937
  await server.listen(Number(this.port));
2824
2938
  console.log("server listening on port", this.port);
@@ -2880,7 +2994,9 @@ ${dangerText(e.message)}
2880
2994
  `ERROR: Branch not configured in tina search configuration.`
2881
2995
  )}`
2882
2996
  );
2883
- throw new Error("Branch not configured in tina search configuration.");
2997
+ throw new Error(
2998
+ "Branch not configured in tina search configuration."
2999
+ );
2884
3000
  }
2885
3001
  if (!((_d = configManager.config) == null ? void 0 : _d.clientId)) {
2886
3002
  logger.error(`${dangerText(`ERROR: clientId not configured.`)}`);
@@ -3023,7 +3139,7 @@ ${dangerText(e.message)}
3023
3139
  });
3024
3140
  throw e;
3025
3141
  }
3026
- const branchBar = new import_progress2.default("Checking branch is on Tina Cloud. :prog", 1);
3142
+ const branchBar = new import_progress2.default("Checking branch is on TinaCloud. :prog", 1);
3027
3143
  if (branchKnown) {
3028
3144
  branchBar.tick({
3029
3145
  prog: "\u2705"
@@ -3060,12 +3176,12 @@ ${dangerText(e.message)}
3060
3176
  });
3061
3177
  logger.error(
3062
3178
  `${dangerText(
3063
- `ERROR: Branch '${branch}' is not on Tina Cloud.`
3179
+ `ERROR: Branch '${branch}' is not on TinaCloud.`
3064
3180
  )} Please make sure that branch '${branch}' exists in your repository and that you have pushed your all changes to the remote. View all all branches and there current status here: ${linkText(
3065
3181
  `https://app.tina.io/projects/${clientId}/configuration`
3066
3182
  )}`
3067
3183
  );
3068
- throw new Error("Branch is not on Tina Cloud");
3184
+ throw new Error("Branch is not on TinaCloud");
3069
3185
  }
3070
3186
  async syncProject(configManager, apiURL, options) {
3071
3187
  const { config: config2 } = configManager;
@@ -3127,7 +3243,7 @@ ${dangerText(e.message)}
3127
3243
  );
3128
3244
  const { config: config2 } = configManager;
3129
3245
  const token = config2.token;
3130
- const { remoteSchema, remoteVersion } = await fetchRemoteGraphqlSchema({
3246
+ const { remoteSchema, remoteProjectVersion } = await fetchRemoteGraphqlSchema({
3131
3247
  url: apiURL,
3132
3248
  token
3133
3249
  });
@@ -3147,7 +3263,7 @@ Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3147
3263
  const localSchemaDocument = await database.getGraphQLSchemaFromBridge();
3148
3264
  const localGraphqlSchema = (0, import_graphql12.buildASTSchema)(localSchemaDocument);
3149
3265
  try {
3150
- const diffResult = await (0, import_core3.diff)(localGraphqlSchema, remoteGqlSchema);
3266
+ const diffResult = await (0, import_core3.diff)(remoteGqlSchema, localGraphqlSchema);
3151
3267
  if (diffResult.length === 0) {
3152
3268
  bar2.tick({
3153
3269
  prog: "\u2705"
@@ -3160,6 +3276,7 @@ Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
3160
3276
  const reason = diffResult[0].message;
3161
3277
  const errorLevel = diffResult[0].criticality.level;
3162
3278
  const faqLink = getFaqLink(type);
3279
+ const tinaGraphQLVersion = configManager.getTinaGraphQLVersion();
3163
3280
  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 && `
3164
3281
  Check out '${faqLink}' for possible solutions.`}`;
3165
3282
  errorMessage += `
@@ -3171,7 +3288,7 @@ Additional info:
3171
3288
  errorMessage += ` Branch: ${config2.branch}, Client ID: ${config2.clientId}
3172
3289
  `;
3173
3290
  }
3174
- errorMessage += ` Local GraphQL version: ${configManager.getTinaGraphQLVersion()} / Remote GraphQL version: ${remoteVersion}
3291
+ errorMessage += ` Local GraphQL version: ${tinaGraphQLVersion.fullVersion} / Remote GraphQL version: ${remoteProjectVersion}
3175
3292
  `;
3176
3293
  errorMessage += ` Last indexed at: ${new Date(
3177
3294
  timestamp
@@ -3203,7 +3320,7 @@ Additional info:
3203
3320
  const { clientId, branch, isLocalClient, host } = (0, import_schema_tools2.parseURL)(apiURL);
3204
3321
  if (isLocalClient || !host || !clientId || !branch) {
3205
3322
  if (verbose) {
3206
- logger.info(logText("Not using Tina Cloud, skipping Tina Schema check"));
3323
+ logger.info(logText("Not using TinaCloud, skipping Tina Schema check"));
3207
3324
  }
3208
3325
  return;
3209
3326
  }
@@ -3262,7 +3379,7 @@ Additional info:
3262
3379
  BuildCommand.paths = [["build"]];
3263
3380
  BuildCommand.usage = import_clipanion3.Command.Usage({
3264
3381
  category: `Commands`,
3265
- description: `Build the CMS and autogenerated modules for usage with Tina Cloud`
3382
+ description: `Build the CMS and autogenerated modules for usage with TinaCloud`
3266
3383
  });
3267
3384
  async function request(args) {
3268
3385
  const headers = new Headers();
@@ -3326,7 +3443,8 @@ var fetchRemoteGraphqlSchema = async ({
3326
3443
  const data = await res.json();
3327
3444
  return {
3328
3445
  remoteSchema: data == null ? void 0 : data.data,
3329
- remoteVersion: res.headers.get("tinacms-grapqhl-version")
3446
+ remoteRuntimeVersion: res.headers.get("tinacms-grapqhl-version"),
3447
+ remoteProjectVersion: res.headers.get("tinacms-graphql-project-version")
3330
3448
  };
3331
3449
  };
3332
3450
  var fetchSchemaSha = async ({
@@ -3451,6 +3569,7 @@ var auditDocuments = async (args) => {
3451
3569
  logger.error(import_chalk5.default.red(err.message));
3452
3570
  if (err.originalError.originalError) {
3453
3571
  logger.error(
3572
+ // @ts-ignore FIXME: this doesn't seem right
3454
3573
  import_chalk5.default.red(` ${err.originalError.originalError.message}`)
3455
3574
  );
3456
3575
  }
@@ -3656,7 +3775,9 @@ var detectEnvironment = async ({
3656
3775
  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")));
3657
3776
  const tinaFolder = import_path7.default.join(baseDir, "tina");
3658
3777
  const tinaConfigExists = Boolean(
3659
- await import_fs_extra8.default.pathExists(tinaFolder) && (await import_fs_extra8.default.readdir(tinaFolder)).find((x) => x.includes("config"))
3778
+ // Does the tina folder exist?
3779
+ await import_fs_extra8.default.pathExists(tinaFolder) && // Does the tina folder contain a config file?
3780
+ (await import_fs_extra8.default.readdir(tinaFolder)).find((x) => x.includes("config"))
3660
3781
  );
3661
3782
  const pagesDir = [baseDir, usingSrc ? "src" : false, "pages"].filter(
3662
3783
  Boolean
@@ -3760,7 +3881,7 @@ var tinaCloudSetupQuestions = [
3760
3881
  {
3761
3882
  name: "clientId",
3762
3883
  type: "text",
3763
- message: `What is your Tina Cloud Client ID? (Hit enter to skip and set up yourself later)
3884
+ message: `What is your TinaCloud Client ID? (Hit enter to skip and set up yourself later)
3764
3885
  ${logText(
3765
3886
  "Don't have a Client ID? Create one here: "
3766
3887
  )}${linkText("https://app.tina.io/projects/new")}`,
@@ -3769,7 +3890,7 @@ ${logText(
3769
3890
  {
3770
3891
  name: "token",
3771
3892
  type: "text",
3772
- message: (prev) => `What is your Tina Cloud Read Only Token?
3893
+ message: (prev) => `What is your TinaCloud Read Only Token?
3773
3894
  ${logText(
3774
3895
  "Don't have a Read Only Token? Create one here: "
3775
3896
  )}${linkText(`https://app.tina.io/projects/${prev || "[XXX]"}/tokens`)}`,
@@ -3891,6 +4012,7 @@ var supportedDatabaseAdapters = {
3891
4012
  {
3892
4013
  from: "mongodb",
3893
4014
  imported: [],
4015
+ // not explicitly imported
3894
4016
  packageName: "mongodb"
3895
4017
  }
3896
4018
  ]
@@ -3963,6 +4085,10 @@ var chooseDatabaseAdapter = async ({
3963
4085
  title: "MongoDB",
3964
4086
  value: "mongodb"
3965
4087
  }
4088
+ // {
4089
+ // title: "I'll create my own database adapter",
4090
+ // value: 'other',
4091
+ // },
3966
4092
  ]
3967
4093
  }
3968
4094
  ]);
@@ -3975,8 +4101,8 @@ var chooseDatabaseAdapter = async ({
3975
4101
  };
3976
4102
 
3977
4103
  // src/cmds/init/prompts/authProvider.ts
3978
- var import_prompts5 = __toESM(require("prompts"));
3979
4104
  var import_crypto_js = __toESM(require("crypto-js"));
4105
+ var import_prompts5 = __toESM(require("prompts"));
3980
4106
  var supportedAuthProviders = {
3981
4107
  other: {
3982
4108
  name: "other"
@@ -4153,7 +4279,7 @@ var askIfUsingSelfHosted = async () => {
4153
4279
  type: "select",
4154
4280
  choices: [
4155
4281
  {
4156
- title: "Tina Cloud",
4282
+ title: "TinaCloud",
4157
4283
  value: "tina-cloud"
4158
4284
  },
4159
4285
  {
@@ -4161,7 +4287,7 @@ var askIfUsingSelfHosted = async () => {
4161
4287
  value: "self-host"
4162
4288
  }
4163
4289
  ],
4164
- message: "Do you want to host your project on Tina Cloud or self-host? (With self-hosting, the graphql api, auth and database will be hosted on your own server.)"
4290
+ message: "Do you want to host your project on TinaCloud or self-host? (With self-hosting, the graphql api, auth and database will be hosted on your own server.)"
4165
4291
  }
4166
4292
  ]);
4167
4293
  return answers;
@@ -4240,6 +4366,7 @@ async function configure(env, opts) {
4240
4366
  packageManager,
4241
4367
  forestryMigrate: false,
4242
4368
  isLocalEnvVarName: "TINA_PUBLIC_IS_LOCAL",
4369
+ // TODO: give this a better default
4243
4370
  typescript: false
4244
4371
  };
4245
4372
  if (config2.framework.name === "next") {
@@ -4343,15 +4470,25 @@ var import_js_yaml = __toESM(require("js-yaml"));
4343
4470
  var import_zod = __toESM(require("zod"));
4344
4471
 
4345
4472
  // src/cmds/forestry-migrate/util/errorSingleton.ts
4346
- var ErrorSingleton = class {
4473
+ var ErrorSingleton = class _ErrorSingleton {
4474
+ /**
4475
+ * The Singleton's constructor should always be private to prevent direct
4476
+ * construction calls with the `new` operator.
4477
+ */
4347
4478
  constructor() {
4348
4479
  }
4480
+ /**
4481
+ * The static method that controls the access to the singleton instance.
4482
+ *
4483
+ * This implementation let you subclass the Singleton class while keeping
4484
+ * just one instance of each subclass around.
4485
+ */
4349
4486
  static getInstance() {
4350
- if (!ErrorSingleton.instance) {
4351
- ErrorSingleton.instance = new ErrorSingleton();
4352
- ErrorSingleton.instance.collectionNameErrors = [];
4487
+ if (!_ErrorSingleton.instance) {
4488
+ _ErrorSingleton.instance = new _ErrorSingleton();
4489
+ _ErrorSingleton.instance.collectionNameErrors = [];
4353
4490
  }
4354
- return ErrorSingleton.instance;
4491
+ return _ErrorSingleton.instance;
4355
4492
  }
4356
4493
  addErrorName(error) {
4357
4494
  this.collectionNameErrors.push(error);
@@ -4394,8 +4531,7 @@ var makeFieldsWithInternalCode = ({
4394
4531
  if (hasBody) {
4395
4532
  return [bodyField, `__TINA_INTERNAL__:::...${field}():::`];
4396
4533
  } else {
4397
- if (spread)
4398
- return `__TINA_INTERNAL__:::...${field}():::`;
4534
+ if (spread) return `__TINA_INTERNAL__:::...${field}():::`;
4399
4535
  return `__TINA_INTERNAL__:::${field}():::`;
4400
4536
  }
4401
4537
  };
@@ -4479,6 +4615,7 @@ var forestryConfigSchema = import_zod.default.object({
4479
4615
  )
4480
4616
  });
4481
4617
  var forestryFieldWithoutField = import_zod.default.object({
4618
+ // TODO: maybe better type this?
4482
4619
  type: import_zod.default.union([
4483
4620
  import_zod.default.literal("text"),
4484
4621
  import_zod.default.literal("datetime"),
@@ -4502,6 +4639,7 @@ var forestryFieldWithoutField = import_zod.default.object({
4502
4639
  default: import_zod.default.any().optional(),
4503
4640
  template: import_zod.default.string().optional(),
4504
4641
  config: import_zod.default.object({
4642
+ // min and max are used for lists
4505
4643
  min: import_zod.default.number().optional().nullable(),
4506
4644
  max: import_zod.default.number().optional().nullable(),
4507
4645
  required: import_zod.default.boolean().optional().nullable(),
@@ -4515,6 +4653,7 @@ var forestryFieldWithoutField = import_zod.default.object({
4515
4653
  import_zod.default.literal("pages"),
4516
4654
  import_zod.default.literal("documents"),
4517
4655
  import_zod.default.literal("simple"),
4656
+ // TODO: I want to ignore this key if its invalid
4518
4657
  import_zod.default.string()
4519
4658
  ]).optional().nullable(),
4520
4659
  section: import_zod.default.string().optional().nullable()
@@ -4550,6 +4689,7 @@ var transformForestryFieldsToTinaFields = ({
4550
4689
  }
4551
4690
  let field;
4552
4691
  switch (forestryField2.type) {
4692
+ // Single filed types
4553
4693
  case "text":
4554
4694
  field = {
4555
4695
  type: "string",
@@ -4629,6 +4769,7 @@ var transformForestryFieldsToTinaFields = ({
4629
4769
  );
4630
4770
  }
4631
4771
  break;
4772
+ // List Types
4632
4773
  case "list":
4633
4774
  field = {
4634
4775
  type: "string",
@@ -4651,6 +4792,7 @@ var transformForestryFieldsToTinaFields = ({
4651
4792
  }
4652
4793
  };
4653
4794
  break;
4795
+ // Object (Group) types
4654
4796
  case "field_group":
4655
4797
  field = {
4656
4798
  type: "object",
@@ -4691,6 +4833,7 @@ var transformForestryFieldsToTinaFields = ({
4691
4833
  });
4692
4834
  const fieldsString = stringifyLabelWithField(template2.label);
4693
4835
  const t = {
4836
+ // @ts-ignore
4694
4837
  fields: makeFieldsWithInternalCode({
4695
4838
  hasBody: false,
4696
4839
  field: fieldsString
@@ -4699,7 +4842,6 @@ var transformForestryFieldsToTinaFields = ({
4699
4842
  name: stringifyTemplateName(tem, tem)
4700
4843
  };
4701
4844
  if (t.name != tem) {
4702
- ;
4703
4845
  t.nameOverride = tem;
4704
4846
  }
4705
4847
  templates2.push(t);
@@ -4728,6 +4870,7 @@ var transformForestryFieldsToTinaFields = ({
4728
4870
  spread: true
4729
4871
  });
4730
4872
  tinaFields.push(
4873
+ // @ts-ignore
4731
4874
  field2
4732
4875
  );
4733
4876
  break;
@@ -4787,6 +4930,7 @@ var parseSections = ({ val }) => {
4787
4930
 
4788
4931
  // src/cmds/forestry-migrate/index.ts
4789
4932
  var BODY_FIELD = {
4933
+ // This is the body field
4790
4934
  type: "rich-text",
4791
4935
  name: "body",
4792
4936
  label: "Body of Document",
@@ -4845,8 +4989,7 @@ var generateAllTemplates = async ({
4845
4989
  };
4846
4990
  var generateCollectionFromForestrySection = (args) => {
4847
4991
  const { section, templateMap } = args;
4848
- if (section.read_only)
4849
- return;
4992
+ if (section.read_only) return;
4850
4993
  let format3 = "md";
4851
4994
  if (section.new_doc_ext) {
4852
4995
  const ext = checkExt(section.new_doc_ext);
@@ -4913,12 +5056,14 @@ var generateCollectionFromForestrySection = (args) => {
4913
5056
  if (((forestryTemplates == null ? void 0 : forestryTemplates.length) || 0) > 1) {
4914
5057
  c = {
4915
5058
  ...baseCollection,
5059
+ // @ts-expect-error
4916
5060
  templates: forestryTemplates.map((tem) => {
4917
5061
  const currentTemplate = templateMap.get(tem);
4918
5062
  const fieldsString = stringifyLabelWithField(
4919
5063
  currentTemplate.templateObj.label
4920
5064
  );
4921
5065
  return {
5066
+ // fields: [BODY_FIELD],
4922
5067
  fields: makeFieldsWithInternalCode({
4923
5068
  hasBody,
4924
5069
  field: fieldsString,
@@ -4936,6 +5081,8 @@ var generateCollectionFromForestrySection = (args) => {
4936
5081
  const fieldsString = stringifyLabelWithField(template.templateObj.label);
4937
5082
  c = {
4938
5083
  ...baseCollection,
5084
+ // fields: [BODY_FIELD],
5085
+ // @ts-expect-error
4939
5086
  fields: makeFieldsWithInternalCode({
4940
5087
  field: fieldsString,
4941
5088
  hasBody,
@@ -5683,6 +5830,7 @@ var makeImportsVisitor = (sourceFile, importMap) => (ctx) => (node) => {
5683
5830
  ) : [];
5684
5831
  const newImports = [
5685
5832
  .../* @__PURE__ */ new Set([
5833
+ // we use Set to remove duplicates
5686
5834
  ...existingImports,
5687
5835
  ...imports
5688
5836
  ])
@@ -5837,10 +5985,14 @@ var addSelfHostedTinaAuthToConfig = async (config2, configFile) => {
5837
5985
  );
5838
5986
  const { configImports, configAuthProviderClass, extraTinaCollections } = config2.authProvider;
5839
5987
  const importMap = {
5840
- ...configImports.reduce((acc, { from, imported }) => {
5841
- acc[from] = imported;
5842
- return acc;
5843
- }, {})
5988
+ // iterate over configImports and add them to the import map
5989
+ ...configImports.reduce(
5990
+ (acc, { from, imported }) => {
5991
+ acc[from] = imported;
5992
+ return acc;
5993
+ },
5994
+ {}
5995
+ )
5844
5996
  };
5845
5997
  const transformedSourceFileResult = import_typescript3.default.transform(
5846
5998
  sourceFile,
@@ -6011,7 +6163,13 @@ async function apply({
6011
6163
  config: config2
6012
6164
  });
6013
6165
  }
6014
- if (env.tinaConfigExists && params.isBackendInit && config2.hosting === "self-host" && (((_a = config2.authProvider) == null ? void 0 : _a.name) || "") !== "tina-cloud") {
6166
+ if (
6167
+ // if the config was just generated we do not need to update the config file because it will be generated correctly
6168
+ env.tinaConfigExists && // Are we running tinacms init backend
6169
+ params.isBackendInit && // Do the user choose the 'self-host' option
6170
+ config2.hosting === "self-host" && // the user did not choose the 'tina-cloud' auth provider
6171
+ (((_a = config2.authProvider) == null ? void 0 : _a.name) || "") !== "tina-cloud"
6172
+ ) {
6015
6173
  await addSelfHostedTinaAuthToConfig(config2, env.generatedFiles["config"]);
6016
6174
  }
6017
6175
  logNextSteps({
@@ -6289,6 +6447,13 @@ ${titleText(" TinaCMS ")} has been initialized!`));
6289
6447
  logger.info(
6290
6448
  "To get started run: " + cmdText(frameworkDevCmds[framework.name]({ packageManager }))
6291
6449
  );
6450
+ if (framework.name === "hugo") {
6451
+ logger.info(
6452
+ focusText("Hugo is required. "),
6453
+ "Don't have Hugo installed? Follow this guide to set it up: ",
6454
+ linkText("https://gohugo.io/installation/")
6455
+ );
6456
+ }
6292
6457
  logger.info(
6293
6458
  "To get your site production ready, run: " + cmdText(`tinacms init backend`)
6294
6459
  );
@@ -6304,6 +6469,7 @@ var other = ({ packageManager }) => {
6304
6469
  const packageManagers = {
6305
6470
  pnpm: `pnpm`,
6306
6471
  npm: `npx`,
6472
+ // npx is the way to run executables that aren't in your "scripts"
6307
6473
  yarn: `yarn`
6308
6474
  };
6309
6475
  return `${packageManagers[packageManager]} tinacms dev -c "<your dev command>"`;
@@ -6316,6 +6482,7 @@ var frameworkDevCmds = {
6316
6482
  const packageManagers = {
6317
6483
  pnpm: `pnpm`,
6318
6484
  npm: `npm run`,
6485
+ // npx is the way to run executables that aren't in your "scripts"
6319
6486
  yarn: `yarn`
6320
6487
  };
6321
6488
  return `${packageManagers[packageManager]} dev`;
@@ -6572,6 +6739,4 @@ cli.register(SearchIndexCommand);
6572
6739
  cli.register(import_clipanion8.Builtins.DefinitionsCommand);
6573
6740
  cli.register(import_clipanion8.Builtins.HelpCommand);
6574
6741
  cli.register(import_clipanion8.Builtins.VersionCommand);
6575
- var src_default = cli;
6576
- // Annotate the CommonJS export names for ESM import in node:
6577
- 0 && (module.exports = {});
6742
+ var index_default = cli;