cabloy 5.1.220 → 5.1.222

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 (87) hide show
  1. package/.cabloy-version +1 -1
  2. package/.github/workflows/agent-governance.yml +2 -2
  3. package/.github/workflows/create-cabloy.yml +2 -2
  4. package/.github/workflows/docs-pages.yml +2 -2
  5. package/.github/workflows/playwright-e2e.yml +4 -4
  6. package/.github/workflows/vona-cov-pg.yml +2 -2
  7. package/.github/workflows/vona-test-crud.yml +2 -2
  8. package/.github/workflows/vona-test-mysql.yml +2 -2
  9. package/.github/workflows/vona-test-pg.yml +2 -2
  10. package/.github/workflows/vona-test-sqlite3.yml +2 -2
  11. package/.github/workflows/vona-tsc.yml +2 -2
  12. package/.github/workflows/zova-ui.yml +2 -2
  13. package/CHANGELOG.md +22 -0
  14. package/package.json +4 -3
  15. package/repo-agent-governance/managed-assets.json +15 -15
  16. package/repo-agent-governance/policies/repository.md +1 -0
  17. package/repo-agent-governance/skills/cabloy-backend-scaffold/SKILL.md +5 -1
  18. package/repo-agent-governance/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +7 -5
  19. package/repo-agent-governance/skills/cabloy-frontend-scaffold/SKILL.md +5 -1
  20. package/repo-agent-governance/skills/cabloy-frontend-scaffold/references/follow-up-checklist.md +6 -4
  21. package/repo-docs/backend/unit-testing.md +5 -1
  22. package/repo-docs/frontend/openapi-sdk-guide.md +2 -0
  23. package/repo-docs/frontend/scripts.md +8 -0
  24. package/repo-docs/reference/repo-scripts.md +5 -1
  25. package/scripts/generateOpenapiIsolated.ts +18 -1
  26. package/scripts/runIsolatedTest.test.ts +9 -1
  27. package/scripts/runIsolatedTest.ts +81 -18
  28. package/scripts/strictGenerationDiagnostics.test.ts +1009 -0
  29. package/scripts/strictGenerationDiagnostics.ts +61 -0
  30. package/vona/package.original.json +3 -2
  31. package/vona/packages-cli/cabloy-cli/package.json +1 -1
  32. package/vona/packages-cli/cli/package.json +1 -1
  33. package/vona/packages-cli/cli-set-api/package.json +1 -1
  34. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.bin.dev.ts +14 -4
  35. package/vona/packages-cli/cli-set-api/src/lib/bean/toolsBin/generateEntryFiles.ts +6 -1
  36. package/vona/packages-cli/cli-set-api/src/lib/bean/toolsBin/generateVonaMeta.ts +2 -10
  37. package/vona/packages-cli/cli-set-api/src/lib/bean/toolsBin/validateGenerationPaths.ts +27 -0
  38. package/vona/packages-cli/cli-set-api/test/binDevLifecycle.test.ts +1 -1
  39. package/vona/packages-cli/cli-set-api/test/strictGenerationPrivacy.test.ts +439 -0
  40. package/vona/packages-utils/process-helper/package.json +1 -1
  41. package/vona/packages-utils/process-helper/src/index.test.ts +62 -0
  42. package/vona/packages-utils/process-helper/src/index.ts +9 -4
  43. package/vona/packages-vona/vona/package.json +1 -1
  44. package/vona/packages-vona/vona-core/package.json +1 -1
  45. package/vona/packages-vona/vona-core/src/lib/core/completedReadiness.test.ts +558 -0
  46. package/vona/packages-vona/vona-core/src/lib/core/completedReadiness.ts +389 -0
  47. package/vona/packages-vona/vona-core/src/lib/core/context.ts +3 -0
  48. package/vona/packages-vona/vona-core/src/lib/core/index.ts +11 -0
  49. package/vona/packages-vona/vona-core/src/lib/core/logger/appLogger.ts +10 -2
  50. package/vona/packages-vona/vona-core/src/lib/core/logger/diagnosticLogger.test.ts +268 -68
  51. package/vona/packages-vona/vona-core/src/lib/core/meta.ts +5 -0
  52. package/vona/packages-vona/vona-core/src/lib/core/testFreshness.ts +3 -9
  53. package/vona/packages-vona/vona-core/src/lib/core/testStrictMode.ts +9 -0
  54. package/vona/packages-vona/vona-core/src/lib/framework/start.test.ts +10 -0
  55. package/vona/packages-vona/vona-core/src/lib/framework/start.ts +8 -0
  56. package/vona/packages-vona/vona-mock/package.json +1 -1
  57. package/vona/pnpm-lock.yaml +542 -236
  58. package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
  59. package/vona/src/suite-vendor/a-vona/modules/a-executor/package.json +1 -1
  60. package/vona/src/suite-vendor/a-vona/modules/a-executor/src/bean/bean.executor.ts +124 -4
  61. package/vona/src/suite-vendor/a-vona/modules/a-executor/src/types/executor.ts +7 -0
  62. package/vona/src/suite-vendor/a-vona/modules/a-executor/test/readyExisting.test.ts +423 -0
  63. package/vona/src/suite-vendor/a-vona/modules/a-executor/test/readyExistingCommit.test.ts +174 -0
  64. package/vona/src/suite-vendor/a-vona/modules/a-instance/package.json +1 -1
  65. package/vona/src/suite-vendor/a-vona/modules/a-instance/src/bean/bean.instance.ts +3 -1
  66. package/vona/src/suite-vendor/a-vona/modules/a-instance/src/lib/existingReadyAdmission.ts +125 -0
  67. package/vona/src/suite-vendor/a-vona/modules/a-instance/src/service/instance.ts +72 -25
  68. package/vona/src/suite-vendor/a-vona/modules/a-instance/test/existingReadyAdmission.test.ts +949 -0
  69. package/vona/src/suite-vendor/a-vona/modules/a-logger/package.json +1 -1
  70. package/vona/src/suite-vendor/a-vona/modules/a-logger/test/middlewareSystem.httpLog.test.ts +61 -59
  71. package/vona/src/suite-vendor/a-vona/modules/a-mail/package.json +1 -1
  72. package/vona/src/suite-vendor/a-vona/modules/a-mail/src/service/mail.ts +5 -0
  73. package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/package.json +1 -1
  74. package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/src/index.ts +11 -0
  75. package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/src/lib/protectedSqliteRegistry.ts +356 -0
  76. package/vona/src/suite-vendor/a-vona/modules/a-startup/package.json +1 -1
  77. package/vona/src/suite-vendor/a-vona/modules/a-startup/test/devSeed.test.ts +61 -2
  78. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  79. package/zova/package.original.json +3 -3
  80. package/zova/packages-cli/cli/package.json +4 -4
  81. package/zova/packages-cli/cli-set-front/package.json +2 -2
  82. package/zova/packages-cli/cli-set-front/src/lib/common/restDependencyVersions.ts +22 -1
  83. package/zova/packages-cli/cli-set-front/test/restDependencies.test.ts +137 -0
  84. package/zova/packages-zova/zova/package.json +2 -2
  85. package/zova/pnpm-lock.yaml +448 -641
  86. package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
  87. package/zova/src/suite-vendor/a-zova/package.json +2 -2
@@ -0,0 +1,389 @@
1
+ import { getRequestBoundary } from './requestBoundary.ts';
2
+
3
+ declare const capabilityBrand: unique symbol;
4
+ export interface ExistingReadyCapability {
5
+ readonly [capabilityBrand]: true;
6
+ }
7
+
8
+ export interface CompletedReadiness {
9
+ snapshot(): Readonly<{ application: 'starting' | 'ready' | 'failed' | 'closing' }>;
10
+ }
11
+
12
+ interface RegistryRow {
13
+ readonly id: number;
14
+ readonly name: string;
15
+ readonly disabled: boolean;
16
+ readonly isolate: boolean;
17
+ readonly config: string | null;
18
+ }
19
+
20
+ interface Provision {
21
+ readonly registry: object;
22
+ readonly route: object;
23
+ readonly handle: object;
24
+ readonly isolate: boolean;
25
+ readonly functions: ReadonlySet<Function>;
26
+ }
27
+
28
+ interface Publication {
29
+ readonly attempt: object;
30
+ readonly provision: Provision;
31
+ readonly row: RegistryRow;
32
+ readonly config: object;
33
+ }
34
+
35
+ interface Owner {
36
+ readonly app: object;
37
+ application: 'starting' | 'ready' | 'failed' | 'closing';
38
+ applicationAttempt: object;
39
+ readonly attempts: Map<string, object>;
40
+ readonly provisions: Map<string, Provision>;
41
+ readonly publications: Map<string, Publication>;
42
+ }
43
+
44
+ const owners = new WeakMap<CompletedReadiness, Owner>();
45
+ const capabilities = new WeakMap<
46
+ ExistingReadyCapability,
47
+ { owner: CompletedReadiness; publication: Publication; deadline: number; now: () => number }
48
+ >();
49
+ const captures = new WeakSet<object>();
50
+ const pins = new WeakMap<object, Publication>();
51
+
52
+ export function createCompletedReadiness(appIdentity: object): CompletedReadiness {
53
+ const state: Owner = {
54
+ app: appIdentity,
55
+ application: 'starting',
56
+ applicationAttempt: Object.freeze({}),
57
+ attempts: new Map(),
58
+ provisions: new Map(),
59
+ publications: new Map(),
60
+ };
61
+ const facade = Object.freeze({
62
+ snapshot: () => Object.freeze({ application: state.application }),
63
+ });
64
+ owners.set(facade, state);
65
+ return facade;
66
+ }
67
+
68
+ // Internal framework integration only. None of the issuance/provisioning helpers are barrel exports.
69
+ export function beginCompletedApplication(owner: CompletedReadiness): object {
70
+ const state = owners.get(owner)!;
71
+ state.publications.clear();
72
+ state.attempts.clear();
73
+ state.applicationAttempt = Object.freeze({});
74
+ if (state.application !== 'closing') state.application = 'starting';
75
+ return state.applicationAttempt;
76
+ }
77
+
78
+ export function finishCompletedApplication(
79
+ owner: CompletedReadiness,
80
+ attempt: object,
81
+ success: boolean,
82
+ ): void {
83
+ const state = owners.get(owner)!;
84
+ if (state.application === 'closing' || state.applicationAttempt !== attempt) return;
85
+ state.application = success ? 'ready' : 'failed';
86
+ if (!success) state.publications.clear();
87
+ }
88
+
89
+ export function closeCompletedReadiness(owner: CompletedReadiness): void {
90
+ const state = owners.get(owner)!;
91
+ state.application = 'closing';
92
+ state.publications.clear();
93
+ state.attempts.clear();
94
+ }
95
+
96
+ export function invalidateCompletedInstance(
97
+ owner: CompletedReadiness | undefined,
98
+ name: string,
99
+ ): void {
100
+ if (!owner) return;
101
+ const state = owners.get(owner)!;
102
+ state.attempts.set(name, Object.freeze({}));
103
+ state.publications.delete(name);
104
+ }
105
+
106
+ export function beginCompletedInstance(
107
+ owner: CompletedReadiness | undefined,
108
+ name: string,
109
+ ): object | undefined {
110
+ if (!owner) return;
111
+ invalidateCompletedInstance(owner, name);
112
+ return owners.get(owner)!.attempts.get(name);
113
+ }
114
+
115
+ function rowCopy(value: unknown): RegistryRow | undefined {
116
+ if (!value || typeof value !== 'object') return;
117
+ const fields = ['id', 'name', 'disabled', 'isolate', 'config'];
118
+ const data: Record<string, unknown> = Object.create(null);
119
+ for (const key of fields) {
120
+ const desc = Object.getOwnPropertyDescriptor(value, key);
121
+ if (!desc || !('value' in desc)) return;
122
+ data[key] = desc.value;
123
+ }
124
+ if (
125
+ typeof data.id !== 'number' ||
126
+ !Number.isSafeInteger(data.id) ||
127
+ data.id <= 0 ||
128
+ typeof data.name !== 'string' ||
129
+ !data.name.isWellFormed() ||
130
+ data.name.includes('\0') ||
131
+ Buffer.byteLength(data.name) > 256 ||
132
+ data.disabled !== false ||
133
+ typeof data.isolate !== 'boolean' ||
134
+ !(
135
+ data.config === null ||
136
+ (typeof data.config === 'string' &&
137
+ data.config.isWellFormed() &&
138
+ Buffer.byteLength(data.config) <= 65_536)
139
+ )
140
+ ) {
141
+ return;
142
+ }
143
+ return Object.freeze(data) as unknown as RegistryRow;
144
+ }
145
+
146
+ function detach(
147
+ value: unknown,
148
+ functions: ReadonlySet<Function>,
149
+ active = new Set<object>(),
150
+ depth = 0,
151
+ budget = { nodes: 0 },
152
+ ): unknown {
153
+ if (++budget.nodes > 100_000 || depth > 64)
154
+ throw new Error('Unsupported completed configuration');
155
+ if (
156
+ value === null ||
157
+ value === undefined ||
158
+ typeof value === 'string' ||
159
+ typeof value === 'boolean' ||
160
+ (typeof value === 'number' && Number.isFinite(value))
161
+ ) {
162
+ return value;
163
+ }
164
+ if (typeof value === 'function') {
165
+ if (!functions.has(value) || !Object.isFrozen(value))
166
+ throw new Error('Unsupported completed configuration');
167
+ for (const key of Reflect.ownKeys(value)) {
168
+ const desc = Object.getOwnPropertyDescriptor(value, key)!;
169
+ if (
170
+ !('value' in desc) ||
171
+ desc.writable ||
172
+ (desc.value && (typeof desc.value === 'object' || typeof desc.value === 'function'))
173
+ ) {
174
+ throw new Error('Unsupported completed configuration');
175
+ }
176
+ }
177
+ return value;
178
+ }
179
+ if (typeof value !== 'object' || !value || active.has(value))
180
+ throw new Error('Unsupported completed configuration');
181
+ const array = Array.isArray(value);
182
+ const proto = Object.getPrototypeOf(value);
183
+ if (
184
+ (!array && proto !== Object.prototype && proto !== null) ||
185
+ (array && proto !== Array.prototype)
186
+ ) {
187
+ throw new Error('Unsupported completed configuration');
188
+ }
189
+ active.add(value);
190
+ const result = array ? [] : Object.create(null);
191
+ for (const key of Reflect.ownKeys(value)) {
192
+ if (array && key === 'length') continue;
193
+ if (typeof key !== 'string') throw new Error('Unsupported completed configuration');
194
+ const desc = Object.getOwnPropertyDescriptor(value, key)!;
195
+ if (!('value' in desc)) throw new Error('Unsupported completed configuration');
196
+ Object.defineProperty(result, key, {
197
+ value: detach(desc.value, functions, active, depth + 1, budget),
198
+ enumerable: desc.enumerable,
199
+ configurable: false,
200
+ writable: false,
201
+ });
202
+ }
203
+ if (array) Object.defineProperty(result, 'length', { value: (value as unknown[]).length });
204
+ active.delete(value);
205
+ return Object.freeze(result);
206
+ }
207
+
208
+ // Controlled inert qualification seam. Production provisioning is intentionally not supplied.
209
+ export function provisionCompletedInstanceForTest(
210
+ owner: CompletedReadiness,
211
+ name: string,
212
+ input: {
213
+ readonly registry: object;
214
+ readonly route: object;
215
+ readonly handle: object;
216
+ readonly isolate: boolean;
217
+ readonly functions?: readonly Function[];
218
+ },
219
+ ): void {
220
+ if (getRequestBoundary()) throw new Error('Provisioning requires lifecycle boundary');
221
+ const state = owners.get(owner)!;
222
+ invalidateCompletedInstance(owner, name);
223
+ state.provisions.set(
224
+ name,
225
+ Object.freeze({ ...input, functions: new Set(input.functions ?? []) }),
226
+ );
227
+ }
228
+
229
+ export function captureCompletedInstance(
230
+ owner: CompletedReadiness | undefined,
231
+ name: string,
232
+ attempt: object | undefined,
233
+ row: unknown,
234
+ config: unknown,
235
+ ): object | undefined {
236
+ if (!owner || !attempt) return;
237
+ const state = owners.get(owner)!;
238
+ const provision = state.provisions.get(name);
239
+ if (!provision || state.application === 'closing' || state.attempts.get(name) !== attempt) return;
240
+ try {
241
+ const capturedRow = rowCopy(row);
242
+ if (!capturedRow || capturedRow.name !== name || capturedRow.isolate !== provision.isolate)
243
+ return;
244
+ const snapshot = detach(config, provision.functions);
245
+ if (!snapshot || typeof snapshot !== 'object') return;
246
+ const captured = Object.freeze({ attempt, provision, row: capturedRow, config: snapshot });
247
+ captures.add(captured);
248
+ return captured;
249
+ } catch {
250
+ // Unsupported snapshots leave admission unavailable without inspecting the failure.
251
+ }
252
+ }
253
+
254
+ export function finishCompletedInstance(
255
+ owner: CompletedReadiness | undefined,
256
+ name: string,
257
+ attempt: object | undefined,
258
+ captured: object | undefined,
259
+ ): void {
260
+ if (!owner || !attempt || !captured || !captures.has(captured)) return;
261
+ const state = owners.get(owner)!;
262
+ const publication = captured as Publication;
263
+ if (
264
+ state.application !== 'closing' &&
265
+ state.application !== 'failed' &&
266
+ state.attempts.get(name) === attempt &&
267
+ publication.attempt === attempt &&
268
+ state.provisions.get(name) === publication.provision
269
+ ) {
270
+ state.publications.set(name, publication);
271
+ }
272
+ }
273
+
274
+ export function getCompletedPublication(
275
+ owner: CompletedReadiness,
276
+ name: string,
277
+ registry: object,
278
+ route: object,
279
+ ): object | undefined {
280
+ const state = owners.get(owner);
281
+ const publication = state?.publications.get(name);
282
+ if (
283
+ state?.application !== 'ready' ||
284
+ !publication ||
285
+ publication.provision.registry !== registry ||
286
+ publication.provision.route !== route
287
+ ) {
288
+ return;
289
+ }
290
+ return publication;
291
+ }
292
+
293
+ export function matchesCompletedRow(publication: object, row: unknown): boolean {
294
+ try {
295
+ const next = rowCopy(row),
296
+ prior = (publication as Publication).row;
297
+ return (
298
+ !!next &&
299
+ next.id === prior.id &&
300
+ next.name === prior.name &&
301
+ next.isolate === prior.isolate &&
302
+ next.config === prior.config
303
+ );
304
+ } catch {
305
+ return false;
306
+ }
307
+ }
308
+
309
+ export function issueExistingReadyCapability(
310
+ owner: CompletedReadiness,
311
+ publication: object,
312
+ deadline: number,
313
+ now: () => number,
314
+ ): ExistingReadyCapability {
315
+ if (!captures.has(publication)) throw new Error('Existing-ready unavailable');
316
+ const capability = Object.freeze({}) as ExistingReadyCapability;
317
+ capabilities.set(capability, { owner, publication: publication as Publication, deadline, now });
318
+ return capability;
319
+ }
320
+
321
+ export function resolveExistingReadyCapability(
322
+ owner: CompletedReadiness,
323
+ capability: ExistingReadyCapability,
324
+ app?: object,
325
+ ): { readonly publication: object; readonly name: string; readonly handle: object } | undefined {
326
+ const issued = capabilities.get(capability),
327
+ state = owners.get(owner);
328
+ if (
329
+ !issued ||
330
+ issued.owner !== owner ||
331
+ !state ||
332
+ state.application !== 'ready' ||
333
+ (app && app !== state.app)
334
+ ) {
335
+ return;
336
+ }
337
+ try {
338
+ const current = issued.now();
339
+ if (!Number.isFinite(current) || current >= issued.deadline) return;
340
+ } catch {
341
+ return;
342
+ }
343
+ const publication = issued.publication;
344
+ if (
345
+ state.publications.get(publication.row.name) !== publication ||
346
+ state.attempts.get(publication.row.name) !== publication.attempt
347
+ ) {
348
+ return;
349
+ }
350
+ return Object.freeze({
351
+ publication,
352
+ name: publication.row.name,
353
+ handle: publication.provision.handle,
354
+ });
355
+ }
356
+
357
+ export function pinExistingReadyContext(
358
+ owner: CompletedReadiness,
359
+ capability: ExistingReadyCapability,
360
+ app: object,
361
+ context: object,
362
+ ): boolean {
363
+ const resolved = resolveExistingReadyCapability(owner, capability, app);
364
+ if (!resolved || pins.has(context)) return false;
365
+ const publication = resolved.publication as Publication;
366
+ pins.set(context, publication);
367
+ for (const [key, value] of [
368
+ ['config', publication.config],
369
+ ['instance', publication.row],
370
+ ['instanceName', publication.row.name],
371
+ ['innerAccess', false],
372
+ ] as const) {
373
+ Object.defineProperty(context, key, {
374
+ value,
375
+ enumerable: true,
376
+ configurable: false,
377
+ writable: false,
378
+ });
379
+ }
380
+ return true;
381
+ }
382
+
383
+ export function getExistingReadyContextConfig(context: object): object | undefined {
384
+ return pins.get(context)?.config;
385
+ }
386
+
387
+ export function isExistingReadyContext(context: object | undefined | null): boolean {
388
+ return !!context && pins.has(context);
389
+ }
@@ -5,6 +5,7 @@ import type { MetadataKey } from './metadata.ts';
5
5
 
6
6
  import { cast } from '../../types/utils/cast.ts';
7
7
  import { BeanContainer } from '../bean/beanContainer.ts';
8
+ import { getExistingReadyContextConfig } from './completedReadiness.ts';
8
9
  import { appResource } from './resource.ts';
9
10
 
10
11
  const BEAN = Symbol.for('Context#__bean');
@@ -46,6 +47,8 @@ export const contextBase: ContextBase = {
46
47
  },
47
48
  get config() {
48
49
  const self = cast(this);
50
+ const pinned = getExistingReadyContextConfig(self);
51
+ if (pinned) return pinned as any;
49
52
  const serviceInstance = cast(self.app.bean._getBean('a-instance.service.instance' as never));
50
53
  return serviceInstance.getConfig(self.instanceName) || self.app.config;
51
54
  },
@@ -1,5 +1,16 @@
1
1
  export * from './application.ts';
2
2
  export * from './config.ts';
3
+ export {
4
+ beginCompletedInstance,
5
+ captureCompletedInstance,
6
+ createCompletedReadiness,
7
+ finishCompletedInstance,
8
+ invalidateCompletedInstance,
9
+ isExistingReadyContext,
10
+ pinExistingReadyContext,
11
+ resolveExistingReadyCapability,
12
+ } from './completedReadiness.ts';
13
+ export type { CompletedReadiness, ExistingReadyCapability } from './completedReadiness.ts';
3
14
  export * from './hmr.ts';
4
15
  export * from './hmrDeps.ts';
5
16
  export * from './isolationGuard.ts';
@@ -14,6 +14,7 @@ import type {
14
14
  import { BeanSimple } from '../../bean/beanSimple.ts';
15
15
  import { deepExtend } from '../../utils/util.ts';
16
16
  import { getRequestBoundary } from '../requestBoundary.ts';
17
+ import { requiresFreshTestResources } from '../testStrictMode.ts';
17
18
  import { createDiagnosticLogger, getSuppressedDiagnosticLogger } from './diagnosticLogger.ts';
18
19
 
19
20
  const SymbolLoggerInstances = Symbol('SymbolLoggerInstances');
@@ -31,7 +32,9 @@ export class AppLogger extends BeanSimple {
31
32
  }
32
33
 
33
34
  get(clientName?: keyof ILoggerClientRecord) {
34
- if (getRequestBoundary()) return getSuppressedDiagnosticLogger();
35
+ if (requiresFreshTestResources() || getRequestBoundary()) {
36
+ return getSuppressedDiagnosticLogger();
37
+ }
35
38
  clientName = clientName || 'default';
36
39
  if (!this[SymbolLoggerInstances][clientName]) {
37
40
  const raw = this._createClient(clientName);
@@ -42,7 +45,9 @@ export class AppLogger extends BeanSimple {
42
45
  }
43
46
 
44
47
  child(childName?: keyof ILoggerChildRecord, clientName?: keyof ILoggerClientRecord) {
45
- if (getRequestBoundary()) return getSuppressedDiagnosticLogger();
48
+ if (requiresFreshTestResources() || getRequestBoundary()) {
49
+ return getSuppressedDiagnosticLogger();
50
+ }
46
51
  const logger = this.get(clientName);
47
52
  if (!childName) return logger;
48
53
  return logger.child({ name: childName });
@@ -120,6 +125,9 @@ export class AppLogger extends BeanSimple {
120
125
  | Winston.transports.FileTransportOptions
121
126
  | DailyRotateFile.DailyRotateFileTransportOptions,
122
127
  ) {
128
+ if (requiresFreshTestResources()) {
129
+ throw new Error('Strict test file logger transport is disabled');
130
+ }
123
131
  const dirname = this.app.config.logger.baseDir;
124
132
  if (!fse.existsSync(dirname)) {
125
133
  const [_, err] = catchErrorSync(() => {