@tinacms/cli 2.5.5 → 2.6.0
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/bin/tinacms +3 -3
- package/dist/cmds/forestry-migrate/util/index.d.ts +14 -14
- package/dist/index.js +1152 -676
- package/dist/next/codegen/index.d.ts +2 -2
- package/dist/next/commands/baseCommands.d.ts +1 -0
- package/dist/next/commands/dev-command/html.d.ts +1 -1
- package/dist/next/commands/dev-command/index.d.ts +1 -1
- package/dist/next/commands/dev-command/server/media.d.ts +26 -0
- package/dist/next/config-build-error.d.ts +4 -0
- package/dist/next/config-manager.d.ts +1 -1
- package/dist/next/version-coherence.d.ts +62 -0
- package/dist/next/vite/index.d.ts +9 -1
- package/dist/next/vite/plugins.d.ts +2 -2
- package/dist/utils/index.d.ts +2 -2
- package/package.json +20 -18
package/dist/index.js
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
import { Cli, Builtins } from "clipanion";
|
|
3
3
|
|
|
4
4
|
// package.json
|
|
5
|
-
var version = "2.
|
|
5
|
+
var version = "2.6.0";
|
|
6
6
|
|
|
7
7
|
// src/next/commands/dev-command/index.ts
|
|
8
|
-
import
|
|
8
|
+
import path12 from "path";
|
|
9
9
|
import { FilesystemBridge as FilesystemBridge2, buildSchema } from "@tinacms/graphql";
|
|
10
10
|
import { Telemetry } from "@tinacms/metrics";
|
|
11
11
|
import { LocalSearchIndexClient, SearchIndexer } from "@tinacms/search";
|
|
12
|
-
import AsyncLock from "async-lock";
|
|
13
12
|
import chokidar from "chokidar";
|
|
14
13
|
import { Command as Command2, Option as Option2 } from "clipanion";
|
|
15
|
-
import
|
|
14
|
+
import fs10 from "fs-extra";
|
|
15
|
+
import { AsyncLock } from "tinacms/dist/client";
|
|
16
16
|
|
|
17
17
|
// src/logger/index.ts
|
|
18
18
|
import chalk from "chalk";
|
|
@@ -191,9 +191,12 @@ var titleText = chalk2.bgHex("d2f1f8").hex("ec4816");
|
|
|
191
191
|
var CONFIRMATION_TEXT = chalk2.dim("enter to confirm");
|
|
192
192
|
|
|
193
193
|
// src/next/codegen/index.ts
|
|
194
|
-
import fs from "fs-extra";
|
|
195
194
|
import path from "path";
|
|
195
|
+
import { mapUserFields } from "@tinacms/graphql";
|
|
196
|
+
import { transform } from "esbuild";
|
|
197
|
+
import fs from "fs-extra";
|
|
196
198
|
import { buildASTSchema, printSchema as printSchema2 } from "graphql";
|
|
199
|
+
import normalizePath from "normalize-path";
|
|
197
200
|
|
|
198
201
|
// src/next/codegen/codegen/index.ts
|
|
199
202
|
import { parse, printSchema } from "graphql";
|
|
@@ -369,6 +372,9 @@ var plugin = (schema, documents, config2) => {
|
|
|
369
372
|
};
|
|
370
373
|
|
|
371
374
|
// src/next/codegen/codegen/index.ts
|
|
375
|
+
var reexportExact = (types) => `${types}
|
|
376
|
+
export type { Exact };
|
|
377
|
+
`;
|
|
372
378
|
var generateTypes = async (schema, queryPathGlob = process.cwd(), fragDocPath = process.cwd(), apiURL) => {
|
|
373
379
|
let docs = [];
|
|
374
380
|
let fragDocs = [];
|
|
@@ -379,7 +385,11 @@ var generateTypes = async (schema, queryPathGlob = process.cwd(), fragDocPath =
|
|
|
379
385
|
filename: process.cwd(),
|
|
380
386
|
schema: parse(printSchema(schema)),
|
|
381
387
|
documents: [...docs, ...fragDocs],
|
|
382
|
-
config: {
|
|
388
|
+
config: {
|
|
389
|
+
// The JSON scalar still carries rich-text bodies, which callers pass
|
|
390
|
+
// straight to <TinaMarkdown/>; codegen's `unknown` default won't assign.
|
|
391
|
+
defaultScalarType: "any"
|
|
392
|
+
},
|
|
383
393
|
plugins: [
|
|
384
394
|
{ typescript: {} },
|
|
385
395
|
{ typescriptOperations: {} },
|
|
@@ -401,7 +411,7 @@ var generateTypes = async (schema, queryPathGlob = process.cwd(), fragDocPath =
|
|
|
401
411
|
AddGeneratedClient: AddGeneratedClient(apiURL)
|
|
402
412
|
}
|
|
403
413
|
});
|
|
404
|
-
return res;
|
|
414
|
+
return reexportExact(res);
|
|
405
415
|
};
|
|
406
416
|
var loadGraphQLDocuments = async (globPath) => {
|
|
407
417
|
let result = [];
|
|
@@ -423,11 +433,6 @@ var loadGraphQLDocuments = async (globPath) => {
|
|
|
423
433
|
return result;
|
|
424
434
|
};
|
|
425
435
|
|
|
426
|
-
// src/next/codegen/index.ts
|
|
427
|
-
import { transform } from "esbuild";
|
|
428
|
-
import { mapUserFields } from "@tinacms/graphql";
|
|
429
|
-
import normalizePath from "normalize-path";
|
|
430
|
-
|
|
431
436
|
// src/next/codegen/stripSearchTokenFromConfig.ts
|
|
432
437
|
function stripSearchTokenFromConfig(config2) {
|
|
433
438
|
const cfg = config2;
|
|
@@ -816,26 +821,165 @@ var unlinkIfExists = async (filepath) => {
|
|
|
816
821
|
};
|
|
817
822
|
|
|
818
823
|
// src/next/config-manager.ts
|
|
819
|
-
import
|
|
824
|
+
import { createRequire } from "module";
|
|
820
825
|
import path5 from "path";
|
|
821
826
|
import { pathToFileURL } from "url";
|
|
822
|
-
import * as esbuild from "esbuild";
|
|
823
827
|
import * as dotenv from "dotenv";
|
|
828
|
+
import * as esbuild from "esbuild";
|
|
829
|
+
import fs4 from "fs-extra";
|
|
824
830
|
import normalizePath2 from "normalize-path";
|
|
825
|
-
import { createRequire } from "module";
|
|
826
831
|
|
|
827
|
-
// src/next/
|
|
832
|
+
// src/next/build-database-esbuild-config.ts
|
|
833
|
+
var buildDatabaseEsbuildConfig = (opts) => ({
|
|
834
|
+
entryPoints: [opts.entryPoint],
|
|
835
|
+
bundle: true,
|
|
836
|
+
platform: "node",
|
|
837
|
+
format: "esm",
|
|
838
|
+
outfile: opts.outfile,
|
|
839
|
+
loader: opts.loader,
|
|
840
|
+
external: opts.external,
|
|
841
|
+
// Provide a require() polyfill for ESM bundles containing CommonJS packages.
|
|
842
|
+
// Some bundled packages (e.g., 'scmp' used by 'mongodb-level') use
|
|
843
|
+
// require('crypto'). When esbuild inlines these CommonJS packages, it keeps
|
|
844
|
+
// the require() calls, but ESM doesn't have a global require. This banner
|
|
845
|
+
// creates one using Node.js's official createRequire API, allowing the
|
|
846
|
+
// bundled CommonJS code to work in ESM.
|
|
847
|
+
banner: {
|
|
848
|
+
js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
// src/next/cache-manager.ts
|
|
828
853
|
import fs2 from "fs-extra";
|
|
829
|
-
import
|
|
854
|
+
import path2 from "path";
|
|
855
|
+
var buildReadOnlyMountErrorMessage = (cacheParentPath, underlyingError) => `TinaCMS cannot write to ${cacheParentPath}.
|
|
856
|
+
|
|
857
|
+
Tina v3 needs write access to your project's tina/__generated__/.cache/ directory at build time. This usually means your project directory is read-only \u2014 common in some Docker setups (\`:ro\` volumes), AWS Lambda's \`/var/task\`, sandboxed CI runners, or restricted file permissions.
|
|
858
|
+
|
|
859
|
+
To resolve, either:
|
|
860
|
+
- Make the project directory writable (e.g. remount with read-write access, or copy the project to a writable location), or
|
|
861
|
+
- Run \`tinacms build\` against a writable copy of your project and deploy the resulting artifacts.
|
|
862
|
+
|
|
863
|
+
Underlying error: ${underlyingError.code} ${underlyingError.message}`;
|
|
864
|
+
var READONLY_ERROR_CODES = /* @__PURE__ */ new Set(["EACCES", "EROFS", "EPERM"]);
|
|
865
|
+
var prepareCacheLocation = async (generatedFolderPath, now = Date.now()) => {
|
|
866
|
+
const parentPath = path2.join(generatedFolderPath, ".cache");
|
|
867
|
+
try {
|
|
868
|
+
if (await fs2.pathExists(parentPath)) {
|
|
869
|
+
await fs2.remove(parentPath);
|
|
870
|
+
}
|
|
871
|
+
await fs2.ensureDir(parentPath);
|
|
872
|
+
} catch (err) {
|
|
873
|
+
const code = err?.code;
|
|
874
|
+
if (code && READONLY_ERROR_CODES.has(code)) {
|
|
875
|
+
throw new Error(
|
|
876
|
+
buildReadOnlyMountErrorMessage(parentPath, err)
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
throw err;
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
parentPath,
|
|
883
|
+
buildPath: path2.join(parentPath, String(now))
|
|
884
|
+
};
|
|
885
|
+
};
|
|
886
|
+
var reapBuildSubdir = (buildSubdirPath, buildParentPath) => {
|
|
887
|
+
fs2.removeSync(buildSubdirPath);
|
|
888
|
+
try {
|
|
889
|
+
fs2.rmdirSync(buildParentPath);
|
|
890
|
+
} catch (err) {
|
|
891
|
+
if (err?.code !== "ENOTEMPTY") throw err;
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
|
|
895
|
+
// src/next/config-build-error.ts
|
|
896
|
+
var isObject = (value) => typeof value === "object" && value !== null;
|
|
897
|
+
var isTinaPackage = (specifier) => specifier === "tinacms" || specifier.startsWith("@tinacms/");
|
|
898
|
+
var collectResolveTargets = (text) => {
|
|
899
|
+
if (!text) {
|
|
900
|
+
return [];
|
|
901
|
+
}
|
|
902
|
+
const targets = [];
|
|
903
|
+
const pattern = /Could not resolve "([^"]+)"/g;
|
|
904
|
+
for (const match of text.matchAll(pattern)) {
|
|
905
|
+
targets.push(match[1]);
|
|
906
|
+
}
|
|
907
|
+
return targets;
|
|
908
|
+
};
|
|
909
|
+
var getUnresolvedTinaPackage = (error) => {
|
|
910
|
+
if (!isObject(error)) {
|
|
911
|
+
return null;
|
|
912
|
+
}
|
|
913
|
+
const esbuildError = error;
|
|
914
|
+
const targets = [
|
|
915
|
+
...(esbuildError.errors ?? []).flatMap(
|
|
916
|
+
(item) => collectResolveTargets(item.text)
|
|
917
|
+
),
|
|
918
|
+
...collectResolveTargets(esbuildError.message)
|
|
919
|
+
];
|
|
920
|
+
return targets.find(isTinaPackage) ?? null;
|
|
921
|
+
};
|
|
922
|
+
var getResolveLocation = (error) => {
|
|
923
|
+
if (!isObject(error)) {
|
|
924
|
+
return null;
|
|
925
|
+
}
|
|
926
|
+
const esbuildError = error;
|
|
927
|
+
const entry = (esbuildError.errors ?? []).find(
|
|
928
|
+
(item) => collectResolveTargets(item.text).some(isTinaPackage)
|
|
929
|
+
);
|
|
930
|
+
return entry?.location ?? null;
|
|
931
|
+
};
|
|
932
|
+
var formatConfigBuildError = ({
|
|
933
|
+
error,
|
|
934
|
+
rootPath
|
|
935
|
+
}) => {
|
|
936
|
+
const unresolvedPackage = getUnresolvedTinaPackage(error);
|
|
937
|
+
if (!unresolvedPackage) {
|
|
938
|
+
return error;
|
|
939
|
+
}
|
|
940
|
+
const lines = [
|
|
941
|
+
`Unable to resolve the "${unresolvedPackage}" package while building your Tina config.`,
|
|
942
|
+
"",
|
|
943
|
+
`Tina looked from: ${rootPath}`
|
|
944
|
+
];
|
|
945
|
+
const location = getResolveLocation(error);
|
|
946
|
+
if (location?.file) {
|
|
947
|
+
const position = [location.line, location.column].filter((value) => typeof value === "number").join(":");
|
|
948
|
+
lines.push(
|
|
949
|
+
"",
|
|
950
|
+
`Failing import: ${location.file}${position ? `:${position}` : ""}`
|
|
951
|
+
);
|
|
952
|
+
if (location.lineText) {
|
|
953
|
+
lines.push(` ${location.lineText.trim()}`);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
lines.push(
|
|
957
|
+
"",
|
|
958
|
+
"Make sure the TinaCMS packages are installed in this project and that you are running the CLI from the project root.",
|
|
959
|
+
"If they are installed, check parent directories for package-manager files that can interfere with module resolution, such as package.json, node_modules, yarn.lock, or .pnp.cjs."
|
|
960
|
+
);
|
|
961
|
+
return new Error(lines.join("\n"));
|
|
962
|
+
};
|
|
963
|
+
|
|
964
|
+
// src/next/external-resolver.ts
|
|
965
|
+
var EXTERNAL_BASELINE = ["better-sqlite3"];
|
|
966
|
+
var resolveDatabaseExternals = (config2) => {
|
|
967
|
+
const userExternals = config2?.build?.externalDependencies ?? [];
|
|
968
|
+
return [...EXTERNAL_BASELINE, ...userExternals];
|
|
969
|
+
};
|
|
970
|
+
|
|
971
|
+
// src/next/resolve-content-root.ts
|
|
972
|
+
import fs3 from "fs-extra";
|
|
973
|
+
import path4 from "path";
|
|
830
974
|
import chalk3 from "chalk";
|
|
831
975
|
import { z } from "zod";
|
|
832
976
|
|
|
833
977
|
// src/utils/path.ts
|
|
834
|
-
import
|
|
978
|
+
import path3 from "path";
|
|
835
979
|
function stripNativeTrailingSlash(p) {
|
|
836
|
-
const { root } =
|
|
980
|
+
const { root } = path3.parse(p);
|
|
837
981
|
let str = p;
|
|
838
|
-
while (str.length > root.length && str.endsWith(
|
|
982
|
+
while (str.length > root.length && str.endsWith(path3.sep)) {
|
|
839
983
|
str = str.slice(0, -1);
|
|
840
984
|
}
|
|
841
985
|
return str;
|
|
@@ -859,9 +1003,9 @@ async function resolveContentRootPath(params) {
|
|
|
859
1003
|
return params.rootPath;
|
|
860
1004
|
}
|
|
861
1005
|
const fullLocalContentPath = stripNativeTrailingSlash(
|
|
862
|
-
|
|
1006
|
+
path4.join(params.tinaFolderPath, localContentPath)
|
|
863
1007
|
);
|
|
864
|
-
const exists = await
|
|
1008
|
+
const exists = await fs3.pathExists(fullLocalContentPath);
|
|
865
1009
|
if (exists) {
|
|
866
1010
|
logger.info(`Using separate content repo at ${fullLocalContentPath}`);
|
|
867
1011
|
return fullLocalContentPath;
|
|
@@ -876,76 +1020,6 @@ async function resolveContentRootPath(params) {
|
|
|
876
1020
|
return params.rootPath;
|
|
877
1021
|
}
|
|
878
1022
|
|
|
879
|
-
// src/next/external-resolver.ts
|
|
880
|
-
var EXTERNAL_BASELINE = ["better-sqlite3"];
|
|
881
|
-
var resolveDatabaseExternals = (config2) => {
|
|
882
|
-
const userExternals = config2?.build?.externalDependencies ?? [];
|
|
883
|
-
return [...EXTERNAL_BASELINE, ...userExternals];
|
|
884
|
-
};
|
|
885
|
-
|
|
886
|
-
// src/next/cache-manager.ts
|
|
887
|
-
import fs3 from "fs-extra";
|
|
888
|
-
import path4 from "path";
|
|
889
|
-
var buildReadOnlyMountErrorMessage = (cacheParentPath, underlyingError) => `TinaCMS cannot write to ${cacheParentPath}.
|
|
890
|
-
|
|
891
|
-
Tina v3 needs write access to your project's tina/__generated__/.cache/ directory at build time. This usually means your project directory is read-only \u2014 common in some Docker setups (\`:ro\` volumes), AWS Lambda's \`/var/task\`, sandboxed CI runners, or restricted file permissions.
|
|
892
|
-
|
|
893
|
-
To resolve, either:
|
|
894
|
-
- Make the project directory writable (e.g. remount with read-write access, or copy the project to a writable location), or
|
|
895
|
-
- Run \`tinacms build\` against a writable copy of your project and deploy the resulting artifacts.
|
|
896
|
-
|
|
897
|
-
Underlying error: ${underlyingError.code} ${underlyingError.message}`;
|
|
898
|
-
var READONLY_ERROR_CODES = /* @__PURE__ */ new Set(["EACCES", "EROFS", "EPERM"]);
|
|
899
|
-
var prepareCacheLocation = async (generatedFolderPath, now = Date.now()) => {
|
|
900
|
-
const parentPath = path4.join(generatedFolderPath, ".cache");
|
|
901
|
-
try {
|
|
902
|
-
if (await fs3.pathExists(parentPath)) {
|
|
903
|
-
await fs3.remove(parentPath);
|
|
904
|
-
}
|
|
905
|
-
await fs3.ensureDir(parentPath);
|
|
906
|
-
} catch (err) {
|
|
907
|
-
const code = err?.code;
|
|
908
|
-
if (code && READONLY_ERROR_CODES.has(code)) {
|
|
909
|
-
throw new Error(
|
|
910
|
-
buildReadOnlyMountErrorMessage(parentPath, err)
|
|
911
|
-
);
|
|
912
|
-
}
|
|
913
|
-
throw err;
|
|
914
|
-
}
|
|
915
|
-
return {
|
|
916
|
-
parentPath,
|
|
917
|
-
buildPath: path4.join(parentPath, String(now))
|
|
918
|
-
};
|
|
919
|
-
};
|
|
920
|
-
var reapBuildSubdir = (buildSubdirPath, buildParentPath) => {
|
|
921
|
-
fs3.removeSync(buildSubdirPath);
|
|
922
|
-
try {
|
|
923
|
-
fs3.rmdirSync(buildParentPath);
|
|
924
|
-
} catch (err) {
|
|
925
|
-
if (err?.code !== "ENOTEMPTY") throw err;
|
|
926
|
-
}
|
|
927
|
-
};
|
|
928
|
-
|
|
929
|
-
// src/next/build-database-esbuild-config.ts
|
|
930
|
-
var buildDatabaseEsbuildConfig = (opts) => ({
|
|
931
|
-
entryPoints: [opts.entryPoint],
|
|
932
|
-
bundle: true,
|
|
933
|
-
platform: "node",
|
|
934
|
-
format: "esm",
|
|
935
|
-
outfile: opts.outfile,
|
|
936
|
-
loader: opts.loader,
|
|
937
|
-
external: opts.external,
|
|
938
|
-
// Provide a require() polyfill for ESM bundles containing CommonJS packages.
|
|
939
|
-
// Some bundled packages (e.g., 'scmp' used by 'mongodb-level') use
|
|
940
|
-
// require('crypto'). When esbuild inlines these CommonJS packages, it keeps
|
|
941
|
-
// the require() calls, but ESM doesn't have a global require. This banner
|
|
942
|
-
// creates one using Node.js's official createRequire API, allowing the
|
|
943
|
-
// bundled CommonJS code to work in ESM.
|
|
944
|
-
banner: {
|
|
945
|
-
js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
|
|
946
|
-
}
|
|
947
|
-
});
|
|
948
|
-
|
|
949
1023
|
// src/next/config-manager.ts
|
|
950
1024
|
var TINA_FOLDER = "tina";
|
|
951
1025
|
var LEGACY_TINA_FOLDER = ".tina";
|
|
@@ -1250,14 +1324,21 @@ var ConfigManager = class {
|
|
|
1250
1324
|
const buildDir = path5.join(this.generatedCachePath, "database");
|
|
1251
1325
|
const outfile = path5.join(buildDir, "database.build.mjs");
|
|
1252
1326
|
const external = resolveDatabaseExternals(this.config);
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1327
|
+
try {
|
|
1328
|
+
await esbuild.build(
|
|
1329
|
+
buildDatabaseEsbuildConfig({
|
|
1330
|
+
entryPoint: this.selfHostedDatabaseFilePath,
|
|
1331
|
+
outfile,
|
|
1332
|
+
external,
|
|
1333
|
+
loader: loaders
|
|
1334
|
+
})
|
|
1335
|
+
);
|
|
1336
|
+
} catch (e) {
|
|
1337
|
+
throw formatConfigBuildError({
|
|
1338
|
+
error: e,
|
|
1339
|
+
rootPath: path5.resolve(this.rootPath)
|
|
1340
|
+
});
|
|
1341
|
+
}
|
|
1261
1342
|
const result = await import(pathToFileURL(outfile).href);
|
|
1262
1343
|
reapBuildSubdir(buildDir, this.generatedCachePath);
|
|
1263
1344
|
return result.default;
|
|
@@ -1274,20 +1355,26 @@ var ConfigManager = class {
|
|
|
1274
1355
|
const esmRequireBanner = {
|
|
1275
1356
|
js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
|
|
1276
1357
|
};
|
|
1358
|
+
const resolvedRootPath = path5.resolve(this.rootPath);
|
|
1277
1359
|
fs4.outputFileSync(tempTSConfigFile, "{}");
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1360
|
+
let result2;
|
|
1361
|
+
try {
|
|
1362
|
+
result2 = await esbuild.build({
|
|
1363
|
+
entryPoints: [configFilePath],
|
|
1364
|
+
bundle: true,
|
|
1365
|
+
target: ["esnext"],
|
|
1366
|
+
platform: "browser",
|
|
1367
|
+
format: "esm",
|
|
1368
|
+
logLevel: "silent",
|
|
1369
|
+
packages: "external",
|
|
1370
|
+
ignoreAnnotations: true,
|
|
1371
|
+
outfile: preBuildConfigPath,
|
|
1372
|
+
loader: loaders,
|
|
1373
|
+
metafile: true
|
|
1374
|
+
});
|
|
1375
|
+
} catch (e) {
|
|
1376
|
+
throw formatConfigBuildError({ error: e, rootPath: resolvedRootPath });
|
|
1377
|
+
}
|
|
1291
1378
|
const flattenedList = [];
|
|
1292
1379
|
Object.keys(result2.metafile.inputs).forEach((key) => {
|
|
1293
1380
|
if (key.includes("node_modules") || key.includes("__generated__")) {
|
|
@@ -1295,27 +1382,31 @@ var ConfigManager = class {
|
|
|
1295
1382
|
}
|
|
1296
1383
|
flattenedList.push(key);
|
|
1297
1384
|
});
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1385
|
+
try {
|
|
1386
|
+
await esbuild.build({
|
|
1387
|
+
entryPoints: [configFilePath],
|
|
1388
|
+
bundle: true,
|
|
1389
|
+
target: ["esnext"],
|
|
1390
|
+
logLevel: "silent",
|
|
1391
|
+
platform: "node",
|
|
1392
|
+
format: "esm",
|
|
1393
|
+
outfile,
|
|
1394
|
+
loader: loaders,
|
|
1395
|
+
banner: esmRequireBanner
|
|
1396
|
+
});
|
|
1397
|
+
await esbuild.build({
|
|
1398
|
+
entryPoints: [outfile],
|
|
1399
|
+
bundle: true,
|
|
1400
|
+
logLevel: "silent",
|
|
1401
|
+
platform: "node",
|
|
1402
|
+
target: ["esnext"],
|
|
1403
|
+
format: "esm",
|
|
1404
|
+
outfile: outfile2,
|
|
1405
|
+
loader: loaders
|
|
1406
|
+
});
|
|
1407
|
+
} catch (e) {
|
|
1408
|
+
throw formatConfigBuildError({ error: e, rootPath: resolvedRootPath });
|
|
1409
|
+
}
|
|
1319
1410
|
let result;
|
|
1320
1411
|
try {
|
|
1321
1412
|
result = await import(pathToFileURL(outfile2).href);
|
|
@@ -1414,294 +1505,23 @@ async function createAndInitializeDatabase(configManager, datalayerPort, bridgeO
|
|
|
1414
1505
|
return database;
|
|
1415
1506
|
}
|
|
1416
1507
|
|
|
1417
|
-
// src/next/
|
|
1418
|
-
import
|
|
1419
|
-
import
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
import childProcess from "child_process";
|
|
1423
|
-
var startSubprocess2 = async ({ command: command2 }) => {
|
|
1424
|
-
if (typeof command2 === "string") {
|
|
1425
|
-
const commands = command2.split(" ");
|
|
1426
|
-
const firstCommand = commands[0];
|
|
1427
|
-
const args = commands.slice(1) || [];
|
|
1428
|
-
const ps = childProcess.spawn(firstCommand, args, {
|
|
1429
|
-
stdio: "inherit",
|
|
1430
|
-
shell: true
|
|
1431
|
-
});
|
|
1432
|
-
ps.on("error", (code) => {
|
|
1433
|
-
logger.error(
|
|
1434
|
-
dangerText(
|
|
1435
|
-
`An error has occurred in the Next.js child process. Error message below`
|
|
1436
|
-
)
|
|
1437
|
-
);
|
|
1438
|
-
logger.error(`name: ${code.name}
|
|
1439
|
-
message: ${code.message}
|
|
1508
|
+
// src/next/vite/index.ts
|
|
1509
|
+
import path7 from "node:path";
|
|
1510
|
+
import react from "@vitejs/plugin-react";
|
|
1511
|
+
import fs5 from "fs-extra";
|
|
1512
|
+
import normalizePath3 from "normalize-path";
|
|
1440
1513
|
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
import { getChangedFiles, getSha, shaExists } from "@tinacms/graphql";
|
|
1453
|
-
import fs5 from "fs-extra";
|
|
1454
|
-
var BaseCommand = class extends Command {
|
|
1455
|
-
experimentalDataLayer = Option.Boolean("--experimentalData", {
|
|
1456
|
-
description: "DEPRECATED - Build the server with additional data querying capabilities"
|
|
1457
|
-
});
|
|
1458
|
-
isomorphicGitBridge = Option.Boolean("--isomorphicGitBridge", {
|
|
1459
|
-
description: "DEPRECATED - Enable Isomorphic Git Bridge Implementation"
|
|
1460
|
-
});
|
|
1461
|
-
port = Option.String("-p,--port", "4001", {
|
|
1462
|
-
description: "Specify a port to run the server on. (default 4001)"
|
|
1463
|
-
});
|
|
1464
|
-
datalayerPort = Option.String("--datalayer-port", "9000", {
|
|
1465
|
-
description: "Specify a port to run the datalayer server on. (default 9000)"
|
|
1466
|
-
});
|
|
1467
|
-
subCommand = Option.String("-c,--command", {
|
|
1468
|
-
description: "The sub-command to run"
|
|
1469
|
-
});
|
|
1470
|
-
rootPath = Option.String("--rootPath", {
|
|
1471
|
-
description: "Specify the root directory to run the CLI from (defaults to current working directory)"
|
|
1472
|
-
});
|
|
1473
|
-
verbose = Option.Boolean("-v,--verbose", false, {
|
|
1474
|
-
description: "increase verbosity of logged output"
|
|
1475
|
-
});
|
|
1476
|
-
noSDK = Option.Boolean("--noSDK", false, {
|
|
1477
|
-
description: "DEPRECATED - This should now be set in the config at client.skip = true'. Don't generate the generated client SDK"
|
|
1478
|
-
});
|
|
1479
|
-
noTelemetry = Option.Boolean("--noTelemetry", false, {
|
|
1480
|
-
description: "Disable anonymous telemetry that is collected"
|
|
1481
|
-
});
|
|
1482
|
-
async startSubCommand() {
|
|
1483
|
-
let subProc;
|
|
1484
|
-
if (this.subCommand) {
|
|
1485
|
-
subProc = await startSubprocess2({ command: this.subCommand });
|
|
1486
|
-
logger.info(
|
|
1487
|
-
`Running web application with command: ${chalk4.cyan(this.subCommand)}`
|
|
1488
|
-
);
|
|
1489
|
-
}
|
|
1490
|
-
function exitHandler(options, exitCode) {
|
|
1491
|
-
if (subProc) {
|
|
1492
|
-
subProc.kill();
|
|
1493
|
-
}
|
|
1494
|
-
process.exit();
|
|
1495
|
-
}
|
|
1496
|
-
process.on("exit", exitHandler);
|
|
1497
|
-
process.on("SIGINT", exitHandler);
|
|
1498
|
-
process.on("SIGUSR1", exitHandler);
|
|
1499
|
-
process.on("SIGUSR2", exitHandler);
|
|
1500
|
-
process.on("uncaughtException", (error) => {
|
|
1501
|
-
logger.error(`Uncaught exception ${error.name}`);
|
|
1502
|
-
console.error(error);
|
|
1503
|
-
});
|
|
1504
|
-
}
|
|
1505
|
-
logDeprecationWarnings() {
|
|
1506
|
-
if (this.isomorphicGitBridge) {
|
|
1507
|
-
logger.warn("--isomorphicGitBridge has been deprecated");
|
|
1508
|
-
}
|
|
1509
|
-
if (this.experimentalDataLayer) {
|
|
1510
|
-
logger.warn(
|
|
1511
|
-
"--experimentalDataLayer has been deprecated, the data layer is now built-in automatically"
|
|
1512
|
-
);
|
|
1513
|
-
}
|
|
1514
|
-
if (this.noSDK) {
|
|
1515
|
-
logger.warn(
|
|
1516
|
-
"--noSDK has been deprecated, and will be unsupported in a future release. This should be set in the config at client.skip = true"
|
|
1517
|
-
);
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
async indexContentWithSpinner({
|
|
1521
|
-
database,
|
|
1522
|
-
graphQLSchema,
|
|
1523
|
-
tinaSchema,
|
|
1524
|
-
configManager,
|
|
1525
|
-
partialReindex,
|
|
1526
|
-
text
|
|
1527
|
-
}) {
|
|
1528
|
-
const textToUse = text || "Indexing local files";
|
|
1529
|
-
const warnings = [];
|
|
1530
|
-
await spin({
|
|
1531
|
-
waitFor: async () => {
|
|
1532
|
-
const rootPath = configManager.rootPath;
|
|
1533
|
-
let sha;
|
|
1534
|
-
try {
|
|
1535
|
-
sha = await getSha({ fs: fs5, dir: rootPath });
|
|
1536
|
-
} catch (e) {
|
|
1537
|
-
if (partialReindex) {
|
|
1538
|
-
console.error(
|
|
1539
|
-
"Failed to get sha. NOTE: `--partial-reindex` only supported for git repositories"
|
|
1540
|
-
);
|
|
1541
|
-
throw e;
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
const lastSha = await database.getMetadata("lastSha");
|
|
1545
|
-
const exists = lastSha && await shaExists({ fs: fs5, dir: rootPath, sha: lastSha });
|
|
1546
|
-
let res;
|
|
1547
|
-
if (partialReindex && lastSha && exists && sha) {
|
|
1548
|
-
const pathFilter = {};
|
|
1549
|
-
if (configManager.isUsingLegacyFolder) {
|
|
1550
|
-
pathFilter[".tina/__generated__/_schema.json"] = {};
|
|
1551
|
-
} else {
|
|
1552
|
-
pathFilter["tina/tina-lock.json"] = {};
|
|
1553
|
-
}
|
|
1554
|
-
for (const collection of tinaSchema.getCollections()) {
|
|
1555
|
-
pathFilter[collection.path] = {
|
|
1556
|
-
matches: collection.match?.exclude || collection.match?.include ? tinaSchema.getMatches({ collection }) : void 0
|
|
1557
|
-
};
|
|
1558
|
-
}
|
|
1559
|
-
const { added, modified, deleted } = await getChangedFiles({
|
|
1560
|
-
fs: fs5,
|
|
1561
|
-
dir: rootPath,
|
|
1562
|
-
from: lastSha,
|
|
1563
|
-
to: sha,
|
|
1564
|
-
pathFilter
|
|
1565
|
-
});
|
|
1566
|
-
const tinaPathUpdates = modified.filter(
|
|
1567
|
-
(path20) => path20.startsWith(".tina/__generated__/_schema.json") || path20.startsWith("tina/tina-lock.json")
|
|
1568
|
-
);
|
|
1569
|
-
if (tinaPathUpdates.length > 0) {
|
|
1570
|
-
res = await database.indexContent({
|
|
1571
|
-
graphQLSchema,
|
|
1572
|
-
tinaSchema
|
|
1573
|
-
});
|
|
1574
|
-
} else {
|
|
1575
|
-
if (added.length > 0 || modified.length > 0) {
|
|
1576
|
-
await database.indexContentByPaths([...added, ...modified]);
|
|
1577
|
-
}
|
|
1578
|
-
if (deleted.length > 0) {
|
|
1579
|
-
await database.deleteContentByPaths(deleted);
|
|
1580
|
-
}
|
|
1581
|
-
}
|
|
1582
|
-
} else {
|
|
1583
|
-
res = await database.indexContent({
|
|
1584
|
-
graphQLSchema,
|
|
1585
|
-
tinaSchema
|
|
1586
|
-
});
|
|
1587
|
-
}
|
|
1588
|
-
if (sha) {
|
|
1589
|
-
await database.setMetadata("lastSha", sha);
|
|
1590
|
-
}
|
|
1591
|
-
if (res?.warnings) {
|
|
1592
|
-
warnings.push(...res.warnings);
|
|
1593
|
-
}
|
|
1594
|
-
},
|
|
1595
|
-
text: textToUse
|
|
1596
|
-
});
|
|
1597
|
-
if (warnings.length > 0) {
|
|
1598
|
-
logger.warn(`Indexing completed with ${warnings.length} warning(s)`);
|
|
1599
|
-
warnings.forEach((warning) => {
|
|
1600
|
-
logger.warn(warnText(`${warning}`));
|
|
1601
|
-
});
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
};
|
|
1605
|
-
|
|
1606
|
-
// src/next/commands/dev-command/html.ts
|
|
1607
|
-
var errorHTML = `<style type="text/css">
|
|
1608
|
-
#no-assets-placeholder body {
|
|
1609
|
-
font-family: sans-serif;
|
|
1610
|
-
font-size: 16px;
|
|
1611
|
-
line-height: 1.4;
|
|
1612
|
-
color: #333;
|
|
1613
|
-
background-color: #f5f5f5;
|
|
1614
|
-
}
|
|
1615
|
-
#no-assets-placeholder {
|
|
1616
|
-
max-width: 600px;
|
|
1617
|
-
margin: 0 auto;
|
|
1618
|
-
padding: 40px;
|
|
1619
|
-
text-align: center;
|
|
1620
|
-
background-color: #fff;
|
|
1621
|
-
box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.1);
|
|
1622
|
-
}
|
|
1623
|
-
#no-assets-placeholder h1 {
|
|
1624
|
-
font-size: 24px;
|
|
1625
|
-
margin-bottom: 20px;
|
|
1626
|
-
}
|
|
1627
|
-
#no-assets-placeholder p {
|
|
1628
|
-
margin-bottom: 10px;
|
|
1629
|
-
}
|
|
1630
|
-
#no-assets-placeholder a {
|
|
1631
|
-
color: #0077cc;
|
|
1632
|
-
text-decoration: none;
|
|
1633
|
-
}
|
|
1634
|
-
#no-assets-placeholder a:hover {
|
|
1635
|
-
text-decoration: underline;
|
|
1636
|
-
}
|
|
1637
|
-
</style>
|
|
1638
|
-
<div id="no-assets-placeholder">
|
|
1639
|
-
<h1>Failed loading TinaCMS assets</h1>
|
|
1640
|
-
<p>
|
|
1641
|
-
Your TinaCMS configuration may be misconfigured, and we could not load
|
|
1642
|
-
the assets for this page.
|
|
1643
|
-
</p>
|
|
1644
|
-
<p>
|
|
1645
|
-
Please visit <a href="https://tina.io/docs/r/FAQ/#13-how-do-i-resolve-failed-loading-tinacms-assets-error">this doc</a> for help.
|
|
1646
|
-
</p>
|
|
1647
|
-
</div>
|
|
1648
|
-
</div>`.trim().replace(/[\r\n\s]+/g, " ");
|
|
1649
|
-
var devHTML = (port) => `<!DOCTYPE html>
|
|
1650
|
-
<html lang="en">
|
|
1651
|
-
<head>
|
|
1652
|
-
<meta charset="UTF-8" />
|
|
1653
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1654
|
-
<title>TinaCMS</title>
|
|
1655
|
-
</head>
|
|
1656
|
-
|
|
1657
|
-
<!-- if development -->
|
|
1658
|
-
<script type="module">
|
|
1659
|
-
import RefreshRuntime from 'http://localhost:${port}/@react-refresh'
|
|
1660
|
-
RefreshRuntime.injectIntoGlobalHook(window)
|
|
1661
|
-
window.$RefreshReg$ = () => {}
|
|
1662
|
-
window.$RefreshSig$ = () => (type) => type
|
|
1663
|
-
window.__vite_plugin_react_preamble_installed__ = true
|
|
1664
|
-
</script>
|
|
1665
|
-
<script type="module" src="http://localhost:${port}/@vite/client"></script>
|
|
1666
|
-
<script>
|
|
1667
|
-
function handleLoadError() {
|
|
1668
|
-
// Assets have failed to load
|
|
1669
|
-
document.getElementById('root').innerHTML = '${errorHTML}';
|
|
1670
|
-
}
|
|
1671
|
-
</script>
|
|
1672
|
-
<script
|
|
1673
|
-
type="module"
|
|
1674
|
-
src="http://localhost:${port}/src/main.tsx"
|
|
1675
|
-
onerror="handleLoadError()"
|
|
1676
|
-
></script>
|
|
1677
|
-
<body class="tina-tailwind">
|
|
1678
|
-
<div id="root"></div>
|
|
1679
|
-
</body>
|
|
1680
|
-
</html>`;
|
|
1681
|
-
|
|
1682
|
-
// src/next/commands/dev-command/server/index.ts
|
|
1683
|
-
import { createServer as createViteServer } from "vite";
|
|
1684
|
-
|
|
1685
|
-
// src/next/vite/index.ts
|
|
1686
|
-
import path7 from "node:path";
|
|
1687
|
-
import react from "@vitejs/plugin-react";
|
|
1688
|
-
import fs6 from "fs-extra";
|
|
1689
|
-
import normalizePath3 from "normalize-path";
|
|
1690
|
-
import {
|
|
1691
|
-
splitVendorChunkPlugin
|
|
1692
|
-
} from "vite";
|
|
1693
|
-
|
|
1694
|
-
// src/next/vite/cors.ts
|
|
1695
|
-
var LOCALHOST_RE = /^https?:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/;
|
|
1696
|
-
var PRIVATE_NETWORK_RE = /^https?:\/\/(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})(:\d+)?$/;
|
|
1697
|
-
function expandOrigins(raw) {
|
|
1698
|
-
const hasPrivate = raw.some((o) => o === "private");
|
|
1699
|
-
const filtered = raw.filter((o) => o !== "private");
|
|
1700
|
-
return hasPrivate ? [...filtered, PRIVATE_NETWORK_RE] : filtered;
|
|
1701
|
-
}
|
|
1702
|
-
function isOriginAllowed(origin, allowedOrigins = []) {
|
|
1703
|
-
if (!origin) {
|
|
1704
|
-
return true;
|
|
1514
|
+
// src/next/vite/cors.ts
|
|
1515
|
+
var LOCALHOST_RE = /^https?:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/;
|
|
1516
|
+
var PRIVATE_NETWORK_RE = /^https?:\/\/(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})(:\d+)?$/;
|
|
1517
|
+
function expandOrigins(raw) {
|
|
1518
|
+
const hasPrivate = raw.some((o) => o === "private");
|
|
1519
|
+
const filtered = raw.filter((o) => o !== "private");
|
|
1520
|
+
return hasPrivate ? [...filtered, PRIVATE_NETWORK_RE] : filtered;
|
|
1521
|
+
}
|
|
1522
|
+
function isOriginAllowed(origin, allowedOrigins = []) {
|
|
1523
|
+
if (!origin) {
|
|
1524
|
+
return true;
|
|
1705
1525
|
}
|
|
1706
1526
|
if (LOCALHOST_RE.test(origin)) {
|
|
1707
1527
|
return true;
|
|
@@ -2034,15 +1854,15 @@ async function listFilesRecursively({
|
|
|
2034
1854
|
config2.publicFolder,
|
|
2035
1855
|
directoryPath
|
|
2036
1856
|
);
|
|
2037
|
-
const exists = await
|
|
1857
|
+
const exists = await fs5.pathExists(fullDirectoryPath);
|
|
2038
1858
|
if (!exists) {
|
|
2039
1859
|
return { "0": [] };
|
|
2040
1860
|
}
|
|
2041
|
-
const items = await
|
|
1861
|
+
const items = await fs5.readdir(fullDirectoryPath);
|
|
2042
1862
|
const staticMediaItems = [];
|
|
2043
1863
|
for (const item of items) {
|
|
2044
1864
|
const itemPath = path7.join(fullDirectoryPath, item);
|
|
2045
|
-
const stats = await
|
|
1865
|
+
const stats = await fs5.promises.lstat(itemPath);
|
|
2046
1866
|
const staticMediaItem = {
|
|
2047
1867
|
id: item,
|
|
2048
1868
|
filename: item,
|
|
@@ -2074,6 +1894,12 @@ async function listFilesRecursively({
|
|
|
2074
1894
|
}
|
|
2075
1895
|
return chunkArrayIntoObject(staticMediaItems, 20);
|
|
2076
1896
|
}
|
|
1897
|
+
var getBasePath = (configManager) => {
|
|
1898
|
+
const basePath = configManager.config.build.basePath;
|
|
1899
|
+
return `/${basePath ? `${normalizePath3(basePath)}/` : ""}${normalizePath3(
|
|
1900
|
+
configManager.config.build.outputFolder
|
|
1901
|
+
)}/`;
|
|
1902
|
+
};
|
|
2077
1903
|
var createConfig = async ({
|
|
2078
1904
|
configManager,
|
|
2079
1905
|
apiURL,
|
|
@@ -2092,9 +1918,9 @@ var createConfig = async ({
|
|
|
2092
1918
|
config: configManager.config.media.tina,
|
|
2093
1919
|
roothPath: configManager.rootPath
|
|
2094
1920
|
});
|
|
2095
|
-
await
|
|
1921
|
+
await fs5.outputFile(staticMediaPath, JSON.stringify(staticMedia, null, 2));
|
|
2096
1922
|
} else {
|
|
2097
|
-
await
|
|
1923
|
+
await fs5.outputFile(staticMediaPath, `[]`);
|
|
2098
1924
|
}
|
|
2099
1925
|
const alias = {
|
|
2100
1926
|
TINA_IMPORT: configManager.prebuildFilePath,
|
|
@@ -2114,17 +1940,11 @@ var createConfig = async ({
|
|
|
2114
1940
|
} else {
|
|
2115
1941
|
alias["CLIENT_IMPORT"] = configManager.isUsingTs() ? configManager.generatedTypesTSFilePath : configManager.generatedTypesJSFilePath;
|
|
2116
1942
|
}
|
|
2117
|
-
let basePath;
|
|
2118
|
-
if (configManager.config.build.basePath) {
|
|
2119
|
-
basePath = configManager.config.build.basePath;
|
|
2120
|
-
}
|
|
2121
1943
|
const fullVersion = configManager.getTinaGraphQLVersion();
|
|
2122
1944
|
const version2 = `${fullVersion.major}.${fullVersion.minor}`;
|
|
2123
1945
|
const config2 = {
|
|
2124
1946
|
root: configManager.spaRootPath,
|
|
2125
|
-
base:
|
|
2126
|
-
configManager.config.build.outputFolder
|
|
2127
|
-
)}/`,
|
|
1947
|
+
base: getBasePath(configManager),
|
|
2128
1948
|
appType: "spa",
|
|
2129
1949
|
resolve: {
|
|
2130
1950
|
alias,
|
|
@@ -2141,11 +1961,13 @@ var createConfig = async ({
|
|
|
2141
1961
|
* - `process.env.__NEXT_CROSS_ORIGIN`
|
|
2142
1962
|
* - `process.env.__NEXT_I18N_SUPPORT`
|
|
2143
1963
|
*
|
|
2144
|
-
*
|
|
2145
|
-
*
|
|
2146
|
-
*
|
|
1964
|
+
* esbuild >=0.25 (bundled by vite >=6) requires define values to be
|
|
1965
|
+
* entity names or JS literals; the `new Object(...)` workaround is
|
|
1966
|
+
* rejected. A plain JSON object literal is safe: esbuild hoists it
|
|
1967
|
+
* into a variable before substituting, so the historical `{}.`
|
|
1968
|
+
* browser-syntax problem can't occur.
|
|
2147
1969
|
*/
|
|
2148
|
-
"process.env":
|
|
1970
|
+
"process.env": JSON.stringify(publicEnv),
|
|
2149
1971
|
// Used by picomatch https://github.com/micromatch/picomatch/blob/master/lib/utils.js#L4
|
|
2150
1972
|
"process.platform": `"${process.platform}"`,
|
|
2151
1973
|
__API_URL__: `"${apiURL}"`,
|
|
@@ -2196,18 +2018,12 @@ var createConfig = async ({
|
|
|
2196
2018
|
rollupOptions
|
|
2197
2019
|
},
|
|
2198
2020
|
plugins: [
|
|
2199
|
-
/**
|
|
2200
|
-
* `splitVendorChunkPlugin` is needed because `tinacms` is quite large,
|
|
2201
|
-
* Vite's chunking strategy chokes on memory issues for smaller machines (ie. on CI).
|
|
2202
|
-
*/
|
|
2203
2021
|
react({
|
|
2204
2022
|
babel: {
|
|
2205
2023
|
// Supresses the warning [NOTE] babel The code generator has deoptimised the styling of
|
|
2206
2024
|
compact: true
|
|
2207
|
-
}
|
|
2208
|
-
fastRefresh: false
|
|
2025
|
+
}
|
|
2209
2026
|
}),
|
|
2210
|
-
splitVendorChunkPlugin(),
|
|
2211
2027
|
tinaTailwind(configManager.spaRootPath, configManager.prebuildFilePath),
|
|
2212
2028
|
...plugins
|
|
2213
2029
|
]
|
|
@@ -2215,9 +2031,446 @@ var createConfig = async ({
|
|
|
2215
2031
|
return config2;
|
|
2216
2032
|
};
|
|
2217
2033
|
|
|
2034
|
+
// src/next/commands/baseCommands.ts
|
|
2035
|
+
import { createRequire as createRequire3 } from "module";
|
|
2036
|
+
import path9 from "path";
|
|
2037
|
+
import { fileURLToPath } from "url";
|
|
2038
|
+
import chalk4 from "chalk";
|
|
2039
|
+
import { Command, Option } from "clipanion";
|
|
2040
|
+
import { getChangedFiles, getSha, shaExists } from "@tinacms/graphql";
|
|
2041
|
+
import fs7 from "fs-extra";
|
|
2042
|
+
|
|
2043
|
+
// src/utils/start-subprocess.ts
|
|
2044
|
+
import childProcess from "child_process";
|
|
2045
|
+
var startSubprocess2 = async ({ command: command2 }) => {
|
|
2046
|
+
if (typeof command2 === "string") {
|
|
2047
|
+
const commands = command2.split(" ");
|
|
2048
|
+
const firstCommand = commands[0];
|
|
2049
|
+
const args = commands.slice(1) || [];
|
|
2050
|
+
const ps = childProcess.spawn(firstCommand, args, {
|
|
2051
|
+
stdio: "inherit",
|
|
2052
|
+
shell: true
|
|
2053
|
+
});
|
|
2054
|
+
ps.on("error", (code) => {
|
|
2055
|
+
logger.error(
|
|
2056
|
+
dangerText(
|
|
2057
|
+
`An error has occurred in the Next.js child process. Error message below`
|
|
2058
|
+
)
|
|
2059
|
+
);
|
|
2060
|
+
logger.error(`name: ${code.name}
|
|
2061
|
+
message: ${code.message}
|
|
2062
|
+
|
|
2063
|
+
stack: ${code.stack || "No stack was provided"}`);
|
|
2064
|
+
});
|
|
2065
|
+
ps.on("close", (code) => {
|
|
2066
|
+
logger.info(`child process exited with code ${code}`);
|
|
2067
|
+
process.exit(code);
|
|
2068
|
+
});
|
|
2069
|
+
return ps;
|
|
2070
|
+
}
|
|
2071
|
+
};
|
|
2072
|
+
|
|
2073
|
+
// src/next/version-coherence.ts
|
|
2074
|
+
import path8 from "path";
|
|
2075
|
+
import fs6 from "fs-extra";
|
|
2076
|
+
var CORE_PACKAGES = [
|
|
2077
|
+
"tinacms",
|
|
2078
|
+
"@tinacms/graphql",
|
|
2079
|
+
"@tinacms/schema-tools"
|
|
2080
|
+
];
|
|
2081
|
+
var PLAIN_SEMVER = /^(\d+)\.(\d+)\.(\d+)$/;
|
|
2082
|
+
var parsePlainVersion = (version2) => {
|
|
2083
|
+
const match = PLAIN_SEMVER.exec(version2);
|
|
2084
|
+
if (!match) {
|
|
2085
|
+
return void 0;
|
|
2086
|
+
}
|
|
2087
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
2088
|
+
};
|
|
2089
|
+
var compareVersions = (a, b) => a[0] - b[0] || a[1] - b[1] || a[2] - b[2];
|
|
2090
|
+
var satisfiesDeclaredRange = (version2, spec) => {
|
|
2091
|
+
const resolved = parsePlainVersion(version2);
|
|
2092
|
+
if (!resolved) {
|
|
2093
|
+
return void 0;
|
|
2094
|
+
}
|
|
2095
|
+
const isCaret = spec.startsWith("^");
|
|
2096
|
+
const base = parsePlainVersion(isCaret ? spec.slice(1) : spec);
|
|
2097
|
+
if (!base) {
|
|
2098
|
+
return void 0;
|
|
2099
|
+
}
|
|
2100
|
+
if (!isCaret) {
|
|
2101
|
+
return compareVersions(resolved, base) === 0;
|
|
2102
|
+
}
|
|
2103
|
+
if (resolved[0] !== base[0]) {
|
|
2104
|
+
return false;
|
|
2105
|
+
}
|
|
2106
|
+
if (base[0] === 0) {
|
|
2107
|
+
if (resolved[1] !== base[1]) {
|
|
2108
|
+
return false;
|
|
2109
|
+
}
|
|
2110
|
+
if (base[1] === 0 && resolved[2] !== base[2]) {
|
|
2111
|
+
return false;
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
return compareVersions(resolved, base) >= 0;
|
|
2115
|
+
};
|
|
2116
|
+
var readPackageJson = (dir) => {
|
|
2117
|
+
try {
|
|
2118
|
+
return fs6.readJSONSync(path8.join(dir, "package.json"));
|
|
2119
|
+
} catch (_) {
|
|
2120
|
+
return void 0;
|
|
2121
|
+
}
|
|
2122
|
+
};
|
|
2123
|
+
var findPackageJsonAbove = (startDir, packageName) => {
|
|
2124
|
+
let dir = startDir;
|
|
2125
|
+
while (true) {
|
|
2126
|
+
const packageJson = readPackageJson(dir);
|
|
2127
|
+
if (packageJson?.name === packageName && packageJson.version) {
|
|
2128
|
+
return { dir, packageJson };
|
|
2129
|
+
}
|
|
2130
|
+
const parent = path8.dirname(dir);
|
|
2131
|
+
if (parent === dir) {
|
|
2132
|
+
return void 0;
|
|
2133
|
+
}
|
|
2134
|
+
dir = parent;
|
|
2135
|
+
}
|
|
2136
|
+
};
|
|
2137
|
+
var findInNodeModulesAbove = (packageName, fromDir) => {
|
|
2138
|
+
let dir = fromDir;
|
|
2139
|
+
while (true) {
|
|
2140
|
+
const candidate = path8.join(dir, "node_modules", ...packageName.split("/"));
|
|
2141
|
+
const packageJson = readPackageJson(candidate);
|
|
2142
|
+
if (packageJson?.name === packageName && packageJson.version) {
|
|
2143
|
+
return { version: packageJson.version, dir: candidate };
|
|
2144
|
+
}
|
|
2145
|
+
const parent = path8.dirname(dir);
|
|
2146
|
+
if (parent === dir) {
|
|
2147
|
+
return void 0;
|
|
2148
|
+
}
|
|
2149
|
+
dir = parent;
|
|
2150
|
+
}
|
|
2151
|
+
};
|
|
2152
|
+
var resolvePackage = (packageName, fromDir, resolveEntry) => {
|
|
2153
|
+
try {
|
|
2154
|
+
const entry = resolveEntry(packageName, fromDir);
|
|
2155
|
+
const found = findPackageJsonAbove(path8.dirname(entry), packageName);
|
|
2156
|
+
if (found?.packageJson.version) {
|
|
2157
|
+
return { version: found.packageJson.version, dir: found.dir };
|
|
2158
|
+
}
|
|
2159
|
+
} catch (_) {
|
|
2160
|
+
return findInNodeModulesAbove(packageName, fromDir);
|
|
2161
|
+
}
|
|
2162
|
+
return void 0;
|
|
2163
|
+
};
|
|
2164
|
+
var getVersionCoherenceWarnings = (input) => {
|
|
2165
|
+
const warnings = [];
|
|
2166
|
+
for (const name2 of CORE_PACKAGES) {
|
|
2167
|
+
const spec = input.cliDependencies[name2];
|
|
2168
|
+
const resolved = input.resolvedFromProject[name2];
|
|
2169
|
+
if (!spec || !resolved) {
|
|
2170
|
+
continue;
|
|
2171
|
+
}
|
|
2172
|
+
if (satisfiesDeclaredRange(resolved.version, spec) === false) {
|
|
2173
|
+
warnings.push(
|
|
2174
|
+
`${name2}@${resolved.version} is installed, but @tinacms/cli@${input.cliVersion} expects ${name2}@${spec}`
|
|
2175
|
+
);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
const fromProject = input.resolvedFromProject["tinacms"];
|
|
2179
|
+
const fromApp = input.tinacmsResolvedFromApp;
|
|
2180
|
+
if (fromProject && fromApp && fromProject.version !== fromApp.version) {
|
|
2181
|
+
warnings.push(
|
|
2182
|
+
`multiple copies of tinacms are installed: ${fromProject.version} (${fromProject.dir}) and ${fromApp.version} (${fromApp.dir}) - the admin UI bundles only one of them`
|
|
2183
|
+
);
|
|
2184
|
+
}
|
|
2185
|
+
return warnings;
|
|
2186
|
+
};
|
|
2187
|
+
var collectVersionCoherenceWarnings = ({
|
|
2188
|
+
rootPath,
|
|
2189
|
+
cliModuleDir,
|
|
2190
|
+
resolveEntry
|
|
2191
|
+
}) => {
|
|
2192
|
+
try {
|
|
2193
|
+
const cli2 = findPackageJsonAbove(cliModuleDir, "@tinacms/cli");
|
|
2194
|
+
if (!cli2?.packageJson.version) {
|
|
2195
|
+
return [];
|
|
2196
|
+
}
|
|
2197
|
+
const resolvedFromProject = {};
|
|
2198
|
+
for (const name2 of CORE_PACKAGES) {
|
|
2199
|
+
resolvedFromProject[name2] = resolvePackage(name2, rootPath, resolveEntry);
|
|
2200
|
+
}
|
|
2201
|
+
const app = resolvePackage("@tinacms/app", cliModuleDir, resolveEntry);
|
|
2202
|
+
const tinacmsResolvedFromApp = app ? resolvePackage("tinacms", app.dir, resolveEntry) : void 0;
|
|
2203
|
+
return getVersionCoherenceWarnings({
|
|
2204
|
+
cliVersion: cli2.packageJson.version,
|
|
2205
|
+
cliDependencies: cli2.packageJson.dependencies || {},
|
|
2206
|
+
resolvedFromProject,
|
|
2207
|
+
tinacmsResolvedFromApp
|
|
2208
|
+
});
|
|
2209
|
+
} catch (_) {
|
|
2210
|
+
return [];
|
|
2211
|
+
}
|
|
2212
|
+
};
|
|
2213
|
+
|
|
2214
|
+
// src/next/commands/baseCommands.ts
|
|
2215
|
+
var BaseCommand = class extends Command {
|
|
2216
|
+
experimentalDataLayer = Option.Boolean("--experimentalData", {
|
|
2217
|
+
description: "DEPRECATED - Build the server with additional data querying capabilities"
|
|
2218
|
+
});
|
|
2219
|
+
isomorphicGitBridge = Option.Boolean("--isomorphicGitBridge", {
|
|
2220
|
+
description: "DEPRECATED - Enable Isomorphic Git Bridge Implementation"
|
|
2221
|
+
});
|
|
2222
|
+
port = Option.String("-p,--port", "4001", {
|
|
2223
|
+
description: "Specify a port to run the server on. (default 4001)"
|
|
2224
|
+
});
|
|
2225
|
+
datalayerPort = Option.String("--datalayer-port", "9000", {
|
|
2226
|
+
description: "Specify a port to run the datalayer server on. (default 9000)"
|
|
2227
|
+
});
|
|
2228
|
+
subCommand = Option.String("-c,--command", {
|
|
2229
|
+
description: "The sub-command to run"
|
|
2230
|
+
});
|
|
2231
|
+
rootPath = Option.String("--rootPath", {
|
|
2232
|
+
description: "Specify the root directory to run the CLI from (defaults to current working directory)"
|
|
2233
|
+
});
|
|
2234
|
+
verbose = Option.Boolean("-v,--verbose", false, {
|
|
2235
|
+
description: "increase verbosity of logged output"
|
|
2236
|
+
});
|
|
2237
|
+
noSDK = Option.Boolean("--noSDK", false, {
|
|
2238
|
+
description: "DEPRECATED - This should now be set in the config at client.skip = true'. Don't generate the generated client SDK"
|
|
2239
|
+
});
|
|
2240
|
+
noTelemetry = Option.Boolean("--noTelemetry", false, {
|
|
2241
|
+
description: "Disable anonymous telemetry that is collected"
|
|
2242
|
+
});
|
|
2243
|
+
async startSubCommand() {
|
|
2244
|
+
let subProc;
|
|
2245
|
+
if (this.subCommand) {
|
|
2246
|
+
subProc = await startSubprocess2({ command: this.subCommand });
|
|
2247
|
+
logger.info(
|
|
2248
|
+
`Running web application with command: ${chalk4.cyan(this.subCommand)}`
|
|
2249
|
+
);
|
|
2250
|
+
}
|
|
2251
|
+
function exitHandler(options, exitCode) {
|
|
2252
|
+
if (subProc) {
|
|
2253
|
+
subProc.kill();
|
|
2254
|
+
}
|
|
2255
|
+
process.exit();
|
|
2256
|
+
}
|
|
2257
|
+
process.on("exit", exitHandler);
|
|
2258
|
+
process.on("SIGINT", exitHandler);
|
|
2259
|
+
process.on("SIGUSR1", exitHandler);
|
|
2260
|
+
process.on("SIGUSR2", exitHandler);
|
|
2261
|
+
process.on("uncaughtException", (error) => {
|
|
2262
|
+
logger.error(`Uncaught exception ${error.name}`);
|
|
2263
|
+
console.error(error);
|
|
2264
|
+
});
|
|
2265
|
+
}
|
|
2266
|
+
warnOnVersionSkew(rootPath) {
|
|
2267
|
+
try {
|
|
2268
|
+
const moduleDir = path9.dirname(fileURLToPath(import.meta.url));
|
|
2269
|
+
const require2 = createRequire3(import.meta.url);
|
|
2270
|
+
const warnings = collectVersionCoherenceWarnings({
|
|
2271
|
+
rootPath,
|
|
2272
|
+
cliModuleDir: moduleDir,
|
|
2273
|
+
resolveEntry: (packageName, fromDir) => require2.resolve(packageName, { paths: [fromDir] })
|
|
2274
|
+
});
|
|
2275
|
+
if (warnings.length > 0) {
|
|
2276
|
+
logger.warn(
|
|
2277
|
+
warnText("WARN: TinaCMS package version mismatch detected:")
|
|
2278
|
+
);
|
|
2279
|
+
warnings.forEach((warning) => {
|
|
2280
|
+
logger.warn(warnText(` - ${warning}`));
|
|
2281
|
+
});
|
|
2282
|
+
logger.warn(
|
|
2283
|
+
warnText(
|
|
2284
|
+
"A held-back package (stale lockfile entry, partial upgrade, pnpm minimumReleaseAge) can leave the admin UI on an older tinacms where newer documented features are silently missing. Upgrade the packages above to matching releases and reinstall."
|
|
2285
|
+
)
|
|
2286
|
+
);
|
|
2287
|
+
}
|
|
2288
|
+
} catch (_) {
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
logDeprecationWarnings() {
|
|
2292
|
+
if (this.isomorphicGitBridge) {
|
|
2293
|
+
logger.warn("--isomorphicGitBridge has been deprecated");
|
|
2294
|
+
}
|
|
2295
|
+
if (this.experimentalDataLayer) {
|
|
2296
|
+
logger.warn(
|
|
2297
|
+
"--experimentalDataLayer has been deprecated, the data layer is now built-in automatically"
|
|
2298
|
+
);
|
|
2299
|
+
}
|
|
2300
|
+
if (this.noSDK) {
|
|
2301
|
+
logger.warn(
|
|
2302
|
+
"--noSDK has been deprecated, and will be unsupported in a future release. This should be set in the config at client.skip = true"
|
|
2303
|
+
);
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
async indexContentWithSpinner({
|
|
2307
|
+
database,
|
|
2308
|
+
graphQLSchema,
|
|
2309
|
+
tinaSchema,
|
|
2310
|
+
configManager,
|
|
2311
|
+
partialReindex,
|
|
2312
|
+
text
|
|
2313
|
+
}) {
|
|
2314
|
+
const textToUse = text || "Indexing local files";
|
|
2315
|
+
const warnings = [];
|
|
2316
|
+
await spin({
|
|
2317
|
+
waitFor: async () => {
|
|
2318
|
+
const rootPath = configManager.rootPath;
|
|
2319
|
+
let sha;
|
|
2320
|
+
try {
|
|
2321
|
+
sha = await getSha({ fs: fs7, dir: rootPath });
|
|
2322
|
+
} catch (e) {
|
|
2323
|
+
if (partialReindex) {
|
|
2324
|
+
console.error(
|
|
2325
|
+
"Failed to get sha. NOTE: `--partial-reindex` only supported for git repositories"
|
|
2326
|
+
);
|
|
2327
|
+
throw e;
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
const lastSha = await database.getMetadata("lastSha");
|
|
2331
|
+
const exists = lastSha && await shaExists({ fs: fs7, dir: rootPath, sha: lastSha });
|
|
2332
|
+
let res;
|
|
2333
|
+
if (partialReindex && lastSha && exists && sha) {
|
|
2334
|
+
const pathFilter = {};
|
|
2335
|
+
if (configManager.isUsingLegacyFolder) {
|
|
2336
|
+
pathFilter[".tina/__generated__/_schema.json"] = {};
|
|
2337
|
+
} else {
|
|
2338
|
+
pathFilter["tina/tina-lock.json"] = {};
|
|
2339
|
+
}
|
|
2340
|
+
for (const collection of tinaSchema.getCollections()) {
|
|
2341
|
+
pathFilter[collection.path] = {
|
|
2342
|
+
matches: collection.match?.exclude || collection.match?.include ? tinaSchema.getMatches({ collection }) : void 0
|
|
2343
|
+
};
|
|
2344
|
+
}
|
|
2345
|
+
const { added, modified, deleted } = await getChangedFiles({
|
|
2346
|
+
fs: fs7,
|
|
2347
|
+
dir: rootPath,
|
|
2348
|
+
from: lastSha,
|
|
2349
|
+
to: sha,
|
|
2350
|
+
pathFilter
|
|
2351
|
+
});
|
|
2352
|
+
const tinaPathUpdates = modified.filter(
|
|
2353
|
+
(path22) => path22.startsWith(".tina/__generated__/_schema.json") || path22.startsWith("tina/tina-lock.json")
|
|
2354
|
+
);
|
|
2355
|
+
if (tinaPathUpdates.length > 0) {
|
|
2356
|
+
res = await database.indexContent({
|
|
2357
|
+
graphQLSchema,
|
|
2358
|
+
tinaSchema
|
|
2359
|
+
});
|
|
2360
|
+
} else {
|
|
2361
|
+
if (added.length > 0 || modified.length > 0) {
|
|
2362
|
+
await database.indexContentByPaths([...added, ...modified]);
|
|
2363
|
+
}
|
|
2364
|
+
if (deleted.length > 0) {
|
|
2365
|
+
await database.deleteContentByPaths(deleted);
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
} else {
|
|
2369
|
+
res = await database.indexContent({
|
|
2370
|
+
graphQLSchema,
|
|
2371
|
+
tinaSchema
|
|
2372
|
+
});
|
|
2373
|
+
}
|
|
2374
|
+
if (sha) {
|
|
2375
|
+
await database.setMetadata("lastSha", sha);
|
|
2376
|
+
}
|
|
2377
|
+
if (res?.warnings) {
|
|
2378
|
+
warnings.push(...res.warnings);
|
|
2379
|
+
}
|
|
2380
|
+
},
|
|
2381
|
+
text: textToUse
|
|
2382
|
+
});
|
|
2383
|
+
if (warnings.length > 0) {
|
|
2384
|
+
logger.warn(`Indexing completed with ${warnings.length} warning(s)`);
|
|
2385
|
+
warnings.forEach((warning) => {
|
|
2386
|
+
logger.warn(warnText(`${warning}`));
|
|
2387
|
+
});
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
};
|
|
2391
|
+
|
|
2392
|
+
// src/next/commands/dev-command/html.ts
|
|
2393
|
+
var errorHTML = `<style type="text/css">
|
|
2394
|
+
#no-assets-placeholder body {
|
|
2395
|
+
font-family: sans-serif;
|
|
2396
|
+
font-size: 16px;
|
|
2397
|
+
line-height: 1.4;
|
|
2398
|
+
color: #333;
|
|
2399
|
+
background-color: #f5f5f5;
|
|
2400
|
+
}
|
|
2401
|
+
#no-assets-placeholder {
|
|
2402
|
+
max-width: 600px;
|
|
2403
|
+
margin: 0 auto;
|
|
2404
|
+
padding: 40px;
|
|
2405
|
+
text-align: center;
|
|
2406
|
+
background-color: #fff;
|
|
2407
|
+
box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.1);
|
|
2408
|
+
}
|
|
2409
|
+
#no-assets-placeholder h1 {
|
|
2410
|
+
font-size: 24px;
|
|
2411
|
+
margin-bottom: 20px;
|
|
2412
|
+
}
|
|
2413
|
+
#no-assets-placeholder p {
|
|
2414
|
+
margin-bottom: 10px;
|
|
2415
|
+
}
|
|
2416
|
+
#no-assets-placeholder a {
|
|
2417
|
+
color: #0077cc;
|
|
2418
|
+
text-decoration: none;
|
|
2419
|
+
}
|
|
2420
|
+
#no-assets-placeholder a:hover {
|
|
2421
|
+
text-decoration: underline;
|
|
2422
|
+
}
|
|
2423
|
+
</style>
|
|
2424
|
+
<div id="no-assets-placeholder">
|
|
2425
|
+
<h1>Failed loading TinaCMS assets</h1>
|
|
2426
|
+
<p>
|
|
2427
|
+
Your TinaCMS configuration may be misconfigured, and we could not load
|
|
2428
|
+
the assets for this page.
|
|
2429
|
+
</p>
|
|
2430
|
+
<p>
|
|
2431
|
+
Please visit <a href="https://tina.io/docs/r/FAQ/#13-how-do-i-resolve-failed-loading-tinacms-assets-error">this doc</a> for help.
|
|
2432
|
+
</p>
|
|
2433
|
+
</div>
|
|
2434
|
+
</div>`.trim().replace(/[\r\n\s]+/g, " ");
|
|
2435
|
+
var devHTML = (port, basePath) => `<!DOCTYPE html>
|
|
2436
|
+
<html lang="en">
|
|
2437
|
+
<head>
|
|
2438
|
+
<meta charset="UTF-8" />
|
|
2439
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
2440
|
+
<title>TinaCMS</title>
|
|
2441
|
+
</head>
|
|
2442
|
+
|
|
2443
|
+
<!-- if development -->
|
|
2444
|
+
<script type="module">
|
|
2445
|
+
import RefreshRuntime from 'http://localhost:${port}${basePath}@react-refresh'
|
|
2446
|
+
RefreshRuntime.injectIntoGlobalHook(window)
|
|
2447
|
+
window.$RefreshReg$ = () => {}
|
|
2448
|
+
window.$RefreshSig$ = () => (type) => type
|
|
2449
|
+
window.__vite_plugin_react_preamble_installed__ = true
|
|
2450
|
+
</script>
|
|
2451
|
+
<script type="module" src="http://localhost:${port}${basePath}@vite/client"></script>
|
|
2452
|
+
<script>
|
|
2453
|
+
function handleLoadError() {
|
|
2454
|
+
// Assets have failed to load
|
|
2455
|
+
document.getElementById('root').innerHTML = '${errorHTML}';
|
|
2456
|
+
}
|
|
2457
|
+
</script>
|
|
2458
|
+
<script
|
|
2459
|
+
type="module"
|
|
2460
|
+
src="http://localhost:${port}${basePath}src/main.tsx"
|
|
2461
|
+
onerror="handleLoadError()"
|
|
2462
|
+
></script>
|
|
2463
|
+
<body class="tina-tailwind">
|
|
2464
|
+
<div id="root"></div>
|
|
2465
|
+
</body>
|
|
2466
|
+
</html>`;
|
|
2467
|
+
|
|
2468
|
+
// src/next/commands/dev-command/server/index.ts
|
|
2469
|
+
import { createServer as createViteServer } from "vite";
|
|
2470
|
+
|
|
2218
2471
|
// src/next/vite/plugins.ts
|
|
2219
|
-
import
|
|
2220
|
-
import
|
|
2472
|
+
import fs9 from "fs";
|
|
2473
|
+
import path11 from "path";
|
|
2221
2474
|
import { createFilter } from "@rollup/pluginutils";
|
|
2222
2475
|
import { resolve as gqlResolve } from "@tinacms/graphql";
|
|
2223
2476
|
import bodyParser from "body-parser";
|
|
@@ -2226,11 +2479,12 @@ import { transform as esbuildTransform } from "esbuild";
|
|
|
2226
2479
|
import { transformWithEsbuild } from "vite";
|
|
2227
2480
|
|
|
2228
2481
|
// src/next/commands/dev-command/server/media.ts
|
|
2229
|
-
import
|
|
2482
|
+
import { randomUUID } from "crypto";
|
|
2483
|
+
import path10, { join } from "path";
|
|
2230
2484
|
import busboy from "busboy";
|
|
2231
|
-
import
|
|
2485
|
+
import fs8 from "fs-extra";
|
|
2232
2486
|
var createMediaRouter = (config2) => {
|
|
2233
|
-
const mediaFolder =
|
|
2487
|
+
const mediaFolder = path10.join(
|
|
2234
2488
|
config2.rootPath,
|
|
2235
2489
|
config2.publicFolder,
|
|
2236
2490
|
config2.mediaRoot
|
|
@@ -2244,10 +2498,12 @@ var createMediaRouter = (config2) => {
|
|
|
2244
2498
|
);
|
|
2245
2499
|
const limit = requestURL.searchParams.get("limit");
|
|
2246
2500
|
const cursor = requestURL.searchParams.get("cursor");
|
|
2501
|
+
const search = requestURL.searchParams.get("search");
|
|
2247
2502
|
const media = await mediaModel.listMedia({
|
|
2248
2503
|
searchPath: folder,
|
|
2249
2504
|
cursor,
|
|
2250
|
-
limit
|
|
2505
|
+
limit,
|
|
2506
|
+
search
|
|
2251
2507
|
});
|
|
2252
2508
|
res.end(JSON.stringify(media));
|
|
2253
2509
|
} catch (error) {
|
|
@@ -2273,6 +2529,39 @@ var createMediaRouter = (config2) => {
|
|
|
2273
2529
|
throw error;
|
|
2274
2530
|
}
|
|
2275
2531
|
};
|
|
2532
|
+
const handleRename = async (req, res) => {
|
|
2533
|
+
const body = req.body;
|
|
2534
|
+
const { from, to } = body || {};
|
|
2535
|
+
if (typeof from !== "string" || typeof to !== "string" || !from || !to) {
|
|
2536
|
+
res.statusCode = 400;
|
|
2537
|
+
res.end(
|
|
2538
|
+
JSON.stringify({
|
|
2539
|
+
code: "INVALID_FILENAME",
|
|
2540
|
+
message: 'Both "from" and "to" are required.'
|
|
2541
|
+
})
|
|
2542
|
+
);
|
|
2543
|
+
return;
|
|
2544
|
+
}
|
|
2545
|
+
try {
|
|
2546
|
+
const result = await mediaModel.renameMedia({ from, to });
|
|
2547
|
+
if ("code" in result) {
|
|
2548
|
+
res.statusCode = RENAME_ERROR_STATUS[result.code];
|
|
2549
|
+
res.end(JSON.stringify({ code: result.code, message: result.message }));
|
|
2550
|
+
return;
|
|
2551
|
+
}
|
|
2552
|
+
res.statusCode = 200;
|
|
2553
|
+
res.end(JSON.stringify({ success: true, from, to }));
|
|
2554
|
+
} catch (error) {
|
|
2555
|
+
if (error instanceof PathTraversalError) {
|
|
2556
|
+
res.statusCode = 403;
|
|
2557
|
+
res.end(
|
|
2558
|
+
JSON.stringify({ code: "INVALID_PATH", message: error.message })
|
|
2559
|
+
);
|
|
2560
|
+
return;
|
|
2561
|
+
}
|
|
2562
|
+
throw error;
|
|
2563
|
+
}
|
|
2564
|
+
};
|
|
2276
2565
|
const handlePost = async function(req, res) {
|
|
2277
2566
|
const bb = busboy({ headers: req.headers });
|
|
2278
2567
|
let responded = false;
|
|
@@ -2294,8 +2583,8 @@ var createMediaRouter = (config2) => {
|
|
|
2294
2583
|
);
|
|
2295
2584
|
return;
|
|
2296
2585
|
}
|
|
2297
|
-
await
|
|
2298
|
-
file.pipe(
|
|
2586
|
+
await fs8.ensureDir(path10.dirname(saveTo));
|
|
2587
|
+
file.pipe(fs8.createWriteStream(saveTo));
|
|
2299
2588
|
});
|
|
2300
2589
|
bb.on("error", (error) => {
|
|
2301
2590
|
responded = true;
|
|
@@ -2313,7 +2602,7 @@ var createMediaRouter = (config2) => {
|
|
|
2313
2602
|
});
|
|
2314
2603
|
req.pipe(bb);
|
|
2315
2604
|
};
|
|
2316
|
-
return { handleList, handleDelete, handlePost };
|
|
2605
|
+
return { handleList, handleDelete, handlePost, handleRename };
|
|
2317
2606
|
};
|
|
2318
2607
|
var parseMediaFolder = (str) => {
|
|
2319
2608
|
let returnString = str;
|
|
@@ -2322,21 +2611,35 @@ var parseMediaFolder = (str) => {
|
|
|
2322
2611
|
returnString = returnString.substr(0, returnString.length - 1);
|
|
2323
2612
|
return returnString;
|
|
2324
2613
|
};
|
|
2614
|
+
var RENAME_ERROR_STATUS = {
|
|
2615
|
+
NOT_FOUND: 404,
|
|
2616
|
+
NAME_COLLISION: 409,
|
|
2617
|
+
UNSUPPORTED: 400,
|
|
2618
|
+
BACKEND_FAILURE: 500
|
|
2619
|
+
};
|
|
2620
|
+
var StagedRenameError = class extends Error {
|
|
2621
|
+
constructor(stagingName) {
|
|
2622
|
+
super(`Left the file as "${stagingName}" in the same folder.`);
|
|
2623
|
+
this.stagingName = stagingName;
|
|
2624
|
+
}
|
|
2625
|
+
stagingName;
|
|
2626
|
+
};
|
|
2627
|
+
var isDestinationExistsError = (error) => error?.code === "EEXIST" || /dest already exists/i.test(error?.message || "");
|
|
2325
2628
|
var ENCODED_TRAVERSAL_RE = /%2e%2e|%2f|%5c/i;
|
|
2326
2629
|
function resolveRealPath(candidate) {
|
|
2327
2630
|
try {
|
|
2328
|
-
return
|
|
2631
|
+
return fs8.realpathSync(candidate);
|
|
2329
2632
|
} catch {
|
|
2330
|
-
const parent =
|
|
2633
|
+
const parent = path10.dirname(candidate);
|
|
2331
2634
|
if (parent === candidate) return candidate;
|
|
2332
|
-
return
|
|
2635
|
+
return path10.join(resolveRealPath(parent), path10.basename(candidate));
|
|
2333
2636
|
}
|
|
2334
2637
|
}
|
|
2335
2638
|
function assertSymlinkWithinBase(resolved, resolvedBase, userPath) {
|
|
2336
2639
|
try {
|
|
2337
|
-
const realBase =
|
|
2640
|
+
const realBase = fs8.realpathSync(resolvedBase);
|
|
2338
2641
|
const realResolved = resolveRealPath(resolved);
|
|
2339
|
-
if (realResolved !== realBase && !realResolved.startsWith(realBase +
|
|
2642
|
+
if (realResolved !== realBase && !realResolved.startsWith(realBase + path10.sep)) {
|
|
2340
2643
|
throw new PathTraversalError(userPath);
|
|
2341
2644
|
}
|
|
2342
2645
|
} catch (err) {
|
|
@@ -2347,13 +2650,13 @@ function resolveWithinBase(userPath, baseDir) {
|
|
|
2347
2650
|
if (ENCODED_TRAVERSAL_RE.test(userPath)) {
|
|
2348
2651
|
throw new PathTraversalError(userPath);
|
|
2349
2652
|
}
|
|
2350
|
-
const resolvedBase =
|
|
2351
|
-
const resolved =
|
|
2653
|
+
const resolvedBase = path10.resolve(baseDir);
|
|
2654
|
+
const resolved = path10.resolve(path10.join(baseDir, userPath));
|
|
2352
2655
|
if (resolved === resolvedBase) {
|
|
2353
2656
|
assertSymlinkWithinBase(resolved, resolvedBase, userPath);
|
|
2354
2657
|
return resolvedBase;
|
|
2355
2658
|
}
|
|
2356
|
-
if (resolved.startsWith(resolvedBase +
|
|
2659
|
+
if (resolved.startsWith(resolvedBase + path10.sep)) {
|
|
2357
2660
|
assertSymlinkWithinBase(resolved, resolvedBase, userPath);
|
|
2358
2661
|
return resolved;
|
|
2359
2662
|
}
|
|
@@ -2363,12 +2666,12 @@ function resolveStrictlyWithinBase(userPath, baseDir) {
|
|
|
2363
2666
|
if (ENCODED_TRAVERSAL_RE.test(userPath)) {
|
|
2364
2667
|
throw new PathTraversalError(userPath);
|
|
2365
2668
|
}
|
|
2366
|
-
const resolvedBase =
|
|
2367
|
-
const resolved =
|
|
2669
|
+
const resolvedBase = path10.resolve(baseDir) + path10.sep;
|
|
2670
|
+
const resolved = path10.resolve(path10.join(baseDir, userPath));
|
|
2368
2671
|
if (!resolved.startsWith(resolvedBase)) {
|
|
2369
2672
|
throw new PathTraversalError(userPath);
|
|
2370
2673
|
}
|
|
2371
|
-
assertSymlinkWithinBase(resolved,
|
|
2674
|
+
assertSymlinkWithinBase(resolved, path10.resolve(baseDir), userPath);
|
|
2372
2675
|
return resolved;
|
|
2373
2676
|
}
|
|
2374
2677
|
var MediaModel = class {
|
|
@@ -2385,16 +2688,27 @@ var MediaModel = class {
|
|
|
2385
2688
|
const mediaBase = join(this.rootPath, this.publicFolder, this.mediaRoot);
|
|
2386
2689
|
const validatedPath = resolveWithinBase(args.searchPath, mediaBase);
|
|
2387
2690
|
const searchPath = parseMediaFolder(args.searchPath);
|
|
2388
|
-
if (!await
|
|
2691
|
+
if (!await fs8.pathExists(validatedPath)) {
|
|
2389
2692
|
return {
|
|
2390
2693
|
files: [],
|
|
2391
2694
|
directories: []
|
|
2392
2695
|
};
|
|
2393
2696
|
}
|
|
2394
|
-
const
|
|
2697
|
+
const search = args.search?.trim().toLowerCase();
|
|
2698
|
+
if (search) {
|
|
2699
|
+
return await this.searchMedia({
|
|
2700
|
+
mediaBase,
|
|
2701
|
+
validatedPath,
|
|
2702
|
+
searchPath,
|
|
2703
|
+
search,
|
|
2704
|
+
cursor: args.cursor,
|
|
2705
|
+
limit: args.limit
|
|
2706
|
+
});
|
|
2707
|
+
}
|
|
2708
|
+
const filesStr = await fs8.readdir(validatedPath);
|
|
2395
2709
|
const filesProm = filesStr.map(async (file) => {
|
|
2396
2710
|
const filePath = join(validatedPath, file);
|
|
2397
|
-
const stat = await
|
|
2711
|
+
const stat = await fs8.stat(filePath);
|
|
2398
2712
|
let src = `/${file}`;
|
|
2399
2713
|
const isFile = stat.isFile();
|
|
2400
2714
|
if (!isFile) {
|
|
@@ -2430,10 +2744,11 @@ var MediaModel = class {
|
|
|
2430
2744
|
}
|
|
2431
2745
|
return 0;
|
|
2432
2746
|
});
|
|
2433
|
-
const
|
|
2434
|
-
const
|
|
2435
|
-
const directories =
|
|
2436
|
-
const
|
|
2747
|
+
const allDirectories = sortedItems.filter((x) => !x.isFile).map((x) => x.src);
|
|
2748
|
+
const allFiles = sortedItems.filter((x) => x.isFile);
|
|
2749
|
+
const directories = offset === 0 ? allDirectories : [];
|
|
2750
|
+
const files = allFiles.slice(offset, offset + limit);
|
|
2751
|
+
const cursor = allFiles.length > offset + limit ? String(offset + limit) : null;
|
|
2437
2752
|
return {
|
|
2438
2753
|
files,
|
|
2439
2754
|
directories,
|
|
@@ -2449,12 +2764,156 @@ var MediaModel = class {
|
|
|
2449
2764
|
};
|
|
2450
2765
|
}
|
|
2451
2766
|
}
|
|
2767
|
+
async searchMedia({
|
|
2768
|
+
mediaBase,
|
|
2769
|
+
validatedPath,
|
|
2770
|
+
searchPath,
|
|
2771
|
+
search,
|
|
2772
|
+
cursor,
|
|
2773
|
+
limit
|
|
2774
|
+
}) {
|
|
2775
|
+
const resolvedBase = path10.resolve(mediaBase);
|
|
2776
|
+
const files = [];
|
|
2777
|
+
const directories = [];
|
|
2778
|
+
const visitedDirs = /* @__PURE__ */ new Set([resolveRealPath(validatedPath)]);
|
|
2779
|
+
const walk = async (dir, relPrefix) => {
|
|
2780
|
+
let entries;
|
|
2781
|
+
try {
|
|
2782
|
+
entries = await fs8.readdir(dir);
|
|
2783
|
+
} catch {
|
|
2784
|
+
return;
|
|
2785
|
+
}
|
|
2786
|
+
const stats = await Promise.all(
|
|
2787
|
+
entries.map(async (entry) => {
|
|
2788
|
+
const absPath = join(dir, entry);
|
|
2789
|
+
try {
|
|
2790
|
+
assertSymlinkWithinBase(absPath, resolvedBase, absPath);
|
|
2791
|
+
} catch {
|
|
2792
|
+
return null;
|
|
2793
|
+
}
|
|
2794
|
+
try {
|
|
2795
|
+
return { entry, absPath, stat: await fs8.stat(absPath) };
|
|
2796
|
+
} catch {
|
|
2797
|
+
return null;
|
|
2798
|
+
}
|
|
2799
|
+
})
|
|
2800
|
+
);
|
|
2801
|
+
for (const entryStat of stats) {
|
|
2802
|
+
if (!entryStat) continue;
|
|
2803
|
+
const { entry, absPath, stat } = entryStat;
|
|
2804
|
+
const relPath = relPrefix ? `${relPrefix}/${entry}` : entry;
|
|
2805
|
+
if (stat.isDirectory()) {
|
|
2806
|
+
const realDir = resolveRealPath(absPath);
|
|
2807
|
+
if (visitedDirs.has(realDir)) continue;
|
|
2808
|
+
visitedDirs.add(realDir);
|
|
2809
|
+
if (entry.toLowerCase().includes(search)) {
|
|
2810
|
+
directories.push(`/${relPath}`);
|
|
2811
|
+
}
|
|
2812
|
+
await walk(absPath, relPath);
|
|
2813
|
+
continue;
|
|
2814
|
+
}
|
|
2815
|
+
if (!relPath.toLowerCase().includes(search)) continue;
|
|
2816
|
+
let src = `/${relPath}`;
|
|
2817
|
+
if (searchPath) src = `/${searchPath}${src}`;
|
|
2818
|
+
if (this.mediaRoot) src = `/${this.mediaRoot}${src}`;
|
|
2819
|
+
files.push({ src, filename: relPath, size: stat.size });
|
|
2820
|
+
}
|
|
2821
|
+
};
|
|
2822
|
+
await walk(validatedPath, "");
|
|
2823
|
+
files.sort((a, b) => a.filename.localeCompare(b.filename));
|
|
2824
|
+
directories.sort();
|
|
2825
|
+
const offset = Number(cursor) || 0;
|
|
2826
|
+
const pageSize = Number(limit) || 20;
|
|
2827
|
+
return {
|
|
2828
|
+
files: files.slice(offset, offset + pageSize),
|
|
2829
|
+
directories: offset === 0 ? directories : [],
|
|
2830
|
+
cursor: files.length > offset + pageSize ? String(offset + pageSize) : null
|
|
2831
|
+
};
|
|
2832
|
+
}
|
|
2833
|
+
/**
|
|
2834
|
+
* @security Both paths go through `resolveStrictlyWithinBase`, which rejects
|
|
2835
|
+
* traversal, symlink escapes and the media root itself.
|
|
2836
|
+
*/
|
|
2837
|
+
async renameMedia(args) {
|
|
2838
|
+
const mediaBase = join(this.rootPath, this.publicFolder, this.mediaRoot);
|
|
2839
|
+
const source = resolveStrictlyWithinBase(args.from, mediaBase);
|
|
2840
|
+
const destination = resolveStrictlyWithinBase(args.to, mediaBase);
|
|
2841
|
+
try {
|
|
2842
|
+
const stats = await fs8.stat(source);
|
|
2843
|
+
if (stats.isDirectory()) {
|
|
2844
|
+
return {
|
|
2845
|
+
ok: false,
|
|
2846
|
+
code: "UNSUPPORTED",
|
|
2847
|
+
message: "Renaming folders is not supported."
|
|
2848
|
+
};
|
|
2849
|
+
}
|
|
2850
|
+
} catch {
|
|
2851
|
+
return {
|
|
2852
|
+
ok: false,
|
|
2853
|
+
code: "NOT_FOUND",
|
|
2854
|
+
message: `"${args.from}" does not exist.`
|
|
2855
|
+
};
|
|
2856
|
+
}
|
|
2857
|
+
const isCaseOnlyRename = source !== destination && source.toLowerCase() === destination.toLowerCase();
|
|
2858
|
+
if (!isCaseOnlyRename && await fs8.pathExists(destination)) {
|
|
2859
|
+
return {
|
|
2860
|
+
ok: false,
|
|
2861
|
+
code: "NAME_COLLISION",
|
|
2862
|
+
message: `"${args.to}" already exists.`
|
|
2863
|
+
};
|
|
2864
|
+
}
|
|
2865
|
+
try {
|
|
2866
|
+
await fs8.ensureDir(path10.dirname(destination));
|
|
2867
|
+
if (isCaseOnlyRename) {
|
|
2868
|
+
await this.renameViaStaging(source, destination);
|
|
2869
|
+
} else {
|
|
2870
|
+
await fs8.move(source, destination, { overwrite: false });
|
|
2871
|
+
}
|
|
2872
|
+
return { ok: true };
|
|
2873
|
+
} catch (error) {
|
|
2874
|
+
if (isDestinationExistsError(error)) {
|
|
2875
|
+
return {
|
|
2876
|
+
ok: false,
|
|
2877
|
+
code: "NAME_COLLISION",
|
|
2878
|
+
message: `"${args.to}" already exists.`
|
|
2879
|
+
};
|
|
2880
|
+
}
|
|
2881
|
+
console.error(error);
|
|
2882
|
+
return {
|
|
2883
|
+
ok: false,
|
|
2884
|
+
code: "BACKEND_FAILURE",
|
|
2885
|
+
message: error instanceof StagedRenameError ? `Failed to rename the file. ${error.message}` : "Failed to rename the file."
|
|
2886
|
+
};
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2889
|
+
/**
|
|
2890
|
+
* A case-insensitive filesystem can treat `a.jpg` -> `A.jpg` as a no-op, so
|
|
2891
|
+
* hop through a unique sibling name. On failure the source is put back; if
|
|
2892
|
+
* even that fails the file survives under the staging name, which
|
|
2893
|
+
* StagedRenameError reports rather than leaving it to be found by accident.
|
|
2894
|
+
*/
|
|
2895
|
+
async renameViaStaging(source, destination) {
|
|
2896
|
+
const stagingName = `.tina-rename-${randomUUID()}`;
|
|
2897
|
+
const staging = join(path10.dirname(source), stagingName);
|
|
2898
|
+
await fs8.move(source, staging, { overwrite: false });
|
|
2899
|
+
try {
|
|
2900
|
+
await fs8.move(staging, destination, { overwrite: false });
|
|
2901
|
+
} catch (error) {
|
|
2902
|
+
try {
|
|
2903
|
+
await fs8.move(staging, source, { overwrite: false });
|
|
2904
|
+
} catch (restoreError) {
|
|
2905
|
+
console.error(restoreError);
|
|
2906
|
+
throw new StagedRenameError(stagingName);
|
|
2907
|
+
}
|
|
2908
|
+
throw error;
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2452
2911
|
async deleteMedia(args) {
|
|
2453
2912
|
try {
|
|
2454
2913
|
const mediaBase = join(this.rootPath, this.publicFolder, this.mediaRoot);
|
|
2455
2914
|
const file = resolveStrictlyWithinBase(args.searchPath, mediaBase);
|
|
2456
|
-
await
|
|
2457
|
-
await
|
|
2915
|
+
await fs8.stat(file);
|
|
2916
|
+
await fs8.remove(file);
|
|
2458
2917
|
return { ok: true };
|
|
2459
2918
|
} catch (error) {
|
|
2460
2919
|
if (error instanceof PathTraversalError) throw error;
|
|
@@ -2562,7 +3021,7 @@ var transformTsxPlugin = ({
|
|
|
2562
3021
|
const plug = {
|
|
2563
3022
|
name: "transform-tsx",
|
|
2564
3023
|
async transform(code, id) {
|
|
2565
|
-
const extName =
|
|
3024
|
+
const extName = path11.extname(id);
|
|
2566
3025
|
if (extName.startsWith(".tsx") || extName.startsWith(".ts")) {
|
|
2567
3026
|
const result = await esbuildTransform(code, { loader: "tsx" });
|
|
2568
3027
|
return {
|
|
@@ -2573,6 +3032,7 @@ var transformTsxPlugin = ({
|
|
|
2573
3032
|
};
|
|
2574
3033
|
return plug;
|
|
2575
3034
|
};
|
|
3035
|
+
var isMediaRenameRequest = (req) => req.method === "POST" && (req.url || "").split("?")[0] === "/media/rename";
|
|
2576
3036
|
var devServerEndPointsPlugin = ({
|
|
2577
3037
|
configManager,
|
|
2578
3038
|
apiURL,
|
|
@@ -2585,6 +3045,7 @@ var devServerEndPointsPlugin = ({
|
|
|
2585
3045
|
const isStateChangingRequest = (req) => {
|
|
2586
3046
|
const url = req.url || "";
|
|
2587
3047
|
if (url.startsWith("/media/upload")) return true;
|
|
3048
|
+
if (isMediaRenameRequest(req)) return true;
|
|
2588
3049
|
if (url.startsWith("/media") && req.method === "DELETE") return true;
|
|
2589
3050
|
if (url.startsWith("/graphql") && req.method === "POST") return true;
|
|
2590
3051
|
if ((url.startsWith("/searchIndex") || url.startsWith("/v2/searchIndex")) && (req.method === "POST" || req.method === "DELETE"))
|
|
@@ -2622,6 +3083,10 @@ var devServerEndPointsPlugin = ({
|
|
|
2622
3083
|
await mediaRouter.handlePost(req, res);
|
|
2623
3084
|
return;
|
|
2624
3085
|
}
|
|
3086
|
+
if (isMediaRenameRequest(req)) {
|
|
3087
|
+
await mediaRouter.handleRename(req, res);
|
|
3088
|
+
return;
|
|
3089
|
+
}
|
|
2625
3090
|
if (req.url.startsWith("/media")) {
|
|
2626
3091
|
if (req.method === "DELETE") {
|
|
2627
3092
|
await mediaRouter.handleDelete(req, res);
|
|
@@ -2686,7 +3151,7 @@ function viteTransformExtension({
|
|
|
2686
3151
|
async transform(code, id) {
|
|
2687
3152
|
if (filter(id)) {
|
|
2688
3153
|
const { transform: transform2 } = await import("@svgr/core");
|
|
2689
|
-
const svgCode = await
|
|
3154
|
+
const svgCode = await fs9.promises.readFile(
|
|
2690
3155
|
id.replace(/\?.*$/, ""),
|
|
2691
3156
|
"utf8"
|
|
2692
3157
|
);
|
|
@@ -2797,6 +3262,7 @@ var DevCommand = class extends BaseCommand {
|
|
|
2797
3262
|
});
|
|
2798
3263
|
logger.info("\u{1F999} TinaCMS Dev Server is initializing...");
|
|
2799
3264
|
this.logDeprecationWarnings();
|
|
3265
|
+
this.warnOnVersionSkew(configManager.rootPath);
|
|
2800
3266
|
createDBServer(Number(this.datalayerPort));
|
|
2801
3267
|
let database = null;
|
|
2802
3268
|
const dbLock = async (fn) => {
|
|
@@ -2836,13 +3302,13 @@ var DevCommand = class extends BaseCommand {
|
|
|
2836
3302
|
});
|
|
2837
3303
|
const apiURL2 = await codegen2.execute();
|
|
2838
3304
|
if (!configManager.isUsingLegacyFolder) {
|
|
2839
|
-
const schemaObject = await
|
|
3305
|
+
const schemaObject = await fs10.readJSON(
|
|
2840
3306
|
configManager.generatedSchemaJSONPath
|
|
2841
3307
|
);
|
|
2842
|
-
const lookupObject = await
|
|
3308
|
+
const lookupObject = await fs10.readJSON(
|
|
2843
3309
|
configManager.generatedLookupJSONPath
|
|
2844
3310
|
);
|
|
2845
|
-
const graphqlSchemaObject = await
|
|
3311
|
+
const graphqlSchemaObject = await fs10.readJSON(
|
|
2846
3312
|
configManager.generatedGraphQLJSONPath
|
|
2847
3313
|
);
|
|
2848
3314
|
const tinaLockFilename = "tina-lock.json";
|
|
@@ -2851,8 +3317,8 @@ var DevCommand = class extends BaseCommand {
|
|
|
2851
3317
|
lookup: lookupObject,
|
|
2852
3318
|
graphql: graphqlSchemaObject
|
|
2853
3319
|
});
|
|
2854
|
-
|
|
2855
|
-
|
|
3320
|
+
fs10.writeFileSync(
|
|
3321
|
+
path12.join(configManager.tinaFolderPath, tinaLockFilename),
|
|
2856
3322
|
tinaLockContent
|
|
2857
3323
|
);
|
|
2858
3324
|
}
|
|
@@ -2896,8 +3362,11 @@ ${dangerText(e.message)}
|
|
|
2896
3362
|
const { apiURL, graphQLSchema, tinaSchema } = await setup({
|
|
2897
3363
|
firstTime: true
|
|
2898
3364
|
});
|
|
2899
|
-
await
|
|
2900
|
-
|
|
3365
|
+
await fs10.outputFile(
|
|
3366
|
+
configManager.outputHTMLFilePath,
|
|
3367
|
+
devHTML(this.port, getBasePath(configManager))
|
|
3368
|
+
);
|
|
3369
|
+
await fs10.outputFile(
|
|
2901
3370
|
configManager.outputGitignorePath,
|
|
2902
3371
|
"index.html\nassets/"
|
|
2903
3372
|
);
|
|
@@ -3042,7 +3511,7 @@ ${dangerText(e.message)}
|
|
|
3042
3511
|
watchContentFiles(configManager, database, databaseLock, searchIndexer) {
|
|
3043
3512
|
const collectionContentFiles = [];
|
|
3044
3513
|
configManager.config.schema.collections.forEach((collection) => {
|
|
3045
|
-
const collectionGlob = `${
|
|
3514
|
+
const collectionGlob = `${path12.join(
|
|
3046
3515
|
configManager.contentRootPath,
|
|
3047
3516
|
collection.path
|
|
3048
3517
|
)}/**/*.${collection.format || "md"}`;
|
|
@@ -3092,8 +3561,10 @@ ${dangerText(e.message)}
|
|
|
3092
3561
|
|
|
3093
3562
|
// src/next/commands/build-command/index.ts
|
|
3094
3563
|
import crypto from "crypto";
|
|
3095
|
-
import
|
|
3096
|
-
import {
|
|
3564
|
+
import path13 from "path";
|
|
3565
|
+
import {
|
|
3566
|
+
diff
|
|
3567
|
+
} from "@graphql-inspector/core";
|
|
3097
3568
|
import { FilesystemBridge as FilesystemBridge3, buildSchema as buildSchema2 } from "@tinacms/graphql";
|
|
3098
3569
|
import { parseURL as parseURL2 } from "@tinacms/schema-tools";
|
|
3099
3570
|
import {
|
|
@@ -3101,7 +3572,7 @@ import {
|
|
|
3101
3572
|
TinaCMSSearchIndexClient
|
|
3102
3573
|
} from "@tinacms/search";
|
|
3103
3574
|
import { Command as Command3, Option as Option3 } from "clipanion";
|
|
3104
|
-
import
|
|
3575
|
+
import fs11 from "fs-extra";
|
|
3105
3576
|
import {
|
|
3106
3577
|
buildASTSchema as buildASTSchema2,
|
|
3107
3578
|
buildClientSchema,
|
|
@@ -3121,6 +3592,78 @@ var getFaqLink = (type) => {
|
|
|
3121
3592
|
}
|
|
3122
3593
|
};
|
|
3123
3594
|
|
|
3595
|
+
// src/utils/posthog.ts
|
|
3596
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
3597
|
+
import { PostHog } from "posthog-node";
|
|
3598
|
+
|
|
3599
|
+
// src/utils/fetchPostHogConfig.ts
|
|
3600
|
+
async function fetchPostHogConfig(endpointUrl) {
|
|
3601
|
+
try {
|
|
3602
|
+
const response = await fetch(endpointUrl, {
|
|
3603
|
+
method: "GET",
|
|
3604
|
+
headers: {
|
|
3605
|
+
"Content-Type": "application/json"
|
|
3606
|
+
},
|
|
3607
|
+
// Cap latency for offline / firewalled developers. Endpoint is
|
|
3608
|
+
// typically single-digit ms when reachable; a timeout returns {}
|
|
3609
|
+
// and disables telemetry for this run, which is the right behavior.
|
|
3610
|
+
signal: AbortSignal.timeout(2e3)
|
|
3611
|
+
});
|
|
3612
|
+
if (!response.ok) {
|
|
3613
|
+
throw new Error(`Failed to fetch PostHog config: ${response.statusText}`);
|
|
3614
|
+
}
|
|
3615
|
+
const config2 = await response.json();
|
|
3616
|
+
return {
|
|
3617
|
+
POSTHOG_API_KEY: config2.api_key,
|
|
3618
|
+
POSTHOG_ENDPOINT: config2.host
|
|
3619
|
+
};
|
|
3620
|
+
} catch {
|
|
3621
|
+
return {};
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
|
|
3625
|
+
// src/utils/posthog.ts
|
|
3626
|
+
function generateSessionId() {
|
|
3627
|
+
return randomUUID2();
|
|
3628
|
+
}
|
|
3629
|
+
var BuildInvokeEvent = "tinacms-cli-build-invoke";
|
|
3630
|
+
var BuildFinishedEvent = "tinacms-cli-build-finished";
|
|
3631
|
+
async function initializePostHog(configEndpoint, disableGeoip) {
|
|
3632
|
+
if (process.env.TINA_DEV === "true") return null;
|
|
3633
|
+
let apiKey;
|
|
3634
|
+
let endpoint;
|
|
3635
|
+
if (configEndpoint) {
|
|
3636
|
+
const config2 = await fetchPostHogConfig(configEndpoint);
|
|
3637
|
+
apiKey = config2.POSTHOG_API_KEY;
|
|
3638
|
+
endpoint = config2.POSTHOG_ENDPOINT;
|
|
3639
|
+
}
|
|
3640
|
+
if (!apiKey) return null;
|
|
3641
|
+
return new PostHog(apiKey, {
|
|
3642
|
+
host: endpoint,
|
|
3643
|
+
disableGeoip: disableGeoip ?? true
|
|
3644
|
+
});
|
|
3645
|
+
}
|
|
3646
|
+
function postHogCapture(client, distinctId, event, properties) {
|
|
3647
|
+
if (!client) {
|
|
3648
|
+
return;
|
|
3649
|
+
}
|
|
3650
|
+
try {
|
|
3651
|
+
client.capture({
|
|
3652
|
+
distinctId,
|
|
3653
|
+
event,
|
|
3654
|
+
properties: {
|
|
3655
|
+
...properties,
|
|
3656
|
+
system: "tinacms/cli",
|
|
3657
|
+
// Bill as anonymous events: distinctId is a throwaway per-run UUID, so
|
|
3658
|
+
// person profiles would be single-use junk at ~4x the event price.
|
|
3659
|
+
$process_person_profile: false
|
|
3660
|
+
}
|
|
3661
|
+
});
|
|
3662
|
+
} catch (error) {
|
|
3663
|
+
console.error("Error capturing event:", error);
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
|
|
3124
3667
|
// src/utils/sleep.ts
|
|
3125
3668
|
function timeout(ms) {
|
|
3126
3669
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
@@ -3238,75 +3781,6 @@ var waitForDB = async (config2, apiUrl, previewName, verbose) => {
|
|
|
3238
3781
|
});
|
|
3239
3782
|
};
|
|
3240
3783
|
|
|
3241
|
-
// src/utils/posthog.ts
|
|
3242
|
-
import { randomUUID } from "node:crypto";
|
|
3243
|
-
import { PostHog } from "posthog-node";
|
|
3244
|
-
|
|
3245
|
-
// src/utils/fetchPostHogConfig.ts
|
|
3246
|
-
async function fetchPostHogConfig(endpointUrl) {
|
|
3247
|
-
try {
|
|
3248
|
-
const response = await fetch(endpointUrl, {
|
|
3249
|
-
method: "GET",
|
|
3250
|
-
headers: {
|
|
3251
|
-
"Content-Type": "application/json"
|
|
3252
|
-
},
|
|
3253
|
-
// Cap latency for offline / firewalled developers. Endpoint is
|
|
3254
|
-
// typically single-digit ms when reachable; a timeout returns {}
|
|
3255
|
-
// and disables telemetry for this run, which is the right behavior.
|
|
3256
|
-
signal: AbortSignal.timeout(2e3)
|
|
3257
|
-
});
|
|
3258
|
-
if (!response.ok) {
|
|
3259
|
-
throw new Error(`Failed to fetch PostHog config: ${response.statusText}`);
|
|
3260
|
-
}
|
|
3261
|
-
const config2 = await response.json();
|
|
3262
|
-
return {
|
|
3263
|
-
POSTHOG_API_KEY: config2.api_key,
|
|
3264
|
-
POSTHOG_ENDPOINT: config2.host
|
|
3265
|
-
};
|
|
3266
|
-
} catch {
|
|
3267
|
-
return {};
|
|
3268
|
-
}
|
|
3269
|
-
}
|
|
3270
|
-
|
|
3271
|
-
// src/utils/posthog.ts
|
|
3272
|
-
function generateSessionId() {
|
|
3273
|
-
return randomUUID();
|
|
3274
|
-
}
|
|
3275
|
-
var BuildInvokeEvent = "tinacms-cli-build-invoke";
|
|
3276
|
-
var BuildFinishedEvent = "tinacms-cli-build-finished";
|
|
3277
|
-
async function initializePostHog(configEndpoint, disableGeoip) {
|
|
3278
|
-
if (process.env.TINA_DEV === "true") return null;
|
|
3279
|
-
let apiKey;
|
|
3280
|
-
let endpoint;
|
|
3281
|
-
if (configEndpoint) {
|
|
3282
|
-
const config2 = await fetchPostHogConfig(configEndpoint);
|
|
3283
|
-
apiKey = config2.POSTHOG_API_KEY;
|
|
3284
|
-
endpoint = config2.POSTHOG_ENDPOINT;
|
|
3285
|
-
}
|
|
3286
|
-
if (!apiKey) return null;
|
|
3287
|
-
return new PostHog(apiKey, {
|
|
3288
|
-
host: endpoint,
|
|
3289
|
-
disableGeoip: disableGeoip ?? true
|
|
3290
|
-
});
|
|
3291
|
-
}
|
|
3292
|
-
function postHogCapture(client, distinctId, event, properties) {
|
|
3293
|
-
if (!client) {
|
|
3294
|
-
return;
|
|
3295
|
-
}
|
|
3296
|
-
try {
|
|
3297
|
-
client.capture({
|
|
3298
|
-
distinctId,
|
|
3299
|
-
event,
|
|
3300
|
-
properties: {
|
|
3301
|
-
...properties,
|
|
3302
|
-
system: "tinacms/cli"
|
|
3303
|
-
}
|
|
3304
|
-
});
|
|
3305
|
-
} catch (error) {
|
|
3306
|
-
console.error("Error capturing event:", error);
|
|
3307
|
-
}
|
|
3308
|
-
}
|
|
3309
|
-
|
|
3310
3784
|
// src/next/commands/build-command/index.ts
|
|
3311
3785
|
var BuildCommand = class extends BaseCommand {
|
|
3312
3786
|
static paths = [["build"]];
|
|
@@ -3372,6 +3846,7 @@ var BuildCommand = class extends BaseCommand {
|
|
|
3372
3846
|
tinaGraphQLVersion: this.tinaGraphQLVersion,
|
|
3373
3847
|
legacyNoSDK: this.noSDK
|
|
3374
3848
|
});
|
|
3849
|
+
this.warnOnVersionSkew(configManager.rootPath);
|
|
3375
3850
|
if (this.previewName && !this.previewBaseBranch) {
|
|
3376
3851
|
logger.error(
|
|
3377
3852
|
`${dangerText(
|
|
@@ -3565,7 +4040,7 @@ ${dangerText(e.message)}
|
|
|
3565
4040
|
}
|
|
3566
4041
|
}
|
|
3567
4042
|
await buildProductionSpa(configManager, database, codegen2.productionUrl);
|
|
3568
|
-
await
|
|
4043
|
+
await fs11.outputFile(
|
|
3569
4044
|
configManager.outputGitignorePath,
|
|
3570
4045
|
"index.html\nassets/"
|
|
3571
4046
|
);
|
|
@@ -3950,7 +4425,7 @@ Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
|
|
|
3950
4425
|
}
|
|
3951
4426
|
const localTinaSchema = JSON.parse(
|
|
3952
4427
|
await database.bridge.get(
|
|
3953
|
-
|
|
4428
|
+
path13.join(database.tinaDirectory, "__generated__", "_schema.json")
|
|
3954
4429
|
)
|
|
3955
4430
|
);
|
|
3956
4431
|
localTinaSchema.version = void 0;
|
|
@@ -4313,19 +4788,19 @@ var AuditCommand = class extends Command4 {
|
|
|
4313
4788
|
import { Command as Command6, Option as Option6 } from "clipanion";
|
|
4314
4789
|
|
|
4315
4790
|
// src/cmds/init/detectEnvironment.ts
|
|
4316
|
-
import
|
|
4317
|
-
import
|
|
4791
|
+
import fs13 from "fs-extra";
|
|
4792
|
+
import path15 from "path";
|
|
4318
4793
|
|
|
4319
4794
|
// src/cmds/init/astro-config-detect.ts
|
|
4320
|
-
import
|
|
4321
|
-
import
|
|
4795
|
+
import fs12 from "fs";
|
|
4796
|
+
import path14 from "path";
|
|
4322
4797
|
var isDefaultAstroConfig = (source) => {
|
|
4323
4798
|
const stripped = source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "").replace(/\s+/g, " ").trim();
|
|
4324
4799
|
return /^import\s*\{\s*defineConfig\s*\}\s*from\s*['"]astro\/config['"]\s*;?\s*export\s+default\s+defineConfig\(\s*\{\s*\}\s*\)\s*;?$/.test(
|
|
4325
4800
|
stripped
|
|
4326
4801
|
);
|
|
4327
4802
|
};
|
|
4328
|
-
var findExistingPaths = (baseDir, relPaths) => relPaths.filter((rel) =>
|
|
4803
|
+
var findExistingPaths = (baseDir, relPaths) => relPaths.filter((rel) => fs12.existsSync(path14.join(baseDir, rel)));
|
|
4329
4804
|
var parseAstroMajor = (version2) => {
|
|
4330
4805
|
const match = version2 ? String(version2).match(/(\d+)/) : null;
|
|
4331
4806
|
return match ? Number(match[1]) : void 0;
|
|
@@ -4341,20 +4816,20 @@ var checkGitignoreForItem = async ({
|
|
|
4341
4816
|
baseDir,
|
|
4342
4817
|
line
|
|
4343
4818
|
}) => {
|
|
4344
|
-
const gitignoreContent =
|
|
4819
|
+
const gitignoreContent = fs13.readFileSync(path15.join(baseDir, ".gitignore")).toString();
|
|
4345
4820
|
return gitignoreContent.split("\n").some((item) => item === line);
|
|
4346
4821
|
};
|
|
4347
4822
|
var makeGeneratedFile = async (name2, generatedFileType, parentPath, opts) => {
|
|
4348
4823
|
const result = {
|
|
4349
|
-
fullPathTS:
|
|
4824
|
+
fullPathTS: path15.join(
|
|
4350
4825
|
parentPath,
|
|
4351
4826
|
`${name2}.${opts?.typescriptSuffix || opts?.extensionOverride || "ts"}`
|
|
4352
4827
|
),
|
|
4353
|
-
fullPathJS:
|
|
4828
|
+
fullPathJS: path15.join(
|
|
4354
4829
|
parentPath,
|
|
4355
4830
|
`${name2}.${opts?.extensionOverride || "js"}`
|
|
4356
4831
|
),
|
|
4357
|
-
fullPathOverride: opts?.extensionOverride ?
|
|
4832
|
+
fullPathOverride: opts?.extensionOverride ? path15.join(parentPath, `${name2}.${opts?.extensionOverride}`) : "",
|
|
4358
4833
|
generatedFileType,
|
|
4359
4834
|
name: name2,
|
|
4360
4835
|
parentPath,
|
|
@@ -4372,8 +4847,8 @@ var makeGeneratedFile = async (name2, generatedFileType, parentPath, opts) => {
|
|
|
4372
4847
|
};
|
|
4373
4848
|
}
|
|
4374
4849
|
};
|
|
4375
|
-
result.typescriptExists = await
|
|
4376
|
-
result.javascriptExists = await
|
|
4850
|
+
result.typescriptExists = await fs13.pathExists(result.fullPathTS);
|
|
4851
|
+
result.javascriptExists = await fs13.pathExists(result.fullPathJS);
|
|
4377
4852
|
return result;
|
|
4378
4853
|
};
|
|
4379
4854
|
var detectEnvironment = async ({
|
|
@@ -4382,21 +4857,21 @@ var detectEnvironment = async ({
|
|
|
4382
4857
|
rootPath,
|
|
4383
4858
|
debug = false
|
|
4384
4859
|
}) => {
|
|
4385
|
-
const hasForestryConfig = await
|
|
4386
|
-
|
|
4860
|
+
const hasForestryConfig = await fs13.pathExists(
|
|
4861
|
+
path15.join(pathToForestryConfig, ".forestry", "settings.yml")
|
|
4387
4862
|
);
|
|
4388
|
-
const sampleContentPath =
|
|
4863
|
+
const sampleContentPath = path15.join(
|
|
4389
4864
|
baseDir,
|
|
4390
4865
|
"content",
|
|
4391
4866
|
"posts",
|
|
4392
4867
|
"hello-world.md"
|
|
4393
4868
|
);
|
|
4394
|
-
const usingSrc =
|
|
4395
|
-
const tinaFolder =
|
|
4869
|
+
const usingSrc = fs13.pathExistsSync(path15.join(baseDir, "src")) && (fs13.pathExistsSync(path15.join(baseDir, "src", "app")) || fs13.pathExistsSync(path15.join(baseDir, "src", "pages")));
|
|
4870
|
+
const tinaFolder = path15.join(baseDir, "tina");
|
|
4396
4871
|
const tinaConfigExists = Boolean(
|
|
4397
4872
|
// Does the tina folder exist?
|
|
4398
|
-
await
|
|
4399
|
-
(await
|
|
4873
|
+
await fs13.pathExists(tinaFolder) && // Does the tina folder contain a config file?
|
|
4874
|
+
(await fs13.readdir(tinaFolder)).find((x) => x.includes("config"))
|
|
4400
4875
|
);
|
|
4401
4876
|
const pagesDir = [baseDir, usingSrc ? "src" : false, "pages"].filter(
|
|
4402
4877
|
Boolean
|
|
@@ -4408,12 +4883,12 @@ var detectEnvironment = async ({
|
|
|
4408
4883
|
"next-api-handler": await makeGeneratedFile(
|
|
4409
4884
|
"[...routes]",
|
|
4410
4885
|
"next-api-handler",
|
|
4411
|
-
|
|
4886
|
+
path15.join(...pagesDir, "api", "tina")
|
|
4412
4887
|
),
|
|
4413
4888
|
"reactive-example": await makeGeneratedFile(
|
|
4414
4889
|
"[filename]",
|
|
4415
4890
|
"reactive-example",
|
|
4416
|
-
|
|
4891
|
+
path15.join(...pagesDir, "demo", "blog"),
|
|
4417
4892
|
{
|
|
4418
4893
|
typescriptSuffix: "tsx"
|
|
4419
4894
|
}
|
|
@@ -4421,24 +4896,24 @@ var detectEnvironment = async ({
|
|
|
4421
4896
|
"users-json": await makeGeneratedFile(
|
|
4422
4897
|
"index",
|
|
4423
4898
|
"users-json",
|
|
4424
|
-
|
|
4899
|
+
path15.join(baseDir, "content", "users"),
|
|
4425
4900
|
{ extensionOverride: "json" }
|
|
4426
4901
|
),
|
|
4427
4902
|
"sample-content": await makeGeneratedFile(
|
|
4428
4903
|
"hello-world",
|
|
4429
4904
|
"sample-content",
|
|
4430
|
-
|
|
4905
|
+
path15.join(baseDir, "content", "posts"),
|
|
4431
4906
|
{ extensionOverride: "md" }
|
|
4432
4907
|
)
|
|
4433
4908
|
};
|
|
4434
|
-
const hasSampleContent = await
|
|
4435
|
-
const hasPackageJSON = await
|
|
4909
|
+
const hasSampleContent = await fs13.pathExists(sampleContentPath);
|
|
4910
|
+
const hasPackageJSON = await fs13.pathExists("package.json");
|
|
4436
4911
|
let hasTinaDeps = false;
|
|
4437
4912
|
let hasReactDep = false;
|
|
4438
4913
|
let astroMajor;
|
|
4439
4914
|
if (hasPackageJSON) {
|
|
4440
4915
|
try {
|
|
4441
|
-
const packageJSON = await
|
|
4916
|
+
const packageJSON = await fs13.readJSON("package.json");
|
|
4442
4917
|
const deps = [];
|
|
4443
4918
|
if (packageJSON?.dependencies) {
|
|
4444
4919
|
deps.push(...Object.keys(packageJSON.dependencies));
|
|
@@ -4461,7 +4936,7 @@ var detectEnvironment = async ({
|
|
|
4461
4936
|
);
|
|
4462
4937
|
}
|
|
4463
4938
|
}
|
|
4464
|
-
const hasGitIgnore = await
|
|
4939
|
+
const hasGitIgnore = await fs13.pathExists(path15.join(".gitignore"));
|
|
4465
4940
|
const hasGitIgnoreNodeModules = hasGitIgnore && await checkGitignoreForItem({ baseDir, line: "node_modules" });
|
|
4466
4941
|
const hasEnvTina = hasGitIgnore && await checkGitignoreForItem({ baseDir, line: ".env.tina" });
|
|
4467
4942
|
const hasGitIgnoreEnv = hasGitIgnore && await checkGitignoreForItem({ baseDir, line: ".env" });
|
|
@@ -4471,9 +4946,9 @@ var detectEnvironment = async ({
|
|
|
4471
4946
|
});
|
|
4472
4947
|
let frontMatterFormat;
|
|
4473
4948
|
if (hasForestryConfig) {
|
|
4474
|
-
const hugoConfigPath =
|
|
4475
|
-
if (await
|
|
4476
|
-
const hugoConfig = await
|
|
4949
|
+
const hugoConfigPath = path15.join(rootPath, "config.toml");
|
|
4950
|
+
if (await fs13.pathExists(hugoConfigPath)) {
|
|
4951
|
+
const hugoConfig = await fs13.readFile(hugoConfigPath, "utf8");
|
|
4477
4952
|
const metaDataFormat = hugoConfig.toString().match(/metaDataFormat = "(.*)"/)?.[1];
|
|
4478
4953
|
if (metaDataFormat && (metaDataFormat === "yaml" || metaDataFormat === "toml" || metaDataFormat === "json")) {
|
|
4479
4954
|
frontMatterFormat = metaDataFormat;
|
|
@@ -5098,6 +5573,7 @@ var CLICommand = class {
|
|
|
5098
5573
|
constructor(handler) {
|
|
5099
5574
|
this.handler = handler;
|
|
5100
5575
|
}
|
|
5576
|
+
handler;
|
|
5101
5577
|
async execute(params) {
|
|
5102
5578
|
await this.handler.setup(params);
|
|
5103
5579
|
const environment = await this.handler.detectEnvironment(params);
|
|
@@ -5107,19 +5583,19 @@ var CLICommand = class {
|
|
|
5107
5583
|
};
|
|
5108
5584
|
|
|
5109
5585
|
// src/cmds/init/apply.ts
|
|
5110
|
-
import
|
|
5586
|
+
import path20 from "path";
|
|
5111
5587
|
|
|
5112
5588
|
// src/cmds/forestry-migrate/index.ts
|
|
5113
|
-
import
|
|
5114
|
-
import
|
|
5589
|
+
import fs15 from "fs-extra";
|
|
5590
|
+
import path17 from "path";
|
|
5115
5591
|
import yaml2 from "js-yaml";
|
|
5116
5592
|
import pkg from "minimatch";
|
|
5117
5593
|
import { parseFile, stringifyFile } from "@tinacms/graphql";
|
|
5118
5594
|
import { CONTENT_FORMATS } from "@tinacms/schema-tools";
|
|
5119
5595
|
|
|
5120
5596
|
// src/cmds/forestry-migrate/util/index.ts
|
|
5121
|
-
import
|
|
5122
|
-
import
|
|
5597
|
+
import fs14 from "fs-extra";
|
|
5598
|
+
import path16 from "path";
|
|
5123
5599
|
import yaml from "js-yaml";
|
|
5124
5600
|
import z2 from "zod";
|
|
5125
5601
|
|
|
@@ -5561,7 +6037,7 @@ var transformForestryFieldsToTinaFields = ({
|
|
|
5561
6037
|
return tinaFields;
|
|
5562
6038
|
};
|
|
5563
6039
|
var getFieldsFromTemplates = ({ tem, pathToForestryConfig, skipBlocks = false }) => {
|
|
5564
|
-
const templatePath =
|
|
6040
|
+
const templatePath = path16.join(
|
|
5565
6041
|
pathToForestryConfig,
|
|
5566
6042
|
".forestry",
|
|
5567
6043
|
"front_matter",
|
|
@@ -5570,7 +6046,7 @@ var getFieldsFromTemplates = ({ tem, pathToForestryConfig, skipBlocks = false })
|
|
|
5570
6046
|
);
|
|
5571
6047
|
let templateString = "";
|
|
5572
6048
|
try {
|
|
5573
|
-
templateString =
|
|
6049
|
+
templateString = fs14.readFileSync(templatePath).toString();
|
|
5574
6050
|
} catch {
|
|
5575
6051
|
throw new Error(
|
|
5576
6052
|
`Could not find template ${tem} at ${templatePath}
|
|
@@ -5629,9 +6105,9 @@ function checkExt(ext) {
|
|
|
5629
6105
|
var generateAllTemplates = async ({
|
|
5630
6106
|
pathToForestryConfig
|
|
5631
6107
|
}) => {
|
|
5632
|
-
const allTemplates = (await
|
|
5633
|
-
|
|
5634
|
-
)).map((tem) =>
|
|
6108
|
+
const allTemplates = (await fs15.readdir(
|
|
6109
|
+
path17.join(pathToForestryConfig, ".forestry", "front_matter", "templates")
|
|
6110
|
+
)).map((tem) => path17.basename(tem, ".yml"));
|
|
5635
6111
|
const templateMap = /* @__PURE__ */ new Map();
|
|
5636
6112
|
const proms = allTemplates.map(async (tem) => {
|
|
5637
6113
|
try {
|
|
@@ -5776,9 +6252,9 @@ var generateCollectionFromForestrySection = (args) => {
|
|
|
5776
6252
|
return c;
|
|
5777
6253
|
} else if (section.type === "document") {
|
|
5778
6254
|
const filePath = section.path;
|
|
5779
|
-
const extname =
|
|
5780
|
-
const fileName =
|
|
5781
|
-
const dir =
|
|
6255
|
+
const extname = path17.extname(filePath);
|
|
6256
|
+
const fileName = path17.basename(filePath, extname);
|
|
6257
|
+
const dir = path17.dirname(filePath);
|
|
5782
6258
|
const ext = checkExt(extname);
|
|
5783
6259
|
if (ext) {
|
|
5784
6260
|
const fields = [];
|
|
@@ -5840,8 +6316,8 @@ var generateCollections = async ({
|
|
|
5840
6316
|
templateMap,
|
|
5841
6317
|
usingTypescript
|
|
5842
6318
|
});
|
|
5843
|
-
const forestryConfig = await
|
|
5844
|
-
|
|
6319
|
+
const forestryConfig = await fs15.readFile(
|
|
6320
|
+
path17.join(pathToForestryConfig, ".forestry", "settings.yml")
|
|
5845
6321
|
);
|
|
5846
6322
|
rewriteTemplateKeysInDocs({
|
|
5847
6323
|
templateMap,
|
|
@@ -5871,12 +6347,12 @@ var rewriteTemplateKeysInDocs = (args) => {
|
|
|
5871
6347
|
const { templateObj } = templateMap.get(templateKey);
|
|
5872
6348
|
templateObj?.pages?.forEach((page) => {
|
|
5873
6349
|
try {
|
|
5874
|
-
const filePath =
|
|
5875
|
-
if (
|
|
6350
|
+
const filePath = path17.join(page);
|
|
6351
|
+
if (fs15.lstatSync(filePath).isDirectory()) {
|
|
5876
6352
|
return;
|
|
5877
6353
|
}
|
|
5878
|
-
const extname =
|
|
5879
|
-
const fileContent =
|
|
6354
|
+
const extname = path17.extname(filePath);
|
|
6355
|
+
const fileContent = fs15.readFileSync(filePath).toString();
|
|
5880
6356
|
const content = parseFile(
|
|
5881
6357
|
fileContent,
|
|
5882
6358
|
extname,
|
|
@@ -5887,7 +6363,7 @@ var rewriteTemplateKeysInDocs = (args) => {
|
|
|
5887
6363
|
_template: stringifyLabel(templateKey),
|
|
5888
6364
|
...content
|
|
5889
6365
|
};
|
|
5890
|
-
|
|
6366
|
+
fs15.writeFileSync(
|
|
5891
6367
|
filePath,
|
|
5892
6368
|
stringifyFile(newContent, extname, true, markdownParseConfig)
|
|
5893
6369
|
);
|
|
@@ -5902,12 +6378,12 @@ var rewriteTemplateKeysInDocs = (args) => {
|
|
|
5902
6378
|
|
|
5903
6379
|
// src/cmds/init/apply.ts
|
|
5904
6380
|
import { Telemetry as Telemetry3 } from "@tinacms/metrics";
|
|
5905
|
-
import
|
|
6381
|
+
import fs19 from "fs-extra";
|
|
5906
6382
|
|
|
5907
6383
|
// src/next/commands/codemod-command/index.ts
|
|
5908
6384
|
import { Command as Command5, Option as Option5 } from "clipanion";
|
|
5909
|
-
import
|
|
5910
|
-
import
|
|
6385
|
+
import fs16 from "fs-extra";
|
|
6386
|
+
import path18 from "path";
|
|
5911
6387
|
var CodemodCommand = class extends Command5 {
|
|
5912
6388
|
static paths = [["codemod"], ["codemod", "move-tina-folder"]];
|
|
5913
6389
|
rootPath = Option5.String("--rootPath", {
|
|
@@ -5948,13 +6424,13 @@ var moveTinaFolder = async (rootPath = process.cwd()) => {
|
|
|
5948
6424
|
logger.error(e.message);
|
|
5949
6425
|
process.exit(1);
|
|
5950
6426
|
}
|
|
5951
|
-
const tinaDestination =
|
|
5952
|
-
if (await
|
|
6427
|
+
const tinaDestination = path18.join(configManager.rootPath, "tina");
|
|
6428
|
+
if (await fs16.existsSync(tinaDestination)) {
|
|
5953
6429
|
logger.info(
|
|
5954
6430
|
`Folder already exists at ${tinaDestination}. Either delete this folder to complete the codemod, or ensure you have properly copied your config from the ".tina" folder.`
|
|
5955
6431
|
);
|
|
5956
6432
|
} else {
|
|
5957
|
-
await
|
|
6433
|
+
await fs16.moveSync(configManager.tinaFolderPath, tinaDestination);
|
|
5958
6434
|
await writeGitignore(configManager.rootPath);
|
|
5959
6435
|
logger.info(
|
|
5960
6436
|
"Move to 'tina' folder complete. Be sure to update any imports of the autogenerated client!"
|
|
@@ -5962,8 +6438,8 @@ var moveTinaFolder = async (rootPath = process.cwd()) => {
|
|
|
5962
6438
|
}
|
|
5963
6439
|
};
|
|
5964
6440
|
var writeGitignore = async (rootPath) => {
|
|
5965
|
-
await
|
|
5966
|
-
|
|
6441
|
+
await fs16.outputFileSync(
|
|
6442
|
+
path18.join(rootPath, "tina", ".gitignore"),
|
|
5967
6443
|
"__generated__"
|
|
5968
6444
|
);
|
|
5969
6445
|
};
|
|
@@ -6022,7 +6498,7 @@ const BlogPage = (props) => {
|
|
|
6022
6498
|
{' '}
|
|
6023
6499
|
Check out this guide
|
|
6024
6500
|
</a>{' '}
|
|
6025
|
-
to see how add TinaCMS to an existing Next.js site.
|
|
6501
|
+
to see how to add TinaCMS to an existing Next.js site.
|
|
6026
6502
|
</div>
|
|
6027
6503
|
</div>
|
|
6028
6504
|
</>
|
|
@@ -6474,8 +6950,8 @@ function extendAstroScripts(scripts) {
|
|
|
6474
6950
|
}
|
|
6475
6951
|
|
|
6476
6952
|
// src/cmds/init/astro-visual-editing.ts
|
|
6477
|
-
import
|
|
6478
|
-
import
|
|
6953
|
+
import fs17 from "fs-extra";
|
|
6954
|
+
import path19 from "path";
|
|
6479
6955
|
var TS_NOCHECK = "// @ts-nocheck (generated types/client appear after your first tinacms dev run)\n";
|
|
6480
6956
|
var DEMO_FILES = {
|
|
6481
6957
|
"src/lib/tina/data.ts": `${TS_NOCHECK}import { requestWithMetadata } from '@tinacms/astro/data';
|
|
@@ -6746,8 +7222,8 @@ var ASTRO_CONFIG_FILES = [
|
|
|
6746
7222
|
"astro.config.cjs",
|
|
6747
7223
|
"astro.config.cts"
|
|
6748
7224
|
];
|
|
6749
|
-
var findAstroConfig = (baseDir) => ASTRO_CONFIG_FILES.map((file) =>
|
|
6750
|
-
(p) =>
|
|
7225
|
+
var findAstroConfig = (baseDir) => ASTRO_CONFIG_FILES.map((file) => path19.join(baseDir, file)).find(
|
|
7226
|
+
(p) => fs17.existsSync(p)
|
|
6751
7227
|
);
|
|
6752
7228
|
var setupAstroVisualEditing = ({
|
|
6753
7229
|
baseDir
|
|
@@ -6765,17 +7241,17 @@ var setupAstroVisualEditing = ({
|
|
|
6765
7241
|
return { configHandled: true, demoScaffolded: false };
|
|
6766
7242
|
}
|
|
6767
7243
|
for (const rel of relPaths) {
|
|
6768
|
-
|
|
7244
|
+
fs17.outputFileSync(path19.join(baseDir, rel), DEMO_FILES[rel]);
|
|
6769
7245
|
}
|
|
6770
7246
|
logger.info("Adding a visual-editing demo at /tinacms-demo... \u2705");
|
|
6771
7247
|
const configPath = findAstroConfig(baseDir);
|
|
6772
7248
|
if (!configPath) {
|
|
6773
|
-
|
|
7249
|
+
fs17.writeFileSync(path19.join(baseDir, "astro.config.mjs"), ASTRO_CONFIG);
|
|
6774
7250
|
logger.info("Creating astro.config for visual editing... \u2705");
|
|
6775
7251
|
return { configHandled: true, demoScaffolded: true };
|
|
6776
7252
|
}
|
|
6777
|
-
if (isDefaultAstroConfig(
|
|
6778
|
-
|
|
7253
|
+
if (isDefaultAstroConfig(fs17.readFileSync(configPath).toString())) {
|
|
7254
|
+
fs17.writeFileSync(configPath, ASTRO_CONFIG);
|
|
6779
7255
|
logger.info("Wiring astro.config for visual editing... \u2705");
|
|
6780
7256
|
return { configHandled: true, demoScaffolded: true };
|
|
6781
7257
|
}
|
|
@@ -6787,7 +7263,7 @@ var logAstroConfigGuidance = () => {
|
|
|
6787
7263
|
|
|
6788
7264
|
// src/cmds/init/codegen/index.ts
|
|
6789
7265
|
import ts2 from "typescript";
|
|
6790
|
-
import
|
|
7266
|
+
import fs18 from "fs-extra";
|
|
6791
7267
|
|
|
6792
7268
|
// src/cmds/init/codegen/util.ts
|
|
6793
7269
|
import ts from "typescript";
|
|
@@ -7024,7 +7500,7 @@ var addSelfHostedTinaAuthToConfig = async (config2, configFile) => {
|
|
|
7024
7500
|
const pathToConfig = configFile.resolve(config2.typescript).path;
|
|
7025
7501
|
const sourceFile = ts2.createSourceFile(
|
|
7026
7502
|
pathToConfig,
|
|
7027
|
-
|
|
7503
|
+
fs18.readFileSync(pathToConfig, "utf8"),
|
|
7028
7504
|
config2.typescript ? ts2.ScriptTarget.Latest : ts2.ScriptTarget.ESNext
|
|
7029
7505
|
);
|
|
7030
7506
|
const { configImports, configAuthProviderClass, extraTinaCollections } = config2.authProvider;
|
|
@@ -7074,7 +7550,7 @@ var addSelfHostedTinaAuthToConfig = async (config2, configFile) => {
|
|
|
7074
7550
|
)
|
|
7075
7551
|
].map((visitor) => makeTransformer(visitor))
|
|
7076
7552
|
);
|
|
7077
|
-
return
|
|
7553
|
+
return fs18.writeFile(
|
|
7078
7554
|
pathToConfig,
|
|
7079
7555
|
ts2.createPrinter({ omitTrailingSemicolon: true }).printFile(transformedSourceFileResult.transformed[0])
|
|
7080
7556
|
);
|
|
@@ -7200,8 +7676,8 @@ async function apply({
|
|
|
7200
7676
|
await addConfigFile({
|
|
7201
7677
|
configArgs: {
|
|
7202
7678
|
config: config2,
|
|
7203
|
-
publicFolder:
|
|
7204
|
-
|
|
7679
|
+
publicFolder: path20.join(
|
|
7680
|
+
path20.relative(process.cwd(), pathToForestryConfig),
|
|
7205
7681
|
config2.publicFolder
|
|
7206
7682
|
),
|
|
7207
7683
|
collections,
|
|
@@ -7278,8 +7754,8 @@ var createPackageJSON = async () => {
|
|
|
7278
7754
|
};
|
|
7279
7755
|
var createGitignore = async ({ baseDir }) => {
|
|
7280
7756
|
logger.info(logText("No .gitignore found, creating one"));
|
|
7281
|
-
|
|
7282
|
-
|
|
7757
|
+
fs19.outputFileSync(
|
|
7758
|
+
path20.join(baseDir, ".gitignore"),
|
|
7283
7759
|
"node_modules\ntina/__generated__\n"
|
|
7284
7760
|
);
|
|
7285
7761
|
};
|
|
@@ -7288,11 +7764,11 @@ var updateGitIgnore = async ({
|
|
|
7288
7764
|
items
|
|
7289
7765
|
}) => {
|
|
7290
7766
|
logger.info(logText(`Adding ${items.join(",")} to .gitignore`));
|
|
7291
|
-
const gitignoreContent =
|
|
7767
|
+
const gitignoreContent = fs19.readFileSync(path20.join(baseDir, ".gitignore")).toString();
|
|
7292
7768
|
const newGitignoreContent = [...gitignoreContent.split("\n"), ...items].join(
|
|
7293
7769
|
"\n"
|
|
7294
7770
|
);
|
|
7295
|
-
await
|
|
7771
|
+
await fs19.writeFile(path20.join(baseDir, ".gitignore"), newGitignoreContent);
|
|
7296
7772
|
};
|
|
7297
7773
|
var addDependencies = async (config2, env, params) => {
|
|
7298
7774
|
const { packageManager } = config2;
|
|
@@ -7369,22 +7845,22 @@ var writeGeneratedFile = async ({
|
|
|
7369
7845
|
content,
|
|
7370
7846
|
typescript
|
|
7371
7847
|
}) => {
|
|
7372
|
-
const { exists, path:
|
|
7848
|
+
const { exists, path: path22, parentPath } = generatedFile.resolve(typescript);
|
|
7373
7849
|
if (exists) {
|
|
7374
7850
|
if (overwrite) {
|
|
7375
|
-
logger.info(`Overwriting file at ${
|
|
7376
|
-
|
|
7851
|
+
logger.info(`Overwriting file at ${path22}... \u2705`);
|
|
7852
|
+
fs19.outputFileSync(path22, content);
|
|
7377
7853
|
} else {
|
|
7378
|
-
logger.info(`Not overwriting file at ${
|
|
7854
|
+
logger.info(`Not overwriting file at ${path22}.`);
|
|
7379
7855
|
logger.info(
|
|
7380
|
-
logText(`Please add the following to ${
|
|
7856
|
+
logText(`Please add the following to ${path22}:
|
|
7381
7857
|
${indentText(content)}}`)
|
|
7382
7858
|
);
|
|
7383
7859
|
}
|
|
7384
7860
|
} else {
|
|
7385
|
-
logger.info(`Adding file at ${
|
|
7386
|
-
await
|
|
7387
|
-
|
|
7861
|
+
logger.info(`Adding file at ${path22}... \u2705`);
|
|
7862
|
+
await fs19.ensureDir(parentPath);
|
|
7863
|
+
fs19.outputFileSync(path22, content);
|
|
7388
7864
|
}
|
|
7389
7865
|
};
|
|
7390
7866
|
var addConfigFile = async ({
|
|
@@ -7462,7 +7938,7 @@ var addContentFile = async ({
|
|
|
7462
7938
|
return () => ({
|
|
7463
7939
|
exists: env.sampleContentExists,
|
|
7464
7940
|
path: env.sampleContentPath,
|
|
7465
|
-
parentPath:
|
|
7941
|
+
parentPath: path20.dirname(env.sampleContentPath)
|
|
7466
7942
|
});
|
|
7467
7943
|
}
|
|
7468
7944
|
},
|
|
@@ -7486,10 +7962,10 @@ ${titleText(" TinaCMS ")} backend initialized!`));
|
|
|
7486
7962
|
return `${x.key}=${x.value || "***"}`;
|
|
7487
7963
|
}).join("\n") + `
|
|
7488
7964
|
TINA_PUBLIC_IS_LOCAL=true`;
|
|
7489
|
-
const envFile =
|
|
7490
|
-
if (!
|
|
7965
|
+
const envFile = path20.join(process.cwd(), ".env");
|
|
7966
|
+
if (!fs19.existsSync(envFile)) {
|
|
7491
7967
|
logger.info(`Adding .env file to your project... \u2705`);
|
|
7492
|
-
|
|
7968
|
+
fs19.writeFileSync(envFile, envFileText);
|
|
7493
7969
|
} else {
|
|
7494
7970
|
logger.info(
|
|
7495
7971
|
"Please add the following environment variables to your .env file"
|
|
@@ -7566,7 +8042,7 @@ var addReactiveFile = {
|
|
|
7566
8042
|
baseDir,
|
|
7567
8043
|
dataLayer
|
|
7568
8044
|
}) => {
|
|
7569
|
-
const packageJsonPath =
|
|
8045
|
+
const packageJsonPath = path20.join(baseDir, "package.json");
|
|
7570
8046
|
await writeGeneratedFile({
|
|
7571
8047
|
generatedFile,
|
|
7572
8048
|
typescript: config2.typescript,
|
|
@@ -7579,7 +8055,7 @@ var addReactiveFile = {
|
|
|
7579
8055
|
})
|
|
7580
8056
|
});
|
|
7581
8057
|
logger.info("Adding a nextjs example... \u2705");
|
|
7582
|
-
const packageJson = JSON.parse(
|
|
8058
|
+
const packageJson = JSON.parse(fs19.readFileSync(packageJsonPath).toString());
|
|
7583
8059
|
const scripts = packageJson.scripts || {};
|
|
7584
8060
|
const updatedPackageJson = JSON.stringify(
|
|
7585
8061
|
{
|
|
@@ -7592,15 +8068,15 @@ var addReactiveFile = {
|
|
|
7592
8068
|
null,
|
|
7593
8069
|
2
|
|
7594
8070
|
);
|
|
7595
|
-
|
|
8071
|
+
fs19.writeFileSync(packageJsonPath, updatedPackageJson);
|
|
7596
8072
|
}
|
|
7597
8073
|
};
|
|
7598
8074
|
var updateAstroPackageJson = async ({ baseDir }) => {
|
|
7599
|
-
const packageJsonPath =
|
|
7600
|
-
if (!
|
|
8075
|
+
const packageJsonPath = path20.join(baseDir, "package.json");
|
|
8076
|
+
if (!fs19.existsSync(packageJsonPath)) {
|
|
7601
8077
|
return;
|
|
7602
8078
|
}
|
|
7603
|
-
const packageJson = JSON.parse(
|
|
8079
|
+
const packageJson = JSON.parse(fs19.readFileSync(packageJsonPath).toString());
|
|
7604
8080
|
const scripts = packageJson.scripts || {};
|
|
7605
8081
|
const updatedPackageJson = JSON.stringify(
|
|
7606
8082
|
{
|
|
@@ -7610,7 +8086,7 @@ var updateAstroPackageJson = async ({ baseDir }) => {
|
|
|
7610
8086
|
null,
|
|
7611
8087
|
2
|
|
7612
8088
|
);
|
|
7613
|
-
|
|
8089
|
+
fs19.writeFileSync(packageJsonPath, updatedPackageJson);
|
|
7614
8090
|
logger.info("Updating package.json scripts for Astro... \u2705");
|
|
7615
8091
|
};
|
|
7616
8092
|
function execShellCommand(cmd) {
|
|
@@ -7810,8 +8286,8 @@ var SearchIndexCommand = class extends Command7 {
|
|
|
7810
8286
|
import { Command as Command8, Option as Option8 } from "clipanion";
|
|
7811
8287
|
|
|
7812
8288
|
// src/next/commands/doctor-command/doctor.ts
|
|
7813
|
-
import
|
|
7814
|
-
import
|
|
8289
|
+
import path21 from "path";
|
|
8290
|
+
import fs20 from "fs-extra";
|
|
7815
8291
|
import yaml3 from "js-yaml";
|
|
7816
8292
|
var DEPENDENCY_TYPES = [
|
|
7817
8293
|
"dependencies",
|
|
@@ -7826,7 +8302,7 @@ var LOCAL_REFERENCE_PREFIXES = [
|
|
|
7826
8302
|
"portal:",
|
|
7827
8303
|
"workspace:"
|
|
7828
8304
|
];
|
|
7829
|
-
function
|
|
8305
|
+
function isTinaPackage2(name2) {
|
|
7830
8306
|
return name2 === "tinacms" || name2 === "create-tina-app" || name2.startsWith("@tinacms/") || name2.startsWith("tinacms-") || name2.startsWith("next-tinacms-");
|
|
7831
8307
|
}
|
|
7832
8308
|
function getTinaDependencies(packageJson) {
|
|
@@ -7835,7 +8311,7 @@ function getTinaDependencies(packageJson) {
|
|
|
7835
8311
|
for (const [name2, declared] of Object.entries(
|
|
7836
8312
|
packageJson[dependencyType] || {}
|
|
7837
8313
|
)) {
|
|
7838
|
-
if (!
|
|
8314
|
+
if (!isTinaPackage2(name2) || dependencies.has(name2)) continue;
|
|
7839
8315
|
dependencies.set(name2, { name: name2, declared, dependencyType });
|
|
7840
8316
|
}
|
|
7841
8317
|
}
|
|
@@ -7844,11 +8320,11 @@ function getTinaDependencies(packageJson) {
|
|
|
7844
8320
|
);
|
|
7845
8321
|
}
|
|
7846
8322
|
async function readProjectPackageJson(rootPath) {
|
|
7847
|
-
const packageJsonPath =
|
|
7848
|
-
if (!await
|
|
8323
|
+
const packageJsonPath = path21.join(rootPath, "package.json");
|
|
8324
|
+
if (!await fs20.pathExists(packageJsonPath)) {
|
|
7849
8325
|
throw new Error(`No package.json found at ${packageJsonPath}`);
|
|
7850
8326
|
}
|
|
7851
|
-
return
|
|
8327
|
+
return fs20.readJSON(packageJsonPath);
|
|
7852
8328
|
}
|
|
7853
8329
|
async function resolveInstalledVersions({
|
|
7854
8330
|
rootPath,
|
|
@@ -7971,14 +8447,14 @@ function isLocalReference(version2) {
|
|
|
7971
8447
|
);
|
|
7972
8448
|
}
|
|
7973
8449
|
async function readNodeModulesVersion(rootPath, packageName) {
|
|
7974
|
-
const packageJsonPath =
|
|
8450
|
+
const packageJsonPath = path21.join(
|
|
7975
8451
|
rootPath,
|
|
7976
8452
|
"node_modules",
|
|
7977
8453
|
...packageName.split("/"),
|
|
7978
8454
|
"package.json"
|
|
7979
8455
|
);
|
|
7980
|
-
if (!await
|
|
7981
|
-
const packageJson = await
|
|
8456
|
+
if (!await fs20.pathExists(packageJsonPath)) return void 0;
|
|
8457
|
+
const packageJson = await fs20.readJSON(packageJsonPath);
|
|
7982
8458
|
return typeof packageJson.version === "string" ? packageJson.version : void 0;
|
|
7983
8459
|
}
|
|
7984
8460
|
async function readLockfileVersions(rootPath) {
|
|
@@ -7994,54 +8470,54 @@ async function readLockfileVersions(rootPath) {
|
|
|
7994
8470
|
return /* @__PURE__ */ new Map();
|
|
7995
8471
|
}
|
|
7996
8472
|
async function readPackageLockVersions(rootPath) {
|
|
7997
|
-
const lockfilePath =
|
|
8473
|
+
const lockfilePath = path21.join(rootPath, "package-lock.json");
|
|
7998
8474
|
const versions = /* @__PURE__ */ new Map();
|
|
7999
|
-
if (!await
|
|
8000
|
-
const lockfile = await
|
|
8475
|
+
if (!await fs20.pathExists(lockfilePath)) return versions;
|
|
8476
|
+
const lockfile = await fs20.readJSON(lockfilePath);
|
|
8001
8477
|
for (const [key, value] of Object.entries(lockfile.packages || {})) {
|
|
8002
8478
|
if (!key.startsWith("node_modules/")) continue;
|
|
8003
8479
|
const name2 = key.replace(/^node_modules\//, "");
|
|
8004
8480
|
const version2 = value.version;
|
|
8005
|
-
if (
|
|
8481
|
+
if (isTinaPackage2(name2) && typeof version2 === "string") {
|
|
8006
8482
|
versions.set(name2, version2);
|
|
8007
8483
|
}
|
|
8008
8484
|
}
|
|
8009
8485
|
for (const [name2, value] of Object.entries(lockfile.dependencies || {})) {
|
|
8010
8486
|
const version2 = value.version;
|
|
8011
|
-
if (
|
|
8487
|
+
if (isTinaPackage2(name2) && typeof version2 === "string") {
|
|
8012
8488
|
versions.set(name2, version2);
|
|
8013
8489
|
}
|
|
8014
8490
|
}
|
|
8015
8491
|
return versions;
|
|
8016
8492
|
}
|
|
8017
8493
|
async function readPnpmLockVersions(rootPath) {
|
|
8018
|
-
const lockfilePath =
|
|
8494
|
+
const lockfilePath = path21.join(rootPath, "pnpm-lock.yaml");
|
|
8019
8495
|
const versions = /* @__PURE__ */ new Map();
|
|
8020
|
-
if (!await
|
|
8021
|
-
const lockfile = yaml3.load(await
|
|
8496
|
+
if (!await fs20.pathExists(lockfilePath)) return versions;
|
|
8497
|
+
const lockfile = yaml3.load(await fs20.readFile(lockfilePath, "utf8"));
|
|
8022
8498
|
const rootImporter = lockfile?.importers?.["."];
|
|
8023
8499
|
for (const dependencyType of DEPENDENCY_TYPES) {
|
|
8024
8500
|
for (const [name2, value] of Object.entries(
|
|
8025
8501
|
rootImporter?.[dependencyType] || {}
|
|
8026
8502
|
)) {
|
|
8027
|
-
if (!
|
|
8503
|
+
if (!isTinaPackage2(name2)) continue;
|
|
8028
8504
|
const version2 = typeof value === "string" ? value : typeof value.version === "string" ? value.version : void 0;
|
|
8029
8505
|
if (version2) versions.set(name2, normalizeInstalledVersion(version2));
|
|
8030
8506
|
}
|
|
8031
8507
|
}
|
|
8032
8508
|
for (const key of Object.keys(lockfile?.packages || {})) {
|
|
8033
8509
|
const parsed = parsePnpmPackageKey(key);
|
|
8034
|
-
if (parsed &&
|
|
8510
|
+
if (parsed && isTinaPackage2(parsed.name) && !versions.has(parsed.name)) {
|
|
8035
8511
|
versions.set(parsed.name, parsed.version);
|
|
8036
8512
|
}
|
|
8037
8513
|
}
|
|
8038
8514
|
return versions;
|
|
8039
8515
|
}
|
|
8040
8516
|
async function readYarnLockVersions(rootPath) {
|
|
8041
|
-
const lockfilePath =
|
|
8517
|
+
const lockfilePath = path21.join(rootPath, "yarn.lock");
|
|
8042
8518
|
const versions = /* @__PURE__ */ new Map();
|
|
8043
|
-
if (!await
|
|
8044
|
-
const contents = await
|
|
8519
|
+
if (!await fs20.pathExists(lockfilePath)) return versions;
|
|
8520
|
+
const contents = await fs20.readFile(lockfilePath, "utf8");
|
|
8045
8521
|
if (contents.includes("__metadata:")) {
|
|
8046
8522
|
return readYarnBerryLockVersions(contents);
|
|
8047
8523
|
}
|
|
@@ -8055,7 +8531,7 @@ async function readYarnLockVersions(rootPath) {
|
|
|
8055
8531
|
const version2 = line.match(/^\s+version\s+"([^"]+)"/)?.[1];
|
|
8056
8532
|
if (!version2) continue;
|
|
8057
8533
|
for (const name2 of activeNames) {
|
|
8058
|
-
if (
|
|
8534
|
+
if (isTinaPackage2(name2) && !versions.has(name2)) {
|
|
8059
8535
|
versions.set(name2, version2);
|
|
8060
8536
|
}
|
|
8061
8537
|
}
|
|
@@ -8069,7 +8545,7 @@ function readYarnBerryLockVersions(contents) {
|
|
|
8069
8545
|
if (descriptor === "__metadata") continue;
|
|
8070
8546
|
const name2 = extractYarnBerryPackageName(descriptor);
|
|
8071
8547
|
const version2 = getYarnBerryInstalledVersion(descriptor, value?.version);
|
|
8072
|
-
if (name2 &&
|
|
8548
|
+
if (name2 && isTinaPackage2(name2) && version2) {
|
|
8073
8549
|
versions.set(name2, version2);
|
|
8074
8550
|
}
|
|
8075
8551
|
}
|