create-forgeon 0.3.16 → 0.3.18
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/package.json +1 -1
- package/src/cli/add-options.test.mjs +5 -2
- package/src/cli/options.test.mjs +1 -0
- package/src/cli/prompt-select.test.mjs +1 -0
- package/src/core/docs.test.mjs +1 -0
- package/src/core/scaffold.test.mjs +1 -0
- package/src/core/validate.test.mjs +1 -0
- package/src/modules/accounts.mjs +416 -0
- package/src/modules/db-prisma.mjs +5 -9
- package/src/modules/dependencies.test.mjs +71 -29
- package/src/modules/executor.mjs +3 -2
- package/src/modules/executor.test.mjs +521 -477
- package/src/modules/files-access.mjs +9 -7
- package/src/modules/files-image.mjs +9 -7
- package/src/modules/files-local.mjs +15 -6
- package/src/modules/files-quotas.mjs +8 -6
- package/src/modules/files-s3.mjs +17 -6
- package/src/modules/files.mjs +21 -21
- package/src/modules/idempotency.test.mjs +13 -7
- package/src/modules/probes.test.mjs +4 -2
- package/src/modules/queue.mjs +9 -6
- package/src/modules/rate-limit.mjs +14 -10
- package/src/modules/rbac.mjs +12 -11
- package/src/modules/registry.mjs +22 -35
- package/src/modules/scheduler.mjs +9 -6
- package/src/modules/shared/files-runtime-wiring.mjs +81 -0
- package/src/modules/shared/patch-utils.mjs +29 -1
- package/src/modules/sync-integrations.mjs +102 -422
- package/src/modules/sync-integrations.test.mjs +32 -111
- package/src/run-add-module.test.mjs +1 -0
- package/templates/base/scripts/forgeon-sync-integrations.mjs +65 -325
- package/templates/module-fragments/{jwt-auth → accounts}/00_title.md +2 -1
- package/templates/module-fragments/{jwt-auth → accounts}/10_overview.md +5 -5
- package/templates/module-fragments/accounts/20_scope.md +29 -0
- package/templates/module-fragments/accounts/90_status_implemented.md +8 -0
- package/templates/module-fragments/accounts/90_status_planned.md +7 -0
- package/templates/module-fragments/rbac/30_what_it_adds.md +3 -2
- package/templates/module-fragments/rbac/40_how_it_works.md +2 -1
- package/templates/module-fragments/rbac/50_how_to_use.md +2 -1
- package/templates/module-fragments/swagger/20_scope.md +2 -1
- package/templates/module-presets/accounts/apps/api/prisma/migrations/0002_accounts_core/migration.sql +97 -0
- package/templates/module-presets/accounts/apps/api/src/accounts/forgeon-accounts-db-prisma.module.ts +17 -0
- package/templates/module-presets/accounts/apps/api/src/accounts/prisma-accounts-persistence.store.ts +332 -0
- package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/package.json +5 -5
- package/templates/module-presets/accounts/packages/accounts-api/src/accounts-email.port.ts +13 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/accounts-persistence.port.ts +67 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/accounts-rbac.port.ts +14 -0
- package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/auth-config.loader.ts +7 -7
- package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/auth-config.service.ts +7 -7
- package/templates/module-presets/accounts/packages/accounts-api/src/auth-core.service.ts +318 -0
- package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/auth-env.schema.ts +4 -4
- package/templates/module-presets/accounts/packages/accounts-api/src/auth-jwt.service.ts +58 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/auth-password.service.ts +21 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/auth.controller.ts +93 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/auth.service.ts +48 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/auth.types.ts +17 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/dto/change-password.dto.ts +13 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/dto/confirm-password-reset.dto.ts +12 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/dto/index.ts +10 -0
- package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/dto/login.dto.ts +1 -1
- package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/dto/refresh.dto.ts +1 -1
- package/templates/module-presets/accounts/packages/accounts-api/src/dto/register.dto.ts +23 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/dto/request-password-reset.dto.ts +7 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/dto/update-user-profile.dto.ts +16 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/dto/update-user-settings.dto.ts +16 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/dto/update-user.dto.ts +8 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/dto/verify-email.dto.ts +8 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/forgeon-accounts.module.ts +82 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/index.ts +24 -0
- package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/jwt.strategy.ts +3 -3
- package/templates/module-presets/accounts/packages/accounts-api/src/owner-access.guard.ts +39 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/users-config.ts +13 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/users.controller.ts +65 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/users.service.ts +87 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/users.types.ts +65 -0
- package/templates/module-presets/{jwt-auth/packages/auth-contracts → accounts/packages/accounts-contracts}/package.json +1 -1
- package/templates/module-presets/accounts/packages/accounts-contracts/src/index.ts +119 -0
- package/templates/module-presets/db-prisma/apps/api/prisma/seed.ts +40 -19
- package/templates/module-presets/files/apps/api/src/files/forgeon-files-db-prisma.module.ts +17 -0
- package/templates/module-presets/files/apps/api/src/files/prisma-files-persistence.store.ts +164 -0
- package/templates/module-presets/files/packages/files/package.json +1 -2
- package/templates/module-presets/files/packages/files/src/files.ports.ts +107 -0
- package/templates/module-presets/files/packages/files/src/files.service.ts +81 -395
- package/templates/module-presets/files/packages/files/src/forgeon-files.module.ts +126 -2
- package/templates/module-presets/files/packages/files/src/index.ts +2 -1
- package/templates/module-presets/files-local/packages/files-local/src/forgeon-files-local-storage.module.ts +18 -0
- package/templates/module-presets/files-local/packages/files-local/src/index.ts +2 -0
- package/templates/module-presets/files-local/packages/files-local/src/local-files-storage.adapter.ts +53 -0
- package/templates/module-presets/files-s3/packages/files-s3/src/forgeon-files-s3-storage.module.ts +18 -0
- package/templates/module-presets/files-s3/packages/files-s3/src/index.ts +2 -0
- package/templates/module-presets/files-s3/packages/files-s3/src/s3-files-storage.adapter.ts +130 -0
- package/src/modules/jwt-auth.mjs +0 -271
- package/templates/module-fragments/jwt-auth/20_scope.md +0 -19
- package/templates/module-fragments/jwt-auth/90_status_implemented.md +0 -8
- package/templates/module-fragments/jwt-auth/90_status_planned.md +0 -3
- package/templates/module-presets/jwt-auth/apps/api/prisma/migrations/0002_auth_refresh_token_hash/migration.sql +0 -3
- package/templates/module-presets/jwt-auth/apps/api/src/auth/prisma-auth-refresh-token.store.ts +0 -36
- package/templates/module-presets/jwt-auth/packages/auth-api/src/auth-refresh-token.store.ts +0 -23
- package/templates/module-presets/jwt-auth/packages/auth-api/src/auth.controller.ts +0 -71
- package/templates/module-presets/jwt-auth/packages/auth-api/src/auth.service.ts +0 -175
- package/templates/module-presets/jwt-auth/packages/auth-api/src/auth.types.ts +0 -6
- package/templates/module-presets/jwt-auth/packages/auth-api/src/dto/index.ts +0 -2
- package/templates/module-presets/jwt-auth/packages/auth-api/src/forgeon-auth.module.ts +0 -47
- package/templates/module-presets/jwt-auth/packages/auth-api/src/index.ts +0 -12
- package/templates/module-presets/jwt-auth/packages/auth-contracts/src/index.ts +0 -47
- /package/templates/module-presets/{jwt-auth/packages/auth-api/src/jwt-auth.guard.ts → accounts/packages/accounts-api/src/access-token.guard.ts} +0 -0
- /package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/auth-config.module.ts +0 -0
- /package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/tsconfig.json +0 -0
- /package/templates/module-presets/{jwt-auth/packages/auth-contracts → accounts/packages/accounts-contracts}/tsconfig.json +0 -0
|
@@ -231,164 +231,244 @@ function assertRbacWiring(projectRoot) {
|
|
|
231
231
|
const readme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
|
|
232
232
|
assert.match(readme, /## RBAC \/ Permissions Module/);
|
|
233
233
|
assert.match(readme, /installs independently/i);
|
|
234
|
-
assert.match(readme, /
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function assertFilesWiring(projectRoot, expectedStorageDriver = 'local') {
|
|
238
|
-
const appModule = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'src', 'app.module.ts'), 'utf8');
|
|
239
|
-
assert.match(appModule, /filesConfig/);
|
|
240
|
-
assert.match(appModule, /filesEnvSchema/);
|
|
241
|
-
assert.match(appModule, /ForgeonFilesModule/);
|
|
242
|
-
|
|
243
|
-
const apiPackage = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'package.json'), 'utf8');
|
|
244
|
-
assert.match(apiPackage, /@forgeon\/files/);
|
|
245
|
-
assert.match(apiPackage, /pnpm --filter @forgeon\/files build/);
|
|
246
|
-
|
|
247
|
-
const apiDockerfile = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'Dockerfile'), 'utf8');
|
|
248
|
-
assert.match(apiDockerfile, /COPY packages\/files\/package\.json packages\/files\/package\.json/);
|
|
249
|
-
assert.match(apiDockerfile, /COPY packages\/files packages\/files/);
|
|
250
|
-
assert.match(apiDockerfile, /RUN pnpm --filter @forgeon\/files build/);
|
|
251
|
-
|
|
252
|
-
const apiEnv = fs.readFileSync(path.join(projectRoot, 'apps', 'api', '.env.example'), 'utf8');
|
|
253
|
-
assert.match(apiEnv, /FILES_ENABLED=true/);
|
|
254
|
-
assert.match(apiEnv, new RegExp(`FILES_STORAGE_DRIVER=${expectedStorageDriver}`));
|
|
255
|
-
assert.match(apiEnv, /FILES_PUBLIC_BASE_PATH=\/files/);
|
|
256
|
-
assert.match(apiEnv, /FILES_MAX_FILE_SIZE_BYTES=10485760/);
|
|
257
|
-
assert.match(apiEnv, /FILES_ALLOWED_MIME_PREFIXES=image\/,application\/pdf,text\//);
|
|
258
|
-
|
|
259
|
-
const healthController = fs.readFileSync(
|
|
260
|
-
path.join(projectRoot, 'apps', 'api', 'src', 'health', 'health.controller.ts'),
|
|
261
|
-
'utf8',
|
|
262
|
-
);
|
|
263
|
-
assert.match(healthController, /@Post\('files'\)/);
|
|
264
|
-
assert.match(healthController, /@Get\('files-variants'\)/);
|
|
265
|
-
assert.match(healthController, /filesService\.createProbeRecord/);
|
|
266
|
-
assert.match(healthController, /filesService\.getVariantsProbeStatus/);
|
|
267
|
-
assert.match(healthController, /filesService\.deleteByPublicId/);
|
|
268
|
-
|
|
269
|
-
const filesController = fs.readFileSync(
|
|
270
|
-
path.join(projectRoot, 'packages', 'files', 'src', 'files.controller.ts'),
|
|
271
|
-
'utf8',
|
|
272
|
-
);
|
|
273
|
-
assert.match(filesController, /@Query\('variant'\) variantQuery\?: string/);
|
|
274
|
-
assert.match(filesController, /parseVariant\(variantQuery\)/);
|
|
275
|
-
assert.match(filesController, /@Delete\(':publicId'\)/);
|
|
276
|
-
|
|
277
|
-
const filesService = fs.readFileSync(
|
|
278
|
-
path.join(projectRoot, 'packages', 'files', 'src', 'files.service.ts'),
|
|
279
|
-
'utf8',
|
|
280
|
-
);
|
|
281
|
-
assert.match(filesService, /getOrCreateBlob/);
|
|
282
|
-
assert.match(filesService, /cleanupReferencedBlobs/);
|
|
283
|
-
assert.match(filesService, /isUniqueConstraintError/);
|
|
284
|
-
assert.match(filesService, /fileBlob\.deleteMany/);
|
|
285
|
-
assert.match(filesService, /variants:\s*\{[\s\S]*?none:\s*\{[\s\S]*?\}/);
|
|
286
|
-
assert.match(filesService, /prisma\.fileBlob/);
|
|
287
|
-
|
|
288
|
-
assertWebProbeShell(projectRoot);
|
|
289
|
-
const probesTs = readWebProbes(projectRoot);
|
|
290
|
-
assert.match(probesTs, /"id": "files"/);
|
|
291
|
-
assert.match(probesTs, /"buttonLabel": "Check files probe \(create metadata\)"/);
|
|
292
|
-
assert.match(probesTs, /"resultTitle": "Files probe response"/);
|
|
293
|
-
assert.match(probesTs, /"id": "files-variants"/);
|
|
294
|
-
assert.match(probesTs, /"buttonLabel": "Check files variants capability"/);
|
|
295
|
-
assert.match(probesTs, /"resultTitle": "Files variants probe response"/);
|
|
296
|
-
|
|
297
|
-
const schema = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'prisma', 'schema.prisma'), 'utf8');
|
|
298
|
-
assert.match(schema, /model FileRecord \{/);
|
|
299
|
-
assert.match(schema, /variants\s+FileVariant\[\]/);
|
|
300
|
-
assert.match(schema, /model FileVariant \{/);
|
|
301
|
-
assert.match(schema, /model FileBlob \{/);
|
|
302
|
-
assert.match(schema, /blobId\s+String/);
|
|
303
|
-
assert.match(schema, /@@unique\(\[hash,\s*size,\s*mimeType,\s*storageDriver\]\)/);
|
|
304
|
-
assert.match(schema, /@@unique\(\[fileId,\s*variantKey\]\)/);
|
|
305
|
-
assert.match(schema, /publicId\s+String\s+@unique/);
|
|
306
|
-
assert.match(schema, /@@index\(\[ownerType,\s*ownerId,\s*createdAt\]\)/);
|
|
307
|
-
|
|
308
|
-
const migration = path.join(
|
|
309
|
-
projectRoot,
|
|
310
|
-
'apps',
|
|
311
|
-
'api',
|
|
312
|
-
'prisma',
|
|
313
|
-
'migrations',
|
|
314
|
-
'20260306_files_file_record',
|
|
315
|
-
'migration.sql',
|
|
316
|
-
);
|
|
317
|
-
assert.equal(fs.existsSync(migration), true);
|
|
318
|
-
|
|
319
|
-
const variantMigration = path.join(
|
|
320
|
-
projectRoot,
|
|
321
|
-
'apps',
|
|
322
|
-
'api',
|
|
323
|
-
'prisma',
|
|
324
|
-
'migrations',
|
|
325
|
-
'20260306_files_file_variant',
|
|
326
|
-
'migration.sql',
|
|
327
|
-
);
|
|
328
|
-
assert.equal(fs.existsSync(variantMigration), true);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function assertFilesLocalWiring(projectRoot) {
|
|
332
|
-
const appModule = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'src', 'app.module.ts'), 'utf8');
|
|
333
|
-
assert.match(appModule, /filesLocalConfig/);
|
|
334
|
-
assert.match(appModule, /filesLocalEnvSchemaZod/);
|
|
335
|
-
assert.match(appModule, /FilesLocalConfigModule/);
|
|
336
|
-
|
|
337
|
-
const apiPackage = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'package.json'), 'utf8');
|
|
338
|
-
assert.match(apiPackage, /@forgeon\/files-local/);
|
|
339
|
-
assert.match(apiPackage, /pnpm --filter @forgeon\/files-local build/);
|
|
340
|
-
|
|
341
|
-
const apiDockerfile = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'Dockerfile'), 'utf8');
|
|
342
|
-
assert.match(apiDockerfile, /COPY packages\/files-local\/package\.json packages\/files-local\/package\.json/);
|
|
343
|
-
assert.match(apiDockerfile, /COPY packages\/files-local packages\/files-local/);
|
|
344
|
-
assert.match(apiDockerfile, /RUN pnpm --filter @forgeon\/files-local build/);
|
|
345
|
-
|
|
346
|
-
const apiEnv = fs.readFileSync(path.join(projectRoot, 'apps', 'api', '.env.example'), 'utf8');
|
|
347
|
-
assert.match(apiEnv, /FILES_LOCAL_ROOT=storage\/uploads/);
|
|
348
|
-
|
|
349
|
-
const gitignore = fs.readFileSync(path.join(projectRoot, '.gitignore'), 'utf8');
|
|
350
|
-
assert.match(gitignore, /storage\//);
|
|
351
|
-
|
|
352
|
-
const compose = fs.readFileSync(path.join(projectRoot, 'infra', 'docker', 'compose.yml'), 'utf8');
|
|
353
|
-
assert.match(compose, /files_data:\/app\/storage/);
|
|
354
|
-
assert.match(compose, /^\s{2}files_data:\s*$/m);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
function assertFilesS3Wiring(projectRoot) {
|
|
358
|
-
const appModule = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'src', 'app.module.ts'), 'utf8');
|
|
359
|
-
assert.match(appModule, /filesS3Config/);
|
|
360
|
-
assert.match(appModule, /filesS3EnvSchemaZod/);
|
|
361
|
-
assert.match(appModule, /FilesS3ConfigModule/);
|
|
362
|
-
|
|
363
|
-
const apiPackage = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'package.json'), 'utf8');
|
|
364
|
-
assert.match(apiPackage, /@forgeon\/files-s3/);
|
|
365
|
-
assert.match(apiPackage, /pnpm --filter @forgeon\/files-s3 build/);
|
|
366
|
-
|
|
367
|
-
const apiDockerfile = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'Dockerfile'), 'utf8');
|
|
368
|
-
assert.match(apiDockerfile, /COPY packages\/files-s3\/package\.json packages\/files-s3\/package\.json/);
|
|
369
|
-
assert.match(apiDockerfile, /COPY packages\/files-s3 packages\/files-s3/);
|
|
370
|
-
assert.match(apiDockerfile, /RUN pnpm --filter @forgeon\/files-s3 build/);
|
|
371
|
-
|
|
372
|
-
const apiEnv = fs.readFileSync(path.join(projectRoot, 'apps', 'api', '.env.example'), 'utf8');
|
|
373
|
-
assert.match(apiEnv, /FILES_STORAGE_DRIVER=s3/);
|
|
374
|
-
assert.match(apiEnv, /FILES_S3_PROVIDER_PRESET=minio/);
|
|
375
|
-
assert.match(apiEnv, /FILES_S3_BUCKET=forgeon-files/);
|
|
376
|
-
assert.match(apiEnv, /FILES_S3_REGION=/);
|
|
377
|
-
assert.match(apiEnv, /FILES_S3_ENDPOINT=/);
|
|
378
|
-
assert.match(apiEnv, /FILES_S3_FORCE_PATH_STYLE=/);
|
|
379
|
-
assert.match(apiEnv, /FILES_S3_MAX_ATTEMPTS=3/);
|
|
380
|
-
|
|
381
|
-
const compose = fs.readFileSync(path.join(projectRoot, 'infra', 'docker', 'compose.yml'), 'utf8');
|
|
382
|
-
assert.match(compose, /FILES_S3_PROVIDER_PRESET: \$\{FILES_S3_PROVIDER_PRESET\}/);
|
|
383
|
-
assert.match(compose, /FILES_S3_MAX_ATTEMPTS: \$\{FILES_S3_MAX_ATTEMPTS\}/);
|
|
384
|
-
|
|
385
|
-
const filesS3Package = fs.readFileSync(
|
|
386
|
-
path.join(projectRoot, 'packages', 'files-s3', 'package.json'),
|
|
387
|
-
'utf8',
|
|
388
|
-
);
|
|
389
|
-
assert.match(filesS3Package, /@aws-sdk\/client-s3/);
|
|
234
|
+
assert.match(readme, /accounts.*optional/i);
|
|
390
235
|
}
|
|
391
236
|
|
|
237
|
+
function assertFilesWiring(projectRoot, expectedStorageDriver = 'local') {
|
|
238
|
+
const appModule = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'src', 'app.module.ts'), 'utf8');
|
|
239
|
+
assert.match(appModule, /filesConfig/);
|
|
240
|
+
assert.match(appModule, /filesEnvSchema/);
|
|
241
|
+
assert.match(appModule, /ForgeonFilesModule\.register\(\{/);
|
|
242
|
+
assert.match(appModule, /ForgeonFilesDbPrismaModule/);
|
|
243
|
+
if (expectedStorageDriver === 's3') {
|
|
244
|
+
assert.match(appModule, /ForgeonFilesS3StorageModule/);
|
|
245
|
+
assert.doesNotMatch(appModule, /imports: \[ForgeonFilesDbPrismaModule, ForgeonFilesLocalStorageModule\]/);
|
|
246
|
+
} else {
|
|
247
|
+
assert.match(appModule, /ForgeonFilesLocalStorageModule/);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const apiPackage = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'package.json'), 'utf8');
|
|
251
|
+
assert.match(apiPackage, /@forgeon\/files/);
|
|
252
|
+
assert.match(apiPackage, /pnpm --filter @forgeon\/files build/);
|
|
253
|
+
|
|
254
|
+
const apiDockerfile = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'Dockerfile'), 'utf8');
|
|
255
|
+
assert.match(apiDockerfile, /COPY packages\/files\/package\.json packages\/files\/package\.json/);
|
|
256
|
+
assert.match(apiDockerfile, /COPY packages\/files packages\/files/);
|
|
257
|
+
assert.match(apiDockerfile, /RUN pnpm --filter @forgeon\/files build/);
|
|
258
|
+
|
|
259
|
+
const apiEnv = fs.readFileSync(path.join(projectRoot, 'apps', 'api', '.env.example'), 'utf8');
|
|
260
|
+
assert.match(apiEnv, /FILES_ENABLED=true/);
|
|
261
|
+
assert.match(apiEnv, new RegExp('FILES_STORAGE_DRIVER=' + expectedStorageDriver));
|
|
262
|
+
assert.match(apiEnv, /FILES_PUBLIC_BASE_PATH=\/files/);
|
|
263
|
+
assert.match(apiEnv, /FILES_MAX_FILE_SIZE_BYTES=10485760/);
|
|
264
|
+
assert.match(apiEnv, /FILES_ALLOWED_MIME_PREFIXES=image\/,application\/pdf,text\//);
|
|
265
|
+
|
|
266
|
+
const healthController = fs.readFileSync(
|
|
267
|
+
path.join(projectRoot, 'apps', 'api', 'src', 'health', 'health.controller.ts'),
|
|
268
|
+
'utf8',
|
|
269
|
+
);
|
|
270
|
+
assert.match(healthController, /@Post\('files'\)/);
|
|
271
|
+
assert.match(healthController, /@Get\('files-variants'\)/);
|
|
272
|
+
assert.match(healthController, /filesService\.createProbeRecord/);
|
|
273
|
+
assert.match(healthController, /filesService\.getVariantsProbeStatus/);
|
|
274
|
+
assert.match(healthController, /filesService\.deleteByPublicId/);
|
|
275
|
+
|
|
276
|
+
const filesController = fs.readFileSync(
|
|
277
|
+
path.join(projectRoot, 'packages', 'files', 'src', 'files.controller.ts'),
|
|
278
|
+
'utf8',
|
|
279
|
+
);
|
|
280
|
+
assert.match(filesController, /@Query\('variant'\) variantQuery\?: string/);
|
|
281
|
+
assert.match(filesController, /parseVariant\(variantQuery\)/);
|
|
282
|
+
assert.match(filesController, /@Delete\(':publicId'\)/);
|
|
283
|
+
|
|
284
|
+
const filesService = fs.readFileSync(
|
|
285
|
+
path.join(projectRoot, 'packages', 'files', 'src', 'files.service.ts'),
|
|
286
|
+
'utf8',
|
|
287
|
+
);
|
|
288
|
+
assert.match(filesService, /FILES_PERSISTENCE_PORT/);
|
|
289
|
+
assert.match(filesService, /FILES_STORAGE_ADAPTER/);
|
|
290
|
+
assert.match(filesService, /getOrCreateBlob/);
|
|
291
|
+
assert.match(filesService, /cleanupReferencedBlobs/);
|
|
292
|
+
assert.match(filesService, /isUniqueConstraintError/);
|
|
293
|
+
assert.match(filesService, /storageAdapter\.put/);
|
|
294
|
+
assert.match(filesService, /persistence\.createBlob/);
|
|
295
|
+
assert.match(filesService, /persistence\.deleteBlobIfUnreferenced/);
|
|
296
|
+
assert.doesNotMatch(filesService, /PrismaService/);
|
|
297
|
+
assert.doesNotMatch(filesService, /@aws-sdk\/client-s3/);
|
|
298
|
+
|
|
299
|
+
const filesPorts = fs.readFileSync(
|
|
300
|
+
path.join(projectRoot, 'packages', 'files', 'src', 'files.ports.ts'),
|
|
301
|
+
'utf8',
|
|
302
|
+
);
|
|
303
|
+
assert.match(filesPorts, /FILES_PERSISTENCE_PORT/);
|
|
304
|
+
assert.match(filesPorts, /FILES_STORAGE_ADAPTER/);
|
|
305
|
+
assert.match(filesPorts, /interface FilesPersistencePort/);
|
|
306
|
+
assert.match(filesPorts, /interface FilesStorageAdapter/);
|
|
307
|
+
|
|
308
|
+
const filesModule = fs.readFileSync(
|
|
309
|
+
path.join(projectRoot, 'packages', 'files', 'src', 'forgeon-files.module.ts'),
|
|
310
|
+
'utf8',
|
|
311
|
+
);
|
|
312
|
+
assert.match(filesModule, /ForgeonFilesModuleOptions/);
|
|
313
|
+
assert.match(filesModule, /static register\(options: ForgeonFilesModuleOptions = \{\}\)/);
|
|
314
|
+
assert.match(filesModule, /FILES_PERSISTENCE_PORT/);
|
|
315
|
+
assert.match(filesModule, /FILES_STORAGE_ADAPTER/);
|
|
316
|
+
|
|
317
|
+
const filesPackage = fs.readFileSync(path.join(projectRoot, 'packages', 'files', 'package.json'), 'utf8');
|
|
318
|
+
assert.doesNotMatch(filesPackage, /@forgeon\/db-prisma/);
|
|
319
|
+
|
|
320
|
+
const prismaFilesStore = fs.readFileSync(
|
|
321
|
+
path.join(projectRoot, 'apps', 'api', 'src', 'files', 'prisma-files-persistence.store.ts'),
|
|
322
|
+
'utf8',
|
|
323
|
+
);
|
|
324
|
+
assert.match(prismaFilesStore, /PrismaService/);
|
|
325
|
+
assert.match(prismaFilesStore, /FILES_PERSISTENCE_PORT/);
|
|
326
|
+
assert.match(prismaFilesStore, /fileBlob\.deleteMany/);
|
|
327
|
+
|
|
328
|
+
const prismaFilesModule = fs.readFileSync(
|
|
329
|
+
path.join(projectRoot, 'apps', 'api', 'src', 'files', 'forgeon-files-db-prisma.module.ts'),
|
|
330
|
+
'utf8',
|
|
331
|
+
);
|
|
332
|
+
assert.match(prismaFilesModule, /ForgeonFilesDbPrismaModule/);
|
|
333
|
+
assert.match(prismaFilesModule, /DbPrismaModule/);
|
|
334
|
+
assert.match(prismaFilesModule, /FILES_PERSISTENCE_PORT/);
|
|
335
|
+
|
|
336
|
+
assertWebProbeShell(projectRoot);
|
|
337
|
+
const probesTs = readWebProbes(projectRoot);
|
|
338
|
+
assert.match(probesTs, /"id": "files"/);
|
|
339
|
+
assert.match(probesTs, /"buttonLabel": "Check files probe \(create metadata\)"/);
|
|
340
|
+
assert.match(probesTs, /"resultTitle": "Files probe response"/);
|
|
341
|
+
assert.match(probesTs, /"id": "files-variants"/);
|
|
342
|
+
assert.match(probesTs, /"buttonLabel": "Check files variants capability"/);
|
|
343
|
+
assert.match(probesTs, /"resultTitle": "Files variants probe response"/);
|
|
344
|
+
|
|
345
|
+
const schema = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'prisma', 'schema.prisma'), 'utf8');
|
|
346
|
+
assert.match(schema, /model FileRecord \{/);
|
|
347
|
+
assert.match(schema, /variants\s+FileVariant\[\]/);
|
|
348
|
+
assert.match(schema, /model FileVariant \{/);
|
|
349
|
+
assert.match(schema, /model FileBlob \{/);
|
|
350
|
+
assert.match(schema, /blobId\s+String/);
|
|
351
|
+
assert.match(schema, /@@unique\(\[hash,\s*size,\s*mimeType,\s*storageDriver\]\)/);
|
|
352
|
+
assert.match(schema, /@@unique\(\[fileId,\s*variantKey\]\)/);
|
|
353
|
+
assert.match(schema, /publicId\s+String\s+@unique/);
|
|
354
|
+
assert.match(schema, /@@index\(\[ownerType,\s*ownerId,\s*createdAt\]\)/);
|
|
355
|
+
|
|
356
|
+
const migration = path.join(
|
|
357
|
+
projectRoot,
|
|
358
|
+
'apps',
|
|
359
|
+
'api',
|
|
360
|
+
'prisma',
|
|
361
|
+
'migrations',
|
|
362
|
+
'20260306_files_file_record',
|
|
363
|
+
'migration.sql',
|
|
364
|
+
);
|
|
365
|
+
assert.equal(fs.existsSync(migration), true);
|
|
366
|
+
|
|
367
|
+
const variantMigration = path.join(
|
|
368
|
+
projectRoot,
|
|
369
|
+
'apps',
|
|
370
|
+
'api',
|
|
371
|
+
'prisma',
|
|
372
|
+
'migrations',
|
|
373
|
+
'20260306_files_file_variant',
|
|
374
|
+
'migration.sql',
|
|
375
|
+
);
|
|
376
|
+
assert.equal(fs.existsSync(variantMigration), true);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function assertFilesLocalWiring(projectRoot) {
|
|
380
|
+
const appModule = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'src', 'app.module.ts'), 'utf8');
|
|
381
|
+
assert.match(appModule, /filesLocalConfig/);
|
|
382
|
+
assert.match(appModule, /filesLocalEnvSchemaZod/);
|
|
383
|
+
assert.match(appModule, /FilesLocalConfigModule/);
|
|
384
|
+
assert.match(appModule, /ForgeonFilesLocalStorageModule/);
|
|
385
|
+
|
|
386
|
+
const apiPackage = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'package.json'), 'utf8');
|
|
387
|
+
assert.match(apiPackage, /@forgeon\/files-local/);
|
|
388
|
+
assert.match(apiPackage, /pnpm --filter @forgeon\/files-local build/);
|
|
389
|
+
|
|
390
|
+
const apiDockerfile = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'Dockerfile'), 'utf8');
|
|
391
|
+
assert.match(apiDockerfile, /COPY packages\/files-local\/package\.json packages\/files-local\/package\.json/);
|
|
392
|
+
assert.match(apiDockerfile, /COPY packages\/files-local packages\/files-local/);
|
|
393
|
+
assert.match(apiDockerfile, /RUN pnpm --filter @forgeon\/files-local build/);
|
|
394
|
+
|
|
395
|
+
const apiEnv = fs.readFileSync(path.join(projectRoot, 'apps', 'api', '.env.example'), 'utf8');
|
|
396
|
+
assert.match(apiEnv, /FILES_LOCAL_ROOT=storage\/uploads/);
|
|
397
|
+
|
|
398
|
+
const localModule = fs.readFileSync(
|
|
399
|
+
path.join(projectRoot, 'packages', 'files-local', 'src', 'forgeon-files-local-storage.module.ts'),
|
|
400
|
+
'utf8',
|
|
401
|
+
);
|
|
402
|
+
assert.match(localModule, /ForgeonFilesLocalStorageModule/);
|
|
403
|
+
assert.match(localModule, /FORGEON_FILES_STORAGE_ADAPTER/);
|
|
404
|
+
|
|
405
|
+
const localAdapter = fs.readFileSync(
|
|
406
|
+
path.join(projectRoot, 'packages', 'files-local', 'src', 'local-files-storage.adapter.ts'),
|
|
407
|
+
'utf8',
|
|
408
|
+
);
|
|
409
|
+
assert.match(localAdapter, /readonly driver = 'local'/);
|
|
410
|
+
assert.match(localAdapter, /createReadStream/);
|
|
411
|
+
assert.match(localAdapter, /writeFile/);
|
|
412
|
+
|
|
413
|
+
const gitignore = fs.readFileSync(path.join(projectRoot, '.gitignore'), 'utf8');
|
|
414
|
+
assert.match(gitignore, /storage\//);
|
|
415
|
+
|
|
416
|
+
const compose = fs.readFileSync(path.join(projectRoot, 'infra', 'docker', 'compose.yml'), 'utf8');
|
|
417
|
+
assert.match(compose, /files_data:\/app\/storage/);
|
|
418
|
+
assert.match(compose, /^\s{2}files_data:\s*$/m);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function assertFilesS3Wiring(projectRoot) {
|
|
422
|
+
const appModule = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'src', 'app.module.ts'), 'utf8');
|
|
423
|
+
assert.match(appModule, /filesS3Config/);
|
|
424
|
+
assert.match(appModule, /filesS3EnvSchemaZod/);
|
|
425
|
+
assert.match(appModule, /FilesS3ConfigModule/);
|
|
426
|
+
assert.match(appModule, /ForgeonFilesS3StorageModule/);
|
|
427
|
+
|
|
428
|
+
const apiPackage = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'package.json'), 'utf8');
|
|
429
|
+
assert.match(apiPackage, /@forgeon\/files-s3/);
|
|
430
|
+
assert.match(apiPackage, /pnpm --filter @forgeon\/files-s3 build/);
|
|
431
|
+
|
|
432
|
+
const apiDockerfile = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'Dockerfile'), 'utf8');
|
|
433
|
+
assert.match(apiDockerfile, /COPY packages\/files-s3\/package\.json packages\/files-s3\/package\.json/);
|
|
434
|
+
assert.match(apiDockerfile, /COPY packages\/files-s3 packages\/files-s3/);
|
|
435
|
+
assert.match(apiDockerfile, /RUN pnpm --filter @forgeon\/files-s3 build/);
|
|
436
|
+
|
|
437
|
+
const apiEnv = fs.readFileSync(path.join(projectRoot, 'apps', 'api', '.env.example'), 'utf8');
|
|
438
|
+
assert.match(apiEnv, /FILES_STORAGE_DRIVER=s3/);
|
|
439
|
+
assert.match(apiEnv, /FILES_S3_PROVIDER_PRESET=minio/);
|
|
440
|
+
assert.match(apiEnv, /FILES_S3_BUCKET=forgeon-files/);
|
|
441
|
+
assert.match(apiEnv, /FILES_S3_REGION=/);
|
|
442
|
+
assert.match(apiEnv, /FILES_S3_ENDPOINT=/);
|
|
443
|
+
assert.match(apiEnv, /FILES_S3_FORCE_PATH_STYLE=/);
|
|
444
|
+
assert.match(apiEnv, /FILES_S3_MAX_ATTEMPTS=3/);
|
|
445
|
+
|
|
446
|
+
const compose = fs.readFileSync(path.join(projectRoot, 'infra', 'docker', 'compose.yml'), 'utf8');
|
|
447
|
+
assert.match(compose, /FILES_S3_PROVIDER_PRESET: \$\{FILES_S3_PROVIDER_PRESET\}/);
|
|
448
|
+
assert.match(compose, /FILES_S3_MAX_ATTEMPTS: \$\{FILES_S3_MAX_ATTEMPTS\}/);
|
|
449
|
+
|
|
450
|
+
const filesS3Package = fs.readFileSync(
|
|
451
|
+
path.join(projectRoot, 'packages', 'files-s3', 'package.json'),
|
|
452
|
+
'utf8',
|
|
453
|
+
);
|
|
454
|
+
assert.match(filesS3Package, /@aws-sdk\/client-s3/);
|
|
455
|
+
|
|
456
|
+
const s3Module = fs.readFileSync(
|
|
457
|
+
path.join(projectRoot, 'packages', 'files-s3', 'src', 'forgeon-files-s3-storage.module.ts'),
|
|
458
|
+
'utf8',
|
|
459
|
+
);
|
|
460
|
+
assert.match(s3Module, /ForgeonFilesS3StorageModule/);
|
|
461
|
+
assert.match(s3Module, /FORGEON_FILES_STORAGE_ADAPTER/);
|
|
462
|
+
|
|
463
|
+
const s3Adapter = fs.readFileSync(
|
|
464
|
+
path.join(projectRoot, 'packages', 'files-s3', 'src', 's3-files-storage.adapter.ts'),
|
|
465
|
+
'utf8',
|
|
466
|
+
);
|
|
467
|
+
assert.match(s3Adapter, /readonly driver = 's3'/);
|
|
468
|
+
assert.match(s3Adapter, /@aws-sdk\/client-s3/);
|
|
469
|
+
assert.match(s3Adapter, /loadS3Module/);
|
|
470
|
+
}
|
|
471
|
+
|
|
392
472
|
function assertFilesAccessWiring(projectRoot) {
|
|
393
473
|
const appModule = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'src', 'app.module.ts'), 'utf8');
|
|
394
474
|
assert.match(appModule, /ForgeonFilesAccessModule/);
|
|
@@ -626,70 +706,80 @@ function assertFilesImageWiring(projectRoot) {
|
|
|
626
706
|
assert.match(readme, /metadata is stripped before storage/i);
|
|
627
707
|
}
|
|
628
708
|
|
|
629
|
-
function
|
|
630
|
-
const apiPackage = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'package.json'), 'utf8');
|
|
631
|
-
assert.match(apiPackage, /@forgeon\/
|
|
632
|
-
assert.match(apiPackage, /@forgeon\/
|
|
633
|
-
assert.match(apiPackage, /pnpm --filter @forgeon\/
|
|
634
|
-
assert.match(apiPackage, /pnpm --filter @forgeon\/
|
|
635
|
-
|
|
636
|
-
const appModule = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'src', 'app.module.ts'), 'utf8');
|
|
637
|
-
assert.match(appModule, /authConfig/);
|
|
638
|
-
assert.match(appModule, /authEnvSchema/);
|
|
639
|
-
assert.match(appModule, /
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
);
|
|
651
|
-
assert.
|
|
652
|
-
assert.
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
assert.match(probesTs, /"
|
|
658
|
-
assert.match(probesTs, /"
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
);
|
|
666
|
-
assert.match(apiDockerfile, /COPY packages\/
|
|
667
|
-
assert.match(apiDockerfile, /COPY packages\/
|
|
668
|
-
assert.match(apiDockerfile, /
|
|
669
|
-
assert.match(apiDockerfile, /RUN pnpm --filter @forgeon\/
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
assert.match(apiEnv, /
|
|
674
|
-
assert.match(apiEnv, /
|
|
675
|
-
assert.match(apiEnv, /
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
assert.match(compose, /
|
|
680
|
-
assert.match(compose, /
|
|
681
|
-
|
|
682
|
-
const readme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
|
|
683
|
-
assert.match(readme, /##
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
}
|
|
692
|
-
|
|
709
|
+
function assertAccountsWiring(projectRoot) {
|
|
710
|
+
const apiPackage = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'package.json'), 'utf8');
|
|
711
|
+
assert.match(apiPackage, /@forgeon\/accounts-api/);
|
|
712
|
+
assert.match(apiPackage, /@forgeon\/accounts-contracts/);
|
|
713
|
+
assert.match(apiPackage, /pnpm --filter @forgeon\/accounts-contracts build/);
|
|
714
|
+
assert.match(apiPackage, /pnpm --filter @forgeon\/accounts-api build/);
|
|
715
|
+
|
|
716
|
+
const appModule = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'src', 'app.module.ts'), 'utf8');
|
|
717
|
+
assert.match(appModule, /authConfig/);
|
|
718
|
+
assert.match(appModule, /authEnvSchema/);
|
|
719
|
+
assert.match(appModule, /ForgeonAccountsDbPrismaModule/);
|
|
720
|
+
assert.match(appModule, /ForgeonAccountsModule\.register\(\{/);
|
|
721
|
+
assert.match(appModule, /UsersModule\.register\(\{\}\)/);
|
|
722
|
+
assert.doesNotMatch(appModule, /AUTH_REFRESH_TOKEN_STORE/);
|
|
723
|
+
|
|
724
|
+
const healthController = fs.readFileSync(
|
|
725
|
+
path.join(projectRoot, 'apps', 'api', 'src', 'health', 'health.controller.ts'),
|
|
726
|
+
'utf8',
|
|
727
|
+
);
|
|
728
|
+
assert.match(healthController, /@Get\('auth'\)/);
|
|
729
|
+
assert.match(healthController, /authService\.getProbeStatus/);
|
|
730
|
+
assert.match(healthController, /\$queryRaw/);
|
|
731
|
+
assert.doesNotMatch(healthController, /data:\s*\{\s*email\s*\}/);
|
|
732
|
+
assert.doesNotMatch(healthController, /,\s*,/);
|
|
733
|
+
|
|
734
|
+
assertWebProbeShell(projectRoot);
|
|
735
|
+
const probesTs = readWebProbes(projectRoot);
|
|
736
|
+
assert.match(probesTs, /"id": "auth"/);
|
|
737
|
+
assert.match(probesTs, /"buttonLabel": "Check accounts probe"/);
|
|
738
|
+
assert.match(probesTs, /"resultTitle": "Accounts probe response"/);
|
|
739
|
+
|
|
740
|
+
const apiDockerfile = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'Dockerfile'), 'utf8');
|
|
741
|
+
assert.match(
|
|
742
|
+
apiDockerfile,
|
|
743
|
+
/COPY packages\/accounts-contracts\/package\.json packages\/accounts-contracts\/package\.json/,
|
|
744
|
+
);
|
|
745
|
+
assert.match(apiDockerfile, /COPY packages\/accounts-api\/package\.json packages\/accounts-api\/package\.json/);
|
|
746
|
+
assert.match(apiDockerfile, /COPY packages\/accounts-contracts packages\/accounts-contracts/);
|
|
747
|
+
assert.match(apiDockerfile, /COPY packages\/accounts-api packages\/accounts-api/);
|
|
748
|
+
assert.match(apiDockerfile, /RUN pnpm --filter @forgeon\/accounts-contracts build/);
|
|
749
|
+
assert.match(apiDockerfile, /RUN pnpm --filter @forgeon\/accounts-api build/);
|
|
750
|
+
|
|
751
|
+
const apiEnv = fs.readFileSync(path.join(projectRoot, 'apps', 'api', '.env.example'), 'utf8');
|
|
752
|
+
assert.match(apiEnv, /JWT_ACCESS_SECRET=/);
|
|
753
|
+
assert.match(apiEnv, /JWT_REFRESH_SECRET=/);
|
|
754
|
+
assert.match(apiEnv, /AUTH_ARGON2_MEMORY_COST=/);
|
|
755
|
+
assert.match(apiEnv, /AUTH_ARGON2_PARALLELISM=/);
|
|
756
|
+
|
|
757
|
+
const compose = fs.readFileSync(path.join(projectRoot, 'infra', 'docker', 'compose.yml'), 'utf8');
|
|
758
|
+
assert.match(compose, /JWT_ACCESS_SECRET: \$\{JWT_ACCESS_SECRET\}/);
|
|
759
|
+
assert.match(compose, /JWT_REFRESH_SECRET: \$\{JWT_REFRESH_SECRET\}/);
|
|
760
|
+
assert.match(compose, /AUTH_ARGON2_MEMORY_COST: \$\{AUTH_ARGON2_MEMORY_COST\}/);
|
|
761
|
+
|
|
762
|
+
const readme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
|
|
763
|
+
assert.match(readme, /## Accounts Module/);
|
|
764
|
+
assert.match(readme, /owner-scoped user routes/);
|
|
765
|
+
assert.match(readme, /AccountsEmailPort/);
|
|
766
|
+
|
|
767
|
+
const authServiceSource = fs.readFileSync(
|
|
768
|
+
path.join(projectRoot, 'packages', 'accounts-api', 'src', 'auth.service.ts'),
|
|
769
|
+
'utf8',
|
|
770
|
+
);
|
|
771
|
+
assert.match(authServiceSource, /import type \{ RegisterRequest \} from '@forgeon\/accounts-contracts';/);
|
|
772
|
+
|
|
773
|
+
const prismaStorePath = path.join(
|
|
774
|
+
projectRoot,
|
|
775
|
+
'apps',
|
|
776
|
+
'api',
|
|
777
|
+
'src',
|
|
778
|
+
'accounts',
|
|
779
|
+
'prisma-accounts-persistence.store.ts',
|
|
780
|
+
);
|
|
781
|
+
assert.equal(fs.existsSync(prismaStorePath), true);
|
|
782
|
+
}
|
|
693
783
|
function stripDbPrismaArtifacts(projectRoot) {
|
|
694
784
|
const dbPackageDir = path.join(projectRoot, 'packages', 'db-prisma');
|
|
695
785
|
if (fs.existsSync(dbPackageDir)) {
|
|
@@ -1452,17 +1542,21 @@ describe('addModule', () => {
|
|
|
1452
1542
|
packageRoot,
|
|
1453
1543
|
});
|
|
1454
1544
|
|
|
1455
|
-
const apiEnv = fs.readFileSync(path.join(projectRoot, 'apps', 'api', '.env.example'), 'utf8');
|
|
1456
|
-
assert.match(apiEnv, /FILES_STORAGE_DRIVER=s3/);
|
|
1457
|
-
|
|
1458
|
-
const
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1545
|
+
const apiEnv = fs.readFileSync(path.join(projectRoot, 'apps', 'api', '.env.example'), 'utf8');
|
|
1546
|
+
assert.match(apiEnv, /FILES_STORAGE_DRIVER=s3/);
|
|
1547
|
+
|
|
1548
|
+
const appModule = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'src', 'app.module.ts'), 'utf8');
|
|
1549
|
+
assert.match(appModule, /ForgeonFilesS3StorageModule/);
|
|
1550
|
+
assert.doesNotMatch(appModule, /imports: \[ForgeonFilesDbPrismaModule, ForgeonFilesLocalStorageModule\]/);
|
|
1551
|
+
|
|
1552
|
+
const filesService = fs.readFileSync(
|
|
1553
|
+
path.join(projectRoot, 'packages', 'files', 'src', 'files.service.ts'),
|
|
1554
|
+
'utf8',
|
|
1555
|
+
);
|
|
1556
|
+
assert.doesNotMatch(filesService, /storeS3/);
|
|
1557
|
+
assert.doesNotMatch(filesService, /openS3/);
|
|
1558
|
+
assert.doesNotMatch(filesService, /deleteS3/);
|
|
1559
|
+
assert.doesNotMatch(filesService, /@aws-sdk\/client-s3/);
|
|
1466
1560
|
} finally {
|
|
1467
1561
|
fs.rmSync(targetRoot, { recursive: true, force: true });
|
|
1468
1562
|
}
|
|
@@ -2072,239 +2166,179 @@ describe('addModule', () => {
|
|
|
2072
2166
|
}
|
|
2073
2167
|
});
|
|
2074
2168
|
|
|
2075
|
-
it('applies
|
|
2076
|
-
const targetRoot = mkTmp('forgeon-module-
|
|
2077
|
-
const projectRoot = path.join(targetRoot, 'demo-
|
|
2078
|
-
const templateRoot = path.join(packageRoot, 'templates', 'base');
|
|
2079
|
-
|
|
2080
|
-
try {
|
|
2081
|
-
scaffoldProject({
|
|
2082
|
-
templateRoot,
|
|
2083
|
-
packageRoot,
|
|
2084
|
-
targetRoot: projectRoot,
|
|
2085
|
-
projectName: 'demo-
|
|
2086
|
-
frontend: 'react',
|
|
2087
|
-
db: 'prisma',
|
|
2088
|
-
dbPrismaEnabled: true,
|
|
2089
|
-
i18nEnabled: true,
|
|
2090
|
-
proxy: 'caddy',
|
|
2091
|
-
});
|
|
2092
|
-
|
|
2093
|
-
const result = addModule({
|
|
2094
|
-
moduleId: '
|
|
2095
|
-
targetRoot: projectRoot,
|
|
2096
|
-
packageRoot,
|
|
2097
|
-
});
|
|
2098
|
-
|
|
2099
|
-
assert.equal(result.applied, true);
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
const
|
|
2103
|
-
|
|
2104
|
-
assert.
|
|
2105
|
-
assert.
|
|
2106
|
-
assert.
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
'
|
|
2114
|
-
'
|
|
2115
|
-
'
|
|
2116
|
-
'
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
);
|
|
2132
|
-
assert.
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
targetRoot: projectRoot,
|
|
2171
|
-
|
|
2172
|
-
});
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
);
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
assert.
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
const
|
|
2236
|
-
|
|
2237
|
-
'
|
|
2238
|
-
);
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
);
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
authService,
|
|
2249
|
-
/permissions: Array\.isArray\(payload\.permissions\) \? payload\.permissions : \[\],/,
|
|
2250
|
-
);
|
|
2251
|
-
|
|
2252
|
-
const authController = fs.readFileSync(
|
|
2253
|
-
path.join(projectRoot, 'packages', 'auth-api', 'src', 'auth.controller.ts'),
|
|
2254
|
-
'utf8',
|
|
2255
|
-
);
|
|
2256
|
-
assert.match(
|
|
2257
|
-
authController,
|
|
2258
|
-
/permissions: Array\.isArray\(payload\.permissions\) \? payload\.permissions : \[\],/,
|
|
2259
|
-
);
|
|
2260
|
-
} finally {
|
|
2261
|
-
fs.rmSync(targetRoot, { recursive: true, force: true });
|
|
2262
|
-
}
|
|
2263
|
-
});
|
|
2264
|
-
|
|
2265
|
-
it('scans auth persistence as db-adapter participant while remaining triggerable from db-prisma install order', () => {
|
|
2266
|
-
const targetRoot = mkTmp('forgeon-module-jwt-db-scan-');
|
|
2267
|
-
const projectRoot = path.join(targetRoot, 'demo-jwt-db-scan');
|
|
2268
|
-
const templateRoot = path.join(packageRoot, 'templates', 'base');
|
|
2269
|
-
|
|
2270
|
-
try {
|
|
2271
|
-
scaffoldProject({
|
|
2272
|
-
templateRoot,
|
|
2273
|
-
packageRoot,
|
|
2274
|
-
targetRoot: projectRoot,
|
|
2275
|
-
projectName: 'demo-jwt-db-scan',
|
|
2276
|
-
frontend: 'react',
|
|
2277
|
-
db: 'prisma',
|
|
2278
|
-
dbPrismaEnabled: false,
|
|
2279
|
-
i18nEnabled: false,
|
|
2280
|
-
proxy: 'caddy',
|
|
2281
|
-
});
|
|
2282
|
-
|
|
2283
|
-
addModule({
|
|
2284
|
-
moduleId: 'jwt-auth',
|
|
2285
|
-
targetRoot: projectRoot,
|
|
2286
|
-
packageRoot,
|
|
2287
|
-
});
|
|
2288
|
-
addModule({
|
|
2289
|
-
moduleId: 'db-prisma',
|
|
2290
|
-
targetRoot: projectRoot,
|
|
2291
|
-
packageRoot,
|
|
2292
|
-
});
|
|
2293
|
-
|
|
2294
|
-
const scan = scanIntegrations({
|
|
2295
|
-
targetRoot: projectRoot,
|
|
2296
|
-
relatedModuleId: 'db-prisma',
|
|
2297
|
-
});
|
|
2298
|
-
const persistenceGroup = scan.groups.find((group) => group.id === 'auth-persistence');
|
|
2299
|
-
|
|
2300
|
-
assert.ok(persistenceGroup);
|
|
2301
|
-
assert.deepEqual(persistenceGroup.modules, ['jwt-auth', 'db-adapter']);
|
|
2302
|
-
} finally {
|
|
2303
|
-
fs.rmSync(targetRoot, { recursive: true, force: true });
|
|
2304
|
-
}
|
|
2305
|
-
});
|
|
2306
|
-
|
|
2307
|
-
it('applies logger then jwt-auth on db/i18n-disabled scaffold without breaking health controller syntax', () => {
|
|
2169
|
+
it('applies accounts with db-prisma and wires the DB-backed runtime immediately', () => {
|
|
2170
|
+
const targetRoot = mkTmp('forgeon-module-accounts-db-');
|
|
2171
|
+
const projectRoot = path.join(targetRoot, 'demo-accounts-db');
|
|
2172
|
+
const templateRoot = path.join(packageRoot, 'templates', 'base');
|
|
2173
|
+
|
|
2174
|
+
try {
|
|
2175
|
+
scaffoldProject({
|
|
2176
|
+
templateRoot,
|
|
2177
|
+
packageRoot,
|
|
2178
|
+
targetRoot: projectRoot,
|
|
2179
|
+
projectName: 'demo-accounts-db',
|
|
2180
|
+
frontend: 'react',
|
|
2181
|
+
db: 'prisma',
|
|
2182
|
+
dbPrismaEnabled: true,
|
|
2183
|
+
i18nEnabled: true,
|
|
2184
|
+
proxy: 'caddy',
|
|
2185
|
+
});
|
|
2186
|
+
|
|
2187
|
+
const result = addModule({
|
|
2188
|
+
moduleId: 'accounts',
|
|
2189
|
+
targetRoot: projectRoot,
|
|
2190
|
+
packageRoot,
|
|
2191
|
+
});
|
|
2192
|
+
|
|
2193
|
+
assert.equal(result.applied, true);
|
|
2194
|
+
assertAccountsWiring(projectRoot);
|
|
2195
|
+
|
|
2196
|
+
const schema = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'prisma', 'schema.prisma'), 'utf8');
|
|
2197
|
+
assert.match(schema, /model UserProfile/);
|
|
2198
|
+
assert.match(schema, /model UserSettings/);
|
|
2199
|
+
assert.match(schema, /model AuthIdentity/);
|
|
2200
|
+
assert.match(schema, /model AuthCredential/);
|
|
2201
|
+
assert.match(schema, /model AuthRefreshToken/);
|
|
2202
|
+
assert.doesNotMatch(schema, /roles\s+/i);
|
|
2203
|
+
assert.doesNotMatch(schema, /permissions\s+/i);
|
|
2204
|
+
|
|
2205
|
+
const migrationPath = path.join(
|
|
2206
|
+
projectRoot,
|
|
2207
|
+
'apps',
|
|
2208
|
+
'api',
|
|
2209
|
+
'prisma',
|
|
2210
|
+
'migrations',
|
|
2211
|
+
'0002_accounts_core',
|
|
2212
|
+
'migration.sql',
|
|
2213
|
+
);
|
|
2214
|
+
assert.equal(fs.existsSync(migrationPath), true);
|
|
2215
|
+
|
|
2216
|
+
const seedSource = fs.readFileSync(path.join(projectRoot, 'apps', 'api', 'prisma', 'seed.ts'), 'utf8');
|
|
2217
|
+
assert.match(seedSource, /Prisma\.dmmf/);
|
|
2218
|
+
assert.match(seedSource, /userFields\.has\('email'\)/);
|
|
2219
|
+
|
|
2220
|
+
const readme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
|
|
2221
|
+
assert.match(readme, /POST \/api\/auth\/register/);
|
|
2222
|
+
assert.match(readme, /POST \/api\/auth\/password-reset\/request/);
|
|
2223
|
+
assert.match(readme, /\/api\/users\/:id\/settings/);
|
|
2224
|
+
|
|
2225
|
+
const moduleDoc = fs.readFileSync(result.docsPath, 'utf8');
|
|
2226
|
+
assert.match(moduleDoc, /Status: implemented/);
|
|
2227
|
+
assert.match(moduleDoc, /db-adapter/);
|
|
2228
|
+
assert.match(moduleDoc, /owner-scoped/);
|
|
2229
|
+
} finally {
|
|
2230
|
+
fs.rmSync(targetRoot, { recursive: true, force: true });
|
|
2231
|
+
}
|
|
2232
|
+
});
|
|
2233
|
+
|
|
2234
|
+
it('detects and applies accounts-rbac compatibility sync explicitly', () => {
|
|
2235
|
+
const targetRoot = mkTmp('forgeon-module-accounts-rbac-');
|
|
2236
|
+
const projectRoot = path.join(targetRoot, 'demo-accounts-rbac');
|
|
2237
|
+
const templateRoot = path.join(packageRoot, 'templates', 'base');
|
|
2238
|
+
|
|
2239
|
+
try {
|
|
2240
|
+
scaffoldProject({
|
|
2241
|
+
templateRoot,
|
|
2242
|
+
packageRoot,
|
|
2243
|
+
targetRoot: projectRoot,
|
|
2244
|
+
projectName: 'demo-accounts-rbac',
|
|
2245
|
+
frontend: 'react',
|
|
2246
|
+
db: 'prisma',
|
|
2247
|
+
dbPrismaEnabled: true,
|
|
2248
|
+
i18nEnabled: false,
|
|
2249
|
+
proxy: 'caddy',
|
|
2250
|
+
});
|
|
2251
|
+
|
|
2252
|
+
addModule({
|
|
2253
|
+
moduleId: 'rbac',
|
|
2254
|
+
targetRoot: projectRoot,
|
|
2255
|
+
packageRoot,
|
|
2256
|
+
});
|
|
2257
|
+
addModule({
|
|
2258
|
+
moduleId: 'accounts',
|
|
2259
|
+
targetRoot: projectRoot,
|
|
2260
|
+
packageRoot,
|
|
2261
|
+
});
|
|
2262
|
+
|
|
2263
|
+
const scan = scanIntegrations({
|
|
2264
|
+
targetRoot: projectRoot,
|
|
2265
|
+
relatedModuleId: 'accounts',
|
|
2266
|
+
});
|
|
2267
|
+
assert.equal(scan.groups.some((group) => group.id === 'accounts-rbac'), true);
|
|
2268
|
+
|
|
2269
|
+
const syncResult = syncIntegrations({
|
|
2270
|
+
targetRoot: projectRoot,
|
|
2271
|
+
packageRoot,
|
|
2272
|
+
groupIds: ['accounts-rbac'],
|
|
2273
|
+
});
|
|
2274
|
+
const claimsPair = syncResult.summary.find((item) => item.id === 'accounts-rbac');
|
|
2275
|
+
assert.ok(claimsPair);
|
|
2276
|
+
assert.equal(claimsPair.result.applied, true);
|
|
2277
|
+
|
|
2278
|
+
const contracts = fs.readFileSync(
|
|
2279
|
+
path.join(projectRoot, 'packages', 'accounts-contracts', 'src', 'index.ts'),
|
|
2280
|
+
'utf8',
|
|
2281
|
+
);
|
|
2282
|
+
assert.match(contracts, /roles\?: string\[\];/);
|
|
2283
|
+
assert.match(contracts, /permissions\?: string\[\];/);
|
|
2284
|
+
|
|
2285
|
+
const authTypes = fs.readFileSync(
|
|
2286
|
+
path.join(projectRoot, 'packages', 'accounts-api', 'src', 'auth.types.ts'),
|
|
2287
|
+
'utf8',
|
|
2288
|
+
);
|
|
2289
|
+
assert.match(authTypes, /roles\?: string\[\];/);
|
|
2290
|
+
assert.match(authTypes, /permissions\?: string\[\];/);
|
|
2291
|
+
|
|
2292
|
+
const readme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
|
|
2293
|
+
assert.match(readme, /forgeon:accounts:rbac:start/);
|
|
2294
|
+
assert.match(readme, /base accounts schema remains free of roles and permissions/);
|
|
2295
|
+
} finally {
|
|
2296
|
+
fs.rmSync(targetRoot, { recursive: true, force: true });
|
|
2297
|
+
}
|
|
2298
|
+
});
|
|
2299
|
+
|
|
2300
|
+
it('scans accounts-rbac compatibility when accounts and rbac are both installed', () => {
|
|
2301
|
+
const targetRoot = mkTmp('forgeon-module-accounts-rbac-scan-');
|
|
2302
|
+
const projectRoot = path.join(targetRoot, 'demo-accounts-rbac-scan');
|
|
2303
|
+
const templateRoot = path.join(packageRoot, 'templates', 'base');
|
|
2304
|
+
|
|
2305
|
+
try {
|
|
2306
|
+
scaffoldProject({
|
|
2307
|
+
templateRoot,
|
|
2308
|
+
packageRoot,
|
|
2309
|
+
targetRoot: projectRoot,
|
|
2310
|
+
projectName: 'demo-accounts-rbac-scan',
|
|
2311
|
+
frontend: 'react',
|
|
2312
|
+
db: 'prisma',
|
|
2313
|
+
dbPrismaEnabled: true,
|
|
2314
|
+
i18nEnabled: false,
|
|
2315
|
+
proxy: 'caddy',
|
|
2316
|
+
});
|
|
2317
|
+
|
|
2318
|
+
addModule({
|
|
2319
|
+
moduleId: 'accounts',
|
|
2320
|
+
targetRoot: projectRoot,
|
|
2321
|
+
packageRoot,
|
|
2322
|
+
});
|
|
2323
|
+
addModule({
|
|
2324
|
+
moduleId: 'rbac',
|
|
2325
|
+
targetRoot: projectRoot,
|
|
2326
|
+
packageRoot,
|
|
2327
|
+
});
|
|
2328
|
+
|
|
2329
|
+
const scan = scanIntegrations({
|
|
2330
|
+
targetRoot: projectRoot,
|
|
2331
|
+
relatedModuleId: 'rbac',
|
|
2332
|
+
});
|
|
2333
|
+
const compatibilityGroup = scan.groups.find((group) => group.id === 'accounts-rbac');
|
|
2334
|
+
|
|
2335
|
+
assert.ok(compatibilityGroup);
|
|
2336
|
+
assert.deepEqual(compatibilityGroup.modules, ['accounts', 'rbac']);
|
|
2337
|
+
} finally {
|
|
2338
|
+
fs.rmSync(targetRoot, { recursive: true, force: true });
|
|
2339
|
+
}
|
|
2340
|
+
});
|
|
2341
|
+
it('applies logger then accounts on db/i18n-disabled scaffold without breaking health controller syntax', () => {
|
|
2308
2342
|
const targetRoot = mkTmp('forgeon-module-jwt-nodb-noi18n-');
|
|
2309
2343
|
const projectRoot = path.join(targetRoot, 'demo-jwt-nodb-noi18n');
|
|
2310
2344
|
const templateRoot = path.join(packageRoot, 'templates', 'base');
|
|
@@ -2328,7 +2362,7 @@ describe('addModule', () => {
|
|
|
2328
2362
|
packageRoot,
|
|
2329
2363
|
});
|
|
2330
2364
|
addModule({
|
|
2331
|
-
moduleId: '
|
|
2365
|
+
moduleId: 'accounts',
|
|
2332
2366
|
targetRoot: projectRoot,
|
|
2333
2367
|
packageRoot,
|
|
2334
2368
|
});
|
|
@@ -2352,7 +2386,7 @@ describe('addModule', () => {
|
|
|
2352
2386
|
}
|
|
2353
2387
|
});
|
|
2354
2388
|
|
|
2355
|
-
it('keeps health controller valid for add sequence
|
|
2389
|
+
it('keeps health controller valid for add sequence accounts -> logger -> swagger -> i18n -> db-prisma on db/i18n-disabled scaffold', () => {
|
|
2356
2390
|
const targetRoot = mkTmp('forgeon-module-seq-health-valid-');
|
|
2357
2391
|
const projectRoot = path.join(targetRoot, 'demo-seq-health-valid');
|
|
2358
2392
|
const templateRoot = path.join(packageRoot, 'templates', 'base');
|
|
@@ -2370,7 +2404,7 @@ describe('addModule', () => {
|
|
|
2370
2404
|
proxy: 'caddy',
|
|
2371
2405
|
});
|
|
2372
2406
|
|
|
2373
|
-
for (const moduleId of ['
|
|
2407
|
+
for (const moduleId of ['accounts', 'logger', 'swagger', 'i18n', 'db-prisma']) {
|
|
2374
2408
|
addModule({ moduleId, targetRoot: projectRoot, packageRoot });
|
|
2375
2409
|
}
|
|
2376
2410
|
|
|
@@ -2405,9 +2439,9 @@ describe('addModule', () => {
|
|
|
2405
2439
|
}
|
|
2406
2440
|
});
|
|
2407
2441
|
|
|
2408
|
-
it('applies swagger then
|
|
2409
|
-
const targetRoot = mkTmp('forgeon-module-
|
|
2410
|
-
const projectRoot = path.join(targetRoot, 'demo-
|
|
2442
|
+
it('applies swagger then accounts without forcing swagger dependency in accounts-api', () => {
|
|
2443
|
+
const targetRoot = mkTmp('forgeon-module-accounts-swagger-');
|
|
2444
|
+
const projectRoot = path.join(targetRoot, 'demo-accounts-swagger');
|
|
2411
2445
|
const templateRoot = path.join(packageRoot, 'templates', 'base');
|
|
2412
2446
|
|
|
2413
2447
|
try {
|
|
@@ -2415,7 +2449,7 @@ describe('addModule', () => {
|
|
|
2415
2449
|
templateRoot,
|
|
2416
2450
|
packageRoot,
|
|
2417
2451
|
targetRoot: projectRoot,
|
|
2418
|
-
projectName: 'demo-
|
|
2452
|
+
projectName: 'demo-accounts-swagger',
|
|
2419
2453
|
frontend: 'react',
|
|
2420
2454
|
db: 'prisma',
|
|
2421
2455
|
dbPrismaEnabled: false,
|
|
@@ -2429,15 +2463,15 @@ describe('addModule', () => {
|
|
|
2429
2463
|
packageRoot,
|
|
2430
2464
|
});
|
|
2431
2465
|
addModule({
|
|
2432
|
-
moduleId: '
|
|
2466
|
+
moduleId: 'accounts',
|
|
2433
2467
|
targetRoot: projectRoot,
|
|
2434
2468
|
packageRoot,
|
|
2435
2469
|
});
|
|
2436
2470
|
|
|
2437
|
-
const
|
|
2438
|
-
fs.readFileSync(path.join(projectRoot, 'packages', '
|
|
2471
|
+
const accountsApiPackage = JSON.parse(
|
|
2472
|
+
fs.readFileSync(path.join(projectRoot, 'packages', 'accounts-api', 'package.json'), 'utf8'),
|
|
2439
2473
|
);
|
|
2440
|
-
assert.equal(Object.hasOwn(
|
|
2474
|
+
assert.equal(Object.hasOwn(accountsApiPackage.dependencies ?? {}, '@nestjs/swagger'), false);
|
|
2441
2475
|
} finally {
|
|
2442
2476
|
fs.rmSync(targetRoot, { recursive: true, force: true });
|
|
2443
2477
|
}
|
|
@@ -2461,7 +2495,7 @@ describe('addModule', () => {
|
|
|
2461
2495
|
proxy: 'caddy',
|
|
2462
2496
|
});
|
|
2463
2497
|
|
|
2464
|
-
for (const moduleId of ['
|
|
2498
|
+
for (const moduleId of ['accounts', 'logger', 'swagger', 'rate-limit', 'i18n', 'db-prisma']) {
|
|
2465
2499
|
addModule({ moduleId, targetRoot: projectRoot, packageRoot });
|
|
2466
2500
|
}
|
|
2467
2501
|
|
|
@@ -2498,7 +2532,7 @@ describe('addModule', () => {
|
|
|
2498
2532
|
proxy: 'caddy',
|
|
2499
2533
|
});
|
|
2500
2534
|
|
|
2501
|
-
for (const moduleId of ['
|
|
2535
|
+
for (const moduleId of ['accounts', 'logger', 'rate-limit', 'rbac', 'swagger', 'i18n', 'db-prisma']) {
|
|
2502
2536
|
addModule({ moduleId, targetRoot: projectRoot, packageRoot });
|
|
2503
2537
|
}
|
|
2504
2538
|
|
|
@@ -2599,3 +2633,13 @@ describe('addModule', () => {
|
|
|
2599
2633
|
|
|
2600
2634
|
|
|
2601
2635
|
|
|
2636
|
+
|
|
2637
|
+
|
|
2638
|
+
|
|
2639
|
+
|
|
2640
|
+
|
|
2641
|
+
|
|
2642
|
+
|
|
2643
|
+
|
|
2644
|
+
|
|
2645
|
+
|