@bud.sh/app 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/client/assets/bud/design.js +1 -1
  2. package/dist/client/assets/{canvas-C8hyPWoT.js → canvas-Cu6R6xxT.js} +1 -1
  3. package/dist/client/assets/difference-worker-jfTSn-Tw.js +8 -0
  4. package/dist/client/assets/{edit-B050x0rV.js → edit-DUotSxjS.js} +12 -12
  5. package/dist/client/assets/files-js6ElfkU.js +1 -0
  6. package/dist/client/assets/i18n-DxqFr2mi.js +1 -0
  7. package/dist/client/assets/index-CFFxP0gS.css +2 -0
  8. package/dist/client/assets/{index-Dpxjiok1.js → index-ChANGtl-.js} +2 -2
  9. package/dist/client/assets/lru-DzKYIXMA.js +1 -0
  10. package/dist/client/assets/pages-6_lhiQmz.js +1 -0
  11. package/dist/client/assets/{project-branches-DzXdaT9L.js → project-branches-DO897zM6.js} +1 -1
  12. package/dist/client/assets/project-comments-DFFKVpia.js +1 -0
  13. package/dist/client/assets/project-thread-links-NLFWQRD2.js +1 -0
  14. package/dist/client/assets/{project-threads-CHGG-6fo.js → project-threads-Lay351p4.js} +105 -105
  15. package/dist/client/assets/{project-work-L5fYMSOu.js → project-work-du0Y-L5Y.js} +1 -1
  16. package/dist/client/assets/rolldown-runtime-XKyaHtl9.js +1 -0
  17. package/dist/client/assets/task-design-Avb2RO4w.js +23 -0
  18. package/dist/client/assets/tasks-CA-E8bbK.js +1 -0
  19. package/dist/client/assets/{tasks-request-DGigNdyK.js → tasks-request-C55IeuiP.js} +1 -1
  20. package/dist/client/assets/workspace-Cw5HvX5d.js +2 -0
  21. package/dist/client/index.html +3 -3
  22. package/dist/hosted/assets/{canvas-MWtOwaWm.js → canvas-V36732ER.js} +6 -4
  23. package/dist/hosted/assets/{comment-data-DsgJWq4n.js → comment-data-CF2ZV_3k.js} +4162 -3659
  24. package/dist/hosted/assets/{files-Wvo11G2A.js → files-DjSCjfU7.js} +5 -3
  25. package/dist/hosted/assets/{pages-BAmRFVtU.js → pages-BzjzeuPu.js} +3 -3
  26. package/dist/hosted/assets/{project-branches-BNloVosX.js → project-branches-BT97J9i7.js} +1 -1
  27. package/dist/hosted/assets/{project-thread-links-BmY8HQXt.js → project-thread-links-BRLgByEe.js} +2 -2
  28. package/dist/hosted/assets/{screen-QmqmI2Aq.js → screen-CKp2C7kx.js} +68 -137
  29. package/dist/hosted/assets/{tasks-C8iWPrWg.js → tasks-Dj7AyBJB.js} +12 -5
  30. package/dist/hosted/assets/{tasks-request-C89fN1dK.js → tasks-request-DZob623r.js} +1 -1
  31. package/dist/hosted/hosted.js +174 -18
  32. package/dist/node/assets/{src-BdvZ2mYc.js → src-CerrKjID.js} +57 -1
  33. package/dist/node/design.js +969 -809
  34. package/dist/node/server.js +25 -3
  35. package/dist/node-host/assets/{canvas-D_F8SIlm.js → canvas-TRUfxfL5.js} +6 -4
  36. package/dist/node-host/assets/{comment-data-q_8INiZz.js → comment-data-DyIZNpfG.js} +4143 -3640
  37. package/dist/node-host/assets/{files-xazOrNCX.js → files-Dh2TiQZq.js} +5 -3
  38. package/dist/node-host/assets/{pages-D6VkmdfQ.js → pages-BxpjbYhs.js} +3 -3
  39. package/dist/node-host/assets/{project-branches-C26hwmo3.js → project-branches-B7HUGiVK.js} +1 -1
  40. package/dist/node-host/assets/{project-thread-links-BOzjws5W.js → project-thread-links-CauJF0Cz.js} +2 -2
  41. package/dist/node-host/assets/{screen-Dog-YByu.js → screen-CZXWJEds.js} +68 -137
  42. package/dist/node-host/assets/{tasks-A1_bpb3_.js → tasks-Bs1IOpeU.js} +12 -5
  43. package/dist/node-host/assets/{tasks-request-Bie1PpQP.js → tasks-request-ZWmbc8fE.js} +1 -1
  44. package/dist/node-host/node-host.js +174 -18
  45. package/dist/server/assets/{canvas-Dn4RYoU2.js → canvas-Dc1mYCwQ.js} +7 -5
  46. package/dist/server/assets/{comment-data-B0OLHBGp.js → comment-data-CsjukwAW.js} +3911 -3619
  47. package/dist/server/assets/{events-6z5v7Uca.js → events-iHpLGr3k.js} +213 -2
  48. package/dist/server/assets/{files-C5Vilfe4.js → files-E9mSFeoc.js} +6 -4
  49. package/dist/server/assets/{listener-o1STuLju.js → listener-DN5TyOjJ.js} +45 -11
  50. package/dist/server/assets/{pages-BNa0MHEc.js → pages-BBBXyJWV.js} +4 -4
  51. package/dist/server/assets/{project-branches-GtQYyOH5.js → project-branches-B0YIK6Ur.js} +2 -2
  52. package/dist/server/assets/{project-thread-links-Nfz9NIny.js → project-thread-links-CBOpf6zk.js} +3 -3
  53. package/dist/server/assets/{project-work-Cy_BpHwR.js → project-work-qSKFO5yj.js} +3 -3
  54. package/dist/server/assets/{screen-BtcJmZwj.js → screen-BIQA2mr4.js} +69 -138
  55. package/dist/server/assets/{server-CYvuOSBA.js → server-DxK-UB_Z.js} +30 -4
  56. package/dist/server/assets/{services-DK4fqrlF.js → services-BRrgXYlT.js} +105 -9
  57. package/dist/server/assets/{tasks-B82tHwyQ.js → tasks-CiXodsLN.js} +14 -7
  58. package/dist/server/assets/{tasks-request-BtJBlkxV.js → tasks-request-DhwCzpRi.js} +2 -2
  59. package/dist/server/migration.js +3 -3
  60. package/dist/server/runtime.js +3 -3
  61. package/dist/server/server.js +2 -2
  62. package/dist/types/server.d.ts +11 -1
  63. package/package.json +1 -1
  64. package/dist/client/assets/difference-worker-BfF4_N3e.js +0 -8
  65. package/dist/client/assets/files-D_Tm7gCK.js +0 -1
  66. package/dist/client/assets/i18n-BtfXum8P.js +0 -1
  67. package/dist/client/assets/index-CjhJtepP.css +0 -2
  68. package/dist/client/assets/lru-BkhKJhvt.js +0 -1
  69. package/dist/client/assets/pages-B-_CKvDS.js +0 -1
  70. package/dist/client/assets/project-comments-CQkB2jbE.js +0 -1
  71. package/dist/client/assets/project-thread-links-BN7zL0AX.js +0 -1
  72. package/dist/client/assets/task-design-DYqcqq1b.js +0 -23
  73. package/dist/client/assets/tasks-A2FKo3_h.js +0 -1
  74. package/dist/client/assets/workspace-CvWmU2RK.js +0 -2
@@ -1,9 +1,9 @@
1
1
  import { i as __toESM } from "./rolldown-runtime-DktXgydw.js";
2
- import { $ as FileSearchPanel, $r as parseReviewRepository, A as parseEditorPreferences, Ar as hasResolvedThemes, At as defaultReviewView, Br as areLanguagesAttached, Bt as fileHref, Cr as WorkerPoolTerminatedError, D as ReviewActionDialog, Dr as isFilePlainText, E as FileConflictPanel, Er as markWorkerErrorReported, F as FileWorkspace, Fr as attachResolvedThemes, Ft as reviewComparison, Gr as parseFileSaveRequest, Gt as fileRoutes, Hr as parseReviewActionPlan, Ht as readFileLocation, I as defaultFileDestination, Ir as themeResolver, It as reviewContextKey, Jr as parseMutationPlan, Kr as parseFileSaveResult, L as fileActionIntent, Ln as jsx, Lr as getThemes, Lt as reviewHref, M as FileMutationDialog, Mr as getSharedHighlighter, Mt as parseReviewSession, N as FileReviewPanel, Nr as prepareThemeResolution, Nt as readReviewLocation, O as FileEditorPanel, Or as renderFileWithHighlighter, P as codeThemes, Pr as validateResolvedThemeName, Pt as rememberReviewPosition, Qr as parseReviewHistory, R as mutationFileView, Rr as getResolvedOrResolveLanguage, Rt as closeFileTab, Sr as WorkerPoolTaskCanceledError, St as isCodeConversation, Tr as isHandledWorkerPoolError, Tt as readConversationLocation, Ur as parseReviewActionRecoveries, Ut as reconcileFileView, Vr as ResolvedLanguages, Vt as parseFileView, Wr as parseReviewActionResult, Wt as rememberFile, Xr as parseRecoveries, Yr as parseMutationResult, Zr as parseReviewDiff, _n as ref, _r as isDiffPlainText, ai as parseFileDocument, br as areFilesEqual, bt as conversationHref, cn as toast, ei as parseReviewSnapshot, f as storeDocument, gr as reviewConflictIdentity, hn as Text, hr as parseFileUpdate, ii as parseFileChange, j as FileRecoveryDialog, jr as areThemesEqual, k as defaultEditorPreferences, kr as areFileRenderOptionsEqual, kt as defaultReviewPosition, l as projectStore, ln as readPreference, m as storedFiles, mr as createCodeAnchor, ni as parseFileSearchQuery, oi as parseFileIndex, p as storedDocument, pn as t, qr as maxFileSaveBytes, ri as parseFileSearchResult, s as applyFileUpdate, si as parseFilePath, ti as parseReviewSource, tt as ConversationSidebar, u as saveFiles, un as writePreference, v as projectLive, vr as renderDiffWithHighlighter, vt as codeCommentCounts, wr as WorkerPoolWorkerError, wt as locateCodeConversations, xr as areDiffTargetsEqual, y as routes, yr as areDiffRenderOptionsEqual, z as remainingMutationIntent, zr as resolveLanguage, zt as defaultFileView } from "./comment-data-DsgJWq4n.js";
2
+ import { $ as FileSearchPanel, $r as parseReviewActionResult, A as parseEditorPreferences, Ar as areDiffTargetsEqual, At as defaultReviewView, Br as areThemesEqual, Bt as fileHref, Cr as createCodeAnchor, D as ReviewActionDialog, Dr as renderDiffWithHighlighter, E as FileConflictPanel, Er as isDiffPlainText, F as FileWorkspace, Fr as markWorkerErrorReported, Ft as reviewComparison, Gr as themeResolver, Gt as fileRoutes, Hr as prepareThemeResolution, Ht as readFileLocation, I as defaultFileDestination, Ir as isFilePlainText, It as reviewContextKey, Jr as resolveLanguage, Kr as getThemes, L as fileActionIntent, Lr as renderFileWithHighlighter, Lt as reviewHref, M as FileMutationDialog, Mr as WorkerPoolTerminatedError, Mt as parseReviewSession, N as FileReviewPanel, Nr as WorkerPoolWorkerError, Nt as readReviewLocation, O as FileEditorPanel, Or as areDiffRenderOptionsEqual, P as codeThemes, Pr as isHandledWorkerPoolError, Pt as rememberReviewPosition, Qr as parseReviewActionRecoveries, R as mutationFileView, Rn as jsx, Rr as areFileRenderOptionsEqual, Rt as closeFileTab, St as isCodeConversation, Tr as reviewConflictIdentity, Tt as readConversationLocation, Ur as validateResolvedThemeName, Ut as reconcileFileView, Vr as getSharedHighlighter, Vt as parseFileView, Wr as attachResolvedThemes, Wt as rememberFile, Xr as ResolvedLanguages, Yr as areLanguagesAttached, Zr as parseReviewActionPlan, ai as parseRecoveries, bt as conversationHref, ci as parseReviewRepository, cn as toast, di as parseFileSearchQuery, ei as parseFileSaveRequest, f as storeDocument, fi as parseFileSearchResult, gi as parseFilePath, gn as Text, hi as parseFileIndex, ii as parseMutationResult, j as FileRecoveryDialog, jr as WorkerPoolTaskCanceledError, k as defaultEditorPreferences, kr as areFilesEqual, kt as defaultReviewPosition, l as projectStore, li as parseReviewSnapshot, ln as readPreference, m as storedFiles, mi as parseFileDocument, mn as t, ni as maxFileSaveBytes, oi as parseReviewDiff, p as storedDocument, pi as parseFileChange, qr as getResolvedOrResolveLanguage, ri as parseMutationPlan, s as applyFileUpdate, si as parseReviewHistory, ti as parseFileSaveResult, tt as ConversationSidebar, u as saveFiles, ui as parseReviewSource, un as writePreference, v as projectLive, vn as ref, vt as codeCommentCounts, wr as parseFileUpdate, wt as locateCodeConversations, y as routes, z as remainingMutationIntent, zr as hasResolvedThemes, zt as defaultFileView } from "./comment-data-CF2ZV_3k.js";
3
3
  import { B as DEFAULT_THEMES, C as getFiletypeFromFileName, S as getCustomExtensionsVersion, x as getCustomExtensionsMap } from "./cloneFileDiffMetadata-C1BcNpxN.js";
4
- import { n as createProjectComments, t as defineScreen } from "./screen-QmqmI2Aq.js";
5
4
  import { t as require_lru } from "./lru-C0_oUet4.js";
6
- import { t as ProjectThreadLinks } from "./project-thread-links-BmY8HQXt.js";
5
+ import { n as createProjectComments, t as defineScreen } from "./screen-CKp2C7kx.js";
6
+ import { t as ProjectThreadLinks } from "./project-thread-links-BRLgByEe.js";
7
7
  //#region ../../node_modules/.pnpm/@pierre+diffs@1.5.2_@shikijs+themes@4.5.0_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/@pierre/diffs/dist/highlighter/languages/getResolvedLanguages.js
8
8
  function getResolvedLanguages(languages) {
9
9
  const resolvedLanguages = [];
@@ -3269,6 +3269,8 @@ function ProjectFileReview(handle) {
3269
3269
  },
3270
3270
  onClose: closeComments,
3271
3271
  onWrite: comments.write,
3272
+ viewerId: comments.viewer?.id,
3273
+ onDelete: (thread, messageId) => comments.remove(thread.id, messageId),
3272
3274
  onCreate: createComment,
3273
3275
  onCancelDraft: () => {
3274
3276
  draftAnchor = void 0;
@@ -1,7 +1,7 @@
1
- import { Ji as optional, Ki as number, Kt as pageRoutes, Ln as jsx, Nn as Fragment, Qt as Spinner, Xi as parseSafe, Zi as string, Zt as Loader, _n as ref, _t as PagesWorkspace, bn as on, ci as MAX_CANVAS_Y, hn as Text, in as IconButton, l as projectStore, ln as readPreference, pn as t, qi as object, rn as Select, un as writePreference, zi as array } from "./comment-data-DsgJWq4n.js";
2
- import { n as createProjectComments, t as defineScreen } from "./screen-QmqmI2Aq.js";
1
+ import { Kt as pageRoutes, Pn as Fragment, Qt as Spinner, Rn as jsx, Zi as array, Zt as Loader, _i as MAX_CANVAS_Y, _t as PagesWorkspace, aa as object, ca as parseSafe, gn as Text, ia as number, in as IconButton, l as projectStore, la as string, ln as readPreference, mn as t, oa as optional, rn as Select, un as writePreference, vn as ref, xn as on } from "./comment-data-CF2ZV_3k.js";
3
2
  import { n as workspaceTab, t as followWorkspaceTab } from "../hosted.js";
4
- import { n as createProjectPreviews, r as locatePreview, t as createProjectBranches } from "./project-branches-BNloVosX.js";
3
+ import { n as createProjectPreviews, r as locatePreview, t as createProjectBranches } from "./project-branches-BT97J9i7.js";
4
+ import { n as createProjectComments, t as defineScreen } from "./screen-CKp2C7kx.js";
5
5
  //#region app/client/page-picture.tsx
6
6
  /**
7
7
  * A page as its latest captured picture, for Pages where there is no running site: its slices
@@ -1,4 +1,4 @@
1
- import { Bi as boolean, Gi as nullable, Ki as number, Kn as parsePreview, S as writeRows, Ui as enum_, Xi as parseSafe, Zi as string, Zn as parsePreviewPins, b as plainRow, c as previewKey, l as projectStore, li as parseElementAnchor, pn as t, qi as object, qn as parsePreviewBranch, v as projectLive, y as routes, zi as array } from "./comment-data-DsgJWq4n.js";
1
+ import { Jn as parsePreviewBranch, Qi as boolean, Qn as parsePreviewPins, S as writeRows, Zi as array, aa as object, b as plainRow, c as previewKey, ca as parseSafe, ia as number, l as projectStore, la as string, mn as t, qn as parsePreview, ra as nullable, ta as enum_, v as projectLive, vi as parseElementAnchor, y as routes } from "./comment-data-CF2ZV_3k.js";
2
2
  //#region app/client/project-previews.ts
3
3
  /**
4
4
  * A preview's capture in a theme at a viewport. Captures from before viewports existed name
@@ -1,5 +1,5 @@
1
- import { C as ThreadTaskLinks, Dt as taskHref, Ei as valueByRole, Ln as jsx, Nn as Fragment, _ as requestComments, _n as ref, bn as on, in as IconButton, ir as parseThread, lr as parseThreadLinkInput, pn as t, ui as parseWorkWorkspace, vi as parseWorkItemRef, w as ThreadTaskPicker, y as routes } from "./comment-data-DsgJWq4n.js";
2
- import { n as requestTasks } from "./tasks-request-C89fN1dK.js";
1
+ import { C as ThreadTaskLinks, Di as parseWorkItemRef, Dt as taskHref, Fi as valueByRole, Pn as Fragment, Rn as jsx, _ as requestComments, fr as parseThread, in as IconButton, mn as t, vn as ref, vr as parseThreadLinkInput, w as ThreadTaskPicker, xn as on, y as routes, yi as parseWorkWorkspace } from "./comment-data-CF2ZV_3k.js";
2
+ import { n as requestTasks } from "./tasks-request-DZob623r.js";
3
3
  //#region app/client/project-task-picker.tsx
4
4
  /**
5
5
  * Loads searchable task choices only while the picker is mounted.
@@ -1,143 +1,20 @@
1
- import { _ as requestComments, a as saveThreads, b as plainRow, cn as toast, dr as parseThreadSnapshot, g as CommentsRequestError, i as saveThread, ir as parseThread, l as projectStore, n as unavailableComments, o as threadMatches, or as parseThreadFilter, pn as t, sr as parseThreadId, x as writeOptimistically, y as routes } from "./comment-data-DsgJWq4n.js";
2
- //#region ../work/src/lib/predict.ts
3
- /**
4
- * How a new task shows until its adapter confirms it: the requested values, and the creation
5
- * time for timestamps the adapter sets, under a provisional identity with no revision,
6
- * relations or counts yet.
7
- * @param schema - The board's schema.
8
- * @param id - A provisional identity no adapter uses.
9
- * @param create - The create request.
10
- * @param now - The creation time.
11
- * @returns The provisional task.
12
- */
13
- function predictWorkCreate(schema, id, create, now = /* @__PURE__ */ new Date()) {
14
- let values = { ...create.values };
15
- for (let field of schema.fields) if ((field.role === "created" || field.role === "updated") && values[field.id] === void 0) values[field.id] = field.kind === "date" ? now.toISOString().slice(0, 10) : now.toISOString();
16
- return {
17
- id,
18
- revision: null,
19
- values,
20
- relations: [],
21
- counts: {},
22
- contentLoaded: false,
23
- extra: null
24
- };
25
- }
26
- /**
27
- * How a task shows until its adapter confirms an edit: the edited values over its own.
28
- * @param item - The task as last confirmed.
29
- * @param update - The update request.
30
- * @returns The predicted task.
31
- */
32
- function predictWorkUpdate(item, update) {
33
- return {
34
- ...item,
35
- values: {
36
- ...item.values,
37
- ...update.values
38
- }
39
- };
40
- }
41
- var targets = {
42
- close: ["done", "cancelled"],
43
- reopen: [
44
- "unstarted",
45
- "backlog",
46
- "started"
47
- ]
48
- };
49
- /**
50
- * How a task shows until its adapter confirms an action. Closing and reopening move it to
51
- * the schema's first matching status; otherwise only input naming the task's own fields
52
- * applies, since an action's effects belong to the adapter.
53
- * @param schema - The board's schema.
54
- * @param item - The task as last confirmed.
55
- * @param action - The action request.
56
- * @returns The predicted task.
57
- */
58
- function predictWorkAction(schema, item, action) {
59
- let fields = new Set(schema.fields.map((field) => field.id));
60
- let values = { ...item.values };
61
- for (let [id, value] of Object.entries(action.input)) if (fields.has(id)) values[id] = value;
62
- let kind = schema.actions.find((candidate) => candidate.id === action.action)?.kind;
63
- let categories = kind ? targets[kind] : void 0;
64
- let field = schema.fields.find((candidate) => candidate.role === "status");
65
- let status = categories?.map((category) => schema.statuses.find((candidate) => candidate.category === category)).find(Boolean);
66
- if (field && status) values[field.id] = status.value;
67
- return {
68
- ...item,
69
- values
70
- };
71
- }
72
- /** Who a message shows as until the server, which derives authors from Git, confirms it. */
73
- var pendingAuthor = {
74
- id: "pending",
75
- name: "You",
76
- email: ""
77
- };
78
- function message(id, body, parentId, now) {
79
- return {
80
- id,
81
- body: body.trim(),
82
- author: pendingAuthor,
83
- createdAt: now.toISOString(),
84
- parentId
85
- };
86
- }
87
- /**
88
- * How a new discussion shows until its adapter confirms it.
89
- * @param id - A provisional identity, also used for its first message.
90
- * @param input - The create request.
91
- * @param now - The creation time.
92
- * @returns The provisional discussion.
93
- */
94
- function predictThreadCreate(id, input, now = /* @__PURE__ */ new Date()) {
95
- let createdAt = now.toISOString();
96
- return {
97
- id,
98
- status: "open",
99
- anchor: input.anchor,
100
- itemIds: [...input.itemIds],
101
- messages: [message(id, input.body, null, now)],
102
- messageCount: 1,
103
- messagesLoaded: true,
104
- messagesTruncated: false,
105
- createdAt,
106
- updatedAt: createdAt,
107
- revision: null
1
+ import { S as writeRows, _ as requestComments, a as saveThreads, ar as predictThreadStatus, b as plainRow, br as parseThreadSnapshot, cn as toast, fr as parseThread, g as CommentsRequestError, gr as parseThreadId, hr as parseThreadFilter, i as saveThread, ir as predictThreadReply, l as projectStore, mn as t, n as unavailableComments, nr as predictThreadCreate, o as threadMatches, rr as predictThreadDelete, x as writeOptimistically, y as routes } from "./comment-data-CF2ZV_3k.js";
2
+ //#region app/client/project-comments.ts
3
+ var viewers = /* @__PURE__ */ new Map();
4
+ function parseViewer(value) {
5
+ let viewer = value && typeof value === "object" && "viewer" in value ? value.viewer : void 0;
6
+ if (viewer === null) return null;
7
+ if (viewer && typeof viewer === "object" && "id" in viewer && "name" in viewer && typeof viewer.id === "string" && typeof viewer.name === "string" && viewer.id.length <= 256 && viewer.name.length <= 1e3) return {
8
+ id: viewer.id,
9
+ name: viewer.name
108
10
  };
11
+ throw new TypeError("Invalid viewer.");
109
12
  }
110
- /**
111
- * How a discussion shows until its adapter confirms a reply.
112
- * @param thread - The discussion as last confirmed.
113
- * @param id - A provisional message identity.
114
- * @param input - The reply request.
115
- * @param now - The reply time.
116
- * @returns The predicted discussion.
117
- */
118
- function predictThreadReply(thread, id, input, now = /* @__PURE__ */ new Date()) {
119
- return {
120
- ...thread,
121
- messages: thread.messagesLoaded ? [...thread.messages, message(id, input.body, input.parentId, now)] : thread.messages,
122
- messageCount: thread.messageCount + 1,
123
- updatedAt: now.toISOString()
124
- };
13
+ function parseDeletion(value) {
14
+ if (!value || typeof value !== "object" || !("thread" in value)) throw new TypeError("Invalid deletion.");
15
+ return { thread: value.thread === null ? null : parseThread(value.thread) };
125
16
  }
126
17
  /**
127
- * How a discussion shows until its adapter confirms a status change.
128
- * @param thread - The discussion as last confirmed.
129
- * @param input - The status request.
130
- * @returns The predicted discussion.
131
- */
132
- function predictThreadStatus(thread, input) {
133
- return {
134
- ...thread,
135
- status: input.status
136
- };
137
- }
138
- //#endregion
139
- //#region app/client/project-comments.ts
140
- /**
141
18
  * Reads one task's discussions with their messages in a single round, so the task page
142
19
  * renders complete instead of loading its discussion after it appears.
143
20
  * @param token - The current companion capability.
@@ -245,6 +122,21 @@ function createProjectComments(options) {
245
122
  let generation = 0, reading;
246
123
  let details = /* @__PURE__ */ new Map();
247
124
  let detailFailures = /* @__PURE__ */ new Set();
125
+ let viewer = null, askedViewer = false;
126
+ function askViewer() {
127
+ if (askedViewer || !snapshot.capabilities.delete) return;
128
+ askedViewer = true;
129
+ let pending = viewers.get(options.token);
130
+ if (!pending) {
131
+ pending = requestComments(routes.comments.viewer.href(), options.token, new AbortController().signal, parseViewer, options.fetcher).catch(() => null);
132
+ viewers.set(options.token, pending);
133
+ }
134
+ pending.then((value) => {
135
+ viewer = value;
136
+ changed();
137
+ });
138
+ }
139
+ askViewer();
248
140
  let opened = Promise.resolve(options.store).then(async (ready) => {
249
141
  store = ready;
250
142
  if (options.initial?.snapshot && !options.initial.stored) await saveThreads(ready, options.initial.snapshot, filter);
@@ -264,6 +156,7 @@ function createProjectComments(options) {
264
156
  loaded = true;
265
157
  now = Date.now();
266
158
  version++;
159
+ askViewer();
267
160
  changed();
268
161
  }
269
162
  function request(url, signal, parse, body) {
@@ -281,6 +174,12 @@ function createProjectComments(options) {
281
174
  await saveThread(store, thread);
282
175
  view();
283
176
  }
177
+ async function forget(id) {
178
+ await opened;
179
+ members?.delete(id);
180
+ await writeRows(store.threads, { delete: [id] });
181
+ view();
182
+ }
284
183
  function includes(thread) {
285
184
  return threadMatches(thread, filter);
286
185
  }
@@ -413,6 +312,13 @@ function createProjectComments(options) {
413
312
  get ready() {
414
313
  return loaded && snapshot.connection.state === "ready";
415
314
  },
315
+ /**
316
+ * Who this browser comments as, once the server said.
317
+ * @returns The viewer, or null until then or without one.
318
+ */
319
+ get viewer() {
320
+ return viewer;
321
+ },
416
322
  loadingThread: (id) => details.has(id),
417
323
  load,
418
324
  loadThread,
@@ -474,6 +380,31 @@ function createProjectComments(options) {
474
380
  thread: saved
475
381
  };
476
382
  },
383
+ /**
384
+ * Deletes one of the viewer's messages; its first message deletes the whole discussion.
385
+ * @param threadId - The discussion.
386
+ * @param messageId - The message to delete.
387
+ * @returns The snapshot after the confirmed deletion.
388
+ */
389
+ async remove(threadId, messageId) {
390
+ requireCapability("delete");
391
+ let id = parseThreadId(threadId), thread = snapshot.threads.find((item) => item.id === id);
392
+ if (!thread?.revision) throw new Error(t("app.client.projectComments.reloadDiscussionBeforeSaving"));
393
+ let next = predictThreadDelete(thread, messageId);
394
+ return operate(routes.comments.deleteMessage.href({ id }), {
395
+ messageId,
396
+ expectedRevision: thread.revision
397
+ }, parseDeletion, (result) => {
398
+ if (!result.thread) return forget(id);
399
+ if (result.thread.id !== id) throw new CommentsRequestError(t("app.client.projectComments.refreshBeforeTryingAgain"), 409, "uncertain");
400
+ return merge(result.thread);
401
+ }, next ? t("app.client.projectComments.commentDeleted") : t("app.client.projectComments.discussionDeleted"), id, (store) => {
402
+ if (next && store.threads.has(id)) store.threads.update(id, (draft) => {
403
+ draft.messages = next.messages;
404
+ draft.messageCount = next.messageCount;
405
+ });
406
+ });
407
+ },
477
408
  async sync() {
478
409
  requireCapability("sync");
479
410
  return operate(routes.comments.sync.href(), { direction: "both" }, parseThreadSnapshot, adopt, t("app.client.projectComments.commentsSynced"));
@@ -491,4 +422,4 @@ function defineScreen(screen) {
491
422
  return screen;
492
423
  }
493
424
  //#endregion
494
- export { predictWorkAction as a, loadItemComments as i, createProjectComments as n, predictWorkCreate as o, loadComments as r, predictWorkUpdate as s, defineScreen as t };
425
+ export { loadItemComments as i, createProjectComments as n, loadComments as r, defineScreen as t };
@@ -1,8 +1,8 @@
1
- import { $t as Button, B as TaskWorkspace, C as ThreadTaskLinks, Ci as parseWorkSyncResult, Dt as taskHref, Et as selectedTask, Jt as CommentThreadDetail, Ln as jsx, Nn as Fragment, Ot as taskRole, S as writeRows, T as ItemDiscussion, Tt as readConversationLocation, Xt as CommentComposer, Yt as CommentThreadItem, _n as ref, b as plainRow, bn as on, cn as toast, di as parseSectionData, gi as parseWorkDetail, h as storedWorkspace, hn as Text, l as projectStore, nt as CommentThreadHeading, pn as t, qt as taskRoutes, x as writeOptimistically, xt as conversationLabel, y as routes, yi as parseWorkMutationResult } from "./comment-data-DsgJWq4n.js";
2
- import { a as predictWorkAction, i as loadItemComments, n as createProjectComments, o as predictWorkCreate, s as predictWorkUpdate, t as defineScreen } from "./screen-QmqmI2Aq.js";
3
- import { n as requestTasks, t as TaskRequestError } from "./tasks-request-C89fN1dK.js";
1
+ import { $t as Button, B as TaskWorkspace, C as ThreadTaskLinks, Dt as taskHref, Et as selectedTask, Jt as CommentThreadDetail, Mi as parseWorkSyncResult, Oi as parseWorkMutationResult, Ot as taskRole, Pn as Fragment, Rn as jsx, S as writeRows, T as ItemDiscussion, Ti as parseWorkDetail, Tt as readConversationLocation, Xt as CommentComposer, Yt as CommentThreadItem, b as plainRow, bi as parseSectionData, cn as toast, cr as predictWorkUpdate, gn as Text, h as storedWorkspace, l as projectStore, mn as t, nt as CommentThreadHeading, or as predictWorkAction, qt as taskRoutes, sr as predictWorkCreate, vn as ref, x as writeOptimistically, xn as on, xt as conversationLabel, y as routes } from "./comment-data-CF2ZV_3k.js";
2
+ import { n as requestTasks, t as TaskRequestError } from "./tasks-request-DZob623r.js";
4
3
  import { r as projectWork } from "../hosted.js";
5
- import { n as ProjectTaskPicker, t as ProjectThreadLinks } from "./project-thread-links-BmY8HQXt.js";
4
+ import { i as loadItemComments, n as createProjectComments, t as defineScreen } from "./screen-CKp2C7kx.js";
5
+ import { n as ProjectTaskPicker, t as ProjectThreadLinks } from "./project-thread-links-BRLgByEe.js";
6
6
  //#region app/client/task-discussion.tsx
7
7
  /**
8
8
  * Owns a task's filtered discussions and lazy detail requests within its mounted lifetime.
@@ -193,7 +193,14 @@ function TaskDiscussion(handle) {
193
193
  id: thread.id,
194
194
  body,
195
195
  parentId
196
- }) : void 0
196
+ }) : void 0,
197
+ viewerId: comments.viewer?.id,
198
+ onDelete: capabilities.delete ? async (messageId) => {
199
+ let whole = thread.messages[0]?.id === messageId;
200
+ await comments.remove(thread.id, messageId);
201
+ if (whole && selected === thread.id) selected = void 0;
202
+ handle.update();
203
+ } : void 0
197
204
  })
198
205
  }, thread.id)) : /* @__PURE__ */ jsx(Text, {
199
206
  variant: "ui-caption",
@@ -1,4 +1,4 @@
1
- import { bi as parseWorkQuery, pn as t, vi as parseWorkItemRef, y as routes, zn as createMultiMatcher } from "./comment-data-DsgJWq4n.js";
1
+ import { Bn as createMultiMatcher, Di as parseWorkItemRef, ki as parseWorkQuery, mn as t, y as routes } from "./comment-data-CF2ZV_3k.js";
2
2
  //#region app/client/tasks-request.ts
3
3
  var reads = createMultiMatcher();
4
4
  var writes = createMultiMatcher();