@ours.network/cowork 1.1.4 → 1.2.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/README.md +3 -0
- package/dist/cli.js +220 -8
- package/dist/daemon.js +1016 -156
- package/dist/web/assets/app.js +9 -9
- package/docs/05-room-workflow.md +37 -1
- package/docs/07-messaging-history.md +9 -3
- package/docs/08-backup-restore.md +1 -1
- package/docs/10-limitations.md +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,8 @@ The package keeps room metadata and a per-room indexed `archive.sqlite3` in its
|
|
|
23
23
|
|
|
24
24
|
Ordinary ours-mcp identities can join only as remote participants over the ours protocol.
|
|
25
25
|
|
|
26
|
+
Granted room members can create message-only scoped reply threads for an explicit subset of stable room participant IDs through the generic Ours command catalog's `start_thread` command. Selected members receive separate root copies and reply with the SDK's native `reply_to_wire_id`; Cowork maps each descendant to the recipient's local immediate-parent copy. The selected participant-ID/CID pairs are immutable, later members are not backfilled, and excluded members receive no scoped message, file notice, notification, participant-history row, command result, or routing metadata. A message without `reply_to_wire_id` remains an ordinary whole-room message. See [Room workflow](./docs/05-room-workflow.md#scoped-reply-threads) for command discovery, schema, errors, and retry behavior, and [Messaging and history](./docs/07-messaging-history.md#reply-threading) for reply and history semantics.
|
|
27
|
+
|
|
26
28
|
Active participants can also send files through the room identity. Cowork treats
|
|
27
29
|
them as opaque bytes, archives them before consuming SDK inbox state, and relays an
|
|
28
30
|
SDK-authenticated metadata envelope plus the binary file to every other active seat.
|
|
@@ -42,3 +44,4 @@ ours-cowork docs web
|
|
|
42
44
|
|
|
43
45
|
Before production use, read the limitations topic. In particular, backups require a stopped daemon and restore uses the complete state directory.
|
|
44
46
|
Lost room identity leases are recovered automatically with a non-force bind and exact persisted-CID proof. Operators can invoke the same safe path explicitly with `ours-cowork room rebind <room-id>`; it never recreates an established identity or steals a live lease.
|
|
47
|
+
The localhost host-management CLI/API and web Archive retain full scoped-thread visibility for administrators, including excluded-member traffic that participant APIs hide. Runtime `room.history` is an authenticated, grant-gated participant view with viewer-local cursors; host cursors and participant cursors are not interchangeable. The shared SDK history remains local to each identity and does not define Cowork routing or host archive retention.
|
package/dist/cli.js
CHANGED
|
@@ -4351,11 +4351,85 @@ var SHARED_ROOM_COMMANDS = [
|
|
|
4351
4351
|
"room.role.rest.remove"
|
|
4352
4352
|
];
|
|
4353
4353
|
var RUNTIME_COMMAND_NAMES = [
|
|
4354
|
+
"start_thread",
|
|
4354
4355
|
"list-members",
|
|
4355
4356
|
"remove-member",
|
|
4356
4357
|
...SHARED_ROOM_COMMANDS
|
|
4357
4358
|
];
|
|
4358
4359
|
|
|
4360
|
+
// src/thread-contracts.ts
|
|
4361
|
+
var ParticipantIdSchema = external_exports.string().regex(
|
|
4362
|
+
/^[0-7][0-9a-hjkmnp-tv-z]{25}$/,
|
|
4363
|
+
"must be a 26-character lowercase Crockford ULID"
|
|
4364
|
+
);
|
|
4365
|
+
var ContainerIdSchema = external_exports.string().regex(/^[0-9a-f]{64}$/i, "must be a 64-character hexadecimal CID").transform((value) => value.toUpperCase());
|
|
4366
|
+
var TopicTextSchema = external_exports.string().refine(
|
|
4367
|
+
(value) => Array.from(value).length >= 1 && Array.from(value).length <= 120 && value.trim().length > 0 && !/[\p{Cc}\p{Cf}]/u.test(value),
|
|
4368
|
+
"topic must contain 1-120 Unicode characters without control or format characters"
|
|
4369
|
+
);
|
|
4370
|
+
var InputTopicSchema = TopicTextSchema.transform((value) => value.trim());
|
|
4371
|
+
var StoredTopicSchema = TopicTextSchema.refine(
|
|
4372
|
+
(value) => value === value.trim(),
|
|
4373
|
+
"stored topic must already be trimmed"
|
|
4374
|
+
);
|
|
4375
|
+
var IdempotencyKeySchema = external_exports.string().regex(
|
|
4376
|
+
/^[A-Za-z0-9._:-]{1,128}$/,
|
|
4377
|
+
"must contain 1-128 portable idempotency-key characters"
|
|
4378
|
+
);
|
|
4379
|
+
var ThreadMemberSchema = external_exports.object({
|
|
4380
|
+
participant_id: ParticipantIdSchema,
|
|
4381
|
+
identity: ContainerIdSchema
|
|
4382
|
+
}).strict();
|
|
4383
|
+
var ThreadRootSchema = external_exports.object({
|
|
4384
|
+
schema_version: external_exports.literal(1),
|
|
4385
|
+
thread_id: ParticipantIdSchema,
|
|
4386
|
+
topic: StoredTopicSchema,
|
|
4387
|
+
creator_participant_id: ParticipantIdSchema,
|
|
4388
|
+
members: external_exports.array(ThreadMemberSchema).min(1),
|
|
4389
|
+
idempotency_key: IdempotencyKeySchema,
|
|
4390
|
+
fingerprint: external_exports.string().regex(/^[0-9a-f]{64}$/, "must be a lowercase SHA-256 digest")
|
|
4391
|
+
}).strict().superRefine((root, context) => {
|
|
4392
|
+
const participantIds = /* @__PURE__ */ new Set();
|
|
4393
|
+
const identities = /* @__PURE__ */ new Set();
|
|
4394
|
+
for (const [index, member] of root.members.entries()) {
|
|
4395
|
+
if (participantIds.has(member.participant_id)) {
|
|
4396
|
+
context.addIssue({
|
|
4397
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4398
|
+
path: ["members", index, "participant_id"],
|
|
4399
|
+
message: "thread member participant IDs must be unique"
|
|
4400
|
+
});
|
|
4401
|
+
}
|
|
4402
|
+
participantIds.add(member.participant_id);
|
|
4403
|
+
if (identities.has(member.identity)) {
|
|
4404
|
+
context.addIssue({
|
|
4405
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4406
|
+
path: ["members", index, "identity"],
|
|
4407
|
+
message: "thread member identities must be unique"
|
|
4408
|
+
});
|
|
4409
|
+
}
|
|
4410
|
+
identities.add(member.identity);
|
|
4411
|
+
}
|
|
4412
|
+
if (!participantIds.has(root.creator_participant_id)) {
|
|
4413
|
+
context.addIssue({
|
|
4414
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4415
|
+
path: ["creator_participant_id"],
|
|
4416
|
+
message: "thread creator must be a member"
|
|
4417
|
+
});
|
|
4418
|
+
}
|
|
4419
|
+
});
|
|
4420
|
+
var ThreadScopeSchema = external_exports.object({
|
|
4421
|
+
thread_id: ParticipantIdSchema,
|
|
4422
|
+
parent_key: external_exports.string().regex(
|
|
4423
|
+
/^(?:message|file):[0-7][0-9a-hjkmnp-tv-z]{25}$/,
|
|
4424
|
+
"must identify an immediate message or file parent"
|
|
4425
|
+
).optional()
|
|
4426
|
+
}).strict();
|
|
4427
|
+
var StartThreadInputSchema = external_exports.object({
|
|
4428
|
+
topic: InputTopicSchema,
|
|
4429
|
+
participant_ids: external_exports.array(ParticipantIdSchema).min(1),
|
|
4430
|
+
idempotency_key: IdempotencyKeySchema
|
|
4431
|
+
}).strict();
|
|
4432
|
+
|
|
4359
4433
|
// src/contracts.ts
|
|
4360
4434
|
var MAX_TEXT_BYTES = 262144;
|
|
4361
4435
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
@@ -4379,10 +4453,10 @@ var LowerCrockfordUlidSchema = external_exports.string().regex(
|
|
|
4379
4453
|
/^[0-7][0-9a-hjkmnp-tv-z]{25}$/,
|
|
4380
4454
|
"must be a 26-character lowercase Crockford ULID"
|
|
4381
4455
|
);
|
|
4382
|
-
var
|
|
4456
|
+
var ContainerIdSchema2 = external_exports.string().regex(/^[0-9a-f]{64}$/i, "must be a 64-character hexadecimal CID").transform((value) => value.toUpperCase());
|
|
4383
4457
|
var RuntimeCommandNameSchema = external_exports.union([external_exports.enum(RUNTIME_COMMAND_NAMES), ConsumerCommandNameSchema]);
|
|
4384
4458
|
var RuntimeCommandGrantSchema = external_exports.object({
|
|
4385
|
-
caller_cid:
|
|
4459
|
+
caller_cid: ContainerIdSchema2,
|
|
4386
4460
|
command: RuntimeCommandNameSchema
|
|
4387
4461
|
}).strict();
|
|
4388
4462
|
function isStrictRfc3339(value) {
|
|
@@ -4727,7 +4801,7 @@ var CurrentRoomSchema = external_exports.object({
|
|
|
4727
4801
|
lifecycle_request: external_exports.object({
|
|
4728
4802
|
request_id: external_exports.string().min(1).max(256),
|
|
4729
4803
|
command: external_exports.enum(["room.close", "room.delete"]),
|
|
4730
|
-
caller_cid:
|
|
4804
|
+
caller_cid: ContainerIdSchema2,
|
|
4731
4805
|
accepted_at: Rfc3339Schema,
|
|
4732
4806
|
state: external_exports.enum(["pending", "failed", "completed"]),
|
|
4733
4807
|
error: external_exports.literal("lifecycle_failed").optional()
|
|
@@ -4881,7 +4955,7 @@ var AcceptExternalInviteInputSchema = external_exports.object({
|
|
|
4881
4955
|
(value) => Buffer.byteLength(value, "utf8") <= MAX_EXTERNAL_INVITE_BYTES,
|
|
4882
4956
|
`invite input must be at most ${MAX_EXTERNAL_INVITE_BYTES} UTF-8 bytes`
|
|
4883
4957
|
),
|
|
4884
|
-
expected_cid:
|
|
4958
|
+
expected_cid: ContainerIdSchema2.optional()
|
|
4885
4959
|
}).strict();
|
|
4886
4960
|
var ListMembersCommandInputSchema = external_exports.object({}).strict();
|
|
4887
4961
|
var CommandIdempotencyKeySchema = external_exports.string().regex(
|
|
@@ -4956,7 +5030,9 @@ var MessageShape = {
|
|
|
4956
5030
|
}),
|
|
4957
5031
|
source_msg_id: external_exports.number().int().nonnegative().safe().optional(),
|
|
4958
5032
|
source_wire_id: NonEmptyStringSchema.optional(),
|
|
4959
|
-
source_reply_to: ReplyReferenceSchema.optional()
|
|
5033
|
+
source_reply_to: ReplyReferenceSchema.optional(),
|
|
5034
|
+
scope: ThreadScopeSchema.optional(),
|
|
5035
|
+
thread_root: ThreadRootSchema.optional()
|
|
4960
5036
|
};
|
|
4961
5037
|
var RelayIntentShape = {
|
|
4962
5038
|
kind: external_exports.literal("relay_intent"),
|
|
@@ -4964,7 +5040,12 @@ var RelayIntentShape = {
|
|
|
4964
5040
|
file_id: LowerCrockfordUlidSchema.optional(),
|
|
4965
5041
|
recipient_identity: NonEmptyStringSchema
|
|
4966
5042
|
};
|
|
4967
|
-
var RelayResultStatusSchema = external_exports.enum([
|
|
5043
|
+
var RelayResultStatusSchema = external_exports.enum([
|
|
5044
|
+
"queued",
|
|
5045
|
+
"send_failed",
|
|
5046
|
+
"skipped_removed",
|
|
5047
|
+
"skipped_reply_unavailable"
|
|
5048
|
+
]);
|
|
4968
5049
|
var RelayResultShape = {
|
|
4969
5050
|
kind: external_exports.literal("relay_result"),
|
|
4970
5051
|
intent_record_id: NonEmptyStringSchema,
|
|
@@ -5002,6 +5083,18 @@ var FileShape = {
|
|
|
5002
5083
|
source_wire_id: NonEmptyStringSchema.optional(),
|
|
5003
5084
|
source_reply_to: ReplyReferenceSchema.optional()
|
|
5004
5085
|
};
|
|
5086
|
+
var IntakeRejectionShape = {
|
|
5087
|
+
kind: external_exports.literal("intake_rejection"),
|
|
5088
|
+
source_kind: external_exports.enum(["message", "file"]),
|
|
5089
|
+
source_msg_id: external_exports.number().int().nonnegative().safe().optional(),
|
|
5090
|
+
source_file_id: external_exports.number().int().nonnegative().safe().optional(),
|
|
5091
|
+
source_wire_id: NonEmptyStringSchema,
|
|
5092
|
+
sender_identity: NonEmptyStringSchema,
|
|
5093
|
+
sender_participant_id: LowerCrockfordUlidSchema,
|
|
5094
|
+
fingerprint: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
5095
|
+
error: external_exports.enum(["reply_target_unavailable", "thread_files_unsupported"]),
|
|
5096
|
+
notification_attempt_claimed: external_exports.literal(true)
|
|
5097
|
+
};
|
|
5005
5098
|
var MembershipIntentShape = {
|
|
5006
5099
|
kind: external_exports.literal("membership_intent"),
|
|
5007
5100
|
action: external_exports.enum(["remove"]),
|
|
@@ -5039,6 +5132,7 @@ var MessageRecordSchema = external_exports.object({ ...RecordCommonShape, ...Mes
|
|
|
5039
5132
|
var FileRecordSchema = external_exports.object({ ...RecordCommonShape, ...FileShape }).strict();
|
|
5040
5133
|
var RelayIntentRecordSchema = external_exports.object({ ...RecordCommonShape, ...RelayIntentShape }).strict();
|
|
5041
5134
|
var RelayResultRecordSchema = external_exports.object({ ...RecordCommonShape, ...RelayResultShape }).strict();
|
|
5135
|
+
var IntakeRejectionRecordSchema = external_exports.object({ ...RecordCommonShape, ...IntakeRejectionShape }).strict();
|
|
5042
5136
|
var MembershipIntentRecordSchema = external_exports.object({ ...RecordCommonShape, ...MembershipIntentShape }).strict();
|
|
5043
5137
|
var MembershipResultRecordSchema = external_exports.object({ ...RecordCommonShape, ...MembershipResultShape }).strict();
|
|
5044
5138
|
var CloseNoticeIntentRecordSchema = external_exports.object({ ...RecordCommonShape, ...CloseNoticeIntentShape }).strict();
|
|
@@ -5048,6 +5142,7 @@ var RawCommunicationRecordSchema = external_exports.discriminatedUnion("kind", [
|
|
|
5048
5142
|
FileRecordSchema,
|
|
5049
5143
|
RelayIntentRecordSchema,
|
|
5050
5144
|
RelayResultRecordSchema,
|
|
5145
|
+
IntakeRejectionRecordSchema,
|
|
5051
5146
|
MembershipIntentRecordSchema,
|
|
5052
5147
|
MembershipResultRecordSchema,
|
|
5053
5148
|
CloseNoticeIntentRecordSchema,
|
|
@@ -5063,6 +5158,18 @@ function refineRelaySubject(record, context) {
|
|
|
5063
5158
|
});
|
|
5064
5159
|
}
|
|
5065
5160
|
}
|
|
5161
|
+
function refineIntakeRejection(record, context) {
|
|
5162
|
+
if (record.kind !== "intake_rejection") return;
|
|
5163
|
+
const hasMessage = record.source_msg_id !== void 0;
|
|
5164
|
+
const hasFile = record.source_file_id !== void 0;
|
|
5165
|
+
if (hasMessage === hasFile || (record.source_kind === "message" ? !hasMessage : !hasFile)) {
|
|
5166
|
+
context.addIssue({
|
|
5167
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5168
|
+
path: ["source_kind"],
|
|
5169
|
+
message: "intake rejections require exactly one numeric source field matching source_kind"
|
|
5170
|
+
});
|
|
5171
|
+
}
|
|
5172
|
+
}
|
|
5066
5173
|
function refineFileRecord(record, context) {
|
|
5067
5174
|
if (record.kind !== "file" || record.data_base64 === void 0) return;
|
|
5068
5175
|
const bytes = Buffer.from(record.data_base64, "base64");
|
|
@@ -5113,6 +5220,102 @@ function refineMessageCategory(message, context) {
|
|
|
5113
5220
|
}
|
|
5114
5221
|
}
|
|
5115
5222
|
}
|
|
5223
|
+
function refineMessageThread(message, context) {
|
|
5224
|
+
if (message.thread_root !== void 0) {
|
|
5225
|
+
if (message.scope === void 0) {
|
|
5226
|
+
context.addIssue({
|
|
5227
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5228
|
+
path: ["scope"],
|
|
5229
|
+
message: "thread root messages require scope"
|
|
5230
|
+
});
|
|
5231
|
+
return;
|
|
5232
|
+
}
|
|
5233
|
+
if (message.scope.thread_id !== message.message_id || message.thread_root.thread_id !== message.message_id) {
|
|
5234
|
+
context.addIssue({
|
|
5235
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5236
|
+
path: ["thread_root", "thread_id"],
|
|
5237
|
+
message: "thread root thread_id and scope thread_id must equal message_id"
|
|
5238
|
+
});
|
|
5239
|
+
}
|
|
5240
|
+
if (message.scope.parent_key !== void 0) {
|
|
5241
|
+
context.addIssue({
|
|
5242
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5243
|
+
path: ["scope", "parent_key"],
|
|
5244
|
+
message: "parent_key is forbidden on thread root messages"
|
|
5245
|
+
});
|
|
5246
|
+
}
|
|
5247
|
+
if (message.category !== "chat") {
|
|
5248
|
+
context.addIssue({
|
|
5249
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5250
|
+
path: ["category"],
|
|
5251
|
+
message: "thread root messages must be chat messages"
|
|
5252
|
+
});
|
|
5253
|
+
}
|
|
5254
|
+
if (message.text !== `Thread: ${message.thread_root.topic}`) {
|
|
5255
|
+
context.addIssue({
|
|
5256
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5257
|
+
path: ["text"],
|
|
5258
|
+
message: "thread root message text must identify its topic"
|
|
5259
|
+
});
|
|
5260
|
+
}
|
|
5261
|
+
const creator = message.thread_root.members.find(
|
|
5262
|
+
(member) => member.participant_id === message.thread_root?.creator_participant_id
|
|
5263
|
+
);
|
|
5264
|
+
if (creator?.identity !== message.author.identity) {
|
|
5265
|
+
context.addIssue({
|
|
5266
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5267
|
+
path: ["thread_root", "creator_participant_id"],
|
|
5268
|
+
message: "thread root creator must match the message author"
|
|
5269
|
+
});
|
|
5270
|
+
}
|
|
5271
|
+
if (message.author_alias !== void 0 && message.author_alias.participant_id !== message.thread_root.creator_participant_id) {
|
|
5272
|
+
context.addIssue({
|
|
5273
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5274
|
+
path: ["author_alias", "participant_id"],
|
|
5275
|
+
message: "thread root author alias must identify the creator"
|
|
5276
|
+
});
|
|
5277
|
+
}
|
|
5278
|
+
for (const field of ["source_msg_id", "source_wire_id", "source_reply_to"]) {
|
|
5279
|
+
if (message[field] !== void 0) {
|
|
5280
|
+
context.addIssue({
|
|
5281
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5282
|
+
path: [field],
|
|
5283
|
+
message: `${field} is forbidden on thread root messages`
|
|
5284
|
+
});
|
|
5285
|
+
}
|
|
5286
|
+
}
|
|
5287
|
+
return;
|
|
5288
|
+
}
|
|
5289
|
+
if (message.scope === void 0) return;
|
|
5290
|
+
if (message.scope.parent_key === void 0) {
|
|
5291
|
+
context.addIssue({
|
|
5292
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5293
|
+
path: ["scope", "parent_key"],
|
|
5294
|
+
message: "thread descendants require an immediate parent_key"
|
|
5295
|
+
});
|
|
5296
|
+
}
|
|
5297
|
+
if (message.scope.thread_id === message.message_id) {
|
|
5298
|
+
context.addIssue({
|
|
5299
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5300
|
+
path: ["scope", "thread_id"],
|
|
5301
|
+
message: "thread descendant thread_id must identify a distinct root message"
|
|
5302
|
+
});
|
|
5303
|
+
}
|
|
5304
|
+
if (message.source_reply_to === void 0) {
|
|
5305
|
+
context.addIssue({
|
|
5306
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5307
|
+
path: ["source_reply_to"],
|
|
5308
|
+
message: "thread descendants require source_reply_to"
|
|
5309
|
+
});
|
|
5310
|
+
}
|
|
5311
|
+
if (message.category !== "chat") {
|
|
5312
|
+
context.addIssue({
|
|
5313
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5314
|
+
path: ["category"],
|
|
5315
|
+
message: "thread descendants must be chat messages"
|
|
5316
|
+
});
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5116
5319
|
var CommunicationRecordSchema = RawCommunicationRecordSchema.superRefine((record, context) => {
|
|
5117
5320
|
if (record.record_id !== `${record.room_id}:${record.seq}`) {
|
|
5118
5321
|
context.addIssue({
|
|
@@ -5121,8 +5324,12 @@ var CommunicationRecordSchema = RawCommunicationRecordSchema.superRefine((record
|
|
|
5121
5324
|
message: 'record_id must equal room_id + ":" + seq'
|
|
5122
5325
|
});
|
|
5123
5326
|
}
|
|
5124
|
-
if (record.kind === "message")
|
|
5327
|
+
if (record.kind === "message") {
|
|
5328
|
+
refineMessageCategory(record, context);
|
|
5329
|
+
refineMessageThread(record, context);
|
|
5330
|
+
}
|
|
5125
5331
|
refineRelaySubject(record, context);
|
|
5332
|
+
refineIntakeRejection(record, context);
|
|
5126
5333
|
refineFileRecord(record, context);
|
|
5127
5334
|
});
|
|
5128
5335
|
var AppendRecordSchema = external_exports.discriminatedUnion("kind", [
|
|
@@ -5130,11 +5337,16 @@ var AppendRecordSchema = external_exports.discriminatedUnion("kind", [
|
|
|
5130
5337
|
external_exports.object({ ...AppendCommonShape, ...FileShape }).strict(),
|
|
5131
5338
|
external_exports.object({ ...AppendCommonShape, ...RelayIntentShape }).strict(),
|
|
5132
5339
|
external_exports.object({ ...AppendCommonShape, ...RelayResultShape }).strict(),
|
|
5340
|
+
external_exports.object({ ...AppendCommonShape, ...IntakeRejectionShape }).strict(),
|
|
5133
5341
|
external_exports.object({ ...AppendCommonShape, ...CloseNoticeIntentShape }).strict(),
|
|
5134
5342
|
external_exports.object({ ...AppendCommonShape, ...CloseNoticeResultShape }).strict()
|
|
5135
5343
|
]).superRefine((record, context) => {
|
|
5136
|
-
if (record.kind === "message")
|
|
5344
|
+
if (record.kind === "message") {
|
|
5345
|
+
refineMessageCategory(record, context);
|
|
5346
|
+
refineMessageThread(record, context);
|
|
5347
|
+
}
|
|
5137
5348
|
refineRelaySubject(record, context);
|
|
5349
|
+
refineIntakeRejection(record, context);
|
|
5138
5350
|
refineFileRecord(record, context);
|
|
5139
5351
|
});
|
|
5140
5352
|
|