create-fullstack-scaffold 0.4.3 → 0.4.4
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/cli/index.js +513 -122
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
- package/template/dist/cli/index.js +237 -94
- package/template/dist/cli/index.js.map +1 -1
- package/template/dist/client/admin.html +15 -10
- package/template/dist/client/assets/App-BpFUIC-5.js +114 -0
- package/template/dist/client/assets/{CartPage-DESSHkaG.js → CartPage-DgDZP-R5.js} +2 -2
- package/template/dist/client/assets/{CategoriesPage-DqLZ_Mom.js → CategoriesPage-fuYNiSmE.js} +2 -2
- package/template/dist/client/assets/ContentDetailPage-BvvFU1Mr.js +1 -0
- package/template/dist/client/assets/ContentListPage-ShPxo6WG.js +1 -0
- package/template/dist/client/assets/DashboardPage-C1rZzZo4.js +11 -0
- package/template/dist/client/assets/{DeveloperDashboardPage-Cum7zFwO.js → DeveloperDashboardPage-_WtmbVoA.js} +2 -2
- package/template/dist/client/assets/{EmptyState-BK7ttK8D.js → EmptyState-DEyOQjbY.js} +1 -1
- package/template/dist/client/assets/LoadingSpinner-BcHjaM1m.js +6 -0
- package/template/dist/client/assets/LoginPage-CjeQqDdO.js +1 -0
- package/template/dist/client/assets/LogoutOutlined-ColFAHdd.js +1 -0
- package/template/dist/client/assets/NotificationPage-DRkEv02s.js +1 -0
- package/template/dist/client/assets/OrdersPage-7I3vPWLP.js +11 -0
- package/template/dist/client/assets/{PluginDetailPage-Br24YS4P.js → PluginDetailPage-CWyxdVCg.js} +3 -13
- package/template/dist/client/assets/PluginsPage-DRgWLeJT.js +6 -0
- package/template/dist/client/assets/ProfilePage-2FFkaii8.js +16 -0
- package/template/dist/client/assets/PublishPage-DW7yvROx.js +1 -0
- package/template/dist/client/assets/{RegisterPage-rPFG4Sry.js → RegisterPage-Dvaf9b0e.js} +2 -2
- package/template/dist/client/assets/SaveOutlined-CLQ2tsSY.js +2 -0
- package/template/dist/client/assets/{SearchPage-DQl1U5Uy.js → SearchPage-DvnEyswS.js} +2 -2
- package/template/dist/client/assets/{SettingsPage-DaYE80wj.js → SettingsPage-IrU-L9Zr.js} +2 -2
- package/template/dist/client/assets/{StatusBadge-BJ3W2Zc7.js → StatusBadge-CG7wVqpu.js} +1 -1
- package/template/dist/client/assets/{TodoPage-zC5wWNBa.js → TodoPage-B7D-bl65.js} +3 -3
- package/template/dist/client/assets/TopicsPage-CYCNr-mn.js +6 -0
- package/template/dist/client/assets/{WebSocketPage-B4NLdz1w.js → WebSocketPage-CGEg6QJE.js} +2 -2
- package/template/dist/client/assets/{activity-B94BUAsD.js → activity-CgTz9Mrd.js} +1 -1
- package/template/dist/client/assets/admin-D2iHWNOg.js +1 -0
- package/template/dist/client/assets/api-request-DIJocPxr.js +356 -0
- package/template/dist/client/assets/{arrow-left-H5JH0iU1.js → arrow-left-DtLQ3tTk.js} +1 -1
- package/template/dist/client/assets/{chevron-down-DwRh_wjD.js → chevron-down-CpIAV_yr.js} +1 -1
- package/template/dist/client/assets/{chevron-right-CpIWaqAL.js → chevron-right-CnU7oPQs.js} +1 -1
- package/template/dist/client/assets/{circle-check-big-CSElLscG.js → circle-check-big-CrZdwS75.js} +1 -1
- package/template/dist/client/assets/{circle-x-CYxr4RAw.js → circle-x-CvN9r3fW.js} +1 -1
- package/template/dist/client/assets/{clock-BseUJ7ex.js → clock-CTeSZBiH.js} +1 -1
- package/template/dist/client/assets/{download-BsGC_Xhq.js → download-OSVfVuNV.js} +1 -1
- package/template/dist/client/assets/{external-link-UTDzdjq8.js → external-link-fBsuHMby.js} +1 -1
- package/template/dist/client/assets/{eye-nR10ui7i.js → eye-CwlZZEsj.js} +1 -1
- package/template/dist/client/assets/index-09IqiOaE.css +1 -0
- package/template/dist/client/assets/index-B3CRby6r.js +51 -0
- package/template/dist/client/assets/index-CC_zy73y.js +17 -0
- package/template/dist/client/assets/main-Cn4IDo2I.js +92 -0
- package/template/dist/client/assets/merchant-DDDN9bMu.js +40 -0
- package/template/dist/client/assets/{message-square-CwWGL-Bh.js → message-square-BRaZfgbJ.js} +1 -1
- package/template/dist/client/assets/pluginStore-DDsWJPe6.js +1 -0
- package/template/dist/client/assets/{plus-pZld_nUL.js → plus-DDZfPiDJ.js} +1 -1
- package/template/dist/client/assets/sse-client-DGQ072hl.js +64 -0
- package/template/dist/client/assets/star-C7tO6w4H.js +11 -0
- package/template/dist/client/assets/{tag-DsiUPF90.js → tag-DBfpQDuJ.js} +1 -1
- package/template/dist/client/assets/tenant-CizbLaLJ.js +1 -0
- package/template/dist/client/assets/{trash-2-DRblNbnA.js → trash-2-BP7fkd5b.js} +1 -1
- package/template/dist/client/assets/{triangle-alert-D1CLh-Vd.js → triangle-alert-CrOQEdJ2.js} +1 -1
- package/template/dist/client/assets/{wifi-BwXjnCqI.js → wifi-CwYSE0J4.js} +1 -1
- package/template/dist/client/assets/{x-BH2rJdFq.js → x-t615pnNR.js} +1 -1
- package/template/dist/client/content/index.html +5 -4
- package/template/dist/client/index.html +4 -3
- package/template/dist/client/merchant.html +18 -0
- package/template/dist/client/notifications/index.html +6 -5
- package/template/dist/client/tenant.html +18 -0
- package/template/dist/client/todos/index.html +6 -5
- package/template/dist/client/websocket/index.html +6 -5
- package/template/dist/cloudflare/chunk-HX7DVRDX.js +1 -0
- package/template/dist/cloudflare/{chunk-QBHAPWIA.js → chunk-IXJL2LE4.js} +1 -1
- package/template/dist/cloudflare/chunk-Q34AN3RF.js +14 -0
- package/template/dist/cloudflare/{chunk-BHPTQ4K2.js → chunk-ZAMVL4EG.js} +2 -2
- package/template/dist/cloudflare/cloudflare.js +35 -29
- package/template/dist/cloudflare/db-4AQOSFAX.js +1 -0
- package/template/dist/cloudflare/{migrator-2ZYYKNI5.js → migrator-TEPBVUFO.js} +1 -1
- package/template/dist/cloudflare/permission-service-impl-RE7NPW3Q.js +1 -0
- package/template/dist/cloudflare/schema-DVEMT3X2.js +1 -0
- package/template/dist/cloudflare/test-setup-Z2RYE5B4.js +265 -0
- package/template/dist/server/chunk-27SIJSPF.js +1 -0
- package/template/dist/server/chunk-37QNGBQU.js +1 -0
- package/template/dist/server/chunk-FIY4CGJJ.js +1 -0
- package/template/dist/server/chunk-HZUDBIT4.js +1 -0
- package/template/dist/server/chunk-I6OBDFDU.js +1 -0
- package/template/dist/server/chunk-JHNYLNG7.js +1 -0
- package/template/dist/server/chunk-MDOVVKKD.js +1 -0
- package/template/dist/server/chunk-NSOCT7E5.js +1 -0
- package/template/dist/server/chunk-OU5IGVVO.js +1 -0
- package/template/dist/server/chunk-OYCBNRMK.js +1 -0
- package/template/dist/server/chunk-P2RJNNGD.js +1 -0
- package/template/dist/server/chunk-UMAQLNPE.js +1 -0
- package/template/dist/server/chunk-XZZTSRSN.js +1 -0
- package/template/dist/server/content-service-5QVHDR5X.js +1 -0
- package/template/dist/server/db-FLI5L5DD.js +1 -0
- package/template/dist/server/dispute-service-E2FCYUEM.js +1 -0
- package/template/dist/server/init-72JXJV3I.js +46 -0
- package/template/dist/server/init-FWYXSKPX.js +46 -0
- package/template/dist/server/node.js +34 -28
- package/template/dist/server/order-service-TKGG5S5K.js +1 -0
- package/template/dist/server/permission-service-impl-M3AKEYNY.js +1 -0
- package/template/dist/server/schema-V4UG7HMU.js +1 -0
- package/template/dist/server/tenant-service-JG6UUWXQ.js +1 -0
- package/template/dist/server/tenant-service-XJWZSEDX.js +1 -0
- package/template/dist/{cloudflare/test-setup-NMZJZLRV.js → server/test-setup-VFOPBGYM.js} +83 -2
- package/template/dist/server/ticket-service-3RSW7V2Z.js +1 -0
- package/template/dist/server/todo-service-S6BGIO7D.js +1 -0
- package/template/src/merchant/pages/DisputesPage.tsx +11 -11
- package/template/src/merchant/pages/OrdersPage.tsx +4 -3
- package/template/src/merchant/pages/ProductsPage.tsx +2 -2
- package/template/src/merchant/stores/merchantStore.ts +11 -6
- package/template/src/server/db/init.ts +5 -642
- package/template/src/server/module-plugin/services/plugin-seed-service.ts +623 -0
- package/template/src/server/module-tenant/routes/tenant-routes.ts +2 -2
- package/template/src/server/module-tenant/services/tenant-service.ts +63 -17
- package/template/src/shared/modules/merchant/index.ts +9 -0
- package/template/src/shared/modules/merchant/schemas.ts +37 -0
- package/template/src/shared/modules/tenant/index.ts +2 -0
- package/template/src/shared/schemas/index.ts +27 -0
- package/template/src/tenant/layouts/Header.tsx +1 -1
- package/template/src/tenant/layouts/Sidebar.tsx +1 -1
- package/template/src/tenant/pages/SettingsPage.tsx +4 -8
- package/template/src/tenant/stores/tenantStore.ts +41 -302
- package/template/tsconfig.json +1 -0
- package/template/tsup.config.ts +11 -3
- package/template/dist/client/assets/ContentDetailPage-DdltMANL.js +0 -1
- package/template/dist/client/assets/ContentListPage-B63sUB6N.js +0 -1
- package/template/dist/client/assets/DashboardPage-tUMilc7Z.js +0 -11
- package/template/dist/client/assets/LoadingSpinner-DVYOLSRM.js +0 -6
- package/template/dist/client/assets/LoginPage-g9mSLIMC.js +0 -6
- package/template/dist/client/assets/NotificationPage-COTzp-HD.js +0 -1
- package/template/dist/client/assets/OrdersPage-BsPh4oEI.js +0 -11
- package/template/dist/client/assets/PluginsPage-BNtAe_yo.js +0 -6
- package/template/dist/client/assets/ProfilePage-dL_iSuZN.js +0 -16
- package/template/dist/client/assets/PublishPage-D96FnbLA.js +0 -1
- package/template/dist/client/assets/TopicsPage-DyLjZa4D.js +0 -6
- package/template/dist/client/assets/admin-Bh1vfz_L.js +0 -486
- package/template/dist/client/assets/index-1bA-ixFv.js +0 -114
- package/template/dist/client/assets/index-CWh3vXC_.css +0 -1
- package/template/dist/client/assets/main-DHnArIp_.js +0 -82
- package/template/dist/client/assets/pluginStore-XQfsm3iR.js +0 -1
- package/template/dist/client/content/content-1/index.html +0 -18
- package/template/dist/client/content/content-13/index.html +0 -18
- package/template/dist/client/content/content-14/index.html +0 -18
- package/template/dist/client/content/content-15/index.html +0 -18
- package/template/dist/client/content/content-19/index.html +0 -18
- package/template/dist/client/content/content-2/index.html +0 -18
- package/template/dist/client/content/content-20/index.html +0 -18
- package/template/dist/cloudflare/chunk-YY6FRMAQ.js +0 -14
- package/template/dist/cloudflare/db-7J42RQ3T.js +0 -1
- package/template/dist/cloudflare/permission-service-impl-TGXVSSSA.js +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,13 +1,433 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import { program } from 'commander';
|
|
3
|
+
import { hc } from 'hono/client';
|
|
4
|
+
import { z } from '@hono/zod-openapi';
|
|
5
|
+
import fs, { readdirSync, statSync, existsSync, readFileSync } from 'fs';
|
|
6
|
+
import path2, { join } from 'path';
|
|
7
|
+
import os from 'os';
|
|
4
8
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
5
|
-
import
|
|
9
|
+
import fs2 from 'fs-extra';
|
|
6
10
|
import chalk from 'chalk';
|
|
7
|
-
import { select } from '@inquirer/prompts';
|
|
8
|
-
import fs from 'fs-extra';
|
|
9
11
|
import ora from 'ora';
|
|
10
12
|
|
|
13
|
+
function createRPCClient(baseUrl) {
|
|
14
|
+
return hc(baseUrl);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/cli/utils/api.ts
|
|
18
|
+
var DEFAULT_BASE_URL = "http://localhost:3010";
|
|
19
|
+
var globalBaseUrl = process.env.BIOMIMIC_API_URL || DEFAULT_BASE_URL;
|
|
20
|
+
function setBaseUrl(url) {
|
|
21
|
+
globalBaseUrl = url;
|
|
22
|
+
}
|
|
23
|
+
function getBaseUrl() {
|
|
24
|
+
return globalBaseUrl;
|
|
25
|
+
}
|
|
26
|
+
function getClient() {
|
|
27
|
+
return createRPCClient(globalBaseUrl);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/cli/utils/logger.ts
|
|
31
|
+
var Logger = class {
|
|
32
|
+
level = "info";
|
|
33
|
+
constructor(options = {}) {
|
|
34
|
+
if (options.debug || process.env.BIOMIMIC_DEBUG === "true") {
|
|
35
|
+
this.level = "debug";
|
|
36
|
+
} else if (options.verbose || process.env.BIOMIMIC_VERBOSE === "true") {
|
|
37
|
+
this.level = "info";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
setLevel(level) {
|
|
41
|
+
this.level = level;
|
|
42
|
+
}
|
|
43
|
+
shouldLog(level) {
|
|
44
|
+
const levels = ["silent", "error", "warn", "info", "debug"];
|
|
45
|
+
return levels.indexOf(level) <= levels.indexOf(this.level);
|
|
46
|
+
}
|
|
47
|
+
info(message, ...args) {
|
|
48
|
+
if (this.shouldLog("info")) {
|
|
49
|
+
process.stdout.write(`${message}${args.length ? " " + args.join(" ") : ""}
|
|
50
|
+
`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
debug(message, ...args) {
|
|
54
|
+
if (this.shouldLog("debug")) {
|
|
55
|
+
process.stdout.write(`[debug] ${message}${args.length ? " " + args.join(" ") : ""}
|
|
56
|
+
`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
warn(message) {
|
|
60
|
+
if (this.shouldLog("warn")) {
|
|
61
|
+
process.stderr.write(`[warn] ${message}
|
|
62
|
+
`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
error(message) {
|
|
66
|
+
if (this.shouldLog("error")) {
|
|
67
|
+
process.stderr.write(`[error] ${message}
|
|
68
|
+
`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
success(message, ...args) {
|
|
72
|
+
if (this.shouldLog("info")) {
|
|
73
|
+
process.stdout.write(`\u2713 ${message}${args.length ? " " + args.join(" ") : ""}
|
|
74
|
+
`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
fail(message) {
|
|
78
|
+
if (this.shouldLog("error")) {
|
|
79
|
+
process.stderr.write(`\u2717 ${message}
|
|
80
|
+
`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var logger = null;
|
|
85
|
+
function createLogger(options = {}) {
|
|
86
|
+
logger = new Logger(options);
|
|
87
|
+
return logger;
|
|
88
|
+
}
|
|
89
|
+
function getLogger() {
|
|
90
|
+
if (!logger) {
|
|
91
|
+
logger = new Logger();
|
|
92
|
+
}
|
|
93
|
+
return logger;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/cli/utils/auto-command.ts
|
|
97
|
+
function extractZodInfo(schema) {
|
|
98
|
+
const def = schema._def;
|
|
99
|
+
if (def.typeName === "ZodOptional") {
|
|
100
|
+
const inner = schema._def.innerType;
|
|
101
|
+
const info = extractZodInfo(inner);
|
|
102
|
+
return { ...info, required: false };
|
|
103
|
+
}
|
|
104
|
+
if (def.typeName === "ZodDefault") {
|
|
105
|
+
const innerDef = schema._def;
|
|
106
|
+
const defaultValue = innerDef.defaultValue();
|
|
107
|
+
const info = extractZodInfo(innerDef.innerType);
|
|
108
|
+
return { ...info, required: false, defaultValue };
|
|
109
|
+
}
|
|
110
|
+
if (def.typeName === "ZodEnum") {
|
|
111
|
+
const enumValues = [...schema._def.values];
|
|
112
|
+
return { type: "enum", required: true, enumValues };
|
|
113
|
+
}
|
|
114
|
+
if (def.typeName === "ZodString") return { type: "string", required: true };
|
|
115
|
+
if (def.typeName === "ZodNumber") return { type: "number", required: true };
|
|
116
|
+
if (def.typeName === "ZodBoolean") return { type: "boolean", required: true };
|
|
117
|
+
if (def.typeName === "ZodObject") return { type: "object", required: true };
|
|
118
|
+
return { type: "string", required: true };
|
|
119
|
+
}
|
|
120
|
+
function schemaToOptions(schema) {
|
|
121
|
+
const options = [];
|
|
122
|
+
const shape = schema.shape;
|
|
123
|
+
for (const [key, zodType] of Object.entries(shape)) {
|
|
124
|
+
const info = extractZodInfo(zodType);
|
|
125
|
+
const longFlag = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
126
|
+
let flags = `--${longFlag} <value>`;
|
|
127
|
+
if (info.type === "boolean") {
|
|
128
|
+
flags = `--${longFlag}`;
|
|
129
|
+
}
|
|
130
|
+
let description = String(info.type);
|
|
131
|
+
if (info.enumValues) {
|
|
132
|
+
description = `${info.type} (${info.enumValues.join("|")})`;
|
|
133
|
+
}
|
|
134
|
+
options.push({
|
|
135
|
+
flags,
|
|
136
|
+
description,
|
|
137
|
+
required: info.required,
|
|
138
|
+
defaultValue: info.defaultValue
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return options;
|
|
142
|
+
}
|
|
143
|
+
function pathToApiCall(client, _method, path3) {
|
|
144
|
+
const pathParts = path3.split("/").filter(Boolean);
|
|
145
|
+
let current = client.api;
|
|
146
|
+
for (const part of pathParts) {
|
|
147
|
+
if (part.startsWith("{") && part.endsWith("}")) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
current = current[part] || current[`:${part}`];
|
|
151
|
+
}
|
|
152
|
+
return current;
|
|
153
|
+
}
|
|
154
|
+
function createCommandFromRoute(config) {
|
|
155
|
+
const options = [];
|
|
156
|
+
const arguments_ = [];
|
|
157
|
+
if (config.params) {
|
|
158
|
+
const shape = config.params.shape;
|
|
159
|
+
for (const [key] of Object.entries(shape)) {
|
|
160
|
+
arguments_.push({
|
|
161
|
+
name: key,
|
|
162
|
+
description: `${key} parameter`,
|
|
163
|
+
required: true
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (config.body) {
|
|
168
|
+
const bodySchema = config.body;
|
|
169
|
+
if (bodySchema.shape) {
|
|
170
|
+
options.push(...schemaToOptions(bodySchema) || []);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (config.query) {
|
|
174
|
+
options.push(...schemaToOptions(config.query) || []);
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
name: config.command,
|
|
178
|
+
description: config.description,
|
|
179
|
+
options,
|
|
180
|
+
arguments: arguments_,
|
|
181
|
+
action: async (opts, args) => {
|
|
182
|
+
const logger2 = getLogger();
|
|
183
|
+
const client = getClient();
|
|
184
|
+
const param = {};
|
|
185
|
+
if (config.params) {
|
|
186
|
+
const shape = config.params.shape;
|
|
187
|
+
const keys = Object.keys(shape);
|
|
188
|
+
keys.forEach((key, i) => {
|
|
189
|
+
param[key] = args[i] || String(opts[key]);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
const json = {};
|
|
193
|
+
if (config.body && opts) {
|
|
194
|
+
const bodySchema = config.body;
|
|
195
|
+
if (bodySchema.shape) {
|
|
196
|
+
const shape = bodySchema.shape;
|
|
197
|
+
for (const key of Object.keys(shape)) {
|
|
198
|
+
if (opts[key] !== void 0) {
|
|
199
|
+
json[key] = opts[key];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const query = {};
|
|
205
|
+
if (config.query && opts) {
|
|
206
|
+
const shape = config.query.shape;
|
|
207
|
+
for (const key of Object.keys(shape)) {
|
|
208
|
+
if (opts[key] !== void 0) {
|
|
209
|
+
query[key] = String(opts[key]);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const apiCall = pathToApiCall(client, config.method, config.path);
|
|
214
|
+
const methodCall = apiCall[`$${config.method.charAt(0).toUpperCase() + config.method.slice(1)}`] || apiCall.$get;
|
|
215
|
+
const res = await methodCall.call(apiCall, {
|
|
216
|
+
param: Object.keys(param).length > 0 ? param : void 0,
|
|
217
|
+
query: Object.keys(query).length > 0 ? query : void 0,
|
|
218
|
+
json: Object.keys(json).length > 0 ? json : void 0
|
|
219
|
+
});
|
|
220
|
+
const data = await res.json();
|
|
221
|
+
logger2.info(JSON.stringify(data, null, 2));
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function registerAutoCommand(program2, config) {
|
|
226
|
+
const cmd = createCommandFromRoute(config);
|
|
227
|
+
const command = program2.command(cmd.name).description(cmd.description).action(async (firstArg, opts) => {
|
|
228
|
+
const args = typeof firstArg === "string" ? [firstArg] : [];
|
|
229
|
+
const options = (typeof firstArg === "object" ? firstArg : opts) || {};
|
|
230
|
+
await cmd.action(options, args);
|
|
231
|
+
});
|
|
232
|
+
cmd.options?.forEach((opt) => {
|
|
233
|
+
if (opt.required) {
|
|
234
|
+
command.requiredOption(opt.flags, opt.description, opt.defaultValue);
|
|
235
|
+
} else {
|
|
236
|
+
command.option(opt.flags, opt.description, opt.defaultValue);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
cmd.arguments?.forEach((arg) => {
|
|
240
|
+
command.argument(arg.required ? `<${arg.name}>` : `[${arg.name}]`, arg.description);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
var TodoStatusSchema = z.enum(["pending", "in_progress", "completed"]);
|
|
244
|
+
var todoRoutes = [
|
|
245
|
+
{
|
|
246
|
+
method: "get",
|
|
247
|
+
path: "/todos",
|
|
248
|
+
command: "list",
|
|
249
|
+
description: "List all todos"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
method: "get",
|
|
253
|
+
path: "/todos/{id}",
|
|
254
|
+
command: "get",
|
|
255
|
+
description: "Get a todo by ID",
|
|
256
|
+
params: z.object({ id: z.string() })
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
method: "post",
|
|
260
|
+
path: "/todos",
|
|
261
|
+
command: "create",
|
|
262
|
+
description: "Create a new todo",
|
|
263
|
+
body: z.object({
|
|
264
|
+
title: z.string().min(1),
|
|
265
|
+
description: z.string().optional()
|
|
266
|
+
})
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
method: "put",
|
|
270
|
+
path: "/todos/{id}",
|
|
271
|
+
command: "update",
|
|
272
|
+
description: "Update a todo",
|
|
273
|
+
params: z.object({ id: z.string() }),
|
|
274
|
+
body: z.object({
|
|
275
|
+
title: z.string().optional(),
|
|
276
|
+
description: z.string().optional(),
|
|
277
|
+
status: TodoStatusSchema.optional()
|
|
278
|
+
})
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
method: "delete",
|
|
282
|
+
path: "/todos/{id}",
|
|
283
|
+
command: "delete",
|
|
284
|
+
description: "Delete a todo",
|
|
285
|
+
params: z.object({ id: z.string() })
|
|
286
|
+
}
|
|
287
|
+
];
|
|
288
|
+
function registerTodoCommands(program2) {
|
|
289
|
+
const todo = program2.command("todo").description("Todo management commands");
|
|
290
|
+
for (const route of todoRoutes) {
|
|
291
|
+
registerAutoCommand(todo, route);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/cli/modules/notification/index.ts
|
|
296
|
+
function registerNotificationCommands(program2) {
|
|
297
|
+
const notification = program2.command("notification").description("Notification management commands");
|
|
298
|
+
notification.command("list").description("List all notifications").option("--unread-only", "Show only unread notifications").option("--limit <number>", "Limit number of results", "20").action(async (options) => {
|
|
299
|
+
const logger2 = getLogger();
|
|
300
|
+
const client = getClient();
|
|
301
|
+
const unreadOnly = Boolean(options.unreadOnly);
|
|
302
|
+
const limit = parseInt(options.limit || "20");
|
|
303
|
+
const res = await client.api.notifications.$get({
|
|
304
|
+
query: { unreadOnly: String(unreadOnly), limit: String(limit) }
|
|
305
|
+
});
|
|
306
|
+
const data = await res.json();
|
|
307
|
+
logger2.info(JSON.stringify(data, null, 2));
|
|
308
|
+
});
|
|
309
|
+
notification.command("create").description("Create a new notification").requiredOption("-t, --title <title>", "Notification title").requiredOption("-m, --message <message>", "Notification message").option("--type <type>", "Notification type (info|warning|success|error)", "info").action(async (options) => {
|
|
310
|
+
const logger2 = getLogger();
|
|
311
|
+
const client = getClient();
|
|
312
|
+
const res = await client.api.notifications.$post({
|
|
313
|
+
json: {
|
|
314
|
+
type: options.type,
|
|
315
|
+
title: options.title,
|
|
316
|
+
message: options.message
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
const data = await res.json();
|
|
320
|
+
logger2.success("Notification created");
|
|
321
|
+
logger2.info(JSON.stringify(data, null, 2));
|
|
322
|
+
});
|
|
323
|
+
notification.command("unread-count").description("Get unread notification count").action(async () => {
|
|
324
|
+
const logger2 = getLogger();
|
|
325
|
+
const client = getClient();
|
|
326
|
+
const res = await client.api.notifications["unread-count"].$get();
|
|
327
|
+
const data = await res.json();
|
|
328
|
+
logger2.info(JSON.stringify(data, null, 2));
|
|
329
|
+
});
|
|
330
|
+
notification.command("mark-read").description("Mark a notification as read").argument("<id>", "Notification ID").action(async (id) => {
|
|
331
|
+
const logger2 = getLogger();
|
|
332
|
+
const client = getClient();
|
|
333
|
+
const res = await client.api.notifications[":id"].read.$patch({ param: { id } });
|
|
334
|
+
const data = await res.json();
|
|
335
|
+
logger2.success("Notification marked as read");
|
|
336
|
+
logger2.info(JSON.stringify(data, null, 2));
|
|
337
|
+
});
|
|
338
|
+
notification.command("delete").description("Delete a notification").argument("<id>", "Notification ID").action(async (id) => {
|
|
339
|
+
const logger2 = getLogger();
|
|
340
|
+
const client = getClient();
|
|
341
|
+
const res = await client.api.notifications[":id"].$delete({ param: { id } });
|
|
342
|
+
const data = await res.json();
|
|
343
|
+
logger2.success("Notification deleted");
|
|
344
|
+
logger2.info(JSON.stringify(data, null, 2));
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
var CONFIG_DIR = path2.join(os.homedir(), ".biomimic");
|
|
348
|
+
var CONFIG_FILE = path2.join(CONFIG_DIR, "config.json");
|
|
349
|
+
function loadConfig() {
|
|
350
|
+
try {
|
|
351
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
352
|
+
const content = fs.readFileSync(CONFIG_FILE, "utf-8");
|
|
353
|
+
return JSON.parse(content);
|
|
354
|
+
}
|
|
355
|
+
} catch {
|
|
356
|
+
}
|
|
357
|
+
return { baseUrl: "http://localhost:3010" };
|
|
358
|
+
}
|
|
359
|
+
function saveConfig(config) {
|
|
360
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
361
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
362
|
+
}
|
|
363
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
364
|
+
}
|
|
365
|
+
function registerConfigCommands(program2) {
|
|
366
|
+
const config = program2.command("config").description("CLI configuration and service management");
|
|
367
|
+
config.command("get").description("Show current configuration").option("-k, --key <key>", "Get specific config key").action((options) => {
|
|
368
|
+
const logger2 = getLogger();
|
|
369
|
+
const cfg = loadConfig();
|
|
370
|
+
if (options.key) {
|
|
371
|
+
const value = cfg[options.key];
|
|
372
|
+
logger2.info(`${options.key}: ${value ?? "not set"}`);
|
|
373
|
+
} else {
|
|
374
|
+
logger2.info(JSON.stringify(cfg, null, 2));
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
config.command("set").description("Set configuration value").option("-u, --url <url>", "Set server URL").action((options) => {
|
|
378
|
+
const logger2 = getLogger();
|
|
379
|
+
const cfg = loadConfig();
|
|
380
|
+
if (options.url) {
|
|
381
|
+
cfg.baseUrl = options.url;
|
|
382
|
+
setBaseUrl(options.url);
|
|
383
|
+
logger2.success(`Server URL set to: ${options.url}`);
|
|
384
|
+
}
|
|
385
|
+
saveConfig(cfg);
|
|
386
|
+
});
|
|
387
|
+
config.command("url").description("Show or set server URL").argument("[url]", "New server URL").action((url) => {
|
|
388
|
+
const logger2 = getLogger();
|
|
389
|
+
if (url) {
|
|
390
|
+
const cfg = loadConfig();
|
|
391
|
+
cfg.baseUrl = url;
|
|
392
|
+
setBaseUrl(url);
|
|
393
|
+
saveConfig(cfg);
|
|
394
|
+
logger2.success(`Server URL set to: ${url}`);
|
|
395
|
+
} else {
|
|
396
|
+
logger2.info(`Current server URL: ${getBaseUrl()}`);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
config.command("status").description("Check server connection status").action(async () => {
|
|
400
|
+
const logger2 = getLogger();
|
|
401
|
+
const client = getClient();
|
|
402
|
+
try {
|
|
403
|
+
const res = await client.health.$get();
|
|
404
|
+
const data = await res.json();
|
|
405
|
+
logger2.success("Server is reachable");
|
|
406
|
+
logger2.info(JSON.stringify(data, null, 2));
|
|
407
|
+
} catch (error) {
|
|
408
|
+
logger2.error(`Server not reachable: ${getBaseUrl()}`);
|
|
409
|
+
logger2.error(String(error));
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
config.command("reset").description("Reset configuration to defaults").action(() => {
|
|
413
|
+
const logger2 = getLogger();
|
|
414
|
+
const defaultConfig = { baseUrl: "http://localhost:3010" };
|
|
415
|
+
saveConfig(defaultConfig);
|
|
416
|
+
setBaseUrl(defaultConfig.baseUrl);
|
|
417
|
+
logger2.success("Configuration reset to defaults");
|
|
418
|
+
});
|
|
419
|
+
config.command("path").description("Show config file path").action(() => {
|
|
420
|
+
const logger2 = getLogger();
|
|
421
|
+
logger2.info(`Config file: ${CONFIG_FILE}`);
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// src/cli/modules/index.ts
|
|
426
|
+
function registerModules(program2) {
|
|
427
|
+
registerTodoCommands(program2);
|
|
428
|
+
registerNotificationCommands(program2);
|
|
429
|
+
registerConfigCommands(program2);
|
|
430
|
+
}
|
|
11
431
|
var tsImportFn;
|
|
12
432
|
async function getTsImport() {
|
|
13
433
|
if (tsImportFn) return tsImportFn;
|
|
@@ -3006,7 +3426,7 @@ if (typeof window !== 'undefined') {
|
|
|
3006
3426
|
|
|
3007
3427
|
// src/commands/create.ts
|
|
3008
3428
|
var __filename$1 = fileURLToPath(import.meta.url);
|
|
3009
|
-
var __dirname$1 =
|
|
3429
|
+
var __dirname$1 = path2.dirname(__filename$1);
|
|
3010
3430
|
var TEMPLATE_PROJECT_NAME = "biomimic-todo-app";
|
|
3011
3431
|
var TEMPLATE_DB_NAME = "biomimic-todo-db";
|
|
3012
3432
|
var ScaffoldError = class extends Error {
|
|
@@ -3048,11 +3468,11 @@ function generateDbName(projectName) {
|
|
|
3048
3468
|
return `${sanitized}-db`;
|
|
3049
3469
|
}
|
|
3050
3470
|
async function updateWranglerToml(targetDir, projectName) {
|
|
3051
|
-
const wranglerPath =
|
|
3052
|
-
if (!await
|
|
3471
|
+
const wranglerPath = path2.join(targetDir, "wrangler.toml");
|
|
3472
|
+
if (!await fs2.pathExists(wranglerPath)) {
|
|
3053
3473
|
return;
|
|
3054
3474
|
}
|
|
3055
|
-
let content = await
|
|
3475
|
+
let content = await fs2.readFile(wranglerPath, "utf-8");
|
|
3056
3476
|
const dbName = generateDbName(projectName);
|
|
3057
3477
|
content = content.replace(
|
|
3058
3478
|
new RegExp(`^name = "${TEMPLATE_PROJECT_NAME}"`, "m"),
|
|
@@ -3066,43 +3486,43 @@ async function updateWranglerToml(targetDir, projectName) {
|
|
|
3066
3486
|
/database_id = "[^"]+"/,
|
|
3067
3487
|
`database_id = "" # TODO: Run 'wrangler d1 create ${dbName}' and paste the ID here`
|
|
3068
3488
|
);
|
|
3069
|
-
await
|
|
3489
|
+
await fs2.writeFile(wranglerPath, content);
|
|
3070
3490
|
}
|
|
3071
3491
|
async function updatePackageJson(targetDir, projectName, resolved) {
|
|
3072
|
-
const pkgJsonPath =
|
|
3073
|
-
if (!await
|
|
3492
|
+
const pkgJsonPath = path2.join(targetDir, "package.json");
|
|
3493
|
+
if (!await fs2.pathExists(pkgJsonPath)) {
|
|
3074
3494
|
return;
|
|
3075
3495
|
}
|
|
3076
|
-
let pkgJson = await
|
|
3496
|
+
let pkgJson = await fs2.readJson(pkgJsonPath);
|
|
3077
3497
|
pkgJson = filterPackageJson(pkgJson, resolved);
|
|
3078
3498
|
pkgJson.name = projectName;
|
|
3079
3499
|
if (pkgJson.bin) {
|
|
3080
3500
|
delete pkgJson.bin;
|
|
3081
3501
|
}
|
|
3082
|
-
await
|
|
3502
|
+
await fs2.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
3083
3503
|
}
|
|
3084
3504
|
async function updatePackageLockJson(targetDir, projectName) {
|
|
3085
|
-
const lockFilePath =
|
|
3086
|
-
if (!await
|
|
3505
|
+
const lockFilePath = path2.join(targetDir, "package-lock.json");
|
|
3506
|
+
if (!await fs2.pathExists(lockFilePath)) {
|
|
3087
3507
|
return;
|
|
3088
3508
|
}
|
|
3089
|
-
const lockFile = await
|
|
3509
|
+
const lockFile = await fs2.readJson(lockFilePath);
|
|
3090
3510
|
if (lockFile.name === TEMPLATE_PROJECT_NAME) {
|
|
3091
3511
|
lockFile.name = projectName;
|
|
3092
3512
|
}
|
|
3093
3513
|
if (lockFile.packages?.[""]?.name === TEMPLATE_PROJECT_NAME) {
|
|
3094
3514
|
lockFile.packages[""].name = projectName;
|
|
3095
3515
|
}
|
|
3096
|
-
await
|
|
3516
|
+
await fs2.writeJson(lockFilePath, lockFile, { spaces: 2 });
|
|
3097
3517
|
}
|
|
3098
3518
|
async function updateReadme(targetDir, projectName) {
|
|
3099
|
-
const readmePath =
|
|
3100
|
-
if (!await
|
|
3519
|
+
const readmePath = path2.join(targetDir, "README.md");
|
|
3520
|
+
if (!await fs2.pathExists(readmePath)) {
|
|
3101
3521
|
return;
|
|
3102
3522
|
}
|
|
3103
|
-
let content = await
|
|
3523
|
+
let content = await fs2.readFile(readmePath, "utf-8");
|
|
3104
3524
|
content = content.replace(/^# (.+)$/m, `# ${projectName}`);
|
|
3105
|
-
await
|
|
3525
|
+
await fs2.writeFile(readmePath, content);
|
|
3106
3526
|
}
|
|
3107
3527
|
async function createProject(projectNameOrOptions, useCurrentDir = false, preset) {
|
|
3108
3528
|
let projectName;
|
|
@@ -3125,19 +3545,19 @@ async function createProject(projectNameOrOptions, useCurrentDir = false, preset
|
|
|
3125
3545
|
if (!currentDir) {
|
|
3126
3546
|
validateProjectName(projectName);
|
|
3127
3547
|
}
|
|
3128
|
-
const templateDir =
|
|
3548
|
+
const templateDir = path2.join(__dirname$1, "../../template");
|
|
3129
3549
|
let targetDir;
|
|
3130
3550
|
if (currentDir) {
|
|
3131
3551
|
targetDir = process.cwd();
|
|
3132
|
-
projectName =
|
|
3552
|
+
projectName = path2.basename(targetDir);
|
|
3133
3553
|
} else if (outputDir) {
|
|
3134
|
-
targetDir =
|
|
3135
|
-
if (await
|
|
3554
|
+
targetDir = path2.resolve(outputDir);
|
|
3555
|
+
if (await fs2.pathExists(targetDir)) {
|
|
3136
3556
|
throw new ScaffoldError(`Directory ${outputDir} already exists`);
|
|
3137
3557
|
}
|
|
3138
3558
|
} else {
|
|
3139
|
-
targetDir =
|
|
3140
|
-
if (await
|
|
3559
|
+
targetDir = path2.resolve(process.cwd(), projectName);
|
|
3560
|
+
if (await fs2.pathExists(targetDir)) {
|
|
3141
3561
|
throw new ScaffoldError(`Directory ${projectName} already exists`);
|
|
3142
3562
|
}
|
|
3143
3563
|
}
|
|
@@ -3164,16 +3584,16 @@ async function createProject(projectNameOrOptions, useCurrentDir = false, preset
|
|
|
3164
3584
|
for (const file of generatedFiles2) {
|
|
3165
3585
|
console.log(` ${chalk.green("\u2713")} ${file}`);
|
|
3166
3586
|
}
|
|
3167
|
-
const gitignorePath2 =
|
|
3587
|
+
const gitignorePath2 = path2.join(templateDir, ".gitignore");
|
|
3168
3588
|
let ignorePatterns2 = [];
|
|
3169
|
-
if (await
|
|
3170
|
-
const gitignoreContent = await
|
|
3589
|
+
if (await fs2.pathExists(gitignorePath2)) {
|
|
3590
|
+
const gitignoreContent = await fs2.readFile(gitignorePath2, "utf-8");
|
|
3171
3591
|
ignorePatterns2 = parseGitignore(gitignoreContent);
|
|
3172
3592
|
}
|
|
3173
3593
|
ignorePatterns2.push("node_modules", ".wrangler");
|
|
3174
3594
|
const excludePatterns2 = getExcludePatterns(resolved, allManifests);
|
|
3175
3595
|
let templateFileCount = 0;
|
|
3176
|
-
const templateFiles = await
|
|
3596
|
+
const templateFiles = await fs2.readdir(templateDir, { recursive: true });
|
|
3177
3597
|
for (const file of templateFiles) {
|
|
3178
3598
|
const relative = String(file);
|
|
3179
3599
|
if (!relative) continue;
|
|
@@ -3208,21 +3628,21 @@ async function createProject(projectNameOrOptions, useCurrentDir = false, preset
|
|
|
3208
3628
|
}
|
|
3209
3629
|
if (!currentDir) {
|
|
3210
3630
|
const dirSpinner = ora("Creating project directory...").start();
|
|
3211
|
-
await
|
|
3631
|
+
await fs2.ensureDir(targetDir);
|
|
3212
3632
|
dirSpinner.succeed(chalk.green("Project directory created"));
|
|
3213
3633
|
}
|
|
3214
3634
|
const copySpinner = ora("Copying template files...").start();
|
|
3215
|
-
const gitignorePath =
|
|
3635
|
+
const gitignorePath = path2.join(templateDir, ".gitignore");
|
|
3216
3636
|
let ignorePatterns = [];
|
|
3217
|
-
if (await
|
|
3218
|
-
const gitignoreContent = await
|
|
3637
|
+
if (await fs2.pathExists(gitignorePath)) {
|
|
3638
|
+
const gitignoreContent = await fs2.readFile(gitignorePath, "utf-8");
|
|
3219
3639
|
ignorePatterns = parseGitignore(gitignoreContent);
|
|
3220
3640
|
}
|
|
3221
3641
|
ignorePatterns.push("node_modules", ".wrangler");
|
|
3222
3642
|
const excludePatterns = getExcludePatterns(resolved, allManifests);
|
|
3223
|
-
await
|
|
3643
|
+
await fs2.copy(templateDir, targetDir, {
|
|
3224
3644
|
filter: (src) => {
|
|
3225
|
-
const relative =
|
|
3645
|
+
const relative = path2.relative(templateDir, src);
|
|
3226
3646
|
if (relative === "") return true;
|
|
3227
3647
|
const negated = ignorePatterns.filter((p) => p.startsWith("!"));
|
|
3228
3648
|
const gitIgnored = ignorePatterns.filter((p) => !p.startsWith("!") && relative.startsWith(p));
|
|
@@ -3244,80 +3664,80 @@ async function createProject(projectNameOrOptions, useCurrentDir = false, preset
|
|
|
3244
3664
|
copySpinner.succeed(chalk.green("Template files copied"));
|
|
3245
3665
|
const genSpinner = ora("Generating module-specific files...").start();
|
|
3246
3666
|
const routeRegistryContent = generateRouteRegistry(resolved);
|
|
3247
|
-
await
|
|
3667
|
+
await fs2.writeFile(path2.join(targetDir, "src/server/route-registry.ts"), routeRegistryContent);
|
|
3248
3668
|
const dbSchemaContent = generateDbSchemaBarrel(resolved);
|
|
3249
|
-
await
|
|
3669
|
+
await fs2.writeFile(path2.join(targetDir, "src/server/db/schema/index.ts"), dbSchemaContent);
|
|
3250
3670
|
if (resolved.hasClient) {
|
|
3251
3671
|
const clientNavContent = generateClientNavigation(resolved);
|
|
3252
|
-
await
|
|
3253
|
-
|
|
3672
|
+
await fs2.writeFile(
|
|
3673
|
+
path2.join(targetDir, "src/client/components/Navigation.tsx"),
|
|
3254
3674
|
clientNavContent
|
|
3255
3675
|
);
|
|
3256
3676
|
const clientAppTestContent = generateClientAppTest(resolved);
|
|
3257
|
-
await
|
|
3258
|
-
await
|
|
3259
|
-
|
|
3677
|
+
await fs2.ensureDir(path2.join(targetDir, "src/client/components/__tests__"));
|
|
3678
|
+
await fs2.writeFile(
|
|
3679
|
+
path2.join(targetDir, "src/client/components/__tests__/App.test.tsx"),
|
|
3260
3680
|
clientAppTestContent
|
|
3261
3681
|
);
|
|
3262
3682
|
const clientNavTestContent = generateClientNavigationTest(resolved);
|
|
3263
|
-
await
|
|
3264
|
-
|
|
3683
|
+
await fs2.writeFile(
|
|
3684
|
+
path2.join(targetDir, "src/client/components/__tests__/Navigation.test.tsx"),
|
|
3265
3685
|
clientNavTestContent
|
|
3266
3686
|
);
|
|
3267
3687
|
const presetUIConfigContent = generatePresetUIConfig(resolved, selectedPreset.id);
|
|
3268
|
-
await
|
|
3269
|
-
|
|
3688
|
+
await fs2.writeFile(
|
|
3689
|
+
path2.join(targetDir, "src/client/preset-ui-config.ts"),
|
|
3270
3690
|
presetUIConfigContent
|
|
3271
3691
|
);
|
|
3272
3692
|
const clientMainContent = generateClientMain(resolved, selectedPreset.id);
|
|
3273
|
-
await
|
|
3693
|
+
await fs2.writeFile(path2.join(targetDir, "src/client/main.tsx"), clientMainContent);
|
|
3274
3694
|
}
|
|
3275
3695
|
if (resolved.hasClient && resolved.modules.has("admin")) {
|
|
3276
3696
|
const adminAppContent = generateAdminApp(resolved);
|
|
3277
3697
|
if (adminAppContent) {
|
|
3278
|
-
await
|
|
3279
|
-
await
|
|
3698
|
+
await fs2.ensureDir(path2.join(targetDir, "src/admin"));
|
|
3699
|
+
await fs2.writeFile(path2.join(targetDir, "src/admin/App.tsx"), adminAppContent);
|
|
3280
3700
|
}
|
|
3281
3701
|
}
|
|
3282
3702
|
const serverAppContent = generateServerApp(resolved);
|
|
3283
|
-
await
|
|
3703
|
+
await fs2.writeFile(path2.join(targetDir, "src/server/app.ts"), serverAppContent);
|
|
3284
3704
|
const generatedFiles = getGeneratedFiles(resolved);
|
|
3285
3705
|
if (generatedFiles.includes("src/server/db/init.ts")) {
|
|
3286
3706
|
const dbInitContent = generateDbInit(resolved);
|
|
3287
|
-
await
|
|
3707
|
+
await fs2.writeFile(path2.join(targetDir, "src/server/db/init.ts"), dbInitContent);
|
|
3288
3708
|
}
|
|
3289
3709
|
const sharedModulesContent = generateSharedModulesIndex(resolved);
|
|
3290
|
-
await
|
|
3710
|
+
await fs2.writeFile(path2.join(targetDir, "src/shared/modules/index.ts"), sharedModulesContent);
|
|
3291
3711
|
const sharedSchemasContent = generateSharedSchemasIndex(resolved);
|
|
3292
|
-
await
|
|
3712
|
+
await fs2.writeFile(path2.join(targetDir, "src/shared/schemas/index.ts"), sharedSchemasContent);
|
|
3293
3713
|
const middlewareIndexContent = generateMiddlewareIndex(resolved);
|
|
3294
|
-
await
|
|
3295
|
-
|
|
3714
|
+
await fs2.writeFile(
|
|
3715
|
+
path2.join(targetDir, "src/server/middleware/index.ts"),
|
|
3296
3716
|
middlewareIndexContent
|
|
3297
3717
|
);
|
|
3298
3718
|
if (generatedFiles.includes("src/server/middleware/auth.ts")) {
|
|
3299
3719
|
const authMiddlewareContent = generateAuthMiddleware(resolved);
|
|
3300
|
-
await
|
|
3301
|
-
|
|
3720
|
+
await fs2.writeFile(
|
|
3721
|
+
path2.join(targetDir, "src/server/middleware/auth.ts"),
|
|
3302
3722
|
authMiddlewareContent
|
|
3303
3723
|
);
|
|
3304
3724
|
}
|
|
3305
3725
|
if (generatedFiles.includes("src/server/utils/auth.ts")) {
|
|
3306
3726
|
const authUtilsContent = generateAuthUtils(resolved);
|
|
3307
|
-
await
|
|
3727
|
+
await fs2.writeFile(path2.join(targetDir, "src/server/utils/auth.ts"), authUtilsContent);
|
|
3308
3728
|
}
|
|
3309
3729
|
if (resolved.hasClient) {
|
|
3310
3730
|
const clientComponentsContent = generateClientComponentsIndex(resolved);
|
|
3311
|
-
await
|
|
3312
|
-
|
|
3731
|
+
await fs2.writeFile(
|
|
3732
|
+
path2.join(targetDir, "src/client/components/index.ts"),
|
|
3313
3733
|
clientComponentsContent
|
|
3314
3734
|
);
|
|
3315
3735
|
}
|
|
3316
3736
|
const cliModulesContent = generateCliModulesIndex(resolved);
|
|
3317
|
-
await
|
|
3737
|
+
await fs2.writeFile(path2.join(targetDir, "src/cli/modules/index.ts"), cliModulesContent);
|
|
3318
3738
|
if (resolved.hasClient && generatedFiles.includes("vite.config.ts")) {
|
|
3319
3739
|
const viteConfigContent = generateViteConfig(resolved, templateDir);
|
|
3320
|
-
await
|
|
3740
|
+
await fs2.writeFile(path2.join(targetDir, "vite.config.ts"), viteConfigContent);
|
|
3321
3741
|
}
|
|
3322
3742
|
genSpinner.succeed(chalk.green("Module-specific files generated"));
|
|
3323
3743
|
const pkgSpinner = ora("Configuring package.json...").start();
|
|
@@ -3369,66 +3789,37 @@ async function createProject(projectNameOrOptions, useCurrentDir = false, preset
|
|
|
3369
3789
|
}
|
|
3370
3790
|
}
|
|
3371
3791
|
|
|
3372
|
-
// src/index.ts
|
|
3373
|
-
var
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
preset = await select({
|
|
3394
|
-
message: "Choose a template preset:",
|
|
3395
|
-
choices: presets.map((p) => ({
|
|
3396
|
-
value: p.id,
|
|
3397
|
-
name: `${p.name} \u2014 ${p.description}`
|
|
3398
|
-
}))
|
|
3399
|
-
});
|
|
3400
|
-
}
|
|
3401
|
-
if (!preset) {
|
|
3402
|
-
preset = "fullstack-admin";
|
|
3403
|
-
}
|
|
3404
|
-
try {
|
|
3405
|
-
await createProject({
|
|
3406
|
-
projectName,
|
|
3407
|
-
currentDir: options.currentDir ?? false,
|
|
3408
|
-
preset,
|
|
3409
|
-
outputDir: options.outputDir,
|
|
3410
|
-
dryRun: options.dryRun ?? false
|
|
3411
|
-
});
|
|
3412
|
-
} catch (error) {
|
|
3413
|
-
if (error instanceof ScaffoldError) {
|
|
3414
|
-
console.error(chalk.red(` \u2716 ${error.message}`));
|
|
3415
|
-
process.exit(1);
|
|
3416
|
-
}
|
|
3417
|
-
throw error;
|
|
3418
|
-
}
|
|
3792
|
+
// src/cli/index.ts
|
|
3793
|
+
var MODULE_COMMANDS = ["todo", "notification", "config"];
|
|
3794
|
+
program.name("create-fullstack-scaffold").description("Create a new fullstack scaffolded project").version("0.1.1").argument("[project-name]", "Name of the project to create").option("-v, --verbose", "Enable verbose output").option("-u, --url <url>", "Server URL", "http://localhost:3010").option("-p, --preset <preset>", "Template preset to use", "fullstack-admin").option("-d, --dry-run", "Preview files without creating them").option("--current-dir", "Scaffold in the current directory").action(async (projectName, cmdOptions) => {
|
|
3795
|
+
if (projectName && !MODULE_COMMANDS.includes(projectName)) {
|
|
3796
|
+
const isCurrentDir = cmdOptions.currentDir === true || projectName === ".";
|
|
3797
|
+
createLogger({ verbose: cmdOptions.verbose });
|
|
3798
|
+
const options = {
|
|
3799
|
+
projectName: isCurrentDir ? "." : projectName,
|
|
3800
|
+
currentDir: isCurrentDir,
|
|
3801
|
+
preset: cmdOptions.preset,
|
|
3802
|
+
dryRun: cmdOptions.dryRun
|
|
3803
|
+
};
|
|
3804
|
+
await createProject(options).catch((err) => {
|
|
3805
|
+
console.error(`Error: ${err.message}`);
|
|
3806
|
+
process.exit(1);
|
|
3807
|
+
});
|
|
3808
|
+
return;
|
|
3809
|
+
}
|
|
3810
|
+
if (!projectName) {
|
|
3811
|
+
program.outputHelp();
|
|
3812
|
+
process.exit(1);
|
|
3419
3813
|
}
|
|
3420
|
-
);
|
|
3421
|
-
program.
|
|
3422
|
-
const
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
console.log(` ${chalk.green(preset.id.padEnd(20))} ${preset.name}`);
|
|
3427
|
-
console.log(` ${" ".repeat(20)} ${preset.description}`);
|
|
3428
|
-
console.log(` ${" ".repeat(20)} Modules: ${preset.modules.join(", ")}`);
|
|
3429
|
-
console.log();
|
|
3814
|
+
});
|
|
3815
|
+
program.hook("preAction", (thisCommand) => {
|
|
3816
|
+
const options = thisCommand.opts();
|
|
3817
|
+
createLogger({ verbose: options.verbose });
|
|
3818
|
+
if (options.url) {
|
|
3819
|
+
setBaseUrl(options.url);
|
|
3430
3820
|
}
|
|
3431
3821
|
});
|
|
3822
|
+
registerModules(program);
|
|
3432
3823
|
program.parse();
|
|
3433
3824
|
//# sourceMappingURL=index.js.map
|
|
3434
3825
|
//# sourceMappingURL=index.js.map
|