@crvouga/mockingbird-service-intercom 3.3.0 → 3.4.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.
@@ -1411,7 +1411,7 @@ var assertSnapshotDocument = (value, label = "snapshot") => {
1411
1411
  });
1412
1412
  }
1413
1413
  if (value.clock !== void 0) {
1414
- if (!isRecord2(value.clock) || typeof value.clock.now !== "number" || typeof value.clock.frozen !== "boolean")
1414
+ if (!isRecord2(value.clock) || typeof value.clock.now !== "number" || !Number.isFinite(value.clock.now) || typeof value.clock.frozen !== "boolean")
1415
1415
  throw new ControlError(`${label}.clock: expected {now, frozen}`);
1416
1416
  }
1417
1417
  return value;
@@ -3351,6 +3351,91 @@ var createMetrics = (partition = true) => {
3351
3351
  };
3352
3352
  };
3353
3353
 
3354
+ // ../core/dist/outbound.js
3355
+ function ownedTransport(policy) {
3356
+ if (!["offline", "allowlist"].includes(policy.mode) || policy.origins?.some((origin) => {
3357
+ try {
3358
+ return new URL(origin).origin !== origin;
3359
+ } catch {
3360
+ return true;
3361
+ }
3362
+ }))
3363
+ throw new Error("invalid outbound transport policy");
3364
+ const reject = (namespace, reason) => {
3365
+ try {
3366
+ policy.onReject?.({ namespace, policy: policy.mode, reason });
3367
+ } catch {
3368
+ }
3369
+ throw new Error(`outbound policy ${policy.mode}: ${reason}`);
3370
+ };
3371
+ return async (request, namespace, send) => {
3372
+ if (policy.mode === "offline")
3373
+ return reject(namespace, "delivery disabled");
3374
+ const allowed = (url2) => ["http:", "https:"].includes(url2.protocol) && !url2.username && !url2.password && (policy.origins ?? []).includes(url2.origin);
3375
+ let url = new URL(request.url);
3376
+ if (!allowed(url))
3377
+ return reject(namespace, "destination not allowed");
3378
+ const max = policy.maxBodyBytes ?? 1024 * 1024;
3379
+ const chunks = [];
3380
+ let size = 0;
3381
+ const reader = request.body?.getReader();
3382
+ if (reader)
3383
+ try {
3384
+ for (; ; ) {
3385
+ const item = await reader.read();
3386
+ if (item.done)
3387
+ break;
3388
+ size += item.value.length;
3389
+ if (size > max)
3390
+ return reject(namespace, "body limit exceeded");
3391
+ chunks.push(item.value);
3392
+ }
3393
+ } finally {
3394
+ void reader.cancel().catch(() => {
3395
+ });
3396
+ reader.releaseLock();
3397
+ }
3398
+ const body = new Uint8Array(size);
3399
+ let offset = 0;
3400
+ for (const chunk of chunks) {
3401
+ body.set(chunk, offset);
3402
+ offset += chunk.length;
3403
+ }
3404
+ let method = request.method, headers = new Headers(request.headers);
3405
+ for (let redirects = 0; ; redirects++) {
3406
+ if (!allowed(url))
3407
+ return reject(namespace, "redirect destination not allowed");
3408
+ const response = await send(new Request(url, {
3409
+ method,
3410
+ headers,
3411
+ ...method !== "GET" && method !== "HEAD" ? { body } : {},
3412
+ redirect: "manual",
3413
+ signal: request.signal
3414
+ }));
3415
+ if (![301, 302, 303, 307, 308].includes(response.status))
3416
+ return response;
3417
+ const location = response.headers.get("location");
3418
+ if (!location)
3419
+ return response;
3420
+ await response.body?.cancel();
3421
+ if (redirects >= (policy.maxRedirects ?? 5))
3422
+ return reject(namespace, "redirect limit exceeded");
3423
+ const next = new URL(location, url);
3424
+ if (next.origin !== url.origin) {
3425
+ headers = new Headers(headers);
3426
+ for (const key of ["authorization", "cookie", "proxy-authorization"])
3427
+ headers.delete(key);
3428
+ }
3429
+ if (response.status === 303 || (response.status === 301 || response.status === 302) && method === "POST") {
3430
+ method = "GET";
3431
+ headers.delete("content-length");
3432
+ headers.delete("content-type");
3433
+ }
3434
+ url = next;
3435
+ }
3436
+ };
3437
+ }
3438
+
3354
3439
  // ../core/dist/outbox.js
3355
3440
  var OutboxStore = class {
3356
3441
  items;
@@ -3986,7 +4071,7 @@ var stateAdminRoutes = (routes) => {
3986
4071
  };
3987
4072
 
3988
4073
  // ../core/dist/version.js
3989
- var PACKAGE_VERSION = true ? "3.3.0" : UNRELEASED_VERSION;
4074
+ var PACKAGE_VERSION = true ? "3.4.0" : UNRELEASED_VERSION;
3990
4075
 
3991
4076
  // ../core/dist/signing.js
3992
4077
  var encoder = new TextEncoder();
@@ -4078,13 +4163,35 @@ var createWebhookHub = (options) => {
4078
4163
  const payloads = /* @__PURE__ */ new Map();
4079
4164
  const faults = /* @__PURE__ */ new Map();
4080
4165
  const held = /* @__PURE__ */ new Map();
4166
+ const deliveryObservers = /* @__PURE__ */ new Set();
4167
+ const notify = (delivery) => {
4168
+ for (const listener of deliveryObservers)
4169
+ try {
4170
+ listener({ namespace: delivery.namespace, state: delivery.state, deliveryId: delivery.id });
4171
+ } catch {
4172
+ }
4173
+ };
4174
+ let transport;
4081
4175
  const inFlight2 = /* @__PURE__ */ new Set();
4176
+ const workNamespace = /* @__PURE__ */ new Map();
4177
+ const activeDeliveries = /* @__PURE__ */ new Map();
4082
4178
  const controllers = /* @__PURE__ */ new Map();
4083
4179
  let immediate = Promise.resolve();
4084
4180
  const snapshots = /* @__PURE__ */ new WeakMap();
4085
- const track = (work) => {
4181
+ const track = (work, delivery) => {
4086
4182
  inFlight2.add(work);
4087
- void work.finally(() => inFlight2.delete(work));
4183
+ workNamespace.set(work, delivery.namespace);
4184
+ const active = activeDeliveries.get(delivery.id) ?? { namespace: delivery.namespace, count: 0 };
4185
+ active.count++;
4186
+ activeDeliveries.set(delivery.id, active);
4187
+ const finish = () => {
4188
+ inFlight2.delete(work);
4189
+ workNamespace.delete(work);
4190
+ active.count--;
4191
+ if (active.count === 0)
4192
+ activeDeliveries.delete(delivery.id);
4193
+ };
4194
+ void work.then(finish, finish);
4088
4195
  };
4089
4196
  const attempt = async (delivery) => {
4090
4197
  const entry = payloads.get(delivery.id);
@@ -4116,7 +4223,8 @@ var createWebhookHub = (options) => {
4116
4223
  type: message.type,
4117
4224
  tags: message.tags
4118
4225
  });
4119
- const response = await send(new Request(endpoint.url, {
4226
+ const ownedSend = (request) => transport ? transport(request, message.namespace, send) : send(request);
4227
+ const response = await ownedSend(new Request(endpoint.url, {
4120
4228
  method: "POST",
4121
4229
  headers: {
4122
4230
  "content-type": message.contentType,
@@ -4143,6 +4251,7 @@ var createWebhookHub = (options) => {
4143
4251
  const index = delivery.attempts.length;
4144
4252
  if (index >= delays.length) {
4145
4253
  delivery.state = "failed";
4254
+ notify(delivery);
4146
4255
  pending.delete(delivery.id);
4147
4256
  return;
4148
4257
  }
@@ -4152,9 +4261,10 @@ var createWebhookHub = (options) => {
4152
4261
  await attempt(delivery).then((ok) => {
4153
4262
  if (!payloads.has(delivery.id))
4154
4263
  return;
4155
- if (ok)
4264
+ if (ok) {
4156
4265
  delivery.state = "delivered";
4157
- else
4266
+ notify(delivery);
4267
+ } else
4158
4268
  schedule(delivery);
4159
4269
  });
4160
4270
  };
@@ -4163,12 +4273,12 @@ var createWebhookHub = (options) => {
4163
4273
  const task = immediate.then(settle);
4164
4274
  immediate = task.catch(() => {
4165
4275
  });
4166
- track(task);
4276
+ track(task, delivery);
4167
4277
  return;
4168
4278
  }
4169
4279
  const timer = scheduleTimer(() => {
4170
4280
  pending.delete(delivery.id);
4171
- track(settle());
4281
+ track(settle(), delivery);
4172
4282
  }, delay);
4173
4283
  unref(timer);
4174
4284
  pending.set(delivery.id, timer);
@@ -4192,6 +4302,8 @@ var createWebhookHub = (options) => {
4192
4302
  payloads.set(delivery.id, { message, endpoint });
4193
4303
  if (state === "pending")
4194
4304
  schedule(delivery);
4305
+ else
4306
+ notify(delivery);
4195
4307
  }
4196
4308
  };
4197
4309
  const takeFault = (namespace) => {
@@ -4213,8 +4325,19 @@ var createWebhookHub = (options) => {
4213
4325
  fanOut(message);
4214
4326
  };
4215
4327
  const hub = {
4328
+ observeDeliveries(listener) {
4329
+ deliveryObservers.add(listener);
4330
+ return () => deliveryObservers.delete(listener);
4331
+ },
4332
+ setTransportPolicy(policy) {
4333
+ transport = policy;
4334
+ },
4216
4335
  pending(namespace) {
4217
- return inFlight2.size + (held.get(namespace)?.length ?? 0) + [...deliveries.values()].filter((d) => d.namespace === namespace && d.state === "pending").length;
4336
+ const ids = new Set([...deliveries.values()].filter((d) => d.namespace === namespace && d.state === "pending").map((d) => d.id));
4337
+ for (const [id2, active] of activeDeliveries)
4338
+ if (active.namespace === namespace)
4339
+ ids.add(id2);
4340
+ return ids.size + (held.get(namespace)?.length ?? 0);
4218
4341
  },
4219
4342
  snapshot(namespace) {
4220
4343
  if (hub.pending(namespace) > 0)
@@ -4230,6 +4353,36 @@ var createWebhookHub = (options) => {
4230
4353
  }));
4231
4354
  return handle;
4232
4355
  },
4356
+ exportSnapshot(handle) {
4357
+ const point = typeof handle === "object" && handle !== null ? snapshots.get(handle) : void 0;
4358
+ if (!point)
4359
+ throw new Error("invalid webhook snapshot");
4360
+ const { namespace: _namespace, ...document2 } = point;
4361
+ return structuredClone(document2);
4362
+ },
4363
+ importSnapshot(namespace, document2) {
4364
+ if (!isRecord4(document2) || !Array.isArray(document2.endpoints) || !Array.isArray(document2.messages) || !Array.isArray(document2.deliveries) || !Array.isArray(document2.payloads) || !Array.isArray(document2.faults))
4365
+ throw new Error("invalid portable webhook snapshot");
4366
+ for (const endpoint of document2.endpoints)
4367
+ if (typeof parseEndpoint(endpoint) === "string")
4368
+ throw new Error("invalid portable webhook endpoint");
4369
+ for (const message of document2.messages)
4370
+ if (!isRecord4(message) || typeof message.id !== "string" || typeof message.body !== "string")
4371
+ throw new Error("invalid portable webhook message");
4372
+ for (const pair of [...document2.deliveries, ...document2.payloads])
4373
+ if (!Array.isArray(pair) || pair.length !== 2 || typeof pair[0] !== "string" || !isRecord4(pair[1]))
4374
+ throw new Error("invalid portable webhook entry");
4375
+ const handle = {};
4376
+ const point = structuredClone(document2);
4377
+ for (const message of point.messages)
4378
+ message.namespace = namespace;
4379
+ for (const [, delivery] of point.deliveries)
4380
+ delivery.namespace = namespace;
4381
+ for (const [, payload] of point.payloads)
4382
+ payload.message.namespace = namespace;
4383
+ snapshots.set(handle, { ...point, namespace });
4384
+ return handle;
4385
+ },
4233
4386
  restore(namespace, handle) {
4234
4387
  const point = typeof handle === "object" && handle !== null ? snapshots.get(handle) : void 0;
4235
4388
  if (!point || point.namespace !== namespace || hub.pending(namespace) > 0)
@@ -4290,9 +4443,14 @@ var createWebhookHub = (options) => {
4290
4443
  const delivery = deliveries.get(id2);
4291
4444
  if (!delivery)
4292
4445
  return void 0;
4293
- const ok = await attempt(delivery);
4294
- if (ok)
4295
- delivery.state = "delivered";
4446
+ const work = (async () => {
4447
+ const ok = await attempt(delivery);
4448
+ if (ok)
4449
+ delivery.state = "delivered";
4450
+ notify({ ...delivery, state: ok ? "delivered" : "failed" });
4451
+ })();
4452
+ track(work, delivery);
4453
+ await work;
4296
4454
  return delivery;
4297
4455
  },
4298
4456
  async flush() {
@@ -4309,11 +4467,12 @@ var createWebhookHub = (options) => {
4309
4467
  if (!delivery)
4310
4468
  continue;
4311
4469
  track(attempt(delivery).then((ok) => {
4312
- if (ok)
4470
+ if (ok) {
4313
4471
  delivery.state = "delivered";
4314
- else
4472
+ notify(delivery);
4473
+ } else
4315
4474
  schedule(delivery);
4316
- }));
4475
+ }), delivery);
4317
4476
  }
4318
4477
  await hub.idle();
4319
4478
  const scheduled = [...pending.values()].some((timer) => timer !== void 0);
@@ -4321,9 +4480,13 @@ var createWebhookHub = (options) => {
4321
4480
  return;
4322
4481
  }
4323
4482
  },
4324
- async idle() {
4325
- while (inFlight2.size > 0)
4326
- await Promise.allSettled([...inFlight2]);
4483
+ async idle(namespace) {
4484
+ for (; ; ) {
4485
+ const selected = [...inFlight2].filter((work) => namespace === void 0 || workNamespace.get(work) === namespace);
4486
+ if (!selected.length)
4487
+ return;
4488
+ await Promise.allSettled(selected);
4489
+ }
4327
4490
  },
4328
4491
  fault(namespace, fault) {
4329
4492
  const queue = faults.get(namespace) ?? [];
@@ -4936,7 +5099,8 @@ var createRuntime = (options) => {
4936
5099
  ...point.rngState !== void 0 ? { rng: { state: point.rngState, ...streams } } : {},
4937
5100
  ...rules ? { faults: rules } : {},
4938
5101
  ...waits ? { latency: waits } : {},
4939
- ...settings?.virtualTime !== void 0 ? { virtualTime: settings.virtualTime } : {}
5102
+ ...settings?.virtualTime !== void 0 ? { virtualTime: settings.virtualTime } : {},
5103
+ ...point.webhooks !== void 0 ? { webhooks: options.webhooks?.exportSnapshot(point.webhooks) } : {}
4940
5104
  };
4941
5105
  };
4942
5106
  const position = (value, label) => {
@@ -5021,7 +5185,8 @@ var createRuntime = (options) => {
5021
5185
  records: stored,
5022
5186
  ...document2.clock ? { clock: { now: document2.clock.now, frozen: document2.clock.frozen } } : {},
5023
5187
  ...document2.rng?.state !== void 0 ? { rngState: position(document2.rng.state, "snapshot.rng.state") } : {},
5024
- controls: held
5188
+ controls: held,
5189
+ ...document2.webhooks !== void 0 ? { webhooks: options.webhooks?.importSnapshot(namespace, document2.webhooks) } : {}
5025
5190
  };
5026
5191
  };
5027
5192
  const kept = /* @__PURE__ */ new Map();
@@ -5155,6 +5320,20 @@ var createRuntime = (options) => {
5155
5320
  restoreAll(namespace, point);
5156
5321
  timelines.delete(namespace);
5157
5322
  },
5323
+ fleetExport(handle) {
5324
+ const point = typeof handle === "object" && handle !== null ? fleetPoints.get(handle) : void 0;
5325
+ if (!point)
5326
+ throw new Error("invalid fleet checkpoint");
5327
+ return toDocument(point);
5328
+ },
5329
+ fleetImport(namespace, document2) {
5330
+ const handle = {};
5331
+ fleetPoints.set(handle, {
5332
+ namespace,
5333
+ ...fromDocument(namespace, assertSnapshotDocument(document2))
5334
+ });
5335
+ return handle;
5336
+ },
5158
5337
  applyPreset: (name2, namespace = DEFAULT_NAMESPACE, overrides = {}) => controls.addFault(namespace, { ...overrides, preset: name2 }),
5159
5338
  instance,
5160
5339
  namespaces: () => [...publicNamespaces].sort(),
@@ -6973,9 +7152,11 @@ export {
6973
7152
  createClock,
6974
7153
  restoreClock,
6975
7154
  parseDuration,
7155
+ normalizeControls,
6976
7156
  normalizeBootControls,
6977
7157
  parseFaultHeader,
6978
7158
  resolveAdminPrefix,
7159
+ ownedTransport,
6979
7160
  document,
6980
7161
  operationIds,
6981
7162
  supportedOperationIds,
@@ -6994,4 +7175,4 @@ export {
6994
7175
  IntercomError,
6995
7176
  IntercomAPI
6996
7177
  };
6997
- //# sourceMappingURL=chunk-FL2LA7Q7.js.map
7178
+ //# sourceMappingURL=chunk-X4SPTTIR.js.map