@agent-native/core 0.101.7 → 0.101.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.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +28 -0
- package/corpus/core/docs/content/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/ar-SA/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/de-DE/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/es-ES/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/fr-FR/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/hi-IN/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/ja-JP/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/ko-KR/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/pt-BR/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/zh-CN/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/zh-TW/deployment.mdx +9 -7
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/client.ts +23 -1
- package/corpus/core/src/a2a/handlers.ts +65 -1
- package/corpus/core/src/a2a/server.ts +124 -0
- package/corpus/core/src/a2a/task-store.ts +253 -0
- package/corpus/core/src/a2a/types.ts +26 -0
- package/corpus/core/src/agent/production-agent.ts +5 -2
- package/corpus/core/src/client/review/ReviewCommentComposer.tsx +9 -1
- package/corpus/core/src/client/review/ReviewThreadPanel.tsx +17 -2
- package/corpus/core/src/client/settings/SettingsPanel.tsx +41 -21
- package/corpus/core/src/client/settings/useBuilderStatus.ts +28 -9
- package/corpus/core/src/client/setup-connections/BuilderConnectCard.tsx +2 -7
- package/corpus/core/src/mcp/builtin-tools.ts +25 -1
- package/corpus/core/src/scripts/call-agent.ts +22 -3
- package/corpus/core/src/server/agent-chat-plugin.ts +86 -1
- package/corpus/core/src/server/auth.ts +25 -1
- package/corpus/core/src/server/builder-browser.ts +353 -1
- package/corpus/core/src/server/core-routes-plugin.ts +601 -223
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +25 -0
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +80 -1
- package/corpus/templates/calendar/app/components/calendar/EventCard.tsx +28 -3
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +5 -1
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +30 -3
- package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +196 -0
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +115 -1
- package/corpus/templates/calendar/app/lib/out-of-office.ts +45 -0
- package/corpus/templates/calendar/changelog/2026-07-14-out-of-office-blocks-now-sit-behind-meetings-and-event-stack.md +6 -0
- package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +23 -0
- package/corpus/templates/content/AGENTS.md +3 -2
- package/corpus/templates/content/actions/_builder-cms-intent-lookup.ts +87 -0
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +173 -25
- package/corpus/templates/content/actions/_builder-cms-source-adapter.ts +1 -0
- package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +427 -18
- package/corpus/templates/content/actions/_builder-cms-write-client.ts +17 -73
- package/corpus/templates/content/actions/_builder-cms-write-settings.ts +27 -7
- package/corpus/templates/content/actions/_builder-source-execution-claim.ts +124 -0
- package/corpus/templates/content/actions/_builder-source-execution-preservation.ts +21 -0
- package/corpus/templates/content/actions/_builder-source-timings.ts +57 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +1041 -154
- package/corpus/templates/content/actions/_database-utils.ts +89 -12
- package/corpus/templates/content/actions/_preview-document-draft.ts +31 -0
- package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +309 -0
- package/corpus/templates/content/actions/execute-builder-source-batch.ts +120 -49
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +608 -264
- package/corpus/templates/content/actions/get-preview-document-draft.ts +26 -0
- package/corpus/templates/content/actions/materialize-builder-required-fields.ts +550 -0
- package/corpus/templates/content/actions/prepare-builder-source-execution.ts +112 -65
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +463 -170
- package/corpus/templates/content/actions/preview-builder-source-review.ts +99 -0
- package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +2 -2
- package/corpus/templates/content/actions/update-preview-document-draft.ts +153 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +27 -15
- package/corpus/templates/content/app/components/editor/MathRenderer.tsx +43 -0
- package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +260 -4
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +57 -5
- package/corpus/templates/content/app/components/editor/body-hydration.ts +27 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +2353 -576
- package/corpus/templates/content/app/components/editor/database/settings.tsx +13 -10
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +358 -75
- package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +78 -0
- package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +124 -29
- package/corpus/templates/content/app/components/editor/previewDocumentSaveRegistry.ts +2 -0
- package/corpus/templates/content/app/global.css +71 -1
- package/corpus/templates/content/app/hooks/use-content-database.ts +68 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +53 -4
- package/corpus/templates/content/app/i18n/zh-TW.ts +38 -0
- package/corpus/templates/content/app/i18n-data.ts +450 -0
- package/corpus/templates/content/app/root.tsx +2 -0
- package/corpus/templates/content/changelog/2026-07-10-builder-backed-preview-edits-are-preserved-when-article-bodi.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-builder-cms-sources-can-now-be-enabled-for-guarded-staged-or.md +6 -0
- package/corpus/templates/content/changelog/2026-07-13-builder-connection-setup-is-now-available-directly-from-conn.md +6 -0
- package/corpus/templates/content/changelog/2026-07-13-builder-reviews-now-hide-already-applied-writes-detect-nativ.md +6 -0
- package/corpus/templates/content/changelog/2026-07-13-required-builder-publishing-fields-can-now-be-added-directly.md +6 -0
- package/corpus/templates/content/changelog/2026-07-13-you-can-now-cancel-a-prepared-builder-update-safely-before-i.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-builder-account-connection-now-remains-available-when-branch.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-builder-backed-articles-now-preserve-fifth-and-sixth-level-h.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-builder-sources-now-review-and-publish-rich-article-updates-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-builder-writes-now-stop-retries-when-reconciliation-is-needed.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-file-and-media-links-now-validate-before-saving.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-latex-equations-render-in-documents-public-pages-and-exports.md +6 -0
- package/corpus/templates/content/package.json +1 -0
- package/corpus/templates/content/parity/matrix.md +27 -25
- package/corpus/templates/content/parity/matrix.ts +50 -2
- package/corpus/templates/content/server/db/schema.ts +47 -0
- package/corpus/templates/content/server/plugins/auth.ts +1 -0
- package/corpus/templates/content/server/plugins/db.ts +53 -0
- package/corpus/templates/content/shared/api.ts +70 -1
- package/corpus/templates/content/shared/builder-mdx.ts +705 -15
- package/corpus/templates/content/shared/document-export.ts +296 -25
- package/corpus/templates/content/shared/inline-math.ts +128 -0
- package/corpus/templates/content/shared/math-rendering.ts +50 -0
- package/corpus/templates/content/shared/nfm.ts +20 -17
- package/corpus/templates/content/vite.config.ts +0 -1
- package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +52 -7
- package/corpus/templates/design/app/components/design/ReviewCommentsPanel.tsx +36 -4
- package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +4 -1
- package/corpus/templates/design/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/design/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/design/app/i18n/en-US.ts +1 -0
- package/corpus/templates/design/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/design/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/design/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/design/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/design/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/design/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/design/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +8 -0
- package/corpus/templates/design/app/pages/design-editor/tool-state.ts +11 -0
- package/corpus/templates/design/changelog/2026-07-14-reviewers-can-now-pin-comments-from-the-canvas-toolbar-targe.md +6 -0
- package/corpus/templates/design/changelog/2026-07-15-viewer-comment-controls-now-sit-inside-the-read-only-notice-.md +6 -0
- package/corpus/templates/design/shared/review-anchor.ts +48 -0
- package/corpus/templates/mail/.agents/skills/email-drafts/SKILL.md +17 -0
- package/corpus/templates/mail/AGENTS.md +21 -19
- package/corpus/templates/mail/actions/create-attachment-upload.ts +49 -0
- package/corpus/templates/mail/changelog/2026-07-14-connected-agents-can-now-securely-upload-local-files-for-mai.md +6 -0
- package/corpus/templates/mail/server/handlers/media.ts +84 -61
- package/corpus/templates/mail/server/lib/attachment-upload-ticket.ts +234 -0
- package/corpus/templates/mail/server/lib/mail-connector-catalog.ts +8 -4
- package/corpus/templates/mail/server/lib/media-upload.ts +114 -0
- package/corpus/templates/mail/server/plugins/auth.ts +9 -1
- package/corpus/templates/mail/server/routes/api/media/attachment-upload/[uploadId].put.ts +1 -0
- package/corpus/templates/plan/server/plan-mdx.ts +53 -7
- package/dist/a2a/client.d.ts +5 -1
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +18 -1
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +57 -8
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/server.d.ts.map +1 -1
- package/dist/a2a/server.js +87 -1
- package/dist/a2a/server.js.map +1 -1
- package/dist/a2a/task-store.d.ts +27 -0
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/a2a/task-store.js +216 -0
- package/dist/a2a/task-store.js.map +1 -1
- package/dist/a2a/types.d.ts +24 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/agent/production-agent.d.ts +1 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +5 -2
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/client/review/ReviewCommentComposer.d.ts +2 -1
- package/dist/client/review/ReviewCommentComposer.d.ts.map +1 -1
- package/dist/client/review/ReviewCommentComposer.js +3 -3
- package/dist/client/review/ReviewCommentComposer.js.map +1 -1
- package/dist/client/review/ReviewThreadPanel.d.ts +9 -1
- package/dist/client/review/ReviewThreadPanel.d.ts.map +1 -1
- package/dist/client/review/ReviewThreadPanel.js +6 -4
- package/dist/client/review/ReviewThreadPanel.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts +3 -0
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +11 -4
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +8 -4
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +19 -6
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/setup-connections/BuilderConnectCard.d.ts.map +1 -1
- package/dist/client/setup-connections/BuilderConnectCard.js +2 -5
- package/dist/client/setup-connections/BuilderConnectCard.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +22 -3
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/scripts/call-agent.d.ts +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +19 -1
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +71 -2
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.d.ts +1 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +19 -2
- package/dist/server/auth.js.map +1 -1
- package/dist/server/builder-browser.d.ts +78 -0
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +246 -1
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +41 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +260 -14
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +25 -0
- package/docs/content/deployment.mdx +9 -7
- package/docs/content/locales/ar-SA/deployment.mdx +9 -7
- package/docs/content/locales/de-DE/deployment.mdx +9 -7
- package/docs/content/locales/es-ES/deployment.mdx +9 -7
- package/docs/content/locales/fr-FR/deployment.mdx +9 -7
- package/docs/content/locales/hi-IN/deployment.mdx +9 -7
- package/docs/content/locales/ja-JP/deployment.mdx +9 -7
- package/docs/content/locales/ko-KR/deployment.mdx +9 -7
- package/docs/content/locales/pt-BR/deployment.mdx +9 -7
- package/docs/content/locales/zh-CN/deployment.mdx +9 -7
- package/docs/content/locales/zh-TW/deployment.mdx +9 -7
- package/package.json +2 -2
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +25 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import { assertAccess } from "@agent-native/core/sharing";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
PreviewBuilderSourceReviewRequest,
|
|
7
|
+
PreviewBuilderSourceReviewResponse,
|
|
8
|
+
} from "../shared/api.js";
|
|
9
|
+
import {
|
|
10
|
+
getContentDatabaseSourceSnapshotForWrite,
|
|
11
|
+
resolveDatabaseForSourceMutation,
|
|
12
|
+
} from "./_database-source-utils.js";
|
|
13
|
+
import {
|
|
14
|
+
BUILDER_SOURCE_REVIEW_PREPARE_LIMIT,
|
|
15
|
+
buildBuilderSourceReviewPayload,
|
|
16
|
+
reviewPreparePriority,
|
|
17
|
+
withAuthoritativeBuilderTargetRows,
|
|
18
|
+
} from "./prepare-builder-source-review.js";
|
|
19
|
+
|
|
20
|
+
export default defineAction({
|
|
21
|
+
description:
|
|
22
|
+
"Preview complete Builder CMS review diffs, including document body changes, without approving or writing anything.",
|
|
23
|
+
schema: z.object({
|
|
24
|
+
databaseId: z.string().optional().describe("Database ID"),
|
|
25
|
+
documentId: z.string().optional().describe("Database document/page ID"),
|
|
26
|
+
sourceId: z.string().optional().describe("Specific Builder source ID"),
|
|
27
|
+
scope: z.enum(["selected", "all"]).optional().default("all"),
|
|
28
|
+
documentIds: z
|
|
29
|
+
.array(z.string())
|
|
30
|
+
.max(BUILDER_SOURCE_REVIEW_PREPARE_LIMIT)
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("Optional selected document IDs that bound the preview"),
|
|
33
|
+
}),
|
|
34
|
+
http: { method: "GET" },
|
|
35
|
+
readOnly: true,
|
|
36
|
+
run: async (
|
|
37
|
+
args: PreviewBuilderSourceReviewRequest,
|
|
38
|
+
): Promise<PreviewBuilderSourceReviewResponse> => {
|
|
39
|
+
const database = await resolveDatabaseForSourceMutation(args);
|
|
40
|
+
if (!database) throw new Error("Database not found.");
|
|
41
|
+
await assertAccess("document", database.documentId, "editor");
|
|
42
|
+
|
|
43
|
+
const source = await getContentDatabaseSourceSnapshotForWrite(
|
|
44
|
+
database,
|
|
45
|
+
args.sourceId,
|
|
46
|
+
);
|
|
47
|
+
if (!source || source.sourceType !== "builder-cms") {
|
|
48
|
+
throw new Error("Attach a Builder CMS source before reviewing updates.");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const selectedDocumentIds = new Set(args.documentIds ?? []);
|
|
52
|
+
if (args.scope === "selected" && selectedDocumentIds.size === 0) {
|
|
53
|
+
throw new Error("Select at least one Builder row before reviewing it.");
|
|
54
|
+
}
|
|
55
|
+
const allReviewableChanges = source.changeSets.filter((changeSet) => {
|
|
56
|
+
if (
|
|
57
|
+
changeSet.direction !== "outbound" ||
|
|
58
|
+
(changeSet.state !== "pending_push" &&
|
|
59
|
+
changeSet.state !== "staged_revision" &&
|
|
60
|
+
changeSet.state !== "approved")
|
|
61
|
+
) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
return (
|
|
65
|
+
args.scope === "all" ||
|
|
66
|
+
(!!changeSet.documentId &&
|
|
67
|
+
selectedDocumentIds.has(changeSet.documentId))
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
const changeSets = [...allReviewableChanges]
|
|
71
|
+
.sort(
|
|
72
|
+
(left, right) =>
|
|
73
|
+
reviewPreparePriority(left) - reviewPreparePriority(right),
|
|
74
|
+
)
|
|
75
|
+
.slice(0, BUILDER_SOURCE_REVIEW_PREPARE_LIMIT);
|
|
76
|
+
const authoritativeSource = await withAuthoritativeBuilderTargetRows({
|
|
77
|
+
source,
|
|
78
|
+
changeSets,
|
|
79
|
+
});
|
|
80
|
+
const review =
|
|
81
|
+
changeSets.length > 0
|
|
82
|
+
? buildBuilderSourceReviewPayload({
|
|
83
|
+
source: authoritativeSource,
|
|
84
|
+
changeSets,
|
|
85
|
+
})
|
|
86
|
+
: null;
|
|
87
|
+
if (review) {
|
|
88
|
+
review.totalRowCount = allReviewableChanges.length;
|
|
89
|
+
review.preparedRowLimit = changeSets.length;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
sourceId: source.id,
|
|
94
|
+
sourceTable: source.sourceTable,
|
|
95
|
+
changeSetIds: changeSets.map((changeSet) => changeSet.id),
|
|
96
|
+
review,
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
});
|
|
@@ -38,7 +38,7 @@ function executableWriteModes(
|
|
|
38
38
|
|
|
39
39
|
export default defineAction({
|
|
40
40
|
description:
|
|
41
|
-
"Set the tiered Builder CMS write mode for one source. Writes stay off by default and
|
|
41
|
+
"Set the tiered Builder CMS write mode for one source. Writes stay off by default and require document administrator access to enable or change.",
|
|
42
42
|
schema: z.object({
|
|
43
43
|
databaseId: z.string().optional().describe("Database ID"),
|
|
44
44
|
documentId: z.string().optional().describe("Database document/page ID"),
|
|
@@ -79,7 +79,7 @@ export default defineAction({
|
|
|
79
79
|
): Promise<ContentDatabaseResponse> => {
|
|
80
80
|
const database = await resolveDatabaseForSourceMutation(args);
|
|
81
81
|
if (!database) throw new Error("Database not found.");
|
|
82
|
-
await assertAccess("document", database.documentId, "
|
|
82
|
+
await assertAccess("document", database.documentId, "admin");
|
|
83
83
|
|
|
84
84
|
const db = getDb();
|
|
85
85
|
const source = await getExistingSourceForWrite(database.id, args.sourceId);
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import {
|
|
3
|
+
getRequestOrgId,
|
|
4
|
+
getRequestUserEmail,
|
|
5
|
+
} from "@agent-native/core/server";
|
|
6
|
+
import { assertAccess } from "@agent-native/core/sharing";
|
|
7
|
+
import { and, eq, sql } from "drizzle-orm";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
|
|
10
|
+
import { getDb, schema } from "../server/db/index.js";
|
|
11
|
+
import { readPreviewDocumentDraft } from "./_preview-document-draft.js";
|
|
12
|
+
|
|
13
|
+
const draftPayload = z.object({
|
|
14
|
+
title: z.string().max(10_000),
|
|
15
|
+
content: z.string().max(500_000),
|
|
16
|
+
baseDocumentUpdatedAt: z.string().max(100).nullable(),
|
|
17
|
+
loadedContentWasEmpty: z.boolean(),
|
|
18
|
+
deferredReason: z.enum(["hydration", "conflict"]).nullable(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
function draftId() {
|
|
22
|
+
return crypto.randomUUID();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default defineAction({
|
|
26
|
+
description:
|
|
27
|
+
"Atomically save or delete the current user's private preview draft.",
|
|
28
|
+
schema: z.discriminatedUnion("operation", [
|
|
29
|
+
z.object({
|
|
30
|
+
operation: z.literal("upsert"),
|
|
31
|
+
documentId: z.string().min(1),
|
|
32
|
+
expectedVersion: z.number().int().positive().nullable(),
|
|
33
|
+
draft: draftPayload,
|
|
34
|
+
}),
|
|
35
|
+
z.object({
|
|
36
|
+
operation: z.literal("delete"),
|
|
37
|
+
documentId: z.string().min(1),
|
|
38
|
+
expectedVersion: z.number().int().positive(),
|
|
39
|
+
expectedTitle: z.string().max(10_000),
|
|
40
|
+
expectedContent: z.string().max(500_000),
|
|
41
|
+
}),
|
|
42
|
+
]),
|
|
43
|
+
agentTool: false,
|
|
44
|
+
toolCallable: false,
|
|
45
|
+
run: async (args, ctx) => {
|
|
46
|
+
const userEmail = getRequestUserEmail();
|
|
47
|
+
const orgId = getRequestOrgId() ?? "";
|
|
48
|
+
if (!userEmail) throw new Error("Not authenticated.");
|
|
49
|
+
await assertAccess("document", args.documentId, "editor");
|
|
50
|
+
const db = getDb();
|
|
51
|
+
const ownerFilter = and(
|
|
52
|
+
eq(schema.documentPreviewDrafts.ownerEmail, userEmail),
|
|
53
|
+
eq(schema.documentPreviewDrafts.orgId, orgId),
|
|
54
|
+
eq(schema.documentPreviewDrafts.documentId, args.documentId),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (args.operation === "delete") {
|
|
58
|
+
const deleted = await db
|
|
59
|
+
.delete(schema.documentPreviewDrafts)
|
|
60
|
+
.where(
|
|
61
|
+
and(
|
|
62
|
+
ownerFilter,
|
|
63
|
+
eq(schema.documentPreviewDrafts.version, args.expectedVersion),
|
|
64
|
+
eq(schema.documentPreviewDrafts.title, args.expectedTitle),
|
|
65
|
+
eq(schema.documentPreviewDrafts.content, args.expectedContent),
|
|
66
|
+
),
|
|
67
|
+
)
|
|
68
|
+
.returning({ id: schema.documentPreviewDrafts.id });
|
|
69
|
+
if (deleted.length > 0)
|
|
70
|
+
return { status: "deleted" as const, draft: null };
|
|
71
|
+
return {
|
|
72
|
+
status: "conflict" as const,
|
|
73
|
+
draft: await readPreviewDocumentDraft(
|
|
74
|
+
userEmail,
|
|
75
|
+
orgId,
|
|
76
|
+
args.documentId,
|
|
77
|
+
),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const now = new Date().toISOString();
|
|
82
|
+
if (args.expectedVersion === null) {
|
|
83
|
+
const inserted = await db
|
|
84
|
+
.insert(schema.documentPreviewDrafts)
|
|
85
|
+
.values({
|
|
86
|
+
id: draftId(),
|
|
87
|
+
ownerEmail: userEmail,
|
|
88
|
+
orgId,
|
|
89
|
+
documentId: args.documentId,
|
|
90
|
+
title: args.draft.title,
|
|
91
|
+
content: args.draft.content,
|
|
92
|
+
baseDocumentUpdatedAt: args.draft.baseDocumentUpdatedAt,
|
|
93
|
+
loadedContentWasEmpty: args.draft.loadedContentWasEmpty ? 1 : 0,
|
|
94
|
+
deferredReason: args.draft.deferredReason,
|
|
95
|
+
version: 1,
|
|
96
|
+
createdAt: now,
|
|
97
|
+
updatedAt: now,
|
|
98
|
+
})
|
|
99
|
+
.onConflictDoNothing({
|
|
100
|
+
target: [
|
|
101
|
+
schema.documentPreviewDrafts.ownerEmail,
|
|
102
|
+
schema.documentPreviewDrafts.orgId,
|
|
103
|
+
schema.documentPreviewDrafts.documentId,
|
|
104
|
+
],
|
|
105
|
+
})
|
|
106
|
+
.returning({ version: schema.documentPreviewDrafts.version });
|
|
107
|
+
if (inserted.length > 0) {
|
|
108
|
+
return {
|
|
109
|
+
status: "saved" as const,
|
|
110
|
+
draft: await readPreviewDocumentDraft(
|
|
111
|
+
userEmail,
|
|
112
|
+
orgId,
|
|
113
|
+
args.documentId,
|
|
114
|
+
),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
const updated = await db
|
|
119
|
+
.update(schema.documentPreviewDrafts)
|
|
120
|
+
.set({
|
|
121
|
+
title: args.draft.title,
|
|
122
|
+
content: args.draft.content,
|
|
123
|
+
baseDocumentUpdatedAt: args.draft.baseDocumentUpdatedAt,
|
|
124
|
+
loadedContentWasEmpty: args.draft.loadedContentWasEmpty ? 1 : 0,
|
|
125
|
+
deferredReason: args.draft.deferredReason,
|
|
126
|
+
version: sql`${schema.documentPreviewDrafts.version} + 1`,
|
|
127
|
+
updatedAt: now,
|
|
128
|
+
})
|
|
129
|
+
.where(
|
|
130
|
+
and(
|
|
131
|
+
ownerFilter,
|
|
132
|
+
eq(schema.documentPreviewDrafts.version, args.expectedVersion),
|
|
133
|
+
),
|
|
134
|
+
)
|
|
135
|
+
.returning({ version: schema.documentPreviewDrafts.version });
|
|
136
|
+
if (updated.length > 0) {
|
|
137
|
+
return {
|
|
138
|
+
status: "saved" as const,
|
|
139
|
+
draft: await readPreviewDocumentDraft(
|
|
140
|
+
userEmail,
|
|
141
|
+
orgId,
|
|
142
|
+
args.documentId,
|
|
143
|
+
),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
status: "conflict" as const,
|
|
150
|
+
draft: await readPreviewDocumentDraft(userEmail, orgId, args.documentId),
|
|
151
|
+
};
|
|
152
|
+
},
|
|
153
|
+
});
|
|
@@ -489,6 +489,24 @@ export function filesMediaEditorValue(value: DocumentProperty["value"]) {
|
|
|
489
489
|
return filesMediaItems(value).join("\n");
|
|
490
490
|
}
|
|
491
491
|
|
|
492
|
+
export function isValidFilesMediaLink(value: string) {
|
|
493
|
+
try {
|
|
494
|
+
const url = new URL(value.trim());
|
|
495
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
496
|
+
} catch {
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
export function mergeFilesMediaItems(items: string[], pendingLink: string) {
|
|
502
|
+
const trimmed = pendingLink.trim();
|
|
503
|
+
if (!trimmed || !isValidFilesMediaLink(trimmed)) return items;
|
|
504
|
+
if (items.some((item) => item.toLowerCase() === trimmed.toLowerCase())) {
|
|
505
|
+
return items;
|
|
506
|
+
}
|
|
507
|
+
return [...items, trimmed];
|
|
508
|
+
}
|
|
509
|
+
|
|
492
510
|
export function filesMediaLabel(value: string) {
|
|
493
511
|
const trimmed = value.trim();
|
|
494
512
|
if (!trimmed) return "File";
|
|
@@ -2060,16 +2078,8 @@ function FilesMediaValueEditor({
|
|
|
2060
2078
|
}, []);
|
|
2061
2079
|
|
|
2062
2080
|
function addItem(value: string) {
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
setItems((current) => {
|
|
2066
|
-
if (
|
|
2067
|
-
current.some((item) => item.toLowerCase() === trimmed.toLowerCase())
|
|
2068
|
-
) {
|
|
2069
|
-
return current;
|
|
2070
|
-
}
|
|
2071
|
-
return [...current, trimmed];
|
|
2072
|
-
});
|
|
2081
|
+
if (!isValidFilesMediaLink(value)) return;
|
|
2082
|
+
setItems((current) => mergeFilesMediaItems(current, value));
|
|
2073
2083
|
setLinkValue("");
|
|
2074
2084
|
}
|
|
2075
2085
|
|
|
@@ -2126,11 +2136,11 @@ function FilesMediaValueEditor({
|
|
|
2126
2136
|
className="grid gap-3"
|
|
2127
2137
|
onSubmit={(event) => {
|
|
2128
2138
|
event.preventDefault();
|
|
2129
|
-
if (linkValue.trim()) {
|
|
2130
|
-
|
|
2139
|
+
if (linkValue.trim() && !isValidFilesMediaLink(linkValue)) {
|
|
2140
|
+
linkInputRef.current?.reportValidity();
|
|
2131
2141
|
return;
|
|
2132
2142
|
}
|
|
2133
|
-
void save();
|
|
2143
|
+
void save(mergeFilesMediaItems(items, linkValue));
|
|
2134
2144
|
}}
|
|
2135
2145
|
>
|
|
2136
2146
|
<div className="grid max-h-48 gap-1 overflow-auto">
|
|
@@ -2174,9 +2184,11 @@ function FilesMediaValueEditor({
|
|
|
2174
2184
|
<div className="flex gap-1">
|
|
2175
2185
|
<Input
|
|
2176
2186
|
ref={linkInputRef}
|
|
2177
|
-
aria-label={t("editor.properties.
|
|
2187
|
+
aria-label={t("editor.properties.editValue", {
|
|
2178
2188
|
name: property.definition.name,
|
|
2179
2189
|
})}
|
|
2190
|
+
type="url"
|
|
2191
|
+
pattern="[hH][tT][tT][pP][sS]?://.*"
|
|
2180
2192
|
value={linkValue}
|
|
2181
2193
|
placeholder={t("editor.properties.pasteFileOrMediaLink")}
|
|
2182
2194
|
onChange={(event) => setLinkValue(event.target.value)}
|
|
@@ -2193,7 +2205,7 @@ function FilesMediaValueEditor({
|
|
|
2193
2205
|
size="sm"
|
|
2194
2206
|
className="shrink-0"
|
|
2195
2207
|
onClick={() => addItem(linkValue)}
|
|
2196
|
-
disabled={!linkValue
|
|
2208
|
+
disabled={!isValidFilesMediaLink(linkValue) || mutation.isPending}
|
|
2197
2209
|
>
|
|
2198
2210
|
<IconPlus className="size-3.5" />
|
|
2199
2211
|
{t("editor.properties.add")}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { renderMathToHtml } from "@shared/math-rendering";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
|
|
4
|
+
interface MathRendererProps {
|
|
5
|
+
latex: string;
|
|
6
|
+
displayMode: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function MathRenderer({ latex, displayMode }: MathRendererProps) {
|
|
10
|
+
const rendered = useMemo(
|
|
11
|
+
() => renderMathToHtml(latex, displayMode),
|
|
12
|
+
[displayMode, latex],
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
if (!rendered.ok) {
|
|
16
|
+
return (
|
|
17
|
+
<code
|
|
18
|
+
className={
|
|
19
|
+
displayMode
|
|
20
|
+
? "content-math-error content-math-error--block"
|
|
21
|
+
: "content-math-error content-math-error--inline"
|
|
22
|
+
}
|
|
23
|
+
title={rendered.error}
|
|
24
|
+
>
|
|
25
|
+
{latex || "Empty equation"}
|
|
26
|
+
</code>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return displayMode ? (
|
|
31
|
+
<span
|
|
32
|
+
className="content-math content-math--block"
|
|
33
|
+
contentEditable={false}
|
|
34
|
+
dangerouslySetInnerHTML={{ __html: rendered.html }}
|
|
35
|
+
/>
|
|
36
|
+
) : (
|
|
37
|
+
<span
|
|
38
|
+
className="content-math content-math--inline"
|
|
39
|
+
contentEditable={false}
|
|
40
|
+
dangerouslySetInnerHTML={{ __html: rendered.html }}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|