@gaonjs/config 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/testkit.js CHANGED
@@ -13,6 +13,7 @@ import { loadGaonConfig } from './load.js';
13
13
  import { configureNonDbBatteries } from './wire.js';
14
14
  import { resetStorage } from '@gaonjs/storage';
15
15
  import { resetI18n } from '@gaonjs/i18n';
16
+ import { connectNats, configureJobs, configureEvents, configureBroadcast, resetJobs, resetEvents, resetBroadcast, } from '@gaonjs/async';
16
17
  import { createDb, registerConnection, deriveTestDatabaseConfig, destroyAllConnections, } from '@gaonjs/data';
17
18
  /**
18
19
  * 테스트용 DB 커넥션 + DB 외 배터리(mail·storage·i18n)를 배선한다(결정 111·136).
@@ -33,11 +34,28 @@ export async function connectTestDatabase(cwd = process.cwd()) {
33
34
  bucketFor: (b) => `${b}-test`,
34
35
  localRootFor: (r) => `${r}-test`,
35
36
  });
37
+ // 결정 143(12차 W5): 잡·이벤트 전송을 serve·work 와 같은 경로로 배선한다. 이게 없으면
38
+ // 테스트에서 도는 도메인 서비스가 `.later()`·emit() 를 할 때 "전송 미설정" 으로 깨졌다 —
39
+ // 운영과 같은 코드가 테스트에서만 실패하는 사각(11차 W4 연장). 스트림/subject 격리는
40
+ // GAON_STREAM_PREFIX(결정 130 · gaon test 가 세팅)로 자동 적용된다.
41
+ let nats;
42
+ if (config.nats) {
43
+ nats = await connectNats({ servers: config.nats.url, name: config.nats.name ?? 'gaon-test' });
44
+ configureJobs(nats);
45
+ configureEvents(nats);
46
+ configureBroadcast(nats); // 결정 126: 잡·리스너에서 broadcast() 사용.
47
+ }
36
48
  return {
37
49
  close: async () => {
38
50
  await destroyAllConnections();
39
51
  resetStorage();
40
52
  resetI18n();
53
+ // 잡·이벤트·broadcast 배선 해제 후 NATS 종료(다음 테스트 파일로 상태 누출 방지).
54
+ resetJobs();
55
+ resetEvents();
56
+ resetBroadcast();
57
+ if (nats)
58
+ await nats.close();
41
59
  },
42
60
  };
43
61
  }
package/dist/wire.js CHANGED
@@ -7,8 +7,8 @@
7
7
  // 세션은 세션 옵션이 세팅된 앱에만 등록된다. AppSessionOptions.secret 은
8
8
  // 필수이므로 auth 앱은 명시적으로 secret 을 제공해야 한다(env 로 주입 권장).
9
9
  import { Redis } from 'ioredis';
10
- import { createDb, registerConnection, destroyAllConnections, } from '@gaonjs/data';
11
- import { connectNats, configureJobs } from '@gaonjs/async';
10
+ import { createDb, registerConnection, destroyAllConnections, getConnection, hasConnection, setServiceTxWrapper, } from '@gaonjs/data';
11
+ import { connectNats, configureJobs, configureEvents, outboxServiceTxWrapper, ensureOutboxTable, } from '@gaonjs/async';
12
12
  import { configureMailer, smtpTransport } from '@gaonjs/mail';
13
13
  import { configureStorage, localDisk, s3Disk, resetStorage } from '@gaonjs/storage';
14
14
  import { configureI18n, loadLocales, resetI18n } from '@gaonjs/i18n';
@@ -125,15 +125,22 @@ export async function wireGaon(config, cwd = process.cwd()) {
125
125
  if (config.redis) {
126
126
  redis = new Redis(config.redis.url, { lazyConnect: false, maxRetriesPerRequest: 3 });
127
127
  }
128
- // 3) NATS — 웹 프로세스도 채널·잡 publish 를 위해 연결한다.
129
- // 연결만으로는 부족하다 — 전송 런타임(configureJobs)까지 배선해야
130
- // 컨트롤러의 `.later()` 실제로 publish 된다. 이걸 빠뜨리면 웹에서
131
- // 발행 "잡 전송이 설정되지 않았습니다" 로 깨진다(work 는 runWork
132
- // 가 이미 설정하지만 serve 는 여기서 해야 한다).
128
+ // 3) NATS — 웹 프로세스도 채널·잡·이벤트 publish 를 위해 연결한다.
129
+ // 연결만으로는 부족하다 — 전송 런타임까지 배선해야 컨트롤러·서비스의
130
+ // `.later()`·`emit()` 실제로 publish 된다(work runWork 가 이미 설정하지만
131
+ // serve 여기서 해야 한다).
133
132
  let nats;
134
133
  if (config.nats) {
135
134
  nats = await connectNats({ servers: config.nats.url, name: config.nats.name ?? 'gaon-serve' });
136
135
  configureJobs(nats);
136
+ // 결정 144(F2a): 이벤트 전송 배선 — 이게 없으면 웹 요청 emit() 이 "전송 미설정" 500.
137
+ configureEvents(nats);
138
+ // 결정 144(A): 서비스 트랜잭션 emit → 같은 트랜잭션으로 _gaon_outbox 적재(이중 쓰기
139
+ // 방지). @gaonjs/async 의 아웃박스 래퍼를 data 의 service() 트랜잭션에 주입하고,
140
+ // 적재 대상 테이블을 main 커넥션에 보장한다(worker 의 릴레이가 그 행을 발행한다).
141
+ setServiceTxWrapper(outboxServiceTxWrapper());
142
+ if (hasConnection('main'))
143
+ await ensureOutboxTable(getConnection('main'));
137
144
  }
138
145
  // 5) 앱 스캔 · createApp.
139
146
  const apps = await resolveApps(root);
@@ -208,6 +215,8 @@ export async function wireGaon(config, cwd = process.cwd()) {
208
215
  await nats.close();
209
216
  if (redis)
210
217
  redis.disconnect();
218
+ // 결정 144: 서비스 트랜잭션 래퍼 배선 해제(다음 wireGaon 인스턴스로 누출 방지).
219
+ setServiceTxWrapper(undefined);
211
220
  await domain.closeDomain();
212
221
  },
213
222
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gaonjs/config",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Gaon 루트 설정 로더·자동 배선 (gaon.config.ts · §3.3 · M9-A)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -25,13 +25,13 @@
25
25
  ],
26
26
  "dependencies": {
27
27
  "ioredis": "^5.4.1",
28
- "@gaonjs/async": "0.8.0",
28
+ "@gaonjs/async": "0.9.0",
29
29
  "@gaonjs/core": "0.2.1",
30
- "@gaonjs/data": "0.14.0",
31
30
  "@gaonjs/i18n": "0.1.2",
31
+ "@gaonjs/data": "0.15.0",
32
32
  "@gaonjs/mail": "0.1.3",
33
- "@gaonjs/web": "0.14.0",
34
- "@gaonjs/storage": "0.1.2"
33
+ "@gaonjs/storage": "0.1.2",
34
+ "@gaonjs/web": "0.15.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "fastify": "^5.0.0"