@idevconn/create-icore 0.5.2 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +109 -45
- package/dist/index.cjs +109 -45
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +109 -45
- package/package.json +1 -1
- package/templates/apps/api/.env.example +20 -0
- package/templates/apps/api/package.json +1 -0
- package/templates/apps/api/tsconfig.json +6 -1
- package/templates/apps/api/webpack.config.js +20 -0
- package/templates/apps/microservices/auth/.env.example +5 -0
- package/templates/apps/microservices/auth/tsconfig.json +6 -1
- package/templates/apps/microservices/auth/webpack.config.js +30 -0
- package/templates/apps/microservices/jobs/tsconfig.json +6 -1
- package/templates/apps/microservices/jobs/webpack.config.js +30 -0
- package/templates/apps/microservices/notes/.env.example +5 -0
- package/templates/apps/microservices/notes/tsconfig.json +6 -1
- package/templates/apps/microservices/notes/webpack.config.js +30 -0
- package/templates/apps/microservices/notes-e2e/src/support/global.d.ts +6 -0
- package/templates/apps/microservices/payment/.env.example +5 -0
- package/templates/apps/microservices/payment/tsconfig.json +6 -1
- package/templates/apps/microservices/payment/webpack.config.js +30 -0
- package/templates/apps/microservices/upload/.env.example +5 -0
- package/templates/apps/microservices/upload/tsconfig.json +6 -1
- package/templates/apps/microservices/upload/webpack.config.js +30 -0
- package/templates/apps/templates/client-antd/src/components/AccessDeniedPage.tsx +1 -1
- package/templates/apps/templates/client-antd/src/components/layout/LayoutHeader.tsx +1 -1
- package/templates/apps/templates/client-antd/src/components/layout/LayoutSider.tsx +3 -3
- package/templates/apps/templates/client-antd/src/routes/_dashboard/dashboard.tsx +2 -2
- package/templates/apps/templates/client-antd/src/routes/_dashboard/notes.tsx +2 -2
- package/templates/apps/templates/client-antd/src/routes/_dashboard/profile.tsx +2 -2
- package/templates/apps/templates/client-antd/src/routes/auth.callback.tsx +1 -1
- package/templates/apps/templates/client-antd/src/routes/auth.oauth.callback.tsx +1 -1
- package/templates/apps/templates/client-antd/src/routes/login.tsx +1 -1
- package/templates/apps/templates/client-antd/tsconfig.json +6 -1
- package/templates/apps/templates/client-antd-e2e/src/icore.spec.ts +2 -2
- package/templates/apps/templates/client-mui/src/components/AccessDeniedPage.tsx +1 -1
- package/templates/apps/templates/client-mui/src/components/layout/LayoutHeader.tsx +1 -1
- package/templates/apps/templates/client-mui/src/components/layout/LayoutSider.tsx +3 -15
- package/templates/apps/templates/client-mui/src/routes/_dashboard/dashboard.tsx +2 -6
- package/templates/apps/templates/client-mui/src/routes/_dashboard/notes.tsx +2 -2
- package/templates/apps/templates/client-mui/src/routes/_dashboard/profile.tsx +3 -3
- package/templates/apps/templates/client-mui/src/routes/auth.callback.tsx +1 -1
- package/templates/apps/templates/client-mui/src/routes/auth.oauth.callback.tsx +1 -1
- package/templates/apps/templates/client-mui/src/routes/login.tsx +3 -3
- package/templates/apps/templates/client-mui/tsconfig.json +6 -1
- package/templates/apps/templates/client-mui-e2e/src/icore.spec.ts +2 -2
- package/templates/apps/templates/client-shadcn/src/components/AccessDeniedPage.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/components/layout/LayoutSider.tsx +3 -3
- package/templates/apps/templates/client-shadcn/src/components/notes/DeleteNoteConfirm.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/components/notes/NoteDialog.tsx +3 -3
- package/templates/apps/templates/client-shadcn/src/components/notes/NotesTable.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/components/ui/button.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/components/ui/card.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/components/ui/input.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/components/ui/label.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/routes/_dashboard/dashboard.tsx +3 -9
- package/templates/apps/templates/client-shadcn/src/routes/_dashboard/notes.tsx +6 -6
- package/templates/apps/templates/client-shadcn/src/routes/_dashboard/profile.tsx +7 -7
- package/templates/apps/templates/client-shadcn/src/routes/auth.callback.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/routes/auth.oauth.callback.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/routes/login.tsx +4 -4
- package/templates/apps/templates/client-shadcn/tsconfig.json +6 -1
- package/templates/libs/auth-client/package.json +1 -1
- package/templates/libs/auth-strategies/firebase/package.json +1 -1
- package/templates/libs/auth-strategies/firebase/src/lib/__tests__/firebase-auth.contract.unit.test.ts +6 -3
- package/templates/libs/auth-strategies/supabase/package.json +1 -1
- package/templates/libs/auth-strategies/supabase/src/lib/__tests__/supabase-auth.contract.unit.test.ts +5 -2
- package/templates/libs/db-strategies/firestore/package.json +1 -1
- package/templates/libs/db-strategies/firestore/src/lib/__tests__/firestore-db.contract.unit.test.ts +1 -2
- package/templates/libs/db-strategies/supabase/package.json +1 -1
- package/templates/libs/db-strategies/supabase/src/lib/__tests__/supabase-db.contract.unit.test.ts +1 -2
- package/templates/libs/firebase-admin/package.json +1 -1
- package/templates/libs/jobs-client/package.json +1 -1
- package/templates/libs/notes-client/package.json +1 -1
- package/templates/libs/payment-client/package.json +1 -1
- package/templates/libs/shared/package.json +3 -3
- package/templates/libs/shared/src/__tests__/cross-boundary.unit.test.ts +2 -1
- package/templates/libs/shared/src/__tests__/transport.unit.test.ts +47 -8
- package/templates/libs/shared/src/abilities/subjects.ts +12 -1
- package/templates/libs/shared/src/strategies/__tests__/fake-auth.contract.unit.test.ts +2 -2
- package/templates/libs/shared/src/strategies/__tests__/fake-db.contract.unit.test.ts +2 -2
- package/templates/libs/shared/src/strategies/__tests__/fake-storage.contract.unit.test.ts +2 -2
- package/templates/libs/shared/src/transport.ts +41 -0
- package/templates/libs/storage-strategies/cloudinary/package.json +1 -1
- package/templates/libs/storage-strategies/cloudinary/src/lib/__tests__/cloudinary-storage.contract.unit.test.ts +1 -2
- package/templates/libs/storage-strategies/firebase/package.json +1 -1
- package/templates/libs/storage-strategies/firebase/src/lib/__tests__/firebase-storage.contract.unit.test.ts +1 -2
- package/templates/libs/storage-strategies/supabase/package.json +1 -1
- package/templates/libs/storage-strategies/supabase/src/lib/__tests__/supabase-storage.contract.unit.test.ts +1 -2
- package/templates/libs/template-shared/package.json +1 -1
- package/templates/libs/upload-client/package.json +1 -1
- package/templates/libs/vite-plugins/src/index.d.mts +5 -7
- package/templates/libs/vite-plugins/src/index.mjs +1 -1
- package/templates/libs/vite-plugins/tsconfig.json +2 -1
- package/templates/package.json +2 -1
- package/templates/tools/create-icore/_template-shell/package.json +2 -1
- package/templates/.yarn/releases/yarn-4.5.0.cjs +0 -925
package/dist/index.js
CHANGED
|
@@ -32,6 +32,24 @@ async function copyTree(src, dest) {
|
|
|
32
32
|
else if (entry.isFile()) await copyFile(s, d);
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
var TRANSPORT_ENV_TOKEN = {
|
|
36
|
+
redis: "REDIS",
|
|
37
|
+
nats: "NATS",
|
|
38
|
+
mqtt: "MQTT",
|
|
39
|
+
rmq: "RMQ",
|
|
40
|
+
kafka: "KAFKA"
|
|
41
|
+
};
|
|
42
|
+
var TRANSPORT_DEPS = {
|
|
43
|
+
nats: { nats: "^2.29.3" },
|
|
44
|
+
mqtt: { mqtt: "^5.15.1" },
|
|
45
|
+
rmq: { amqplib: "^2.0.1", "amqp-connection-manager": "^5.0.0" },
|
|
46
|
+
kafka: { kafkajs: "^2.2.4" }
|
|
47
|
+
};
|
|
48
|
+
function uncommentTransportEnv(text2, prefix, transport) {
|
|
49
|
+
const token = TRANSPORT_ENV_TOKEN[transport];
|
|
50
|
+
if (!token) return text2;
|
|
51
|
+
return text2.replace(new RegExp(`^# (${prefix}_${token}_[A-Z0-9_]*=)`, "gm"), "$1");
|
|
52
|
+
}
|
|
35
53
|
async function rewriteRootPackageJson(targetDir, opts) {
|
|
36
54
|
const pkgPath = join(targetDir, "package.json");
|
|
37
55
|
const raw = await readFile(pkgPath, "utf8");
|
|
@@ -40,38 +58,31 @@ async function rewriteRootPackageJson(targetDir, opts) {
|
|
|
40
58
|
pkg["version"] = "0.0.1";
|
|
41
59
|
pkg["private"] = true;
|
|
42
60
|
delete pkg.description;
|
|
43
|
-
|
|
61
|
+
const transportDeps = TRANSPORT_DEPS[opts.transport];
|
|
62
|
+
if (transportDeps) {
|
|
44
63
|
const deps = pkg["dependencies"] ??= {};
|
|
45
|
-
deps
|
|
64
|
+
Object.assign(deps, transportDeps);
|
|
46
65
|
}
|
|
47
66
|
if (opts.packageManager !== "yarn") {
|
|
48
67
|
delete pkg.packageManager;
|
|
68
|
+
} else {
|
|
69
|
+
try {
|
|
70
|
+
const yarnrc = await readFile(join(targetDir, ".yarnrc.yml"), "utf8");
|
|
71
|
+
const match = yarnrc.match(/^yarnPath:\s*.+yarn-(\d+\.\d+\.\d+)\.cjs/m);
|
|
72
|
+
if (match?.[1]) {
|
|
73
|
+
pkg["packageManager"] = `yarn@${match[1]}`;
|
|
74
|
+
}
|
|
75
|
+
} catch {
|
|
76
|
+
}
|
|
49
77
|
}
|
|
50
|
-
|
|
51
|
-
pkg["pnpm"] = {
|
|
52
|
-
onlyBuiltDependencies: [
|
|
53
|
-
"@firebase/util",
|
|
54
|
-
"@nestjs/core",
|
|
55
|
-
"@parcel/watcher",
|
|
56
|
-
"@scarf/scarf",
|
|
57
|
-
"@swc/core",
|
|
58
|
-
"less",
|
|
59
|
-
"msgpackr-extract",
|
|
60
|
-
"nx",
|
|
61
|
-
"protobufjs",
|
|
62
|
-
"unrs-resolver"
|
|
63
|
-
]
|
|
64
|
-
};
|
|
65
|
-
}
|
|
78
|
+
delete pkg.pnpm;
|
|
66
79
|
await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
67
80
|
}
|
|
68
81
|
async function writeAuthEnv(targetDir, opts) {
|
|
69
82
|
const envExample = join(targetDir, "apps/microservices/auth/.env.example");
|
|
70
83
|
const env = await readFile(envExample, "utf8");
|
|
71
84
|
let next = env.replace(/^AUTH_PROVIDER=.*$/m, `AUTH_PROVIDER=${opts.authProvider}`).replace(/^AUTH_TRANSPORT=.*$/m, `AUTH_TRANSPORT=${opts.transport}`);
|
|
72
|
-
|
|
73
|
-
next = next.replace(/^# (AUTH_(?:REDIS|NATS)_URL=)/m, "$1");
|
|
74
|
-
}
|
|
85
|
+
next = uncommentTransportEnv(next, "AUTH", opts.transport);
|
|
75
86
|
await writeFile(join(targetDir, "apps/microservices/auth/.env"), next);
|
|
76
87
|
}
|
|
77
88
|
async function writeUploadEnv(targetDir, opts) {
|
|
@@ -79,9 +90,7 @@ async function writeUploadEnv(targetDir, opts) {
|
|
|
79
90
|
const envExample = join(targetDir, "apps/microservices/upload/.env.example");
|
|
80
91
|
const env = await readFile(envExample, "utf8");
|
|
81
92
|
let next = env.replace(/^STORAGE_PROVIDER=.*$/m, `STORAGE_PROVIDER=${opts.upload}`).replace(/^UPLOAD_TRANSPORT=.*$/m, `UPLOAD_TRANSPORT=${opts.transport}`);
|
|
82
|
-
|
|
83
|
-
next = next.replace(/^# (UPLOAD_(?:REDIS|NATS)_URL=)/m, "$1");
|
|
84
|
-
}
|
|
93
|
+
next = uncommentTransportEnv(next, "UPLOAD", opts.transport);
|
|
85
94
|
await writeFile(join(targetDir, "apps/microservices/upload/.env"), next);
|
|
86
95
|
}
|
|
87
96
|
async function writeNotesEnv(targetDir, opts) {
|
|
@@ -90,9 +99,7 @@ async function writeNotesEnv(targetDir, opts) {
|
|
|
90
99
|
try {
|
|
91
100
|
const env = await readFile(envExample, "utf8");
|
|
92
101
|
let next = env.replace(/^NOTES_TRANSPORT=.*$/m, `NOTES_TRANSPORT=${opts.transport}`);
|
|
93
|
-
|
|
94
|
-
next = next.replace(/^# (NOTES_(?:REDIS|NATS)_URL=)/m, "$1");
|
|
95
|
-
}
|
|
102
|
+
next = uncommentTransportEnv(next, "NOTES", opts.transport);
|
|
96
103
|
await writeFile(join(targetDir, "apps/microservices/notes/.env"), next);
|
|
97
104
|
} catch {
|
|
98
105
|
}
|
|
@@ -101,8 +108,8 @@ async function writeGatewayEnv(targetDir, opts) {
|
|
|
101
108
|
const envExample = join(targetDir, "apps/api/.env.example");
|
|
102
109
|
const env = await readFile(envExample, "utf8");
|
|
103
110
|
let next = env.replace(/^AUTH_TRANSPORT=.*$/m, `AUTH_TRANSPORT=${opts.transport}`).replace(/^UPLOAD_TRANSPORT=.*$/m, `UPLOAD_TRANSPORT=${opts.transport}`).replace(/^NOTES_TRANSPORT=.*$/m, `NOTES_TRANSPORT=${opts.transport}`).replace(/^PAYMENT_TRANSPORT=.*$/m, `PAYMENT_TRANSPORT=${opts.transport}`);
|
|
104
|
-
|
|
105
|
-
next = next
|
|
111
|
+
for (const prefix of ["AUTH", "UPLOAD", "NOTES", "PAYMENT"]) {
|
|
112
|
+
next = uncommentTransportEnv(next, prefix, opts.transport);
|
|
106
113
|
}
|
|
107
114
|
await writeFile(join(targetDir, "apps/api/.env"), next);
|
|
108
115
|
}
|
|
@@ -140,9 +147,7 @@ async function writePaymentEnv(targetDir, opts) {
|
|
|
140
147
|
try {
|
|
141
148
|
const env = await readFile(envExample, "utf8");
|
|
142
149
|
let next = env.replace(/^PAYMENT_PROVIDER=.*$/m, `PAYMENT_PROVIDER=${opts.payment}`).replace(/^PAYMENT_TRANSPORT=.*$/m, `PAYMENT_TRANSPORT=${opts.transport}`);
|
|
143
|
-
|
|
144
|
-
next = next.replace(/^# (PAYMENT_(?:REDIS|NATS)_URL=)/m, "$1");
|
|
145
|
-
}
|
|
150
|
+
next = uncommentTransportEnv(next, "PAYMENT", opts.transport);
|
|
146
151
|
await writeFile(join(targetDir, "apps/microservices/payment/.env"), next);
|
|
147
152
|
} catch {
|
|
148
153
|
}
|
|
@@ -231,7 +236,10 @@ async function removeNotesStack(targetDir) {
|
|
|
231
236
|
await writeFile(appModulePath, next);
|
|
232
237
|
} catch {
|
|
233
238
|
}
|
|
234
|
-
await stripDeps(join(targetDir, "apps/api/package.json"), [
|
|
239
|
+
await stripDeps(join(targetDir, "apps/api/package.json"), [
|
|
240
|
+
"@icore/notes-client",
|
|
241
|
+
"@casl/ability"
|
|
242
|
+
]);
|
|
235
243
|
await stripGatewayTransport(targetDir, "NOTES");
|
|
236
244
|
const tsconfigPath = join(targetDir, "tsconfig.base.json");
|
|
237
245
|
try {
|
|
@@ -243,21 +251,16 @@ async function removeNotesStack(targetDir) {
|
|
|
243
251
|
const siderPath = join(targetDir, "apps/client/src/components/layout/LayoutSider.tsx");
|
|
244
252
|
try {
|
|
245
253
|
const src = await readFile(siderPath, "utf8");
|
|
246
|
-
const next = src.replace(", StickyNote", "").replace(/\n {8}<Link\n {10}to="\/_dashboard\/notes"[\s\S]*?<\/Link>/, "").replace(", FileTextOutlined", "").replace(
|
|
254
|
+
const next = src.replace(", StickyNote", "").replace(/\n {8}<Link\n {10}to="\/(?:_dashboard\/)?notes"[\s\S]*?<\/Link>/, "").replace(", FileTextOutlined", "").replace(
|
|
247
255
|
"const selectedKey = pathname.includes('/notes')\n ? 'notes'\n : pathname.includes('/profile')",
|
|
248
256
|
"const selectedKey = pathname.includes('/profile')"
|
|
249
257
|
).replace(
|
|
250
|
-
|
|
251
|
-
{
|
|
252
|
-
key: 'notes',
|
|
253
|
-
icon: <FileTextOutlined />,
|
|
254
|
-
label: <Link to="/_dashboard/notes">{t('notes.title')}</Link>,
|
|
255
|
-
},`,
|
|
258
|
+
/\n {4}\{\n {6}key: 'notes',\n {6}icon: <FileTextOutlined \/>,\n {6}label: <Link to="\/(?:_dashboard\/)?notes">\{t\('notes\.title'\)\}<\/Link>,\n {4}\},/,
|
|
256
259
|
""
|
|
257
260
|
).replace("import NoteOutlinedIcon from '@mui/icons-material/NoteOutlined';\n", "").replace(
|
|
258
|
-
/\n {8}<ListItemButton\n {10}component=\{Link\}\n {10}to="\/_dashboard\/notes"[\s\S]*?<\/ListItemButton>/,
|
|
261
|
+
/\n {8}<ListItemButton\n {10}component=\{Link\}\n {10}to="\/(?:_dashboard\/)?notes"[\s\S]*?<\/ListItemButton>/,
|
|
259
262
|
""
|
|
260
|
-
).replace(/\n\s*<Link to="\/_dashboard\/notes">[\s\S]*?<\/Link>/m, "");
|
|
263
|
+
).replace(/\n\s*<Link to="\/(?:_dashboard\/)?notes">[\s\S]*?<\/Link>/m, "");
|
|
261
264
|
await writeFile(siderPath, next);
|
|
262
265
|
} catch {
|
|
263
266
|
}
|
|
@@ -400,7 +403,7 @@ async function removeUnusedDbStrategies(targetDir, dbProvider) {
|
|
|
400
403
|
await stripTsconfigPath(targetDir, "@icore/db-supabase");
|
|
401
404
|
try {
|
|
402
405
|
const src = await readFile(modulePath, "utf8");
|
|
403
|
-
const next = src.replace(/^import \{ createClient \} from '@supabase\/supabase-js';\n/m, "").replace(/^import \{[^}]*SupabaseDBStrategy[^}]*\} from '@icore\/db-supabase';\n/m, "").replace(/\nfunction makeSupabaseDB[\s\S]*?\n}\n/m, "").replace(
|
|
406
|
+
const next = src.replace(/^import \{ createClient \} from '@supabase\/supabase-js';\n/m, "").replace(/^import \{[^}]*SupabaseDBStrategy[^}]*\} from '@icore\/db-supabase';\n/m, "").replace(/\nfunction makeSupabaseDB[\s\S]*?\n}\n/m, "").replace(/\nfunction requireEnv[\s\S]*?\n}\n/m, "").replace(
|
|
404
407
|
/if \(provider === 'supabase'\) return makeSupabaseDB\(cfg\);\n\s*return makeFirestoreDB\(cfg\);/m,
|
|
405
408
|
"return makeFirestoreDB(cfg);"
|
|
406
409
|
);
|
|
@@ -533,11 +536,69 @@ async function scaffold(opts, templatesDir) {
|
|
|
533
536
|
await rm(join(opts.targetDir, ".yarn"), { recursive: true, force: true });
|
|
534
537
|
await rm(join(opts.targetDir, ".yarnrc.yml"), { force: true });
|
|
535
538
|
}
|
|
539
|
+
if (opts.packageManager === "pnpm") {
|
|
540
|
+
await writePnpmWorkspace(opts.targetDir);
|
|
541
|
+
await rewritePnpmWorkspaceDeps(opts.targetDir);
|
|
542
|
+
}
|
|
536
543
|
await patchGitignoreForPm(opts.targetDir, opts.packageManager);
|
|
537
544
|
await writeAiFiles(opts.targetDir, opts);
|
|
538
545
|
if (opts.install) runInstall(opts.targetDir, opts.packageManager);
|
|
539
546
|
if (opts.initGit) gitInit(opts.targetDir, opts.projectName);
|
|
540
547
|
}
|
|
548
|
+
async function writePnpmWorkspace(targetDir) {
|
|
549
|
+
const pkgPath = join(targetDir, "package.json");
|
|
550
|
+
const pkg = JSON.parse(await readFile(pkgPath, "utf8"));
|
|
551
|
+
const workspaces = pkg.workspaces ?? [];
|
|
552
|
+
const packagesBlock = workspaces.map((p2) => ` - '${p2}'`).join("\n");
|
|
553
|
+
const allowBuilds = [
|
|
554
|
+
"@firebase/util",
|
|
555
|
+
"@nestjs/core",
|
|
556
|
+
"@parcel/watcher",
|
|
557
|
+
"@scarf/scarf",
|
|
558
|
+
"@swc/core",
|
|
559
|
+
"less",
|
|
560
|
+
"msgpackr-extract",
|
|
561
|
+
"nx",
|
|
562
|
+
"protobufjs",
|
|
563
|
+
"unrs-resolver"
|
|
564
|
+
].map((p2) => ` '${p2}': true`).join("\n");
|
|
565
|
+
const content = `packages:
|
|
566
|
+
${packagesBlock}
|
|
567
|
+
|
|
568
|
+
allowBuilds:
|
|
569
|
+
${allowBuilds}
|
|
570
|
+
`;
|
|
571
|
+
await writeFile(join(targetDir, "pnpm-workspace.yaml"), content);
|
|
572
|
+
}
|
|
573
|
+
async function rewritePnpmWorkspaceDeps(targetDir) {
|
|
574
|
+
const { readdir: rd } = await import("fs/promises");
|
|
575
|
+
async function walk(dir) {
|
|
576
|
+
const found = [];
|
|
577
|
+
let entries;
|
|
578
|
+
try {
|
|
579
|
+
entries = await rd(dir, { withFileTypes: true });
|
|
580
|
+
} catch {
|
|
581
|
+
return found;
|
|
582
|
+
}
|
|
583
|
+
for (const e of entries) {
|
|
584
|
+
if (e.isDirectory() && e.name !== "node_modules") {
|
|
585
|
+
found.push(...await walk(join(dir, e.name)));
|
|
586
|
+
} else if (e.isFile() && e.name === "package.json") {
|
|
587
|
+
found.push(join(dir, e.name));
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return found;
|
|
591
|
+
}
|
|
592
|
+
const pkgFiles = await walk(targetDir);
|
|
593
|
+
for (const f of pkgFiles) {
|
|
594
|
+
try {
|
|
595
|
+
const raw = await readFile(f, "utf8");
|
|
596
|
+
const next = raw.replace(/"(@icore\/[^"]+)":\s*"\*"/g, '"$1": "workspace:*"');
|
|
597
|
+
if (next !== raw) await writeFile(f, next);
|
|
598
|
+
} catch {
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
541
602
|
async function patchGitignoreForPm(targetDir, pm) {
|
|
542
603
|
const giPath = join(targetDir, ".gitignore");
|
|
543
604
|
try {
|
|
@@ -641,7 +702,7 @@ Apache-2.0
|
|
|
641
702
|
|
|
642
703
|
- **Branch strategy**: \`dev\` is default. Cut \`feature/<name>\` or \`bug/<name>\` from dev. PRs only target dev. Never push directly to main.
|
|
643
704
|
- **No code without approval**: Propose changes first, wait for go-ahead.
|
|
644
|
-
-
|
|
705
|
+
- **RULE \u2014 no crash on missing .env**: MS factories must catch config errors, print a boxed banner with ALL missing vars, and return a Fake strategy in dev. In prod (\`NODE_ENV=production\`) throw the same banner. The \`formatEnvBanner\` + \`missingEnv\` helpers from \`@icore/shared\` handle this.
|
|
645
706
|
- **Post-coding routine**: \`npx prettier --write <files>\` \u2192 \`${nx} lint <project>\` \u2192 \`${nx} build <project>\` \u2014 all green before committing.
|
|
646
707
|
- **Nx generators only**: never hand-write \`project.json\` / tsconfig stacks. Use \`${nx} g @nx/<plugin>:<schematic>\`.
|
|
647
708
|
|
|
@@ -938,7 +999,10 @@ Re-run with @latest to refresh:
|
|
|
938
999
|
options: [
|
|
939
1000
|
{ value: "tcp", label: "TCP (default, no broker required)" },
|
|
940
1001
|
{ value: "redis", label: "Redis" },
|
|
941
|
-
{ value: "nats", label: "NATS" }
|
|
1002
|
+
{ value: "nats", label: "NATS" },
|
|
1003
|
+
{ value: "mqtt", label: "MQTT" },
|
|
1004
|
+
{ value: "rmq", label: "RabbitMQ" },
|
|
1005
|
+
{ value: "kafka", label: "Kafka" }
|
|
942
1006
|
],
|
|
943
1007
|
initialValue: "tcp"
|
|
944
1008
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idevconn/create-icore",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Bootstrap a new project from the iCore scaffold (Nx + NestJS + React + Vite + shadcn/Tailwind, swappable auth + storage providers).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "iDEVconn",
|
|
@@ -7,6 +7,11 @@ AUTH_HOST=127.0.0.1
|
|
|
7
7
|
AUTH_PORT=4001
|
|
8
8
|
# AUTH_REDIS_URL=redis://localhost:6379
|
|
9
9
|
# AUTH_NATS_URL=nats://localhost:4222
|
|
10
|
+
# AUTH_MQTT_URL=mqtt://localhost:1883
|
|
11
|
+
# AUTH_RMQ_URL=amqp://localhost:5672
|
|
12
|
+
# AUTH_RMQ_QUEUE=auth_queue
|
|
13
|
+
# AUTH_KAFKA_BROKERS=localhost:9092
|
|
14
|
+
# AUTH_KAFKA_CLIENT_ID=auth
|
|
10
15
|
|
|
11
16
|
# Upload MS transport — must match apps/microservices/upload/.env
|
|
12
17
|
UPLOAD_TRANSPORT=tcp
|
|
@@ -14,6 +19,11 @@ UPLOAD_HOST=127.0.0.1
|
|
|
14
19
|
UPLOAD_PORT=4002
|
|
15
20
|
# UPLOAD_REDIS_URL=redis://localhost:6379
|
|
16
21
|
# UPLOAD_NATS_URL=nats://localhost:4222
|
|
22
|
+
# UPLOAD_MQTT_URL=mqtt://localhost:1883
|
|
23
|
+
# UPLOAD_RMQ_URL=amqp://localhost:5672
|
|
24
|
+
# UPLOAD_RMQ_QUEUE=upload_queue
|
|
25
|
+
# UPLOAD_KAFKA_BROKERS=localhost:9092
|
|
26
|
+
# UPLOAD_KAFKA_CLIENT_ID=upload
|
|
17
27
|
|
|
18
28
|
# Notes MS transport — must match apps/microservices/notes/.env
|
|
19
29
|
NOTES_TRANSPORT=tcp
|
|
@@ -21,6 +31,11 @@ NOTES_HOST=127.0.0.1
|
|
|
21
31
|
NOTES_PORT=4004
|
|
22
32
|
# NOTES_REDIS_URL=redis://localhost:6379
|
|
23
33
|
# NOTES_NATS_URL=nats://localhost:4222
|
|
34
|
+
# NOTES_MQTT_URL=mqtt://localhost:1883
|
|
35
|
+
# NOTES_RMQ_URL=amqp://localhost:5672
|
|
36
|
+
# NOTES_RMQ_QUEUE=notes_queue
|
|
37
|
+
# NOTES_KAFKA_BROKERS=localhost:9092
|
|
38
|
+
# NOTES_KAFKA_CLIENT_ID=notes
|
|
24
39
|
|
|
25
40
|
# Payment MS transport — must match apps/microservices/payment/.env
|
|
26
41
|
PAYMENT_TRANSPORT=tcp
|
|
@@ -28,6 +43,11 @@ PAYMENT_HOST=127.0.0.1
|
|
|
28
43
|
PAYMENT_PORT=4003
|
|
29
44
|
# PAYMENT_REDIS_URL=redis://localhost:6379
|
|
30
45
|
# PAYMENT_NATS_URL=nats://localhost:4222
|
|
46
|
+
# PAYMENT_MQTT_URL=mqtt://localhost:1883
|
|
47
|
+
# PAYMENT_RMQ_URL=amqp://localhost:5672
|
|
48
|
+
# PAYMENT_RMQ_QUEUE=payment_queue
|
|
49
|
+
# PAYMENT_KAFKA_BROKERS=localhost:9092
|
|
50
|
+
# PAYMENT_KAFKA_CLIENT_ID=payment
|
|
31
51
|
|
|
32
52
|
# Per-request multipart file size cap (KB). Default 5120 (5 MB) when unset.
|
|
33
53
|
MAX_FILE_SIZE_KB=5120
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
|
|
2
|
+
const { TsconfigPathsPlugin } = require('tsconfig-paths-webpack-plugin');
|
|
2
3
|
const { join } = require('path');
|
|
3
4
|
|
|
4
5
|
module.exports = {
|
|
@@ -9,6 +10,23 @@ module.exports = {
|
|
|
9
10
|
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
|
|
10
11
|
}),
|
|
11
12
|
},
|
|
13
|
+
resolve: {
|
|
14
|
+
plugins: [new TsconfigPathsPlugin({ configFile: join(__dirname, 'tsconfig.app.json') })],
|
|
15
|
+
},
|
|
16
|
+
// See microservices/*/webpack.config.js for the @icore/* bundling rationale.
|
|
17
|
+
externals: [
|
|
18
|
+
function ({ request }, callback) {
|
|
19
|
+
if (
|
|
20
|
+
!request ||
|
|
21
|
+
request.startsWith('.') ||
|
|
22
|
+
request.startsWith('/') ||
|
|
23
|
+
request.startsWith('@icore/')
|
|
24
|
+
) {
|
|
25
|
+
return callback();
|
|
26
|
+
}
|
|
27
|
+
return callback(null, 'commonjs ' + request);
|
|
28
|
+
},
|
|
29
|
+
],
|
|
12
30
|
plugins: [
|
|
13
31
|
new NxAppWebpackPlugin({
|
|
14
32
|
target: 'node',
|
|
@@ -19,6 +37,8 @@ module.exports = {
|
|
|
19
37
|
optimization: false,
|
|
20
38
|
outputHashing: 'none',
|
|
21
39
|
generatePackageJson: true,
|
|
40
|
+
mergeExternals: true,
|
|
41
|
+
externalDependencies: [],
|
|
22
42
|
sourceMap: true,
|
|
23
43
|
}),
|
|
24
44
|
],
|
|
@@ -4,6 +4,11 @@ AUTH_HOST=127.0.0.1
|
|
|
4
4
|
AUTH_PORT=4001
|
|
5
5
|
# AUTH_REDIS_URL=redis://localhost:6379
|
|
6
6
|
# AUTH_NATS_URL=nats://localhost:4222
|
|
7
|
+
# AUTH_MQTT_URL=mqtt://localhost:1883
|
|
8
|
+
# AUTH_RMQ_URL=amqp://localhost:5672
|
|
9
|
+
# AUTH_RMQ_QUEUE=auth_queue
|
|
10
|
+
# AUTH_KAFKA_BROKERS=localhost:9092
|
|
11
|
+
# AUTH_KAFKA_CLIENT_ID=auth
|
|
7
12
|
|
|
8
13
|
# Which concrete AuthStrategy to instantiate
|
|
9
14
|
AUTH_PROVIDER=supabase
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
|
|
2
|
+
const { TsconfigPathsPlugin } = require('tsconfig-paths-webpack-plugin');
|
|
2
3
|
const { join } = require('path');
|
|
3
4
|
|
|
4
5
|
module.exports = {
|
|
@@ -9,6 +10,31 @@ module.exports = {
|
|
|
9
10
|
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
|
|
10
11
|
}),
|
|
11
12
|
},
|
|
13
|
+
resolve: {
|
|
14
|
+
// Resolve @icore/* via tsconfig paths so webpack can bundle them inline.
|
|
15
|
+
// nx skips its own tsconfig-paths plugin on "TS solution" workspaces, so we
|
|
16
|
+
// wire the standalone plugin explicitly (it follows extends → tsconfig.base).
|
|
17
|
+
plugins: [new TsconfigPathsPlugin({ configFile: join(__dirname, 'tsconfig.app.json') })],
|
|
18
|
+
},
|
|
19
|
+
// Keep every npm package external EXCEPT @icore/* workspace packages, which
|
|
20
|
+
// are bundled inline. @icore/* are workspace-internal: at runtime the package
|
|
21
|
+
// manager symlinks them to their TS source dir (not the compiled dist), so an
|
|
22
|
+
// external require('@icore/shared') fails ("Cannot find module './env'").
|
|
23
|
+
// Bundling removes runtime workspace resolution entirely — works identically
|
|
24
|
+
// on yarn / npm / pnpm.
|
|
25
|
+
externals: [
|
|
26
|
+
function ({ request }, callback) {
|
|
27
|
+
if (
|
|
28
|
+
!request ||
|
|
29
|
+
request.startsWith('.') ||
|
|
30
|
+
request.startsWith('/') ||
|
|
31
|
+
request.startsWith('@icore/')
|
|
32
|
+
) {
|
|
33
|
+
return callback(); // bundle inline
|
|
34
|
+
}
|
|
35
|
+
return callback(null, 'commonjs ' + request); // keep external
|
|
36
|
+
},
|
|
37
|
+
],
|
|
12
38
|
plugins: [
|
|
13
39
|
new NxAppWebpackPlugin({
|
|
14
40
|
target: 'node',
|
|
@@ -19,6 +45,10 @@ module.exports = {
|
|
|
19
45
|
optimization: false,
|
|
20
46
|
outputHashing: 'none',
|
|
21
47
|
generatePackageJson: true,
|
|
48
|
+
// Keep our externals (above) authoritative — do not let the plugin add
|
|
49
|
+
// its own nodeExternals that would re-externalize @icore/*.
|
|
50
|
+
mergeExternals: true,
|
|
51
|
+
externalDependencies: [],
|
|
22
52
|
sourceMap: true,
|
|
23
53
|
}),
|
|
24
54
|
],
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
|
|
2
|
+
const { TsconfigPathsPlugin } = require('tsconfig-paths-webpack-plugin');
|
|
2
3
|
const { join } = require('path');
|
|
3
4
|
|
|
4
5
|
module.exports = {
|
|
@@ -9,6 +10,31 @@ module.exports = {
|
|
|
9
10
|
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
|
|
10
11
|
}),
|
|
11
12
|
},
|
|
13
|
+
resolve: {
|
|
14
|
+
// Resolve @icore/* via tsconfig paths so webpack can bundle them inline.
|
|
15
|
+
// nx skips its own tsconfig-paths plugin on "TS solution" workspaces, so we
|
|
16
|
+
// wire the standalone plugin explicitly (it follows extends → tsconfig.base).
|
|
17
|
+
plugins: [new TsconfigPathsPlugin({ configFile: join(__dirname, 'tsconfig.app.json') })],
|
|
18
|
+
},
|
|
19
|
+
// Keep every npm package external EXCEPT @icore/* workspace packages, which
|
|
20
|
+
// are bundled inline. @icore/* are workspace-internal: at runtime the package
|
|
21
|
+
// manager symlinks them to their TS source dir (not the compiled dist), so an
|
|
22
|
+
// external require('@icore/shared') fails ("Cannot find module './env'").
|
|
23
|
+
// Bundling removes runtime workspace resolution entirely — works identically
|
|
24
|
+
// on yarn / npm / pnpm.
|
|
25
|
+
externals: [
|
|
26
|
+
function ({ request }, callback) {
|
|
27
|
+
if (
|
|
28
|
+
!request ||
|
|
29
|
+
request.startsWith('.') ||
|
|
30
|
+
request.startsWith('/') ||
|
|
31
|
+
request.startsWith('@icore/')
|
|
32
|
+
) {
|
|
33
|
+
return callback(); // bundle inline
|
|
34
|
+
}
|
|
35
|
+
return callback(null, 'commonjs ' + request); // keep external
|
|
36
|
+
},
|
|
37
|
+
],
|
|
12
38
|
plugins: [
|
|
13
39
|
new NxAppWebpackPlugin({
|
|
14
40
|
target: 'node',
|
|
@@ -19,6 +45,10 @@ module.exports = {
|
|
|
19
45
|
optimization: false,
|
|
20
46
|
outputHashing: 'none',
|
|
21
47
|
generatePackageJson: true,
|
|
48
|
+
// Keep our externals (above) authoritative — do not let the plugin add
|
|
49
|
+
// its own nodeExternals that would re-externalize @icore/*.
|
|
50
|
+
mergeExternals: true,
|
|
51
|
+
externalDependencies: [],
|
|
22
52
|
sourceMap: true,
|
|
23
53
|
}),
|
|
24
54
|
],
|
|
@@ -4,6 +4,11 @@ NOTES_HOST=127.0.0.1
|
|
|
4
4
|
NOTES_PORT=4004
|
|
5
5
|
# NOTES_REDIS_URL=redis://localhost:6379
|
|
6
6
|
# NOTES_NATS_URL=nats://localhost:4222
|
|
7
|
+
# NOTES_MQTT_URL=mqtt://localhost:1883
|
|
8
|
+
# NOTES_RMQ_URL=amqp://localhost:5672
|
|
9
|
+
# NOTES_RMQ_QUEUE=notes_queue
|
|
10
|
+
# NOTES_KAFKA_BROKERS=localhost:9092
|
|
11
|
+
# NOTES_KAFKA_CLIENT_ID=notes
|
|
7
12
|
|
|
8
13
|
# Which DB to use — defaults to the root .env DB_PROVIDER if unset.
|
|
9
14
|
# Supabase Postgres or Firestore. Both honored by NotesController via DBStrategy.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
|
|
2
|
+
const { TsconfigPathsPlugin } = require('tsconfig-paths-webpack-plugin');
|
|
2
3
|
const { join } = require('path');
|
|
3
4
|
|
|
4
5
|
module.exports = {
|
|
@@ -9,6 +10,31 @@ module.exports = {
|
|
|
9
10
|
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
|
|
10
11
|
}),
|
|
11
12
|
},
|
|
13
|
+
resolve: {
|
|
14
|
+
// Resolve @icore/* via tsconfig paths so webpack can bundle them inline.
|
|
15
|
+
// nx skips its own tsconfig-paths plugin on "TS solution" workspaces, so we
|
|
16
|
+
// wire the standalone plugin explicitly (it follows extends → tsconfig.base).
|
|
17
|
+
plugins: [new TsconfigPathsPlugin({ configFile: join(__dirname, 'tsconfig.app.json') })],
|
|
18
|
+
},
|
|
19
|
+
// Keep every npm package external EXCEPT @icore/* workspace packages, which
|
|
20
|
+
// are bundled inline. @icore/* are workspace-internal: at runtime the package
|
|
21
|
+
// manager symlinks them to their TS source dir (not the compiled dist), so an
|
|
22
|
+
// external require('@icore/shared') fails ("Cannot find module './env'").
|
|
23
|
+
// Bundling removes runtime workspace resolution entirely — works identically
|
|
24
|
+
// on yarn / npm / pnpm.
|
|
25
|
+
externals: [
|
|
26
|
+
function ({ request }, callback) {
|
|
27
|
+
if (
|
|
28
|
+
!request ||
|
|
29
|
+
request.startsWith('.') ||
|
|
30
|
+
request.startsWith('/') ||
|
|
31
|
+
request.startsWith('@icore/')
|
|
32
|
+
) {
|
|
33
|
+
return callback(); // bundle inline
|
|
34
|
+
}
|
|
35
|
+
return callback(null, 'commonjs ' + request); // keep external
|
|
36
|
+
},
|
|
37
|
+
],
|
|
12
38
|
plugins: [
|
|
13
39
|
new NxAppWebpackPlugin({
|
|
14
40
|
target: 'node',
|
|
@@ -19,6 +45,10 @@ module.exports = {
|
|
|
19
45
|
optimization: false,
|
|
20
46
|
outputHashing: 'none',
|
|
21
47
|
generatePackageJson: true,
|
|
48
|
+
// Keep our externals (above) authoritative — do not let the plugin add
|
|
49
|
+
// its own nodeExternals that would re-externalize @icore/*.
|
|
50
|
+
mergeExternals: true,
|
|
51
|
+
externalDependencies: [],
|
|
22
52
|
sourceMap: true,
|
|
23
53
|
}),
|
|
24
54
|
],
|
|
@@ -4,6 +4,11 @@ PAYMENT_HOST=127.0.0.1
|
|
|
4
4
|
PAYMENT_PORT=4003
|
|
5
5
|
# PAYMENT_REDIS_URL=redis://localhost:6379
|
|
6
6
|
# PAYMENT_NATS_URL=nats://localhost:4222
|
|
7
|
+
# PAYMENT_MQTT_URL=mqtt://localhost:1883
|
|
8
|
+
# PAYMENT_RMQ_URL=amqp://localhost:5672
|
|
9
|
+
# PAYMENT_RMQ_QUEUE=payment_queue
|
|
10
|
+
# PAYMENT_KAFKA_BROKERS=localhost:9092
|
|
11
|
+
# PAYMENT_KAFKA_CLIENT_ID=payment
|
|
7
12
|
|
|
8
13
|
# Which concrete PaymentStrategy to instantiate
|
|
9
14
|
PAYMENT_PROVIDER=paypal
|