@mastra/factory 0.10.2-alpha.3 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +18 -2
- package/dist/factory.js.map +1 -1
- package/dist/routes/attention-providers.d.ts +101 -0
- package/dist/routes/attention-providers.d.ts.map +1 -0
- package/dist/routes/attention-providers.js +384 -0
- package/dist/routes/attention-providers.js.map +1 -0
- package/dist/routes/attention.d.ts +11 -9
- package/dist/routes/attention.d.ts.map +1 -1
- package/dist/routes/attention.js +143 -193
- package/dist/routes/attention.js.map +1 -1
- package/dist/routes/surface.d.ts +2 -0
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +3 -1
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/work-items.d.ts +3 -0
- package/dist/routes/work-items.d.ts.map +1 -1
- package/dist/routes/work-items.js +3 -1
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/dispatcher.d.ts +3 -0
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +9 -1
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/start-coordinator.d.ts +2 -1
- package/dist/rules/start-coordinator.d.ts.map +1 -1
- package/dist/rules/start-coordinator.js +10 -2
- package/dist/rules/start-coordinator.js.map +1 -1
- package/dist/storage/domains/audit/domain.d.ts.map +1 -1
- package/dist/storage/domains/audit/domain.js +2 -5
- package/dist/storage/domains/audit/domain.js.map +1 -1
- package/dist/storage/domains/channel-identity/base.d.ts +4 -0
- package/dist/storage/domains/channel-identity/base.d.ts.map +1 -1
- package/dist/storage/domains/channel-identity/base.js +15 -0
- package/dist/storage/domains/channel-identity/base.js.map +1 -1
- package/dist/storage/domains/comments/actor.d.ts +51 -0
- package/dist/storage/domains/comments/actor.d.ts.map +1 -0
- package/dist/storage/domains/comments/actor.js +38 -0
- package/dist/storage/domains/comments/actor.js.map +1 -0
- package/dist/storage/domains/comments/base.d.ts +230 -0
- package/dist/storage/domains/comments/base.d.ts.map +1 -0
- package/dist/storage/domains/comments/base.js +490 -0
- package/dist/storage/domains/comments/base.js.map +1 -0
- package/dist/storage/domains/comments/domain.d.ts +125 -0
- package/dist/storage/domains/comments/domain.d.ts.map +1 -0
- package/dist/storage/domains/comments/domain.js +270 -0
- package/dist/storage/domains/comments/domain.js.map +1 -0
- package/dist/storage/domains/comments/feed-context.d.ts +20 -0
- package/dist/storage/domains/comments/feed-context.d.ts.map +1 -0
- package/dist/storage/domains/comments/feed-context.js +74 -0
- package/dist/storage/domains/comments/feed-context.js.map +1 -0
- package/dist/storage/domains/comments/feed-sync.d.ts +38 -0
- package/dist/storage/domains/comments/feed-sync.d.ts.map +1 -0
- package/dist/storage/domains/comments/feed-sync.js +1 -0
- package/dist/storage/domains/comments/parse.d.ts +22 -0
- package/dist/storage/domains/comments/parse.d.ts.map +1 -0
- package/dist/storage/domains/comments/parse.js +90 -0
- package/dist/storage/domains/comments/parse.js.map +1 -0
- package/dist/storage/domains/comments/routes.d.ts +22 -0
- package/dist/storage/domains/comments/routes.d.ts.map +1 -0
- package/dist/storage/domains/comments/routes.js +248 -0
- package/dist/storage/domains/comments/routes.js.map +1 -0
- package/dist/storage/domains/comments/schema.d.ts +4 -0
- package/dist/storage/domains/comments/schema.d.ts.map +1 -0
- package/dist/storage/domains/comments/schema.js +135 -0
- package/dist/storage/domains/comments/schema.js.map +1 -0
- package/dist/storage/domains/comments/wire.d.ts +40 -0
- package/dist/storage/domains/comments/wire.d.ts.map +1 -0
- package/dist/storage/domains/comments/wire.js +37 -0
- package/dist/storage/domains/comments/wire.js.map +1 -0
- package/dist/storage/domains/work-items/base.d.ts +14 -10
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +109 -22
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/factory-skills/factory-rereview/SKILL.md +20 -12
- package/factory-skills/factory-review/SKILL.md +17 -12
- package/package.json +8 -8
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { commentBodyError } from "./base.js";
|
|
2
|
+
import { isMentionableActorId } from "./actor.js";
|
|
3
|
+
//#region src/storage/domains/comments/parse.ts
|
|
4
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
5
|
+
const CLIENT_TOKEN_RE = /^[A-Za-z0-9-]{8,64}$/;
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
async function readJson(c) {
|
|
10
|
+
try {
|
|
11
|
+
return await c.req.json();
|
|
12
|
+
} catch {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** `undefined` when the field is absent, `null` when it is present but malformed. */
|
|
17
|
+
function parseMentions(raw) {
|
|
18
|
+
if (raw === void 0) return void 0;
|
|
19
|
+
if (!Array.isArray(raw) || raw.length > 20) return null;
|
|
20
|
+
const mentions = [];
|
|
21
|
+
for (const entry of raw) {
|
|
22
|
+
if (!isRecord(entry)) return null;
|
|
23
|
+
if (entry.kind !== "user" || typeof entry.id !== "string" || !isMentionableActorId(entry.id)) return null;
|
|
24
|
+
mentions.push({
|
|
25
|
+
kind: "user",
|
|
26
|
+
id: entry.id
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return mentions;
|
|
30
|
+
}
|
|
31
|
+
function parseBody(raw) {
|
|
32
|
+
if (typeof raw !== "string" || commentBodyError(raw)) return null;
|
|
33
|
+
return raw;
|
|
34
|
+
}
|
|
35
|
+
function parseClientToken(raw) {
|
|
36
|
+
if (raw === void 0) return void 0;
|
|
37
|
+
if (typeof raw !== "string" || !CLIENT_TOKEN_RE.test(raw)) return null;
|
|
38
|
+
return raw;
|
|
39
|
+
}
|
|
40
|
+
function parseExpectedRevision(raw) {
|
|
41
|
+
if (raw === void 0) return void 0;
|
|
42
|
+
if (typeof raw !== "number" || !Number.isInteger(raw)) return null;
|
|
43
|
+
return raw;
|
|
44
|
+
}
|
|
45
|
+
function parseReplyTo(raw) {
|
|
46
|
+
if (raw === void 0) return void 0;
|
|
47
|
+
if (!isRecord(raw)) return null;
|
|
48
|
+
if (typeof raw.commentId !== "string" || !UUID_RE.test(raw.commentId)) return null;
|
|
49
|
+
if (raw.quote !== void 0 && typeof raw.quote !== "string") return null;
|
|
50
|
+
const quote = typeof raw.quote === "string" ? raw.quote.slice(0, 500) : void 0;
|
|
51
|
+
return {
|
|
52
|
+
commentId: raw.commentId,
|
|
53
|
+
...quote ? { quote } : {}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function parseCreateCommentBody(raw) {
|
|
57
|
+
if (!isRecord(raw)) return null;
|
|
58
|
+
const body = parseBody(raw.body);
|
|
59
|
+
if (body === null) return null;
|
|
60
|
+
const mentions = parseMentions(raw.mentions);
|
|
61
|
+
if (mentions === null) return null;
|
|
62
|
+
const replyTo = parseReplyTo(raw.replyTo);
|
|
63
|
+
if (replyTo === null) return null;
|
|
64
|
+
const clientToken = parseClientToken(raw.clientToken);
|
|
65
|
+
if (clientToken === null) return null;
|
|
66
|
+
return {
|
|
67
|
+
body,
|
|
68
|
+
...clientToken ? { clientToken } : {},
|
|
69
|
+
...replyTo ? { replyTo } : {},
|
|
70
|
+
...mentions ? { mentions } : {}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function parseEditCommentBody(raw) {
|
|
74
|
+
if (!isRecord(raw)) return null;
|
|
75
|
+
const body = parseBody(raw.body);
|
|
76
|
+
if (body === null) return null;
|
|
77
|
+
const mentions = parseMentions(raw.mentions);
|
|
78
|
+
if (mentions === null) return null;
|
|
79
|
+
const expectedRevision = parseExpectedRevision(raw.expectedRevision);
|
|
80
|
+
if (expectedRevision === null) return null;
|
|
81
|
+
return {
|
|
82
|
+
body,
|
|
83
|
+
...mentions ? { mentions } : {},
|
|
84
|
+
...expectedRevision !== void 0 ? { expectedRevision } : {}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { UUID_RE, parseCreateCommentBody, parseEditCommentBody, readJson };
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","names":[],"sources":["../../../../src/storage/domains/comments/parse.ts"],"sourcesContent":["/** Request-body parsing for the comment routes: unknown JSON in, a typed input or `null` out. */\n\nimport type { Context } from 'hono';\n\nimport { isMentionableActorId } from './actor.js';\nimport type { FactoryMentionRef } from './base.js';\nimport { commentBodyError, MAX_COMMENT_MENTIONS, MAX_COMMENT_QUOTE_LENGTH } from './base.js';\n\nexport const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst CLIENT_TOKEN_RE = /^[A-Za-z0-9-]{8,64}$/;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport async function readJson(c: Context): Promise<unknown> {\n try {\n return await c.req.json();\n } catch {\n return undefined;\n }\n}\n\n/** `undefined` when the field is absent, `null` when it is present but malformed. */\nfunction parseMentions(raw: unknown): FactoryMentionRef[] | null | undefined {\n if (raw === undefined) return undefined;\n if (!Array.isArray(raw) || raw.length > MAX_COMMENT_MENTIONS) return null;\n const mentions: FactoryMentionRef[] = [];\n for (const entry of raw) {\n if (!isRecord(entry)) return null;\n if (entry.kind !== 'user' || typeof entry.id !== 'string' || !isMentionableActorId(entry.id)) return null;\n mentions.push({ kind: 'user', id: entry.id });\n }\n return mentions;\n}\n\nfunction parseBody(raw: unknown): string | null {\n if (typeof raw !== 'string' || commentBodyError(raw)) return null;\n return raw;\n}\n\nfunction parseClientToken(raw: unknown): string | null | undefined {\n if (raw === undefined) return undefined;\n if (typeof raw !== 'string' || !CLIENT_TOKEN_RE.test(raw)) return null;\n return raw;\n}\n\nfunction parseExpectedRevision(raw: unknown): number | null | undefined {\n if (raw === undefined) return undefined;\n if (typeof raw !== 'number' || !Number.isInteger(raw)) return null;\n return raw;\n}\n\nfunction parseReplyTo(raw: unknown): { commentId: string; quote?: string } | null | undefined {\n if (raw === undefined) return undefined;\n if (!isRecord(raw)) return null;\n if (typeof raw.commentId !== 'string' || !UUID_RE.test(raw.commentId)) return null;\n if (raw.quote !== undefined && typeof raw.quote !== 'string') return null;\n const quote = typeof raw.quote === 'string' ? raw.quote.slice(0, MAX_COMMENT_QUOTE_LENGTH) : undefined;\n return { commentId: raw.commentId, ...(quote ? { quote } : {}) };\n}\n\nexport interface ParsedCreateComment {\n body: string;\n clientToken?: string;\n replyTo?: { commentId: string; quote?: string };\n mentions?: FactoryMentionRef[];\n}\n\nexport function parseCreateCommentBody(raw: unknown): ParsedCreateComment | null {\n if (!isRecord(raw)) return null;\n\n const body = parseBody(raw.body);\n if (body === null) return null;\n const mentions = parseMentions(raw.mentions);\n if (mentions === null) return null;\n const replyTo = parseReplyTo(raw.replyTo);\n if (replyTo === null) return null;\n const clientToken = parseClientToken(raw.clientToken);\n if (clientToken === null) return null;\n\n return {\n body,\n ...(clientToken ? { clientToken } : {}),\n ...(replyTo ? { replyTo } : {}),\n ...(mentions ? { mentions } : {}),\n };\n}\n\nexport interface ParsedEditComment {\n body: string;\n mentions?: FactoryMentionRef[];\n expectedRevision?: number;\n}\n\nexport function parseEditCommentBody(raw: unknown): ParsedEditComment | null {\n if (!isRecord(raw)) return null;\n\n const body = parseBody(raw.body);\n if (body === null) return null;\n const mentions = parseMentions(raw.mentions);\n if (mentions === null) return null;\n const expectedRevision = parseExpectedRevision(raw.expectedRevision);\n if (expectedRevision === null) return null;\n\n return {\n body,\n ...(mentions ? { mentions } : {}),\n ...(expectedRevision !== undefined ? { expectedRevision } : {}),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP for the item feed. Every handler is the same shape: resolve the tenant,
|
|
3
|
+
* validate the path ids, delegate to a `CommentsDomain` service method, map its
|
|
4
|
+
* result status to a status code, then emit audit.
|
|
5
|
+
*/
|
|
6
|
+
import type { ApiRoute } from '@mastra/core/server';
|
|
7
|
+
import type { RouteAuth } from '../../../routes/route.js';
|
|
8
|
+
import type { AuditEmitter } from '../audit/domain.js';
|
|
9
|
+
import type { FactoryProjectsStorage } from '../projects/base.js';
|
|
10
|
+
import type { WorkItemsStorage } from '../work-items/base.js';
|
|
11
|
+
import type { WorkItemCommentsStorage } from './base.js';
|
|
12
|
+
import type { CommentsDomain } from './domain.js';
|
|
13
|
+
export interface CommentRouteDependencies {
|
|
14
|
+
domain: CommentsDomain;
|
|
15
|
+
auth: RouteAuth;
|
|
16
|
+
comments: WorkItemCommentsStorage;
|
|
17
|
+
workItems: WorkItemsStorage;
|
|
18
|
+
projects: FactoryProjectsStorage;
|
|
19
|
+
audit?: AuditEmitter;
|
|
20
|
+
}
|
|
21
|
+
export declare function buildCommentRoutes(dependencies: CommentRouteDependencies): ApiRoute[];
|
|
22
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/comments/routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAKpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,aAAa,CAAC;AAOjE,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,uBAAuB,CAAC;IAClC,SAAS,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,EAAE,sBAAsB,CAAC;IACjC,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAWD,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,wBAAwB,GAAG,QAAQ,EAAE,CA4OrF"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { getFactoryAuthUser } from "../../../auth.js";
|
|
2
|
+
import { decodeCommentCursor } from "./base.js";
|
|
3
|
+
import { actorFromAuthUser } from "./actor.js";
|
|
4
|
+
import { UUID_RE, parseCreateCommentBody, parseEditCommentBody, readJson } from "./parse.js";
|
|
5
|
+
import { toWireComment } from "./wire.js";
|
|
6
|
+
import { registerApiRoute } from "@mastra/core/server";
|
|
7
|
+
//#region src/storage/domains/comments/routes.ts
|
|
8
|
+
const MAX_AUDIT_BODY_SNAPSHOT = 1024;
|
|
9
|
+
function loose(c) {
|
|
10
|
+
return c;
|
|
11
|
+
}
|
|
12
|
+
function buildCommentRoutes(dependencies) {
|
|
13
|
+
const { domain, auth, comments, workItems, projects, audit } = dependencies;
|
|
14
|
+
async function resolveTenant(c) {
|
|
15
|
+
await auth.ensureUser(c);
|
|
16
|
+
const tenant = auth.tenant(c);
|
|
17
|
+
if (!tenant) return { response: c.json({ error: "unauthorized" }, 401) };
|
|
18
|
+
if (!tenant.orgId) return { response: c.json({
|
|
19
|
+
error: "organization_required",
|
|
20
|
+
message: "The item feed requires an organization."
|
|
21
|
+
}, 403) };
|
|
22
|
+
return {
|
|
23
|
+
orgId: tenant.orgId,
|
|
24
|
+
userId: tenant.userId
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function editorFor(c, tenant) {
|
|
28
|
+
return {
|
|
29
|
+
userId: tenant.userId,
|
|
30
|
+
canModerate: () => auth.isOrganizationAdmin(c, tenant.orgId)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
async function emitMentionAudit(c, target, commentId, mentionedIds) {
|
|
34
|
+
if (mentionedIds.length === 0) return;
|
|
35
|
+
await audit?.emit({
|
|
36
|
+
context: c,
|
|
37
|
+
input: {
|
|
38
|
+
action: "factory.work_item.comment_mentioned",
|
|
39
|
+
factoryProjectId: target.factoryProjectId,
|
|
40
|
+
targets: [{
|
|
41
|
+
type: "work_item",
|
|
42
|
+
id: target.workItemId,
|
|
43
|
+
...target.title ? { name: target.title } : {}
|
|
44
|
+
}],
|
|
45
|
+
metadata: {
|
|
46
|
+
commentId,
|
|
47
|
+
mentionedIds
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return [
|
|
53
|
+
registerApiRoute("/web/factory/work-items/:workItemId/comments", {
|
|
54
|
+
method: "GET",
|
|
55
|
+
handler: async (cc) => {
|
|
56
|
+
const c = loose(cc);
|
|
57
|
+
const tenant = await resolveTenant(c);
|
|
58
|
+
if ("response" in tenant) return tenant.response;
|
|
59
|
+
const workItemId = c.req.param("workItemId");
|
|
60
|
+
if (!workItemId || !UUID_RE.test(workItemId)) return c.json({ error: "Work item not found" }, 404);
|
|
61
|
+
await workItems.ensureReady();
|
|
62
|
+
const workItem = await workItems.get({
|
|
63
|
+
orgId: tenant.orgId,
|
|
64
|
+
id: workItemId
|
|
65
|
+
});
|
|
66
|
+
if (!workItem) return c.json({ error: "Work item not found" }, 404);
|
|
67
|
+
await comments.ensureReady();
|
|
68
|
+
const limitRaw = c.req.query("limit");
|
|
69
|
+
const limit = limitRaw ? Number.parseInt(limitRaw, 10) : void 0;
|
|
70
|
+
const before = c.req.query("before") || void 0;
|
|
71
|
+
if (before && !decodeCommentCursor(before)) return c.json({ error: "invalid_cursor" }, 422);
|
|
72
|
+
const around = c.req.query("around") || void 0;
|
|
73
|
+
if (around && !UUID_RE.test(around)) return c.json({ error: "invalid_comment_id" }, 422);
|
|
74
|
+
const page = await comments.list({
|
|
75
|
+
orgId: tenant.orgId,
|
|
76
|
+
factoryProjectId: workItem.factoryProjectId,
|
|
77
|
+
workItemId,
|
|
78
|
+
before,
|
|
79
|
+
...around ? { around } : {},
|
|
80
|
+
...limit !== void 0 && Number.isFinite(limit) ? { limit } : {}
|
|
81
|
+
});
|
|
82
|
+
const wirePage = {
|
|
83
|
+
comments: page.comments.map((comment) => toWireComment(comment, tenant.userId)),
|
|
84
|
+
...page.nextCursor ? { nextCursor: page.nextCursor } : {}
|
|
85
|
+
};
|
|
86
|
+
return c.json(wirePage);
|
|
87
|
+
}
|
|
88
|
+
}),
|
|
89
|
+
registerApiRoute("/web/factory/work-items/:workItemId/comments", {
|
|
90
|
+
method: "POST",
|
|
91
|
+
handler: async (cc) => {
|
|
92
|
+
const c = loose(cc);
|
|
93
|
+
const tenant = await resolveTenant(c);
|
|
94
|
+
if ("response" in tenant) return tenant.response;
|
|
95
|
+
const workItemId = c.req.param("workItemId");
|
|
96
|
+
if (!workItemId || !UUID_RE.test(workItemId)) return c.json({ error: "Work item not found" }, 404);
|
|
97
|
+
const parsed = parseCreateCommentBody(await readJson(c));
|
|
98
|
+
if (!parsed) return c.json({ error: "invalid_comment" }, 422);
|
|
99
|
+
const result = await domain.createComment({
|
|
100
|
+
orgId: tenant.orgId,
|
|
101
|
+
workItemId,
|
|
102
|
+
author: actorFromAuthUser(tenant.userId, getFactoryAuthUser(c)),
|
|
103
|
+
body: parsed.body,
|
|
104
|
+
...parsed.replyTo ? { replyTo: parsed.replyTo } : {},
|
|
105
|
+
...parsed.mentions ? { mentions: parsed.mentions } : {},
|
|
106
|
+
...parsed.clientToken ? { clientToken: parsed.clientToken } : {}
|
|
107
|
+
});
|
|
108
|
+
if (result.status === "work_item_not_found") return c.json({ error: "Work item not found" }, 404);
|
|
109
|
+
if (result.status === "token_conflict") return c.json({ error: "comment_token_conflict" }, 409);
|
|
110
|
+
if (result.status === "invalid") return c.json({
|
|
111
|
+
error: "invalid_comment",
|
|
112
|
+
message: result.message
|
|
113
|
+
}, 422);
|
|
114
|
+
const { comment, workItem } = result;
|
|
115
|
+
await audit?.emit({
|
|
116
|
+
context: c,
|
|
117
|
+
input: {
|
|
118
|
+
action: "factory.work_item.comment_created",
|
|
119
|
+
factoryProjectId: workItem.factoryProjectId,
|
|
120
|
+
targets: [{
|
|
121
|
+
type: "work_item",
|
|
122
|
+
id: workItem.id,
|
|
123
|
+
name: workItem.title
|
|
124
|
+
}],
|
|
125
|
+
metadata: { commentId: comment.id }
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
await emitMentionAudit(c, {
|
|
129
|
+
factoryProjectId: workItem.factoryProjectId,
|
|
130
|
+
workItemId: workItem.id,
|
|
131
|
+
title: workItem.title
|
|
132
|
+
}, comment.id, comment.mentions.map((mention) => mention.id).filter((id) => id !== comment.author.id));
|
|
133
|
+
return c.json({ comment: toWireComment(comment, tenant.userId) }, 201);
|
|
134
|
+
}
|
|
135
|
+
}),
|
|
136
|
+
registerApiRoute("/web/factory/work-items/:workItemId/comments/:commentId", {
|
|
137
|
+
method: "PATCH",
|
|
138
|
+
handler: async (cc) => {
|
|
139
|
+
const c = loose(cc);
|
|
140
|
+
const tenant = await resolveTenant(c);
|
|
141
|
+
if ("response" in tenant) return tenant.response;
|
|
142
|
+
const workItemId = c.req.param("workItemId");
|
|
143
|
+
const commentId = c.req.param("commentId");
|
|
144
|
+
if (!workItemId || !UUID_RE.test(workItemId) || !commentId || !UUID_RE.test(commentId)) return c.json({ error: "Comment not found" }, 404);
|
|
145
|
+
const parsed = parseEditCommentBody(await readJson(c));
|
|
146
|
+
if (!parsed) return c.json({ error: "invalid_comment" }, 422);
|
|
147
|
+
const result = await domain.editComment({
|
|
148
|
+
orgId: tenant.orgId,
|
|
149
|
+
workItemId,
|
|
150
|
+
commentId,
|
|
151
|
+
editor: editorFor(c, tenant),
|
|
152
|
+
body: parsed.body,
|
|
153
|
+
...parsed.mentions ? { mentions: parsed.mentions } : {},
|
|
154
|
+
...parsed.expectedRevision !== void 0 ? { expectedRevision: parsed.expectedRevision } : {}
|
|
155
|
+
});
|
|
156
|
+
if (result.status === "not_found") return c.json({ error: "Comment not found" }, 404);
|
|
157
|
+
if (result.status === "forbidden") return c.json({ error: "not_comment_author" }, 403);
|
|
158
|
+
if (result.status === "not_editable") return c.json({ error: "comment_not_editable" }, 409);
|
|
159
|
+
if (result.status === "conflict") return c.json({ error: "comment_conflict" }, 409);
|
|
160
|
+
if (result.status === "invalid") return c.json({
|
|
161
|
+
error: "invalid_comment",
|
|
162
|
+
message: result.message
|
|
163
|
+
}, 422);
|
|
164
|
+
const { comment } = result;
|
|
165
|
+
await audit?.emit({
|
|
166
|
+
context: c,
|
|
167
|
+
input: {
|
|
168
|
+
action: "factory.work_item.comment_edited",
|
|
169
|
+
factoryProjectId: comment.factoryProjectId,
|
|
170
|
+
targets: [{
|
|
171
|
+
type: "work_item",
|
|
172
|
+
id: comment.workItemId
|
|
173
|
+
}],
|
|
174
|
+
metadata: {
|
|
175
|
+
commentId: comment.id,
|
|
176
|
+
previousBody: result.previousBody.slice(0, MAX_AUDIT_BODY_SNAPSHOT)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
await emitMentionAudit(c, {
|
|
181
|
+
factoryProjectId: comment.factoryProjectId,
|
|
182
|
+
workItemId: comment.workItemId
|
|
183
|
+
}, comment.id, result.addedMentions.map((mention) => mention.id));
|
|
184
|
+
return c.json({ comment: toWireComment(comment, tenant.userId) });
|
|
185
|
+
}
|
|
186
|
+
}),
|
|
187
|
+
registerApiRoute("/web/factory/work-items/:workItemId/comments/:commentId", {
|
|
188
|
+
method: "DELETE",
|
|
189
|
+
handler: async (cc) => {
|
|
190
|
+
const c = loose(cc);
|
|
191
|
+
const tenant = await resolveTenant(c);
|
|
192
|
+
if ("response" in tenant) return tenant.response;
|
|
193
|
+
const workItemId = c.req.param("workItemId");
|
|
194
|
+
const commentId = c.req.param("commentId");
|
|
195
|
+
if (!workItemId || !UUID_RE.test(workItemId) || !commentId || !UUID_RE.test(commentId)) return c.json({ error: "Comment not found" }, 404);
|
|
196
|
+
const result = await domain.deleteComment({
|
|
197
|
+
orgId: tenant.orgId,
|
|
198
|
+
workItemId,
|
|
199
|
+
commentId,
|
|
200
|
+
editor: editorFor(c, tenant)
|
|
201
|
+
});
|
|
202
|
+
if (result.status === "not_found") return c.json({ error: "Comment not found" }, 404);
|
|
203
|
+
if (result.status === "forbidden") return c.json({ error: "not_comment_author" }, 403);
|
|
204
|
+
if (result.status === "not_editable") return c.json({ error: "comment_not_editable" }, 409);
|
|
205
|
+
await audit?.emit({
|
|
206
|
+
context: c,
|
|
207
|
+
input: {
|
|
208
|
+
action: "factory.work_item.comment_deleted",
|
|
209
|
+
factoryProjectId: result.comment.factoryProjectId,
|
|
210
|
+
targets: [{
|
|
211
|
+
type: "work_item",
|
|
212
|
+
id: result.comment.workItemId
|
|
213
|
+
}],
|
|
214
|
+
metadata: { commentId: result.comment.id }
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
return c.json({ comment: toWireComment(result.comment, tenant.userId) });
|
|
218
|
+
}
|
|
219
|
+
}),
|
|
220
|
+
registerApiRoute("/web/factory/projects/:id/mention-roster", {
|
|
221
|
+
method: "GET",
|
|
222
|
+
handler: async (cc) => {
|
|
223
|
+
const c = loose(cc);
|
|
224
|
+
const tenant = await resolveTenant(c);
|
|
225
|
+
if ("response" in tenant) return tenant.response;
|
|
226
|
+
const projectId = c.req.param("id");
|
|
227
|
+
if (!projectId || !UUID_RE.test(projectId)) return c.json({ error: "Project not found" }, 404);
|
|
228
|
+
await projects.ensureReady();
|
|
229
|
+
if (!await projects.get({
|
|
230
|
+
orgId: tenant.orgId,
|
|
231
|
+
id: projectId
|
|
232
|
+
})) return c.json({ error: "Project not found" }, 404);
|
|
233
|
+
await comments.ensureReady();
|
|
234
|
+
const roster = await domain.mentionRoster({
|
|
235
|
+
orgId: tenant.orgId,
|
|
236
|
+
factoryProjectId: projectId
|
|
237
|
+
});
|
|
238
|
+
const query = c.req.query("q")?.trim().toLowerCase();
|
|
239
|
+
const members = query ? roster.filter((member) => (member.name ?? member.id).toLowerCase().startsWith(query)) : roster;
|
|
240
|
+
return c.json({ members });
|
|
241
|
+
}
|
|
242
|
+
})
|
|
243
|
+
];
|
|
244
|
+
}
|
|
245
|
+
//#endregion
|
|
246
|
+
export { buildCommentRoutes };
|
|
247
|
+
|
|
248
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","names":[],"sources":["../../../../src/storage/domains/comments/routes.ts"],"sourcesContent":["/**\n * HTTP for the item feed. Every handler is the same shape: resolve the tenant,\n * validate the path ids, delegate to a `CommentsDomain` service method, map its\n * result status to a status code, then emit audit.\n */\n\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\nimport { getFactoryAuthUser } from '../../../auth.js';\nimport type { RouteAuth } from '../../../routes/route.js';\nimport type { AuditEmitter } from '../audit/domain.js';\nimport type { FactoryProjectsStorage } from '../projects/base.js';\nimport type { WorkItemsStorage } from '../work-items/base.js';\nimport { actorFromAuthUser } from './actor.js';\nimport type { WorkItemCommentsStorage } from './base.js';\nimport { decodeCommentCursor } from './base.js';\nimport type { CommentEditor, CommentsDomain } from './domain.js';\nimport { parseCreateCommentBody, parseEditCommentBody, readJson, UUID_RE } from './parse.js';\nimport { toWireComment } from './wire.js';\nimport type { WireCommentPage } from './wire.js';\n\nconst MAX_AUDIT_BODY_SNAPSHOT = 1024;\n\nexport interface CommentRouteDependencies {\n domain: CommentsDomain;\n auth: RouteAuth;\n comments: WorkItemCommentsStorage;\n workItems: WorkItemsStorage;\n projects: FactoryProjectsStorage;\n audit?: AuditEmitter;\n}\n\ninterface Tenant {\n orgId: string;\n userId: string;\n}\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nexport function buildCommentRoutes(dependencies: CommentRouteDependencies): ApiRoute[] {\n const { domain, auth, comments, workItems, projects, audit } = dependencies;\n\n async function resolveTenant(c: Context): Promise<Tenant | { response: Response }> {\n await auth.ensureUser(c);\n const tenant = auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json({ error: 'organization_required', message: 'The item feed requires an organization.' }, 403),\n };\n }\n return { orgId: tenant.orgId, userId: tenant.userId };\n }\n\n function editorFor(c: Context, tenant: Tenant): CommentEditor {\n return {\n userId: tenant.userId,\n canModerate: () => auth.isOrganizationAdmin(c, tenant.orgId),\n };\n }\n\n async function emitMentionAudit(\n c: Context,\n target: { factoryProjectId: string; workItemId: string; title?: string },\n commentId: string,\n mentionedIds: string[],\n ): Promise<void> {\n if (mentionedIds.length === 0) return;\n await audit?.emit({\n context: c,\n input: {\n action: 'factory.work_item.comment_mentioned',\n factoryProjectId: target.factoryProjectId,\n targets: [{ type: 'work_item', id: target.workItemId, ...(target.title ? { name: target.title } : {}) }],\n metadata: { commentId, mentionedIds },\n },\n });\n }\n\n return [\n registerApiRoute('/web/factory/work-items/:workItemId/comments', {\n method: 'GET',\n handler: async cc => {\n const c = loose(cc);\n const tenant = await resolveTenant(c);\n if ('response' in tenant) return tenant.response;\n\n const workItemId = c.req.param('workItemId');\n if (!workItemId || !UUID_RE.test(workItemId)) return c.json({ error: 'Work item not found' }, 404);\n await workItems.ensureReady();\n const workItem = await workItems.get({ orgId: tenant.orgId, id: workItemId });\n if (!workItem) return c.json({ error: 'Work item not found' }, 404);\n\n await comments.ensureReady();\n const limitRaw = c.req.query('limit');\n const limit = limitRaw ? Number.parseInt(limitRaw, 10) : undefined;\n const before = c.req.query('before') || undefined;\n if (before && !decodeCommentCursor(before)) return c.json({ error: 'invalid_cursor' }, 422);\n const around = c.req.query('around') || undefined;\n if (around && !UUID_RE.test(around)) return c.json({ error: 'invalid_comment_id' }, 422);\n const page = await comments.list({\n orgId: tenant.orgId,\n factoryProjectId: workItem.factoryProjectId,\n workItemId,\n before,\n ...(around ? { around } : {}),\n ...(limit !== undefined && Number.isFinite(limit) ? { limit } : {}),\n });\n const wirePage: WireCommentPage = {\n comments: page.comments.map(comment => toWireComment(comment, tenant.userId)),\n ...(page.nextCursor ? { nextCursor: page.nextCursor } : {}),\n };\n return c.json(wirePage);\n },\n }),\n\n registerApiRoute('/web/factory/work-items/:workItemId/comments', {\n method: 'POST',\n handler: async cc => {\n const c = loose(cc);\n const tenant = await resolveTenant(c);\n if ('response' in tenant) return tenant.response;\n\n const workItemId = c.req.param('workItemId');\n if (!workItemId || !UUID_RE.test(workItemId)) return c.json({ error: 'Work item not found' }, 404);\n\n const parsed = parseCreateCommentBody(await readJson(c));\n if (!parsed) return c.json({ error: 'invalid_comment' }, 422);\n\n const result = await domain.createComment({\n orgId: tenant.orgId,\n workItemId,\n author: actorFromAuthUser(tenant.userId, getFactoryAuthUser(c)),\n body: parsed.body,\n ...(parsed.replyTo ? { replyTo: parsed.replyTo } : {}),\n ...(parsed.mentions ? { mentions: parsed.mentions } : {}),\n ...(parsed.clientToken ? { clientToken: parsed.clientToken } : {}),\n });\n if (result.status === 'work_item_not_found') return c.json({ error: 'Work item not found' }, 404);\n if (result.status === 'token_conflict') return c.json({ error: 'comment_token_conflict' }, 409);\n if (result.status === 'invalid') return c.json({ error: 'invalid_comment', message: result.message }, 422);\n\n const { comment, workItem } = result;\n await audit?.emit({\n context: c,\n input: {\n action: 'factory.work_item.comment_created',\n factoryProjectId: workItem.factoryProjectId,\n targets: [{ type: 'work_item', id: workItem.id, name: workItem.title }],\n metadata: { commentId: comment.id },\n },\n });\n await emitMentionAudit(\n c,\n { factoryProjectId: workItem.factoryProjectId, workItemId: workItem.id, title: workItem.title },\n comment.id,\n comment.mentions.map(mention => mention.id).filter(id => id !== comment.author.id),\n );\n return c.json({ comment: toWireComment(comment, tenant.userId) }, 201);\n },\n }),\n\n registerApiRoute('/web/factory/work-items/:workItemId/comments/:commentId', {\n method: 'PATCH',\n handler: async cc => {\n const c = loose(cc);\n const tenant = await resolveTenant(c);\n if ('response' in tenant) return tenant.response;\n\n const workItemId = c.req.param('workItemId');\n const commentId = c.req.param('commentId');\n if (!workItemId || !UUID_RE.test(workItemId) || !commentId || !UUID_RE.test(commentId)) {\n return c.json({ error: 'Comment not found' }, 404);\n }\n\n const parsed = parseEditCommentBody(await readJson(c));\n if (!parsed) return c.json({ error: 'invalid_comment' }, 422);\n\n const result = await domain.editComment({\n orgId: tenant.orgId,\n workItemId,\n commentId,\n editor: editorFor(c, tenant),\n body: parsed.body,\n ...(parsed.mentions ? { mentions: parsed.mentions } : {}),\n ...(parsed.expectedRevision !== undefined ? { expectedRevision: parsed.expectedRevision } : {}),\n });\n if (result.status === 'not_found') return c.json({ error: 'Comment not found' }, 404);\n if (result.status === 'forbidden') return c.json({ error: 'not_comment_author' }, 403);\n if (result.status === 'not_editable') return c.json({ error: 'comment_not_editable' }, 409);\n if (result.status === 'conflict') return c.json({ error: 'comment_conflict' }, 409);\n if (result.status === 'invalid') return c.json({ error: 'invalid_comment', message: result.message }, 422);\n\n const { comment } = result;\n await audit?.emit({\n context: c,\n input: {\n action: 'factory.work_item.comment_edited',\n factoryProjectId: comment.factoryProjectId,\n targets: [{ type: 'work_item', id: comment.workItemId }],\n metadata: {\n commentId: comment.id,\n previousBody: result.previousBody.slice(0, MAX_AUDIT_BODY_SNAPSHOT),\n },\n },\n });\n await emitMentionAudit(\n c,\n { factoryProjectId: comment.factoryProjectId, workItemId: comment.workItemId },\n comment.id,\n result.addedMentions.map(mention => mention.id),\n );\n return c.json({ comment: toWireComment(comment, tenant.userId) });\n },\n }),\n\n registerApiRoute('/web/factory/work-items/:workItemId/comments/:commentId', {\n method: 'DELETE',\n handler: async cc => {\n const c = loose(cc);\n const tenant = await resolveTenant(c);\n if ('response' in tenant) return tenant.response;\n\n const workItemId = c.req.param('workItemId');\n const commentId = c.req.param('commentId');\n if (!workItemId || !UUID_RE.test(workItemId) || !commentId || !UUID_RE.test(commentId)) {\n return c.json({ error: 'Comment not found' }, 404);\n }\n\n const result = await domain.deleteComment({\n orgId: tenant.orgId,\n workItemId,\n commentId,\n editor: editorFor(c, tenant),\n });\n if (result.status === 'not_found') return c.json({ error: 'Comment not found' }, 404);\n if (result.status === 'forbidden') return c.json({ error: 'not_comment_author' }, 403);\n if (result.status === 'not_editable') return c.json({ error: 'comment_not_editable' }, 409);\n\n await audit?.emit({\n context: c,\n input: {\n action: 'factory.work_item.comment_deleted',\n factoryProjectId: result.comment.factoryProjectId,\n targets: [{ type: 'work_item', id: result.comment.workItemId }],\n metadata: { commentId: result.comment.id },\n },\n });\n return c.json({ comment: toWireComment(result.comment, tenant.userId) });\n },\n }),\n\n registerApiRoute('/web/factory/projects/:id/mention-roster', {\n method: 'GET',\n handler: async cc => {\n const c = loose(cc);\n const tenant = await resolveTenant(c);\n if ('response' in tenant) return tenant.response;\n\n const projectId = c.req.param('id');\n if (!projectId || !UUID_RE.test(projectId)) return c.json({ error: 'Project not found' }, 404);\n await projects.ensureReady();\n const project = await projects.get({ orgId: tenant.orgId, id: projectId });\n if (!project) return c.json({ error: 'Project not found' }, 404);\n\n await comments.ensureReady();\n const roster = await domain.mentionRoster({ orgId: tenant.orgId, factoryProjectId: projectId });\n const query = c.req.query('q')?.trim().toLowerCase();\n const members = query\n ? roster.filter(member => (member.name ?? member.id).toLowerCase().startsWith(query))\n : roster;\n return c.json({ members });\n },\n }),\n ];\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/comments/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,eAAO,MAAM,yBAAyB,EAAE,gBA2CvC,CAAC;AAEF,eAAO,MAAM,iCAAiC,EAAE,gBA6B/C,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
//#region src/storage/domains/comments/schema.ts
|
|
2
|
+
const WORK_ITEM_COMMENTS_SCHEMA = {
|
|
3
|
+
name: "work_item_comments",
|
|
4
|
+
columns: {
|
|
5
|
+
id: { type: "uuid-pk" },
|
|
6
|
+
org_id: { type: "text" },
|
|
7
|
+
factory_project_id: { type: "text" },
|
|
8
|
+
work_item_id: { type: "text" },
|
|
9
|
+
kind: {
|
|
10
|
+
type: "text",
|
|
11
|
+
default: "comment"
|
|
12
|
+
},
|
|
13
|
+
body: { type: "text" },
|
|
14
|
+
body_format: {
|
|
15
|
+
type: "text",
|
|
16
|
+
default: "markdown"
|
|
17
|
+
},
|
|
18
|
+
author_kind: { type: "text" },
|
|
19
|
+
author_id: { type: "text" },
|
|
20
|
+
author_display_name: {
|
|
21
|
+
type: "text",
|
|
22
|
+
nullable: true
|
|
23
|
+
},
|
|
24
|
+
author_avatar_url: {
|
|
25
|
+
type: "text",
|
|
26
|
+
nullable: true
|
|
27
|
+
},
|
|
28
|
+
author_external: {
|
|
29
|
+
type: "json",
|
|
30
|
+
nullable: true
|
|
31
|
+
},
|
|
32
|
+
reply_to_comment_id: {
|
|
33
|
+
type: "text",
|
|
34
|
+
nullable: true
|
|
35
|
+
},
|
|
36
|
+
reply_quote: {
|
|
37
|
+
type: "text",
|
|
38
|
+
nullable: true
|
|
39
|
+
},
|
|
40
|
+
reply_to_author_id: {
|
|
41
|
+
type: "text",
|
|
42
|
+
nullable: true
|
|
43
|
+
},
|
|
44
|
+
reply_to_author_name: {
|
|
45
|
+
type: "text",
|
|
46
|
+
nullable: true
|
|
47
|
+
},
|
|
48
|
+
mentions: { type: "json" },
|
|
49
|
+
external_source: {
|
|
50
|
+
type: "json",
|
|
51
|
+
nullable: true
|
|
52
|
+
},
|
|
53
|
+
source_key: {
|
|
54
|
+
type: "text",
|
|
55
|
+
nullable: true
|
|
56
|
+
},
|
|
57
|
+
occurred_at: { type: "timestamp" },
|
|
58
|
+
edited_at: {
|
|
59
|
+
type: "timestamp",
|
|
60
|
+
nullable: true
|
|
61
|
+
},
|
|
62
|
+
deleted_at: {
|
|
63
|
+
type: "timestamp",
|
|
64
|
+
nullable: true
|
|
65
|
+
},
|
|
66
|
+
deleted_by: {
|
|
67
|
+
type: "text",
|
|
68
|
+
nullable: true
|
|
69
|
+
},
|
|
70
|
+
revision: {
|
|
71
|
+
type: "integer",
|
|
72
|
+
default: 1
|
|
73
|
+
},
|
|
74
|
+
created_at: { type: "timestamp" },
|
|
75
|
+
updated_at: { type: "timestamp" }
|
|
76
|
+
},
|
|
77
|
+
uniqueIndexes: [{
|
|
78
|
+
name: "work_item_comments_project_source_key_unique",
|
|
79
|
+
columns: ["factory_project_id", "source_key"],
|
|
80
|
+
whereNotNull: "source_key"
|
|
81
|
+
}],
|
|
82
|
+
indexes: [{
|
|
83
|
+
name: "work_item_comments_feed_idx",
|
|
84
|
+
columns: [
|
|
85
|
+
"org_id",
|
|
86
|
+
"factory_project_id",
|
|
87
|
+
"work_item_id",
|
|
88
|
+
"occurred_at",
|
|
89
|
+
"id"
|
|
90
|
+
]
|
|
91
|
+
}]
|
|
92
|
+
};
|
|
93
|
+
const WORK_ITEM_COMMENT_MENTIONS_SCHEMA = {
|
|
94
|
+
name: "work_item_comment_mentions",
|
|
95
|
+
columns: {
|
|
96
|
+
id: { type: "uuid-pk" },
|
|
97
|
+
comment_id: { type: "text" },
|
|
98
|
+
mentioned_kind: { type: "text" },
|
|
99
|
+
mentioned_id: { type: "text" },
|
|
100
|
+
author_id: { type: "text" },
|
|
101
|
+
org_id: { type: "text" },
|
|
102
|
+
factory_project_id: { type: "text" },
|
|
103
|
+
work_item_id: { type: "text" },
|
|
104
|
+
occurred_at: { type: "timestamp" }
|
|
105
|
+
},
|
|
106
|
+
uniqueIndexes: [{
|
|
107
|
+
name: "work_item_comment_mentions_comment_target_unique",
|
|
108
|
+
columns: [
|
|
109
|
+
"comment_id",
|
|
110
|
+
"mentioned_kind",
|
|
111
|
+
"mentioned_id"
|
|
112
|
+
]
|
|
113
|
+
}],
|
|
114
|
+
indexes: [{
|
|
115
|
+
name: "work_item_comment_mentions_inbox_idx",
|
|
116
|
+
columns: [
|
|
117
|
+
"org_id",
|
|
118
|
+
"factory_project_id",
|
|
119
|
+
"mentioned_id",
|
|
120
|
+
"occurred_at",
|
|
121
|
+
"id"
|
|
122
|
+
]
|
|
123
|
+
}, {
|
|
124
|
+
name: "work_item_comment_mentions_item_idx",
|
|
125
|
+
columns: [
|
|
126
|
+
"org_id",
|
|
127
|
+
"factory_project_id",
|
|
128
|
+
"work_item_id"
|
|
129
|
+
]
|
|
130
|
+
}]
|
|
131
|
+
};
|
|
132
|
+
//#endregion
|
|
133
|
+
export { WORK_ITEM_COMMENTS_SCHEMA, WORK_ITEM_COMMENT_MENTIONS_SCHEMA };
|
|
134
|
+
|
|
135
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","names":[],"sources":["../../../../src/storage/domains/comments/schema.ts"],"sourcesContent":["import type { CollectionSchema } from '@mastra/core/storage';\n\nexport const WORK_ITEM_COMMENTS_SCHEMA: CollectionSchema = {\n name: 'work_item_comments',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n work_item_id: { type: 'text' },\n kind: { type: 'text', default: 'comment' },\n body: { type: 'text' },\n body_format: { type: 'text', default: 'markdown' },\n author_kind: { type: 'text' },\n author_id: { type: 'text' },\n author_display_name: { type: 'text', nullable: true },\n author_avatar_url: { type: 'text', nullable: true },\n author_external: { type: 'json', nullable: true },\n reply_to_comment_id: { type: 'text', nullable: true },\n reply_quote: { type: 'text', nullable: true },\n reply_to_author_id: { type: 'text', nullable: true },\n reply_to_author_name: { type: 'text', nullable: true },\n mentions: { type: 'json' },\n external_source: { type: 'json', nullable: true },\n source_key: { type: 'text', nullable: true },\n occurred_at: { type: 'timestamp' },\n edited_at: { type: 'timestamp', nullable: true },\n deleted_at: { type: 'timestamp', nullable: true },\n deleted_by: { type: 'text', nullable: true },\n revision: { type: 'integer', default: 1 },\n created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n },\n uniqueIndexes: [\n {\n name: 'work_item_comments_project_source_key_unique',\n columns: ['factory_project_id', 'source_key'],\n whereNotNull: 'source_key',\n },\n ],\n indexes: [\n {\n name: 'work_item_comments_feed_idx',\n columns: ['org_id', 'factory_project_id', 'work_item_id', 'occurred_at', 'id'],\n },\n ],\n};\n\nexport const WORK_ITEM_COMMENT_MENTIONS_SCHEMA: CollectionSchema = {\n name: 'work_item_comment_mentions',\n columns: {\n id: { type: 'uuid-pk' },\n comment_id: { type: 'text' },\n mentioned_kind: { type: 'text' },\n mentioned_id: { type: 'text' },\n author_id: { type: 'text' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n work_item_id: { type: 'text' },\n occurred_at: { type: 'timestamp' },\n },\n uniqueIndexes: [\n {\n name: 'work_item_comment_mentions_comment_target_unique',\n columns: ['comment_id', 'mentioned_kind', 'mentioned_id'],\n },\n ],\n indexes: [\n {\n name: 'work_item_comment_mentions_inbox_idx',\n columns: ['org_id', 'factory_project_id', 'mentioned_id', 'occurred_at', 'id'],\n },\n {\n name: 'work_item_comment_mentions_item_idx',\n columns: ['org_id', 'factory_project_id', 'work_item_id'],\n },\n ],\n};\n"],"mappings":";AAEA,MAAa,4BAA8C;CACzD,MAAM;CACN,SAAS;EACP,IAAI,EAAE,MAAM,UAAU;EACtB,QAAQ,EAAE,MAAM,OAAO;EACvB,oBAAoB,EAAE,MAAM,OAAO;EACnC,cAAc,EAAE,MAAM,OAAO;EAC7B,MAAM;GAAE,MAAM;GAAQ,SAAS;EAAU;EACzC,MAAM,EAAE,MAAM,OAAO;EACrB,aAAa;GAAE,MAAM;GAAQ,SAAS;EAAW;EACjD,aAAa,EAAE,MAAM,OAAO;EAC5B,WAAW,EAAE,MAAM,OAAO;EAC1B,qBAAqB;GAAE,MAAM;GAAQ,UAAU;EAAK;EACpD,mBAAmB;GAAE,MAAM;GAAQ,UAAU;EAAK;EAClD,iBAAiB;GAAE,MAAM;GAAQ,UAAU;EAAK;EAChD,qBAAqB;GAAE,MAAM;GAAQ,UAAU;EAAK;EACpD,aAAa;GAAE,MAAM;GAAQ,UAAU;EAAK;EAC5C,oBAAoB;GAAE,MAAM;GAAQ,UAAU;EAAK;EACnD,sBAAsB;GAAE,MAAM;GAAQ,UAAU;EAAK;EACrD,UAAU,EAAE,MAAM,OAAO;EACzB,iBAAiB;GAAE,MAAM;GAAQ,UAAU;EAAK;EAChD,YAAY;GAAE,MAAM;GAAQ,UAAU;EAAK;EAC3C,aAAa,EAAE,MAAM,YAAY;EACjC,WAAW;GAAE,MAAM;GAAa,UAAU;EAAK;EAC/C,YAAY;GAAE,MAAM;GAAa,UAAU;EAAK;EAChD,YAAY;GAAE,MAAM;GAAQ,UAAU;EAAK;EAC3C,UAAU;GAAE,MAAM;GAAW,SAAS;EAAE;EACxC,YAAY,EAAE,MAAM,YAAY;EAChC,YAAY,EAAE,MAAM,YAAY;CAClC;CACA,eAAe,CACb;EACE,MAAM;EACN,SAAS,CAAC,sBAAsB,YAAY;EAC5C,cAAc;CAChB,CACF;CACA,SAAS,CACP;EACE,MAAM;EACN,SAAS;GAAC;GAAU;GAAsB;GAAgB;GAAe;EAAI;CAC/E,CACF;AACF;AAEA,MAAa,oCAAsD;CACjE,MAAM;CACN,SAAS;EACP,IAAI,EAAE,MAAM,UAAU;EACtB,YAAY,EAAE,MAAM,OAAO;EAC3B,gBAAgB,EAAE,MAAM,OAAO;EAC/B,cAAc,EAAE,MAAM,OAAO;EAC7B,WAAW,EAAE,MAAM,OAAO;EAC1B,QAAQ,EAAE,MAAM,OAAO;EACvB,oBAAoB,EAAE,MAAM,OAAO;EACnC,cAAc,EAAE,MAAM,OAAO;EAC7B,aAAa,EAAE,MAAM,YAAY;CACnC;CACA,eAAe,CACb;EACE,MAAM;EACN,SAAS;GAAC;GAAc;GAAkB;EAAc;CAC1D,CACF;CACA,SAAS,CACP;EACE,MAAM;EACN,SAAS;GAAC;GAAU;GAAsB;GAAgB;GAAe;EAAI;CAC/E,GACA;EACE,MAAM;EACN,SAAS;GAAC;GAAU;GAAsB;EAAc;CAC1D,CACF;AACF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { FactoryActorKind } from './actor.js';
|
|
2
|
+
import type { FactoryMentionRef, WorkItemCommentReplyRef, WorkItemCommentRow } from './base.js';
|
|
3
|
+
/**
|
|
4
|
+
* Display-only author. The stored `FactoryActorRef` also carries the platform
|
|
5
|
+
* join keys (team, message, bot flag) that linked a sender to a tenant user;
|
|
6
|
+
* those never reach a thread reader.
|
|
7
|
+
*/
|
|
8
|
+
export interface WireCommentAuthor {
|
|
9
|
+
kind: FactoryActorKind;
|
|
10
|
+
id: string;
|
|
11
|
+
displayName?: string;
|
|
12
|
+
avatarUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface WireComment {
|
|
15
|
+
id: string;
|
|
16
|
+
workItemId: string;
|
|
17
|
+
kind: string;
|
|
18
|
+
body: string;
|
|
19
|
+
bodyFormat: string;
|
|
20
|
+
author: WireCommentAuthor;
|
|
21
|
+
replyTo?: WorkItemCommentReplyRef;
|
|
22
|
+
mentions: FactoryMentionRef[];
|
|
23
|
+
/** The viewer's own local sends only, so their client can match pending rows. */
|
|
24
|
+
clientToken?: string;
|
|
25
|
+
origin?: {
|
|
26
|
+
integrationId: string;
|
|
27
|
+
type: string;
|
|
28
|
+
url?: string;
|
|
29
|
+
};
|
|
30
|
+
revision: number;
|
|
31
|
+
occurredAt: string;
|
|
32
|
+
editedAt?: string;
|
|
33
|
+
deletedAt?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface WireCommentPage {
|
|
36
|
+
comments: WireComment[];
|
|
37
|
+
nextCursor?: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function toWireComment(comment: WorkItemCommentRow, viewerId: string): WireComment;
|
|
40
|
+
//# sourceMappingURL=wire.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/comments/wire.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAmB,MAAM,YAAY,CAAC;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAEhG;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,gBAAgB,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,CAAC,EAAE,uBAAuB,CAAC;IAClC,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAaD,wBAAgB,aAAa,CAAC,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,CA6BxF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/storage/domains/comments/wire.ts
|
|
2
|
+
const LOCAL_SOURCE_KEY_PREFIX = "local:comment:";
|
|
3
|
+
function toWireAuthor({ kind, id, displayName, avatarUrl }) {
|
|
4
|
+
return {
|
|
5
|
+
kind,
|
|
6
|
+
id,
|
|
7
|
+
...displayName ? { displayName } : {},
|
|
8
|
+
...avatarUrl ? { avatarUrl } : {}
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function toWireComment(comment, viewerId) {
|
|
12
|
+
const clientToken = comment.author.id === viewerId && comment.sourceKey?.startsWith(LOCAL_SOURCE_KEY_PREFIX) ? comment.sourceKey.slice(14) : void 0;
|
|
13
|
+
return {
|
|
14
|
+
id: comment.id,
|
|
15
|
+
workItemId: comment.workItemId,
|
|
16
|
+
kind: comment.kind,
|
|
17
|
+
body: comment.body,
|
|
18
|
+
bodyFormat: comment.bodyFormat,
|
|
19
|
+
author: toWireAuthor(comment.author),
|
|
20
|
+
...comment.replyTo ? { replyTo: comment.replyTo } : {},
|
|
21
|
+
mentions: comment.mentions,
|
|
22
|
+
...clientToken ? { clientToken } : {},
|
|
23
|
+
...comment.externalSource ? { origin: {
|
|
24
|
+
integrationId: comment.externalSource.integrationId,
|
|
25
|
+
type: comment.externalSource.type,
|
|
26
|
+
...comment.externalSource.url ? { url: comment.externalSource.url } : {}
|
|
27
|
+
} } : {},
|
|
28
|
+
revision: comment.revision,
|
|
29
|
+
occurredAt: comment.occurredAt.toISOString(),
|
|
30
|
+
...comment.editedAt ? { editedAt: comment.editedAt.toISOString() } : {},
|
|
31
|
+
...comment.deletedAt ? { deletedAt: comment.deletedAt.toISOString() } : {}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { toWireComment };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=wire.js.map
|