@chaos-maker/core 0.4.0 → 0.5.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/sw.mjs CHANGED
@@ -1,21 +1,44 @@
1
- var oe = Object.defineProperty;
2
- var ae = (e, t, n) => t in e ? oe(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
3
- var W = (e, t, n) => ae(e, typeof t != "symbol" ? t + "" : t, n);
4
- class se {
5
- constructor(t = 2e3) {
6
- W(this, "listeners", /* @__PURE__ */ new Map());
7
- W(this, "log", []);
8
- this.maxLogEntries = t;
1
+ var ce = Object.defineProperty;
2
+ var ie = (n, e, t) => e in n ? ce(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t;
3
+ var O = (n, e, t) => ie(n, typeof e != "symbol" ? e + "" : e, t);
4
+ class de {
5
+ constructor(e = 2e3) {
6
+ O(this, "listeners", /* @__PURE__ */ new Map());
7
+ O(this, "log", []);
8
+ O(this, "logger");
9
+ O(this, "ruleIds");
10
+ this.maxLogEntries = e;
11
+ }
12
+ on(e, t) {
13
+ this.listeners.has(e) || this.listeners.set(e, /* @__PURE__ */ new Set()), this.listeners.get(e).add(t);
14
+ }
15
+ off(e, t) {
16
+ var o;
17
+ (o = this.listeners.get(e)) == null || o.delete(t);
9
18
  }
10
- on(t, n) {
11
- this.listeners.has(t) || this.listeners.set(t, /* @__PURE__ */ new Set()), this.listeners.get(t).add(n);
19
+ emit(e) {
20
+ this.log.push(e), this.log.length > this.maxLogEntries && this.log.shift(), this.notify(this.listeners.get(e.type), e), this.notify(this.listeners.get("*"), e);
12
21
  }
13
- off(t, n) {
14
- var r;
15
- (r = this.listeners.get(t)) == null || r.delete(n);
22
+ /** Attach a Debug Mode logger. When unset, `debug()` is a fast-path no-op. */
23
+ setLogger(e) {
24
+ this.logger = e;
16
25
  }
17
- emit(t) {
18
- this.log.push(t), this.log.length > this.maxLogEntries && this.log.shift(), this.notify(this.listeners.get(t.type), t), this.notify(this.listeners.get("*"), t);
26
+ /** Attach the rule-id map so debug events auto-resolve `ruleType` /
27
+ * `ruleId` from a rule object reference. */
28
+ setRuleIds(e) {
29
+ this.ruleIds = e;
30
+ }
31
+ /**
32
+ * Emit a Debug Mode event. Fast-path no-op when no logger is attached —
33
+ * single undefined-check before any allocation. When `rule` is supplied
34
+ * and present in the rule-id map, `detail.ruleType` and `detail.ruleId`
35
+ * are filled in automatically.
36
+ */
37
+ debug(e, t, o) {
38
+ var f;
39
+ if (!this.logger) return;
40
+ const s = o ? (f = this.ruleIds) == null ? void 0 : f.get(o) : void 0, p = s ? { ...t, ruleType: s.ruleType, ruleId: s.ruleId } : t, l = this.logger.log(e, p);
41
+ l && this.emit(l);
19
42
  }
20
43
  getLog() {
21
44
  return [...this.log];
@@ -23,624 +46,934 @@ class se {
23
46
  clearLog() {
24
47
  this.log = [];
25
48
  }
26
- notify(t, n) {
27
- if (t)
28
- for (const r of t)
49
+ notify(e, t) {
50
+ if (e)
51
+ for (const o of e)
29
52
  try {
30
- r(n);
53
+ o(t);
31
54
  } catch {
32
55
  }
33
56
  }
34
57
  }
35
- function ie(e) {
36
- let t = e | 0;
58
+ function pe(n) {
59
+ let e = n | 0;
37
60
  return () => {
38
- t = t + 1831565813 | 0;
39
- let n = Math.imul(t ^ t >>> 15, 1 | t);
40
- return n = n + Math.imul(n ^ n >>> 7, 61 | n) ^ n, ((n ^ n >>> 14) >>> 0) / 4294967296;
61
+ e = e + 1831565813 | 0;
62
+ let t = Math.imul(e ^ e >>> 15, 1 | e);
63
+ return t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t, ((t ^ t >>> 14) >>> 0) / 4294967296;
41
64
  };
42
65
  }
43
- function ue() {
66
+ function fe() {
44
67
  return Math.random() * 4294967296 >>> 0;
45
68
  }
46
- function Y(e) {
47
- const t = e ?? ue();
69
+ function re(n) {
70
+ const e = n ?? fe();
48
71
  return {
49
- random: ie(t),
50
- seed: t
72
+ random: pe(e),
73
+ seed: e
51
74
  };
52
75
  }
53
- function N(e, t) {
54
- return t() < e;
76
+ const z = "default";
77
+ class se {
78
+ constructor() {
79
+ O(this, "groups", /* @__PURE__ */ new Map());
80
+ /**
81
+ * Tracks groups that have already emitted a `rule-group:gated` event since
82
+ * the last toggle. Cleared on every `setEnabled()` so the next toggle cycle
83
+ * gets a fresh diagnostic event without flooding.
84
+ */
85
+ O(this, "gatedEmitted", /* @__PURE__ */ new Set());
86
+ }
87
+ /**
88
+ * Look up an existing group or create a new one.
89
+ *
90
+ * - Implicit (auto-create from `isActive`): `explicit: false`, defaults
91
+ * `enabled: true`.
92
+ * - Explicit (`ChaosConfig.groups` / `createGroup()`): `explicit: true`.
93
+ * When called with both `explicit: true` and `enabled` set, the existing
94
+ * group's `enabled` is overwritten; the explicit form is the source of truth.
95
+ */
96
+ ensure(e, t) {
97
+ const o = this.groups.get(e);
98
+ if (o)
99
+ return t != null && t.explicit && (o.explicit = !0), (t == null ? void 0 : t.enabled) !== void 0 && (o.enabled = t.enabled), o;
100
+ const s = {
101
+ name: e,
102
+ enabled: (t == null ? void 0 : t.enabled) ?? !0,
103
+ explicit: (t == null ? void 0 : t.explicit) ?? !1
104
+ };
105
+ return this.groups.set(e, s), s;
106
+ }
107
+ setEnabled(e, t) {
108
+ this.ensure(e).enabled = t, this.gatedEmitted.clear();
109
+ }
110
+ /**
111
+ * Auto-creates unknown groups on first check (implicit). Rationale:
112
+ * silently returning `true` for unknown names lets typos like
113
+ * `group: 'paymets'` mask chaos as if no group existed; auto-registering
114
+ * surfaces the typo via `list()` / `getSnapshot()` and keeps default-on
115
+ * backward compat.
116
+ */
117
+ isActive(e) {
118
+ return this.ensure(e ?? z).enabled;
119
+ }
120
+ /** True when this group should emit a `rule-group:gated` event right now (first block since last toggle). */
121
+ shouldEmitGated(e) {
122
+ return this.gatedEmitted.has(e) ? !1 : (this.gatedEmitted.add(e), !0);
123
+ }
124
+ has(e) {
125
+ return this.groups.has(e);
126
+ }
127
+ /**
128
+ * Remove a group from the registry.
129
+ * - `'default'` cannot be removed (returns `false`).
130
+ * - By default, throws when any rule in `referencedBy` still uses the group.
131
+ * - Pass `{ force: true }` to remove anyway. Subsequent `isActive(name)`
132
+ * calls auto-recreate the group (default-on).
133
+ */
134
+ remove(e, t, o) {
135
+ if (e === z) return !1;
136
+ if (!(o != null && o.force) && t.has(e))
137
+ throw new Error(
138
+ `[chaos-maker] Cannot remove group '${e}': still referenced by one or more rules. Pass { force: true } to override.`
139
+ );
140
+ const s = this.groups.delete(e);
141
+ return s && this.gatedEmitted.delete(e), s;
142
+ }
143
+ list() {
144
+ return [...this.groups.values()].map(
145
+ (e) => ({ ...e })
146
+ );
147
+ }
148
+ getSnapshot() {
149
+ const e = {};
150
+ for (const t of this.groups.values()) e[t.name] = t.enabled;
151
+ return e;
152
+ }
153
+ }
154
+ function $(n, e) {
155
+ return e() < n;
55
156
  }
56
- function $(e, t) {
57
- const n = (t.get(e) ?? 0) + 1;
58
- return t.set(e, n), n;
157
+ function q(n, e) {
158
+ const t = (e.get(n) ?? 0) + 1;
159
+ return e.set(n, t), t;
59
160
  }
60
- function B(e, t) {
61
- return e.onNth !== void 0 ? t === e.onNth : e.everyNth !== void 0 ? t % e.everyNth === 0 : e.afterN !== void 0 ? t > e.afterN : !0;
161
+ function P(n, e) {
162
+ return n.onNth !== void 0 ? e === n.onNth : n.everyNth !== void 0 ? e % n.everyNth === 0 : n.afterN !== void 0 ? e > n.afterN : !0;
62
163
  }
63
- function U(e, t) {
64
- return t === "*" ? !0 : e.includes(t);
164
+ function Z(n, e) {
165
+ return e === "*" ? !0 : n.includes(e);
65
166
  }
66
- function le(e, t) {
67
- switch (t) {
167
+ function ge(n, e) {
168
+ switch (e) {
68
169
  case "truncate":
69
- return e.slice(0, Math.max(0, Math.floor(e.length / 2)));
170
+ return n.slice(0, Math.max(0, Math.floor(n.length / 2)));
70
171
  case "malformed-json":
71
- return `${e}"}`;
172
+ return `${n}"}`;
72
173
  case "empty":
73
174
  return "";
74
175
  case "wrong-type":
75
176
  return "<html><body>Unexpected HTML</body></html>";
76
177
  }
77
178
  }
78
- function ee(e) {
79
- const t = e.replace(/#[^\r\n]*/g, " "), n = /\b(?:query|mutation|subscription)\s+([A-Za-z_][A-Za-z0-9_]*)/.exec(t);
80
- return (n == null ? void 0 : n[1]) ?? null;
179
+ function G(n, e, t, o) {
180
+ if (!e || e.isActive(n.group)) return !0;
181
+ const s = n.group ?? z;
182
+ return e.shouldEmitGated(s) && t && t.emit({
183
+ type: "rule-group:gated",
184
+ timestamp: Date.now(),
185
+ applied: !1,
186
+ detail: { ...o, groupName: s }
187
+ }), t == null || t.debug("rule-skip-group", { ...o, groupName: s }, n), !1;
188
+ }
189
+ function he(n, e) {
190
+ var o, s, p, l, f, u, a, E, x, M, L, A, S, d;
191
+ const t = (c) => {
192
+ if (c)
193
+ for (const i of c) e(i);
194
+ };
195
+ t((o = n.network) == null ? void 0 : o.failures), t((s = n.network) == null ? void 0 : s.latencies), t((p = n.network) == null ? void 0 : p.aborts), t((l = n.network) == null ? void 0 : l.corruptions), t((f = n.network) == null ? void 0 : f.cors), t((u = n.ui) == null ? void 0 : u.assaults), t((a = n.websocket) == null ? void 0 : a.drops), t((E = n.websocket) == null ? void 0 : E.delays), t((x = n.websocket) == null ? void 0 : x.corruptions), t((M = n.websocket) == null ? void 0 : M.closes), t((L = n.sse) == null ? void 0 : L.drops), t((A = n.sse) == null ? void 0 : A.delays), t((S = n.sse) == null ? void 0 : S.corruptions), t((d = n.sse) == null ? void 0 : d.closes);
81
196
  }
82
- function ce(e) {
197
+ function ae(n) {
198
+ const e = n.replace(/#[^\r\n]*/g, " "), t = /\b(?:query|mutation|subscription)\s+([A-Za-z_][A-Za-z0-9_]*)/.exec(e);
199
+ return (t == null ? void 0 : t[1]) ?? null;
200
+ }
201
+ function be(n) {
83
202
  try {
84
- return JSON.parse(e);
203
+ return JSON.parse(n);
85
204
  } catch {
86
205
  return;
87
206
  }
88
207
  }
89
- function te(e) {
90
- if (!e || typeof e != "object") return { isGraphQL: !1, operationName: null };
91
- if (Array.isArray(e))
92
- return e.length === 0 ? { isGraphQL: !1, operationName: null } : te(e[0]);
93
- const t = e, n = typeof t.query == "string", r = typeof t.operationName == "string";
94
- return !n && !r ? { isGraphQL: !1, operationName: null } : r && t.operationName.length > 0 ? { isGraphQL: !0, operationName: t.operationName } : n ? { isGraphQL: !0, operationName: ee(t.query) } : { isGraphQL: !0, operationName: null };
208
+ function ue(n) {
209
+ if (!n || typeof n != "object") return { isGraphQL: !1, operationName: null };
210
+ if (Array.isArray(n))
211
+ return n.length === 0 ? { isGraphQL: !1, operationName: null } : ue(n[0]);
212
+ const e = n, t = typeof e.query == "string", o = typeof e.operationName == "string";
213
+ return !t && !o ? { isGraphQL: !1, operationName: null } : o && e.operationName.length > 0 ? { isGraphQL: !0, operationName: e.operationName } : t ? { isGraphQL: !0, operationName: ae(e.query) } : { isGraphQL: !0, operationName: null };
95
214
  }
96
- function fe(e) {
97
- let t;
215
+ function ye(n) {
216
+ let e;
98
217
  try {
99
- t = new URL(e, "http://_chaos-maker.invalid");
218
+ e = new URL(n, "http://_chaos-maker.invalid");
100
219
  } catch {
101
220
  return { kind: "not-graphql" };
102
221
  }
103
- const n = t.searchParams.get("operationName"), r = t.searchParams.get("query");
104
- return n && n.length > 0 ? { kind: "extracted", operationName: n } : r && r.length > 0 ? { kind: "extracted", operationName: ee(r) } : { kind: "not-graphql" };
105
- }
106
- function de(e, t, n, r) {
107
- const a = e.toUpperCase();
108
- if (a === "POST") {
109
- if (n !== null) {
110
- const u = ce(n);
111
- if (u === void 0) return { kind: "not-graphql" };
112
- const { isGraphQL: p, operationName: c } = te(u);
113
- return p ? { kind: "extracted", operationName: c } : { kind: "not-graphql" };
222
+ const t = e.searchParams.get("operationName"), o = e.searchParams.get("query");
223
+ return t && t.length > 0 ? { kind: "extracted", operationName: t } : o && o.length > 0 ? { kind: "extracted", operationName: ae(o) } : { kind: "not-graphql" };
224
+ }
225
+ function ke(n, e, t, o) {
226
+ const s = n.toUpperCase();
227
+ if (s === "POST") {
228
+ if (t !== null) {
229
+ const p = be(t);
230
+ if (p === void 0) return { kind: "not-graphql" };
231
+ const { isGraphQL: l, operationName: f } = ue(p);
232
+ return l ? { kind: "extracted", operationName: f } : { kind: "not-graphql" };
114
233
  }
115
- return r ? { kind: "unparseable" } : { kind: "not-graphql" };
234
+ return o ? { kind: "unparseable" } : { kind: "not-graphql" };
116
235
  }
117
- return a === "GET" ? fe(t) : { kind: "not-graphql" };
236
+ return s === "GET" ? ye(e) : { kind: "not-graphql" };
118
237
  }
119
- function pe(e, t) {
120
- return t === null ? !1 : typeof e == "string" ? e === t : ((e.global || e.sticky) && (e.lastIndex = 0), e.test(t));
238
+ function we(n, e) {
239
+ return e === null ? !1 : typeof n == "string" ? n === e : ((n.global || n.sticky) && (n.lastIndex = 0), n.test(e));
121
240
  }
122
- function ne(e, t) {
123
- return e ? t.kind === "not-graphql" ? { kind: "no-match" } : t.kind === "unparseable" ? { kind: "unparseable" } : pe(e, t.operationName) ? { kind: "match", operationName: t.operationName } : { kind: "no-match" } : t.kind === "extracted" ? { kind: "skip-no-constraint", operationName: t.operationName } : { kind: "skip-no-constraint", operationName: null };
241
+ function Me(n, e) {
242
+ return n ? e.kind === "not-graphql" ? { kind: "no-match" } : e.kind === "unparseable" ? { kind: "unparseable" } : we(n, e.operationName) ? { kind: "match", operationName: e.operationName } : { kind: "no-match" } : e.kind === "extracted" ? { kind: "skip-no-constraint", operationName: e.operationName } : { kind: "skip-no-constraint", operationName: null };
124
243
  }
125
- function H(e) {
126
- return typeof Request < "u" && e instanceof Request;
244
+ function J(n) {
245
+ return typeof Request < "u" && n instanceof Request;
127
246
  }
128
- function he(e) {
129
- return H(e) ? e.url : e.toString();
247
+ function ve(n) {
248
+ return J(n) ? n.url : n.toString();
130
249
  }
131
- function ye(e, t) {
132
- return t != null && t.method ? t.method.toUpperCase() : H(e) ? e.method.toUpperCase() : "GET";
250
+ function Ce(n, e) {
251
+ return e != null && e.method ? e.method.toUpperCase() : J(n) ? n.method.toUpperCase() : "GET";
133
252
  }
134
- function ge(e, t) {
135
- if (t != null && t.signal)
136
- return t.signal;
137
- if (H(e))
253
+ function Ee(n, e) {
254
+ if (e != null && e.signal)
138
255
  return e.signal;
256
+ if (J(n))
257
+ return n.signal;
139
258
  }
140
- function be() {
259
+ function Se() {
141
260
  if (typeof DOMException < "u")
142
261
  return new DOMException("The user aborted a request.", "AbortError");
143
- const e = new Error("The user aborted a request.");
144
- return e.name = "AbortError", e;
262
+ const n = new Error("The user aborted a request.");
263
+ return n.name = "AbortError", n;
145
264
  }
146
- function me(e, t) {
147
- if (!t)
148
- return e;
149
- const n = new AbortController(), r = (c) => {
150
- p(), n.signal.aborted || n.abort(c.reason);
151
- }, a = () => r(e), u = () => r(t), p = () => {
152
- e.removeEventListener("abort", a), t.removeEventListener("abort", u);
265
+ function Te(n, e) {
266
+ if (!e)
267
+ return n;
268
+ const t = new AbortController(), o = (f) => {
269
+ l(), t.signal.aborted || t.abort(f.reason);
270
+ }, s = () => o(n), p = () => o(e), l = () => {
271
+ n.removeEventListener("abort", s), e.removeEventListener("abort", p);
153
272
  };
154
- return e.aborted ? (r(e), n.signal) : t.aborted ? (r(t), n.signal) : (e.addEventListener("abort", a, { once: !0 }), t.addEventListener("abort", u, { once: !0 }), n.signal);
155
- }
156
- function ke(e, t) {
157
- return t ? {
158
- ...e ?? {},
159
- signal: t
160
- } : e;
161
- }
162
- async function we(e, t) {
163
- const n = t == null ? void 0 : t.body;
164
- if (n != null) {
165
- if (typeof n == "string") return { text: n, unparseable: !1 };
166
- if (typeof URLSearchParams < "u" && n instanceof URLSearchParams)
167
- return { text: n.toString(), unparseable: !1 };
168
- if (typeof Blob < "u" && n instanceof Blob) {
169
- if (!(n.type === "" || /json|text|graphql/i.test(n.type))) return { text: null, unparseable: !0 };
273
+ return n.aborted ? (o(n), t.signal) : e.aborted ? (o(e), t.signal) : (n.addEventListener("abort", s, { once: !0 }), e.addEventListener("abort", p, { once: !0 }), t.signal);
274
+ }
275
+ function Le(n, e) {
276
+ return e ? {
277
+ ...n ?? {},
278
+ signal: e
279
+ } : n;
280
+ }
281
+ async function xe(n, e) {
282
+ const t = e == null ? void 0 : e.body;
283
+ if (t != null) {
284
+ if (typeof t == "string") return { text: t, unparseable: !1 };
285
+ if (typeof URLSearchParams < "u" && t instanceof URLSearchParams)
286
+ return { text: t.toString(), unparseable: !1 };
287
+ if (typeof Blob < "u" && t instanceof Blob) {
288
+ if (!(t.type === "" || /json|text|graphql/i.test(t.type))) return { text: null, unparseable: !0 };
170
289
  try {
171
- return { text: await n.text(), unparseable: !1 };
290
+ return { text: await t.text(), unparseable: !1 };
172
291
  } catch {
173
292
  return { text: null, unparseable: !0 };
174
293
  }
175
294
  }
176
295
  return { text: null, unparseable: !0 };
177
296
  }
178
- if (H(e)) {
179
- if (e.body === null) return { text: null, unparseable: !1 };
297
+ if (J(n)) {
298
+ if (n.body === null) return { text: null, unparseable: !1 };
180
299
  try {
181
- return { text: await e.clone().text(), unparseable: !1 };
300
+ return { text: await n.clone().text(), unparseable: !1 };
182
301
  } catch {
183
302
  return { text: null, unparseable: !0 };
184
303
  }
185
304
  }
186
305
  return { text: null, unparseable: !1 };
187
306
  }
188
- function q(e, t, n, r, a) {
189
- e == null || e.emit({
190
- type: t,
307
+ function U(n, e, t, o, s) {
308
+ n == null || n.emit({
309
+ type: e,
191
310
  timestamp: Date.now(),
192
311
  applied: !1,
193
- detail: { url: n, method: r, ...a, reason: "graphql-body-unparseable" }
312
+ detail: { url: t, method: o, ...s, reason: "graphql-body-unparseable" }
194
313
  });
195
314
  }
196
- function R(e, t, n, r, a) {
197
- if (!U(t, e.urlPattern)) return { proceed: !1, outcome: null };
198
- if (e.methods && !e.methods.includes(n)) return { proceed: !1, outcome: null };
199
- const u = ne(e.graphqlOperation, r);
200
- if (u.kind === "no-match" || u.kind === "unparseable")
201
- return { proceed: !1, outcome: u };
202
- const p = $(e, a);
203
- return B(e, p) ? { proceed: !0, outcome: u } : { proceed: !1, outcome: u };
315
+ function B(n, e, t, o) {
316
+ if (!Z(e, n.urlPattern)) return { proceed: !1, outcome: null };
317
+ if (n.methods && !n.methods.includes(t)) return { proceed: !1, outcome: null };
318
+ const s = Me(n.graphqlOperation, o);
319
+ return s.kind === "no-match" ? { proceed: !1, outcome: s } : { proceed: !0, outcome: s };
204
320
  }
205
- function P(e) {
206
- return e ? e.kind === "match" || e.kind === "skip-no-constraint" ? e.operationName ? { operationName: e.operationName } : {} : {} : {};
321
+ function W(n) {
322
+ return n ? n.kind === "match" || n.kind === "skip-no-constraint" ? n.operationName ? { operationName: n.operationName } : {} : {} : {};
207
323
  }
208
- function j(e, t, n, r, a, u) {
209
- e == null || e.emit({
324
+ function V(n, e, t, o, s, p) {
325
+ n == null || n.emit({
210
326
  type: "network:abort",
211
327
  timestamp: Date.now(),
212
- applied: a,
213
- detail: { url: n, method: r, timeoutMs: t.timeout, ...P(u) }
328
+ applied: s,
329
+ detail: { url: t, method: o, timeoutMs: e.timeout, ...W(p) }
214
330
  });
215
331
  }
216
- function F(e, t, n, r, a, u) {
217
- e == null || e.emit({
332
+ function Q(n, e, t, o, s, p) {
333
+ n == null || n.emit({
218
334
  type: "network:corruption",
219
335
  timestamp: Date.now(),
220
- applied: a,
221
- detail: { url: n, method: r, strategy: t.strategy, ...P(u) }
336
+ applied: s,
337
+ detail: { url: t, method: o, strategy: e.strategy, ...W(p) }
222
338
  });
223
339
  }
224
- function Se(e) {
225
- return e.graphqlOperation !== void 0;
340
+ function Ae(n) {
341
+ return n.graphqlOperation !== void 0;
226
342
  }
227
- function Me(e, t, n, r, a = /* @__PURE__ */ new Map()) {
228
- return async (u, p) => {
229
- var b, m, k, w;
230
- const c = he(u), d = ye(u, p), C = ge(u, p), L = (() => {
231
- const o = [t.failures, t.latencies, t.aborts, t.corruptions, t.cors];
232
- for (const y of o)
233
- if (y != null && y.some(Se)) return !0;
343
+ function Ne(n, e, t, o, s = /* @__PURE__ */ new Map(), p) {
344
+ return async (l, f) => {
345
+ var k, w, C, T, R;
346
+ const u = ve(l), a = Ce(l, f), E = Ee(l, f), x = (() => {
347
+ const r = [e.failures, e.latencies, e.aborts, e.corruptions, e.cors];
348
+ for (const b of r)
349
+ if (b != null && b.some(Ae)) return !0;
234
350
  return !1;
235
351
  })();
236
- let S = { kind: "not-graphql" };
237
- if (L) {
238
- const o = await we(u, p);
239
- S = de(d, c, o.text, o.unparseable);
352
+ let M = { kind: "not-graphql" };
353
+ if (x) {
354
+ const r = await xe(l, f);
355
+ M = ke(a, u, r.text, r.unparseable);
240
356
  }
241
- if (t.cors)
242
- for (const o of t.cors) {
243
- if (!U(c, o.urlPattern) || o.methods && !o.methods.includes(d)) continue;
244
- const y = ne(o.graphqlOperation, S);
245
- if (y.kind === "no-match") continue;
246
- if (y.kind === "unparseable") {
247
- q(r, "network:cors", c, d, {});
357
+ if (e.cors)
358
+ for (const r of e.cors) {
359
+ o == null || o.debug("rule-evaluating", { url: u, method: a }, r);
360
+ const b = B(r, u, a, M);
361
+ if (!b.proceed) {
362
+ o == null || o.debug("rule-skip-match", { url: u, method: a }, r);
363
+ continue;
364
+ }
365
+ o == null || o.debug("rule-matched", { url: u, method: a }, r);
366
+ const N = q(r, s);
367
+ if (!P(r, N)) {
368
+ o == null || o.debug("rule-skip-counting", { url: u, method: a }, r);
248
369
  continue;
249
370
  }
250
- const E = $(o, a);
251
- if (!B(o, E)) continue;
252
- const v = N(o.probability, n);
253
- if (r == null || r.emit({
371
+ if (!G(r, p, o, { url: u, method: a })) continue;
372
+ const v = $(r.probability, t);
373
+ if (((k = b.outcome) == null ? void 0 : k.kind) === "unparseable") {
374
+ v && U(o, "network:cors", u, a, {});
375
+ continue;
376
+ }
377
+ if (o == null || o.emit({
254
378
  type: "network:cors",
255
379
  timestamp: Date.now(),
256
380
  applied: v,
257
- detail: { url: c, method: d, ...P(y) }
258
- }), v) {
259
- console.debug(`[chaos-maker] CORS block: ${d} ${c}`);
260
- const x = new TypeError("Failed to fetch");
261
- throw x.stack = "", x;
381
+ detail: { url: u, method: a, ...W(b.outcome) }
382
+ }), !v) {
383
+ o == null || o.debug("rule-skip-probability", { url: u, method: a }, r);
384
+ continue;
262
385
  }
386
+ o == null || o.debug("rule-applied", { url: u, method: a }, r);
387
+ const _ = new TypeError("Failed to fetch");
388
+ throw _.stack = "", _;
263
389
  }
264
- let M = null, A = null, T, i, s = !1;
265
- const l = (o) => {
266
- !M || s || (s = !0, i && (clearTimeout(i), i = void 0), j(r, M, c, d, o, A));
390
+ let L = null, A = null, S, d, c = !1;
391
+ const i = (r) => {
392
+ !L || c || (c = !0, d && (clearTimeout(d), d = void 0), V(o, L, u, a, r, A));
267
393
  };
268
- if (t.aborts)
269
- for (const o of t.aborts) {
270
- const y = R(o, c, d, S, a);
271
- if (!y.proceed) {
272
- ((b = y.outcome) == null ? void 0 : b.kind) === "unparseable" && q(r, "network:abort", c, d, { timeoutMs: o.timeout });
394
+ if (e.aborts)
395
+ for (const r of e.aborts) {
396
+ o == null || o.debug("rule-evaluating", { url: u, method: a, timeoutMs: r.timeout }, r);
397
+ const b = B(r, u, a, M);
398
+ if (!b.proceed) {
399
+ o == null || o.debug("rule-skip-match", { url: u, method: a, timeoutMs: r.timeout }, r);
400
+ continue;
401
+ }
402
+ o == null || o.debug("rule-matched", { url: u, method: a, timeoutMs: r.timeout }, r);
403
+ const N = q(r, s);
404
+ if (!P(r, N)) {
405
+ o == null || o.debug("rule-skip-counting", { url: u, method: a, timeoutMs: r.timeout }, r);
273
406
  continue;
274
407
  }
275
- if (!N(o.probability, n)) {
276
- j(r, o, c, d, !1, y.outcome);
408
+ if (!G(r, p, o, { url: u, method: a, timeoutMs: r.timeout })) continue;
409
+ const v = $(r.probability, t);
410
+ if (((w = b.outcome) == null ? void 0 : w.kind) === "unparseable") {
411
+ v && U(o, "network:abort", u, a, { timeoutMs: r.timeout });
277
412
  continue;
278
413
  }
279
- console.warn(`CHAOS: Aborting ${d} ${c} after ${o.timeout || 0}ms`), M = o, A = y.outcome;
280
- const v = new AbortController();
281
- T = me(v.signal, C);
282
- const x = () => {
283
- s || (l(!0), v.abort(be()));
414
+ if (!v) {
415
+ o == null || o.debug("rule-skip-probability", { url: u, method: a, timeoutMs: r.timeout }, r), V(o, r, u, a, !1, b.outcome);
416
+ continue;
417
+ }
418
+ o == null || o.debug("rule-applied", { url: u, method: a, timeoutMs: r.timeout }, r), console.warn(`CHAOS: Aborting ${a} ${u} after ${r.timeout || 0}ms`), L = r, A = b.outcome;
419
+ const _ = new AbortController();
420
+ S = Te(_.signal, E);
421
+ const H = () => {
422
+ c || (i(!0), _.abort(Se()));
284
423
  };
285
- o.timeout ? i = setTimeout(x, o.timeout) : x();
424
+ r.timeout ? d = setTimeout(H, r.timeout) : H();
286
425
  break;
287
426
  }
288
- if (M)
427
+ if (L)
289
428
  try {
290
- const o = await e(u, ke(p, T));
291
- return l(!1), o;
292
- } catch (o) {
293
- throw l(!1), o;
429
+ const r = await n(l, Le(f, S));
430
+ return i(!1), r;
431
+ } catch (r) {
432
+ throw i(!1), r;
294
433
  }
295
- if (t.failures)
296
- for (const o of t.failures) {
297
- const y = R(o, c, d, S, a);
298
- if (!y.proceed) {
299
- ((m = y.outcome) == null ? void 0 : m.kind) === "unparseable" && q(r, "network:failure", c, d, { statusCode: o.statusCode });
434
+ if (e.failures)
435
+ for (const r of e.failures) {
436
+ o == null || o.debug("rule-evaluating", { url: u, method: a, statusCode: r.statusCode }, r);
437
+ const b = B(r, u, a, M);
438
+ if (!b.proceed) {
439
+ o == null || o.debug("rule-skip-match", { url: u, method: a, statusCode: r.statusCode }, r);
440
+ continue;
441
+ }
442
+ o == null || o.debug("rule-matched", { url: u, method: a, statusCode: r.statusCode }, r);
443
+ const N = q(r, s);
444
+ if (!P(r, N)) {
445
+ o == null || o.debug("rule-skip-counting", { url: u, method: a, statusCode: r.statusCode }, r);
446
+ continue;
447
+ }
448
+ if (!G(r, p, o, { url: u, method: a, statusCode: r.statusCode })) continue;
449
+ const v = $(r.probability, t);
450
+ if (((C = b.outcome) == null ? void 0 : C.kind) === "unparseable") {
451
+ v && U(o, "network:failure", u, a, { statusCode: r.statusCode });
300
452
  continue;
301
453
  }
302
- const E = N(o.probability, n);
303
- if (r == null || r.emit({
454
+ if (o == null || o.emit({
304
455
  type: "network:failure",
305
456
  timestamp: Date.now(),
306
- applied: E,
307
- detail: { url: c, method: d, statusCode: o.statusCode, ...P(y.outcome) }
308
- }), E) {
309
- console.warn(`CHAOS: Forcing ${o.statusCode} for ${d} ${c}`);
310
- const v = o.body ?? JSON.stringify({ error: "Chaos Maker Attack!" }), x = o.headers ?? {};
311
- return new Response(v, {
312
- status: o.statusCode,
313
- statusText: o.statusText ?? "Service Unavailable (Chaos)",
314
- headers: x
315
- });
457
+ applied: v,
458
+ detail: { url: u, method: a, statusCode: r.statusCode, ...W(b.outcome) }
459
+ }), !v) {
460
+ o == null || o.debug("rule-skip-probability", { url: u, method: a, statusCode: r.statusCode }, r);
461
+ continue;
316
462
  }
463
+ o == null || o.debug("rule-applied", { url: u, method: a, statusCode: r.statusCode }, r), console.warn(`CHAOS: Forcing ${r.statusCode} for ${a} ${u}`);
464
+ const _ = r.body ?? JSON.stringify({ error: "Chaos Maker Attack!" }), H = r.headers ?? {};
465
+ return new Response(_, {
466
+ status: r.statusCode,
467
+ statusText: r.statusText ?? "Service Unavailable (Chaos)",
468
+ headers: H
469
+ });
317
470
  }
318
- if (t.latencies)
319
- for (const o of t.latencies) {
320
- const y = R(o, c, d, S, a);
321
- if (!y.proceed) {
322
- ((k = y.outcome) == null ? void 0 : k.kind) === "unparseable" && q(r, "network:latency", c, d, { delayMs: o.delayMs });
471
+ if (e.latencies)
472
+ for (const r of e.latencies) {
473
+ o == null || o.debug("rule-evaluating", { url: u, method: a, delayMs: r.delayMs }, r);
474
+ const b = B(r, u, a, M);
475
+ if (!b.proceed) {
476
+ o == null || o.debug("rule-skip-match", { url: u, method: a, delayMs: r.delayMs }, r);
477
+ continue;
478
+ }
479
+ o == null || o.debug("rule-matched", { url: u, method: a, delayMs: r.delayMs }, r);
480
+ const N = q(r, s);
481
+ if (!P(r, N)) {
482
+ o == null || o.debug("rule-skip-counting", { url: u, method: a, delayMs: r.delayMs }, r);
483
+ continue;
484
+ }
485
+ if (!G(r, p, o, { url: u, method: a, delayMs: r.delayMs })) continue;
486
+ const v = $(r.probability, t);
487
+ if (((T = b.outcome) == null ? void 0 : T.kind) === "unparseable") {
488
+ v && U(o, "network:latency", u, a, { delayMs: r.delayMs });
323
489
  continue;
324
490
  }
325
- const E = N(o.probability, n);
326
- r == null || r.emit({
491
+ if (o == null || o.emit({
327
492
  type: "network:latency",
328
493
  timestamp: Date.now(),
329
- applied: E,
330
- detail: { url: c, method: d, delayMs: o.delayMs, ...P(y.outcome) }
331
- }), E && (console.warn(`CHAOS: Adding ${o.delayMs}ms latency to ${d} ${c}`), await new Promise((v) => setTimeout(v, o.delayMs)));
494
+ applied: v,
495
+ detail: { url: u, method: a, delayMs: r.delayMs, ...W(b.outcome) }
496
+ }), !v) {
497
+ o == null || o.debug("rule-skip-probability", { url: u, method: a, delayMs: r.delayMs }, r);
498
+ continue;
499
+ }
500
+ o == null || o.debug("rule-applied", { url: u, method: a, delayMs: r.delayMs }, r), console.warn(`CHAOS: Adding ${r.delayMs}ms latency to ${a} ${u}`), await new Promise((_) => setTimeout(_, r.delayMs));
332
501
  }
333
- let f = null, h = null;
334
- if (t.corruptions)
335
- for (const o of t.corruptions) {
336
- const y = R(o, c, d, S, a);
337
- if (!y.proceed) {
338
- ((w = y.outcome) == null ? void 0 : w.kind) === "unparseable" && q(r, "network:corruption", c, d, { strategy: o.strategy });
502
+ let g = null, h = null;
503
+ if (e.corruptions)
504
+ for (const r of e.corruptions) {
505
+ o == null || o.debug("rule-evaluating", { url: u, method: a, strategy: r.strategy }, r);
506
+ const b = B(r, u, a, M);
507
+ if (!b.proceed) {
508
+ o == null || o.debug("rule-skip-match", { url: u, method: a, strategy: r.strategy }, r);
509
+ continue;
510
+ }
511
+ o == null || o.debug("rule-matched", { url: u, method: a, strategy: r.strategy }, r);
512
+ const N = q(r, s);
513
+ if (!P(r, N)) {
514
+ o == null || o.debug("rule-skip-counting", { url: u, method: a, strategy: r.strategy }, r);
339
515
  continue;
340
516
  }
341
- if (!N(o.probability, n)) {
342
- F(r, o, c, d, !1, y.outcome);
517
+ if (!G(r, p, o, { url: u, method: a, strategy: r.strategy })) continue;
518
+ const v = $(r.probability, t);
519
+ if (((R = b.outcome) == null ? void 0 : R.kind) === "unparseable") {
520
+ v && U(o, "network:corruption", u, a, { strategy: r.strategy });
343
521
  continue;
344
522
  }
345
- f = o, h = y.outcome;
523
+ if (!v) {
524
+ o == null || o.debug("rule-skip-probability", { url: u, method: a, strategy: r.strategy }, r), Q(o, r, u, a, !1, b.outcome);
525
+ continue;
526
+ }
527
+ o == null || o.debug("rule-applied", { url: u, method: a, strategy: r.strategy }, r), g = r, h = b.outcome;
346
528
  break;
347
529
  }
348
- let g;
530
+ let y;
349
531
  try {
350
- g = await e(u, p);
351
- } catch (o) {
352
- throw f && F(r, f, c, d, !1, h), o;
532
+ y = await n(l, f);
533
+ } catch (r) {
534
+ throw g && Q(o, g, u, a, !1, h), r;
353
535
  }
354
- if (!f)
355
- return g;
536
+ if (!g)
537
+ return y;
356
538
  try {
357
- console.warn(`CHAOS: Corrupting response for ${d} ${c} with strategy: ${f.strategy}`);
358
- const o = await g.text(), y = le(o, f.strategy);
359
- return F(r, f, c, d, !0, h), new Response(y, {
360
- status: g.status,
361
- statusText: g.statusText,
362
- headers: g.headers
539
+ console.warn(`CHAOS: Corrupting response for ${a} ${u} with strategy: ${g.strategy}`);
540
+ const r = await y.text(), b = ge(r, g.strategy);
541
+ return Q(o, g, u, a, !0, h), new Response(b, {
542
+ status: y.status,
543
+ statusText: y.statusText,
544
+ headers: y.headers
363
545
  });
364
- } catch (o) {
365
- throw F(r, f, c, d, !1, h), o;
546
+ } catch (r) {
547
+ throw Q(o, g, u, a, !1, h), r;
366
548
  }
367
549
  };
368
550
  }
369
- const J = /* @__PURE__ */ Symbol.for("chaos-maker.websocket.intercepted");
370
- function Ce(e, t) {
371
- return e === "both" ? !0 : e === t;
551
+ const X = /* @__PURE__ */ Symbol.for("chaos-maker.websocket.intercepted");
552
+ function _e(n, e) {
553
+ return n === "both" ? !0 : n === e;
372
554
  }
373
- function z(e) {
374
- return typeof e == "string" ? "text" : "binary";
555
+ function m(n) {
556
+ return typeof n == "string" ? "text" : "binary";
375
557
  }
376
- function K(e, t) {
377
- switch (t) {
558
+ function ee(n, e) {
559
+ switch (e) {
378
560
  case "truncate":
379
- return e.slice(0, Math.max(0, Math.floor(e.length / 2)));
561
+ return n.slice(0, Math.max(0, Math.floor(n.length / 2)));
380
562
  case "malformed-json":
381
- return `${e}"}`;
563
+ return `${n}"}`;
382
564
  case "empty":
383
565
  return "";
384
566
  case "wrong-type":
385
567
  return "<html><body>Unexpected HTML</body></html>";
386
568
  }
387
569
  }
388
- function Z(e, t) {
389
- if (t === "malformed-json" || t === "wrong-type") return null;
390
- if (t === "empty")
391
- return typeof Blob < "u" && e instanceof Blob ? new Blob([]) : e instanceof ArrayBuffer ? new ArrayBuffer(0) : new Uint8Array(0);
392
- if (typeof Blob < "u" && e instanceof Blob)
393
- return e.slice(0, Math.max(0, Math.floor(e.size / 2)));
394
- if (e instanceof ArrayBuffer)
395
- return e.slice(0, Math.max(0, Math.floor(e.byteLength / 2)));
396
- const n = e, r = Math.max(0, Math.floor(n.byteLength / 2));
397
- return new Uint8Array(n.buffer.slice(n.byteOffset, n.byteOffset + r));
398
- }
399
- function O(e, t, n, r, a) {
400
- if (!e) return null;
401
- for (const u of e) {
402
- if (!U(t, u.urlPattern) || !Ce(u.direction, n)) continue;
403
- const p = $(u, a);
404
- if (B(u, p) && N(u.probability, r))
405
- return u;
570
+ function ne(n, e) {
571
+ if (e === "malformed-json" || e === "wrong-type") return null;
572
+ if (e === "empty")
573
+ return typeof Blob < "u" && n instanceof Blob ? new Blob([]) : n instanceof ArrayBuffer ? new ArrayBuffer(0) : new Uint8Array(0);
574
+ if (typeof Blob < "u" && n instanceof Blob)
575
+ return n.slice(0, Math.max(0, Math.floor(n.size / 2)));
576
+ if (n instanceof ArrayBuffer)
577
+ return n.slice(0, Math.max(0, Math.floor(n.byteLength / 2)));
578
+ const t = n, o = Math.max(0, Math.floor(t.byteLength / 2));
579
+ return new Uint8Array(t.buffer.slice(t.byteOffset, t.byteOffset + o));
580
+ }
581
+ function I(n, e, t, o, s, p, l) {
582
+ if (!n) return null;
583
+ for (const f of n) {
584
+ if (l == null || l.debug("rule-evaluating", { url: e, direction: t }, f), !Z(e, f.urlPattern)) {
585
+ l == null || l.debug("rule-skip-match", { url: e, direction: t }, f);
586
+ continue;
587
+ }
588
+ if (!_e(f.direction, t)) {
589
+ l == null || l.debug("rule-skip-match", { url: e, direction: t }, f);
590
+ continue;
591
+ }
592
+ l == null || l.debug("rule-matched", { url: e, direction: t }, f);
593
+ const u = q(f, s);
594
+ if (!P(f, u)) {
595
+ l == null || l.debug("rule-skip-counting", { url: e, direction: t }, f);
596
+ continue;
597
+ }
598
+ if (G(f, p, l, { url: e, direction: t })) {
599
+ if (!$(f.probability, o)) {
600
+ l == null || l.debug("rule-skip-probability", { url: e, direction: t }, f);
601
+ continue;
602
+ }
603
+ return l == null || l.debug("rule-applied", { url: e, direction: t }, f), f;
604
+ }
406
605
  }
407
606
  return null;
408
607
  }
409
- function G(e, t, n, r, a) {
410
- e.emit({
608
+ function j(n, e, t, o, s) {
609
+ n.emit({
411
610
  type: "websocket:drop",
412
611
  timestamp: Date.now(),
413
612
  applied: !0,
414
- detail: { url: t, direction: n, payloadType: r, ...a ? { reason: a } : {} }
613
+ detail: { url: e, direction: t, payloadType: o, ...s ? { reason: s } : {} }
415
614
  });
416
615
  }
417
- function V(e, t, n, r, a) {
418
- e.emit({
616
+ function oe(n, e, t, o, s) {
617
+ n.emit({
419
618
  type: "websocket:delay",
420
619
  timestamp: Date.now(),
421
620
  applied: !0,
422
- detail: { url: t, direction: n, payloadType: r, delayMs: a }
621
+ detail: { url: e, direction: t, payloadType: o, delayMs: s }
423
622
  });
424
623
  }
425
- function _(e, t, n, r, a, u, p) {
426
- e.emit({
624
+ function D(n, e, t, o, s, p, l) {
625
+ n.emit({
427
626
  type: "websocket:corrupt",
428
627
  timestamp: Date.now(),
429
- applied: u,
430
- detail: { url: t, direction: n, payloadType: r, strategy: a, ...p ? { reason: p } : {} }
628
+ applied: p,
629
+ detail: { url: e, direction: t, payloadType: o, strategy: s, ...l ? { reason: l } : {} }
431
630
  });
432
631
  }
433
- function Le(e, t, n, r) {
434
- e.emit({
632
+ function Re(n, e, t, o) {
633
+ n.emit({
435
634
  type: "websocket:close",
436
635
  timestamp: Date.now(),
437
636
  applied: !0,
438
- detail: { url: t, closeCode: n, closeReason: r }
637
+ detail: { url: e, closeCode: t, closeReason: o }
439
638
  });
440
639
  }
441
- function Ee(e, t, n, r, a) {
442
- const u = /* @__PURE__ */ new Map();
443
- let p = !0;
444
- const c = (i, s) => {
445
- let l = u.get(i);
446
- l || (l = /* @__PURE__ */ new Set(), u.set(i, l)), l.add(s);
447
- }, d = (i, s) => {
448
- var l;
449
- (l = u.get(i)) == null || l.delete(s);
450
- }, C = (i, s) => {
451
- const l = u.get(i);
452
- if (l) {
453
- for (const f of l)
454
- clearTimeout(f.handle), f.kind === "delay" && G(n, f.url, f.direction, f.payloadType, s);
455
- u.delete(i);
640
+ function Oe(n, e, t, o, s, p) {
641
+ const l = /* @__PURE__ */ new Map();
642
+ let f = !0;
643
+ const u = (d, c) => {
644
+ let i = l.get(d);
645
+ i || (i = /* @__PURE__ */ new Set(), l.set(d, i)), i.add(c);
646
+ }, a = (d, c) => {
647
+ var i;
648
+ (i = l.get(d)) == null || i.delete(c);
649
+ }, E = (d, c) => {
650
+ const i = l.get(d);
651
+ if (i) {
652
+ for (const g of i)
653
+ clearTimeout(g.handle), g.kind === "delay" && j(t, g.url, g.direction, g.payloadType, c);
654
+ l.delete(d);
456
655
  }
457
- }, L = (i, s, l) => {
458
- const f = new MessageEvent("message", {
459
- data: l,
460
- origin: s.origin,
461
- lastEventId: s.lastEventId,
462
- source: s.source,
463
- ports: Array.from(s.ports ?? [])
656
+ }, x = (d, c, i) => {
657
+ const g = new MessageEvent("message", {
658
+ data: i,
659
+ origin: c.origin,
660
+ lastEventId: c.lastEventId,
661
+ source: c.source,
662
+ ports: Array.from(c.ports ?? [])
464
663
  });
465
- f[J] = !0, i.dispatchEvent(f);
466
- }, S = (i, s, l, f) => {
467
- if (!p) return { handled: !1, data: l };
468
- const h = "outbound", g = z(l);
469
- if (O(t.drops, s, h, r, a))
470
- return G(n, s, h, g), { handled: !0, data: l };
471
- let b = l;
472
- const m = O(t.corruptions, s, h, r, a);
473
- if (m)
474
- if (g === "text")
475
- b = K(b, m.strategy), _(n, s, h, g, m.strategy, !0);
664
+ g[X] = !0, d.dispatchEvent(g);
665
+ }, M = (d, c, i, g) => {
666
+ if (!f) return { handled: !1, data: i };
667
+ const h = "outbound", y = m(i);
668
+ if (I(e.drops, c, h, o, s, p, t))
669
+ return j(t, c, h, y), { handled: !0, data: i };
670
+ let k = i;
671
+ const w = I(e.corruptions, c, h, o, s, p, t);
672
+ if (w)
673
+ if (y === "text")
674
+ k = ee(k, w.strategy), D(t, c, h, y, w.strategy, !0);
476
675
  else {
477
- const w = Z(b, m.strategy);
478
- w === null ? _(n, s, h, g, m.strategy, !1, "incompatible-payload-type") : (b = w, _(n, s, h, g, m.strategy, !0));
676
+ const T = ne(k, w.strategy);
677
+ T === null ? D(t, c, h, y, w.strategy, !1, "incompatible-payload-type") : (k = T, D(t, c, h, y, w.strategy, !0));
479
678
  }
480
- const k = O(t.delays, s, h, r, a);
481
- if (k) {
482
- V(n, s, h, g, k.delayMs);
483
- const w = {
679
+ const C = I(e.delays, c, h, o, s, p, t);
680
+ if (C) {
681
+ oe(t, c, h, y, C.delayMs);
682
+ const T = {
484
683
  kind: "delay",
485
684
  handle: setTimeout(() => {
486
- d(i, w);
685
+ a(d, T);
487
686
  try {
488
- f(b);
687
+ g(k);
489
688
  } catch {
490
689
  }
491
- }, k.delayMs),
492
- url: s,
690
+ }, C.delayMs),
691
+ url: c,
493
692
  direction: h,
494
- payloadType: g
693
+ payloadType: y
495
694
  };
496
- return c(i, w), { handled: !0, data: b };
695
+ return u(d, T), { handled: !0, data: k };
497
696
  }
498
- return { handled: !1, data: b };
499
- }, M = (i, s) => {
500
- i.addEventListener("message", (l) => {
501
- const f = l;
502
- if (f[J] || !p) return;
503
- const h = "inbound", g = z(f.data);
504
- if (O(t.drops, s, h, r, a)) {
505
- f.stopImmediatePropagation(), G(n, s, h, g);
697
+ return { handled: !1, data: k };
698
+ }, L = (d, c) => {
699
+ d.addEventListener("message", (i) => {
700
+ const g = i;
701
+ if (g[X] || !f) return;
702
+ const h = "inbound", y = m(g.data);
703
+ if (I(e.drops, c, h, o, s, p, t)) {
704
+ g.stopImmediatePropagation(), j(t, c, h, y);
506
705
  return;
507
706
  }
508
- let b = f.data, m = !1;
509
- const k = O(t.corruptions, s, h, r, a);
510
- if (k)
511
- if (g === "text")
512
- b = K(b, k.strategy), m = !0, _(n, s, h, g, k.strategy, !0);
707
+ let k = g.data, w = !1;
708
+ const C = I(e.corruptions, c, h, o, s, p, t);
709
+ if (C)
710
+ if (y === "text")
711
+ k = ee(k, C.strategy), w = !0, D(t, c, h, y, C.strategy, !0);
513
712
  else {
514
- const o = Z(b, k.strategy);
515
- o === null ? _(n, s, h, g, k.strategy, !1, "incompatible-payload-type") : (b = o, m = !0, _(n, s, h, g, k.strategy, !0));
713
+ const R = ne(k, C.strategy);
714
+ R === null ? D(t, c, h, y, C.strategy, !1, "incompatible-payload-type") : (k = R, w = !0, D(t, c, h, y, C.strategy, !0));
516
715
  }
517
- const w = O(t.delays, s, h, r, a);
518
- if (w) {
519
- f.stopImmediatePropagation(), V(n, s, h, g, w.delayMs);
520
- const o = {
716
+ const T = I(e.delays, c, h, o, s, p, t);
717
+ if (T) {
718
+ g.stopImmediatePropagation(), oe(t, c, h, y, T.delayMs);
719
+ const R = {
521
720
  kind: "delay",
522
721
  handle: setTimeout(() => {
523
- d(i, o), L(i, f, b);
524
- }, w.delayMs),
525
- url: s,
722
+ a(d, R), x(d, g, k);
723
+ }, T.delayMs),
724
+ url: c,
526
725
  direction: h,
527
- payloadType: g
726
+ payloadType: y
528
727
  };
529
- c(i, o);
728
+ u(d, R);
530
729
  return;
531
730
  }
532
- m && (f.stopImmediatePropagation(), L(i, f, b));
731
+ w && (g.stopImmediatePropagation(), x(d, g, k));
533
732
  });
534
- }, A = (i, s) => {
535
- if (t.closes)
536
- for (const l of t.closes) {
537
- if (!U(s, l.urlPattern)) continue;
538
- const f = $(l, a);
539
- if (!B(l, f) || !N(l.probability, r)) continue;
540
- const h = l.code ?? 1e3, g = l.reason ?? "Chaos Maker close", b = l.afterMs ?? 0, m = () => {
541
- if (p) {
542
- C(i, "close-interrupt"), Le(n, s, h, g);
733
+ }, A = (d, c) => {
734
+ if (e.closes)
735
+ for (const i of e.closes) {
736
+ if (t.debug("rule-evaluating", { url: c }, i), !Z(c, i.urlPattern)) {
737
+ t.debug("rule-skip-match", { url: c }, i);
738
+ continue;
739
+ }
740
+ t.debug("rule-matched", { url: c }, i);
741
+ const g = q(i, s);
742
+ if (!P(i, g)) {
743
+ t.debug("rule-skip-counting", { url: c }, i);
744
+ continue;
745
+ }
746
+ if (!G(i, p, t, { url: c })) continue;
747
+ if (!$(i.probability, o)) {
748
+ t.debug("rule-skip-probability", { url: c }, i);
749
+ continue;
750
+ }
751
+ t.debug("rule-applied", { url: c }, i);
752
+ const h = i.code ?? 1e3, y = i.reason ?? "Chaos Maker close", k = i.afterMs ?? 0, w = () => {
753
+ if (f) {
754
+ E(d, "close-interrupt"), Re(t, c, h, y);
543
755
  try {
544
- i.close(h, g);
756
+ d.close(h, y);
545
757
  } catch {
546
758
  try {
547
- i.close();
759
+ d.close();
548
760
  } catch {
549
761
  }
550
762
  }
551
763
  }
552
764
  };
553
- if (b <= 0)
554
- i.readyState === i.OPEN ? m() : i.addEventListener("open", m, { once: !0 });
765
+ if (k <= 0)
766
+ d.readyState === d.OPEN ? w() : d.addEventListener("open", w, { once: !0 });
555
767
  else {
556
- const k = () => {
557
- const w = {
768
+ const C = () => {
769
+ const T = {
558
770
  kind: "close",
559
- handle: setTimeout(m, b)
771
+ handle: setTimeout(w, k)
560
772
  };
561
- c(i, w);
773
+ u(d, T);
562
774
  };
563
- i.readyState === i.OPEN ? k() : i.addEventListener("open", k, { once: !0 });
775
+ d.readyState === d.OPEN ? C() : d.addEventListener("open", C, { once: !0 });
564
776
  }
565
777
  return;
566
778
  }
567
779
  };
568
- function T(i, s) {
569
- const l = new e(i, s), f = typeof i == "string" ? i : i.toString(), h = l.send.bind(l);
570
- return l.send = function(b) {
571
- const m = S(l, f, b, h);
572
- m.handled || h(m.data);
573
- }, M(l, f), A(l, f), l;
574
- }
575
- Object.defineProperty(T, "prototype", {
576
- value: e.prototype,
780
+ function S(d, c) {
781
+ const i = new n(d, c), g = typeof d == "string" ? d : d.toString(), h = i.send.bind(i);
782
+ return i.send = function(k) {
783
+ const w = M(i, g, k, h);
784
+ w.handled || h(w.data);
785
+ }, L(i, g), A(i, g), i;
786
+ }
787
+ Object.defineProperty(S, "prototype", {
788
+ value: n.prototype,
577
789
  writable: !1
578
790
  });
579
- for (const i of ["CONNECTING", "OPEN", "CLOSING", "CLOSED"])
580
- T[i] = e[i];
791
+ for (const d of ["CONNECTING", "OPEN", "CLOSING", "CLOSED"])
792
+ S[d] = n[d];
581
793
  return {
582
- Wrapped: T,
794
+ Wrapped: S,
583
795
  uninstall() {
584
- p = !1;
585
- for (const [, i] of u)
586
- for (const s of i)
587
- clearTimeout(s.handle), s.kind === "delay" && G(n, s.url, s.direction, s.payloadType, "stop-during-delay");
588
- u.clear();
796
+ f = !1;
797
+ for (const [, d] of l)
798
+ for (const c of d)
799
+ clearTimeout(c.handle), c.kind === "delay" && j(t, c.url, c.direction, c.payloadType, "stop-during-delay");
800
+ l.clear();
589
801
  }
590
802
  };
591
803
  }
592
- const Q = /* @__PURE__ */ Symbol.for("chaos-maker.sw.installed");
593
- function ve() {
804
+ function $e(n) {
805
+ return n === void 0 ? { enabled: !1 } : typeof n == "boolean" ? { enabled: n } : { enabled: n.enabled };
806
+ }
807
+ const qe = [
808
+ { pick: (n) => {
809
+ var e;
810
+ return (e = n.network) == null ? void 0 : e.failures;
811
+ }, ruleType: "failure" },
812
+ { pick: (n) => {
813
+ var e;
814
+ return (e = n.network) == null ? void 0 : e.latencies;
815
+ }, ruleType: "latency" },
816
+ { pick: (n) => {
817
+ var e;
818
+ return (e = n.network) == null ? void 0 : e.aborts;
819
+ }, ruleType: "abort" },
820
+ { pick: (n) => {
821
+ var e;
822
+ return (e = n.network) == null ? void 0 : e.corruptions;
823
+ }, ruleType: "corruption" },
824
+ { pick: (n) => {
825
+ var e;
826
+ return (e = n.network) == null ? void 0 : e.cors;
827
+ }, ruleType: "cors" },
828
+ { pick: (n) => {
829
+ var e;
830
+ return (e = n.ui) == null ? void 0 : e.assaults;
831
+ }, ruleType: "ui-assault" },
832
+ { pick: (n) => {
833
+ var e;
834
+ return (e = n.websocket) == null ? void 0 : e.drops;
835
+ }, ruleType: "ws-drop" },
836
+ { pick: (n) => {
837
+ var e;
838
+ return (e = n.websocket) == null ? void 0 : e.delays;
839
+ }, ruleType: "ws-delay" },
840
+ { pick: (n) => {
841
+ var e;
842
+ return (e = n.websocket) == null ? void 0 : e.corruptions;
843
+ }, ruleType: "ws-corrupt" },
844
+ { pick: (n) => {
845
+ var e;
846
+ return (e = n.websocket) == null ? void 0 : e.closes;
847
+ }, ruleType: "ws-close" },
848
+ { pick: (n) => {
849
+ var e;
850
+ return (e = n.sse) == null ? void 0 : e.drops;
851
+ }, ruleType: "sse-drop" },
852
+ { pick: (n) => {
853
+ var e;
854
+ return (e = n.sse) == null ? void 0 : e.delays;
855
+ }, ruleType: "sse-delay" },
856
+ { pick: (n) => {
857
+ var e;
858
+ return (e = n.sse) == null ? void 0 : e.corruptions;
859
+ }, ruleType: "sse-corrupt" },
860
+ { pick: (n) => {
861
+ var e;
862
+ return (e = n.sse) == null ? void 0 : e.closes;
863
+ }, ruleType: "sse-close" }
864
+ ];
865
+ function Pe(n) {
866
+ const e = /* @__PURE__ */ new WeakMap();
867
+ for (const { pick: t, ruleType: o } of qe) {
868
+ const s = t(n);
869
+ s && s.forEach((p, l) => {
870
+ e.set(p, { ruleType: o, ruleId: `${o}#${l}` });
871
+ });
872
+ }
873
+ return e;
874
+ }
875
+ function Ge(n, e) {
876
+ const t = [];
877
+ return e.ruleId && t.push(`rule=${e.ruleId}`), e.phase && t.push(e.phase), e.method && t.push(e.method), e.url && t.push(e.url), e.statusCode !== void 0 && t.push(`-> ${e.statusCode}`), e.delayMs !== void 0 && t.push(`+${e.delayMs}ms`), e.direction && t.push(e.direction), e.eventType && t.push(`event=${e.eventType}`), e.selector && t.push(`selector=${e.selector}`), e.action && t.push(`action=${e.action}`), e.strategy && t.push(`strategy=${e.strategy}`), e.groupName && t.push(`group=${e.groupName}`), e.reason && t.push(`reason=${e.reason}`), t.length === 0 ? n : `${n}: ${t.join(" ")}`;
878
+ }
879
+ class Ie {
880
+ constructor(e, t = "page") {
881
+ this.opts = e, this.target = t;
882
+ }
883
+ isEnabled() {
884
+ return this.opts.enabled;
885
+ }
886
+ /**
887
+ * Build a `type: 'debug'` event with `detail.stage = stage`, mirror a
888
+ * `[Chaos] ...` (page) or `[Chaos SW] ...` (Service Worker) line to
889
+ * `console.debug`, and return the event for the emitter to fan out. The
890
+ * formatted string is never stored on the event payload.
891
+ *
892
+ * Returns `null` when the logger was constructed with `enabled: false`.
893
+ * Internal callers (the emitter fast-path) never reach this branch because
894
+ * `ChaosMaker` does not attach a logger when debug is off, but the guard
895
+ * keeps the public `Logger` API consistent with the `DebugOptions.enabled`
896
+ * contract for external consumers who instantiate it directly.
897
+ */
898
+ log(e, t) {
899
+ if (!this.opts.enabled) return null;
900
+ const o = { ...t, stage: e }, s = {
901
+ type: "debug",
902
+ timestamp: Date.now(),
903
+ applied: !1,
904
+ detail: o
905
+ };
906
+ if (typeof console < "u" && typeof console.debug == "function") {
907
+ const p = this.target === "sw" ? "[Chaos SW]" : "[Chaos]";
908
+ try {
909
+ console.debug(`${p} ${Ge(e, o)}`);
910
+ } catch {
911
+ }
912
+ }
913
+ return s;
914
+ }
915
+ }
916
+ const Y = /* @__PURE__ */ Symbol.for("chaos-maker.sw.installed");
917
+ function De() {
594
918
  return typeof self < "u" ? self : typeof globalThis < "u" ? globalThis : null;
595
919
  }
596
- function re(e, t) {
597
- const n = e.clients;
598
- !n || typeof n.matchAll != "function" || n.matchAll({ includeUncontrolled: !0 }).then((r) => {
599
- for (const a of r)
920
+ function le(n, e) {
921
+ const t = n.clients;
922
+ !t || typeof t.matchAll != "function" || t.matchAll({ includeUncontrolled: !0 }).then((o) => {
923
+ for (const s of o)
600
924
  try {
601
- a.postMessage(t);
925
+ s.postMessage(e);
602
926
  } catch {
603
927
  }
604
928
  }).catch(() => {
605
929
  });
606
930
  }
607
- function X(e, t) {
608
- e.running && I(e);
609
- const n = Y(t.seed);
610
- if (e.seed = n.seed, e.random = n.random, e.requestCounters = /* @__PURE__ */ new Map(), t.network) {
611
- const r = e.target;
612
- typeof r.fetch == "function" && (e.originalFetch = r.fetch, r.fetch = Me(
613
- e.originalFetch.bind(r),
614
- t.network,
615
- e.random,
616
- e.emitter,
617
- e.requestCounters
931
+ function te(n, e) {
932
+ n.running && K(n);
933
+ const t = re(e.seed);
934
+ n.seed = t.seed, n.random = t.random, n.requestCounters = /* @__PURE__ */ new Map(), n.groups = new se();
935
+ for (const s of e.groups ?? [])
936
+ n.groups.ensure(s.name, { enabled: s.enabled ?? !0, explicit: !0 });
937
+ he(e, (s) => {
938
+ s.group && n.groups.ensure(s.group);
939
+ }), n.groups.ensure(z, { enabled: !0 });
940
+ const o = $e(e.debug);
941
+ if (o.enabled ? (n.emitter.setRuleIds(Pe(e)), n.emitter.setLogger(new Ie(o, "sw"))) : (n.emitter.setRuleIds(void 0), n.emitter.setLogger(void 0)), n.emitter.debug("lifecycle", { phase: "sw:config-applied" }), e.network) {
942
+ const s = n.target;
943
+ typeof s.fetch == "function" && (n.originalFetch = s.fetch, s.fetch = Ne(
944
+ n.originalFetch.bind(s),
945
+ e.network,
946
+ n.random,
947
+ n.emitter,
948
+ n.requestCounters,
949
+ n.groups
618
950
  ));
619
951
  }
620
- return t.websocket && typeof e.target.WebSocket < "u" && (e.originalWebSocket = e.target.WebSocket, e.webSocketHandle = Ee(
621
- e.originalWebSocket,
622
- t.websocket,
623
- e.emitter,
624
- e.random,
625
- e.requestCounters
626
- ), e.target.WebSocket = e.webSocketHandle.Wrapped), e.running = !0, e.seed;
627
- }
628
- function I(e) {
629
- !e.running && !e.originalFetch && !e.originalWebSocket || (e.originalFetch && (e.target.fetch = e.originalFetch, e.originalFetch = void 0), e.originalWebSocket && (e.target.WebSocket = e.originalWebSocket, e.originalWebSocket = void 0), e.webSocketHandle && (e.webSocketHandle.uninstall(), e.webSocketHandle = void 0), e.running = !1);
630
- }
631
- function D(e, t, n) {
632
- var a;
633
- const r = (a = t.ports) == null ? void 0 : a[0];
634
- if (r && typeof r.postMessage == "function")
952
+ return e.websocket && typeof n.target.WebSocket < "u" && (n.originalWebSocket = n.target.WebSocket, n.webSocketHandle = Oe(
953
+ n.originalWebSocket,
954
+ e.websocket,
955
+ n.emitter,
956
+ n.random,
957
+ n.requestCounters,
958
+ n.groups
959
+ ), n.target.WebSocket = n.webSocketHandle.Wrapped), n.running = !0, n.seed;
960
+ }
961
+ function K(n) {
962
+ !n.running && !n.originalFetch && !n.originalWebSocket || (n.originalFetch && (n.target.fetch = n.originalFetch, n.originalFetch = void 0), n.originalWebSocket && (n.target.WebSocket = n.originalWebSocket, n.originalWebSocket = void 0), n.webSocketHandle && (n.webSocketHandle.uninstall(), n.webSocketHandle = void 0), n.emitter.debug("lifecycle", { phase: "sw:config-stopped" }), n.emitter.setLogger(void 0), n.emitter.setRuleIds(void 0), n.running = !1);
963
+ }
964
+ function F(n, e, t) {
965
+ var s;
966
+ const o = (s = e.ports) == null ? void 0 : s[0];
967
+ if (o && typeof o.postMessage == "function")
635
968
  try {
636
- r.postMessage(n);
969
+ o.postMessage(t);
637
970
  return;
638
971
  } catch {
639
972
  }
640
- re(e, n);
973
+ le(n, t);
641
974
  }
642
- function xe(e = {}) {
643
- const t = ve(), n = {
975
+ function Fe(n = {}) {
976
+ const e = De(), t = {
644
977
  isRunning: () => !1,
645
978
  getSeed: () => null,
646
979
  getLog: () => [],
@@ -649,72 +982,93 @@ function xe(e = {}) {
649
982
  uninstall: () => {
650
983
  }
651
984
  };
652
- if (!t || typeof t.fetch != "function" || typeof t.addEventListener != "function")
653
- return n;
654
- const r = t[Q];
655
- if (r) return r;
656
- const a = new se(e.maxLogEntries ?? 2e3), u = Y(0), p = {
657
- target: t,
658
- emitter: a,
985
+ if (!e || typeof e.fetch != "function" || typeof e.addEventListener != "function")
986
+ return t;
987
+ const o = e[Y];
988
+ if (o) return o;
989
+ const s = new de(n.maxLogEntries ?? 2e3), p = re(0), l = {
990
+ target: e,
991
+ emitter: s,
659
992
  running: !1,
660
993
  seed: null,
661
- random: u.random,
662
- requestCounters: /* @__PURE__ */ new Map()
994
+ random: p.random,
995
+ requestCounters: /* @__PURE__ */ new Map(),
996
+ groups: new se()
663
997
  };
664
- a.on("*", (C) => {
665
- re(t, { __chaosMakerSWEvent: !0, event: C });
998
+ s.on("*", (a) => {
999
+ le(e, { __chaosMakerSWEvent: !0, event: a });
666
1000
  });
667
- const c = (C) => {
668
- const L = C, S = L.data;
669
- if (!S || typeof S != "object") return;
670
- const M = S;
1001
+ const f = (a) => {
1002
+ const E = a, x = E.data;
1003
+ if (!x || typeof x != "object") return;
1004
+ const M = x;
671
1005
  if (M.__chaosMakerConfig) {
672
- const A = X(p, M.__chaosMakerConfig);
673
- D(t, L, {
1006
+ const L = te(l, M.__chaosMakerConfig);
1007
+ F(e, E, {
674
1008
  __chaosMakerAck: !0,
675
- seed: A,
676
- running: p.running
1009
+ seed: L,
1010
+ running: l.running
677
1011
  });
678
1012
  return;
679
1013
  }
680
1014
  if (M.__chaosMakerStop) {
681
- I(p), D(t, L, {
1015
+ K(l), F(e, E, {
682
1016
  __chaosMakerAck: !0,
683
1017
  running: !1
684
1018
  });
685
1019
  return;
686
1020
  }
1021
+ if (M.__chaosMakerToggleGroup) {
1022
+ const { name: L, enabled: A } = M.__chaosMakerToggleGroup, S = L.trim();
1023
+ if (!S) {
1024
+ F(e, E, {
1025
+ __chaosMakerAck: !0,
1026
+ running: l.running
1027
+ });
1028
+ return;
1029
+ }
1030
+ l.groups.setEnabled(S, A), l.emitter.emit({
1031
+ type: A ? "rule-group:enabled" : "rule-group:disabled",
1032
+ timestamp: Date.now(),
1033
+ applied: !0,
1034
+ detail: { groupName: S }
1035
+ }), l.emitter.debug("lifecycle", { phase: "sw:group-toggled", groupName: S, enabled: A }), F(e, E, {
1036
+ __chaosMakerAck: !0,
1037
+ running: l.running
1038
+ });
1039
+ return;
1040
+ }
687
1041
  if (M.__chaosMakerGetLog) {
688
- D(t, L, {
1042
+ F(e, E, {
689
1043
  __chaosMakerLog: !0,
690
- log: a.getLog()
1044
+ log: s.getLog()
691
1045
  });
692
1046
  return;
693
1047
  }
694
1048
  if (M.__chaosMakerClearLog) {
695
- a.clearLog(), D(t, L, {
1049
+ s.clearLog(), F(e, E, {
696
1050
  __chaosMakerAck: !0,
697
- running: p.running
1051
+ running: l.running
698
1052
  });
699
1053
  return;
700
1054
  }
701
1055
  };
702
- if (t.addEventListener("message", c), (e.source ?? "message") === "self-global") {
703
- const C = t.__CHAOS_CONFIG__;
704
- C && typeof C == "object" && X(p, C);
705
- }
706
- const d = {
707
- isRunning: () => p.running,
708
- getSeed: () => p.seed,
709
- getLog: () => a.getLog(),
710
- clearLog: () => a.clearLog(),
1056
+ if (e.addEventListener("message", f), (n.source ?? "message") === "self-global") {
1057
+ const a = e.__CHAOS_CONFIG__;
1058
+ a && typeof a == "object" && te(l, a);
1059
+ }
1060
+ const u = {
1061
+ isRunning: () => l.running,
1062
+ getSeed: () => l.seed,
1063
+ getLog: () => s.getLog(),
1064
+ clearLog: () => s.clearLog(),
711
1065
  uninstall: () => {
712
- t.removeEventListener("message", c), I(p), delete t[Q];
1066
+ e.removeEventListener("message", f), K(l), delete e[Y];
713
1067
  }
714
1068
  };
715
- return t[Q] = d, d;
1069
+ return e[Y] = u, u;
716
1070
  }
717
- typeof self < "u" && typeof importScripts == "function" && xe({ source: "message" });
1071
+ typeof self < "u" && typeof importScripts == "function" && Fe({ source: "message" });
718
1072
  export {
719
- xe as installChaosSW
1073
+ Fe as installChaosSW
720
1074
  };