@lumerahq/cli 0.10.1 → 0.11.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/dist/{chunk-WTDV3MTG.js → chunk-CHRKCAIZ.js} +54 -3
- package/dist/{chunk-WRAZC6SJ.js → chunk-HIYM7EM2.js} +17 -1
- package/dist/dev-2HVDP3NX.js +155 -0
- package/dist/index.js +164 -16
- package/dist/{init-OH433IPH.js → init-4JSHTLX2.js} +139 -77
- package/dist/{resources-PGBVCS2K.js → resources-ZRAW4EFI.js} +60 -41
- package/dist/{run-WIRQDYYX.js → run-47GF5VVS.js} +2 -4
- package/dist/templates-6KMZWOYH.js +194 -0
- package/package.json +1 -1
- package/dist/chunk-2CR762KB.js +0 -18
- package/dist/dev-BHBF4ECH.js +0 -87
- package/dist/templates-67O6PVFK.js +0 -70
|
@@ -2,11 +2,9 @@ import {
|
|
|
2
2
|
deploy
|
|
3
3
|
} from "./chunk-CDZZ3JYU.js";
|
|
4
4
|
import {
|
|
5
|
-
createApiClient
|
|
6
|
-
} from "./chunk-WRAZC6SJ.js";
|
|
7
|
-
import {
|
|
5
|
+
createApiClient,
|
|
8
6
|
loadEnv
|
|
9
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-HIYM7EM2.js";
|
|
10
8
|
import {
|
|
11
9
|
getToken
|
|
12
10
|
} from "./chunk-NDLYGKS6.js";
|
|
@@ -235,7 +233,7 @@ function loadLocalCollections(platformDir, filterName) {
|
|
|
235
233
|
}
|
|
236
234
|
return collections;
|
|
237
235
|
}
|
|
238
|
-
function loadLocalAutomations(platformDir, filterName) {
|
|
236
|
+
function loadLocalAutomations(platformDir, filterName, appName) {
|
|
239
237
|
const automationsDir = join(platformDir, "automations");
|
|
240
238
|
if (!existsSync(automationsDir)) {
|
|
241
239
|
return [];
|
|
@@ -262,8 +260,12 @@ function loadLocalAutomations(platformDir, filterName) {
|
|
|
262
260
|
continue;
|
|
263
261
|
}
|
|
264
262
|
if (!config.external_id) {
|
|
265
|
-
|
|
266
|
-
|
|
263
|
+
if (appName) {
|
|
264
|
+
config.external_id = `${appName}:${entry.name}`;
|
|
265
|
+
} else {
|
|
266
|
+
errors.push(`${entry.name}: missing external_id in config.json`);
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
267
269
|
}
|
|
268
270
|
if (!config.name) {
|
|
269
271
|
errors.push(`${entry.name}: missing name in config.json`);
|
|
@@ -288,7 +290,7 @@ function loadLocalAutomations(platformDir, filterName) {
|
|
|
288
290
|
}
|
|
289
291
|
return automations;
|
|
290
292
|
}
|
|
291
|
-
function loadLocalHooks(platformDir, filterName) {
|
|
293
|
+
function loadLocalHooks(platformDir, filterName, appName) {
|
|
292
294
|
const hooksDir = join(platformDir, "hooks");
|
|
293
295
|
if (!existsSync(hooksDir)) {
|
|
294
296
|
return [];
|
|
@@ -304,13 +306,20 @@ function loadLocalHooks(platformDir, filterName) {
|
|
|
304
306
|
continue;
|
|
305
307
|
}
|
|
306
308
|
if (!config.external_id) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
+
if (appName) {
|
|
310
|
+
config.external_id = `${appName}:${file.replace(/\.(js|ts)$/, "")}`;
|
|
311
|
+
} else {
|
|
312
|
+
console.log(pc.yellow(` \u26A0 Skipping ${file}: missing external_id in config`));
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
309
315
|
}
|
|
310
316
|
if (filterName && config.external_id !== filterName && file.replace(/\.(js|ts)$/, "") !== filterName) {
|
|
311
317
|
continue;
|
|
312
318
|
}
|
|
313
|
-
|
|
319
|
+
let script = extractHookScript(content);
|
|
320
|
+
if (appName) {
|
|
321
|
+
script = script.replaceAll("{{app}}", appName);
|
|
322
|
+
}
|
|
314
323
|
hooks.push({ hook: config, script, fileName: file });
|
|
315
324
|
}
|
|
316
325
|
return hooks;
|
|
@@ -326,9 +335,9 @@ function parseHookConfig(content) {
|
|
|
326
335
|
const collection = content.match(/collection:\s*['"]([^'"]+)['"]/)?.[1];
|
|
327
336
|
const trigger = content.match(/trigger:\s*['"]([^'"]+)['"]/)?.[1];
|
|
328
337
|
const enabled = content.match(/enabled:\s*(true|false)/)?.[1];
|
|
329
|
-
if (!
|
|
338
|
+
if (!collection || !trigger) return null;
|
|
330
339
|
return {
|
|
331
|
-
external_id: externalId,
|
|
340
|
+
external_id: externalId || "",
|
|
332
341
|
collection,
|
|
333
342
|
trigger,
|
|
334
343
|
enabled: enabled !== "false"
|
|
@@ -814,7 +823,7 @@ ${hook.script.split("\n").map((line) => " " + line).join("\n")}
|
|
|
814
823
|
console.log(pc.green(" \u2713"), `${hook.name} \u2192 hooks/${fileName}`);
|
|
815
824
|
}
|
|
816
825
|
}
|
|
817
|
-
async function listResources(api, platformDir, filterType) {
|
|
826
|
+
async function listResources(api, platformDir, filterType, appName) {
|
|
818
827
|
const results = [];
|
|
819
828
|
if (!filterType || filterType === "collections") {
|
|
820
829
|
const localCollections = loadLocalCollections(platformDir);
|
|
@@ -848,7 +857,7 @@ async function listResources(api, platformDir, filterType) {
|
|
|
848
857
|
}
|
|
849
858
|
}
|
|
850
859
|
if (!filterType || filterType === "automations") {
|
|
851
|
-
const localAutomations = loadLocalAutomations(platformDir);
|
|
860
|
+
const localAutomations = loadLocalAutomations(platformDir, void 0, appName);
|
|
852
861
|
const remoteAutomations = await api.listAutomations({ include_code: true });
|
|
853
862
|
const remoteByExternalId = new Map(remoteAutomations.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a]));
|
|
854
863
|
const localIds = new Set(localAutomations.map((a) => a.automation.external_id));
|
|
@@ -874,7 +883,7 @@ async function listResources(api, platformDir, filterType) {
|
|
|
874
883
|
}
|
|
875
884
|
}
|
|
876
885
|
if (!filterType || filterType === "hooks") {
|
|
877
|
-
const localHooks = loadLocalHooks(platformDir);
|
|
886
|
+
const localHooks = loadLocalHooks(platformDir, void 0, appName);
|
|
878
887
|
const remoteHooks = await api.listHooks();
|
|
879
888
|
const remoteByExternalId = new Map(remoteHooks.filter((h) => h.external_id).map((h) => [h.external_id, h]));
|
|
880
889
|
const localIds = new Set(localHooks.map((h) => h.hook.external_id));
|
|
@@ -969,7 +978,7 @@ function planCollectionDelete(collections, platformDir) {
|
|
|
969
978
|
cycleEdges
|
|
970
979
|
};
|
|
971
980
|
}
|
|
972
|
-
async function destroyResources(api, platformDir, resourceType, resourceName, skipConfirm, forceCycles) {
|
|
981
|
+
async function destroyResources(api, platformDir, resourceType, resourceName, skipConfirm, forceCycles, appName) {
|
|
973
982
|
const toDelete = [];
|
|
974
983
|
if (!resourceType || resourceType === "collections") {
|
|
975
984
|
const localCollections = loadLocalCollections(platformDir, resourceName || void 0);
|
|
@@ -984,7 +993,7 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
|
|
|
984
993
|
}
|
|
985
994
|
if (!resourceType || resourceType === "automations") {
|
|
986
995
|
try {
|
|
987
|
-
const localAutomations = loadLocalAutomations(platformDir, resourceName || void 0);
|
|
996
|
+
const localAutomations = loadLocalAutomations(platformDir, resourceName || void 0, appName);
|
|
988
997
|
const remoteAutomations = await api.listAutomations();
|
|
989
998
|
const remoteByExternalId = new Map(remoteAutomations.filter((a) => a.external_id).map((a) => [a.external_id, a]));
|
|
990
999
|
for (const { automation } of localAutomations) {
|
|
@@ -997,7 +1006,7 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
|
|
|
997
1006
|
}
|
|
998
1007
|
}
|
|
999
1008
|
if (!resourceType || resourceType === "hooks") {
|
|
1000
|
-
const localHooks = loadLocalHooks(platformDir, resourceName || void 0);
|
|
1009
|
+
const localHooks = loadLocalHooks(platformDir, resourceName || void 0, appName);
|
|
1001
1010
|
const remoteHooks = await api.listHooks();
|
|
1002
1011
|
const remoteByExternalId = new Map(remoteHooks.filter((h) => h.external_id).map((h) => [h.external_id, h]));
|
|
1003
1012
|
for (const { hook } of localHooks) {
|
|
@@ -1139,7 +1148,7 @@ async function destroyApp(skipConfirm) {
|
|
|
1139
1148
|
}
|
|
1140
1149
|
console.log(pc.green(" \u2713"), `App "${appRecord.name}" deleted from Lumera.`);
|
|
1141
1150
|
}
|
|
1142
|
-
async function showResource(api, platformDir, resourceType, resourceName) {
|
|
1151
|
+
async function showResource(api, platformDir, resourceType, resourceName, appName) {
|
|
1143
1152
|
if (resourceType === "collections") {
|
|
1144
1153
|
const localCollections = loadLocalCollections(platformDir, resourceName);
|
|
1145
1154
|
const remoteCollections = await api.listCollections();
|
|
@@ -1203,7 +1212,7 @@ async function showResource(api, platformDir, resourceType, resourceName) {
|
|
|
1203
1212
|
}
|
|
1204
1213
|
console.log();
|
|
1205
1214
|
} else if (resourceType === "automations") {
|
|
1206
|
-
const localAutomations = loadLocalAutomations(platformDir, resourceName);
|
|
1215
|
+
const localAutomations = loadLocalAutomations(platformDir, resourceName, appName);
|
|
1207
1216
|
const remoteAutomations = await api.listAutomations();
|
|
1208
1217
|
const local = localAutomations[0];
|
|
1209
1218
|
const remote = remoteAutomations.find((a) => a.external_id === resourceName || a.name === resourceName);
|
|
@@ -1226,7 +1235,7 @@ async function showResource(api, platformDir, resourceType, resourceName) {
|
|
|
1226
1235
|
}
|
|
1227
1236
|
console.log();
|
|
1228
1237
|
} else if (resourceType === "hooks") {
|
|
1229
|
-
const localHooks = loadLocalHooks(platformDir, resourceName);
|
|
1238
|
+
const localHooks = loadLocalHooks(platformDir, resourceName, appName);
|
|
1230
1239
|
const remoteHooks = await api.listHooks();
|
|
1231
1240
|
const local = localHooks[0];
|
|
1232
1241
|
const remote = remoteHooks.find((h) => h.external_id === resourceName);
|
|
@@ -1245,14 +1254,14 @@ async function showResource(api, platformDir, resourceType, resourceName) {
|
|
|
1245
1254
|
const projectRoot = findProjectRoot();
|
|
1246
1255
|
loadEnv(projectRoot);
|
|
1247
1256
|
const token = getToken(projectRoot);
|
|
1248
|
-
const
|
|
1257
|
+
const appName2 = getAppName(projectRoot);
|
|
1249
1258
|
const appTitle = getAppTitle(projectRoot);
|
|
1250
1259
|
let apiUrl = getApiUrl().replace(/\/+$/, "").replace(/\/api$/, "");
|
|
1251
1260
|
console.log();
|
|
1252
|
-
console.log(pc.bold(` App: ${appTitle ||
|
|
1261
|
+
console.log(pc.bold(` App: ${appTitle || appName2}`));
|
|
1253
1262
|
console.log();
|
|
1254
|
-
console.log(` External ID: ${
|
|
1255
|
-
const filterParam = encodeURIComponent(JSON.stringify({ external_id:
|
|
1263
|
+
console.log(` External ID: ${appName2}`);
|
|
1264
|
+
const filterParam = encodeURIComponent(JSON.stringify({ external_id: appName2 }));
|
|
1256
1265
|
const searchRes = await fetch(
|
|
1257
1266
|
`${apiUrl}/api/pb/collections/lm_custom_apps/records?filter=${filterParam}`,
|
|
1258
1267
|
{ headers: { Authorization: `Bearer ${token}` } }
|
|
@@ -1277,9 +1286,11 @@ async function plan(args) {
|
|
|
1277
1286
|
showPlanHelp();
|
|
1278
1287
|
return;
|
|
1279
1288
|
}
|
|
1280
|
-
|
|
1289
|
+
const projectRoot = findProjectRoot();
|
|
1290
|
+
loadEnv(projectRoot);
|
|
1281
1291
|
const platformDir = getPlatformDir();
|
|
1282
1292
|
const api = createApiClient();
|
|
1293
|
+
const appName = getAppName(projectRoot);
|
|
1283
1294
|
const { type, name } = parseResource(args[0]);
|
|
1284
1295
|
console.log();
|
|
1285
1296
|
console.log(pc.cyan(pc.bold(" Plan")));
|
|
@@ -1301,14 +1312,14 @@ async function plan(args) {
|
|
|
1301
1312
|
}
|
|
1302
1313
|
}
|
|
1303
1314
|
if (!type || type === "automations") {
|
|
1304
|
-
const localAutomations = loadLocalAutomations(platformDir, name || void 0);
|
|
1315
|
+
const localAutomations = loadLocalAutomations(platformDir, name || void 0, appName);
|
|
1305
1316
|
if (localAutomations.length > 0) {
|
|
1306
1317
|
const changes = await planAutomations(api, localAutomations);
|
|
1307
1318
|
allChanges.push(...changes);
|
|
1308
1319
|
}
|
|
1309
1320
|
}
|
|
1310
1321
|
if (!type || type === "hooks") {
|
|
1311
|
-
const localHooks = loadLocalHooks(platformDir, name || void 0);
|
|
1322
|
+
const localHooks = loadLocalHooks(platformDir, name || void 0, appName);
|
|
1312
1323
|
if (localHooks.length > 0) {
|
|
1313
1324
|
const changes = await planHooks(api, localHooks, collections);
|
|
1314
1325
|
allChanges.push(...changes);
|
|
@@ -1344,9 +1355,11 @@ async function apply(args) {
|
|
|
1344
1355
|
showApplyHelp();
|
|
1345
1356
|
return;
|
|
1346
1357
|
}
|
|
1347
|
-
|
|
1358
|
+
const projectRoot = findProjectRoot();
|
|
1359
|
+
loadEnv(projectRoot);
|
|
1348
1360
|
const platformDir = getPlatformDir();
|
|
1349
1361
|
const api = createApiClient();
|
|
1362
|
+
const appName = getAppName(projectRoot);
|
|
1350
1363
|
const { type, name } = parseResource(args[0]);
|
|
1351
1364
|
console.log();
|
|
1352
1365
|
console.log(pc.cyan(pc.bold(" Apply")));
|
|
@@ -1382,7 +1395,7 @@ async function apply(args) {
|
|
|
1382
1395
|
collections = /* @__PURE__ */ new Map();
|
|
1383
1396
|
}
|
|
1384
1397
|
if (!type || type === "automations") {
|
|
1385
|
-
const localAutomations = loadLocalAutomations(platformDir, name || void 0);
|
|
1398
|
+
const localAutomations = loadLocalAutomations(platformDir, name || void 0, appName);
|
|
1386
1399
|
if (localAutomations.length > 0) {
|
|
1387
1400
|
console.log(pc.bold(" Automations:"));
|
|
1388
1401
|
totalErrors += await applyAutomations(api, localAutomations);
|
|
@@ -1393,7 +1406,7 @@ async function apply(args) {
|
|
|
1393
1406
|
}
|
|
1394
1407
|
}
|
|
1395
1408
|
if (!type || type === "hooks") {
|
|
1396
|
-
const localHooks = loadLocalHooks(platformDir, name || void 0);
|
|
1409
|
+
const localHooks = loadLocalHooks(platformDir, name || void 0, appName);
|
|
1397
1410
|
if (localHooks.length > 0) {
|
|
1398
1411
|
console.log(pc.bold(" Hooks:"));
|
|
1399
1412
|
totalErrors += await applyHooks(api, localHooks, collections);
|
|
@@ -1405,8 +1418,8 @@ async function apply(args) {
|
|
|
1405
1418
|
}
|
|
1406
1419
|
if (!type) {
|
|
1407
1420
|
try {
|
|
1408
|
-
const
|
|
1409
|
-
if (existsSync(join(
|
|
1421
|
+
const projectRoot2 = findProjectRoot();
|
|
1422
|
+
if (existsSync(join(projectRoot2, "dist")) || existsSync(join(projectRoot2, "src"))) {
|
|
1410
1423
|
console.log(pc.bold(" App:"));
|
|
1411
1424
|
await applyApp(args);
|
|
1412
1425
|
console.log();
|
|
@@ -1458,9 +1471,11 @@ async function destroy(args) {
|
|
|
1458
1471
|
showDestroyHelp();
|
|
1459
1472
|
return;
|
|
1460
1473
|
}
|
|
1461
|
-
|
|
1474
|
+
const projectRoot = findProjectRoot();
|
|
1475
|
+
loadEnv(projectRoot);
|
|
1462
1476
|
const platformDir = getPlatformDir();
|
|
1463
1477
|
const api = createApiClient();
|
|
1478
|
+
const appName = getAppName(projectRoot);
|
|
1464
1479
|
const { type, name } = parseResource(args[0]);
|
|
1465
1480
|
const skipConfirm = args.includes("--confirm");
|
|
1466
1481
|
const forceCycles = args.includes("--force-cycles");
|
|
@@ -1470,7 +1485,7 @@ async function destroy(args) {
|
|
|
1470
1485
|
if (type === "app") {
|
|
1471
1486
|
await destroyApp(skipConfirm);
|
|
1472
1487
|
} else {
|
|
1473
|
-
await destroyResources(api, platformDir, type || void 0, name || void 0, skipConfirm, forceCycles);
|
|
1488
|
+
await destroyResources(api, platformDir, type || void 0, name || void 0, skipConfirm, forceCycles, appName);
|
|
1474
1489
|
}
|
|
1475
1490
|
console.log();
|
|
1476
1491
|
}
|
|
@@ -1479,16 +1494,18 @@ async function list(args) {
|
|
|
1479
1494
|
showListHelp();
|
|
1480
1495
|
return;
|
|
1481
1496
|
}
|
|
1482
|
-
|
|
1497
|
+
const projectRoot = findProjectRoot();
|
|
1498
|
+
loadEnv(projectRoot);
|
|
1483
1499
|
const platformDir = getPlatformDir();
|
|
1484
1500
|
const api = createApiClient();
|
|
1501
|
+
const appName = getAppName(projectRoot);
|
|
1485
1502
|
const showAll = args.includes("--all");
|
|
1486
1503
|
const positionalArgs = args.filter((a) => !a.startsWith("--"));
|
|
1487
1504
|
const filterType = positionalArgs[0];
|
|
1488
1505
|
console.log();
|
|
1489
1506
|
console.log(pc.cyan(pc.bold(" Resources")));
|
|
1490
1507
|
console.log();
|
|
1491
|
-
const allResources = await listResources(api, platformDir, filterType);
|
|
1508
|
+
const allResources = await listResources(api, platformDir, filterType, appName);
|
|
1492
1509
|
const remoteOnlyCount = allResources.filter((r) => r.status === "remote-only").length;
|
|
1493
1510
|
const resources = showAll ? allResources : allResources.filter((r) => r.status !== "remote-only");
|
|
1494
1511
|
if (resources.length === 0 && remoteOnlyCount === 0) {
|
|
@@ -1557,9 +1574,11 @@ async function show(args) {
|
|
|
1557
1574
|
if (args.length === 0) process.exit(1);
|
|
1558
1575
|
return;
|
|
1559
1576
|
}
|
|
1560
|
-
|
|
1577
|
+
const projectRoot = findProjectRoot();
|
|
1578
|
+
loadEnv(projectRoot);
|
|
1561
1579
|
const platformDir = getPlatformDir();
|
|
1562
1580
|
const api = createApiClient();
|
|
1581
|
+
const appName = getAppName(projectRoot);
|
|
1563
1582
|
const { type, name } = parseResource(args[0]);
|
|
1564
1583
|
if (!type) {
|
|
1565
1584
|
console.log(pc.red(` Invalid resource path: ${args[0]}`));
|
|
@@ -1567,13 +1586,13 @@ async function show(args) {
|
|
|
1567
1586
|
process.exit(1);
|
|
1568
1587
|
}
|
|
1569
1588
|
if (type === "app") {
|
|
1570
|
-
await showResource(api, platformDir, "app", "");
|
|
1589
|
+
await showResource(api, platformDir, "app", "", appName);
|
|
1571
1590
|
} else if (!name) {
|
|
1572
1591
|
console.log(pc.red(` Resource name required`));
|
|
1573
1592
|
console.log(pc.dim(" Use format: <type>/<name> (e.g., collections/users)"));
|
|
1574
1593
|
process.exit(1);
|
|
1575
1594
|
} else {
|
|
1576
|
-
await showResource(api, platformDir, type, name);
|
|
1595
|
+
await showResource(api, platformDir, type, name, appName);
|
|
1577
1596
|
}
|
|
1578
1597
|
}
|
|
1579
1598
|
export {
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listAllTemplates
|
|
3
|
+
} from "./chunk-CHRKCAIZ.js";
|
|
4
|
+
|
|
5
|
+
// src/commands/templates.ts
|
|
6
|
+
import pc from "picocolors";
|
|
7
|
+
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
8
|
+
import { join, resolve, extname } from "path";
|
|
9
|
+
function showHelp() {
|
|
10
|
+
console.log(`
|
|
11
|
+
${pc.dim("Usage:")}
|
|
12
|
+
lumera templates <command> [options]
|
|
13
|
+
|
|
14
|
+
${pc.dim("Commands:")}
|
|
15
|
+
list, ls List available templates (default)
|
|
16
|
+
validate [dir] Validate a template directory
|
|
17
|
+
|
|
18
|
+
${pc.dim("Options:")}
|
|
19
|
+
--verbose, -v Show full descriptions (list)
|
|
20
|
+
--help, -h Show this help
|
|
21
|
+
|
|
22
|
+
${pc.dim("Examples:")}
|
|
23
|
+
lumera templates # List available templates
|
|
24
|
+
lumera templates list -v # Show with descriptions
|
|
25
|
+
lumera templates validate ./my-template # Validate a template dir
|
|
26
|
+
lumera init my-app -t invoice-processing # Use a template
|
|
27
|
+
`);
|
|
28
|
+
}
|
|
29
|
+
async function list(args) {
|
|
30
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
31
|
+
showHelp();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const verbose = args.includes("--verbose") || args.includes("-v");
|
|
35
|
+
try {
|
|
36
|
+
const allTemplates = await listAllTemplates();
|
|
37
|
+
if (process.env.LUMERA_JSON) {
|
|
38
|
+
console.log(JSON.stringify(allTemplates, null, 2));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
console.log();
|
|
42
|
+
console.log(pc.cyan(pc.bold(" Available Templates")));
|
|
43
|
+
console.log();
|
|
44
|
+
if (allTemplates.length === 0) {
|
|
45
|
+
console.log(pc.dim(" No templates available."));
|
|
46
|
+
console.log();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const byCategory = /* @__PURE__ */ new Map();
|
|
50
|
+
for (const t of allTemplates) {
|
|
51
|
+
const cat = t.category || "General";
|
|
52
|
+
if (!byCategory.has(cat)) byCategory.set(cat, []);
|
|
53
|
+
byCategory.get(cat).push(t);
|
|
54
|
+
}
|
|
55
|
+
for (const [category, items] of byCategory) {
|
|
56
|
+
console.log(pc.bold(` ${category}`));
|
|
57
|
+
console.log();
|
|
58
|
+
for (const t of items) {
|
|
59
|
+
console.log(` ${pc.green(t.title)} ${pc.dim(`(${t.name})`)}`);
|
|
60
|
+
if (verbose) {
|
|
61
|
+
console.log(` ${pc.dim(t.description)}`);
|
|
62
|
+
console.log();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!verbose) console.log();
|
|
66
|
+
}
|
|
67
|
+
console.log(pc.dim(` ${allTemplates.length} template${allTemplates.length === 1 ? "" : "s"} available.`));
|
|
68
|
+
console.log();
|
|
69
|
+
console.log(pc.dim(" Usage:"), pc.cyan("lumera init <name> --template <template-name>"));
|
|
70
|
+
console.log();
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.error(pc.red(` Error: ${err}`));
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".venv", "dist", "__pycache__", ".tanstack"]);
|
|
77
|
+
var TEXT_EXTS = /* @__PURE__ */ new Set([".json", ".ts", ".tsx", ".js", ".jsx", ".py", ".md", ".html", ".css", ".yaml", ".yml", ".toml"]);
|
|
78
|
+
function scanForPlaceholders(dir, prefix = "") {
|
|
79
|
+
const results = [];
|
|
80
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
81
|
+
if (SKIP_DIRS.has(entry.name)) continue;
|
|
82
|
+
const fullPath = join(dir, entry.name);
|
|
83
|
+
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
84
|
+
if (entry.isDirectory()) {
|
|
85
|
+
results.push(...scanForPlaceholders(fullPath, relativePath));
|
|
86
|
+
} else {
|
|
87
|
+
const ext = extname(entry.name);
|
|
88
|
+
if (!TEXT_EXTS.has(ext)) continue;
|
|
89
|
+
if (entry.name === "template.json") continue;
|
|
90
|
+
try {
|
|
91
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
92
|
+
const lines = content.split("\n");
|
|
93
|
+
for (let i = 0; i < lines.length; i++) {
|
|
94
|
+
const matches = lines[i].match(/\{\{[^}]+\}\}/g);
|
|
95
|
+
if (matches) {
|
|
96
|
+
for (const match of matches) {
|
|
97
|
+
if (match.includes(":")) continue;
|
|
98
|
+
results.push({ file: relativePath, line: i + 1, text: match });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} catch {
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return results;
|
|
107
|
+
}
|
|
108
|
+
async function validate(args) {
|
|
109
|
+
const dir = args.find((a) => !a.startsWith("-")) || ".";
|
|
110
|
+
const targetDir = resolve(process.cwd(), dir);
|
|
111
|
+
console.log();
|
|
112
|
+
console.log(pc.cyan(pc.bold(" Validate Template")));
|
|
113
|
+
console.log(pc.dim(` Directory: ${targetDir}`));
|
|
114
|
+
console.log();
|
|
115
|
+
const issues = [];
|
|
116
|
+
const warnings = [];
|
|
117
|
+
const templateJsonPath = join(targetDir, "template.json");
|
|
118
|
+
if (!existsSync(templateJsonPath)) {
|
|
119
|
+
issues.push("Missing template.json");
|
|
120
|
+
} else {
|
|
121
|
+
try {
|
|
122
|
+
const meta = JSON.parse(readFileSync(templateJsonPath, "utf-8"));
|
|
123
|
+
const required = ["name", "title", "description", "category"];
|
|
124
|
+
for (const field of required) {
|
|
125
|
+
if (!meta[field]) {
|
|
126
|
+
issues.push(`template.json: missing required field "${field}"`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
} catch {
|
|
130
|
+
issues.push("template.json: invalid JSON");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (!existsSync(join(targetDir, "package.json"))) {
|
|
134
|
+
issues.push("Missing package.json");
|
|
135
|
+
}
|
|
136
|
+
if (!existsSync(join(targetDir, "platform"))) {
|
|
137
|
+
warnings.push("Missing platform/ directory");
|
|
138
|
+
} else if (!existsSync(join(targetDir, "platform", "collections"))) {
|
|
139
|
+
warnings.push("platform/ has no collections/ subdirectory");
|
|
140
|
+
}
|
|
141
|
+
const stalePatterns = scanForPlaceholders(targetDir);
|
|
142
|
+
for (const match of stalePatterns) {
|
|
143
|
+
warnings.push(`Stale placeholder: ${match.file}:${match.line} \u2014 ${match.text}`);
|
|
144
|
+
}
|
|
145
|
+
if (issues.length === 0 && warnings.length === 0) {
|
|
146
|
+
console.log(pc.green(" \u2713 Template is valid"));
|
|
147
|
+
console.log();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (issues.length > 0) {
|
|
151
|
+
console.log(pc.red(` ${issues.length} error${issues.length > 1 ? "s" : ""}:`));
|
|
152
|
+
for (const issue of issues) {
|
|
153
|
+
console.log(pc.red(` \u2717 ${issue}`));
|
|
154
|
+
}
|
|
155
|
+
console.log();
|
|
156
|
+
}
|
|
157
|
+
if (warnings.length > 0) {
|
|
158
|
+
console.log(pc.yellow(` ${warnings.length} warning${warnings.length > 1 ? "s" : ""}:`));
|
|
159
|
+
for (const warning of warnings) {
|
|
160
|
+
console.log(pc.yellow(` \u26A0 ${warning}`));
|
|
161
|
+
}
|
|
162
|
+
console.log();
|
|
163
|
+
}
|
|
164
|
+
if (issues.length > 0) {
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async function templates(subcommand, args) {
|
|
169
|
+
if (subcommand === "--help" || subcommand === "-h") {
|
|
170
|
+
showHelp();
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const cmd = subcommand || "list";
|
|
174
|
+
switch (cmd) {
|
|
175
|
+
case "list":
|
|
176
|
+
case "ls":
|
|
177
|
+
await list(args);
|
|
178
|
+
break;
|
|
179
|
+
case "validate":
|
|
180
|
+
await validate(args);
|
|
181
|
+
break;
|
|
182
|
+
default:
|
|
183
|
+
if (cmd.startsWith("-")) {
|
|
184
|
+
await list([cmd, ...args]);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
console.error(pc.red(`Unknown templates command: ${cmd}`));
|
|
188
|
+
console.error(`Run ${pc.cyan("lumera templates --help")} for usage.`);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
export {
|
|
193
|
+
templates
|
|
194
|
+
};
|
package/package.json
CHANGED
package/dist/chunk-2CR762KB.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// src/lib/env.ts
|
|
2
|
-
import { config } from "dotenv";
|
|
3
|
-
import { existsSync } from "fs";
|
|
4
|
-
import { resolve } from "path";
|
|
5
|
-
function loadEnv(cwd = process.cwd()) {
|
|
6
|
-
const envPath = resolve(cwd, ".env");
|
|
7
|
-
const envLocalPath = resolve(cwd, ".env.local");
|
|
8
|
-
if (existsSync(envPath)) {
|
|
9
|
-
config({ path: envPath });
|
|
10
|
-
}
|
|
11
|
-
if (existsSync(envLocalPath)) {
|
|
12
|
-
config({ path: envLocalPath, override: true });
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export {
|
|
17
|
-
loadEnv
|
|
18
|
-
};
|
package/dist/dev-BHBF4ECH.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
dev
|
|
3
|
-
} from "./chunk-CDZZ3JYU.js";
|
|
4
|
-
import {
|
|
5
|
-
loadEnv
|
|
6
|
-
} from "./chunk-2CR762KB.js";
|
|
7
|
-
import {
|
|
8
|
-
getToken
|
|
9
|
-
} from "./chunk-NDLYGKS6.js";
|
|
10
|
-
import {
|
|
11
|
-
findProjectRoot,
|
|
12
|
-
getApiUrl,
|
|
13
|
-
getAppName,
|
|
14
|
-
getAppTitle
|
|
15
|
-
} from "./chunk-D2BLSEGR.js";
|
|
16
|
-
|
|
17
|
-
// src/commands/dev.ts
|
|
18
|
-
import pc from "picocolors";
|
|
19
|
-
function parseFlags(args) {
|
|
20
|
-
const result = {};
|
|
21
|
-
for (let i = 0; i < args.length; i++) {
|
|
22
|
-
const arg = args[i];
|
|
23
|
-
if (arg.startsWith("--")) {
|
|
24
|
-
const key = arg.slice(2);
|
|
25
|
-
const next = args[i + 1];
|
|
26
|
-
if (next && !next.startsWith("--")) {
|
|
27
|
-
result[key] = next;
|
|
28
|
-
i++;
|
|
29
|
-
} else {
|
|
30
|
-
result[key] = true;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return result;
|
|
35
|
-
}
|
|
36
|
-
function showHelp() {
|
|
37
|
-
console.log(`
|
|
38
|
-
${pc.dim("Usage:")}
|
|
39
|
-
lumera dev [options]
|
|
40
|
-
|
|
41
|
-
${pc.dim("Description:")}
|
|
42
|
-
Start the development server with Lumera registration.
|
|
43
|
-
Registers your app with Lumera and starts a local dev server.
|
|
44
|
-
|
|
45
|
-
${pc.dim("Options:")}
|
|
46
|
-
--port <number> Dev server port (default: 8080)
|
|
47
|
-
--url <url> App URL for dev mode (default: http://localhost:{port})
|
|
48
|
-
--help, -h Show this help
|
|
49
|
-
|
|
50
|
-
${pc.dim("Environment variables:")}
|
|
51
|
-
LUMERA_TOKEN API token (overrides \`lumera login\`)
|
|
52
|
-
LUMERA_API_URL API base URL (default: https://app.lumerahq.com/api)
|
|
53
|
-
PORT Dev server port (default: 8080)
|
|
54
|
-
APP_URL App URL for dev mode
|
|
55
|
-
|
|
56
|
-
${pc.dim("Examples:")}
|
|
57
|
-
lumera dev # Start dev server on port 8080
|
|
58
|
-
lumera dev --port 3000 # Start dev server on port 3000
|
|
59
|
-
lumera dev --url http://192.168.1.100:8080 # Custom URL for mobile testing
|
|
60
|
-
`);
|
|
61
|
-
}
|
|
62
|
-
async function dev2(args) {
|
|
63
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
64
|
-
showHelp();
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
const flags = parseFlags(args);
|
|
68
|
-
const projectRoot = findProjectRoot();
|
|
69
|
-
loadEnv(projectRoot);
|
|
70
|
-
const token = getToken(projectRoot);
|
|
71
|
-
const appName = getAppName(projectRoot);
|
|
72
|
-
const appTitle = getAppTitle(projectRoot);
|
|
73
|
-
const apiUrl = getApiUrl();
|
|
74
|
-
const port = Number(flags.port || process.env.PORT || "8080");
|
|
75
|
-
const appUrl = typeof flags.url === "string" ? flags.url : process.env.APP_URL;
|
|
76
|
-
await dev({
|
|
77
|
-
token,
|
|
78
|
-
appName,
|
|
79
|
-
appTitle,
|
|
80
|
-
port,
|
|
81
|
-
appUrl,
|
|
82
|
-
apiUrl
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
export {
|
|
86
|
-
dev2 as dev
|
|
87
|
-
};
|