@crvouga/mockingbird-service-intercom 1.0.0 → 1.1.1
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/CHANGELOG.md +13 -4
- package/README.md +18 -9
- package/dist/{chunk-OSBG2XJ7.js → chunk-G2BMC225.js} +243 -56
- package/dist/chunk-G2BMC225.js.map +7 -0
- package/dist/{chunk-5RRE6WVT.js → chunk-LKMXLCCL.js} +18 -4
- package/dist/chunk-LKMXLCCL.js.map +7 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +179 -91
- package/dist/index.js +1 -1
- package/dist/server.d.ts +282 -166
- package/dist/server.js +2 -2
- package/package.json +2 -2
- package/dist/chunk-5RRE6WVT.js.map +0 -7
- package/dist/chunk-OSBG2XJ7.js.map +0 -7
|
@@ -1149,6 +1149,73 @@ var createMetrics = () => {
|
|
|
1149
1149
|
};
|
|
1150
1150
|
};
|
|
1151
1151
|
|
|
1152
|
+
// ../core/dist/outbox.js
|
|
1153
|
+
var OutboxStore = class {
|
|
1154
|
+
items;
|
|
1155
|
+
constructor(sqlite, namespace, name = "outbox") {
|
|
1156
|
+
this.items = new Collection(sqlite, namespace, name);
|
|
1157
|
+
}
|
|
1158
|
+
record(item) {
|
|
1159
|
+
this.items.insert(item.id, item);
|
|
1160
|
+
return item;
|
|
1161
|
+
}
|
|
1162
|
+
get(id) {
|
|
1163
|
+
return this.items.get(id);
|
|
1164
|
+
}
|
|
1165
|
+
update(id, item) {
|
|
1166
|
+
this.items.update(id, item);
|
|
1167
|
+
}
|
|
1168
|
+
/** Oldest first, so a suite reads messages in the order they were sent. */
|
|
1169
|
+
list(query = {}) {
|
|
1170
|
+
const to = query.to?.toLowerCase();
|
|
1171
|
+
const matched = this.items.list({ order: "oldest" }).map((row) => row.value).filter((item) => {
|
|
1172
|
+
if (to !== void 0) {
|
|
1173
|
+
const recipients = Array.isArray(item.to) ? item.to : [item.to];
|
|
1174
|
+
if (!recipients.some((r) => r.toLowerCase() === to))
|
|
1175
|
+
return false;
|
|
1176
|
+
}
|
|
1177
|
+
if (query.since !== void 0 && Date.parse(item.createdAt) < query.since)
|
|
1178
|
+
return false;
|
|
1179
|
+
if (query.where && !query.where(item))
|
|
1180
|
+
return false;
|
|
1181
|
+
return true;
|
|
1182
|
+
});
|
|
1183
|
+
return query.limit !== void 0 ? matched.slice(-Math.max(0, query.limit)) : matched;
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1186
|
+
var json2 = (status, body) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
|
|
1187
|
+
var parseSince = (value) => {
|
|
1188
|
+
if (value === null)
|
|
1189
|
+
return void 0;
|
|
1190
|
+
const parsed = /^\d+$/.test(value) ? Number(value) : Date.parse(value);
|
|
1191
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
1192
|
+
};
|
|
1193
|
+
var outboxAdminRoutes = (runtime, pick, filter) => ({
|
|
1194
|
+
"GET /outbox": ({ url, namespace }) => {
|
|
1195
|
+
const since = parseSince(url.searchParams.get("since"));
|
|
1196
|
+
if (since === null) {
|
|
1197
|
+
return json2(400, {
|
|
1198
|
+
error: { type: "mockingbird_admin", message: "since: expected epoch ms or ISO-8601" }
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
const limit = url.searchParams.get("limit");
|
|
1202
|
+
const where = filter?.(url.searchParams);
|
|
1203
|
+
const to = url.searchParams.get("to");
|
|
1204
|
+
return json2(200, {
|
|
1205
|
+
messages: pick(runtime.instance(namespace)).list({
|
|
1206
|
+
...to !== null ? { to } : {},
|
|
1207
|
+
...since !== void 0 ? { since } : {},
|
|
1208
|
+
...where ? { where } : {},
|
|
1209
|
+
...limit !== null && /^\d+$/.test(limit) ? { limit: Number(limit) } : {}
|
|
1210
|
+
})
|
|
1211
|
+
});
|
|
1212
|
+
},
|
|
1213
|
+
"GET /outbox/:id": ({ params, namespace }) => {
|
|
1214
|
+
const item = pick(runtime.instance(namespace)).get(params.id);
|
|
1215
|
+
return item ? json2(200, item) : json2(404, { error: { type: "mockingbird_admin", message: `no message ${params.id}` } });
|
|
1216
|
+
}
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1152
1219
|
// ../../core/dist/timeline.js
|
|
1153
1220
|
var BRANCH_PATTERN = /^[A-Za-z0-9_.-]{1,64}$/;
|
|
1154
1221
|
var Timeline = class {
|
|
@@ -1407,6 +1474,90 @@ var operationMetadata = (operation) => {
|
|
|
1407
1474
|
|
|
1408
1475
|
// ../core/dist/service.js
|
|
1409
1476
|
import { Hono } from "hono";
|
|
1477
|
+
|
|
1478
|
+
// ../core/dist/validation.js
|
|
1479
|
+
var requestBodyOf = (context) => {
|
|
1480
|
+
const requestBody = context.operation.operation.requestBody;
|
|
1481
|
+
return requestBody ? deref(context.document, requestBody) : void 0;
|
|
1482
|
+
};
|
|
1483
|
+
var mediaTypeMatches = (accepted, actual) => {
|
|
1484
|
+
const pattern = mediaTypeOf(accepted) ?? accepted.toLowerCase();
|
|
1485
|
+
if (pattern === actual || pattern === "*/*")
|
|
1486
|
+
return true;
|
|
1487
|
+
const [type, subtype] = pattern.split("/");
|
|
1488
|
+
const [actualType, actualSubtype] = actual.split("/");
|
|
1489
|
+
if (type !== actualType && type !== "*")
|
|
1490
|
+
return false;
|
|
1491
|
+
if (subtype === void 0 || subtype === "*")
|
|
1492
|
+
return true;
|
|
1493
|
+
if (subtype.startsWith("*+"))
|
|
1494
|
+
return actualSubtype?.endsWith(subtype.slice(1)) === true;
|
|
1495
|
+
return false;
|
|
1496
|
+
};
|
|
1497
|
+
var acceptedKeyFor = (content, mediaType) => {
|
|
1498
|
+
if (!content || mediaType === void 0)
|
|
1499
|
+
return void 0;
|
|
1500
|
+
const keys = Object.keys(content);
|
|
1501
|
+
return keys.find((key) => mediaTypeOf(key) === mediaType) ?? keys.find((key) => mediaTypeMatches(key, mediaType));
|
|
1502
|
+
};
|
|
1503
|
+
var unsupportedMediaType = (context, options = {}) => {
|
|
1504
|
+
if (context.body.kind === "empty" && options.includeEmpty !== true)
|
|
1505
|
+
return void 0;
|
|
1506
|
+
const content = requestBodyOf(context)?.content;
|
|
1507
|
+
if (!content || Object.keys(content).length === 0)
|
|
1508
|
+
return void 0;
|
|
1509
|
+
const mediaType = mediaTypeOf(context.request.headers.get("content-type"));
|
|
1510
|
+
if (acceptedKeyFor(content, mediaType) !== void 0)
|
|
1511
|
+
return void 0;
|
|
1512
|
+
return { mediaType: mediaType ?? null, accepted: Object.keys(content) };
|
|
1513
|
+
};
|
|
1514
|
+
var recorded = /* @__PURE__ */ new WeakMap();
|
|
1515
|
+
var recordedIssues = (request) => recorded.get(request);
|
|
1516
|
+
var bodyIssues = (context, contentType = "application/json") => {
|
|
1517
|
+
const issues = findBodyIssues(context, contentType);
|
|
1518
|
+
if (issues.length > 0)
|
|
1519
|
+
recorded.set(context.request, issues);
|
|
1520
|
+
return issues;
|
|
1521
|
+
};
|
|
1522
|
+
var findBodyIssues = (context, contentType) => {
|
|
1523
|
+
const resolved = requestBodyOf(context);
|
|
1524
|
+
if (!resolved)
|
|
1525
|
+
return [];
|
|
1526
|
+
const unsupported = unsupportedMediaType(context);
|
|
1527
|
+
if (unsupported) {
|
|
1528
|
+
return [
|
|
1529
|
+
{
|
|
1530
|
+
path: "",
|
|
1531
|
+
kind: "media_type",
|
|
1532
|
+
message: unsupported.mediaType === null ? "request body has no content-type" : `request body media type ${unsupported.mediaType} is not supported`
|
|
1533
|
+
}
|
|
1534
|
+
];
|
|
1535
|
+
}
|
|
1536
|
+
const key = acceptedKeyFor(resolved.content, mediaTypeOf(context.request.headers.get("content-type"))) ?? contentType;
|
|
1537
|
+
const schema = resolved.content?.[key]?.schema;
|
|
1538
|
+
if (!schema)
|
|
1539
|
+
return [];
|
|
1540
|
+
if (context.body.kind === "invalid") {
|
|
1541
|
+
return [
|
|
1542
|
+
{
|
|
1543
|
+
path: "",
|
|
1544
|
+
kind: "syntax",
|
|
1545
|
+
message: `request body is not valid ${context.body.mediaType}`
|
|
1546
|
+
}
|
|
1547
|
+
];
|
|
1548
|
+
}
|
|
1549
|
+
const value = context.body.kind === "json" || context.body.kind === "form" || context.body.kind === "text" ? context.body.value : void 0;
|
|
1550
|
+
if (value === void 0) {
|
|
1551
|
+
return resolved.required && context.body.kind === "empty" ? [{ path: "", kind: "required", message: "request body is required" }] : [];
|
|
1552
|
+
}
|
|
1553
|
+
return validateValue(context.document, resolveSchema(context.document, schema), value).map((issue) => ({ path: issue.path.join("."), kind: "schema", message: issue.message }));
|
|
1554
|
+
};
|
|
1555
|
+
|
|
1556
|
+
// ../core/dist/service.js
|
|
1557
|
+
var withIssues = (request, response) => {
|
|
1558
|
+
const issues = response.status >= 400 ? recordedIssues(request) : void 0;
|
|
1559
|
+
return issues && issues.length > 0 ? annotateResponse(response, { issues }) : response;
|
|
1560
|
+
};
|
|
1410
1561
|
var defineOperations = (handlers) => handlers;
|
|
1411
1562
|
var OperationRegistryError = class extends Error {
|
|
1412
1563
|
problems;
|
|
@@ -1492,9 +1643,7 @@ var createService = (options) => {
|
|
|
1492
1643
|
now
|
|
1493
1644
|
};
|
|
1494
1645
|
const short = await options.before?.(context);
|
|
1495
|
-
|
|
1496
|
-
return short;
|
|
1497
|
-
return handler(context);
|
|
1646
|
+
return withIssues(request, short ?? await handler(context));
|
|
1498
1647
|
};
|
|
1499
1648
|
app.on(operation.method.toUpperCase(), honoPath(operation.path), route);
|
|
1500
1649
|
}
|
|
@@ -1531,7 +1680,7 @@ var restoreNamespace = (sqlite, namespace, snapshot) => {
|
|
|
1531
1680
|
};
|
|
1532
1681
|
|
|
1533
1682
|
// ../core/dist/version.js
|
|
1534
|
-
var PACKAGE_VERSION = true ? "1.
|
|
1683
|
+
var PACKAGE_VERSION = true ? "1.1.1" : UNRELEASED_VERSION;
|
|
1535
1684
|
|
|
1536
1685
|
// ../core/dist/signing.js
|
|
1537
1686
|
var encoder = new TextEncoder();
|
|
@@ -1854,8 +2003,8 @@ var createWebhookHub = (options) => {
|
|
|
1854
2003
|
};
|
|
1855
2004
|
return hub;
|
|
1856
2005
|
};
|
|
1857
|
-
var
|
|
1858
|
-
var adminError2 = (status, message) =>
|
|
2006
|
+
var json3 = (status, body) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
|
|
2007
|
+
var adminError2 = (status, message) => json3(status, { error: { type: "mockingbird_admin", message } });
|
|
1859
2008
|
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1860
2009
|
var parseEndpoint = (value) => {
|
|
1861
2010
|
if (!isRecord3(value) || typeof value.url !== "string")
|
|
@@ -1886,7 +2035,7 @@ var parseEndpoint = (value) => {
|
|
|
1886
2035
|
return endpoint;
|
|
1887
2036
|
};
|
|
1888
2037
|
var webhookAdminRoutes = (hub) => ({
|
|
1889
|
-
"GET /webhooks": ({ url, namespace }) =>
|
|
2038
|
+
"GET /webhooks": ({ url, namespace }) => json3(200, {
|
|
1890
2039
|
deliveries: hub.deliveries(url.searchParams.get("all") === "1" ? void 0 : namespace).filter((d) => {
|
|
1891
2040
|
const type = url.searchParams.get("type");
|
|
1892
2041
|
return type === null || d.type === type;
|
|
@@ -1894,17 +2043,17 @@ var webhookAdminRoutes = (hub) => ({
|
|
|
1894
2043
|
}),
|
|
1895
2044
|
"GET /webhooks/events": ({ url, namespace }) => {
|
|
1896
2045
|
const type = url.searchParams.get("type");
|
|
1897
|
-
return
|
|
2046
|
+
return json3(200, {
|
|
1898
2047
|
events: hub.messages(url.searchParams.get("all") === "1" ? void 0 : namespace).filter((m) => type === null || m.type === type).map((m) => ({ ...m, payload: parsePayload(m) }))
|
|
1899
2048
|
});
|
|
1900
2049
|
},
|
|
1901
2050
|
"POST /webhooks/:id/replay": async ({ params }) => {
|
|
1902
2051
|
const replayed = await hub.replay(params.id);
|
|
1903
|
-
return replayed ?
|
|
2052
|
+
return replayed ? json3(200, replayed) : adminError2(404, `no delivery ${params.id}`);
|
|
1904
2053
|
},
|
|
1905
2054
|
"POST /webhooks/flush": async () => {
|
|
1906
2055
|
await hub.flush();
|
|
1907
|
-
return
|
|
2056
|
+
return json3(200, { status: "ok" });
|
|
1908
2057
|
},
|
|
1909
2058
|
"POST /webhooks/faults": ({ body, namespace }) => {
|
|
1910
2059
|
if (!isRecord3(body) || !["duplicate", "reorder", "drop"].includes(String(body.mode))) {
|
|
@@ -1914,9 +2063,9 @@ var webhookAdminRoutes = (hub) => ({
|
|
|
1914
2063
|
if (typeof body.count === "number")
|
|
1915
2064
|
fault.count = body.count;
|
|
1916
2065
|
hub.fault(namespace, fault);
|
|
1917
|
-
return
|
|
2066
|
+
return json3(201, { namespace, ...fault });
|
|
1918
2067
|
},
|
|
1919
|
-
"GET /webhook-endpoints": ({ namespace }) =>
|
|
2068
|
+
"GET /webhook-endpoints": ({ namespace }) => json3(200, {
|
|
1920
2069
|
endpoints: hub.endpoints(namespace).map(({ secret, ...rest }) => ({
|
|
1921
2070
|
...rest,
|
|
1922
2071
|
secret: secret ? "(set)" : null
|
|
@@ -1934,11 +2083,11 @@ var webhookAdminRoutes = (hub) => ({
|
|
|
1934
2083
|
parsed.push(endpoint);
|
|
1935
2084
|
}
|
|
1936
2085
|
const set = hub.setEndpoints(namespace, parsed);
|
|
1937
|
-
return
|
|
2086
|
+
return json3(200, { endpoints: set.map((e) => ({ ...e, secret: e.secret ? "(set)" : null })) });
|
|
1938
2087
|
},
|
|
1939
2088
|
"DELETE /webhook-endpoints": ({ namespace }) => {
|
|
1940
2089
|
hub.setEndpoints(namespace, []);
|
|
1941
|
-
return
|
|
2090
|
+
return json3(200, { status: "ok" });
|
|
1942
2091
|
}
|
|
1943
2092
|
});
|
|
1944
2093
|
var parsePayload = (message) => {
|
|
@@ -2291,8 +2440,15 @@ var createRuntime = (options) => {
|
|
|
2291
2440
|
const started = monotonicNow();
|
|
2292
2441
|
const url = new URL(request.url);
|
|
2293
2442
|
const operationId = operationIdFor(request, url.pathname);
|
|
2443
|
+
const contentLength = request.headers.get("content-length");
|
|
2444
|
+
const received = {
|
|
2445
|
+
contentType: request.headers.get("content-type"),
|
|
2446
|
+
bodyBytes: contentLength !== null && /^\d+$/.test(contentLength) ? Number(contentLength) : null,
|
|
2447
|
+
transferEncoding: request.headers.get("transfer-encoding")
|
|
2448
|
+
};
|
|
2294
2449
|
const log = (status, faultId, response2) => {
|
|
2295
2450
|
const noted = response2 ? responseNotes(response2) : void 0;
|
|
2451
|
+
const rejected = status >= 400 && faultId === void 0;
|
|
2296
2452
|
const entry = {
|
|
2297
2453
|
service: options.name,
|
|
2298
2454
|
namespace,
|
|
@@ -2304,7 +2460,9 @@ var createRuntime = (options) => {
|
|
|
2304
2460
|
unmatched: options.document !== void 0 && operationId === void 0,
|
|
2305
2461
|
...faultId !== void 0 ? { faultId } : {},
|
|
2306
2462
|
...noted?.ids && Object.keys(noted.ids).length > 0 ? { ids: noted.ids } : {},
|
|
2307
|
-
...noted?.adopted ? { adopted: true } : {}
|
|
2463
|
+
...noted?.adopted ? { adopted: true } : {},
|
|
2464
|
+
...rejected ? { request: { ...received } } : {},
|
|
2465
|
+
...rejected && noted?.issues && noted.issues.length > 0 ? { issues: noted.issues.map((issue) => ({ ...issue })) } : {}
|
|
2308
2466
|
};
|
|
2309
2467
|
metrics.record(entry);
|
|
2310
2468
|
journal.record({ ...entry, at: new Date(clock.now()).toISOString() });
|
|
@@ -2511,25 +2669,6 @@ var presetRoutes = (presets, runtime) => ({
|
|
|
2511
2669
|
}
|
|
2512
2670
|
});
|
|
2513
2671
|
|
|
2514
|
-
// ../core/dist/validation.js
|
|
2515
|
-
var bodyIssues = (context, contentType = "application/json") => {
|
|
2516
|
-
const requestBody = context.operation.operation.requestBody;
|
|
2517
|
-
if (!requestBody)
|
|
2518
|
-
return [];
|
|
2519
|
-
const resolved = deref(context.document, requestBody);
|
|
2520
|
-
const schema = resolved.content?.[contentType]?.schema;
|
|
2521
|
-
if (!schema)
|
|
2522
|
-
return [];
|
|
2523
|
-
const value = context.body.kind === "json" || context.body.kind === "form" ? context.body.value : void 0;
|
|
2524
|
-
if (context.body.kind === "invalid") {
|
|
2525
|
-
return [{ path: "", message: `request body is not valid ${context.body.mediaType}` }];
|
|
2526
|
-
}
|
|
2527
|
-
if (value === void 0) {
|
|
2528
|
-
return resolved.required ? [{ path: "", message: "request body is required" }] : [];
|
|
2529
|
-
}
|
|
2530
|
-
return validateValue(context.document, resolveSchema(context.document, schema), value).map((issue) => ({ path: issue.path.join("."), message: issue.message }));
|
|
2531
|
-
};
|
|
2532
|
-
|
|
2533
2672
|
// src/generated/openapi.ts
|
|
2534
2673
|
var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Intercom REST API 2.11 (Mockingbird subset)","description":"Stateful mock subset of the Intercom REST API (version 2.11): contacts (search, create,\\nupdate, get), conversations (create, update, reply as user or admin with attachments,\\nclose/open/snooze/assign, get, search) and the admin identity endpoints. Covers the backend's\\nmember messaging adapter and the Intercom sync adapter.\\n","version":"2.11","x-mockingbird-upstream":{"note":"Trimmed from Intercom's published 2.11 API reference to the operations and fields our consumers use (intercom-messaging.adapter.ts, intercom-api.adapter.ts) and the webhook receivers (messaging.controller.ts, the EMR IntercomWebhookService)."}},"servers":[{"url":"https://api.intercom.io"}],"security":[{"bearerAuth":[]}],"paths":{"/contacts/search":{"post":{"operationId":"SearchContacts","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"$ref":"#/components/schemas/ContactQuery"},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"responses":{"200":{"description":"Matching contacts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/contacts":{"post":{"operationId":"CreateContact","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactCreate"}}}},"responses":{"200":{"description":"The created contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/contacts/{contact_id}":{"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"contact","missing":0}}}],"get":{"operationId":"GetContact","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"operationId":"UpdateContact","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactUpdate"}}}},"responses":{"200":{"description":"The updated contact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/conversations":{"post":{"operationId":"CreateConversation","description":"A contact-initiated conversation. An optional \`Idempotency-Key\` header replays.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,40}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["from","body"],"properties":{"from":{"type":"object","required":["type","id"],"properties":{"type":{"type":"string","enum":["user","lead","contact"]},"id":{"type":"string","x-mockingbird-resource-ref":{"type":"contact","missing":0}}}},"body":{"type":"string","minLength":1,"maxLength":400},"created_at":{"type":"integer","minimum":1600000000,"maximum":1900000000}}}}}},"responses":{"200":{"description":"The first message of the new conversation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/conversations/search":{"post":{"operationId":"SearchConversations","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/DisplayAs"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"$ref":"#/components/schemas/ConversationQuery"},"pagination":{"$ref":"#/components/schemas/Pagination"},"sort_field":{"type":"string","enum":["updated_at","created_at","id","waiting_since"]},"sort_order":{"type":"string","enum":["ascending","descending"]}}}}}},"responses":{"200":{"description":"A page of matching conversations (without conversation parts)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/conversations/{conversation_id}":{"parameters":[{"$ref":"#/components/parameters/ConversationId"}],"get":{"operationId":"GetConversation","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/DisplayAs"}],"responses":{"200":{"description":"The conversation with its parts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Conversation"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"operationId":"UpdateConversation","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"parameters":[{"$ref":"#/components/parameters/DisplayAs"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"read":{"type":"boolean"},"title":{"type":"string","maxLength":120},"custom_attributes":{"type":"object","maxProperties":4,"additionalProperties":{"type":["string","number","boolean","null"]}}}}}}},"responses":{"200":{"description":"The updated conversation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Conversation"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/conversations/{conversation_id}/reply":{"parameters":[{"$ref":"#/components/parameters/ConversationId"}],"post":{"operationId":"ReplyConversation","description":"Reply as the contact (\`type: user\` + \`intercom_user_id\`) or as an admin (\`type: admin\` + \`admin_id\`), as JSON (attachments as base64 \`attachment_files\`) or multipart (\`attachment_files[]\` file parts). Admin comments fire \`conversation.admin.replied\`.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplyBody"}},"multipart/form-data":{"schema":{"type":"object","required":["message_type","type"],"properties":{"message_type":{"type":"string"},"type":{"type":"string"},"intercom_user_id":{"type":"string"},"admin_id":{"type":"string"},"body":{"type":"string"},"attachment_files[]":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"200":{"description":"The conversation, with the new part","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Conversation"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/conversations/{conversation_id}/parts":{"parameters":[{"$ref":"#/components/parameters/ConversationId"}],"post":{"operationId":"ManageConversation","description":"Close, open, snooze or assign; close and open fire \`conversation.admin.closed\` / \`opened\`.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["message_type","type","admin_id"],"properties":{"message_type":{"type":"string","enum":["close","open","snoozed","assignment"]},"type":{"type":"string","enum":["admin"]},"admin_id":{"type":"string","x-mockingbird-resource-ref":{"type":"admin","missing":"9999999"}},"body":{"type":"string","maxLength":400},"snoozed_until":{"type":"integer","minimum":1600000000,"maximum":1900000000},"assignee_id":{"type":"string","x-mockingbird-resource-ref":{"type":"admin","missing":"9999999"}}}}}}},"responses":{"200":{"description":"The conversation, with the new part","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Conversation"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admins":{"get":{"operationId":"ListAdmins","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The workspace's admins","content":{"application/json":{"schema":{"type":"object","required":["type","admins"],"properties":{"type":{"type":"string","enum":["admin.list"]},"admins":{"type":"array","items":{"$ref":"#/components/schemas/Admin"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/me":{"get":{"operationId":"GetMe","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The admin that owns the access token","content":{"application/json":{"schema":{"type":"object","required":["type","id","email","app"],"properties":{"type":{"type":"string","enum":["admin"]},"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"has_inbox_seat":{"type":"boolean"},"avatar":{"type":"object"},"app":{"type":"object","required":["type","id_code"],"properties":{"type":{"type":"string"},"id_code":{"type":"string"},"name":{"type":"string"},"created_at":{"type":"integer"},"secure":{"type":"boolean"},"identity_verification":{"type":"boolean"},"timezone":{"type":"string"},"region":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"parameters":{"ConversationId":{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"conversation","missing":"999999999999999"}}},"DisplayAs":{"name":"display_as","in":"query","schema":{"type":"string","enum":["plaintext"]}}},"responses":{"BadRequest":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorList"}}}},"Unauthorized":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorList"}}}},"NotFound":{"description":"Unknown resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorList"}}}},"Conflict":{"description":"A contact with that external_id or email already exists (or an idempotency conflict)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorList"}}}}},"schemas":{"ErrorList":{"type":"object","required":["type","errors"],"properties":{"type":{"type":"string","enum":["error.list"]},"request_id":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"errors":{"type":"array","minItems":1,"items":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}},"Pagination":{"type":"object","properties":{"per_page":{"type":"integer","minimum":1,"maximum":150},"starting_after":{"type":"string","maxLength":80}}},"ContactFilter":{"type":"object","required":["field","operator","value"],"properties":{"field":{"type":"string","enum":["external_id","email","id","name","role","phone"]},"operator":{"type":"string","enum":["=","!=","~","!~","^","$","IN","NIN"]},"value":{"oneOf":[{"type":"string","maxLength":80},{"type":"array","maxItems":3,"items":{"type":"string","maxLength":80}}]}}},"ContactQuery":{"oneOf":[{"$ref":"#/components/schemas/ContactFilter"},{"type":"object","required":["operator","value"],"properties":{"operator":{"type":"string","enum":["AND","OR"]},"value":{"type":"array","minItems":1,"maxItems":3,"items":{"$ref":"#/components/schemas/ContactFilter"}}}}]},"ConversationFilter":{"type":"object","required":["field","operator","value"],"properties":{"field":{"type":"string","enum":["id","contact_ids","admin_assignee_id","team_assignee_id","state","open","read","created_at","updated_at","source.author.email","source.delivered_as"]},"operator":{"type":"string","enum":["=","!=","<",">","~","IN","NIN"]},"value":{"oneOf":[{"type":"string","maxLength":80},{"type":"integer"},{"type":"boolean"},{"type":"array","maxItems":3,"items":{"type":"string","maxLength":80}}]}}},"ConversationQuery":{"oneOf":[{"$ref":"#/components/schemas/ConversationFilter"},{"type":"object","required":["operator","value"],"properties":{"operator":{"type":"string","enum":["AND","OR"]},"value":{"type":"array","minItems":1,"maxItems":3,"items":{"$ref":"#/components/schemas/ConversationFilter"}}}}]},"CustomAttributes":{"type":"object","maxProperties":30,"additionalProperties":{"type":["string","number","boolean","null"]}},"ContactCreate":{"type":"object","properties":{"role":{"type":"string","enum":["user","lead"]},"external_id":{"description":"Any string. The first branch steers the walk generator toward a few values, so random walks reach the duplicate (409) path.","anyOf":[{"type":"string","pattern":"^[1-4]$"},{"type":"string","minLength":1,"maxLength":64}]},"email":{"type":"string","format":"email","maxLength":120},"name":{"type":["string","null"],"maxLength":80},"phone":{"type":["string","null"],"maxLength":40},"signed_up_at":{"type":["integer","null"],"minimum":1000000000,"maximum":1900000000},"last_seen_at":{"type":["integer","null"],"minimum":1000000000,"maximum":1900000000},"custom_attributes":{"$ref":"#/components/schemas/CustomAttributes"}}},"ContactUpdate":{"allOf":[{"$ref":"#/components/schemas/ContactCreate"}]},"ReplyBody":{"type":"object","required":["message_type","type"],"properties":{"message_type":{"type":"string","enum":["comment","note","quick_reply"]},"type":{"type":"string","enum":["user","admin"]},"body":{"type":"string","maxLength":400},"intercom_user_id":{"type":"string","x-mockingbird-resource-ref":{"type":"contact","missing":0}},"user_id":{"type":"string","maxLength":64},"email":{"type":"string","maxLength":120},"admin_id":{"type":"string","x-mockingbird-resource-ref":{"type":"admin","missing":"9999999"}},"created_at":{"type":"integer","minimum":1600000000,"maximum":1900000000},"attachment_urls":{"type":"array","maxItems":3,"items":{"type":"string","maxLength":200}},"attachment_files":{"type":"array","maxItems":3,"items":{"type":"object","required":["content_type","data","name"],"properties":{"content_type":{"type":"string","maxLength":80},"data":{"type":"string","maxLength":400},"name":{"type":"string","minLength":1,"maxLength":80}}}}}},"Contact":{"type":"object","required":["type","id","role","created_at","updated_at","custom_attributes"],"properties":{"type":{"type":"string","enum":["contact"]},"id":{"type":"string","x-mockingbird-resource":{"type":"contact","identity":true}},"workspace_id":{"type":"string"},"external_id":{"type":["string","null"]},"role":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"name":{"type":["string","null"]},"avatar":{"type":["string","null"]},"owner_id":{"type":["integer","null"]},"has_hard_bounced":{"type":"boolean"},"marked_email_as_spam":{"type":"boolean"},"unsubscribed_from_emails":{"type":"boolean"},"created_at":{"type":"integer","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"integer","x-mockingbird-volatile":{"kind":"timestamp"}},"signed_up_at":{"type":["integer","null"]},"last_seen_at":{"type":["integer","null"]},"custom_attributes":{"type":"object"},"tags":{"type":"object"},"notes":{"type":"object"},"companies":{"type":"object"},"location":{"type":"object"},"social_profiles":{"type":"object"}}},"Pages":{"type":"object","required":["type","page","per_page","total_pages"],"properties":{"type":{"type":"string","enum":["pages"]},"page":{"type":"integer"},"per_page":{"type":"integer"},"total_pages":{"type":"integer"},"next":{"type":"object","required":["page","starting_after"],"properties":{"page":{"type":"integer"},"starting_after":{"type":"string"}}}}},"ContactList":{"type":"object","required":["type","data","total_count","pages"],"properties":{"type":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"total_count":{"type":"integer"},"pages":{"$ref":"#/components/schemas/Pages"}}},"Author":{"type":"object","required":["type","id"],"properties":{"type":{"type":"string"},"id":{"type":"string"},"name":{"type":["string","null"]},"email":{"type":["string","null"]}}},"Attachment":{"type":"object","required":["type","name","url","content_type"],"properties":{"type":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"content_type":{"type":"string"},"filesize":{"type":"integer"},"width":{"type":["integer","null"]},"height":{"type":["integer","null"]}}},"ConversationPart":{"type":"object","required":["type","id","part_type","created_at","author"],"properties":{"type":{"type":"string","enum":["conversation_part"]},"id":{"type":"string"},"part_type":{"type":"string"},"body":{"type":["string","null"]},"created_at":{"type":"integer","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"integer","x-mockingbird-volatile":{"kind":"timestamp"}},"notified_at":{"type":"integer","x-mockingbird-volatile":{"kind":"timestamp"}},"assigned_to":{"type":["object","null"]},"author":{"$ref":"#/components/schemas/Author"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/Attachment"}},"external_id":{"type":["string","null"]},"redacted":{"type":"boolean"}}},"Conversation":{"type":"object","required":["type","id","created_at","updated_at","open","state","read","source","contacts"],"properties":{"type":{"type":"string","enum":["conversation"]},"id":{"type":"string","x-mockingbird-resource":{"type":"conversation","identity":true}},"title":{"type":["string","null"]},"created_at":{"type":"integer","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"integer","x-mockingbird-volatile":{"kind":"timestamp"}},"waiting_since":{"type":["integer","null"],"x-mockingbird-volatile":{"kind":"timestamp"}},"snoozed_until":{"type":["integer","null"]},"open":{"type":"boolean"},"state":{"type":"string","enum":["open","closed","snoozed"]},"read":{"type":"boolean"},"priority":{"type":"string"},"admin_assignee_id":{"type":["integer","null"]},"team_assignee_id":{"type":["string","null"]},"tags":{"type":"object"},"conversation_rating":{"type":["object","null"]},"source":{"type":"object","required":["type","id","delivered_as","body","author"],"properties":{"type":{"type":"string"},"id":{"type":"string"},"delivered_as":{"type":"string"},"subject":{"type":"string"},"body":{"type":["string","null"]},"author":{"$ref":"#/components/schemas/Author"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/Attachment"}},"url":{"type":["string","null"]},"redacted":{"type":"boolean"}}},"contacts":{"type":"object","required":["type","contacts"],"properties":{"type":{"type":"string"},"contacts":{"type":"array","items":{"type":"object","required":["type","id"],"properties":{"type":{"type":"string"},"id":{"type":"string"},"external_id":{"type":["string","null"]}}}}}},"teammates":{"type":"object"},"custom_attributes":{"type":"object"},"first_contact_reply":{"type":["object","null"]},"sla_applied":{"type":["object","null"]},"statistics":{"type":["object","null"]},"ai_agent_participated":{"type":"boolean"},"conversation_parts":{"type":"object","required":["type","conversation_parts","total_count"],"properties":{"type":{"type":"string"},"conversation_parts":{"type":"array","items":{"$ref":"#/components/schemas/ConversationPart"}},"total_count":{"type":"integer"}}}}},"ConversationList":{"type":"object","required":["type","pages","total_count","conversations"],"properties":{"type":{"type":"string","enum":["conversation.list"]},"pages":{"$ref":"#/components/schemas/Pages"},"total_count":{"type":"integer"},"conversations":{"type":"array","items":{"$ref":"#/components/schemas/Conversation"}}}},"Message":{"type":"object","required":["type","id","created_at","body","message_type","conversation_id"],"properties":{"type":{"type":"string","enum":["user_message"]},"id":{"type":"string"},"created_at":{"type":"integer","x-mockingbird-volatile":{"kind":"timestamp"}},"body":{"type":"string"},"message_type":{"type":"string","enum":["inapp"]},"conversation_id":{"type":"string","x-mockingbird-resource":{"type":"conversation","identity":true}}}},"Admin":{"type":"object","required":["type","id","name","email"],"properties":{"type":{"type":"string","enum":["admin"]},"id":{"type":"string","x-mockingbird-resource":{"type":"admin","identity":true}},"name":{"type":"string"},"email":{"type":"string"},"job_title":{"type":["string","null"]},"away_mode_enabled":{"type":"boolean"},"away_mode_reassign":{"type":"boolean"},"has_inbox_seat":{"type":"boolean"},"team_ids":{"type":"array","items":{"type":"integer"}}}}}}}`);
|
|
2535
2674
|
var operationIds = ["SearchContacts", "CreateContact", "GetContact", "UpdateContact", "CreateConversation", "SearchConversations", "GetConversation", "UpdateConversation", "ReplyConversation", "ManageConversation", "ListAdmins", "GetMe"];
|
|
@@ -2683,6 +2822,7 @@ var IntercomState = class {
|
|
|
2683
2822
|
this.admins = new Collection(sqlite, namespace, "admins");
|
|
2684
2823
|
this.settings = new Collection(sqlite, namespace, "settings");
|
|
2685
2824
|
this.counters = new Collection(sqlite, namespace, "counters");
|
|
2825
|
+
this.outbox = new OutboxStore(sqlite, namespace, "outbox");
|
|
2686
2826
|
this.workspaceId = "mockapp";
|
|
2687
2827
|
this.ensureSeeded();
|
|
2688
2828
|
}
|
|
@@ -2693,6 +2833,7 @@ var IntercomState = class {
|
|
|
2693
2833
|
admins;
|
|
2694
2834
|
settings;
|
|
2695
2835
|
counters;
|
|
2836
|
+
outbox;
|
|
2696
2837
|
workspaceId;
|
|
2697
2838
|
ensureSeeded() {
|
|
2698
2839
|
if (this.admins.count() === 0) {
|
|
@@ -2810,8 +2951,8 @@ var INTERCOM_PRESETS = {
|
|
|
2810
2951
|
webhook: { mode: "drop" }
|
|
2811
2952
|
}
|
|
2812
2953
|
};
|
|
2813
|
-
var
|
|
2814
|
-
var adminError3 = (status, message) =>
|
|
2954
|
+
var json4 = (status, body) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
|
|
2955
|
+
var adminError3 = (status, message) => json4(status, { error: { type: "mockingbird_admin", message } });
|
|
2815
2956
|
var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2816
2957
|
var guard = (run) => {
|
|
2817
2958
|
try {
|
|
@@ -2826,8 +2967,9 @@ var adminRoutes = (runtime) => {
|
|
|
2826
2967
|
const conversation = (namespace, id) => api(namespace).state.conversations.get(id);
|
|
2827
2968
|
const defaultAdmin = (namespace) => api(namespace).state.admins.list({ order: "oldest" }).at(0)?.value.id ?? "";
|
|
2828
2969
|
return {
|
|
2829
|
-
|
|
2830
|
-
"GET /
|
|
2970
|
+
...outboxAdminRoutes(runtime, (instance) => instance.state.outbox),
|
|
2971
|
+
"GET /contacts": ({ namespace }) => json4(200, { contacts: api(namespace).contacts() }),
|
|
2972
|
+
"GET /conversations": ({ namespace }) => json4(200, { conversations: api(namespace).conversations() }),
|
|
2831
2973
|
"POST /conversations": ({ body, namespace }) => guard(() => {
|
|
2832
2974
|
if (!isRecord5(body) || typeof body.body !== "string") {
|
|
2833
2975
|
return adminError3(400, 'expected {"contactId" | "externalId", "adminId"?, "body"}');
|
|
@@ -2840,7 +2982,7 @@ var adminRoutes = (runtime) => {
|
|
|
2840
2982
|
adminId: typeof body.adminId === "string" ? body.adminId : defaultAdmin(namespace),
|
|
2841
2983
|
body: body.body
|
|
2842
2984
|
});
|
|
2843
|
-
return
|
|
2985
|
+
return json4(201, created);
|
|
2844
2986
|
}),
|
|
2845
2987
|
"POST /conversations/:id/admin-reply": ({ params, body, namespace }) => guard(() => {
|
|
2846
2988
|
const found = conversation(namespace, params.id);
|
|
@@ -2848,32 +2990,33 @@ var adminRoutes = (runtime) => {
|
|
|
2848
2990
|
if (!isRecord5(body) || typeof body.body !== "string") {
|
|
2849
2991
|
return adminError3(
|
|
2850
2992
|
400,
|
|
2851
|
-
'expected {"adminId"?, "body", "messageType"?: "comment" | "note"}'
|
|
2993
|
+
'expected {"adminId" | "admin_id"?, "body", "messageType"?: "comment" | "note"}'
|
|
2852
2994
|
);
|
|
2853
2995
|
}
|
|
2854
2996
|
const instance = api(namespace);
|
|
2997
|
+
const requested = body.adminId ?? body.admin_id;
|
|
2855
2998
|
const author = instance.state.admins.get(
|
|
2856
|
-
typeof
|
|
2999
|
+
typeof requested === "string" ? requested : defaultAdmin(namespace)
|
|
2857
3000
|
);
|
|
2858
|
-
if (!author) return adminError3(404, `no admin ${String(
|
|
3001
|
+
if (!author) return adminError3(404, `no admin ${String(requested)}`);
|
|
2859
3002
|
const next = instance.appendPart(found, {
|
|
2860
3003
|
partType: body.messageType === "note" ? "note" : "comment",
|
|
2861
3004
|
author: { type: "admin", id: author.id, name: author.name, email: author.email },
|
|
2862
3005
|
body: toHtml(body.body)
|
|
2863
3006
|
});
|
|
2864
|
-
return
|
|
3007
|
+
return json4(200, next);
|
|
2865
3008
|
}),
|
|
2866
3009
|
"POST /conversations/:id/close": ({ params, body, namespace }) => guard(() => {
|
|
2867
3010
|
const found = conversation(namespace, params.id);
|
|
2868
3011
|
if (!found) return adminError3(404, `no conversation ${params.id}`);
|
|
2869
3012
|
const adminId = isRecord5(body) && typeof body.adminId === "string" ? body.adminId : defaultAdmin(namespace);
|
|
2870
|
-
return
|
|
3013
|
+
return json4(200, api(namespace).manage(found, { action: "close", adminId }));
|
|
2871
3014
|
}),
|
|
2872
3015
|
"POST /conversations/:id/open": ({ params, body, namespace }) => guard(() => {
|
|
2873
3016
|
const found = conversation(namespace, params.id);
|
|
2874
3017
|
if (!found) return adminError3(404, `no conversation ${params.id}`);
|
|
2875
3018
|
const adminId = isRecord5(body) && typeof body.adminId === "string" ? body.adminId : defaultAdmin(namespace);
|
|
2876
|
-
return
|
|
3019
|
+
return json4(200, api(namespace).manage(found, { action: "open", adminId }));
|
|
2877
3020
|
}),
|
|
2878
3021
|
"PUT /admins": ({ body, namespace }) => {
|
|
2879
3022
|
const list = Array.isArray(body) ? body : isRecord5(body) ? body.admins : void 0;
|
|
@@ -2895,9 +3038,9 @@ var adminRoutes = (runtime) => {
|
|
|
2895
3038
|
team_ids: []
|
|
2896
3039
|
});
|
|
2897
3040
|
}
|
|
2898
|
-
return
|
|
3041
|
+
return json4(200, { admins: state.admins.list({ order: "oldest" }).map((row) => row.value) });
|
|
2899
3042
|
},
|
|
2900
|
-
"GET /settings": ({ namespace }) =>
|
|
3043
|
+
"GET /settings": ({ namespace }) => json4(200, api(namespace).state.current()),
|
|
2901
3044
|
"PUT /settings": ({ body, namespace }) => {
|
|
2902
3045
|
if (!isRecord5(body)) return adminError3(400, "expected a JSON object");
|
|
2903
3046
|
const patch = {};
|
|
@@ -2911,7 +3054,7 @@ var adminRoutes = (runtime) => {
|
|
|
2911
3054
|
}
|
|
2912
3055
|
patch.customAttributes = body.customAttributes === null ? null : body.customAttributes.map(String);
|
|
2913
3056
|
}
|
|
2914
|
-
return
|
|
3057
|
+
return json4(200, api(namespace).state.update(patch));
|
|
2915
3058
|
}
|
|
2916
3059
|
};
|
|
2917
3060
|
};
|
|
@@ -2924,14 +3067,15 @@ var createRuntime2 = (options = {}) => {
|
|
|
2924
3067
|
...hooks?.retryDelaysMs ? { retryDelaysMs: hooks.retryDelaysMs } : {},
|
|
2925
3068
|
...hooks?.fetch ? { fetch: hooks.fetch } : {},
|
|
2926
3069
|
...options.wallClock ? { now: options.wallClock } : {},
|
|
2927
|
-
endpoints: (hooks?.urls ?? []).map(
|
|
2928
|
-
|
|
3070
|
+
endpoints: (hooks?.urls ?? []).map((entry, index) => {
|
|
3071
|
+
const target = typeof entry === "string" ? { url: entry } : entry;
|
|
3072
|
+
return {
|
|
2929
3073
|
id: `we_intercom_${index}`,
|
|
2930
|
-
url,
|
|
3074
|
+
url: target.url,
|
|
2931
3075
|
...hooks?.secret ? { secret: hooks.secret } : {},
|
|
2932
|
-
events: [...hooks?.events ?? DEFAULT_TOPICS]
|
|
2933
|
-
}
|
|
2934
|
-
)
|
|
3076
|
+
events: [...target.events ?? hooks?.events ?? DEFAULT_TOPICS]
|
|
3077
|
+
};
|
|
3078
|
+
})
|
|
2935
3079
|
});
|
|
2936
3080
|
const runtime = createRuntime({
|
|
2937
3081
|
name: INTERCOM_NAMESPACE,
|
|
@@ -2972,7 +3116,9 @@ var INTERCOM_TOPICS = [
|
|
|
2972
3116
|
"conversation.admin.opened",
|
|
2973
3117
|
"conversation.admin.snoozed",
|
|
2974
3118
|
"conversation.admin.assigned",
|
|
2975
|
-
"conversation.admin.single.created"
|
|
3119
|
+
"conversation.admin.single.created",
|
|
3120
|
+
"conversation.user.created",
|
|
3121
|
+
"conversation.user.replied"
|
|
2976
3122
|
];
|
|
2977
3123
|
var CONTACT_FIELDS = [
|
|
2978
3124
|
"id",
|
|
@@ -3407,6 +3553,17 @@ var IntercomAPI = class {
|
|
|
3407
3553
|
parts: []
|
|
3408
3554
|
};
|
|
3409
3555
|
this.state.conversations.insert(conversation.id, conversation);
|
|
3556
|
+
const text2 = String(body.body);
|
|
3557
|
+
this.recordSent({
|
|
3558
|
+
operation: "CreateConversation",
|
|
3559
|
+
conversation,
|
|
3560
|
+
partId: null,
|
|
3561
|
+
partType: "source",
|
|
3562
|
+
author: conversation.source.author,
|
|
3563
|
+
bodyLength: text2.length,
|
|
3564
|
+
attachmentCount: 0
|
|
3565
|
+
});
|
|
3566
|
+
this.notify("conversation.user.created", conversation, []);
|
|
3410
3567
|
return annotateResponse(
|
|
3411
3568
|
jsonRes(200, {
|
|
3412
3569
|
type: "user_message",
|
|
@@ -3577,6 +3734,15 @@ var IntercomAPI = class {
|
|
|
3577
3734
|
body: body === void 0 ? null : toHtml(body),
|
|
3578
3735
|
attachments: stored
|
|
3579
3736
|
});
|
|
3737
|
+
this.recordSent({
|
|
3738
|
+
operation: "ReplyConversation",
|
|
3739
|
+
conversation: next,
|
|
3740
|
+
partId,
|
|
3741
|
+
partType: messageType,
|
|
3742
|
+
author,
|
|
3743
|
+
bodyLength: body?.length ?? 0,
|
|
3744
|
+
attachmentCount: stored.length
|
|
3745
|
+
});
|
|
3580
3746
|
return annotateResponse(jsonRes(200, this.conversationBody(next, { parts: next.parts })), {
|
|
3581
3747
|
ids: { conversationId: next.id, partId }
|
|
3582
3748
|
});
|
|
@@ -3611,8 +3777,29 @@ var IntercomAPI = class {
|
|
|
3611
3777
|
};
|
|
3612
3778
|
this.state.conversations.update(conversation.id, next);
|
|
3613
3779
|
if (byAdmin && visible) this.notify("conversation.admin.replied", next, [part]);
|
|
3780
|
+
if (input.author.type === "user") this.notify("conversation.user.replied", next, [part]);
|
|
3614
3781
|
return next;
|
|
3615
3782
|
}
|
|
3783
|
+
/** Record what the API client sent, for `GET /__admin/outbox`: metadata only, never the body. */
|
|
3784
|
+
recordSent(input) {
|
|
3785
|
+
const at = new Date(this.now()).toISOString();
|
|
3786
|
+
this.state.outbox.record({
|
|
3787
|
+
id: `sent_${this.state.next("sent")}`,
|
|
3788
|
+
to: [input.conversation.id, input.conversation.contactId],
|
|
3789
|
+
createdAt: at,
|
|
3790
|
+
at,
|
|
3791
|
+
operation: input.operation,
|
|
3792
|
+
conversationId: input.conversation.id,
|
|
3793
|
+
contactId: input.conversation.contactId,
|
|
3794
|
+
partId: input.partId,
|
|
3795
|
+
partType: input.partType,
|
|
3796
|
+
authorType: input.author.type === "admin" ? "admin" : "user",
|
|
3797
|
+
authorId: input.author.id,
|
|
3798
|
+
hasBody: input.bodyLength > 0,
|
|
3799
|
+
bodyLength: input.bodyLength,
|
|
3800
|
+
attachmentCount: input.attachmentCount
|
|
3801
|
+
});
|
|
3802
|
+
}
|
|
3616
3803
|
manageConversation(context) {
|
|
3617
3804
|
return this.withConversation(context, (conversation) => {
|
|
3618
3805
|
const body = this.json(context);
|
|
@@ -3832,4 +4019,4 @@ export {
|
|
|
3832
4019
|
IntercomError,
|
|
3833
4020
|
IntercomAPI
|
|
3834
4021
|
};
|
|
3835
|
-
//# sourceMappingURL=chunk-
|
|
4022
|
+
//# sourceMappingURL=chunk-G2BMC225.js.map
|