@tinacms/cli 2.5.6 → 2.6.1
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 +978 -588
- 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/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 +21 -21
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.1";
|
|
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;
|
|
@@ -1500,339 +1505,68 @@ async function createAndInitializeDatabase(configManager, datalayerPort, bridgeO
|
|
|
1500
1505
|
return database;
|
|
1501
1506
|
}
|
|
1502
1507
|
|
|
1503
|
-
// src/next/
|
|
1504
|
-
import
|
|
1505
|
-
import
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
import childProcess from "child_process";
|
|
1509
|
-
var startSubprocess2 = async ({ command: command2 }) => {
|
|
1510
|
-
if (typeof command2 === "string") {
|
|
1511
|
-
const commands = command2.split(" ");
|
|
1512
|
-
const firstCommand = commands[0];
|
|
1513
|
-
const args = commands.slice(1) || [];
|
|
1514
|
-
const ps = childProcess.spawn(firstCommand, args, {
|
|
1515
|
-
stdio: "inherit",
|
|
1516
|
-
shell: true
|
|
1517
|
-
});
|
|
1518
|
-
ps.on("error", (code) => {
|
|
1519
|
-
logger.error(
|
|
1520
|
-
dangerText(
|
|
1521
|
-
`An error has occurred in the Next.js child process. Error message below`
|
|
1522
|
-
)
|
|
1523
|
-
);
|
|
1524
|
-
logger.error(`name: ${code.name}
|
|
1525
|
-
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";
|
|
1526
1513
|
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
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;
|
|
1534
1525
|
}
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
// src/next/commands/baseCommands.ts
|
|
1538
|
-
import { getChangedFiles, getSha, shaExists } from "@tinacms/graphql";
|
|
1539
|
-
import fs5 from "fs-extra";
|
|
1540
|
-
var BaseCommand = class extends Command {
|
|
1541
|
-
experimentalDataLayer = Option.Boolean("--experimentalData", {
|
|
1542
|
-
description: "DEPRECATED - Build the server with additional data querying capabilities"
|
|
1543
|
-
});
|
|
1544
|
-
isomorphicGitBridge = Option.Boolean("--isomorphicGitBridge", {
|
|
1545
|
-
description: "DEPRECATED - Enable Isomorphic Git Bridge Implementation"
|
|
1546
|
-
});
|
|
1547
|
-
port = Option.String("-p,--port", "4001", {
|
|
1548
|
-
description: "Specify a port to run the server on. (default 4001)"
|
|
1549
|
-
});
|
|
1550
|
-
datalayerPort = Option.String("--datalayer-port", "9000", {
|
|
1551
|
-
description: "Specify a port to run the datalayer server on. (default 9000)"
|
|
1552
|
-
});
|
|
1553
|
-
subCommand = Option.String("-c,--command", {
|
|
1554
|
-
description: "The sub-command to run"
|
|
1555
|
-
});
|
|
1556
|
-
rootPath = Option.String("--rootPath", {
|
|
1557
|
-
description: "Specify the root directory to run the CLI from (defaults to current working directory)"
|
|
1558
|
-
});
|
|
1559
|
-
verbose = Option.Boolean("-v,--verbose", false, {
|
|
1560
|
-
description: "increase verbosity of logged output"
|
|
1561
|
-
});
|
|
1562
|
-
noSDK = Option.Boolean("--noSDK", false, {
|
|
1563
|
-
description: "DEPRECATED - This should now be set in the config at client.skip = true'. Don't generate the generated client SDK"
|
|
1564
|
-
});
|
|
1565
|
-
noTelemetry = Option.Boolean("--noTelemetry", false, {
|
|
1566
|
-
description: "Disable anonymous telemetry that is collected"
|
|
1567
|
-
});
|
|
1568
|
-
async startSubCommand() {
|
|
1569
|
-
let subProc;
|
|
1570
|
-
if (this.subCommand) {
|
|
1571
|
-
subProc = await startSubprocess2({ command: this.subCommand });
|
|
1572
|
-
logger.info(
|
|
1573
|
-
`Running web application with command: ${chalk4.cyan(this.subCommand)}`
|
|
1574
|
-
);
|
|
1575
|
-
}
|
|
1576
|
-
function exitHandler(options, exitCode) {
|
|
1577
|
-
if (subProc) {
|
|
1578
|
-
subProc.kill();
|
|
1579
|
-
}
|
|
1580
|
-
process.exit();
|
|
1581
|
-
}
|
|
1582
|
-
process.on("exit", exitHandler);
|
|
1583
|
-
process.on("SIGINT", exitHandler);
|
|
1584
|
-
process.on("SIGUSR1", exitHandler);
|
|
1585
|
-
process.on("SIGUSR2", exitHandler);
|
|
1586
|
-
process.on("uncaughtException", (error) => {
|
|
1587
|
-
logger.error(`Uncaught exception ${error.name}`);
|
|
1588
|
-
console.error(error);
|
|
1589
|
-
});
|
|
1526
|
+
if (LOCALHOST_RE.test(origin)) {
|
|
1527
|
+
return true;
|
|
1590
1528
|
}
|
|
1591
|
-
|
|
1592
|
-
if (
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
)
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
logger.warn(
|
|
1602
|
-
"--noSDK has been deprecated, and will be unsupported in a future release. This should be set in the config at client.skip = true"
|
|
1603
|
-
);
|
|
1529
|
+
for (const allowed of expandOrigins(allowedOrigins)) {
|
|
1530
|
+
if (typeof allowed === "string") {
|
|
1531
|
+
if (allowed === origin) {
|
|
1532
|
+
return true;
|
|
1533
|
+
}
|
|
1534
|
+
} else {
|
|
1535
|
+
allowed.lastIndex = 0;
|
|
1536
|
+
if (allowed.test(origin)) {
|
|
1537
|
+
return true;
|
|
1538
|
+
}
|
|
1604
1539
|
}
|
|
1605
1540
|
}
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
if (partialReindex) {
|
|
1624
|
-
console.error(
|
|
1625
|
-
"Failed to get sha. NOTE: `--partial-reindex` only supported for git repositories"
|
|
1626
|
-
);
|
|
1627
|
-
throw e;
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
const lastSha = await database.getMetadata("lastSha");
|
|
1631
|
-
const exists = lastSha && await shaExists({ fs: fs5, dir: rootPath, sha: lastSha });
|
|
1632
|
-
let res;
|
|
1633
|
-
if (partialReindex && lastSha && exists && sha) {
|
|
1634
|
-
const pathFilter = {};
|
|
1635
|
-
if (configManager.isUsingLegacyFolder) {
|
|
1636
|
-
pathFilter[".tina/__generated__/_schema.json"] = {};
|
|
1637
|
-
} else {
|
|
1638
|
-
pathFilter["tina/tina-lock.json"] = {};
|
|
1639
|
-
}
|
|
1640
|
-
for (const collection of tinaSchema.getCollections()) {
|
|
1641
|
-
pathFilter[collection.path] = {
|
|
1642
|
-
matches: collection.match?.exclude || collection.match?.include ? tinaSchema.getMatches({ collection }) : void 0
|
|
1643
|
-
};
|
|
1644
|
-
}
|
|
1645
|
-
const { added, modified, deleted } = await getChangedFiles({
|
|
1646
|
-
fs: fs5,
|
|
1647
|
-
dir: rootPath,
|
|
1648
|
-
from: lastSha,
|
|
1649
|
-
to: sha,
|
|
1650
|
-
pathFilter
|
|
1651
|
-
});
|
|
1652
|
-
const tinaPathUpdates = modified.filter(
|
|
1653
|
-
(path20) => path20.startsWith(".tina/__generated__/_schema.json") || path20.startsWith("tina/tina-lock.json")
|
|
1654
|
-
);
|
|
1655
|
-
if (tinaPathUpdates.length > 0) {
|
|
1656
|
-
res = await database.indexContent({
|
|
1657
|
-
graphQLSchema,
|
|
1658
|
-
tinaSchema
|
|
1659
|
-
});
|
|
1660
|
-
} else {
|
|
1661
|
-
if (added.length > 0 || modified.length > 0) {
|
|
1662
|
-
await database.indexContentByPaths([...added, ...modified]);
|
|
1663
|
-
}
|
|
1664
|
-
if (deleted.length > 0) {
|
|
1665
|
-
await database.deleteContentByPaths(deleted);
|
|
1666
|
-
}
|
|
1667
|
-
}
|
|
1541
|
+
return false;
|
|
1542
|
+
}
|
|
1543
|
+
function buildCorsOriginCheck(allowedOrigins = []) {
|
|
1544
|
+
return (origin, callback) => {
|
|
1545
|
+
callback(null, isOriginAllowed(origin, allowedOrigins));
|
|
1546
|
+
};
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
// src/next/vite/filterPublicEnv.ts
|
|
1550
|
+
function filterPublicEnv(env = process.env) {
|
|
1551
|
+
const publicEnv = {};
|
|
1552
|
+
Object.keys(env).forEach((key) => {
|
|
1553
|
+
if (key.startsWith("TINA_PUBLIC_") || key.startsWith("NEXT_PUBLIC_") || key === "NODE_ENV" || key === "HEAD") {
|
|
1554
|
+
try {
|
|
1555
|
+
const value = env[key];
|
|
1556
|
+
if (typeof value === "string") {
|
|
1557
|
+
publicEnv[key] = value;
|
|
1668
1558
|
} else {
|
|
1669
|
-
|
|
1670
|
-
graphQLSchema,
|
|
1671
|
-
tinaSchema
|
|
1672
|
-
});
|
|
1673
|
-
}
|
|
1674
|
-
if (sha) {
|
|
1675
|
-
await database.setMetadata("lastSha", sha);
|
|
1676
|
-
}
|
|
1677
|
-
if (res?.warnings) {
|
|
1678
|
-
warnings.push(...res.warnings);
|
|
1559
|
+
publicEnv[key] = JSON.stringify(value);
|
|
1679
1560
|
}
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
logger.warn(warnText(`${warning}`));
|
|
1687
|
-
});
|
|
1561
|
+
} catch (error) {
|
|
1562
|
+
console.warn(
|
|
1563
|
+
`Could not stringify public env process.env.${key} env variable`
|
|
1564
|
+
);
|
|
1565
|
+
console.warn(error);
|
|
1566
|
+
}
|
|
1688
1567
|
}
|
|
1689
|
-
}
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
// src/next/commands/dev-command/html.ts
|
|
1693
|
-
var errorHTML = `<style type="text/css">
|
|
1694
|
-
#no-assets-placeholder body {
|
|
1695
|
-
font-family: sans-serif;
|
|
1696
|
-
font-size: 16px;
|
|
1697
|
-
line-height: 1.4;
|
|
1698
|
-
color: #333;
|
|
1699
|
-
background-color: #f5f5f5;
|
|
1700
|
-
}
|
|
1701
|
-
#no-assets-placeholder {
|
|
1702
|
-
max-width: 600px;
|
|
1703
|
-
margin: 0 auto;
|
|
1704
|
-
padding: 40px;
|
|
1705
|
-
text-align: center;
|
|
1706
|
-
background-color: #fff;
|
|
1707
|
-
box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.1);
|
|
1708
|
-
}
|
|
1709
|
-
#no-assets-placeholder h1 {
|
|
1710
|
-
font-size: 24px;
|
|
1711
|
-
margin-bottom: 20px;
|
|
1712
|
-
}
|
|
1713
|
-
#no-assets-placeholder p {
|
|
1714
|
-
margin-bottom: 10px;
|
|
1715
|
-
}
|
|
1716
|
-
#no-assets-placeholder a {
|
|
1717
|
-
color: #0077cc;
|
|
1718
|
-
text-decoration: none;
|
|
1719
|
-
}
|
|
1720
|
-
#no-assets-placeholder a:hover {
|
|
1721
|
-
text-decoration: underline;
|
|
1722
|
-
}
|
|
1723
|
-
</style>
|
|
1724
|
-
<div id="no-assets-placeholder">
|
|
1725
|
-
<h1>Failed loading TinaCMS assets</h1>
|
|
1726
|
-
<p>
|
|
1727
|
-
Your TinaCMS configuration may be misconfigured, and we could not load
|
|
1728
|
-
the assets for this page.
|
|
1729
|
-
</p>
|
|
1730
|
-
<p>
|
|
1731
|
-
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.
|
|
1732
|
-
</p>
|
|
1733
|
-
</div>
|
|
1734
|
-
</div>`.trim().replace(/[\r\n\s]+/g, " ");
|
|
1735
|
-
var devHTML = (port) => `<!DOCTYPE html>
|
|
1736
|
-
<html lang="en">
|
|
1737
|
-
<head>
|
|
1738
|
-
<meta charset="UTF-8" />
|
|
1739
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1740
|
-
<title>TinaCMS</title>
|
|
1741
|
-
</head>
|
|
1742
|
-
|
|
1743
|
-
<!-- if development -->
|
|
1744
|
-
<script type="module">
|
|
1745
|
-
import RefreshRuntime from 'http://localhost:${port}/@react-refresh'
|
|
1746
|
-
RefreshRuntime.injectIntoGlobalHook(window)
|
|
1747
|
-
window.$RefreshReg$ = () => {}
|
|
1748
|
-
window.$RefreshSig$ = () => (type) => type
|
|
1749
|
-
window.__vite_plugin_react_preamble_installed__ = true
|
|
1750
|
-
</script>
|
|
1751
|
-
<script type="module" src="http://localhost:${port}/@vite/client"></script>
|
|
1752
|
-
<script>
|
|
1753
|
-
function handleLoadError() {
|
|
1754
|
-
// Assets have failed to load
|
|
1755
|
-
document.getElementById('root').innerHTML = '${errorHTML}';
|
|
1756
|
-
}
|
|
1757
|
-
</script>
|
|
1758
|
-
<script
|
|
1759
|
-
type="module"
|
|
1760
|
-
src="http://localhost:${port}/src/main.tsx"
|
|
1761
|
-
onerror="handleLoadError()"
|
|
1762
|
-
></script>
|
|
1763
|
-
<body class="tina-tailwind">
|
|
1764
|
-
<div id="root"></div>
|
|
1765
|
-
</body>
|
|
1766
|
-
</html>`;
|
|
1767
|
-
|
|
1768
|
-
// src/next/commands/dev-command/server/index.ts
|
|
1769
|
-
import { createServer as createViteServer } from "vite";
|
|
1770
|
-
|
|
1771
|
-
// src/next/vite/index.ts
|
|
1772
|
-
import path7 from "node:path";
|
|
1773
|
-
import react from "@vitejs/plugin-react";
|
|
1774
|
-
import fs6 from "fs-extra";
|
|
1775
|
-
import normalizePath3 from "normalize-path";
|
|
1776
|
-
import {
|
|
1777
|
-
splitVendorChunkPlugin
|
|
1778
|
-
} from "vite";
|
|
1779
|
-
|
|
1780
|
-
// src/next/vite/cors.ts
|
|
1781
|
-
var LOCALHOST_RE = /^https?:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/;
|
|
1782
|
-
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+)?$/;
|
|
1783
|
-
function expandOrigins(raw) {
|
|
1784
|
-
const hasPrivate = raw.some((o) => o === "private");
|
|
1785
|
-
const filtered = raw.filter((o) => o !== "private");
|
|
1786
|
-
return hasPrivate ? [...filtered, PRIVATE_NETWORK_RE] : filtered;
|
|
1787
|
-
}
|
|
1788
|
-
function isOriginAllowed(origin, allowedOrigins = []) {
|
|
1789
|
-
if (!origin) {
|
|
1790
|
-
return true;
|
|
1791
|
-
}
|
|
1792
|
-
if (LOCALHOST_RE.test(origin)) {
|
|
1793
|
-
return true;
|
|
1794
|
-
}
|
|
1795
|
-
for (const allowed of expandOrigins(allowedOrigins)) {
|
|
1796
|
-
if (typeof allowed === "string") {
|
|
1797
|
-
if (allowed === origin) {
|
|
1798
|
-
return true;
|
|
1799
|
-
}
|
|
1800
|
-
} else {
|
|
1801
|
-
allowed.lastIndex = 0;
|
|
1802
|
-
if (allowed.test(origin)) {
|
|
1803
|
-
return true;
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
return false;
|
|
1808
|
-
}
|
|
1809
|
-
function buildCorsOriginCheck(allowedOrigins = []) {
|
|
1810
|
-
return (origin, callback) => {
|
|
1811
|
-
callback(null, isOriginAllowed(origin, allowedOrigins));
|
|
1812
|
-
};
|
|
1813
|
-
}
|
|
1814
|
-
|
|
1815
|
-
// src/next/vite/filterPublicEnv.ts
|
|
1816
|
-
function filterPublicEnv(env = process.env) {
|
|
1817
|
-
const publicEnv = {};
|
|
1818
|
-
Object.keys(env).forEach((key) => {
|
|
1819
|
-
if (key.startsWith("TINA_PUBLIC_") || key.startsWith("NEXT_PUBLIC_") || key === "NODE_ENV" || key === "HEAD") {
|
|
1820
|
-
try {
|
|
1821
|
-
const value = env[key];
|
|
1822
|
-
if (typeof value === "string") {
|
|
1823
|
-
publicEnv[key] = value;
|
|
1824
|
-
} else {
|
|
1825
|
-
publicEnv[key] = JSON.stringify(value);
|
|
1826
|
-
}
|
|
1827
|
-
} catch (error) {
|
|
1828
|
-
console.warn(
|
|
1829
|
-
`Could not stringify public env process.env.${key} env variable`
|
|
1830
|
-
);
|
|
1831
|
-
console.warn(error);
|
|
1832
|
-
}
|
|
1833
|
-
}
|
|
1834
|
-
});
|
|
1835
|
-
return publicEnv;
|
|
1568
|
+
});
|
|
1569
|
+
return publicEnv;
|
|
1836
1570
|
}
|
|
1837
1571
|
|
|
1838
1572
|
// src/next/vite/tailwind.ts
|
|
@@ -2120,15 +1854,15 @@ async function listFilesRecursively({
|
|
|
2120
1854
|
config2.publicFolder,
|
|
2121
1855
|
directoryPath
|
|
2122
1856
|
);
|
|
2123
|
-
const exists = await
|
|
1857
|
+
const exists = await fs5.pathExists(fullDirectoryPath);
|
|
2124
1858
|
if (!exists) {
|
|
2125
1859
|
return { "0": [] };
|
|
2126
1860
|
}
|
|
2127
|
-
const items = await
|
|
1861
|
+
const items = await fs5.readdir(fullDirectoryPath);
|
|
2128
1862
|
const staticMediaItems = [];
|
|
2129
1863
|
for (const item of items) {
|
|
2130
1864
|
const itemPath = path7.join(fullDirectoryPath, item);
|
|
2131
|
-
const stats = await
|
|
1865
|
+
const stats = await fs5.promises.lstat(itemPath);
|
|
2132
1866
|
const staticMediaItem = {
|
|
2133
1867
|
id: item,
|
|
2134
1868
|
filename: item,
|
|
@@ -2160,6 +1894,12 @@ async function listFilesRecursively({
|
|
|
2160
1894
|
}
|
|
2161
1895
|
return chunkArrayIntoObject(staticMediaItems, 20);
|
|
2162
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
|
+
};
|
|
2163
1903
|
var createConfig = async ({
|
|
2164
1904
|
configManager,
|
|
2165
1905
|
apiURL,
|
|
@@ -2178,9 +1918,9 @@ var createConfig = async ({
|
|
|
2178
1918
|
config: configManager.config.media.tina,
|
|
2179
1919
|
roothPath: configManager.rootPath
|
|
2180
1920
|
});
|
|
2181
|
-
await
|
|
1921
|
+
await fs5.outputFile(staticMediaPath, JSON.stringify(staticMedia, null, 2));
|
|
2182
1922
|
} else {
|
|
2183
|
-
await
|
|
1923
|
+
await fs5.outputFile(staticMediaPath, `[]`);
|
|
2184
1924
|
}
|
|
2185
1925
|
const alias = {
|
|
2186
1926
|
TINA_IMPORT: configManager.prebuildFilePath,
|
|
@@ -2200,17 +1940,11 @@ var createConfig = async ({
|
|
|
2200
1940
|
} else {
|
|
2201
1941
|
alias["CLIENT_IMPORT"] = configManager.isUsingTs() ? configManager.generatedTypesTSFilePath : configManager.generatedTypesJSFilePath;
|
|
2202
1942
|
}
|
|
2203
|
-
let basePath;
|
|
2204
|
-
if (configManager.config.build.basePath) {
|
|
2205
|
-
basePath = configManager.config.build.basePath;
|
|
2206
|
-
}
|
|
2207
1943
|
const fullVersion = configManager.getTinaGraphQLVersion();
|
|
2208
1944
|
const version2 = `${fullVersion.major}.${fullVersion.minor}`;
|
|
2209
1945
|
const config2 = {
|
|
2210
1946
|
root: configManager.spaRootPath,
|
|
2211
|
-
base:
|
|
2212
|
-
configManager.config.build.outputFolder
|
|
2213
|
-
)}/`,
|
|
1947
|
+
base: getBasePath(configManager),
|
|
2214
1948
|
appType: "spa",
|
|
2215
1949
|
resolve: {
|
|
2216
1950
|
alias,
|
|
@@ -2227,11 +1961,13 @@ var createConfig = async ({
|
|
|
2227
1961
|
* - `process.env.__NEXT_CROSS_ORIGIN`
|
|
2228
1962
|
* - `process.env.__NEXT_I18N_SUPPORT`
|
|
2229
1963
|
*
|
|
2230
|
-
*
|
|
2231
|
-
*
|
|
2232
|
-
*
|
|
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.
|
|
2233
1969
|
*/
|
|
2234
|
-
"process.env":
|
|
1970
|
+
"process.env": JSON.stringify(publicEnv),
|
|
2235
1971
|
// Used by picomatch https://github.com/micromatch/picomatch/blob/master/lib/utils.js#L4
|
|
2236
1972
|
"process.platform": `"${process.platform}"`,
|
|
2237
1973
|
__API_URL__: `"${apiURL}"`,
|
|
@@ -2282,18 +2018,12 @@ var createConfig = async ({
|
|
|
2282
2018
|
rollupOptions
|
|
2283
2019
|
},
|
|
2284
2020
|
plugins: [
|
|
2285
|
-
/**
|
|
2286
|
-
* `splitVendorChunkPlugin` is needed because `tinacms` is quite large,
|
|
2287
|
-
* Vite's chunking strategy chokes on memory issues for smaller machines (ie. on CI).
|
|
2288
|
-
*/
|
|
2289
2021
|
react({
|
|
2290
2022
|
babel: {
|
|
2291
2023
|
// Supresses the warning [NOTE] babel The code generator has deoptimised the styling of
|
|
2292
2024
|
compact: true
|
|
2293
|
-
}
|
|
2294
|
-
fastRefresh: false
|
|
2025
|
+
}
|
|
2295
2026
|
}),
|
|
2296
|
-
splitVendorChunkPlugin(),
|
|
2297
2027
|
tinaTailwind(configManager.spaRootPath, configManager.prebuildFilePath),
|
|
2298
2028
|
...plugins
|
|
2299
2029
|
]
|
|
@@ -2301,9 +2031,446 @@ var createConfig = async ({
|
|
|
2301
2031
|
return config2;
|
|
2302
2032
|
};
|
|
2303
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
|
+
|
|
2304
2471
|
// src/next/vite/plugins.ts
|
|
2305
|
-
import
|
|
2306
|
-
import
|
|
2472
|
+
import fs9 from "fs";
|
|
2473
|
+
import path11 from "path";
|
|
2307
2474
|
import { createFilter } from "@rollup/pluginutils";
|
|
2308
2475
|
import { resolve as gqlResolve } from "@tinacms/graphql";
|
|
2309
2476
|
import bodyParser from "body-parser";
|
|
@@ -2312,11 +2479,12 @@ import { transform as esbuildTransform } from "esbuild";
|
|
|
2312
2479
|
import { transformWithEsbuild } from "vite";
|
|
2313
2480
|
|
|
2314
2481
|
// src/next/commands/dev-command/server/media.ts
|
|
2315
|
-
import
|
|
2482
|
+
import { randomUUID } from "crypto";
|
|
2483
|
+
import path10, { join } from "path";
|
|
2316
2484
|
import busboy from "busboy";
|
|
2317
|
-
import
|
|
2485
|
+
import fs8 from "fs-extra";
|
|
2318
2486
|
var createMediaRouter = (config2) => {
|
|
2319
|
-
const mediaFolder =
|
|
2487
|
+
const mediaFolder = path10.join(
|
|
2320
2488
|
config2.rootPath,
|
|
2321
2489
|
config2.publicFolder,
|
|
2322
2490
|
config2.mediaRoot
|
|
@@ -2330,10 +2498,12 @@ var createMediaRouter = (config2) => {
|
|
|
2330
2498
|
);
|
|
2331
2499
|
const limit = requestURL.searchParams.get("limit");
|
|
2332
2500
|
const cursor = requestURL.searchParams.get("cursor");
|
|
2501
|
+
const search = requestURL.searchParams.get("search");
|
|
2333
2502
|
const media = await mediaModel.listMedia({
|
|
2334
2503
|
searchPath: folder,
|
|
2335
2504
|
cursor,
|
|
2336
|
-
limit
|
|
2505
|
+
limit,
|
|
2506
|
+
search
|
|
2337
2507
|
});
|
|
2338
2508
|
res.end(JSON.stringify(media));
|
|
2339
2509
|
} catch (error) {
|
|
@@ -2359,6 +2529,39 @@ var createMediaRouter = (config2) => {
|
|
|
2359
2529
|
throw error;
|
|
2360
2530
|
}
|
|
2361
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
|
+
};
|
|
2362
2565
|
const handlePost = async function(req, res) {
|
|
2363
2566
|
const bb = busboy({ headers: req.headers });
|
|
2364
2567
|
let responded = false;
|
|
@@ -2380,8 +2583,8 @@ var createMediaRouter = (config2) => {
|
|
|
2380
2583
|
);
|
|
2381
2584
|
return;
|
|
2382
2585
|
}
|
|
2383
|
-
await
|
|
2384
|
-
file.pipe(
|
|
2586
|
+
await fs8.ensureDir(path10.dirname(saveTo));
|
|
2587
|
+
file.pipe(fs8.createWriteStream(saveTo));
|
|
2385
2588
|
});
|
|
2386
2589
|
bb.on("error", (error) => {
|
|
2387
2590
|
responded = true;
|
|
@@ -2399,7 +2602,7 @@ var createMediaRouter = (config2) => {
|
|
|
2399
2602
|
});
|
|
2400
2603
|
req.pipe(bb);
|
|
2401
2604
|
};
|
|
2402
|
-
return { handleList, handleDelete, handlePost };
|
|
2605
|
+
return { handleList, handleDelete, handlePost, handleRename };
|
|
2403
2606
|
};
|
|
2404
2607
|
var parseMediaFolder = (str) => {
|
|
2405
2608
|
let returnString = str;
|
|
@@ -2408,21 +2611,35 @@ var parseMediaFolder = (str) => {
|
|
|
2408
2611
|
returnString = returnString.substr(0, returnString.length - 1);
|
|
2409
2612
|
return returnString;
|
|
2410
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 || "");
|
|
2411
2628
|
var ENCODED_TRAVERSAL_RE = /%2e%2e|%2f|%5c/i;
|
|
2412
2629
|
function resolveRealPath(candidate) {
|
|
2413
2630
|
try {
|
|
2414
|
-
return
|
|
2631
|
+
return fs8.realpathSync(candidate);
|
|
2415
2632
|
} catch {
|
|
2416
|
-
const parent =
|
|
2633
|
+
const parent = path10.dirname(candidate);
|
|
2417
2634
|
if (parent === candidate) return candidate;
|
|
2418
|
-
return
|
|
2635
|
+
return path10.join(resolveRealPath(parent), path10.basename(candidate));
|
|
2419
2636
|
}
|
|
2420
2637
|
}
|
|
2421
2638
|
function assertSymlinkWithinBase(resolved, resolvedBase, userPath) {
|
|
2422
2639
|
try {
|
|
2423
|
-
const realBase =
|
|
2640
|
+
const realBase = fs8.realpathSync(resolvedBase);
|
|
2424
2641
|
const realResolved = resolveRealPath(resolved);
|
|
2425
|
-
if (realResolved !== realBase && !realResolved.startsWith(realBase +
|
|
2642
|
+
if (realResolved !== realBase && !realResolved.startsWith(realBase + path10.sep)) {
|
|
2426
2643
|
throw new PathTraversalError(userPath);
|
|
2427
2644
|
}
|
|
2428
2645
|
} catch (err) {
|
|
@@ -2433,13 +2650,13 @@ function resolveWithinBase(userPath, baseDir) {
|
|
|
2433
2650
|
if (ENCODED_TRAVERSAL_RE.test(userPath)) {
|
|
2434
2651
|
throw new PathTraversalError(userPath);
|
|
2435
2652
|
}
|
|
2436
|
-
const resolvedBase =
|
|
2437
|
-
const resolved =
|
|
2653
|
+
const resolvedBase = path10.resolve(baseDir);
|
|
2654
|
+
const resolved = path10.resolve(path10.join(baseDir, userPath));
|
|
2438
2655
|
if (resolved === resolvedBase) {
|
|
2439
2656
|
assertSymlinkWithinBase(resolved, resolvedBase, userPath);
|
|
2440
2657
|
return resolvedBase;
|
|
2441
2658
|
}
|
|
2442
|
-
if (resolved.startsWith(resolvedBase +
|
|
2659
|
+
if (resolved.startsWith(resolvedBase + path10.sep)) {
|
|
2443
2660
|
assertSymlinkWithinBase(resolved, resolvedBase, userPath);
|
|
2444
2661
|
return resolved;
|
|
2445
2662
|
}
|
|
@@ -2449,12 +2666,12 @@ function resolveStrictlyWithinBase(userPath, baseDir) {
|
|
|
2449
2666
|
if (ENCODED_TRAVERSAL_RE.test(userPath)) {
|
|
2450
2667
|
throw new PathTraversalError(userPath);
|
|
2451
2668
|
}
|
|
2452
|
-
const resolvedBase =
|
|
2453
|
-
const resolved =
|
|
2669
|
+
const resolvedBase = path10.resolve(baseDir) + path10.sep;
|
|
2670
|
+
const resolved = path10.resolve(path10.join(baseDir, userPath));
|
|
2454
2671
|
if (!resolved.startsWith(resolvedBase)) {
|
|
2455
2672
|
throw new PathTraversalError(userPath);
|
|
2456
2673
|
}
|
|
2457
|
-
assertSymlinkWithinBase(resolved,
|
|
2674
|
+
assertSymlinkWithinBase(resolved, path10.resolve(baseDir), userPath);
|
|
2458
2675
|
return resolved;
|
|
2459
2676
|
}
|
|
2460
2677
|
var MediaModel = class {
|
|
@@ -2471,16 +2688,27 @@ var MediaModel = class {
|
|
|
2471
2688
|
const mediaBase = join(this.rootPath, this.publicFolder, this.mediaRoot);
|
|
2472
2689
|
const validatedPath = resolveWithinBase(args.searchPath, mediaBase);
|
|
2473
2690
|
const searchPath = parseMediaFolder(args.searchPath);
|
|
2474
|
-
if (!await
|
|
2691
|
+
if (!await fs8.pathExists(validatedPath)) {
|
|
2475
2692
|
return {
|
|
2476
2693
|
files: [],
|
|
2477
2694
|
directories: []
|
|
2478
2695
|
};
|
|
2479
2696
|
}
|
|
2480
|
-
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);
|
|
2481
2709
|
const filesProm = filesStr.map(async (file) => {
|
|
2482
2710
|
const filePath = join(validatedPath, file);
|
|
2483
|
-
const stat = await
|
|
2711
|
+
const stat = await fs8.stat(filePath);
|
|
2484
2712
|
let src = `/${file}`;
|
|
2485
2713
|
const isFile = stat.isFile();
|
|
2486
2714
|
if (!isFile) {
|
|
@@ -2516,10 +2744,11 @@ var MediaModel = class {
|
|
|
2516
2744
|
}
|
|
2517
2745
|
return 0;
|
|
2518
2746
|
});
|
|
2519
|
-
const
|
|
2520
|
-
const
|
|
2521
|
-
const directories =
|
|
2522
|
-
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;
|
|
2523
2752
|
return {
|
|
2524
2753
|
files,
|
|
2525
2754
|
directories,
|
|
@@ -2535,12 +2764,156 @@ var MediaModel = class {
|
|
|
2535
2764
|
};
|
|
2536
2765
|
}
|
|
2537
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
|
+
}
|
|
2538
2911
|
async deleteMedia(args) {
|
|
2539
2912
|
try {
|
|
2540
2913
|
const mediaBase = join(this.rootPath, this.publicFolder, this.mediaRoot);
|
|
2541
2914
|
const file = resolveStrictlyWithinBase(args.searchPath, mediaBase);
|
|
2542
|
-
await
|
|
2543
|
-
await
|
|
2915
|
+
await fs8.stat(file);
|
|
2916
|
+
await fs8.remove(file);
|
|
2544
2917
|
return { ok: true };
|
|
2545
2918
|
} catch (error) {
|
|
2546
2919
|
if (error instanceof PathTraversalError) throw error;
|
|
@@ -2648,7 +3021,7 @@ var transformTsxPlugin = ({
|
|
|
2648
3021
|
const plug = {
|
|
2649
3022
|
name: "transform-tsx",
|
|
2650
3023
|
async transform(code, id) {
|
|
2651
|
-
const extName =
|
|
3024
|
+
const extName = path11.extname(id);
|
|
2652
3025
|
if (extName.startsWith(".tsx") || extName.startsWith(".ts")) {
|
|
2653
3026
|
const result = await esbuildTransform(code, { loader: "tsx" });
|
|
2654
3027
|
return {
|
|
@@ -2659,6 +3032,7 @@ var transformTsxPlugin = ({
|
|
|
2659
3032
|
};
|
|
2660
3033
|
return plug;
|
|
2661
3034
|
};
|
|
3035
|
+
var isMediaRenameRequest = (req) => req.method === "POST" && (req.url || "").split("?")[0] === "/media/rename";
|
|
2662
3036
|
var devServerEndPointsPlugin = ({
|
|
2663
3037
|
configManager,
|
|
2664
3038
|
apiURL,
|
|
@@ -2671,6 +3045,7 @@ var devServerEndPointsPlugin = ({
|
|
|
2671
3045
|
const isStateChangingRequest = (req) => {
|
|
2672
3046
|
const url = req.url || "";
|
|
2673
3047
|
if (url.startsWith("/media/upload")) return true;
|
|
3048
|
+
if (isMediaRenameRequest(req)) return true;
|
|
2674
3049
|
if (url.startsWith("/media") && req.method === "DELETE") return true;
|
|
2675
3050
|
if (url.startsWith("/graphql") && req.method === "POST") return true;
|
|
2676
3051
|
if ((url.startsWith("/searchIndex") || url.startsWith("/v2/searchIndex")) && (req.method === "POST" || req.method === "DELETE"))
|
|
@@ -2708,6 +3083,10 @@ var devServerEndPointsPlugin = ({
|
|
|
2708
3083
|
await mediaRouter.handlePost(req, res);
|
|
2709
3084
|
return;
|
|
2710
3085
|
}
|
|
3086
|
+
if (isMediaRenameRequest(req)) {
|
|
3087
|
+
await mediaRouter.handleRename(req, res);
|
|
3088
|
+
return;
|
|
3089
|
+
}
|
|
2711
3090
|
if (req.url.startsWith("/media")) {
|
|
2712
3091
|
if (req.method === "DELETE") {
|
|
2713
3092
|
await mediaRouter.handleDelete(req, res);
|
|
@@ -2772,7 +3151,7 @@ function viteTransformExtension({
|
|
|
2772
3151
|
async transform(code, id) {
|
|
2773
3152
|
if (filter(id)) {
|
|
2774
3153
|
const { transform: transform2 } = await import("@svgr/core");
|
|
2775
|
-
const svgCode = await
|
|
3154
|
+
const svgCode = await fs9.promises.readFile(
|
|
2776
3155
|
id.replace(/\?.*$/, ""),
|
|
2777
3156
|
"utf8"
|
|
2778
3157
|
);
|
|
@@ -2883,6 +3262,7 @@ var DevCommand = class extends BaseCommand {
|
|
|
2883
3262
|
});
|
|
2884
3263
|
logger.info("\u{1F999} TinaCMS Dev Server is initializing...");
|
|
2885
3264
|
this.logDeprecationWarnings();
|
|
3265
|
+
this.warnOnVersionSkew(configManager.rootPath);
|
|
2886
3266
|
createDBServer(Number(this.datalayerPort));
|
|
2887
3267
|
let database = null;
|
|
2888
3268
|
const dbLock = async (fn) => {
|
|
@@ -2922,13 +3302,13 @@ var DevCommand = class extends BaseCommand {
|
|
|
2922
3302
|
});
|
|
2923
3303
|
const apiURL2 = await codegen2.execute();
|
|
2924
3304
|
if (!configManager.isUsingLegacyFolder) {
|
|
2925
|
-
const schemaObject = await
|
|
3305
|
+
const schemaObject = await fs10.readJSON(
|
|
2926
3306
|
configManager.generatedSchemaJSONPath
|
|
2927
3307
|
);
|
|
2928
|
-
const lookupObject = await
|
|
3308
|
+
const lookupObject = await fs10.readJSON(
|
|
2929
3309
|
configManager.generatedLookupJSONPath
|
|
2930
3310
|
);
|
|
2931
|
-
const graphqlSchemaObject = await
|
|
3311
|
+
const graphqlSchemaObject = await fs10.readJSON(
|
|
2932
3312
|
configManager.generatedGraphQLJSONPath
|
|
2933
3313
|
);
|
|
2934
3314
|
const tinaLockFilename = "tina-lock.json";
|
|
@@ -2937,8 +3317,8 @@ var DevCommand = class extends BaseCommand {
|
|
|
2937
3317
|
lookup: lookupObject,
|
|
2938
3318
|
graphql: graphqlSchemaObject
|
|
2939
3319
|
});
|
|
2940
|
-
|
|
2941
|
-
|
|
3320
|
+
fs10.writeFileSync(
|
|
3321
|
+
path12.join(configManager.tinaFolderPath, tinaLockFilename),
|
|
2942
3322
|
tinaLockContent
|
|
2943
3323
|
);
|
|
2944
3324
|
}
|
|
@@ -2982,8 +3362,11 @@ ${dangerText(e.message)}
|
|
|
2982
3362
|
const { apiURL, graphQLSchema, tinaSchema } = await setup({
|
|
2983
3363
|
firstTime: true
|
|
2984
3364
|
});
|
|
2985
|
-
await
|
|
2986
|
-
|
|
3365
|
+
await fs10.outputFile(
|
|
3366
|
+
configManager.outputHTMLFilePath,
|
|
3367
|
+
devHTML(this.port, getBasePath(configManager))
|
|
3368
|
+
);
|
|
3369
|
+
await fs10.outputFile(
|
|
2987
3370
|
configManager.outputGitignorePath,
|
|
2988
3371
|
"index.html\nassets/"
|
|
2989
3372
|
);
|
|
@@ -3128,7 +3511,7 @@ ${dangerText(e.message)}
|
|
|
3128
3511
|
watchContentFiles(configManager, database, databaseLock, searchIndexer) {
|
|
3129
3512
|
const collectionContentFiles = [];
|
|
3130
3513
|
configManager.config.schema.collections.forEach((collection) => {
|
|
3131
|
-
const collectionGlob = `${
|
|
3514
|
+
const collectionGlob = `${path12.join(
|
|
3132
3515
|
configManager.contentRootPath,
|
|
3133
3516
|
collection.path
|
|
3134
3517
|
)}/**/*.${collection.format || "md"}`;
|
|
@@ -3178,8 +3561,10 @@ ${dangerText(e.message)}
|
|
|
3178
3561
|
|
|
3179
3562
|
// src/next/commands/build-command/index.ts
|
|
3180
3563
|
import crypto from "crypto";
|
|
3181
|
-
import
|
|
3182
|
-
import {
|
|
3564
|
+
import path13 from "path";
|
|
3565
|
+
import {
|
|
3566
|
+
diff
|
|
3567
|
+
} from "@graphql-inspector/core";
|
|
3183
3568
|
import { FilesystemBridge as FilesystemBridge3, buildSchema as buildSchema2 } from "@tinacms/graphql";
|
|
3184
3569
|
import { parseURL as parseURL2 } from "@tinacms/schema-tools";
|
|
3185
3570
|
import {
|
|
@@ -3187,7 +3572,7 @@ import {
|
|
|
3187
3572
|
TinaCMSSearchIndexClient
|
|
3188
3573
|
} from "@tinacms/search";
|
|
3189
3574
|
import { Command as Command3, Option as Option3 } from "clipanion";
|
|
3190
|
-
import
|
|
3575
|
+
import fs11 from "fs-extra";
|
|
3191
3576
|
import {
|
|
3192
3577
|
buildASTSchema as buildASTSchema2,
|
|
3193
3578
|
buildClientSchema,
|
|
@@ -3207,6 +3592,78 @@ var getFaqLink = (type) => {
|
|
|
3207
3592
|
}
|
|
3208
3593
|
};
|
|
3209
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
|
+
|
|
3210
3667
|
// src/utils/sleep.ts
|
|
3211
3668
|
function timeout(ms) {
|
|
3212
3669
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
@@ -3324,75 +3781,6 @@ var waitForDB = async (config2, apiUrl, previewName, verbose) => {
|
|
|
3324
3781
|
});
|
|
3325
3782
|
};
|
|
3326
3783
|
|
|
3327
|
-
// src/utils/posthog.ts
|
|
3328
|
-
import { randomUUID } from "node:crypto";
|
|
3329
|
-
import { PostHog } from "posthog-node";
|
|
3330
|
-
|
|
3331
|
-
// src/utils/fetchPostHogConfig.ts
|
|
3332
|
-
async function fetchPostHogConfig(endpointUrl) {
|
|
3333
|
-
try {
|
|
3334
|
-
const response = await fetch(endpointUrl, {
|
|
3335
|
-
method: "GET",
|
|
3336
|
-
headers: {
|
|
3337
|
-
"Content-Type": "application/json"
|
|
3338
|
-
},
|
|
3339
|
-
// Cap latency for offline / firewalled developers. Endpoint is
|
|
3340
|
-
// typically single-digit ms when reachable; a timeout returns {}
|
|
3341
|
-
// and disables telemetry for this run, which is the right behavior.
|
|
3342
|
-
signal: AbortSignal.timeout(2e3)
|
|
3343
|
-
});
|
|
3344
|
-
if (!response.ok) {
|
|
3345
|
-
throw new Error(`Failed to fetch PostHog config: ${response.statusText}`);
|
|
3346
|
-
}
|
|
3347
|
-
const config2 = await response.json();
|
|
3348
|
-
return {
|
|
3349
|
-
POSTHOG_API_KEY: config2.api_key,
|
|
3350
|
-
POSTHOG_ENDPOINT: config2.host
|
|
3351
|
-
};
|
|
3352
|
-
} catch {
|
|
3353
|
-
return {};
|
|
3354
|
-
}
|
|
3355
|
-
}
|
|
3356
|
-
|
|
3357
|
-
// src/utils/posthog.ts
|
|
3358
|
-
function generateSessionId() {
|
|
3359
|
-
return randomUUID();
|
|
3360
|
-
}
|
|
3361
|
-
var BuildInvokeEvent = "tinacms-cli-build-invoke";
|
|
3362
|
-
var BuildFinishedEvent = "tinacms-cli-build-finished";
|
|
3363
|
-
async function initializePostHog(configEndpoint, disableGeoip) {
|
|
3364
|
-
if (process.env.TINA_DEV === "true") return null;
|
|
3365
|
-
let apiKey;
|
|
3366
|
-
let endpoint;
|
|
3367
|
-
if (configEndpoint) {
|
|
3368
|
-
const config2 = await fetchPostHogConfig(configEndpoint);
|
|
3369
|
-
apiKey = config2.POSTHOG_API_KEY;
|
|
3370
|
-
endpoint = config2.POSTHOG_ENDPOINT;
|
|
3371
|
-
}
|
|
3372
|
-
if (!apiKey) return null;
|
|
3373
|
-
return new PostHog(apiKey, {
|
|
3374
|
-
host: endpoint,
|
|
3375
|
-
disableGeoip: disableGeoip ?? true
|
|
3376
|
-
});
|
|
3377
|
-
}
|
|
3378
|
-
function postHogCapture(client, distinctId, event, properties) {
|
|
3379
|
-
if (!client) {
|
|
3380
|
-
return;
|
|
3381
|
-
}
|
|
3382
|
-
try {
|
|
3383
|
-
client.capture({
|
|
3384
|
-
distinctId,
|
|
3385
|
-
event,
|
|
3386
|
-
properties: {
|
|
3387
|
-
...properties,
|
|
3388
|
-
system: "tinacms/cli"
|
|
3389
|
-
}
|
|
3390
|
-
});
|
|
3391
|
-
} catch (error) {
|
|
3392
|
-
console.error("Error capturing event:", error);
|
|
3393
|
-
}
|
|
3394
|
-
}
|
|
3395
|
-
|
|
3396
3784
|
// src/next/commands/build-command/index.ts
|
|
3397
3785
|
var BuildCommand = class extends BaseCommand {
|
|
3398
3786
|
static paths = [["build"]];
|
|
@@ -3458,6 +3846,7 @@ var BuildCommand = class extends BaseCommand {
|
|
|
3458
3846
|
tinaGraphQLVersion: this.tinaGraphQLVersion,
|
|
3459
3847
|
legacyNoSDK: this.noSDK
|
|
3460
3848
|
});
|
|
3849
|
+
this.warnOnVersionSkew(configManager.rootPath);
|
|
3461
3850
|
if (this.previewName && !this.previewBaseBranch) {
|
|
3462
3851
|
logger.error(
|
|
3463
3852
|
`${dangerText(
|
|
@@ -3651,7 +4040,7 @@ ${dangerText(e.message)}
|
|
|
3651
4040
|
}
|
|
3652
4041
|
}
|
|
3653
4042
|
await buildProductionSpa(configManager, database, codegen2.productionUrl);
|
|
3654
|
-
await
|
|
4043
|
+
await fs11.outputFile(
|
|
3655
4044
|
configManager.outputGitignorePath,
|
|
3656
4045
|
"index.html\nassets/"
|
|
3657
4046
|
);
|
|
@@ -4036,7 +4425,7 @@ Additional info: Branch: ${config2.branch}, Client ID: ${config2.clientId} `;
|
|
|
4036
4425
|
}
|
|
4037
4426
|
const localTinaSchema = JSON.parse(
|
|
4038
4427
|
await database.bridge.get(
|
|
4039
|
-
|
|
4428
|
+
path13.join(database.tinaDirectory, "__generated__", "_schema.json")
|
|
4040
4429
|
)
|
|
4041
4430
|
);
|
|
4042
4431
|
localTinaSchema.version = void 0;
|
|
@@ -4399,19 +4788,19 @@ var AuditCommand = class extends Command4 {
|
|
|
4399
4788
|
import { Command as Command6, Option as Option6 } from "clipanion";
|
|
4400
4789
|
|
|
4401
4790
|
// src/cmds/init/detectEnvironment.ts
|
|
4402
|
-
import
|
|
4403
|
-
import
|
|
4791
|
+
import fs13 from "fs-extra";
|
|
4792
|
+
import path15 from "path";
|
|
4404
4793
|
|
|
4405
4794
|
// src/cmds/init/astro-config-detect.ts
|
|
4406
|
-
import
|
|
4407
|
-
import
|
|
4795
|
+
import fs12 from "fs";
|
|
4796
|
+
import path14 from "path";
|
|
4408
4797
|
var isDefaultAstroConfig = (source) => {
|
|
4409
4798
|
const stripped = source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "").replace(/\s+/g, " ").trim();
|
|
4410
4799
|
return /^import\s*\{\s*defineConfig\s*\}\s*from\s*['"]astro\/config['"]\s*;?\s*export\s+default\s+defineConfig\(\s*\{\s*\}\s*\)\s*;?$/.test(
|
|
4411
4800
|
stripped
|
|
4412
4801
|
);
|
|
4413
4802
|
};
|
|
4414
|
-
var findExistingPaths = (baseDir, relPaths) => relPaths.filter((rel) =>
|
|
4803
|
+
var findExistingPaths = (baseDir, relPaths) => relPaths.filter((rel) => fs12.existsSync(path14.join(baseDir, rel)));
|
|
4415
4804
|
var parseAstroMajor = (version2) => {
|
|
4416
4805
|
const match = version2 ? String(version2).match(/(\d+)/) : null;
|
|
4417
4806
|
return match ? Number(match[1]) : void 0;
|
|
@@ -4427,20 +4816,20 @@ var checkGitignoreForItem = async ({
|
|
|
4427
4816
|
baseDir,
|
|
4428
4817
|
line
|
|
4429
4818
|
}) => {
|
|
4430
|
-
const gitignoreContent =
|
|
4819
|
+
const gitignoreContent = fs13.readFileSync(path15.join(baseDir, ".gitignore")).toString();
|
|
4431
4820
|
return gitignoreContent.split("\n").some((item) => item === line);
|
|
4432
4821
|
};
|
|
4433
4822
|
var makeGeneratedFile = async (name2, generatedFileType, parentPath, opts) => {
|
|
4434
4823
|
const result = {
|
|
4435
|
-
fullPathTS:
|
|
4824
|
+
fullPathTS: path15.join(
|
|
4436
4825
|
parentPath,
|
|
4437
4826
|
`${name2}.${opts?.typescriptSuffix || opts?.extensionOverride || "ts"}`
|
|
4438
4827
|
),
|
|
4439
|
-
fullPathJS:
|
|
4828
|
+
fullPathJS: path15.join(
|
|
4440
4829
|
parentPath,
|
|
4441
4830
|
`${name2}.${opts?.extensionOverride || "js"}`
|
|
4442
4831
|
),
|
|
4443
|
-
fullPathOverride: opts?.extensionOverride ?
|
|
4832
|
+
fullPathOverride: opts?.extensionOverride ? path15.join(parentPath, `${name2}.${opts?.extensionOverride}`) : "",
|
|
4444
4833
|
generatedFileType,
|
|
4445
4834
|
name: name2,
|
|
4446
4835
|
parentPath,
|
|
@@ -4458,8 +4847,8 @@ var makeGeneratedFile = async (name2, generatedFileType, parentPath, opts) => {
|
|
|
4458
4847
|
};
|
|
4459
4848
|
}
|
|
4460
4849
|
};
|
|
4461
|
-
result.typescriptExists = await
|
|
4462
|
-
result.javascriptExists = await
|
|
4850
|
+
result.typescriptExists = await fs13.pathExists(result.fullPathTS);
|
|
4851
|
+
result.javascriptExists = await fs13.pathExists(result.fullPathJS);
|
|
4463
4852
|
return result;
|
|
4464
4853
|
};
|
|
4465
4854
|
var detectEnvironment = async ({
|
|
@@ -4468,21 +4857,21 @@ var detectEnvironment = async ({
|
|
|
4468
4857
|
rootPath,
|
|
4469
4858
|
debug = false
|
|
4470
4859
|
}) => {
|
|
4471
|
-
const hasForestryConfig = await
|
|
4472
|
-
|
|
4860
|
+
const hasForestryConfig = await fs13.pathExists(
|
|
4861
|
+
path15.join(pathToForestryConfig, ".forestry", "settings.yml")
|
|
4473
4862
|
);
|
|
4474
|
-
const sampleContentPath =
|
|
4863
|
+
const sampleContentPath = path15.join(
|
|
4475
4864
|
baseDir,
|
|
4476
4865
|
"content",
|
|
4477
4866
|
"posts",
|
|
4478
4867
|
"hello-world.md"
|
|
4479
4868
|
);
|
|
4480
|
-
const usingSrc =
|
|
4481
|
-
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");
|
|
4482
4871
|
const tinaConfigExists = Boolean(
|
|
4483
4872
|
// Does the tina folder exist?
|
|
4484
|
-
await
|
|
4485
|
-
(await
|
|
4873
|
+
await fs13.pathExists(tinaFolder) && // Does the tina folder contain a config file?
|
|
4874
|
+
(await fs13.readdir(tinaFolder)).find((x) => x.includes("config"))
|
|
4486
4875
|
);
|
|
4487
4876
|
const pagesDir = [baseDir, usingSrc ? "src" : false, "pages"].filter(
|
|
4488
4877
|
Boolean
|
|
@@ -4494,12 +4883,12 @@ var detectEnvironment = async ({
|
|
|
4494
4883
|
"next-api-handler": await makeGeneratedFile(
|
|
4495
4884
|
"[...routes]",
|
|
4496
4885
|
"next-api-handler",
|
|
4497
|
-
|
|
4886
|
+
path15.join(...pagesDir, "api", "tina")
|
|
4498
4887
|
),
|
|
4499
4888
|
"reactive-example": await makeGeneratedFile(
|
|
4500
4889
|
"[filename]",
|
|
4501
4890
|
"reactive-example",
|
|
4502
|
-
|
|
4891
|
+
path15.join(...pagesDir, "demo", "blog"),
|
|
4503
4892
|
{
|
|
4504
4893
|
typescriptSuffix: "tsx"
|
|
4505
4894
|
}
|
|
@@ -4507,24 +4896,24 @@ var detectEnvironment = async ({
|
|
|
4507
4896
|
"users-json": await makeGeneratedFile(
|
|
4508
4897
|
"index",
|
|
4509
4898
|
"users-json",
|
|
4510
|
-
|
|
4899
|
+
path15.join(baseDir, "content", "users"),
|
|
4511
4900
|
{ extensionOverride: "json" }
|
|
4512
4901
|
),
|
|
4513
4902
|
"sample-content": await makeGeneratedFile(
|
|
4514
4903
|
"hello-world",
|
|
4515
4904
|
"sample-content",
|
|
4516
|
-
|
|
4905
|
+
path15.join(baseDir, "content", "posts"),
|
|
4517
4906
|
{ extensionOverride: "md" }
|
|
4518
4907
|
)
|
|
4519
4908
|
};
|
|
4520
|
-
const hasSampleContent = await
|
|
4521
|
-
const hasPackageJSON = await
|
|
4909
|
+
const hasSampleContent = await fs13.pathExists(sampleContentPath);
|
|
4910
|
+
const hasPackageJSON = await fs13.pathExists("package.json");
|
|
4522
4911
|
let hasTinaDeps = false;
|
|
4523
4912
|
let hasReactDep = false;
|
|
4524
4913
|
let astroMajor;
|
|
4525
4914
|
if (hasPackageJSON) {
|
|
4526
4915
|
try {
|
|
4527
|
-
const packageJSON = await
|
|
4916
|
+
const packageJSON = await fs13.readJSON("package.json");
|
|
4528
4917
|
const deps = [];
|
|
4529
4918
|
if (packageJSON?.dependencies) {
|
|
4530
4919
|
deps.push(...Object.keys(packageJSON.dependencies));
|
|
@@ -4547,7 +4936,7 @@ var detectEnvironment = async ({
|
|
|
4547
4936
|
);
|
|
4548
4937
|
}
|
|
4549
4938
|
}
|
|
4550
|
-
const hasGitIgnore = await
|
|
4939
|
+
const hasGitIgnore = await fs13.pathExists(path15.join(".gitignore"));
|
|
4551
4940
|
const hasGitIgnoreNodeModules = hasGitIgnore && await checkGitignoreForItem({ baseDir, line: "node_modules" });
|
|
4552
4941
|
const hasEnvTina = hasGitIgnore && await checkGitignoreForItem({ baseDir, line: ".env.tina" });
|
|
4553
4942
|
const hasGitIgnoreEnv = hasGitIgnore && await checkGitignoreForItem({ baseDir, line: ".env" });
|
|
@@ -4557,9 +4946,9 @@ var detectEnvironment = async ({
|
|
|
4557
4946
|
});
|
|
4558
4947
|
let frontMatterFormat;
|
|
4559
4948
|
if (hasForestryConfig) {
|
|
4560
|
-
const hugoConfigPath =
|
|
4561
|
-
if (await
|
|
4562
|
-
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");
|
|
4563
4952
|
const metaDataFormat = hugoConfig.toString().match(/metaDataFormat = "(.*)"/)?.[1];
|
|
4564
4953
|
if (metaDataFormat && (metaDataFormat === "yaml" || metaDataFormat === "toml" || metaDataFormat === "json")) {
|
|
4565
4954
|
frontMatterFormat = metaDataFormat;
|
|
@@ -4821,7 +5210,7 @@ var chooseDatabaseAdapter = async ({
|
|
|
4821
5210
|
};
|
|
4822
5211
|
|
|
4823
5212
|
// src/cmds/init/prompts/authProvider.ts
|
|
4824
|
-
import
|
|
5213
|
+
import { randomBytes } from "node:crypto";
|
|
4825
5214
|
import prompts5 from "prompts";
|
|
4826
5215
|
var supportedAuthProviders = {
|
|
4827
5216
|
other: {
|
|
@@ -4876,7 +5265,7 @@ var authProviderUpdateConfig = {
|
|
|
4876
5265
|
name: "nextAuthSecret",
|
|
4877
5266
|
type: "text",
|
|
4878
5267
|
message: `What is the NextAuth.js Secret? (Hit enter to use a randomly generated secret)`,
|
|
4879
|
-
initial: process.env.NEXTAUTH_SECRET ||
|
|
5268
|
+
initial: process.env.NEXTAUTH_SECRET || randomBytes(16).toString("hex")
|
|
4880
5269
|
}
|
|
4881
5270
|
]);
|
|
4882
5271
|
config2.envVars.push({
|
|
@@ -5184,6 +5573,7 @@ var CLICommand = class {
|
|
|
5184
5573
|
constructor(handler) {
|
|
5185
5574
|
this.handler = handler;
|
|
5186
5575
|
}
|
|
5576
|
+
handler;
|
|
5187
5577
|
async execute(params) {
|
|
5188
5578
|
await this.handler.setup(params);
|
|
5189
5579
|
const environment = await this.handler.detectEnvironment(params);
|
|
@@ -5193,19 +5583,19 @@ var CLICommand = class {
|
|
|
5193
5583
|
};
|
|
5194
5584
|
|
|
5195
5585
|
// src/cmds/init/apply.ts
|
|
5196
|
-
import
|
|
5586
|
+
import path20 from "path";
|
|
5197
5587
|
|
|
5198
5588
|
// src/cmds/forestry-migrate/index.ts
|
|
5199
|
-
import
|
|
5200
|
-
import
|
|
5589
|
+
import fs15 from "fs-extra";
|
|
5590
|
+
import path17 from "path";
|
|
5201
5591
|
import yaml2 from "js-yaml";
|
|
5202
5592
|
import pkg from "minimatch";
|
|
5203
5593
|
import { parseFile, stringifyFile } from "@tinacms/graphql";
|
|
5204
5594
|
import { CONTENT_FORMATS } from "@tinacms/schema-tools";
|
|
5205
5595
|
|
|
5206
5596
|
// src/cmds/forestry-migrate/util/index.ts
|
|
5207
|
-
import
|
|
5208
|
-
import
|
|
5597
|
+
import fs14 from "fs-extra";
|
|
5598
|
+
import path16 from "path";
|
|
5209
5599
|
import yaml from "js-yaml";
|
|
5210
5600
|
import z2 from "zod";
|
|
5211
5601
|
|
|
@@ -5264,10 +5654,10 @@ var stringifyLabelWithField = (label) => {
|
|
|
5264
5654
|
var isForestrySafeString = (value) => !/[\x00\r\n]/.test(value);
|
|
5265
5655
|
|
|
5266
5656
|
// src/cmds/forestry-migrate/util/codeTransformer.ts
|
|
5267
|
-
import
|
|
5657
|
+
import crypto2 from "crypto";
|
|
5268
5658
|
import { format } from "prettier";
|
|
5269
5659
|
import TsParser from "prettier/parser-typescript.js";
|
|
5270
|
-
var INTERNAL_NONCE =
|
|
5660
|
+
var INTERNAL_NONCE = crypto2.randomBytes(16).toString("hex");
|
|
5271
5661
|
var MARKER_OPEN = `__TINA_INTERNAL_${INTERNAL_NONCE}__:::`;
|
|
5272
5662
|
var MARKER_CLOSE = `:::__TINA_INTERNAL_${INTERNAL_NONCE}__`;
|
|
5273
5663
|
var MARKER_REGEX = new RegExp(`"${MARKER_OPEN}(.*?)${MARKER_CLOSE}"`, "g");
|
|
@@ -5647,7 +6037,7 @@ var transformForestryFieldsToTinaFields = ({
|
|
|
5647
6037
|
return tinaFields;
|
|
5648
6038
|
};
|
|
5649
6039
|
var getFieldsFromTemplates = ({ tem, pathToForestryConfig, skipBlocks = false }) => {
|
|
5650
|
-
const templatePath =
|
|
6040
|
+
const templatePath = path16.join(
|
|
5651
6041
|
pathToForestryConfig,
|
|
5652
6042
|
".forestry",
|
|
5653
6043
|
"front_matter",
|
|
@@ -5656,7 +6046,7 @@ var getFieldsFromTemplates = ({ tem, pathToForestryConfig, skipBlocks = false })
|
|
|
5656
6046
|
);
|
|
5657
6047
|
let templateString = "";
|
|
5658
6048
|
try {
|
|
5659
|
-
templateString =
|
|
6049
|
+
templateString = fs14.readFileSync(templatePath).toString();
|
|
5660
6050
|
} catch {
|
|
5661
6051
|
throw new Error(
|
|
5662
6052
|
`Could not find template ${tem} at ${templatePath}
|
|
@@ -5715,9 +6105,9 @@ function checkExt(ext) {
|
|
|
5715
6105
|
var generateAllTemplates = async ({
|
|
5716
6106
|
pathToForestryConfig
|
|
5717
6107
|
}) => {
|
|
5718
|
-
const allTemplates = (await
|
|
5719
|
-
|
|
5720
|
-
)).map((tem) =>
|
|
6108
|
+
const allTemplates = (await fs15.readdir(
|
|
6109
|
+
path17.join(pathToForestryConfig, ".forestry", "front_matter", "templates")
|
|
6110
|
+
)).map((tem) => path17.basename(tem, ".yml"));
|
|
5721
6111
|
const templateMap = /* @__PURE__ */ new Map();
|
|
5722
6112
|
const proms = allTemplates.map(async (tem) => {
|
|
5723
6113
|
try {
|
|
@@ -5862,9 +6252,9 @@ var generateCollectionFromForestrySection = (args) => {
|
|
|
5862
6252
|
return c;
|
|
5863
6253
|
} else if (section.type === "document") {
|
|
5864
6254
|
const filePath = section.path;
|
|
5865
|
-
const extname =
|
|
5866
|
-
const fileName =
|
|
5867
|
-
const dir =
|
|
6255
|
+
const extname = path17.extname(filePath);
|
|
6256
|
+
const fileName = path17.basename(filePath, extname);
|
|
6257
|
+
const dir = path17.dirname(filePath);
|
|
5868
6258
|
const ext = checkExt(extname);
|
|
5869
6259
|
if (ext) {
|
|
5870
6260
|
const fields = [];
|
|
@@ -5926,8 +6316,8 @@ var generateCollections = async ({
|
|
|
5926
6316
|
templateMap,
|
|
5927
6317
|
usingTypescript
|
|
5928
6318
|
});
|
|
5929
|
-
const forestryConfig = await
|
|
5930
|
-
|
|
6319
|
+
const forestryConfig = await fs15.readFile(
|
|
6320
|
+
path17.join(pathToForestryConfig, ".forestry", "settings.yml")
|
|
5931
6321
|
);
|
|
5932
6322
|
rewriteTemplateKeysInDocs({
|
|
5933
6323
|
templateMap,
|
|
@@ -5957,12 +6347,12 @@ var rewriteTemplateKeysInDocs = (args) => {
|
|
|
5957
6347
|
const { templateObj } = templateMap.get(templateKey);
|
|
5958
6348
|
templateObj?.pages?.forEach((page) => {
|
|
5959
6349
|
try {
|
|
5960
|
-
const filePath =
|
|
5961
|
-
if (
|
|
6350
|
+
const filePath = path17.join(page);
|
|
6351
|
+
if (fs15.lstatSync(filePath).isDirectory()) {
|
|
5962
6352
|
return;
|
|
5963
6353
|
}
|
|
5964
|
-
const extname =
|
|
5965
|
-
const fileContent =
|
|
6354
|
+
const extname = path17.extname(filePath);
|
|
6355
|
+
const fileContent = fs15.readFileSync(filePath).toString();
|
|
5966
6356
|
const content = parseFile(
|
|
5967
6357
|
fileContent,
|
|
5968
6358
|
extname,
|
|
@@ -5973,7 +6363,7 @@ var rewriteTemplateKeysInDocs = (args) => {
|
|
|
5973
6363
|
_template: stringifyLabel(templateKey),
|
|
5974
6364
|
...content
|
|
5975
6365
|
};
|
|
5976
|
-
|
|
6366
|
+
fs15.writeFileSync(
|
|
5977
6367
|
filePath,
|
|
5978
6368
|
stringifyFile(newContent, extname, true, markdownParseConfig)
|
|
5979
6369
|
);
|
|
@@ -5988,12 +6378,12 @@ var rewriteTemplateKeysInDocs = (args) => {
|
|
|
5988
6378
|
|
|
5989
6379
|
// src/cmds/init/apply.ts
|
|
5990
6380
|
import { Telemetry as Telemetry3 } from "@tinacms/metrics";
|
|
5991
|
-
import
|
|
6381
|
+
import fs19 from "fs-extra";
|
|
5992
6382
|
|
|
5993
6383
|
// src/next/commands/codemod-command/index.ts
|
|
5994
6384
|
import { Command as Command5, Option as Option5 } from "clipanion";
|
|
5995
|
-
import
|
|
5996
|
-
import
|
|
6385
|
+
import fs16 from "fs-extra";
|
|
6386
|
+
import path18 from "path";
|
|
5997
6387
|
var CodemodCommand = class extends Command5 {
|
|
5998
6388
|
static paths = [["codemod"], ["codemod", "move-tina-folder"]];
|
|
5999
6389
|
rootPath = Option5.String("--rootPath", {
|
|
@@ -6034,13 +6424,13 @@ var moveTinaFolder = async (rootPath = process.cwd()) => {
|
|
|
6034
6424
|
logger.error(e.message);
|
|
6035
6425
|
process.exit(1);
|
|
6036
6426
|
}
|
|
6037
|
-
const tinaDestination =
|
|
6038
|
-
if (await
|
|
6427
|
+
const tinaDestination = path18.join(configManager.rootPath, "tina");
|
|
6428
|
+
if (await fs16.existsSync(tinaDestination)) {
|
|
6039
6429
|
logger.info(
|
|
6040
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.`
|
|
6041
6431
|
);
|
|
6042
6432
|
} else {
|
|
6043
|
-
await
|
|
6433
|
+
await fs16.moveSync(configManager.tinaFolderPath, tinaDestination);
|
|
6044
6434
|
await writeGitignore(configManager.rootPath);
|
|
6045
6435
|
logger.info(
|
|
6046
6436
|
"Move to 'tina' folder complete. Be sure to update any imports of the autogenerated client!"
|
|
@@ -6048,8 +6438,8 @@ var moveTinaFolder = async (rootPath = process.cwd()) => {
|
|
|
6048
6438
|
}
|
|
6049
6439
|
};
|
|
6050
6440
|
var writeGitignore = async (rootPath) => {
|
|
6051
|
-
await
|
|
6052
|
-
|
|
6441
|
+
await fs16.outputFileSync(
|
|
6442
|
+
path18.join(rootPath, "tina", ".gitignore"),
|
|
6053
6443
|
"__generated__"
|
|
6054
6444
|
);
|
|
6055
6445
|
};
|
|
@@ -6108,7 +6498,7 @@ const BlogPage = (props) => {
|
|
|
6108
6498
|
{' '}
|
|
6109
6499
|
Check out this guide
|
|
6110
6500
|
</a>{' '}
|
|
6111
|
-
to see how add TinaCMS to an existing Next.js site.
|
|
6501
|
+
to see how to add TinaCMS to an existing Next.js site.
|
|
6112
6502
|
</div>
|
|
6113
6503
|
</div>
|
|
6114
6504
|
</>
|
|
@@ -6560,8 +6950,8 @@ function extendAstroScripts(scripts) {
|
|
|
6560
6950
|
}
|
|
6561
6951
|
|
|
6562
6952
|
// src/cmds/init/astro-visual-editing.ts
|
|
6563
|
-
import
|
|
6564
|
-
import
|
|
6953
|
+
import fs17 from "fs-extra";
|
|
6954
|
+
import path19 from "path";
|
|
6565
6955
|
var TS_NOCHECK = "// @ts-nocheck (generated types/client appear after your first tinacms dev run)\n";
|
|
6566
6956
|
var DEMO_FILES = {
|
|
6567
6957
|
"src/lib/tina/data.ts": `${TS_NOCHECK}import { requestWithMetadata } from '@tinacms/astro/data';
|
|
@@ -6832,8 +7222,8 @@ var ASTRO_CONFIG_FILES = [
|
|
|
6832
7222
|
"astro.config.cjs",
|
|
6833
7223
|
"astro.config.cts"
|
|
6834
7224
|
];
|
|
6835
|
-
var findAstroConfig = (baseDir) => ASTRO_CONFIG_FILES.map((file) =>
|
|
6836
|
-
(p) =>
|
|
7225
|
+
var findAstroConfig = (baseDir) => ASTRO_CONFIG_FILES.map((file) => path19.join(baseDir, file)).find(
|
|
7226
|
+
(p) => fs17.existsSync(p)
|
|
6837
7227
|
);
|
|
6838
7228
|
var setupAstroVisualEditing = ({
|
|
6839
7229
|
baseDir
|
|
@@ -6851,17 +7241,17 @@ var setupAstroVisualEditing = ({
|
|
|
6851
7241
|
return { configHandled: true, demoScaffolded: false };
|
|
6852
7242
|
}
|
|
6853
7243
|
for (const rel of relPaths) {
|
|
6854
|
-
|
|
7244
|
+
fs17.outputFileSync(path19.join(baseDir, rel), DEMO_FILES[rel]);
|
|
6855
7245
|
}
|
|
6856
7246
|
logger.info("Adding a visual-editing demo at /tinacms-demo... \u2705");
|
|
6857
7247
|
const configPath = findAstroConfig(baseDir);
|
|
6858
7248
|
if (!configPath) {
|
|
6859
|
-
|
|
7249
|
+
fs17.writeFileSync(path19.join(baseDir, "astro.config.mjs"), ASTRO_CONFIG);
|
|
6860
7250
|
logger.info("Creating astro.config for visual editing... \u2705");
|
|
6861
7251
|
return { configHandled: true, demoScaffolded: true };
|
|
6862
7252
|
}
|
|
6863
|
-
if (isDefaultAstroConfig(
|
|
6864
|
-
|
|
7253
|
+
if (isDefaultAstroConfig(fs17.readFileSync(configPath).toString())) {
|
|
7254
|
+
fs17.writeFileSync(configPath, ASTRO_CONFIG);
|
|
6865
7255
|
logger.info("Wiring astro.config for visual editing... \u2705");
|
|
6866
7256
|
return { configHandled: true, demoScaffolded: true };
|
|
6867
7257
|
}
|
|
@@ -6873,7 +7263,7 @@ var logAstroConfigGuidance = () => {
|
|
|
6873
7263
|
|
|
6874
7264
|
// src/cmds/init/codegen/index.ts
|
|
6875
7265
|
import ts2 from "typescript";
|
|
6876
|
-
import
|
|
7266
|
+
import fs18 from "fs-extra";
|
|
6877
7267
|
|
|
6878
7268
|
// src/cmds/init/codegen/util.ts
|
|
6879
7269
|
import ts from "typescript";
|
|
@@ -7110,7 +7500,7 @@ var addSelfHostedTinaAuthToConfig = async (config2, configFile) => {
|
|
|
7110
7500
|
const pathToConfig = configFile.resolve(config2.typescript).path;
|
|
7111
7501
|
const sourceFile = ts2.createSourceFile(
|
|
7112
7502
|
pathToConfig,
|
|
7113
|
-
|
|
7503
|
+
fs18.readFileSync(pathToConfig, "utf8"),
|
|
7114
7504
|
config2.typescript ? ts2.ScriptTarget.Latest : ts2.ScriptTarget.ESNext
|
|
7115
7505
|
);
|
|
7116
7506
|
const { configImports, configAuthProviderClass, extraTinaCollections } = config2.authProvider;
|
|
@@ -7160,7 +7550,7 @@ var addSelfHostedTinaAuthToConfig = async (config2, configFile) => {
|
|
|
7160
7550
|
)
|
|
7161
7551
|
].map((visitor) => makeTransformer(visitor))
|
|
7162
7552
|
);
|
|
7163
|
-
return
|
|
7553
|
+
return fs18.writeFile(
|
|
7164
7554
|
pathToConfig,
|
|
7165
7555
|
ts2.createPrinter({ omitTrailingSemicolon: true }).printFile(transformedSourceFileResult.transformed[0])
|
|
7166
7556
|
);
|
|
@@ -7286,8 +7676,8 @@ async function apply({
|
|
|
7286
7676
|
await addConfigFile({
|
|
7287
7677
|
configArgs: {
|
|
7288
7678
|
config: config2,
|
|
7289
|
-
publicFolder:
|
|
7290
|
-
|
|
7679
|
+
publicFolder: path20.join(
|
|
7680
|
+
path20.relative(process.cwd(), pathToForestryConfig),
|
|
7291
7681
|
config2.publicFolder
|
|
7292
7682
|
),
|
|
7293
7683
|
collections,
|
|
@@ -7364,8 +7754,8 @@ var createPackageJSON = async () => {
|
|
|
7364
7754
|
};
|
|
7365
7755
|
var createGitignore = async ({ baseDir }) => {
|
|
7366
7756
|
logger.info(logText("No .gitignore found, creating one"));
|
|
7367
|
-
|
|
7368
|
-
|
|
7757
|
+
fs19.outputFileSync(
|
|
7758
|
+
path20.join(baseDir, ".gitignore"),
|
|
7369
7759
|
"node_modules\ntina/__generated__\n"
|
|
7370
7760
|
);
|
|
7371
7761
|
};
|
|
@@ -7374,11 +7764,11 @@ var updateGitIgnore = async ({
|
|
|
7374
7764
|
items
|
|
7375
7765
|
}) => {
|
|
7376
7766
|
logger.info(logText(`Adding ${items.join(",")} to .gitignore`));
|
|
7377
|
-
const gitignoreContent =
|
|
7767
|
+
const gitignoreContent = fs19.readFileSync(path20.join(baseDir, ".gitignore")).toString();
|
|
7378
7768
|
const newGitignoreContent = [...gitignoreContent.split("\n"), ...items].join(
|
|
7379
7769
|
"\n"
|
|
7380
7770
|
);
|
|
7381
|
-
await
|
|
7771
|
+
await fs19.writeFile(path20.join(baseDir, ".gitignore"), newGitignoreContent);
|
|
7382
7772
|
};
|
|
7383
7773
|
var addDependencies = async (config2, env, params) => {
|
|
7384
7774
|
const { packageManager } = config2;
|
|
@@ -7455,22 +7845,22 @@ var writeGeneratedFile = async ({
|
|
|
7455
7845
|
content,
|
|
7456
7846
|
typescript
|
|
7457
7847
|
}) => {
|
|
7458
|
-
const { exists, path:
|
|
7848
|
+
const { exists, path: path22, parentPath } = generatedFile.resolve(typescript);
|
|
7459
7849
|
if (exists) {
|
|
7460
7850
|
if (overwrite) {
|
|
7461
|
-
logger.info(`Overwriting file at ${
|
|
7462
|
-
|
|
7851
|
+
logger.info(`Overwriting file at ${path22}... \u2705`);
|
|
7852
|
+
fs19.outputFileSync(path22, content);
|
|
7463
7853
|
} else {
|
|
7464
|
-
logger.info(`Not overwriting file at ${
|
|
7854
|
+
logger.info(`Not overwriting file at ${path22}.`);
|
|
7465
7855
|
logger.info(
|
|
7466
|
-
logText(`Please add the following to ${
|
|
7856
|
+
logText(`Please add the following to ${path22}:
|
|
7467
7857
|
${indentText(content)}}`)
|
|
7468
7858
|
);
|
|
7469
7859
|
}
|
|
7470
7860
|
} else {
|
|
7471
|
-
logger.info(`Adding file at ${
|
|
7472
|
-
await
|
|
7473
|
-
|
|
7861
|
+
logger.info(`Adding file at ${path22}... \u2705`);
|
|
7862
|
+
await fs19.ensureDir(parentPath);
|
|
7863
|
+
fs19.outputFileSync(path22, content);
|
|
7474
7864
|
}
|
|
7475
7865
|
};
|
|
7476
7866
|
var addConfigFile = async ({
|
|
@@ -7548,7 +7938,7 @@ var addContentFile = async ({
|
|
|
7548
7938
|
return () => ({
|
|
7549
7939
|
exists: env.sampleContentExists,
|
|
7550
7940
|
path: env.sampleContentPath,
|
|
7551
|
-
parentPath:
|
|
7941
|
+
parentPath: path20.dirname(env.sampleContentPath)
|
|
7552
7942
|
});
|
|
7553
7943
|
}
|
|
7554
7944
|
},
|
|
@@ -7572,10 +7962,10 @@ ${titleText(" TinaCMS ")} backend initialized!`));
|
|
|
7572
7962
|
return `${x.key}=${x.value || "***"}`;
|
|
7573
7963
|
}).join("\n") + `
|
|
7574
7964
|
TINA_PUBLIC_IS_LOCAL=true`;
|
|
7575
|
-
const envFile =
|
|
7576
|
-
if (!
|
|
7965
|
+
const envFile = path20.join(process.cwd(), ".env");
|
|
7966
|
+
if (!fs19.existsSync(envFile)) {
|
|
7577
7967
|
logger.info(`Adding .env file to your project... \u2705`);
|
|
7578
|
-
|
|
7968
|
+
fs19.writeFileSync(envFile, envFileText);
|
|
7579
7969
|
} else {
|
|
7580
7970
|
logger.info(
|
|
7581
7971
|
"Please add the following environment variables to your .env file"
|
|
@@ -7652,7 +8042,7 @@ var addReactiveFile = {
|
|
|
7652
8042
|
baseDir,
|
|
7653
8043
|
dataLayer
|
|
7654
8044
|
}) => {
|
|
7655
|
-
const packageJsonPath =
|
|
8045
|
+
const packageJsonPath = path20.join(baseDir, "package.json");
|
|
7656
8046
|
await writeGeneratedFile({
|
|
7657
8047
|
generatedFile,
|
|
7658
8048
|
typescript: config2.typescript,
|
|
@@ -7665,7 +8055,7 @@ var addReactiveFile = {
|
|
|
7665
8055
|
})
|
|
7666
8056
|
});
|
|
7667
8057
|
logger.info("Adding a nextjs example... \u2705");
|
|
7668
|
-
const packageJson = JSON.parse(
|
|
8058
|
+
const packageJson = JSON.parse(fs19.readFileSync(packageJsonPath).toString());
|
|
7669
8059
|
const scripts = packageJson.scripts || {};
|
|
7670
8060
|
const updatedPackageJson = JSON.stringify(
|
|
7671
8061
|
{
|
|
@@ -7678,15 +8068,15 @@ var addReactiveFile = {
|
|
|
7678
8068
|
null,
|
|
7679
8069
|
2
|
|
7680
8070
|
);
|
|
7681
|
-
|
|
8071
|
+
fs19.writeFileSync(packageJsonPath, updatedPackageJson);
|
|
7682
8072
|
}
|
|
7683
8073
|
};
|
|
7684
8074
|
var updateAstroPackageJson = async ({ baseDir }) => {
|
|
7685
|
-
const packageJsonPath =
|
|
7686
|
-
if (!
|
|
8075
|
+
const packageJsonPath = path20.join(baseDir, "package.json");
|
|
8076
|
+
if (!fs19.existsSync(packageJsonPath)) {
|
|
7687
8077
|
return;
|
|
7688
8078
|
}
|
|
7689
|
-
const packageJson = JSON.parse(
|
|
8079
|
+
const packageJson = JSON.parse(fs19.readFileSync(packageJsonPath).toString());
|
|
7690
8080
|
const scripts = packageJson.scripts || {};
|
|
7691
8081
|
const updatedPackageJson = JSON.stringify(
|
|
7692
8082
|
{
|
|
@@ -7696,7 +8086,7 @@ var updateAstroPackageJson = async ({ baseDir }) => {
|
|
|
7696
8086
|
null,
|
|
7697
8087
|
2
|
|
7698
8088
|
);
|
|
7699
|
-
|
|
8089
|
+
fs19.writeFileSync(packageJsonPath, updatedPackageJson);
|
|
7700
8090
|
logger.info("Updating package.json scripts for Astro... \u2705");
|
|
7701
8091
|
};
|
|
7702
8092
|
function execShellCommand(cmd) {
|
|
@@ -7896,8 +8286,8 @@ var SearchIndexCommand = class extends Command7 {
|
|
|
7896
8286
|
import { Command as Command8, Option as Option8 } from "clipanion";
|
|
7897
8287
|
|
|
7898
8288
|
// src/next/commands/doctor-command/doctor.ts
|
|
7899
|
-
import
|
|
7900
|
-
import
|
|
8289
|
+
import path21 from "path";
|
|
8290
|
+
import fs20 from "fs-extra";
|
|
7901
8291
|
import yaml3 from "js-yaml";
|
|
7902
8292
|
var DEPENDENCY_TYPES = [
|
|
7903
8293
|
"dependencies",
|
|
@@ -7930,11 +8320,11 @@ function getTinaDependencies(packageJson) {
|
|
|
7930
8320
|
);
|
|
7931
8321
|
}
|
|
7932
8322
|
async function readProjectPackageJson(rootPath) {
|
|
7933
|
-
const packageJsonPath =
|
|
7934
|
-
if (!await
|
|
8323
|
+
const packageJsonPath = path21.join(rootPath, "package.json");
|
|
8324
|
+
if (!await fs20.pathExists(packageJsonPath)) {
|
|
7935
8325
|
throw new Error(`No package.json found at ${packageJsonPath}`);
|
|
7936
8326
|
}
|
|
7937
|
-
return
|
|
8327
|
+
return fs20.readJSON(packageJsonPath);
|
|
7938
8328
|
}
|
|
7939
8329
|
async function resolveInstalledVersions({
|
|
7940
8330
|
rootPath,
|
|
@@ -8057,14 +8447,14 @@ function isLocalReference(version2) {
|
|
|
8057
8447
|
);
|
|
8058
8448
|
}
|
|
8059
8449
|
async function readNodeModulesVersion(rootPath, packageName) {
|
|
8060
|
-
const packageJsonPath =
|
|
8450
|
+
const packageJsonPath = path21.join(
|
|
8061
8451
|
rootPath,
|
|
8062
8452
|
"node_modules",
|
|
8063
8453
|
...packageName.split("/"),
|
|
8064
8454
|
"package.json"
|
|
8065
8455
|
);
|
|
8066
|
-
if (!await
|
|
8067
|
-
const packageJson = await
|
|
8456
|
+
if (!await fs20.pathExists(packageJsonPath)) return void 0;
|
|
8457
|
+
const packageJson = await fs20.readJSON(packageJsonPath);
|
|
8068
8458
|
return typeof packageJson.version === "string" ? packageJson.version : void 0;
|
|
8069
8459
|
}
|
|
8070
8460
|
async function readLockfileVersions(rootPath) {
|
|
@@ -8080,10 +8470,10 @@ async function readLockfileVersions(rootPath) {
|
|
|
8080
8470
|
return /* @__PURE__ */ new Map();
|
|
8081
8471
|
}
|
|
8082
8472
|
async function readPackageLockVersions(rootPath) {
|
|
8083
|
-
const lockfilePath =
|
|
8473
|
+
const lockfilePath = path21.join(rootPath, "package-lock.json");
|
|
8084
8474
|
const versions = /* @__PURE__ */ new Map();
|
|
8085
|
-
if (!await
|
|
8086
|
-
const lockfile = await
|
|
8475
|
+
if (!await fs20.pathExists(lockfilePath)) return versions;
|
|
8476
|
+
const lockfile = await fs20.readJSON(lockfilePath);
|
|
8087
8477
|
for (const [key, value] of Object.entries(lockfile.packages || {})) {
|
|
8088
8478
|
if (!key.startsWith("node_modules/")) continue;
|
|
8089
8479
|
const name2 = key.replace(/^node_modules\//, "");
|
|
@@ -8101,10 +8491,10 @@ async function readPackageLockVersions(rootPath) {
|
|
|
8101
8491
|
return versions;
|
|
8102
8492
|
}
|
|
8103
8493
|
async function readPnpmLockVersions(rootPath) {
|
|
8104
|
-
const lockfilePath =
|
|
8494
|
+
const lockfilePath = path21.join(rootPath, "pnpm-lock.yaml");
|
|
8105
8495
|
const versions = /* @__PURE__ */ new Map();
|
|
8106
|
-
if (!await
|
|
8107
|
-
const lockfile = yaml3.load(await
|
|
8496
|
+
if (!await fs20.pathExists(lockfilePath)) return versions;
|
|
8497
|
+
const lockfile = yaml3.load(await fs20.readFile(lockfilePath, "utf8"));
|
|
8108
8498
|
const rootImporter = lockfile?.importers?.["."];
|
|
8109
8499
|
for (const dependencyType of DEPENDENCY_TYPES) {
|
|
8110
8500
|
for (const [name2, value] of Object.entries(
|
|
@@ -8124,10 +8514,10 @@ async function readPnpmLockVersions(rootPath) {
|
|
|
8124
8514
|
return versions;
|
|
8125
8515
|
}
|
|
8126
8516
|
async function readYarnLockVersions(rootPath) {
|
|
8127
|
-
const lockfilePath =
|
|
8517
|
+
const lockfilePath = path21.join(rootPath, "yarn.lock");
|
|
8128
8518
|
const versions = /* @__PURE__ */ new Map();
|
|
8129
|
-
if (!await
|
|
8130
|
-
const contents = await
|
|
8519
|
+
if (!await fs20.pathExists(lockfilePath)) return versions;
|
|
8520
|
+
const contents = await fs20.readFile(lockfilePath, "utf8");
|
|
8131
8521
|
if (contents.includes("__metadata:")) {
|
|
8132
8522
|
return readYarnBerryLockVersions(contents);
|
|
8133
8523
|
}
|