cronus-ui 0.6.18 → 0.6.20
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/README.md +2 -2
- package/dist/commands/upgrade.js +17 -1
- package/dist/compose/gold-path.d.ts +7 -1
- package/dist/compose/gold-path.js +88 -54
- package/dist/config.d.ts +2 -2
- package/dist/config.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ Notes that match the commander surface:
|
|
|
49
49
|
`packages/cli/scripts/build-registry.ts` — each item carries its source, its npm
|
|
50
50
|
`dependencies`, and its `registryDependencies` (other components it imports),
|
|
51
51
|
derived by parsing imports.
|
|
52
|
-
- The default registry is pinned to the CLI package version (`v0.6.
|
|
52
|
+
- The default registry is pinned to the CLI package version (`v0.6.20` here), not
|
|
53
53
|
mutable `main`, so a published CLI reads the registry snapshot it was released
|
|
54
54
|
with. Use `-r, --registry ./registry` when testing local registry changes before
|
|
55
55
|
a release tag exists.
|
|
@@ -80,7 +80,7 @@ Notes that match the commander surface:
|
|
|
80
80
|
"lib": "lib",
|
|
81
81
|
"blocks": "components/blocks"
|
|
82
82
|
},
|
|
83
|
-
"registry": "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.6.
|
|
83
|
+
"registry": "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.6.20/registry"
|
|
84
84
|
}
|
|
85
85
|
```
|
|
86
86
|
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -5,7 +5,7 @@ import { tmpdir } from "node:os";
|
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { createInterface } from "node:readline/promises";
|
|
7
7
|
import pc from "picocolors";
|
|
8
|
-
import { goldPatchAppShellChrome, goldPatchHomePage, goldPatchShellLayout, goldPatchTeamPage, isGoldPathTemplate, } from "../compose/gold-path.js";
|
|
8
|
+
import { goldPatchAppShellChrome, goldPatchHomePage, goldPatchShellLayout, goldPatchTeamPage, isGoldPathTemplate, reemitGoldPathOwned, } from "../compose/gold-path.js";
|
|
9
9
|
import { buildComposePlan } from "../compose/plan.js";
|
|
10
10
|
import { baseSnapshotDest, filterManifestToComposedPages, listBaseSnapshotRels, readBaseSnapshot, reloadManifest, } from "../compose/reload.js";
|
|
11
11
|
import { renderPlan } from "../compose/render.js";
|
|
@@ -465,6 +465,21 @@ function goldPathSurfaceRels(cwd, composed) {
|
|
|
465
465
|
}
|
|
466
466
|
return [...rels];
|
|
467
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* `--all` on saas/admin: re-emit compose's `always: true` gold-path files so
|
|
470
|
+
* CLI gold-path fixes reach apps composed on an older release. Named upgrades
|
|
471
|
+
* (e.g. `upgrade stats`) do not touch them. auth.ts / schema stay user-owned.
|
|
472
|
+
*/
|
|
473
|
+
async function reemitGoldPathOwnedOnUpgrade(cwd, config, composed, upgradeComposed) {
|
|
474
|
+
if (!upgradeComposed)
|
|
475
|
+
return;
|
|
476
|
+
if (!Object.keys(composed).some((key) => isGoldPathTemplate(key)))
|
|
477
|
+
return;
|
|
478
|
+
const written = await reemitGoldPathOwned(cwd, config);
|
|
479
|
+
if (written.length === 0)
|
|
480
|
+
return;
|
|
481
|
+
log.ok(`gold-path owned: re-emitted ${written.join(", ")}`);
|
|
482
|
+
}
|
|
468
483
|
async function repatchGoldPathSurfaces(cwd, config, composed) {
|
|
469
484
|
if (!Object.keys(composed).some((key) => isGoldPathTemplate(key)))
|
|
470
485
|
return;
|
|
@@ -834,6 +849,7 @@ export async function upgrade(names, options) {
|
|
|
834
849
|
const newlyInstalled = await installPendingBlocks(itemPlans, config, cwd, targetVersion);
|
|
835
850
|
Object.assign(installed, newlyInstalled);
|
|
836
851
|
const written = await applyPlans(itemPlans, options, confirm);
|
|
852
|
+
await reemitGoldPathOwnedOnUpgrade(cwd, config, composed, upgradeComposed);
|
|
837
853
|
await repatchGoldPathSurfaces(cwd, config, composed);
|
|
838
854
|
await refreshComposeSnapshots(itemPlans);
|
|
839
855
|
// Manifest: record every item that now fully embodies the target release.
|
|
@@ -67,9 +67,15 @@ export declare function patchTeamPageSource(source: string, membersImport: strin
|
|
|
67
67
|
* app chrome. Idempotent. Returns undefined when AppShellNav is missing.
|
|
68
68
|
*/
|
|
69
69
|
export declare function patchShellLayoutSource(source: string, authImport: string): string | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Re-emit compose's `always: true` gold-path files. Idempotent when bytes
|
|
72
|
+
* already match. Used by `upgrade --all` so CLI gold-path fixes reach apps
|
|
73
|
+
* composed on an older release without clobbering auth.ts / schema.
|
|
74
|
+
*/
|
|
75
|
+
export declare function reemitGoldPathOwned(targetDir: string, config: CronusUIConfig): Promise<string[]>;
|
|
70
76
|
/**
|
|
71
77
|
* Write sqlite + Drizzle + Better-Auth files into a composed saas/admin app.
|
|
72
|
-
* Overwrites
|
|
78
|
+
* Overwrites owned adapters/panels always (`always: true`).
|
|
73
79
|
* Patches the shell home, /team, and shell layout only when compose wrote them
|
|
74
80
|
* this run.
|
|
75
81
|
*/
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Authenticated gold path for saas/admin compose: SQLite + Drizzle + Better-Auth.
|
|
3
3
|
* Always sqlite — postgres/mysql live in create-cronus-stack.
|
|
4
4
|
*/
|
|
5
|
+
import { randomBytes } from "node:crypto";
|
|
5
6
|
import { existsSync } from "node:fs";
|
|
6
7
|
import { readFile } from "node:fs/promises";
|
|
7
8
|
import { join } from "node:path";
|
|
@@ -66,12 +67,13 @@ const GOLD_PATH_SCRIPTS = {
|
|
|
66
67
|
"db:generate": "drizzle-kit generate",
|
|
67
68
|
"db:studio": "drizzle-kit studio",
|
|
68
69
|
};
|
|
70
|
+
const ENV_EXAMPLE_SECRET = "change-me-to-a-32-character-secret";
|
|
69
71
|
const ENV_VARS = {
|
|
70
72
|
DATABASE_URL: "file:./data/app.db",
|
|
71
|
-
BETTER_AUTH_SECRET:
|
|
73
|
+
BETTER_AUTH_SECRET: ENV_EXAMPLE_SECRET,
|
|
72
74
|
BETTER_AUTH_URL: "http://localhost:3000",
|
|
73
75
|
};
|
|
74
|
-
const GITIGNORE_ENTRIES = ["*.db", "data/", "drizzle/"];
|
|
76
|
+
const GITIGNORE_ENTRIES = ["*.db", "data/", "drizzle/", ".env"];
|
|
75
77
|
const DATABASE_URL_FALLBACK = "file:./data/app.db";
|
|
76
78
|
const TITLE_MAX = 200;
|
|
77
79
|
export function goldPathLayout(config) {
|
|
@@ -1251,6 +1253,21 @@ function mergeNextConfig(raw) {
|
|
|
1251
1253
|
}
|
|
1252
1254
|
return `${raw.trimEnd()}\n`;
|
|
1253
1255
|
}
|
|
1256
|
+
function envFileBody(secret) {
|
|
1257
|
+
return `${Object.entries({ ...ENV_VARS, BETTER_AUTH_SECRET: secret })
|
|
1258
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
1259
|
+
.join("\n")}\n`;
|
|
1260
|
+
}
|
|
1261
|
+
function newAuthSecret() {
|
|
1262
|
+
return randomBytes(32).toString("hex");
|
|
1263
|
+
}
|
|
1264
|
+
/** Write `.env` once so first `bun dev` has a real Better Auth secret. Never overwrite. */
|
|
1265
|
+
async function writeDotEnvIfMissing(targetDir) {
|
|
1266
|
+
const dest = resolveSafeDest(targetDir, ".", ".env");
|
|
1267
|
+
if (existsSync(dest))
|
|
1268
|
+
return;
|
|
1269
|
+
await writeFileEnsured(dest, envFileBody(newAuthSecret()));
|
|
1270
|
+
}
|
|
1254
1271
|
function mergeEnvExample(raw) {
|
|
1255
1272
|
const lines = raw.split(/\r?\n/);
|
|
1256
1273
|
const keys = new Set(lines.map((line) => {
|
|
@@ -1286,97 +1303,115 @@ async function writeRel(targetDir, rel, content, overwrite, always, written, ski
|
|
|
1286
1303
|
written.push(rel);
|
|
1287
1304
|
}
|
|
1288
1305
|
/**
|
|
1289
|
-
*
|
|
1290
|
-
*
|
|
1291
|
-
*
|
|
1292
|
-
* this run.
|
|
1306
|
+
* Gold-path files compose always overwrites (`always: true`). Scaffold files
|
|
1307
|
+
* (auth.ts, schema, middleware) are not in this list — those stay user-owned
|
|
1308
|
+
* after the first write.
|
|
1293
1309
|
*/
|
|
1294
|
-
|
|
1295
|
-
const { targetDir, config, generatedFiles, overwrite } = options;
|
|
1310
|
+
function goldPathOwnedFiles(config, appDir) {
|
|
1296
1311
|
const layout = goldPathLayout(config);
|
|
1297
|
-
const appDir = resolveAppDir(targetDir, layout, generatedFiles);
|
|
1298
|
-
const middlewareRel = appDir === "src/app"
|
|
1299
|
-
? "src/middleware.ts"
|
|
1300
|
-
: appDir === "app"
|
|
1301
|
-
? "middleware.ts"
|
|
1302
|
-
: layout.middlewareRel;
|
|
1303
1312
|
const authImport = `${config.aliases.lib}/auth`;
|
|
1304
1313
|
const authClientImport = `${config.aliases.lib}/auth-client`;
|
|
1305
1314
|
const itemsActionsImport = `${config.aliases.lib}/items`;
|
|
1306
1315
|
const itemsViewImport = "@/components/items-view";
|
|
1307
|
-
const itemsImport = "@/components/items-panel";
|
|
1308
1316
|
const membersActionsImport = `${config.aliases.lib}/members`;
|
|
1309
1317
|
const membersViewImport = "@/components/members-view";
|
|
1310
|
-
const membersImport = "@/components/members-panel";
|
|
1311
|
-
const workspaceImport = "@/components/workspace-menu";
|
|
1312
1318
|
const inviteImport = "@/components/invite-member";
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
const skipped = [];
|
|
1317
|
-
const files = [
|
|
1318
|
-
{ rel: "drizzle.config.ts", content: drizzleConfigSource(layout.dbDir) },
|
|
1319
|
-
{ rel: `${layout.dbDir}/schema.ts`, content: dbSchemaSource() },
|
|
1320
|
-
{ rel: `${layout.dbDir}/index.ts`, content: dbClientSource() },
|
|
1321
|
-
{ rel: `${layout.libDir}/auth.ts`, content: authServerSource() },
|
|
1322
|
-
{ rel: `${layout.libDir}/auth-client.ts`, content: authClientSource() },
|
|
1323
|
-
{ rel: `${layout.libDir}/auth-adapter.ts`, content: authAdapterSource(), always: true },
|
|
1324
|
-
{
|
|
1325
|
-
rel: `${layout.libDir}/items.ts`,
|
|
1326
|
-
content: itemsActionsSource(authImport),
|
|
1327
|
-
always: true,
|
|
1328
|
-
},
|
|
1329
|
-
{
|
|
1330
|
-
rel: `${appDir}/api/auth/[...all]/route.ts`,
|
|
1331
|
-
content: authRouteSource(authImport),
|
|
1332
|
-
},
|
|
1333
|
-
{ rel: middlewareRel, content: middlewareSource() },
|
|
1319
|
+
return [
|
|
1320
|
+
{ rel: `${layout.libDir}/auth-adapter.ts`, content: authAdapterSource() },
|
|
1321
|
+
{ rel: `${layout.libDir}/items.ts`, content: itemsActionsSource(authImport) },
|
|
1334
1322
|
{
|
|
1335
1323
|
rel: `${layout.componentsDir}/items-panel.tsx`,
|
|
1336
1324
|
content: itemsPanelSource(itemsActionsImport, itemsViewImport),
|
|
1337
|
-
always: true,
|
|
1338
1325
|
},
|
|
1339
1326
|
{
|
|
1340
1327
|
rel: `${layout.componentsDir}/items-view.tsx`,
|
|
1341
1328
|
content: itemsViewSource(itemsActionsImport),
|
|
1342
|
-
always: true,
|
|
1343
|
-
},
|
|
1344
|
-
{
|
|
1345
|
-
rel: `${layout.libDir}/members.ts`,
|
|
1346
|
-
content: membersActionsSource(authImport),
|
|
1347
|
-
always: true,
|
|
1348
1329
|
},
|
|
1330
|
+
{ rel: `${layout.libDir}/members.ts`, content: membersActionsSource(authImport) },
|
|
1349
1331
|
{
|
|
1350
1332
|
rel: `${layout.componentsDir}/members-panel.tsx`,
|
|
1351
1333
|
content: membersPanelSource(membersActionsImport, membersViewImport),
|
|
1352
|
-
always: true,
|
|
1353
1334
|
},
|
|
1354
1335
|
{
|
|
1355
1336
|
rel: `${layout.componentsDir}/members-view.tsx`,
|
|
1356
1337
|
content: membersViewSource(inviteImport),
|
|
1357
|
-
always: true,
|
|
1358
1338
|
},
|
|
1359
1339
|
{
|
|
1360
1340
|
rel: `${layout.componentsDir}/workspace-menu.tsx`,
|
|
1361
1341
|
content: workspaceMenuSource(authClientImport),
|
|
1362
|
-
always: true,
|
|
1363
1342
|
},
|
|
1364
1343
|
{
|
|
1365
1344
|
rel: `${layout.componentsDir}/invite-member.tsx`,
|
|
1366
1345
|
content: inviteMemberSource(authClientImport),
|
|
1367
|
-
always: true,
|
|
1368
1346
|
},
|
|
1369
1347
|
{
|
|
1370
1348
|
rel: `${layout.componentsDir}/session-user.tsx`,
|
|
1371
1349
|
content: sessionUserSource(authClientImport),
|
|
1372
|
-
always: true,
|
|
1373
1350
|
},
|
|
1374
1351
|
{
|
|
1375
1352
|
rel: `${appDir}/(bare)/accept-invitation/page.tsx`,
|
|
1376
1353
|
content: acceptInvitationPageSource(authClientImport),
|
|
1377
|
-
always: true,
|
|
1378
1354
|
},
|
|
1379
1355
|
];
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* Re-emit compose's `always: true` gold-path files. Idempotent when bytes
|
|
1359
|
+
* already match. Used by `upgrade --all` so CLI gold-path fixes reach apps
|
|
1360
|
+
* composed on an older release without clobbering auth.ts / schema.
|
|
1361
|
+
*/
|
|
1362
|
+
export async function reemitGoldPathOwned(targetDir, config) {
|
|
1363
|
+
const layout = goldPathLayout(config);
|
|
1364
|
+
const appDir = resolveAppDir(targetDir, layout, []);
|
|
1365
|
+
const written = [];
|
|
1366
|
+
for (const file of goldPathOwnedFiles(config, appDir)) {
|
|
1367
|
+
const dest = resolveSafeDest(targetDir, ".", file.rel);
|
|
1368
|
+
if (existsSync(dest)) {
|
|
1369
|
+
const current = await readFile(dest, "utf8");
|
|
1370
|
+
if (current === file.content)
|
|
1371
|
+
continue;
|
|
1372
|
+
}
|
|
1373
|
+
await writeFileEnsured(dest, file.content);
|
|
1374
|
+
written.push(file.rel);
|
|
1375
|
+
}
|
|
1376
|
+
return written;
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Write sqlite + Drizzle + Better-Auth files into a composed saas/admin app.
|
|
1380
|
+
* Overwrites owned adapters/panels always (`always: true`).
|
|
1381
|
+
* Patches the shell home, /team, and shell layout only when compose wrote them
|
|
1382
|
+
* this run.
|
|
1383
|
+
*/
|
|
1384
|
+
export async function applyGoldPath(options) {
|
|
1385
|
+
const { targetDir, config, generatedFiles, overwrite } = options;
|
|
1386
|
+
const layout = goldPathLayout(config);
|
|
1387
|
+
const appDir = resolveAppDir(targetDir, layout, generatedFiles);
|
|
1388
|
+
const middlewareRel = appDir === "src/app"
|
|
1389
|
+
? "src/middleware.ts"
|
|
1390
|
+
: appDir === "app"
|
|
1391
|
+
? "middleware.ts"
|
|
1392
|
+
: layout.middlewareRel;
|
|
1393
|
+
const authImport = `${config.aliases.lib}/auth`;
|
|
1394
|
+
const itemsImport = "@/components/items-panel";
|
|
1395
|
+
const membersImport = "@/components/members-panel";
|
|
1396
|
+
const workspaceImport = "@/components/workspace-menu";
|
|
1397
|
+
const inviteImport = "@/components/invite-member";
|
|
1398
|
+
const sessionImport = "@/components/session-user";
|
|
1399
|
+
const chromeRel = `${posix(config.paths.blocks)}/app-shell-chrome.tsx`;
|
|
1400
|
+
const written = [];
|
|
1401
|
+
const skipped = [];
|
|
1402
|
+
const files = [
|
|
1403
|
+
{ rel: "drizzle.config.ts", content: drizzleConfigSource(layout.dbDir) },
|
|
1404
|
+
{ rel: `${layout.dbDir}/schema.ts`, content: dbSchemaSource() },
|
|
1405
|
+
{ rel: `${layout.dbDir}/index.ts`, content: dbClientSource() },
|
|
1406
|
+
{ rel: `${layout.libDir}/auth.ts`, content: authServerSource() },
|
|
1407
|
+
{ rel: `${layout.libDir}/auth-client.ts`, content: authClientSource() },
|
|
1408
|
+
{
|
|
1409
|
+
rel: `${appDir}/api/auth/[...all]/route.ts`,
|
|
1410
|
+
content: authRouteSource(authImport),
|
|
1411
|
+
},
|
|
1412
|
+
{ rel: middlewareRel, content: middlewareSource() },
|
|
1413
|
+
...goldPathOwnedFiles(config, appDir).map((file) => ({ ...file, always: true })),
|
|
1414
|
+
];
|
|
1380
1415
|
for (const file of files) {
|
|
1381
1416
|
await writeRel(targetDir, file.rel, file.content, overwrite, file.always === true, written, skipped);
|
|
1382
1417
|
}
|
|
@@ -1445,9 +1480,8 @@ export async function applyGoldPath(options) {
|
|
|
1445
1480
|
}
|
|
1446
1481
|
await mergeTextFile(targetDir, "package.json", mergePackageJson);
|
|
1447
1482
|
await mergeOrCreate(targetDir, "next.config.mjs", nextConfigSource(), mergeNextConfig);
|
|
1448
|
-
await mergeOrCreate(targetDir, ".env.example",
|
|
1449
|
-
|
|
1450
|
-
.join("\n")}\n`, mergeEnvExample);
|
|
1483
|
+
await mergeOrCreate(targetDir, ".env.example", envFileBody(ENV_EXAMPLE_SECRET), mergeEnvExample);
|
|
1484
|
+
await writeDotEnvIfMissing(targetDir);
|
|
1451
1485
|
await mergeOrCreate(targetDir, ".gitignore", `${GITIGNORE_ENTRIES.join("\n")}\n`, mergeGitignore);
|
|
1452
1486
|
return { written, skipped };
|
|
1453
1487
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const CONFIG_FILE = "cronus-ui.json";
|
|
2
|
-
export declare const CLI_VERSION = "0.6.
|
|
3
|
-
export declare const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.6.
|
|
2
|
+
export declare const CLI_VERSION = "0.6.20";
|
|
3
|
+
export declare const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.6.20/registry";
|
|
4
4
|
/** Manifest entry `add`/`upgrade` record per installed registry item. */
|
|
5
5
|
export interface InstalledRecord {
|
|
6
6
|
/** Registry release the files came from (git tag without the leading "v"). */
|
package/dist/config.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import { readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
export const CONFIG_FILE = "cronus-ui.json";
|
|
5
|
-
export const CLI_VERSION = "0.6.
|
|
5
|
+
export const CLI_VERSION = "0.6.20";
|
|
6
6
|
export const DEFAULT_REGISTRY = `https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v${CLI_VERSION}/registry`;
|
|
7
7
|
export const DEFAULT_CONFIG = {
|
|
8
8
|
aliases: { ui: "@/components/ui", lib: "@/lib", blocks: "@/components/blocks" },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cronus-ui",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.20",
|
|
4
4
|
"description": "cronus-ui — add Cronus UI components to your project, shadcn-style (copy-paste registry).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"registry:check": "bun run scripts/check-registry.ts"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@cronus-ui/ai-kit": "0.6.
|
|
57
|
+
"@cronus-ui/ai-kit": "0.6.20",
|
|
58
58
|
"commander": "^15.0.0",
|
|
59
59
|
"picocolors": "^1.1.1"
|
|
60
60
|
},
|