@idevconn/create-icore 0.5.0 → 0.5.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 +84 -25
- package/dist/index.cjs +81 -24
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +80 -24
- package/package.json +1 -1
- package/templates/apps/api/.env.example +14 -0
- package/templates/apps/microservices/auth/package.json +1 -1
- package/templates/apps/microservices/auth/src/app/app.module.ts +17 -30
- package/templates/apps/microservices/auth/src/main.ts +6 -23
- package/templates/apps/microservices/jobs/src/app/redis-connection.ts +35 -0
- package/templates/apps/microservices/jobs/src/app/workers/cleanup.worker.ts +2 -1
- package/templates/apps/microservices/jobs/src/app/workers/email.worker.ts +2 -1
- package/templates/apps/microservices/jobs/src/app/workers/image-process.worker.ts +2 -1
- package/templates/apps/microservices/notes/src/app/app.module.ts +22 -27
- package/templates/apps/microservices/notes/src/main.ts +6 -23
- package/templates/apps/microservices/payment/src/app/app.module.ts +6 -4
- package/templates/apps/microservices/payment/src/main.ts +6 -23
- package/templates/apps/microservices/upload/package.json +1 -1
- package/templates/apps/microservices/upload/src/app/app.module.ts +18 -30
- package/templates/apps/microservices/upload/src/main.ts +6 -23
- package/templates/libs/firebase-admin/README.md +11 -0
- package/templates/libs/firebase-admin/eslint.config.mjs +24 -0
- package/templates/libs/firebase-admin/package.json +12 -0
- package/templates/libs/firebase-admin/project.json +19 -0
- package/templates/libs/firebase-admin/src/index.ts +1 -0
- package/templates/libs/firebase-admin/src/lib/__tests__/firebase-admin.unit.test.ts +105 -0
- package/templates/libs/firebase-admin/src/lib/firebase-admin.ts +70 -0
- package/templates/libs/firebase-admin/tsconfig.json +23 -0
- package/templates/libs/firebase-admin/tsconfig.lib.json +23 -0
- package/templates/libs/firebase-admin/tsconfig.spec.json +22 -0
- package/templates/libs/firebase-admin/vitest.config.mts +21 -0
- package/templates/libs/jobs-client/src/lib/jobs-client.service.ts +14 -2
- package/templates/libs/shared/src/__tests__/bootstrap.unit.test.ts +92 -0
- package/templates/libs/shared/src/__tests__/transport.unit.test.ts +14 -2
- package/templates/libs/shared/src/bootstrap.ts +79 -0
- package/templates/libs/shared/src/index.ts +1 -0
- package/templates/libs/shared/src/transport.ts +25 -3
- package/templates/tsconfig.base.json +2 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { formatEnvBanner } from './env';
|
|
2
|
+
|
|
3
|
+
interface MicroserviceLike {
|
|
4
|
+
listen: () => Promise<unknown>;
|
|
5
|
+
close: () => Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface LoggerLike {
|
|
9
|
+
log: (msg: string) => void;
|
|
10
|
+
warn: (msg: string) => void;
|
|
11
|
+
error: (msg: string, trace?: unknown) => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const RETRY_DELAY_MS = 3000;
|
|
15
|
+
|
|
16
|
+
function delay(ms: number): Promise<void> {
|
|
17
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Boots a microservice and binds its transport, surviving a broker that isn't
|
|
22
|
+
* up yet.
|
|
23
|
+
*
|
|
24
|
+
* NestJS `ServerRedis`/`ServerNats` REJECT `app.listen()` on the *initial*
|
|
25
|
+
* connect failure — the ioredis retryStrategy / NATS reconnect only governs
|
|
26
|
+
* re-connection after a first successful connect. So without this helper a MS
|
|
27
|
+
* would `process.exit(1)` whenever Redis/NATS is down on boot, even though the
|
|
28
|
+
* transport options ask for infinite retries.
|
|
29
|
+
*
|
|
30
|
+
* Behaviour (honours the "never crash on missing infra" rule):
|
|
31
|
+
* - tcp transport, or NODE_ENV=production → fail fast: `process.exit(1)`.
|
|
32
|
+
* - redis/nats in dev → log a boxed banner and retry `listen()` forever, so
|
|
33
|
+
* the service idles until the broker appears, then binds automatically.
|
|
34
|
+
*
|
|
35
|
+
* `createApp` must construct a *fresh* app each call: a failed listen closes
|
|
36
|
+
* the transport's clients, so the next attempt needs a new instance.
|
|
37
|
+
*/
|
|
38
|
+
export async function bootstrapMicroservice(
|
|
39
|
+
prefix: string,
|
|
40
|
+
createApp: () => Promise<MicroserviceLike>,
|
|
41
|
+
logger: LoggerLike,
|
|
42
|
+
): Promise<void> {
|
|
43
|
+
const transport = (process.env[`${prefix}_TRANSPORT`] ?? 'tcp').toLowerCase();
|
|
44
|
+
const isProd = process.env['NODE_ENV'] === 'production';
|
|
45
|
+
const failFast = transport === 'tcp' || isProd;
|
|
46
|
+
|
|
47
|
+
for (let attempt = 1; ; attempt++) {
|
|
48
|
+
let app: MicroserviceLike | undefined;
|
|
49
|
+
try {
|
|
50
|
+
app = await createApp();
|
|
51
|
+
await app.listen();
|
|
52
|
+
logger.log(`${prefix} microservice listening — transport=${transport}`);
|
|
53
|
+
return;
|
|
54
|
+
} catch (err) {
|
|
55
|
+
if (app) await app.close().catch(() => undefined);
|
|
56
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
57
|
+
|
|
58
|
+
if (failFast) {
|
|
59
|
+
logger.error(
|
|
60
|
+
`${prefix} microservice bootstrap failed`,
|
|
61
|
+
err instanceof Error ? err.stack : err,
|
|
62
|
+
);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
logger.warn(
|
|
67
|
+
formatEnvBanner({
|
|
68
|
+
service: `${prefix} microservice`,
|
|
69
|
+
provider: transport,
|
|
70
|
+
missing: [],
|
|
71
|
+
envPath: `the service .env (${prefix}_${transport.toUpperCase()}_URL)`,
|
|
72
|
+
reason: `${reason} — retry ${attempt} in ${RETRY_DELAY_MS / 1000}s; idling until the ${transport} broker is reachable`,
|
|
73
|
+
headline: `⚠ ${prefix} microservice — ${transport} broker unreachable (idling, not crashing)`,
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
await delay(RETRY_DELAY_MS);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -67,15 +67,37 @@ export function buildTransport(prefix: string): ClientOptions {
|
|
|
67
67
|
// ioredis accepts a connection URL string; the NestJS RedisOptions type
|
|
68
68
|
// exposes host/port fields but passes options directly to ioredis which
|
|
69
69
|
// also accepts a url field at runtime.
|
|
70
|
+
//
|
|
71
|
+
// retryAttempts/retryDelay are mandatory for resilience: NestJS
|
|
72
|
+
// ServerRedis builds its ioredis retryStrategy from them, and when
|
|
73
|
+
// retryAttempts is unset it logs "retry attempts not specified", stops
|
|
74
|
+
// reconnecting, and `app.listen()` REJECTS → the MS process exits. With
|
|
75
|
+
// an effectively-infinite retry the initial connect stays pending and
|
|
76
|
+
// keeps reconnecting, so a not-yet-up Redis never crashes the service —
|
|
77
|
+
// it idles and attaches once Redis is reachable.
|
|
70
78
|
return {
|
|
71
79
|
transport: Transport.REDIS,
|
|
72
|
-
options: {
|
|
80
|
+
options: {
|
|
81
|
+
url: required(`${prefix}_REDIS_URL`),
|
|
82
|
+
retryAttempts: Number.POSITIVE_INFINITY,
|
|
83
|
+
retryDelay: 2000,
|
|
84
|
+
},
|
|
73
85
|
} as unknown as ClientOptions;
|
|
74
86
|
case 'nats':
|
|
87
|
+
// reconnect/maxReconnectAttempts: -1 retries forever once connected, so a
|
|
88
|
+
// dropped broker re-attaches instead of giving up. The *initial* connect
|
|
89
|
+
// is intentionally allowed to reject when NATS is down on boot —
|
|
90
|
+
// bootstrapMicroservice() catches that, logs a banner, and retries, giving
|
|
91
|
+
// the same visible behaviour as the Redis transport above.
|
|
75
92
|
return {
|
|
76
93
|
transport: Transport.NATS,
|
|
77
|
-
options: {
|
|
78
|
-
|
|
94
|
+
options: {
|
|
95
|
+
servers: required(`${prefix}_NATS_URL`).split(','),
|
|
96
|
+
reconnect: true,
|
|
97
|
+
maxReconnectAttempts: -1,
|
|
98
|
+
reconnectTimeWait: 2000,
|
|
99
|
+
},
|
|
100
|
+
} as unknown as ClientOptions;
|
|
79
101
|
default:
|
|
80
102
|
throw new Error(`Unknown transport: ${kind}`);
|
|
81
103
|
}
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"@icore/payment-client": ["./libs/payment-client/src/index.ts"],
|
|
30
30
|
"@icore/notes-client": ["./libs/notes-client/src/index.ts"],
|
|
31
31
|
"@icore/jobs-client": ["./libs/jobs-client/src/index.ts"],
|
|
32
|
-
"@icore/vite-plugins": ["./libs/vite-plugins/src/index.d.mts"]
|
|
32
|
+
"@icore/vite-plugins": ["./libs/vite-plugins/src/index.d.mts"],
|
|
33
|
+
"@icore/firebase-admin": ["./libs/firebase-admin/src/index.ts"]
|
|
33
34
|
}
|
|
34
35
|
},
|
|
35
36
|
"exclude": ["node_modules", "dist", ".nx"]
|