@idevconn/create-icore 0.5.0 → 0.5.2
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 +3 -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/auth-strategies/firebase/src/lib/__tests__/firebase-auth.contract.unit.test.ts +1 -1
- package/templates/libs/auth-strategies/supabase/src/lib/__tests__/supabase-auth.contract.unit.test.ts +1 -1
- package/templates/libs/db-strategies/firestore/src/lib/__tests__/firestore-db.contract.unit.test.ts +1 -1
- package/templates/libs/db-strategies/supabase/src/lib/__tests__/supabase-db.contract.unit.test.ts +1 -1
- 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 +24 -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/jobs-client/tsconfig.json +2 -1
- package/templates/libs/notes-client/tsconfig.json +2 -1
- package/templates/libs/payment-client/tsconfig.json +2 -1
- 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/strategies/__tests__/fake-auth.contract.unit.test.ts +1 -1
- package/templates/libs/shared/src/strategies/__tests__/fake-db.contract.unit.test.ts +1 -1
- package/templates/libs/shared/src/strategies/__tests__/fake-storage.contract.unit.test.ts +1 -1
- package/templates/libs/shared/src/strategies/index.ts +3 -3
- package/templates/libs/shared/src/testing.ts +14 -0
- package/templates/libs/shared/src/transport.ts +25 -3
- package/templates/libs/shared/tsconfig.lib.json +3 -1
- package/templates/libs/shared/vitest.config.mts +11 -1
- package/templates/libs/storage-strategies/cloudinary/src/lib/__tests__/cloudinary-storage.contract.unit.test.ts +1 -1
- package/templates/libs/storage-strategies/firebase/src/lib/__tests__/firebase-storage.contract.unit.test.ts +1 -1
- package/templates/libs/storage-strategies/supabase/src/lib/__tests__/supabase-storage.contract.unit.test.ts +1 -1
- package/templates/tsconfig.base.json +3 -1
- /package/templates/libs/shared/src/strategies/{contract/auth-contract.ts → __tests__/auth.contract.unit.test.ts} +0 -0
- /package/templates/libs/shared/src/strategies/{contract/db-contract.ts → __tests__/db.contract.unit.test.ts} +0 -0
- /package/templates/libs/shared/src/strategies/{contract/storage-contract.ts → __tests__/storage.contract.unit.test.ts} +0 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { bootstrapMicroservice } from '../bootstrap';
|
|
3
|
+
|
|
4
|
+
interface FakeApp {
|
|
5
|
+
listen: () => Promise<void>;
|
|
6
|
+
close: () => Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function makeLogger() {
|
|
10
|
+
return { log: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const ORIG = { ...process.env };
|
|
14
|
+
|
|
15
|
+
describe('bootstrapMicroservice', () => {
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
vi.useFakeTimers();
|
|
18
|
+
delete process.env['AUTH_TRANSPORT'];
|
|
19
|
+
delete process.env['NODE_ENV'];
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
vi.useRealTimers();
|
|
24
|
+
vi.restoreAllMocks();
|
|
25
|
+
Object.assign(process.env, ORIG);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('redis in dev: retries with a banner instead of exiting, then binds when the broker appears', async () => {
|
|
29
|
+
process.env['AUTH_TRANSPORT'] = 'redis';
|
|
30
|
+
const logger = makeLogger();
|
|
31
|
+
const close = vi.fn().mockResolvedValue(undefined);
|
|
32
|
+
let attempts = 0;
|
|
33
|
+
const createApp = vi.fn(async (): Promise<FakeApp> => {
|
|
34
|
+
attempts += 1;
|
|
35
|
+
return {
|
|
36
|
+
// first attempt fails (broker down), second succeeds
|
|
37
|
+
listen:
|
|
38
|
+
attempts < 2 ? () => Promise.reject(new Error('ECONNREFUSED')) : () => Promise.resolve(),
|
|
39
|
+
close,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const done = bootstrapMicroservice('AUTH', createApp, logger);
|
|
44
|
+
// let the first attempt fail + the retry delay elapse
|
|
45
|
+
await vi.advanceTimersByTimeAsync(3000);
|
|
46
|
+
await done;
|
|
47
|
+
|
|
48
|
+
expect(createApp).toHaveBeenCalledTimes(2);
|
|
49
|
+
expect(close).toHaveBeenCalledTimes(1); // failed app cleaned up before retry
|
|
50
|
+
expect(logger.warn).toHaveBeenCalledTimes(1);
|
|
51
|
+
expect(logger.warn.mock.calls[0][0]).toContain('broker unreachable');
|
|
52
|
+
expect(logger.log).toHaveBeenCalledTimes(1); // "listening" on success
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('tcp: fails fast (process.exit) rather than retrying', async () => {
|
|
56
|
+
process.env['AUTH_TRANSPORT'] = 'tcp';
|
|
57
|
+
const logger = makeLogger();
|
|
58
|
+
const exit = vi.spyOn(process, 'exit').mockImplementation(((): never => {
|
|
59
|
+
throw new Error('__exit__');
|
|
60
|
+
}) as never);
|
|
61
|
+
const createApp = vi.fn(
|
|
62
|
+
async (): Promise<FakeApp> => ({
|
|
63
|
+
listen: () => Promise.reject(new Error('EADDRINUSE')),
|
|
64
|
+
close: () => Promise.resolve(),
|
|
65
|
+
}),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
await expect(bootstrapMicroservice('AUTH', createApp, logger)).rejects.toThrow('__exit__');
|
|
69
|
+
expect(exit).toHaveBeenCalledWith(1);
|
|
70
|
+
expect(logger.error).toHaveBeenCalledTimes(1);
|
|
71
|
+
expect(logger.warn).not.toHaveBeenCalled();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('production: fails fast even on a broker transport', async () => {
|
|
75
|
+
process.env['AUTH_TRANSPORT'] = 'redis';
|
|
76
|
+
process.env['NODE_ENV'] = 'production';
|
|
77
|
+
const logger = makeLogger();
|
|
78
|
+
const exit = vi.spyOn(process, 'exit').mockImplementation(((): never => {
|
|
79
|
+
throw new Error('__exit__');
|
|
80
|
+
}) as never);
|
|
81
|
+
const createApp = vi.fn(
|
|
82
|
+
async (): Promise<FakeApp> => ({
|
|
83
|
+
listen: () => Promise.reject(new Error('ECONNREFUSED')),
|
|
84
|
+
close: () => Promise.resolve(),
|
|
85
|
+
}),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
await expect(bootstrapMicroservice('AUTH', createApp, logger)).rejects.toThrow('__exit__');
|
|
89
|
+
expect(exit).toHaveBeenCalledWith(1);
|
|
90
|
+
expect(logger.warn).not.toHaveBeenCalled();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -33,8 +33,12 @@ describe('buildTransport', () => {
|
|
|
33
33
|
process.env.AUTH_REDIS_URL = 'redis://localhost:6379';
|
|
34
34
|
const opts = buildTransport('AUTH');
|
|
35
35
|
expect(opts.transport).toBe(Transport.REDIS);
|
|
36
|
-
const redis = opts.options as { url: string };
|
|
36
|
+
const redis = opts.options as { url: string; retryAttempts: number; retryDelay: number };
|
|
37
37
|
expect(redis.url).toBe('redis://localhost:6379');
|
|
38
|
+
// Resilience: NestJS gives up (and app.listen() rejects) when retryAttempts
|
|
39
|
+
// is unset — an effectively-infinite retry keeps reconnecting instead.
|
|
40
|
+
expect(redis.retryAttempts).toBe(Number.POSITIVE_INFINITY);
|
|
41
|
+
expect(redis.retryDelay).toBeGreaterThan(0);
|
|
38
42
|
});
|
|
39
43
|
|
|
40
44
|
it('selects NATS when ${PREFIX}_TRANSPORT=nats', () => {
|
|
@@ -42,8 +46,16 @@ describe('buildTransport', () => {
|
|
|
42
46
|
process.env.AUTH_NATS_URL = 'nats://localhost:4222,nats://localhost:4223';
|
|
43
47
|
const opts = buildTransport('AUTH');
|
|
44
48
|
expect(opts.transport).toBe(Transport.NATS);
|
|
45
|
-
const nats = opts.options as {
|
|
49
|
+
const nats = opts.options as {
|
|
50
|
+
servers: string[];
|
|
51
|
+
reconnect: boolean;
|
|
52
|
+
maxReconnectAttempts: number;
|
|
53
|
+
};
|
|
46
54
|
expect(nats.servers).toEqual(['nats://localhost:4222', 'nats://localhost:4223']);
|
|
55
|
+
// Resilience: reconnect forever once connected (the initial connect is left
|
|
56
|
+
// to reject so bootstrapMicroservice() can banner + retry).
|
|
57
|
+
expect(nats.reconnect).toBe(true);
|
|
58
|
+
expect(nats.maxReconnectAttempts).toBe(-1);
|
|
47
59
|
});
|
|
48
60
|
|
|
49
61
|
it('throws on unknown transport', () => {
|
|
@@ -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
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FakeAuthStrategy } from '../fakes/fake-auth';
|
|
2
|
-
import { runAuthContract } from '
|
|
2
|
+
import { runAuthContract } from './auth.contract.unit.test';
|
|
3
3
|
|
|
4
4
|
runAuthContract('FakeAuthStrategy', () => new FakeAuthStrategy(), {
|
|
5
5
|
getMagicLinkToken: (strategy, email) =>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { FakeStorageStrategy } from '../fakes/fake-storage';
|
|
2
|
-
import { runStorageContract } from '
|
|
2
|
+
import { runStorageContract } from './storage.contract.unit.test';
|
|
3
3
|
|
|
4
4
|
runStorageContract('FakeStorageStrategy', () => new FakeStorageStrategy());
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './auth';
|
|
2
2
|
export * from './storage';
|
|
3
3
|
export * from './db';
|
|
4
|
-
export * from './contract/auth-contract';
|
|
5
|
-
export * from './contract/storage-contract';
|
|
6
|
-
export * from './contract/db-contract';
|
|
7
4
|
export * from './fakes';
|
|
5
|
+
// NOTE: the strategy contract harness (runAuthContract / runStorageContract /
|
|
6
|
+
// runDBContract) is intentionally NOT exported here — it is test-only code and
|
|
7
|
+
// lives behind the '@icore/shared/testing' entry. See ../testing.ts.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Test-only surface of @icore/shared.
|
|
2
|
+
//
|
|
3
|
+
// The strategy CONTRACT HARNESS lives here, NOT in the production `index.ts`:
|
|
4
|
+
// it uses Vitest globals (describe/it/expect) and must never compile into the
|
|
5
|
+
// shipped library. Import it from test files via '@icore/shared/testing'.
|
|
6
|
+
//
|
|
7
|
+
// The harness implementation sits under `strategies/__tests__/` so the prod
|
|
8
|
+
// build (tsconfig.lib.json excludes `__tests__`) skips it entirely.
|
|
9
|
+
export {
|
|
10
|
+
runAuthContract,
|
|
11
|
+
type AuthContractHelpers,
|
|
12
|
+
} from './strategies/__tests__/auth.contract.unit.test';
|
|
13
|
+
export { runStorageContract } from './strategies/__tests__/storage.contract.unit.test';
|
|
14
|
+
export { runDBContract } from './strategies/__tests__/db.contract.unit.test';
|
|
@@ -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
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"compilerOptions": {
|
|
4
4
|
"outDir": "../../dist/out-tsc",
|
|
5
5
|
"declaration": true,
|
|
6
|
-
"types": ["node"
|
|
6
|
+
"types": ["node"]
|
|
7
7
|
},
|
|
8
8
|
"include": ["src/**/*.ts"],
|
|
9
9
|
"exclude": [
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
"vite.config.mts",
|
|
12
12
|
"vitest.config.ts",
|
|
13
13
|
"vitest.config.mts",
|
|
14
|
+
"src/testing.ts",
|
|
15
|
+
"src/**/__tests__/**",
|
|
14
16
|
"src/**/*.test.ts",
|
|
15
17
|
"src/**/*.spec.ts",
|
|
16
18
|
"src/**/*.test.tsx",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineConfig } from 'vitest/config';
|
|
1
|
+
import { defineConfig, configDefaults } from 'vitest/config';
|
|
2
2
|
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
|
3
3
|
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
|
4
4
|
|
|
@@ -12,6 +12,16 @@ export default defineConfig(() => ({
|
|
|
12
12
|
globals: true,
|
|
13
13
|
environment: 'node',
|
|
14
14
|
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
|
15
|
+
// The strategy contract harness files only EXPORT reusable suites
|
|
16
|
+
// (runAuthContract / runStorageContract / runDBContract) — they hold no
|
|
17
|
+
// top-level tests, so Vitest must not try to run them directly. They follow
|
|
18
|
+
// the *.unit.test.ts naming so the prod build excludes them; the concrete
|
|
19
|
+
// `fake-*.contract.unit.test.ts` files (and the per-provider libs) invoke
|
|
20
|
+
// the harness.
|
|
21
|
+
exclude: [
|
|
22
|
+
...configDefaults.exclude,
|
|
23
|
+
'**/strategies/__tests__/{auth,storage,db}.contract.unit.test.ts',
|
|
24
|
+
],
|
|
15
25
|
reporters: ['default'],
|
|
16
26
|
coverage: {
|
|
17
27
|
reportsDirectory: '../../coverage/libs/shared',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { runStorageContract } from '@icore/shared';
|
|
1
|
+
import { runStorageContract } from '@icore/shared/testing';
|
|
2
2
|
import { FirebaseStorageStrategy } from '../firebase-storage.strategy.js';
|
|
3
3
|
import { createMockFirebaseBucket } from '../testing/mock-firebase-storage.js';
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { runStorageContract } from '@icore/shared';
|
|
1
|
+
import { runStorageContract } from '@icore/shared/testing';
|
|
2
2
|
import { SupabaseStorageStrategy } from '../supabase-storage.strategy';
|
|
3
3
|
import { createMockSupabaseStorageClient } from '../testing/mock-supabase-storage';
|
|
4
4
|
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"paths": {
|
|
15
15
|
"@icore/shared": ["./libs/shared/src/index.ts"],
|
|
16
16
|
"@icore/shared/client": ["./libs/shared/src/client.ts"],
|
|
17
|
+
"@icore/shared/testing": ["./libs/shared/src/testing.ts"],
|
|
17
18
|
"@icore/auth-supabase": ["./libs/auth-strategies/supabase/src/index.ts"],
|
|
18
19
|
"@icore/auth-client": ["./libs/auth-client/src/index.ts"],
|
|
19
20
|
"@icore/package.json": ["./package.json"],
|
|
@@ -29,7 +30,8 @@
|
|
|
29
30
|
"@icore/payment-client": ["./libs/payment-client/src/index.ts"],
|
|
30
31
|
"@icore/notes-client": ["./libs/notes-client/src/index.ts"],
|
|
31
32
|
"@icore/jobs-client": ["./libs/jobs-client/src/index.ts"],
|
|
32
|
-
"@icore/vite-plugins": ["./libs/vite-plugins/src/index.d.mts"]
|
|
33
|
+
"@icore/vite-plugins": ["./libs/vite-plugins/src/index.d.mts"],
|
|
34
|
+
"@icore/firebase-admin": ["./libs/firebase-admin/src/index.ts"]
|
|
33
35
|
}
|
|
34
36
|
},
|
|
35
37
|
"exclude": ["node_modules", "dist", ".nx"]
|
|
File without changes
|
|
File without changes
|