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.
Files changed (109) hide show
  1. package/package.json +1 -1
  2. package/src/cli/add-options.test.mjs +5 -2
  3. package/src/cli/options.test.mjs +1 -0
  4. package/src/cli/prompt-select.test.mjs +1 -0
  5. package/src/core/docs.test.mjs +1 -0
  6. package/src/core/scaffold.test.mjs +1 -0
  7. package/src/core/validate.test.mjs +1 -0
  8. package/src/modules/accounts.mjs +416 -0
  9. package/src/modules/db-prisma.mjs +5 -9
  10. package/src/modules/dependencies.test.mjs +71 -29
  11. package/src/modules/executor.mjs +3 -2
  12. package/src/modules/executor.test.mjs +521 -477
  13. package/src/modules/files-access.mjs +9 -7
  14. package/src/modules/files-image.mjs +9 -7
  15. package/src/modules/files-local.mjs +15 -6
  16. package/src/modules/files-quotas.mjs +8 -6
  17. package/src/modules/files-s3.mjs +17 -6
  18. package/src/modules/files.mjs +21 -21
  19. package/src/modules/idempotency.test.mjs +13 -7
  20. package/src/modules/probes.test.mjs +4 -2
  21. package/src/modules/queue.mjs +9 -6
  22. package/src/modules/rate-limit.mjs +14 -10
  23. package/src/modules/rbac.mjs +12 -11
  24. package/src/modules/registry.mjs +22 -35
  25. package/src/modules/scheduler.mjs +9 -6
  26. package/src/modules/shared/files-runtime-wiring.mjs +81 -0
  27. package/src/modules/shared/patch-utils.mjs +29 -1
  28. package/src/modules/sync-integrations.mjs +102 -422
  29. package/src/modules/sync-integrations.test.mjs +32 -111
  30. package/src/run-add-module.test.mjs +1 -0
  31. package/templates/base/scripts/forgeon-sync-integrations.mjs +65 -325
  32. package/templates/module-fragments/{jwt-auth → accounts}/00_title.md +2 -1
  33. package/templates/module-fragments/{jwt-auth → accounts}/10_overview.md +5 -5
  34. package/templates/module-fragments/accounts/20_scope.md +29 -0
  35. package/templates/module-fragments/accounts/90_status_implemented.md +8 -0
  36. package/templates/module-fragments/accounts/90_status_planned.md +7 -0
  37. package/templates/module-fragments/rbac/30_what_it_adds.md +3 -2
  38. package/templates/module-fragments/rbac/40_how_it_works.md +2 -1
  39. package/templates/module-fragments/rbac/50_how_to_use.md +2 -1
  40. package/templates/module-fragments/swagger/20_scope.md +2 -1
  41. package/templates/module-presets/accounts/apps/api/prisma/migrations/0002_accounts_core/migration.sql +97 -0
  42. package/templates/module-presets/accounts/apps/api/src/accounts/forgeon-accounts-db-prisma.module.ts +17 -0
  43. package/templates/module-presets/accounts/apps/api/src/accounts/prisma-accounts-persistence.store.ts +332 -0
  44. package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/package.json +5 -5
  45. package/templates/module-presets/accounts/packages/accounts-api/src/accounts-email.port.ts +13 -0
  46. package/templates/module-presets/accounts/packages/accounts-api/src/accounts-persistence.port.ts +67 -0
  47. package/templates/module-presets/accounts/packages/accounts-api/src/accounts-rbac.port.ts +14 -0
  48. package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/auth-config.loader.ts +7 -7
  49. package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/auth-config.service.ts +7 -7
  50. package/templates/module-presets/accounts/packages/accounts-api/src/auth-core.service.ts +318 -0
  51. package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/auth-env.schema.ts +4 -4
  52. package/templates/module-presets/accounts/packages/accounts-api/src/auth-jwt.service.ts +58 -0
  53. package/templates/module-presets/accounts/packages/accounts-api/src/auth-password.service.ts +21 -0
  54. package/templates/module-presets/accounts/packages/accounts-api/src/auth.controller.ts +93 -0
  55. package/templates/module-presets/accounts/packages/accounts-api/src/auth.service.ts +48 -0
  56. package/templates/module-presets/accounts/packages/accounts-api/src/auth.types.ts +17 -0
  57. package/templates/module-presets/accounts/packages/accounts-api/src/dto/change-password.dto.ts +13 -0
  58. package/templates/module-presets/accounts/packages/accounts-api/src/dto/confirm-password-reset.dto.ts +12 -0
  59. package/templates/module-presets/accounts/packages/accounts-api/src/dto/index.ts +10 -0
  60. package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/dto/login.dto.ts +1 -1
  61. package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/dto/refresh.dto.ts +1 -1
  62. package/templates/module-presets/accounts/packages/accounts-api/src/dto/register.dto.ts +23 -0
  63. package/templates/module-presets/accounts/packages/accounts-api/src/dto/request-password-reset.dto.ts +7 -0
  64. package/templates/module-presets/accounts/packages/accounts-api/src/dto/update-user-profile.dto.ts +16 -0
  65. package/templates/module-presets/accounts/packages/accounts-api/src/dto/update-user-settings.dto.ts +16 -0
  66. package/templates/module-presets/accounts/packages/accounts-api/src/dto/update-user.dto.ts +8 -0
  67. package/templates/module-presets/accounts/packages/accounts-api/src/dto/verify-email.dto.ts +8 -0
  68. package/templates/module-presets/accounts/packages/accounts-api/src/forgeon-accounts.module.ts +82 -0
  69. package/templates/module-presets/accounts/packages/accounts-api/src/index.ts +24 -0
  70. package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/jwt.strategy.ts +3 -3
  71. package/templates/module-presets/accounts/packages/accounts-api/src/owner-access.guard.ts +39 -0
  72. package/templates/module-presets/accounts/packages/accounts-api/src/users-config.ts +13 -0
  73. package/templates/module-presets/accounts/packages/accounts-api/src/users.controller.ts +65 -0
  74. package/templates/module-presets/accounts/packages/accounts-api/src/users.service.ts +87 -0
  75. package/templates/module-presets/accounts/packages/accounts-api/src/users.types.ts +65 -0
  76. package/templates/module-presets/{jwt-auth/packages/auth-contracts → accounts/packages/accounts-contracts}/package.json +1 -1
  77. package/templates/module-presets/accounts/packages/accounts-contracts/src/index.ts +119 -0
  78. package/templates/module-presets/db-prisma/apps/api/prisma/seed.ts +40 -19
  79. package/templates/module-presets/files/apps/api/src/files/forgeon-files-db-prisma.module.ts +17 -0
  80. package/templates/module-presets/files/apps/api/src/files/prisma-files-persistence.store.ts +164 -0
  81. package/templates/module-presets/files/packages/files/package.json +1 -2
  82. package/templates/module-presets/files/packages/files/src/files.ports.ts +107 -0
  83. package/templates/module-presets/files/packages/files/src/files.service.ts +81 -395
  84. package/templates/module-presets/files/packages/files/src/forgeon-files.module.ts +126 -2
  85. package/templates/module-presets/files/packages/files/src/index.ts +2 -1
  86. package/templates/module-presets/files-local/packages/files-local/src/forgeon-files-local-storage.module.ts +18 -0
  87. package/templates/module-presets/files-local/packages/files-local/src/index.ts +2 -0
  88. package/templates/module-presets/files-local/packages/files-local/src/local-files-storage.adapter.ts +53 -0
  89. package/templates/module-presets/files-s3/packages/files-s3/src/forgeon-files-s3-storage.module.ts +18 -0
  90. package/templates/module-presets/files-s3/packages/files-s3/src/index.ts +2 -0
  91. package/templates/module-presets/files-s3/packages/files-s3/src/s3-files-storage.adapter.ts +130 -0
  92. package/src/modules/jwt-auth.mjs +0 -271
  93. package/templates/module-fragments/jwt-auth/20_scope.md +0 -19
  94. package/templates/module-fragments/jwt-auth/90_status_implemented.md +0 -8
  95. package/templates/module-fragments/jwt-auth/90_status_planned.md +0 -3
  96. package/templates/module-presets/jwt-auth/apps/api/prisma/migrations/0002_auth_refresh_token_hash/migration.sql +0 -3
  97. package/templates/module-presets/jwt-auth/apps/api/src/auth/prisma-auth-refresh-token.store.ts +0 -36
  98. package/templates/module-presets/jwt-auth/packages/auth-api/src/auth-refresh-token.store.ts +0 -23
  99. package/templates/module-presets/jwt-auth/packages/auth-api/src/auth.controller.ts +0 -71
  100. package/templates/module-presets/jwt-auth/packages/auth-api/src/auth.service.ts +0 -175
  101. package/templates/module-presets/jwt-auth/packages/auth-api/src/auth.types.ts +0 -6
  102. package/templates/module-presets/jwt-auth/packages/auth-api/src/dto/index.ts +0 -2
  103. package/templates/module-presets/jwt-auth/packages/auth-api/src/forgeon-auth.module.ts +0 -47
  104. package/templates/module-presets/jwt-auth/packages/auth-api/src/index.ts +0 -12
  105. package/templates/module-presets/jwt-auth/packages/auth-contracts/src/index.ts +0 -47
  106. /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
  107. /package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/src/auth-config.module.ts +0 -0
  108. /package/templates/module-presets/{jwt-auth/packages/auth-api → accounts/packages/accounts-api}/tsconfig.json +0 -0
  109. /package/templates/module-presets/{jwt-auth/packages/auth-contracts → accounts/packages/accounts-contracts}/tsconfig.json +0 -0
@@ -31,29 +31,29 @@ describe('sync integrations', () => {
31
31
  const modulesDir = path.dirname(fileURLToPath(import.meta.url));
32
32
  const packageRoot = path.resolve(modulesDir, '..', '..');
33
33
 
34
- it('does not expose auth persistence integration without a db-adapter provider', () => {
35
- const tempRoot = makeTempDir('forgeon-sync-no-provider-');
36
- const projectRoot = path.join(tempRoot, 'demo-sync-no-provider');
34
+ it('does not expose accounts-rbac integration when rbac is missing', () => {
35
+ const tempRoot = makeTempDir('forgeon-sync-no-rbac-');
36
+ const projectRoot = path.join(tempRoot, 'demo-sync-no-rbac');
37
37
 
38
38
  try {
39
39
  scaffoldBaseProject({
40
40
  packageRoot,
41
41
  targetRoot: projectRoot,
42
- projectName: 'demo-sync-no-provider',
42
+ projectName: 'demo-sync-no-rbac',
43
43
  });
44
44
 
45
- addModule({ moduleId: 'jwt-auth', targetRoot: projectRoot, packageRoot });
45
+ addModule({ moduleId: 'db-prisma', targetRoot: projectRoot, packageRoot });
46
+ addModule({ moduleId: 'accounts', targetRoot: projectRoot, packageRoot });
46
47
 
47
48
  const scan = scanIntegrations({
48
49
  targetRoot: projectRoot,
49
- relatedModuleId: 'jwt-auth',
50
+ relatedModuleId: 'accounts',
50
51
  });
51
- assert.equal(scan.groups.some((group) => group.id === 'auth-persistence'), false);
52
+ assert.equal(scan.groups.some((group) => group.id === 'accounts-rbac'), false);
52
53
 
53
54
  const syncResult = syncIntegrations({
54
55
  targetRoot: projectRoot,
55
- packageRoot,
56
- groupIds: ['auth-persistence'],
56
+ groupIds: ['accounts-rbac'],
57
57
  });
58
58
  assert.deepEqual(syncResult.summary, []);
59
59
  assert.deepEqual(syncResult.changedFiles, []);
@@ -62,48 +62,7 @@ describe('sync integrations', () => {
62
62
  }
63
63
  });
64
64
 
65
- it('treats auth persistence sync as a no-op after it has already been applied', () => {
66
- const tempRoot = makeTempDir('forgeon-sync-db-noop-');
67
- const projectRoot = path.join(tempRoot, 'demo-sync-db-noop');
68
-
69
- try {
70
- scaffoldBaseProject({
71
- packageRoot,
72
- targetRoot: projectRoot,
73
- projectName: 'demo-sync-db-noop',
74
- dbPrismaEnabled: true,
75
- });
76
-
77
- addModule({ moduleId: 'jwt-auth', targetRoot: projectRoot, packageRoot });
78
-
79
- const firstSync = syncIntegrations({
80
- targetRoot: projectRoot,
81
- packageRoot,
82
- groupIds: ['auth-persistence'],
83
- });
84
- assert.equal(firstSync.summary.length, 1);
85
- assert.equal(firstSync.summary[0].id, 'auth-persistence');
86
- assert.equal(firstSync.summary[0].result.applied, true);
87
-
88
- const secondScan = scanIntegrations({
89
- targetRoot: projectRoot,
90
- relatedModuleId: 'jwt-auth',
91
- });
92
- assert.equal(secondScan.groups.some((group) => group.id === 'auth-persistence'), false);
93
-
94
- const secondSync = syncIntegrations({
95
- targetRoot: projectRoot,
96
- packageRoot,
97
- groupIds: ['auth-persistence'],
98
- });
99
- assert.deepEqual(secondSync.summary, []);
100
- assert.deepEqual(secondSync.changedFiles, []);
101
- } finally {
102
- fs.rmSync(tempRoot, { recursive: true, force: true });
103
- }
104
- });
105
-
106
- it('treats auth claims sync as a no-op after it has already been applied', () => {
65
+ it('treats accounts-rbac sync as a no-op after it has already been applied', () => {
107
66
  const tempRoot = makeTempDir('forgeon-sync-rbac-noop-');
108
67
  const projectRoot = path.join(tempRoot, 'demo-sync-rbac-noop');
109
68
 
@@ -114,28 +73,27 @@ describe('sync integrations', () => {
114
73
  projectName: 'demo-sync-rbac-noop',
115
74
  });
116
75
 
76
+ addModule({ moduleId: 'db-prisma', targetRoot: projectRoot, packageRoot });
117
77
  addModule({ moduleId: 'rbac', targetRoot: projectRoot, packageRoot });
118
- addModule({ moduleId: 'jwt-auth', targetRoot: projectRoot, packageRoot });
78
+ addModule({ moduleId: 'accounts', targetRoot: projectRoot, packageRoot });
119
79
 
120
80
  const firstSync = syncIntegrations({
121
81
  targetRoot: projectRoot,
122
- packageRoot,
123
- groupIds: ['auth-rbac-claims'],
82
+ groupIds: ['accounts-rbac'],
124
83
  });
125
84
  assert.equal(firstSync.summary.length, 1);
126
- assert.equal(firstSync.summary[0].id, 'auth-rbac-claims');
85
+ assert.equal(firstSync.summary[0].id, 'accounts-rbac');
127
86
  assert.equal(firstSync.summary[0].result.applied, true);
128
87
 
129
88
  const secondScan = scanIntegrations({
130
89
  targetRoot: projectRoot,
131
- relatedModuleId: 'jwt-auth',
90
+ relatedModuleId: 'accounts',
132
91
  });
133
- assert.equal(secondScan.groups.some((group) => group.id === 'auth-rbac-claims'), false);
92
+ assert.equal(secondScan.groups.some((group) => group.id === 'accounts-rbac'), false);
134
93
 
135
94
  const secondSync = syncIntegrations({
136
95
  targetRoot: projectRoot,
137
- packageRoot,
138
- groupIds: ['auth-rbac-claims'],
96
+ groupIds: ['accounts-rbac'],
139
97
  });
140
98
  assert.deepEqual(secondSync.summary, []);
141
99
  assert.deepEqual(secondSync.changedFiles, []);
@@ -143,45 +101,8 @@ describe('sync integrations', () => {
143
101
  fs.rmSync(tempRoot, { recursive: true, force: true });
144
102
  }
145
103
  });
146
- it('uses persistence markers instead of README prose when auth persistence sync runs', () => {
147
- const tempRoot = makeTempDir('forgeon-sync-db-markers-');
148
- const projectRoot = path.join(tempRoot, 'demo-sync-db-markers');
149
-
150
- try {
151
- scaffoldBaseProject({
152
- packageRoot,
153
- targetRoot: projectRoot,
154
- projectName: 'demo-sync-db-markers',
155
- dbPrismaEnabled: true,
156
- });
157
-
158
- addModule({ moduleId: 'jwt-auth', targetRoot: projectRoot, packageRoot });
159
-
160
- const readmePath = path.join(projectRoot, 'README.md');
161
- const customizedReadme = fs
162
- .readFileSync(readmePath, 'utf8')
163
- .replace('refresh token persistence: disabled by default', 'refresh token persistence: custom local note');
164
- fs.writeFileSync(readmePath, customizedReadme, 'utf8');
165
-
166
- const syncResult = syncIntegrations({
167
- targetRoot: projectRoot,
168
- packageRoot,
169
- groupIds: ['auth-persistence'],
170
- });
171
- assert.equal(syncResult.summary.length, 1);
172
- assert.equal(syncResult.summary[0].result.applied, true);
173
-
174
- const readme = fs.readFileSync(readmePath, 'utf8');
175
- assert.match(readme, /forgeon:jwt-auth:persistence:start/);
176
- assert.match(readme, /refresh token persistence: enabled through the `db-adapter` capability/);
177
- assert.match(readme, /0002_auth_refresh_token_hash/);
178
- assert.doesNotMatch(readme, /custom local note/);
179
- } finally {
180
- fs.rmSync(tempRoot, { recursive: true, force: true });
181
- }
182
- });
183
104
 
184
- it('uses RBAC markers instead of the demo credentials heading when auth claims sync runs', () => {
105
+ it('updates claim types and README markers when accounts-rbac sync runs', () => {
185
106
  const tempRoot = makeTempDir('forgeon-sync-rbac-markers-');
186
107
  const projectRoot = path.join(tempRoot, 'demo-sync-rbac-markers');
187
108
 
@@ -192,29 +113,29 @@ describe('sync integrations', () => {
192
113
  projectName: 'demo-sync-rbac-markers',
193
114
  });
194
115
 
116
+ addModule({ moduleId: 'db-prisma', targetRoot: projectRoot, packageRoot });
195
117
  addModule({ moduleId: 'rbac', targetRoot: projectRoot, packageRoot });
196
- addModule({ moduleId: 'jwt-auth', targetRoot: projectRoot, packageRoot });
197
-
198
- const readmePath = path.join(projectRoot, 'README.md');
199
- const customizedReadme = fs
200
- .readFileSync(readmePath, 'utf8')
201
- .replace('Default demo credentials:', 'Demo credentials:');
202
- fs.writeFileSync(readmePath, customizedReadme, 'utf8');
118
+ addModule({ moduleId: 'accounts', targetRoot: projectRoot, packageRoot });
203
119
 
204
120
  const syncResult = syncIntegrations({
205
121
  targetRoot: projectRoot,
206
- packageRoot,
207
- groupIds: ['auth-rbac-claims'],
122
+ groupIds: ['accounts-rbac'],
208
123
  });
209
124
  assert.equal(syncResult.summary.length, 1);
210
125
  assert.equal(syncResult.summary[0].result.applied, true);
211
126
 
212
- const readme = fs.readFileSync(readmePath, 'utf8');
213
- assert.match(readme, /forgeon:jwt-auth:rbac:start/);
214
- assert.match(readme, /RBAC integration: demo auth tokens include `health\.rbac` permission/);
215
- assert.match(readme, /Demo credentials:/);
127
+ const readme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
128
+ const contracts = fs.readFileSync(path.join(projectRoot, 'packages', 'accounts-contracts', 'src', 'index.ts'), 'utf8');
129
+ const authTypes = fs.readFileSync(path.join(projectRoot, 'packages', 'accounts-api', 'src', 'auth.types.ts'), 'utf8');
130
+
131
+ assert.match(readme, /forgeon:accounts:rbac:start/);
132
+ assert.match(readme, /base accounts schema remains free of roles and permissions/);
133
+ assert.match(contracts, /roles\?: string\[\];/);
134
+ assert.match(contracts, /permissions\?: string\[\];/);
135
+ assert.match(authTypes, /roles\?: string\[\];/);
136
+ assert.match(authTypes, /permissions\?: string\[\];/);
216
137
  } finally {
217
138
  fs.rmSync(tempRoot, { recursive: true, force: true });
218
139
  }
219
140
  });
220
- });
141
+ });
@@ -151,3 +151,4 @@ describe('runAddModule', () => {
151
151
  }
152
152
  });
153
153
  });
154
+