@exabugs/dynamodb-client 1.10.0 → 1.11.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -0
  3. package/dist/notify/channels/email.d.ts +32 -0
  4. package/dist/notify/channels/email.d.ts.map +1 -0
  5. package/dist/notify/channels/email.js +67 -0
  6. package/dist/notify/channels/email.js.map +1 -0
  7. package/dist/notify/channels/slack.d.ts +12 -0
  8. package/dist/notify/channels/slack.d.ts.map +1 -0
  9. package/dist/notify/channels/slack.js +46 -0
  10. package/dist/notify/channels/slack.js.map +1 -0
  11. package/dist/notify/format.d.ts +7 -0
  12. package/dist/notify/format.d.ts.map +1 -0
  13. package/dist/notify/format.js +29 -0
  14. package/dist/notify/format.js.map +1 -0
  15. package/dist/notify/handler.d.ts +42 -0
  16. package/dist/notify/handler.d.ts.map +1 -0
  17. package/dist/notify/handler.js +175 -0
  18. package/dist/notify/handler.js.map +1 -0
  19. package/dist/notify/index.d.ts +18 -0
  20. package/dist/notify/index.d.ts.map +1 -0
  21. package/dist/notify/index.js +14 -0
  22. package/dist/notify/index.js.map +1 -0
  23. package/dist/notify/logger.d.ts +6 -0
  24. package/dist/notify/logger.d.ts.map +1 -0
  25. package/dist/notify/logger.js +11 -0
  26. package/dist/notify/logger.js.map +1 -0
  27. package/dist/notify/normalize.d.ts +11 -0
  28. package/dist/notify/normalize.d.ts.map +1 -0
  29. package/dist/notify/normalize.js +245 -0
  30. package/dist/notify/normalize.js.map +1 -0
  31. package/dist/notify/policy.d.ts +15 -0
  32. package/dist/notify/policy.d.ts.map +1 -0
  33. package/dist/notify/policy.js +36 -0
  34. package/dist/notify/policy.js.map +1 -0
  35. package/dist/notify/store.d.ts +22 -0
  36. package/dist/notify/store.d.ts.map +1 -0
  37. package/dist/notify/store.js +119 -0
  38. package/dist/notify/store.js.map +1 -0
  39. package/dist/notify/types.d.ts +63 -0
  40. package/dist/notify/types.d.ts.map +1 -0
  41. package/dist/notify/types.js +8 -0
  42. package/dist/notify/types.js.map +1 -0
  43. package/dist/server/handler.cjs +3 -3
  44. package/dist/server/media-handler.cjs +2 -2
  45. package/dist/server/media-process-handler-dlq.cjs +2 -2
  46. package/dist/server/media-process-handler.cjs +2 -2
  47. package/dist/sharp-layer.zip +0 -0
  48. package/docs/NOTIFY.md +103 -0
  49. package/package.json +8 -3
@@ -0,0 +1,245 @@
1
+ /**
2
+ * 入力の正規化: CloudWatch Logs の購読 / EventBridge のアラーム状態変化 / 直接呼び出し → Notice[]
3
+ *
4
+ * ログ行の形は 3 種類ある。
5
+ * 1. アプリの JSON 1 行: {"level":"warn","message":"…","event":"…"}
6
+ * 2. Lambda のテキスト形式: `時刻<TAB>RequestId<TAB>INFO<TAB>{アプリの JSON}`
7
+ * 3. Lambda の JSON 形式: {"timestamp":…,"level":"INFO","requestId":…,"message":"{アプリの JSON 文字列}"}
8
+ * アプリの JSON が見つかれば、その level とフィールドを優先する(外側の level は Lambda のもので、
9
+ * console.log で出した warn は INFO になる)。
10
+ */
11
+ import { gunzipSync } from 'node:zlib';
12
+ import { clean, cleanLine } from './policy.js';
13
+ const LEVELS = new Map([
14
+ ['warn', 'warn'],
15
+ ['warning', 'warn'],
16
+ ['error', 'error'],
17
+ ['fatal', 'fatal'],
18
+ ['critical', 'fatal'],
19
+ ]);
20
+ /** level の値(任意の文字列)から通知レベルを引く。`constructor` などの名前は無視する */
21
+ const levelOf = (v) => typeof v === 'string' ? LEVELS.get(v.toLowerCase()) : undefined;
22
+ /** Lambda の実行基盤の、致命的な失敗(アプリの JSON ログにならない) */
23
+ const LAMBDA_FAILURE_LINE = /^(?:\S+\s+[0-9a-fA-F-]{8,}\s+|RequestId: \S+\s+(?:Error: )?)?(Task timed out after [\d.]+ seconds|Runtime exited (?:with error|without error)|Process exited before completing request)/;
24
+ /** `REPORT …` 行の、失敗の状態 */
25
+ const REPORT_FAILURE = /^REPORT RequestId:[\s\S]*\bStatus: (timeout|error|failure)\b/;
26
+ const LAMBDA_FAILURE_LABEL = /^(Invoke Error|Unhandled Promise Rejection|Uncaught Exception)\b/;
27
+ /** `時刻<TAB>RequestId<TAB>LEVEL<TAB>本文`(テキスト形式)。本文と外側の level を分ける */
28
+ const TEXT_PREFIX = /^\S+\t(?:[0-9a-fA-F-]{8,}|undefined)\t(TRACE|DEBUG|INFO|WARN|ERROR|FATAL)\t([\s\S]*)$/;
29
+ function asObj(text) {
30
+ const t = text.trim();
31
+ if (!t.startsWith('{'))
32
+ return undefined;
33
+ try {
34
+ const v = JSON.parse(t);
35
+ return typeof v === 'object' && v !== null && !Array.isArray(v) ? v : undefined;
36
+ }
37
+ catch {
38
+ return undefined;
39
+ }
40
+ }
41
+ const str = (v) => (typeof v === 'string' ? v : undefined);
42
+ const isAppLog = (o) => typeof o.level === 'string' || typeof o.event === 'string';
43
+ function parseLine(line) {
44
+ let body = line;
45
+ let outerLevel;
46
+ const m = TEXT_PREFIX.exec(line);
47
+ if (m) {
48
+ outerLevel = m[1];
49
+ body = m[2];
50
+ }
51
+ // Invoke Error など: `ラベル<TAB>{json}`
52
+ const tab = body.indexOf('\t{');
53
+ if (tab > 0 && !body.trimStart().startsWith('{')) {
54
+ const json = asObj(body.slice(tab + 1));
55
+ if (json && typeof json.errorType === 'string') {
56
+ return { runtime: json, text: body.slice(0, tab), outerLevel };
57
+ }
58
+ }
59
+ const outer = asObj(body);
60
+ if (!outer)
61
+ return { text: body, outerLevel };
62
+ // Lambda のシステムログ(JSON 形式): {"type":"platform.report","record":{"status":"timeout"}}
63
+ if (typeof outer.type === 'string' && /^platform\.(report|runtimeDone)$/.test(outer.type)) {
64
+ const status = str(outer.record?.status);
65
+ return { text: '', platformStatus: status, outerLevel };
66
+ }
67
+ // Lambda の JSON 形式: {"timestamp":…,"level":"INFO","requestId":…,"message":…}
68
+ // Lambda の level は大文字(createLogger は小文字)。event を持つアプリのログは、外側として扱わない
69
+ const lambdaWrapped = 'timestamp' in outer &&
70
+ typeof outer.level === 'string' &&
71
+ /^(TRACE|DEBUG|INFO|WARN|ERROR|FATAL)$/.test(outer.level) &&
72
+ !('event' in outer);
73
+ if (lambdaWrapped) {
74
+ const level = str(outer.level);
75
+ const msg = outer.message;
76
+ // アプリの JSON 文字列が message に入っている
77
+ const inner = typeof msg === 'string' ? asObj(msg) : undefined;
78
+ if (inner && isAppLog(inner))
79
+ return { app: inner, text: '', outerLevel: level };
80
+ // エラーのオブジェクト(Invoke Error など)
81
+ const errObj = typeof msg === 'object' && msg !== null ? msg : undefined;
82
+ const withType = typeof outer.errorType === 'string'
83
+ ? outer
84
+ : errObj && typeof errObj.errorType === 'string'
85
+ ? errObj
86
+ : undefined;
87
+ if (withType) {
88
+ return { runtime: withType, text: typeof msg === 'string' ? msg : '', outerLevel: level };
89
+ }
90
+ const text = typeof msg === 'string' ? msg : errObj ? JSON.stringify(errObj) : '';
91
+ return { text, outerLevel: level };
92
+ }
93
+ return { app: outer, text: '', outerLevel };
94
+ }
95
+ function failure(message, ctx, occurredAt, target) {
96
+ return {
97
+ level: 'fatal',
98
+ event: 'LAMBDA_FAILURE',
99
+ message: clean(message, 500) ?? 'Lambda の失敗',
100
+ target: cleanLine(target, 100),
101
+ app: ctx.app,
102
+ env: ctx.env,
103
+ occurredAt,
104
+ suppressed: 0,
105
+ };
106
+ }
107
+ /** ログ 1 行 → Notice(通知対象でなければ undefined) */
108
+ export function noticeFromLogLine(line, ctx, at) {
109
+ const t = at !== undefined && Number.isFinite(at) ? new Date(at) : ctx.now();
110
+ const occurredAt = (Number.isNaN(t.getTime()) ? ctx.now() : t).toISOString();
111
+ const p = parseLine(line);
112
+ const outer = p.outerLevel ? levelOf(p.outerLevel) : undefined;
113
+ if (p.platformStatus && /^(timeout|error|failure)$/.test(p.platformStatus)) {
114
+ return failure(`Lambda の実行が失敗しました(status: ${p.platformStatus})`, ctx, occurredAt);
115
+ }
116
+ if (p.runtime) {
117
+ const label = p.text.trim();
118
+ const type = str(p.runtime.errorType) ?? '';
119
+ const labelled = LAMBDA_FAILURE_LABEL.test(label);
120
+ // ラベル付き、または Runtime.* で外側の level が warn 以上のもの。それ以外は、通常の行として扱う
121
+ if (labelled || (/^Runtime\./.test(type) && outer !== undefined)) {
122
+ return failure(`${type}: ${str(p.runtime.errorMessage) ?? label}`, ctx, occurredAt, type);
123
+ }
124
+ }
125
+ if (p.app) {
126
+ const level = levelOf(p.app.level) ?? outer;
127
+ if (!level)
128
+ return undefined;
129
+ const target = [p.app.resource, p.app.target].find((v) => typeof v === 'string');
130
+ const actions = Array.isArray(p.app.actions)
131
+ ? p.app.actions.filter((a) => typeof a === 'string').join(' / ')
132
+ : undefined;
133
+ const message = clean(p.app.message, 500) ?? '(メッセージなし)';
134
+ const event = cleanLine(p.app.event, 100);
135
+ return {
136
+ level,
137
+ event: event ?? `LOG_${level.toUpperCase()}`,
138
+ message,
139
+ app: ctx.app,
140
+ env: ctx.env,
141
+ // event の無いログは、種類を区別できないので、メッセージの先頭で指紋を分ける(別々のエラーを 1 つにしない)
142
+ target: cleanLine(target, 200) ?? (event ? undefined : cleanLine(message, 60)),
143
+ action: clean(str(p.app.action) ?? actions, 500),
144
+ occurredAt,
145
+ suppressed: 0,
146
+ };
147
+ }
148
+ let text = p.text.trim();
149
+ // errorType つきの JSON で、失敗と判定しなかったもの: 外側の level が warn 以上なら、通常のエラーとして通知する
150
+ if (p.runtime && text === '') {
151
+ text = `${str(p.runtime.errorType) ?? 'Error'}: ${str(p.runtime.errorMessage) ?? ''}`.trim();
152
+ }
153
+ if (LAMBDA_FAILURE_LINE.test(text) || REPORT_FAILURE.test(text)) {
154
+ return failure(text, ctx, occurredAt);
155
+ }
156
+ // アプリの JSON ではない行(console.error の文字列など)は、外側の level が warn 以上のときだけ
157
+ if (outer && text !== '') {
158
+ return {
159
+ level: outer,
160
+ event: `LOG_${outer.toUpperCase()}`,
161
+ message: clean(text, 500) ?? '(メッセージなし)',
162
+ app: ctx.app,
163
+ env: ctx.env,
164
+ target: cleanLine(text, 60),
165
+ occurredAt,
166
+ suppressed: 0,
167
+ };
168
+ }
169
+ return undefined;
170
+ }
171
+ function fromLogs(event, ctx) {
172
+ const payload = JSON.parse(gunzipSync(Buffer.from(event.awslogs.data, 'base64')).toString('utf8'));
173
+ const out = [];
174
+ for (const e of payload.logEvents ?? []) {
175
+ // 1 行の失敗で、同じバッチの他の行を失わない
176
+ try {
177
+ if (typeof e?.message !== 'string')
178
+ continue;
179
+ const n = noticeFromLogLine(e.message, ctx, e.timestamp);
180
+ if (n)
181
+ out.push(n);
182
+ }
183
+ catch {
184
+ continue;
185
+ }
186
+ }
187
+ return out;
188
+ }
189
+ function validTime(t, fallback) {
190
+ if (typeof t !== 'string')
191
+ return fallback.toISOString();
192
+ const d = new Date(t);
193
+ return Number.isNaN(d.getTime()) ? fallback.toISOString() : d.toISOString();
194
+ }
195
+ function fromAlarm(event, ctx) {
196
+ const name = cleanLine(event.detail?.alarmName, 200);
197
+ const state = event.detail?.state?.value;
198
+ if (!name || (state !== 'ALARM' && state !== 'OK'))
199
+ return [];
200
+ return [
201
+ {
202
+ level: state === 'OK' ? 'ok' : 'error',
203
+ event: `ALARM:${name}`,
204
+ message: clean(event.detail?.state?.reason, 500) ??
205
+ (state === 'OK' ? 'アラームが復旧しました' : 'アラームが発生しました'),
206
+ app: ctx.app,
207
+ env: ctx.env,
208
+ occurredAt: validTime(event.time, ctx.now()),
209
+ suppressed: 0,
210
+ },
211
+ ];
212
+ }
213
+ function fromDirect(event, ctx) {
214
+ const n = event.notice;
215
+ const rawLevel = typeof n.level === 'string' ? n.level.toLowerCase() : 'warn';
216
+ const level = rawLevel === 'ok' ? 'ok' : (LEVELS.get(rawLevel) ?? 'warn');
217
+ return [
218
+ {
219
+ level,
220
+ event: cleanLine(n.event, 100) ?? 'DIRECT',
221
+ message: clean(n.message, 500) ?? '(メッセージなし)',
222
+ app: ctx.app,
223
+ env: ctx.env,
224
+ target: cleanLine(n.target, 200),
225
+ action: clean(n.action, 500),
226
+ occurredAt: ctx.now().toISOString(),
227
+ suppressed: 0,
228
+ },
229
+ ];
230
+ }
231
+ /** どの入力かを判別して Notice[] にする。未知の入力は空配列 */
232
+ export function normalize(event, ctx) {
233
+ if (typeof event !== 'object' || event === null)
234
+ return [];
235
+ const e = event;
236
+ if (typeof e.awslogs?.data === 'string') {
237
+ return fromLogs(e, ctx);
238
+ }
239
+ if (e['detail-type'] === 'CloudWatch Alarm State Change')
240
+ return fromAlarm(e, ctx);
241
+ if (typeof e.notice === 'object' && e.notice !== null)
242
+ return fromDirect(e, ctx);
243
+ return [];
244
+ }
245
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/notify/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAS/C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAsB;IAC1C,CAAC,MAAM,EAAE,MAAM,CAAC;IAChB,CAAC,SAAS,EAAE,MAAM,CAAC;IACnB,CAAC,OAAO,EAAE,OAAO,CAAC;IAClB,CAAC,OAAO,EAAE,OAAO,CAAC;IAClB,CAAC,UAAU,EAAE,OAAO,CAAC;CACtB,CAAC,CAAC;AACH,0DAA0D;AAC1D,MAAM,OAAO,GAAG,CAAC,CAAU,EAA2B,EAAE,CACtD,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAIlE,8CAA8C;AAC9C,MAAM,mBAAmB,GACvB,yLAAyL,CAAC;AAC5L,0BAA0B;AAC1B,MAAM,cAAc,GAAG,8DAA8D,CAAC;AACtF,MAAM,oBAAoB,GAAG,kEAAkE,CAAC;AAEhG,oEAAoE;AACpE,MAAM,WAAW,GACf,uFAAuF,CAAC;AAE1F,SAAS,KAAK,CAAC,IAAY;IACzB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACtB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,CAAC,GAAY,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,GAAG,GAAG,CAAC,CAAU,EAAsB,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAexF,MAAM,QAAQ,GAAG,CAAC,CAAM,EAAW,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC;AAEjG,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,IAAI,GAAG,IAAI,CAAC;IAChB,IAAI,UAA8B,CAAC;IACnC,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,CAAC;QACN,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;IACD,oCAAoC;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACxC,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC/C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,CAAC;QACjE,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAE9C,oFAAoF;IACpF,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,kCAAkC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1F,MAAM,MAAM,GAAG,GAAG,CAAE,KAAK,CAAC,MAA0B,EAAE,MAAM,CAAC,CAAC;QAC9D,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAC1D,CAAC;IAED,6EAA6E;IAC7E,oEAAoE;IACpE,MAAM,aAAa,GACjB,WAAW,IAAI,KAAK;QACpB,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;QAC/B,uCAAuC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QACzD,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,CAAC;IACtB,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC;QAC1B,gCAAgC;QAChC,MAAM,KAAK,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC/D,IAAI,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;QACjF,8BAA8B;QAC9B,MAAM,MAAM,GAAG,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC,CAAE,GAAW,CAAC,CAAC,CAAC,SAAS,CAAC;QAClF,MAAM,QAAQ,GACZ,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ;YACjC,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;gBAC9C,CAAC,CAAC,MAAM;gBACR,CAAC,CAAC,SAAS,CAAC;QAClB,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;QAC5F,CAAC;QACD,MAAM,IAAI,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACrC,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC;AAC9C,CAAC;AAED,SAAS,OAAO,CACd,OAAe,EACf,GAAqB,EACrB,UAAkB,EAClB,MAAe;IAEf,OAAO;QACL,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,gBAAgB;QACvB,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,YAAY;QAC5C,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC;QAC9B,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,UAAU;QACV,UAAU,EAAE,CAAC;KACd,CAAC;AACJ,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,iBAAiB,CAC/B,IAAY,EACZ,GAAqB,EACrB,EAAW;IAEX,MAAM,CAAC,GAAG,EAAE,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;IAC7E,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7E,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE/D,IAAI,CAAC,CAAC,cAAc,IAAI,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,EAAE,CAAC;QAC3E,OAAO,OAAO,CAAC,6BAA6B,CAAC,CAAC,cAAc,GAAG,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;IACpF,CAAC;IAED,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClD,8DAA8D;QAC9D,IAAI,QAAQ,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,SAAS,CAAC,EAAE,CAAC;YACjE,OAAO,OAAO,CAAC,GAAG,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,KAAK,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IAED,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;QACV,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;QAC5C,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7B,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;QACjF,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;YAC1C,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;YAC7E,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,WAAW,CAAC;QACzD,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC1C,OAAO;YACL,KAAK;YACL,KAAK,EAAE,KAAK,IAAI,OAAO,KAAK,CAAC,WAAW,EAAE,EAAE;YAC5C,OAAO;YACP,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,4DAA4D;YAC5D,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC9E,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,EAAE,GAAG,CAAC;YAChD,UAAU;YACV,UAAU,EAAE,CAAC;SACd,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACzB,yEAAyE;IACzE,IAAI,CAAC,CAAC,OAAO,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAC7B,IAAI,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;IAC/F,CAAC;IACD,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAChE,OAAO,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;IACxC,CAAC;IACD,kEAAkE;IAClE,IAAI,KAAK,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QACzB,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,OAAO,KAAK,CAAC,WAAW,EAAE,EAAE;YACnC,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,WAAW;YACxC,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;YAC3B,UAAU;YACV,UAAU,EAAE,CAAC;SACd,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAMD,SAAS,QAAQ,CAAC,KAAoC,EAAE,GAAqB;IAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CACxB,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CACxD,CAAC;IACjB,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;QACxC,yBAAyB;QACzB,IAAI,CAAC;YACH,IAAI,OAAO,CAAC,EAAE,OAAO,KAAK,QAAQ;gBAAE,SAAS;YAC7C,MAAM,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC;YACzD,IAAI,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAOD,SAAS,SAAS,CAAC,CAAU,EAAE,QAAc;IAC3C,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC,WAAW,EAAE,CAAC;IACzD,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;AAC9E,CAAC;AAED,SAAS,SAAS,CAAC,KAAiB,EAAE,GAAqB;IACzD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC;IACzC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9D,OAAO;QACL;YACE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;YACtC,KAAK,EAAE,SAAS,IAAI,EAAE;YACtB,OAAO,EACL,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC;gBACvC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC;YAClD,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,UAAU,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAC5C,UAAU,EAAE,CAAC;SACd;KACF,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,KAAsB,EAAE,GAAqB;IAC/D,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAC9E,MAAM,KAAK,GAAgB,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC;IACvF,OAAO;QACL;YACE,KAAK;YACL,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,QAAQ;YAC1C,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,WAAW;YAC7C,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC;YAChC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC;YAC5B,UAAU,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;YACnC,UAAU,EAAE,CAAC;SACd;KACF,CAAC;AACJ,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,SAAS,CAAC,KAAc,EAAE,GAAqB;IAC7D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAC3D,MAAM,CAAC,GAAG,KAAY,CAAC;IACvB,IAAI,OAAQ,CAAC,CAAC,OAA0C,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5E,OAAO,QAAQ,CAAC,CAAkC,EAAE,GAAG,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,CAAC,aAAa,CAAC,KAAK,+BAA+B;QAAE,OAAO,SAAS,CAAC,CAAe,EAAE,GAAG,CAAC,CAAC;IACjG,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI;QACnD,OAAO,UAAU,CAAC,CAAoB,EAAE,GAAG,CAAC,CAAC;IAC/C,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { Notice, NoticeLevel } from './types.js';
2
+ /** 重複抑制の窓(秒)。0 は抑制しない */
3
+ export declare const DEFAULT_WINDOWS: Record<NoticeLevel, number>;
4
+ /** 流量制限(チャネルごと): 窓の中で送る通知の上限。超えたら「省略」の 1 通だけ送る */
5
+ export declare const DEFAULT_RATE: {
6
+ windowSec: number;
7
+ limit: number;
8
+ };
9
+ /** 指紋: app・env・level・event・target。level を含める(warn の窓が、後の error を抑制しない) */
10
+ export declare function fingerprintOf(n: Pick<Notice, 'app' | 'env' | 'level' | 'event' | 'target'>): string;
11
+ /** 本文用: 制御文字を除き、長さを制限する(外部への送信に、長いログや不正な文字を持ち出さない) */
12
+ export declare function clean(value: unknown, max: number): string | undefined;
13
+ /** 1 行の値用(event・target・件名): 改行・タブも空白にする */
14
+ export declare function cleanLine(value: unknown, max: number): string | undefined;
15
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/notify/policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEtD,yBAAyB;AACzB,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAKvD,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,YAAY;;;CAAgC,CAAC;AAE1D,0EAA0E;AAC1E,wBAAgB,aAAa,CAC3B,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC,GAC5D,MAAM,CAER;AAaD,sDAAsD;AACtD,wBAAgB,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGrE;AAED,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzE"}
@@ -0,0 +1,36 @@
1
+ /** 重複抑制の窓(秒)。0 は抑制しない */
2
+ export const DEFAULT_WINDOWS = {
3
+ warn: 3600,
4
+ error: 600,
5
+ fatal: 0,
6
+ ok: 0,
7
+ };
8
+ /** 流量制限(チャネルごと): 窓の中で送る通知の上限。超えたら「省略」の 1 通だけ送る */
9
+ export const DEFAULT_RATE = { windowSec: 600, limit: 20 };
10
+ /** 指紋: app・env・level・event・target。level を含める(warn の窓が、後の error を抑制しない) */
11
+ export function fingerprintOf(n) {
12
+ return [n.app, n.env, n.level, n.event, n.target ?? ''].join('#').slice(0, 512);
13
+ }
14
+ /** 改行・タブ以外の制御文字と、表示の向きを変える文字(U+202A〜202E, U+2066〜2069) */
15
+ const CONTROL = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f\u202a-\u202e\u2066-\u2069]/g;
16
+ /** 1 行の値では、改行・タブも空白にする */
17
+ const LINE_BREAKS = /[\r\n\t\u2028\u2029]+/g;
18
+ function limit(s, max) {
19
+ const t = s.trim();
20
+ if (t === '')
21
+ return undefined;
22
+ return t.length > max ? `${t.slice(0, max)}…` : t;
23
+ }
24
+ /** 本文用: 制御文字を除き、長さを制限する(外部への送信に、長いログや不正な文字を持ち出さない) */
25
+ export function clean(value, max) {
26
+ if (typeof value !== 'string')
27
+ return undefined;
28
+ return limit(value.replace(CONTROL, ' '), max);
29
+ }
30
+ /** 1 行の値用(event・target・件名): 改行・タブも空白にする */
31
+ export function cleanLine(value, max) {
32
+ if (typeof value !== 'string')
33
+ return undefined;
34
+ return limit(value.replace(CONTROL, ' ').replace(LINE_BREAKS, ' '), max);
35
+ }
36
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/notify/policy.ts"],"names":[],"mappings":"AAEA,yBAAyB;AACzB,MAAM,CAAC,MAAM,eAAe,GAAgC;IAC1D,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,GAAG;IACV,KAAK,EAAE,CAAC;IACR,EAAE,EAAE,CAAC;CACN,CAAC;AAEF,kDAAkD;AAClD,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAE1D,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAC3B,CAA6D;IAE7D,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAClF,CAAC;AAED,0DAA0D;AAC1D,MAAM,OAAO,GAAG,2EAA2E,CAAC;AAC5F,0BAA0B;AAC1B,MAAM,WAAW,GAAG,wBAAwB,CAAC;AAE7C,SAAS,KAAK,CAAC,CAAS,EAAE,GAAW;IACnC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACnB,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC/B,OAAO,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,KAAK,CAAC,KAAc,EAAE,GAAW;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChD,OAAO,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AACjD,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,SAAS,CAAC,KAAc,EAAE,GAAW;IACnD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChD,OAAO,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AAC3E,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
2
+ import type { ClaimResult, NoticeStore } from './types.js';
3
+ export declare class DynamoNoticeStore implements NoticeStore {
4
+ private readonly doc;
5
+ private readonly tableName;
6
+ constructor(doc: Pick<DynamoDBDocumentClient, 'send'>, tableName: string);
7
+ claim(fingerprint: string, windowSec: number, nowSec: number, count: number): Promise<ClaimResult>;
8
+ release(fingerprint: string, token: number, restore: number): Promise<void>;
9
+ consume(bucket: string, windowSec: number, nowSec: number, n: number): Promise<number>;
10
+ }
11
+ /** テスト・ローカル用(1 プロセス内だけ) */
12
+ export declare class MemoryNoticeStore implements NoticeStore {
13
+ readonly fps: Map<string, {
14
+ expiresAt: number;
15
+ suppressed: number;
16
+ }>;
17
+ private readonly counts;
18
+ claim(fingerprint: string, windowSec: number, nowSec: number, count: number): Promise<ClaimResult>;
19
+ release(fingerprint: string, token: number, restore: number): Promise<void>;
20
+ consume(bucket: string, windowSec: number, nowSec: number, n: number): Promise<number>;
21
+ }
22
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/notify/store.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,sBAAsB,EAAiB,MAAM,uBAAuB,CAAC;AAE9E,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI3D,qBAAa,iBAAkB,YAAW,WAAW;IAEjD,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,GAAG,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,EACzC,SAAS,EAAE,MAAM;IAG9B,KAAK,CACT,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,CAAC;IAiDjB,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB3E,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAc7F;AAED,2BAA2B;AAC3B,qBAAa,iBAAkB,YAAW,WAAW;IACnD,QAAQ,CAAC,GAAG;mBAAgC,MAAM;oBAAc,MAAM;OAAM;IAC5E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IAE9C,KAAK,CACT,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,CAAC;IAWjB,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM3E,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAM7F"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * 重複抑制・流量制限の記録(DynamoDB。専用のテーブル: パーティションキー `pk`(文字列)、TTL 属性 `ttl`)
3
+ * 同時実行でも二重に確保しないよう、条件付き更新を使う。窓の判定は `expiresAt`(TTL の削除の遅れに影響されない)。
4
+ */
5
+ import { ConditionalCheckFailedException } from '@aws-sdk/client-dynamodb';
6
+ import { UpdateCommand } from '@aws-sdk/lib-dynamodb';
7
+ const KEEP_SEC = 86400;
8
+ export class DynamoNoticeStore {
9
+ doc;
10
+ tableName;
11
+ constructor(doc, tableName) {
12
+ this.doc = doc;
13
+ this.tableName = tableName;
14
+ }
15
+ async claim(fingerprint, windowSec, nowSec, count) {
16
+ const pk = `fp#${fingerprint}`;
17
+ // 2 回まで: 抑制の加算の直前に行が消えた(TTL)ときは、取り直す
18
+ for (let attempt = 0; attempt < 2; attempt++) {
19
+ try {
20
+ const r = await this.doc.send(new UpdateCommand({
21
+ TableName: this.tableName,
22
+ Key: { pk },
23
+ UpdateExpression: 'SET expiresAt = :exp, #ttl = :ttl, suppressed = :zero',
24
+ ConditionExpression: 'attribute_not_exists(pk) OR expiresAt <= :now',
25
+ ExpressionAttributeNames: { '#ttl': 'ttl' },
26
+ ExpressionAttributeValues: {
27
+ ':exp': nowSec + windowSec,
28
+ ':ttl': nowSec + windowSec + KEEP_SEC,
29
+ ':zero': 0,
30
+ ':now': nowSec,
31
+ },
32
+ ReturnValues: 'ALL_OLD',
33
+ }));
34
+ const prev = r.Attributes?.suppressed;
35
+ return {
36
+ granted: true,
37
+ suppressed: typeof prev === 'number' ? prev : 0,
38
+ token: nowSec + windowSec,
39
+ };
40
+ }
41
+ catch (e) {
42
+ if (!(e instanceof ConditionalCheckFailedException))
43
+ throw e;
44
+ }
45
+ try {
46
+ await this.doc.send(new UpdateCommand({
47
+ TableName: this.tableName,
48
+ Key: { pk },
49
+ UpdateExpression: 'ADD suppressed :n',
50
+ ConditionExpression: 'attribute_exists(pk) AND expiresAt > :now',
51
+ ExpressionAttributeValues: { ':n': count, ':now': nowSec },
52
+ }));
53
+ return { granted: false, suppressed: 0, token: 0 };
54
+ }
55
+ catch (e) {
56
+ if (!(e instanceof ConditionalCheckFailedException))
57
+ throw e;
58
+ }
59
+ }
60
+ // 取り直しても確保できなかった(競合が続いた)。通知を落とさないよう、許可する
61
+ return { granted: true, suppressed: 0, token: nowSec + windowSec };
62
+ }
63
+ async release(fingerprint, token, restore) {
64
+ try {
65
+ await this.doc.send(new UpdateCommand({
66
+ TableName: this.tableName,
67
+ Key: { pk: `fp#${fingerprint}` },
68
+ UpdateExpression: 'SET expiresAt = :zero ADD suppressed :r',
69
+ ConditionExpression: 'expiresAt = :mine',
70
+ ExpressionAttributeValues: { ':zero': 0, ':r': restore, ':mine': token },
71
+ }));
72
+ }
73
+ catch (e) {
74
+ // 別の実行が確保を取り直していたら、そちらを壊さない
75
+ if (!(e instanceof ConditionalCheckFailedException))
76
+ throw e;
77
+ }
78
+ }
79
+ async consume(bucket, windowSec, nowSec, n) {
80
+ const slot = Math.floor(nowSec / windowSec);
81
+ const r = await this.doc.send(new UpdateCommand({
82
+ TableName: this.tableName,
83
+ Key: { pk: `rl#${bucket}#${slot}` },
84
+ UpdateExpression: 'ADD cnt :n SET #ttl = :ttl',
85
+ ExpressionAttributeNames: { '#ttl': 'ttl' },
86
+ ExpressionAttributeValues: { ':n': n, ':ttl': (slot + 1) * windowSec + KEEP_SEC },
87
+ ReturnValues: 'UPDATED_NEW',
88
+ }));
89
+ return typeof r.Attributes?.cnt === 'number' ? r.Attributes.cnt : n;
90
+ }
91
+ }
92
+ /** テスト・ローカル用(1 プロセス内だけ) */
93
+ export class MemoryNoticeStore {
94
+ fps = new Map();
95
+ counts = new Map();
96
+ async claim(fingerprint, windowSec, nowSec, count) {
97
+ const cur = this.fps.get(fingerprint);
98
+ if (cur && cur.expiresAt > nowSec) {
99
+ cur.suppressed += count;
100
+ return { granted: false, suppressed: 0, token: 0 };
101
+ }
102
+ const token = nowSec + windowSec;
103
+ this.fps.set(fingerprint, { expiresAt: token, suppressed: 0 });
104
+ return { granted: true, suppressed: cur?.suppressed ?? 0, token };
105
+ }
106
+ async release(fingerprint, token, restore) {
107
+ const cur = this.fps.get(fingerprint);
108
+ if (!cur || cur.expiresAt !== token)
109
+ return;
110
+ this.fps.set(fingerprint, { expiresAt: 0, suppressed: cur.suppressed + restore });
111
+ }
112
+ async consume(bucket, windowSec, nowSec, n) {
113
+ const key = `${bucket}#${Math.floor(nowSec / windowSec)}`;
114
+ const total = (this.counts.get(key) ?? 0) + n;
115
+ this.counts.set(key, total);
116
+ return total;
117
+ }
118
+ }
119
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/notify/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * 運用通知の型
3
+ *
4
+ * 通知は `Notice` に正規化してから、重複抑制 → チャネルへ配信する。
5
+ * `Notice` には許可したフィールドだけを入れる(ログ全体を転送しない)。
6
+ */
7
+ /** 通知するレベル。`ok` はアラームの復旧 */
8
+ export type NoticeLevel = 'warn' | 'error' | 'fatal' | 'ok';
9
+ export interface Notice {
10
+ level: NoticeLevel;
11
+ /** 機械可読の種別(例: SPARSE_SCAN、ALARM:astro-dev-xxx) */
12
+ event: string;
13
+ message: string;
14
+ app: string;
15
+ env: string;
16
+ /** 対象(コレクション名など)。重複抑制の指紋に使う */
17
+ target?: string;
18
+ /** 対策の案内 */
19
+ action?: string;
20
+ /** ISO 8601 */
21
+ occurredAt: string;
22
+ /** 抑制していた同種の通知の件数(今回を含まない) */
23
+ suppressed: number;
24
+ }
25
+ /** 配信先 */
26
+ export interface Channel {
27
+ name: string;
28
+ /** メールなど、宛先(管理者)が必要なチャネルか */
29
+ needsRecipients: boolean;
30
+ send(notices: Notice[], recipients: string[]): Promise<void>;
31
+ }
32
+ /** 宛先(管理者のメールアドレス)の取得。スキーマは強制しない */
33
+ export interface AdminDirectory {
34
+ listEmails(): Promise<string[]>;
35
+ }
36
+ export interface ClaimResult {
37
+ granted: boolean;
38
+ /** granted のとき、前回の窓の間に抑制した件数 */
39
+ suppressed: number;
40
+ /** granted のとき、確保の印(release に渡す。別の実行が取り直した確保を壊さないため) */
41
+ token: number;
42
+ }
43
+ /** 重複抑制・流量制限の記録 */
44
+ export interface NoticeStore {
45
+ /**
46
+ * 指紋の窓を確保する。窓の中なら granted: false にして、抑制の件数を count 増やす。
47
+ * count は、この呼び出しが代表する発生の件数(同じバッチの重複をまとめたもの)
48
+ */
49
+ claim(fingerprint: string, windowSec: number, nowSec: number, count: number): Promise<ClaimResult>;
50
+ /**
51
+ * 送れなかった確保を解放する(次の発生で、窓を待たずに通知できる)。自分の確保(token)のときだけ。
52
+ * restore 件を抑制の件数に戻す(前回ぶん + 今回の発生)
53
+ */
54
+ release(fingerprint: string, token: number, restore: number): Promise<void>;
55
+ /** 流量の計数を n 増やし、窓の中の件数(増やした後)を返す */
56
+ consume(bucket: string, windowSec: number, nowSec: number, n: number): Promise<number>;
57
+ }
58
+ export interface NotifyLogger {
59
+ info(message: string, meta?: Record<string, unknown>): void;
60
+ warn(message: string, meta?: Record<string, unknown>): void;
61
+ error(message: string, meta?: Record<string, unknown>): void;
62
+ }
63
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/notify/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,4BAA4B;AAC5B,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;AAE5D,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,WAAW,CAAC;IACnB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU;AACV,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AAED,oCAAoC;AACpC,MAAM,WAAW,cAAc;IAC7B,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,mBAAmB;AACnB,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,KAAK,CACH,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,CAAC,CAAC;IACxB;;;OAGG;IACH,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,oCAAoC;IACpC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACxF;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9D"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 運用通知の型
3
+ *
4
+ * 通知は `Notice` に正規化してから、重複抑制 → チャネルへ配信する。
5
+ * `Notice` には許可したフィールドだけを入れる(ログ全体を転送しない)。
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/notify/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -1,5 +1,5 @@
1
- // @exabugs/dynamodb-client v1.10.0
2
- // Built: 2026-10-11T23:48:57.909Z
1
+ // @exabugs/dynamodb-client v1.11.0
2
+ // Built: 2026-10-12T06:23:05.041Z
3
3
  "use strict";
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -38988,7 +38988,7 @@ async function handler(event) {
38988
38988
  return createCorsResponse(HTTP_STATUS.OK);
38989
38989
  }
38990
38990
  if (event.requestContext.http.method === "GET" && event.requestContext.http.path === "/version") {
38991
- const version = "1.10.0";
38991
+ const version = "1.11.0";
38992
38992
  return createSuccessResponse({ version, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, requestId);
38993
38993
  }
38994
38994
  if (event.requestContext.http.method !== "POST") {
@@ -1,5 +1,5 @@
1
- // @exabugs/dynamodb-client v1.10.0
2
- // Built: 2026-10-11T23:48:57.909Z
1
+ // @exabugs/dynamodb-client v1.11.0
2
+ // Built: 2026-10-12T06:23:05.041Z
3
3
  "use strict";
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -1,5 +1,5 @@
1
- // @exabugs/dynamodb-client v1.10.0
2
- // Built: 2026-10-11T23:48:57.909Z
1
+ // @exabugs/dynamodb-client v1.11.0
2
+ // Built: 2026-10-12T06:23:05.041Z
3
3
  "use strict";
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -1,5 +1,5 @@
1
- // @exabugs/dynamodb-client v1.10.0
2
- // Built: 2026-10-11T23:48:57.909Z
1
+ // @exabugs/dynamodb-client v1.11.0
2
+ // Built: 2026-10-12T06:23:05.041Z
3
3
  "use strict";
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
Binary file