@agent-native/core 0.77.8 → 0.77.11

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 (216) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +35 -0
  3. package/corpus/core/package.json +3 -3
  4. package/corpus/core/src/a2a/task-store.ts +25 -3
  5. package/corpus/core/src/agent/harness/store.ts +89 -55
  6. package/corpus/core/src/agent/observational-memory/store.ts +40 -14
  7. package/corpus/core/src/agent/run-store.ts +116 -59
  8. package/corpus/core/src/application-state/store.ts +36 -2
  9. package/corpus/core/src/audit/store.ts +37 -6
  10. package/corpus/core/src/browser-sessions/store.ts +31 -12
  11. package/corpus/core/src/chat-threads/store.ts +67 -3
  12. package/corpus/core/src/checkpoints/store.ts +14 -3
  13. package/corpus/core/src/cli/create.ts +9 -0
  14. package/corpus/core/src/collab/awareness.ts +12 -9
  15. package/corpus/core/src/collab/client.ts +4 -2
  16. package/corpus/core/src/collab/storage.ts +20 -2
  17. package/corpus/core/src/db/ddl-guard.ts +112 -0
  18. package/corpus/core/src/extensions/store.ts +76 -3
  19. package/corpus/core/src/integrations/a2a-continuations-store.ts +69 -26
  20. package/corpus/core/src/integrations/config-store.ts +19 -18
  21. package/corpus/core/src/integrations/pending-tasks-store.ts +40 -16
  22. package/corpus/core/src/integrations/remote-commands-store.ts +37 -23
  23. package/corpus/core/src/integrations/remote-devices-store.ts +64 -20
  24. package/corpus/core/src/integrations/remote-push-store.ts +75 -35
  25. package/corpus/core/src/integrations/remote-run-events-store.ts +38 -12
  26. package/corpus/core/src/integrations/thread-mapping-store.ts +11 -2
  27. package/corpus/core/src/mcp/connect-store.ts +53 -16
  28. package/corpus/core/src/mcp/oauth-store.ts +32 -7
  29. package/corpus/core/src/notifications/store.ts +20 -4
  30. package/corpus/core/src/oauth-tokens/store.ts +45 -2
  31. package/corpus/core/src/observability/store.ts +154 -47
  32. package/corpus/core/src/progress/store.ts +36 -21
  33. package/corpus/core/src/provider-api/corpus-jobs-store.ts +25 -5
  34. package/corpus/core/src/provider-api/custom-registry.ts +15 -4
  35. package/corpus/core/src/provider-api/quota-governor.ts +15 -3
  36. package/corpus/core/src/provider-api/staged-datasets-store.ts +22 -5
  37. package/corpus/core/src/resources/store.ts +66 -31
  38. package/corpus/core/src/secrets/storage.ts +18 -22
  39. package/corpus/core/src/server/agent-teams-run-queue.ts +22 -10
  40. package/corpus/core/src/server/auth.ts +22 -4
  41. package/corpus/core/src/server/better-auth-instance.ts +49 -15
  42. package/corpus/core/src/server/embed-session.ts +19 -4
  43. package/corpus/core/src/server/identity-sso-store.ts +40 -11
  44. package/corpus/core/src/server/recap-image-store.ts +28 -9
  45. package/corpus/core/src/settings/store.ts +14 -19
  46. package/corpus/core/src/usage/store.ts +51 -16
  47. package/corpus/core/src/workspace-connections/store.ts +200 -22
  48. package/corpus/templates/calendar/changelog/2026-06-25-booking-link-previews-now-show-the-content-directly-on-the-g.md +6 -0
  49. package/corpus/templates/calendar/server/lib/booking-og-image.ts +0 -2
  50. package/corpus/templates/clips/chrome-extension/package.json +1 -1
  51. package/corpus/templates/content/actions/list-trashed-content-databases.ts +36 -2
  52. package/corpus/templates/content/actions/move-document.ts +79 -33
  53. package/corpus/templates/content/actions/restore-content-database.ts +40 -3
  54. package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +84 -2
  55. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +177 -49
  56. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +393 -219
  57. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +632 -467
  58. package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +114 -14
  59. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +56 -15
  60. package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +6 -5
  61. package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +12 -4
  62. package/corpus/templates/content/app/global.css +9 -0
  63. package/corpus/templates/content/app/hooks/use-create-page.ts +36 -7
  64. package/corpus/templates/content/app/i18n-data.ts +140 -10
  65. package/corpus/templates/content/changelog/2026-06-25-comment-cards-now-track-their-highlighted-text-while-scrolli.md +6 -0
  66. package/corpus/templates/content/changelog/2026-06-25-comments-now-scroll-with-the-document-and-stay-below-the-pag.md +6 -0
  67. package/corpus/templates/content/changelog/2026-06-25-creating-a-database-from-the-slash-menu-no-longer-leaves-sta.md +6 -0
  68. package/corpus/templates/content/changelog/2026-06-25-sidebar-hover-controls-no-longer-leave-a-lingering-fade-when.md +6 -0
  69. package/corpus/templates/content/changelog/2026-06-25-sidebar-page-actions-are-now-easier-to-see-when-hovering-ina.md +6 -0
  70. package/corpus/templates/content/changelog/2026-06-25-text-selections-in-the-editor-no-longer-show-white-gaps-when.md +6 -0
  71. package/corpus/templates/content/changelog/2026-06-25-the-editor-toolbar-now-has-a-one-click-page-link-copy-button.md +6 -0
  72. package/corpus/templates/content/changelog/2026-06-25-the-editor-toolbar-now-shows-page-breadcrumbs-and-the-latest.md +6 -0
  73. package/corpus/templates/content/changelog/2026-06-25-the-page-command-now-leaves-a-notion-style-page-reference-an.md +6 -0
  74. package/corpus/templates/content/shared/nfm.ts +16 -0
  75. package/corpus/templates/forms/changelog/2026-06-25-form-previews-now-show-the-content-directly-on-the-grid-back.md +6 -0
  76. package/corpus/templates/forms/server/lib/form-og-image.ts +0 -2
  77. package/corpus/templates/plan/app/global.css +6 -11
  78. package/corpus/templates/plan/app/pages/PlansPage.tsx +12 -10
  79. package/corpus/templates/plan/changelog/2026-06-25-plan-access-request-pages-stay-visible-during-background-ref.md +6 -0
  80. package/corpus/templates/plan/changelog/2026-06-25-plan-documents-keep-their-full-reading-width-below-1200px-an.md +6 -0
  81. package/dist/a2a/task-store.d.ts.map +1 -1
  82. package/dist/a2a/task-store.js +19 -3
  83. package/dist/a2a/task-store.js.map +1 -1
  84. package/dist/agent/harness/store.d.ts.map +1 -1
  85. package/dist/agent/harness/store.js +63 -34
  86. package/dist/agent/harness/store.js.map +1 -1
  87. package/dist/agent/observational-memory/store.d.ts.map +1 -1
  88. package/dist/agent/observational-memory/store.js +30 -8
  89. package/dist/agent/observational-memory/store.js.map +1 -1
  90. package/dist/agent/run-store.d.ts.map +1 -1
  91. package/dist/agent/run-store.js +103 -46
  92. package/dist/agent/run-store.js.map +1 -1
  93. package/dist/application-state/store.d.ts.map +1 -1
  94. package/dist/application-state/store.js +28 -2
  95. package/dist/application-state/store.js.map +1 -1
  96. package/dist/audit/store.d.ts.map +1 -1
  97. package/dist/audit/store.js +18 -3
  98. package/dist/audit/store.js.map +1 -1
  99. package/dist/browser-sessions/store.d.ts.map +1 -1
  100. package/dist/browser-sessions/store.js +22 -7
  101. package/dist/browser-sessions/store.js.map +1 -1
  102. package/dist/chat-threads/store.d.ts.map +1 -1
  103. package/dist/chat-threads/store.js +51 -3
  104. package/dist/chat-threads/store.js.map +1 -1
  105. package/dist/checkpoints/store.d.ts.map +1 -1
  106. package/dist/checkpoints/store.js +12 -3
  107. package/dist/checkpoints/store.js.map +1 -1
  108. package/dist/cli/create.d.ts.map +1 -1
  109. package/dist/cli/create.js +9 -0
  110. package/dist/cli/create.js.map +1 -1
  111. package/dist/collab/awareness.d.ts +1 -1
  112. package/dist/collab/awareness.d.ts.map +1 -1
  113. package/dist/collab/awareness.js +12 -8
  114. package/dist/collab/awareness.js.map +1 -1
  115. package/dist/collab/client.d.ts.map +1 -1
  116. package/dist/collab/client.js +4 -3
  117. package/dist/collab/client.js.map +1 -1
  118. package/dist/collab/routes.d.ts +1 -1
  119. package/dist/collab/storage.d.ts.map +1 -1
  120. package/dist/collab/storage.js +14 -2
  121. package/dist/collab/storage.js.map +1 -1
  122. package/dist/db/ddl-guard.d.ts +63 -0
  123. package/dist/db/ddl-guard.d.ts.map +1 -1
  124. package/dist/db/ddl-guard.js +85 -0
  125. package/dist/db/ddl-guard.js.map +1 -1
  126. package/dist/extensions/store.d.ts.map +1 -1
  127. package/dist/extensions/store.js +32 -3
  128. package/dist/extensions/store.js.map +1 -1
  129. package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
  130. package/dist/integrations/a2a-continuations-store.js +44 -24
  131. package/dist/integrations/a2a-continuations-store.js.map +1 -1
  132. package/dist/integrations/config-store.d.ts.map +1 -1
  133. package/dist/integrations/config-store.js +17 -11
  134. package/dist/integrations/config-store.js.map +1 -1
  135. package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
  136. package/dist/integrations/pending-tasks-store.js +24 -16
  137. package/dist/integrations/pending-tasks-store.js.map +1 -1
  138. package/dist/integrations/remote-commands-store.d.ts.map +1 -1
  139. package/dist/integrations/remote-commands-store.js +29 -21
  140. package/dist/integrations/remote-commands-store.js.map +1 -1
  141. package/dist/integrations/remote-devices-store.d.ts.map +1 -1
  142. package/dist/integrations/remote-devices-store.js +33 -18
  143. package/dist/integrations/remote-devices-store.js.map +1 -1
  144. package/dist/integrations/remote-push-store.d.ts.map +1 -1
  145. package/dist/integrations/remote-push-store.js +53 -31
  146. package/dist/integrations/remote-push-store.js.map +1 -1
  147. package/dist/integrations/remote-run-events-store.d.ts.map +1 -1
  148. package/dist/integrations/remote-run-events-store.js +26 -10
  149. package/dist/integrations/remote-run-events-store.js.map +1 -1
  150. package/dist/integrations/thread-mapping-store.d.ts.map +1 -1
  151. package/dist/integrations/thread-mapping-store.js +10 -2
  152. package/dist/integrations/thread-mapping-store.js.map +1 -1
  153. package/dist/mcp/connect-store.d.ts.map +1 -1
  154. package/dist/mcp/connect-store.js +34 -16
  155. package/dist/mcp/connect-store.js.map +1 -1
  156. package/dist/mcp/oauth-store.d.ts.map +1 -1
  157. package/dist/mcp/oauth-store.js +22 -7
  158. package/dist/mcp/oauth-store.js.map +1 -1
  159. package/dist/notifications/store.d.ts.map +1 -1
  160. package/dist/notifications/store.js +15 -3
  161. package/dist/notifications/store.js.map +1 -1
  162. package/dist/oauth-tokens/store.d.ts.map +1 -1
  163. package/dist/oauth-tokens/store.js +33 -2
  164. package/dist/oauth-tokens/store.js.map +1 -1
  165. package/dist/observability/store.d.ts.map +1 -1
  166. package/dist/observability/store.js +72 -29
  167. package/dist/observability/store.js.map +1 -1
  168. package/dist/progress/store.d.ts.map +1 -1
  169. package/dist/progress/store.js +31 -16
  170. package/dist/progress/store.js.map +1 -1
  171. package/dist/provider-api/corpus-jobs-store.d.ts.map +1 -1
  172. package/dist/provider-api/corpus-jobs-store.js +16 -5
  173. package/dist/provider-api/corpus-jobs-store.js.map +1 -1
  174. package/dist/provider-api/custom-registry.d.ts.map +1 -1
  175. package/dist/provider-api/custom-registry.js +14 -4
  176. package/dist/provider-api/custom-registry.js.map +1 -1
  177. package/dist/provider-api/quota-governor.d.ts.map +1 -1
  178. package/dist/provider-api/quota-governor.js +12 -3
  179. package/dist/provider-api/quota-governor.js.map +1 -1
  180. package/dist/provider-api/staged-datasets-store.d.ts.map +1 -1
  181. package/dist/provider-api/staged-datasets-store.js +16 -5
  182. package/dist/provider-api/staged-datasets-store.js.map +1 -1
  183. package/dist/resources/store.d.ts.map +1 -1
  184. package/dist/resources/store.js +56 -25
  185. package/dist/resources/store.js.map +1 -1
  186. package/dist/secrets/storage.d.ts.map +1 -1
  187. package/dist/secrets/storage.js +10 -14
  188. package/dist/secrets/storage.js.map +1 -1
  189. package/dist/server/agent-teams-run-queue.d.ts.map +1 -1
  190. package/dist/server/agent-teams-run-queue.js +15 -4
  191. package/dist/server/agent-teams-run-queue.js.map +1 -1
  192. package/dist/server/auth.d.ts.map +1 -1
  193. package/dist/server/auth.js +16 -2
  194. package/dist/server/auth.js.map +1 -1
  195. package/dist/server/better-auth-instance.d.ts.map +1 -1
  196. package/dist/server/better-auth-instance.js +55 -21
  197. package/dist/server/better-auth-instance.js.map +1 -1
  198. package/dist/server/embed-session.d.ts.map +1 -1
  199. package/dist/server/embed-session.js +15 -4
  200. package/dist/server/embed-session.js.map +1 -1
  201. package/dist/server/identity-sso-store.d.ts.map +1 -1
  202. package/dist/server/identity-sso-store.js +30 -11
  203. package/dist/server/identity-sso-store.js.map +1 -1
  204. package/dist/server/recap-image-store.d.ts.map +1 -1
  205. package/dist/server/recap-image-store.js +21 -7
  206. package/dist/server/recap-image-store.js.map +1 -1
  207. package/dist/settings/store.d.ts.map +1 -1
  208. package/dist/settings/store.js +11 -13
  209. package/dist/settings/store.js.map +1 -1
  210. package/dist/usage/store.d.ts.map +1 -1
  211. package/dist/usage/store.js +36 -11
  212. package/dist/usage/store.js.map +1 -1
  213. package/dist/workspace-connections/store.d.ts.map +1 -1
  214. package/dist/workspace-connections/store.js +57 -7
  215. package/dist/workspace-connections/store.js.map +1 -1
  216. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  import { defineAction } from "@agent-native/core";
2
2
  import { writeAppState } from "@agent-native/core/application-state";
3
- import { assertAccess } from "@agent-native/core/sharing";
3
+ import { assertAccess, type Visibility } from "@agent-native/core/sharing";
4
4
  import { and, eq, sql } from "drizzle-orm";
5
5
  import { z } from "zod";
6
6
 
@@ -54,19 +54,17 @@ async function assertParentIsNotDescendant({
54
54
  }
55
55
  }
56
56
 
57
- async function clearBlockDatabaseOwnershipAfterParentChange({
57
+ async function preflightBlockDatabaseOwnershipClearance({
58
58
  db,
59
59
  documentId,
60
60
  ownerEmail,
61
61
  parentId,
62
- updatedAt,
63
62
  }: {
64
63
  db: ReturnType<typeof getDb>;
65
64
  documentId: string;
66
65
  ownerEmail: string;
67
66
  parentId: string | null;
68
- updatedAt: string;
69
- }) {
67
+ }): Promise<string | null> {
70
68
  const [database] = await db
71
69
  .select({
72
70
  id: schema.contentDatabases.id,
@@ -81,11 +79,24 @@ async function clearBlockDatabaseOwnershipAfterParentChange({
81
79
  );
82
80
 
83
81
  if (!database?.ownerDocumentId || database.ownerDocumentId === parentId) {
84
- return;
82
+ return null;
85
83
  }
86
84
 
87
85
  await assertAccess("document", database.ownerDocumentId, "editor");
86
+ return database.id;
87
+ }
88
88
 
89
+ async function clearBlockDatabaseOwnership({
90
+ db,
91
+ databaseId,
92
+ ownerEmail,
93
+ updatedAt,
94
+ }: {
95
+ db: Pick<ReturnType<typeof getDb>, "update">;
96
+ databaseId: string;
97
+ ownerEmail: string;
98
+ updatedAt: string;
99
+ }) {
89
100
  await db
90
101
  .update(schema.contentDatabases)
91
102
  .set({
@@ -95,23 +106,44 @@ async function clearBlockDatabaseOwnershipAfterParentChange({
95
106
  })
96
107
  .where(
97
108
  and(
98
- eq(schema.contentDatabases.id, database.id),
109
+ eq(schema.contentDatabases.id, databaseId),
99
110
  eq(schema.contentDatabases.ownerEmail, ownerEmail),
100
111
  ),
101
112
  );
102
113
  }
103
114
 
115
+ function sameRootSection(
116
+ left: { visibility: Visibility; orgId?: string | null },
117
+ right: { visibility: Visibility; orgId?: string | null },
118
+ ) {
119
+ return left.visibility === right.visibility && left.orgId === right.orgId;
120
+ }
121
+
122
+ function rootSectionFilter(document: {
123
+ visibility: Visibility;
124
+ orgId?: string | null;
125
+ }) {
126
+ return and(
127
+ eq(schema.documents.visibility, document.visibility),
128
+ document.orgId
129
+ ? eq(schema.documents.orgId, document.orgId)
130
+ : sql`${schema.documents.orgId} IS NULL`,
131
+ );
132
+ }
133
+
104
134
  async function resolveSiblingPositionsAfterMove({
105
135
  db,
106
136
  ownerEmail,
107
137
  id,
108
138
  parentId,
139
+ rootSection,
109
140
  position,
110
141
  }: {
111
142
  db: ReturnType<typeof getDb>;
112
143
  ownerEmail: string;
113
144
  id: string;
114
145
  parentId: string | null;
146
+ rootSection: { visibility: Visibility; orgId?: string | null };
115
147
  position: number;
116
148
  }) {
117
149
  const siblings = await db
@@ -129,6 +161,7 @@ async function resolveSiblingPositionsAfterMove({
129
161
  )
130
162
  : and(
131
163
  eq(schema.documents.ownerEmail, ownerEmail),
164
+ rootSectionFilter(rootSection),
132
165
  sql`parent_id IS NULL`,
133
166
  ),
134
167
  );
@@ -209,6 +242,9 @@ export default defineAction({
209
242
  if (parentAccess.resource.ownerEmail !== ownerEmail) {
210
243
  throw new Error("Parent document must belong to the same owner");
211
244
  }
245
+ if (!sameRootSection(parentAccess.resource, existing)) {
246
+ throw new Error("Parent document must be in the same section");
247
+ }
212
248
  await assertParentIsNotDescendant({
213
249
  db,
214
250
  ownerEmail,
@@ -221,6 +257,15 @@ export default defineAction({
221
257
 
222
258
  const targetParentId =
223
259
  args.parentId !== undefined ? args.parentId : existing.parentId;
260
+ const blockDatabaseIdToDetach =
261
+ args.parentId !== undefined
262
+ ? await preflightBlockDatabaseOwnershipClearance({
263
+ db,
264
+ documentId: id,
265
+ ownerEmail,
266
+ parentId: args.parentId,
267
+ })
268
+ : null;
224
269
  const normalizedSiblingPositions =
225
270
  args.position !== undefined
226
271
  ? await resolveSiblingPositionsAfterMove({
@@ -228,6 +273,7 @@ export default defineAction({
228
273
  ownerEmail,
229
274
  id,
230
275
  parentId: targetParentId,
276
+ rootSection: existing,
231
277
  position: args.position,
232
278
  })
233
279
  : null;
@@ -249,36 +295,36 @@ export default defineAction({
249
295
  )
250
296
  : and(
251
297
  eq(schema.documents.ownerEmail, ownerEmail),
298
+ rootSectionFilter(existing),
252
299
  sql`parent_id IS NULL`,
253
300
  ),
254
301
  );
255
302
  updates.position = (maxPos[0]?.max ?? -1) + 1;
256
303
  }
257
304
 
258
- await db
259
- .update(schema.documents)
260
- .set(updates)
261
- .where(
262
- and(
263
- eq(schema.documents.id, id),
264
- eq(schema.documents.ownerEmail, ownerEmail),
265
- ),
266
- );
305
+ await db.transaction(async (tx) => {
306
+ await tx
307
+ .update(schema.documents)
308
+ .set(updates)
309
+ .where(
310
+ and(
311
+ eq(schema.documents.id, id),
312
+ eq(schema.documents.ownerEmail, ownerEmail),
313
+ ),
314
+ );
267
315
 
268
- if (args.parentId !== undefined) {
269
- await clearBlockDatabaseOwnershipAfterParentChange({
270
- db,
271
- documentId: id,
272
- ownerEmail,
273
- parentId: args.parentId,
274
- updatedAt,
275
- });
276
- }
316
+ if (args.parentId !== undefined && blockDatabaseIdToDetach) {
317
+ await clearBlockDatabaseOwnership({
318
+ db: tx,
319
+ databaseId: blockDatabaseIdToDetach,
320
+ ownerEmail,
321
+ updatedAt,
322
+ });
323
+ }
277
324
 
278
- if (normalizedSiblingPositions) {
279
- await Promise.all(
280
- normalizedSiblingPositions.map((document) =>
281
- db
325
+ if (normalizedSiblingPositions) {
326
+ for (const document of normalizedSiblingPositions) {
327
+ await tx
282
328
  .update(schema.documents)
283
329
  .set({ position: document.position })
284
330
  .where(
@@ -286,10 +332,10 @@ export default defineAction({
286
332
  eq(schema.documents.id, document.id),
287
333
  eq(schema.documents.ownerEmail, ownerEmail),
288
334
  ),
289
- ),
290
- ),
291
- );
292
- }
335
+ );
336
+ }
337
+ }
338
+ });
293
339
 
294
340
  const [doc] = await db
295
341
  .select()
@@ -1,10 +1,37 @@
1
1
  import { defineAction } from "@agent-native/core";
2
2
  import { writeAppState } from "@agent-native/core/application-state";
3
+ import { resolveAccess } from "@agent-native/core/sharing";
3
4
  import { eq } from "drizzle-orm";
4
5
  import { z } from "zod";
5
6
 
6
7
  import { getDb, schema } from "../server/db/index.js";
7
- import { assertContentDatabaseLifecycleAccess } from "./_content-database-lifecycle.js";
8
+ import {
9
+ assertContentDatabaseLifecycleAccess,
10
+ collectInlineDatabaseOwnerBlockIds,
11
+ } from "./_content-database-lifecycle.js";
12
+ import pullDocumentAction from "./pull-document.js";
13
+
14
+ async function shouldClearStaleInlineOwnership(args: {
15
+ ownerDocumentId: string | null;
16
+ ownerBlockId: string | null;
17
+ }) {
18
+ if (!args.ownerDocumentId || !args.ownerBlockId) return false;
19
+ let content: string | null = null;
20
+ try {
21
+ const host = await pullDocumentAction.run({
22
+ id: args.ownerDocumentId,
23
+ format: "markdown",
24
+ });
25
+ content = String(host.content ?? "");
26
+ } catch {
27
+ const hostAccess = await resolveAccess("document", args.ownerDocumentId);
28
+ if (!hostAccess) return false;
29
+ content = String(hostAccess.resource.content ?? "");
30
+ }
31
+
32
+ const parsed = await collectInlineDatabaseOwnerBlockIds(content);
33
+ return parsed.ok && !parsed.ownerBlockIds.has(args.ownerBlockId);
34
+ }
8
35
 
9
36
  export default defineAction({
10
37
  description: "Restore a soft-deleted content database.",
@@ -12,13 +39,23 @@ export default defineAction({
12
39
  databaseId: z.string().describe("Content database ID"),
13
40
  }),
14
41
  run: async ({ databaseId }) => {
15
- await assertContentDatabaseLifecycleAccess(databaseId);
42
+ const ownership = await assertContentDatabaseLifecycleAccess(databaseId);
16
43
  const db = getDb();
17
44
  const now = new Date().toISOString();
45
+ const clearInlineOwnership = await shouldClearStaleInlineOwnership({
46
+ ownerDocumentId: ownership.database.ownerDocumentId,
47
+ ownerBlockId: ownership.database.ownerBlockId,
48
+ });
18
49
 
19
50
  await db
20
51
  .update(schema.contentDatabases)
21
- .set({ deletedAt: null, updatedAt: now })
52
+ .set({
53
+ deletedAt: null,
54
+ updatedAt: now,
55
+ ...(clearInlineOwnership
56
+ ? { ownerDocumentId: null, ownerBlockId: null }
57
+ : {}),
58
+ })
22
59
  .where(eq(schema.contentDatabases.id, databaseId));
23
60
 
24
61
  await writeAppState("refresh-signal", { ts: Date.now() });
@@ -11,10 +11,16 @@ import {
11
11
  IconH3,
12
12
  IconH4,
13
13
  } from "@tabler/icons-react";
14
- import { NodeSelection, type EditorState } from "@tiptap/pm/state";
14
+ import {
15
+ NodeSelection,
16
+ Plugin,
17
+ PluginKey,
18
+ type EditorState,
19
+ } from "@tiptap/pm/state";
20
+ import { Decoration, DecorationSet } from "@tiptap/pm/view";
15
21
  import type { Editor } from "@tiptap/react";
16
22
  import { BubbleMenu } from "@tiptap/react/menus";
17
- import { useState } from "react";
23
+ import { useEffect, useState } from "react";
18
24
 
19
25
  import {
20
26
  Tooltip,
@@ -44,6 +50,15 @@ const BUBBLE_TOOLBAR_EXCLUDED_NODE_TYPES = new Set([
44
50
  "localMdxComponent",
45
51
  ]);
46
52
 
53
+ type SelectionFillRange = {
54
+ from: number;
55
+ to: number;
56
+ };
57
+
58
+ const selectionFillPluginKey = new PluginKey<SelectionFillRange | null>(
59
+ "contentSelectionFill",
60
+ );
61
+
47
62
  function selectionIncludesBubbleToolbarExcludedNode(
48
63
  state: EditorState,
49
64
  from: number,
@@ -72,6 +87,73 @@ export function BubbleToolbar({ editor, onComment }: BubbleToolbarProps) {
72
87
  const [showLinkInput, setShowLinkInput] = useState(false);
73
88
  const [linkUrl, setLinkUrl] = useState("");
74
89
 
90
+ useEffect(() => {
91
+ const plugin = new Plugin<SelectionFillRange | null>({
92
+ key: selectionFillPluginKey,
93
+ state: {
94
+ init: () => null,
95
+ apply: (tr, value) => {
96
+ const meta = tr.getMeta(selectionFillPluginKey);
97
+ if (meta !== undefined) return meta;
98
+ return value
99
+ ? {
100
+ from: tr.mapping.map(value.from),
101
+ to: tr.mapping.map(value.to),
102
+ }
103
+ : null;
104
+ },
105
+ },
106
+ props: {
107
+ decorations(state) {
108
+ const range = selectionFillPluginKey.getState(state);
109
+ if (!range || range.from === range.to) return DecorationSet.empty;
110
+ return DecorationSet.create(state.doc, [
111
+ Decoration.inline(range.from, range.to, {
112
+ class: "notion-selection-fill",
113
+ }),
114
+ ]);
115
+ },
116
+ },
117
+ });
118
+
119
+ editor.registerPlugin(plugin);
120
+
121
+ const syncSelectionFill = () => {
122
+ const { state } = editor;
123
+ const { from, to } = state.selection;
124
+ const nextRange =
125
+ editor.isFocused &&
126
+ from !== to &&
127
+ !selectionIncludesBubbleToolbarExcludedNode(state, from, to)
128
+ ? { from, to }
129
+ : null;
130
+ const currentRange = selectionFillPluginKey.getState(state);
131
+ if (
132
+ currentRange?.from === nextRange?.from &&
133
+ currentRange?.to === nextRange?.to
134
+ ) {
135
+ return;
136
+ }
137
+ editor.view.dispatch(
138
+ state.tr
139
+ .setMeta(selectionFillPluginKey, nextRange)
140
+ .setMeta("addToHistory", false),
141
+ );
142
+ };
143
+
144
+ editor.on("selectionUpdate", syncSelectionFill);
145
+ editor.on("focus", syncSelectionFill);
146
+ editor.on("blur", syncSelectionFill);
147
+ syncSelectionFill();
148
+
149
+ return () => {
150
+ editor.off("selectionUpdate", syncSelectionFill);
151
+ editor.off("focus", syncSelectionFill);
152
+ editor.off("blur", syncSelectionFill);
153
+ editor.unregisterPlugin(selectionFillPluginKey);
154
+ };
155
+ }, [editor]);
156
+
75
157
  const handleSetLink = () => {
76
158
  if (linkUrl.trim()) {
77
159
  editor