@xopcai/xopc 0.0.222 → 0.0.224
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/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-NItGQmvR.js → activity-store--GBciH10.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DsR_2U9-.js → agent-avatar-dicebear-K7V4XXt7.js} +1 -1
- package/dist/gateway/static/root/assets/agents-BsxTpXyq.js +68 -0
- package/dist/gateway/static/root/assets/{api-53ZXsuyr.js → api-HoIz_ija.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BCzVX09V.js → app-management-settings-panel-xQCmkAHh.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DgSpwqQI.js → appearance-settings-BRoeA4kU.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BXgpBA8w.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-D8o8CP9Y.js → archive-plugin-CteCVsBP.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-BQHcAR6J.js → attachment-load-D7xNA2jB.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-CswK3HFb.js → automations-page-BD1vK7r5.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-wrgf-z7D.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-BlpyTJ1b.js → binary-plugins-C3DaJa0W.js} +1 -1
- package/dist/gateway/static/root/assets/block-editor-lTkcHTve.js +184 -0
- package/dist/gateway/static/root/assets/browser-settings-page-zhzNkeVG.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-Bi6RSSpD.js → browser-workflow-inputs-1UZ0vnIy.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-CZNOOQY4.js → browser-workflows-page-BHuJOF4M.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-DuCmg2Ej.js +7 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-pC2fno7r.js → capability-presets-api-yNqTIuyd.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DjiP3mQQ.js +3 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-B5Szgu_z.js → channel-recipient-api-krezGsKc.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-B4AtvQHk.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-DMxB7slL.js +1 -0
- package/dist/gateway/static/root/assets/{chat-terminal-dock-2fpzufzt.js → chat-terminal-dock-BRrL2iHA.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-fmda2NEP.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-VePLfPUR.js → cron-expression-Bl-2DzBQ.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-CJegmPTJ.js → date-picker-CxTl6Wlz.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-B2o9unBk.js → dependency-picker-DSl0mOPa.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-BH4Np-ay.js → desktop-pet-DTeCmCdb.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-Duu3ctxD.js → desktop-pet-settings-BNebxg0V.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-BBCUZOg2.js → directory-picker-path-field-Dn9XpmXY.js} +1 -1
- package/dist/gateway/static/root/assets/dist-DaxPZj9e.js +1 -0
- package/dist/gateway/static/root/assets/{dist-DY4Af0fY.js → dist-J_ySZvz0.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DS_o3F97.js → extension-debug-page-D-J-eOTb.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BTLBZdCq.js → extension-page-CpST24nU.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-KTGrYbgk.js → extension-settings-page-4nQXFnFq.js} +1 -1
- package/dist/gateway/static/root/assets/floating-ui.dom-B7uQOZZW.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-config-api-D3YJVfzY.js → gateway-config-api-BHWHduDi.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-BzTbnu4O.js → gateway-config-swr-yUxMMVjK.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-B8--s3yC.js → gateway-settings-BimMKmkM.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-B2zpkNvi.js → gateway-startup-retry-9mrsL84j.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-MUJ3mEC9.js +1 -0
- package/dist/gateway/static/root/assets/home-page-DSM6aPHF.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-BXRjz-iY.js → image-generation-api-CgFAGDi8.js} +1 -1
- package/dist/gateway/static/root/assets/index-B3zYJBhK.js +74 -0
- package/dist/gateway/static/root/assets/index-D3_xSYKd.css +2 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-D-Ib-suu.js → keyboard-shortcuts-settings-6Ar5rfX4.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-tzM0wTL8.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-Bsy1lvAc.js → local-apps-page-B5n-x544.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-iKjqemWG.js → locale-store-CPylQjH9.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-CgoQlera.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-D-akydG4.js → management-settings-CXBLyU-0.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-DHH4Cu2i.js → markdown-split-CtmQemJi.js} +1 -1
- package/dist/gateway/static/root/assets/markdown-view-CUsob4Pz.js +69 -0
- package/dist/gateway/static/root/assets/{media-plugins-BwHtUXkj.js → media-plugins-Dsd-IEOW.js} +1 -1
- package/dist/gateway/static/root/assets/messages-B82nsi9k.js +3 -0
- package/dist/gateway/static/root/assets/notes-api-CfKZYrBC.js +1 -0
- package/dist/gateway/static/root/assets/{notes-page-BxM1p6hz.js → notes-page-BKbOTE2n.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-BScELo01.js +4 -0
- package/dist/gateway/static/root/assets/oauth-authorization-window-Cdolr2wE.js +1 -0
- package/dist/gateway/static/root/assets/{popover-select-BzdnTy3h.js → popover-select-CccGri5Y.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-DrfWH1ir.js → product-open-page-DqB9bsDB.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DUoyty8X.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-PeXUdGdO.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-Cx3JxXSL.js → registry-api-B_5D8epF.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-sHho-uXP.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DF7syQRd.js → runtime-tools-settings-panel-DBTH_t0O.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-BQ_qRIsM.js → schema-form-CqMKAwV0.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DyvNgaP9.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-CnYf1R7z.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-BBHGOQHU.js → settings-form-section-dPriuuYq.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-CiwjP2-b.js → settings-loading-skeleton-B-Mbm8Va.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-Rl9waapk.js → settings-page-Dyj3w-Ml.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-C4FxY5J3.js +1 -0
- package/dist/gateway/static/root/assets/share-preview-page-emEdx7YL.js +2 -0
- package/dist/gateway/static/root/assets/shares-settings-BQBVq-sN.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-BFoEpQ4I.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-YbtR_zEU.js → skills-page-BNtYnrRT.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-DTmx2Zza.js → skills-page.utils-DjnbNFs5.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-BZDJcKdS.js → system-settings-panel-DDStf-jZ.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-ZVwr8KbS.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-BOD2D0dJ.js → theme-store-BN-32Fz5.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-Be9aR9qA.js → use-autosave-C2mKZ-ua.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-CHjIinCW.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-IMc3Ua6C.js → voice-api-key-field-D7OHeQby.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-TC-xQenr.js → work-discovery-overlay-CIiXie7F.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-B2auxcRv.js → workflow-run-setup-panel-9_dAGW3_.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-DXpYJxao.js +5 -0
- package/dist/gateway/static/root/index.html +15 -14
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-instance-gateway.d.ts +3 -0
- package/dist/src/agent/agent-manager.d.ts +3 -0
- package/dist/src/agent/agent-manager.js +30 -24
- package/dist/src/agent/embedded/index.d.ts +1 -1
- package/dist/src/agent/embedded/index.js +2 -2
- package/dist/src/agent/embedded/run-for-session.js +101 -62
- package/dist/src/agent/embedded/run-turn.js +56 -28
- package/dist/src/agent/embedded/runs.d.ts +16 -29
- package/dist/src/agent/embedded/runs.js +44 -65
- package/dist/src/agent/embedded/types.d.ts +4 -0
- package/dist/src/agent/orchestration/agent-run-supervisor.d.ts +28 -0
- package/dist/src/agent/orchestration/agent-run-supervisor.js +49 -0
- package/dist/src/agent/orchestration/agent-turn-policy.d.ts +18 -0
- package/dist/src/agent/orchestration/agent-turn-policy.js +36 -0
- package/dist/src/agent/orchestration/llm-turn-retry.d.ts +5 -0
- package/dist/src/agent/orchestration/llm-turn-retry.js +34 -4
- package/dist/src/agent/orchestration/run-agent-turn-with-timeout.d.ts +10 -1
- package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js +25 -4
- package/dist/src/agent/service/async-queue.d.ts +16 -3
- package/dist/src/agent/service/async-queue.js +29 -11
- package/dist/src/agent/service/process-direct-streaming.js +27 -4
- package/dist/src/agent/service.js +1 -0
- package/dist/src/agent/tools/exec-command.d.ts +2 -0
- package/dist/src/agent/tools/exec-command.js +70 -7
- package/dist/src/auth/oauth/index.js +3 -3
- package/dist/src/auth/oauth/registry.d.ts +2 -0
- package/dist/src/auth/oauth/registry.js +20 -12
- package/dist/src/auth/oauth/xopc-cloud.d.ts +1 -0
- package/dist/src/auth/oauth/xopc-cloud.js +32 -16
- package/dist/src/cli/commands/channels.js +1 -1
- package/dist/src/cli/commands/connectors.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/commands/tunnel.js +4 -5
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/schema.d.ts +18 -0
- package/dist/src/config/schema.js +19 -1
- package/dist/src/extensions/sdk/index.js +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/hono/app.js +2 -1
- package/dist/src/gateway/hono/oauth-async.d.ts +1 -0
- package/dist/src/gateway/hono/oauth-async.js +11 -4
- package/dist/src/gateway/hono/routes/config.js +10 -0
- package/dist/src/gateway/hono/routes/host-fs.js +40 -1
- package/dist/src/gateway/hono/routes/media.js +33 -1
- package/dist/src/gateway/hono/routes/notes.js +162 -7
- package/dist/src/gateway/hono/routes/shares.js +141 -6
- package/dist/src/gateway/hono/routes/tunnel.js +47 -10
- package/dist/src/gateway/hono/routes/voice.d.ts +2 -6
- package/dist/src/gateway/hono/routes/voice.js +20 -4
- package/dist/src/gateway/hono/routes/workflows.js +2 -2
- package/dist/src/gateway/run-loop.js +3 -0
- package/dist/src/gateway/server.d.ts +3 -0
- package/dist/src/gateway/server.js +30 -5
- package/dist/src/gateway/service.js +4 -4
- package/dist/src/notes/service.d.ts +6 -2
- package/dist/src/notes/service.js +36 -4
- package/dist/src/providers/index.js +2 -2
- package/dist/src/share/note-share-service.d.ts +67 -0
- package/dist/src/share/note-share-service.js +283 -0
- package/dist/src/share/share-config.js +32 -3
- package/dist/src/share/share-landing.d.ts +5 -1
- package/dist/src/share/share-landing.js +28 -1
- package/dist/src/share/share-store.d.ts +34 -5
- package/dist/src/share/share-store.js +125 -19
- package/dist/src/share/share-thumbnail.js +4 -2
- package/dist/src/share/share-types.d.ts +52 -14
- package/dist/src/share/share-types.js +9 -0
- package/dist/src/share/share-zip.d.ts +2 -2
- package/dist/src/tui/backends/embedded-backend.js +1 -1
- package/dist/src/tunnel/env.d.ts +12 -6
- package/dist/src/tunnel/env.js +34 -26
- package/dist/src/tunnel/gateway-lifecycle.js +2 -13
- package/dist/src/tunnel/index.d.ts +1 -1
- package/dist/src/tunnel/index.js +2 -2
- package/dist/src/tunnel/tunnel-audit.d.ts +1 -1
- package/dist/src/tunnel/tunnel-config.d.ts +1 -1
- package/dist/src/tunnel/tunnel-config.js +9 -4
- package/dist/src/tunnel/tunnel-service.d.ts +1 -1
- package/dist/src/tunnel/tunnel-service.js +3 -0
- package/dist/src/tunnel/well-known.d.ts +1 -1
- package/dist/src/tunnel/well-known.js +1 -1
- package/dist/src/tunnel/xopc-cloud-registration.d.ts +9 -0
- package/dist/src/tunnel/xopc-cloud-registration.js +42 -0
- package/dist/src/voice/stt/transcribe-core.js +17 -1
- package/dist/src/voice/stt/types.d.ts +1 -1
- package/package.json +2 -2
- package/dist/gateway/static/root/assets/agents-DijFbC4G.js +0 -68
- package/dist/gateway/static/root/assets/apps-page-BFAmf9hq.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-B8us5JBf.js +0 -6
- package/dist/gateway/static/root/assets/block-editor-C3mwGsms.js +0 -184
- package/dist/gateway/static/root/assets/browser-settings-page-BeBd17-3.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-Bv0z3KRq.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-BczD-pWE.js +0 -3
- package/dist/gateway/static/root/assets/channels-settings-2KQYq6xl.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-ByRbxC6z.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-PB1boaNy.js +0 -2
- package/dist/gateway/static/root/assets/dist-C230izr8.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-5YQ5BUwp.js +0 -1
- package/dist/gateway/static/root/assets/home-page-DfIVWJl3.js +0 -1
- package/dist/gateway/static/root/assets/index-BXGC3VFm.css +0 -2
- package/dist/gateway/static/root/assets/index-jqDCfet4.js +0 -74
- package/dist/gateway/static/root/assets/local-app-workbench-page-CAb0odzu.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-CFxKbDZl.js +0 -2
- package/dist/gateway/static/root/assets/markdown-view-DYkxMtJA.js +0 -69
- package/dist/gateway/static/root/assets/messages-kx5W39dO.js +0 -3
- package/dist/gateway/static/root/assets/notes-api-DJizatxh.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-BGjEC89c.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-Dj9kEQwg.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-CBRy5Ezz.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DSwz9RBh.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-WtattyVX.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CNAz_q1F.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-CNo4Ajhn.js +0 -1
- package/dist/gateway/static/root/assets/share-preview-page-B7PI3yZ6.js +0 -2
- package/dist/gateway/static/root/assets/shares-settings-DpOH0zWB.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BOf4xCat.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-DrMX5Yhj.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-ewIK2ddC.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-Bdn82kFQ.js +0 -5
|
@@ -19,6 +19,15 @@ const ShareThumbnailPatchSchema = z.object({
|
|
|
19
19
|
failureCooldownMs: z.number().int().min(0).max(36e5).optional(),
|
|
20
20
|
internalGatewayUrl: z.string().min(1).optional()
|
|
21
21
|
});
|
|
22
|
+
const ShareNotePatchSchema = z.object({
|
|
23
|
+
enabled: z.boolean().optional(),
|
|
24
|
+
maxMarkdownBytes: z.number().int().min(1024).max(10485760).optional(),
|
|
25
|
+
maxAttachmentCount: z.number().int().min(0).max(500).optional(),
|
|
26
|
+
maxAttachmentSize: z.number().int().min(1024).max(1073741824).optional(),
|
|
27
|
+
maxTotalSize: z.number().int().min(1024).max(2147483648).optional(),
|
|
28
|
+
assetTicketTtlMs: z.number().int().min(6e4).max(36e5).optional(),
|
|
29
|
+
revokeOnSourceDelete: z.boolean().optional()
|
|
30
|
+
});
|
|
22
31
|
const ShareConfigPatchSchema = z.object({
|
|
23
32
|
enabled: z.boolean().optional(),
|
|
24
33
|
defaultTtlMs: z.number().int().min(6e4).max(6048e5).optional(),
|
|
@@ -27,7 +36,8 @@ const ShareConfigPatchSchema = z.object({
|
|
|
27
36
|
maxFileSize: z.number().int().min(1048576).max(10737418240).optional(),
|
|
28
37
|
inlinePreviewMimes: z.array(z.string().min(1)).optional(),
|
|
29
38
|
directory: ShareDirectoryPatchSchema.optional(),
|
|
30
|
-
thumbnail: ShareThumbnailPatchSchema.optional()
|
|
39
|
+
thumbnail: ShareThumbnailPatchSchema.optional(),
|
|
40
|
+
note: ShareNotePatchSchema.optional()
|
|
31
41
|
});
|
|
32
42
|
function resolveDirectoryConfig(raw) {
|
|
33
43
|
const base = SHARE_CONFIG_DEFAULTS.directory;
|
|
@@ -57,6 +67,20 @@ function resolveThumbnailConfig(raw) {
|
|
|
57
67
|
internalGatewayUrl: patch.internalGatewayUrl ?? base.internalGatewayUrl
|
|
58
68
|
};
|
|
59
69
|
}
|
|
70
|
+
function resolveNoteConfig(raw) {
|
|
71
|
+
const base = SHARE_CONFIG_DEFAULTS.note;
|
|
72
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return { ...base };
|
|
73
|
+
const patch = raw;
|
|
74
|
+
return {
|
|
75
|
+
enabled: patch.enabled ?? base.enabled,
|
|
76
|
+
maxMarkdownBytes: patch.maxMarkdownBytes ?? base.maxMarkdownBytes,
|
|
77
|
+
maxAttachmentCount: patch.maxAttachmentCount ?? base.maxAttachmentCount,
|
|
78
|
+
maxAttachmentSize: patch.maxAttachmentSize ?? base.maxAttachmentSize,
|
|
79
|
+
maxTotalSize: patch.maxTotalSize ?? base.maxTotalSize,
|
|
80
|
+
assetTicketTtlMs: patch.assetTicketTtlMs ?? base.assetTicketTtlMs,
|
|
81
|
+
revokeOnSourceDelete: patch.revokeOnSourceDelete ?? base.revokeOnSourceDelete
|
|
82
|
+
};
|
|
83
|
+
}
|
|
60
84
|
function resolveShareConfig(raw) {
|
|
61
85
|
const patch = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
62
86
|
return {
|
|
@@ -67,7 +91,8 @@ function resolveShareConfig(raw) {
|
|
|
67
91
|
maxFileSize: patch.maxFileSize ?? SHARE_CONFIG_DEFAULTS.maxFileSize,
|
|
68
92
|
inlinePreviewMimes: Array.isArray(patch.inlinePreviewMimes) ? patch.inlinePreviewMimes.filter((x) => typeof x === "string" && x.trim().length > 0) : [...SHARE_CONFIG_DEFAULTS.inlinePreviewMimes],
|
|
69
93
|
directory: resolveDirectoryConfig(patch.directory),
|
|
70
|
-
thumbnail: resolveThumbnailConfig(patch.thumbnail)
|
|
94
|
+
thumbnail: resolveThumbnailConfig(patch.thumbnail),
|
|
95
|
+
note: resolveNoteConfig(patch.note)
|
|
71
96
|
};
|
|
72
97
|
}
|
|
73
98
|
function mergeShareConfigPatch(config, patch) {
|
|
@@ -99,7 +124,11 @@ function mergeShareConfigPatch(config, patch) {
|
|
|
99
124
|
thumbnail: parsed.data.thumbnail ? {
|
|
100
125
|
...current.thumbnail,
|
|
101
126
|
...parsed.data.thumbnail
|
|
102
|
-
} : current.thumbnail
|
|
127
|
+
} : current.thumbnail,
|
|
128
|
+
note: parsed.data.note ? {
|
|
129
|
+
...current.note,
|
|
130
|
+
...parsed.data.note
|
|
131
|
+
} : current.note
|
|
103
132
|
};
|
|
104
133
|
if (next.defaultTtlMs > next.maxTtlMs) return {
|
|
105
134
|
ok: false,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DirectoryListing } from './share-store.js';
|
|
2
|
-
import type { ShareRecord } from './share-types.js';
|
|
2
|
+
import type { NoteShareRecord, ShareRecord } from './share-types.js';
|
|
3
3
|
export interface ShareLandingOgOptions {
|
|
4
4
|
/** Absolute https/http URL of this landing page (for og:url). Omit if non-public. */
|
|
5
5
|
absoluteShareUrl?: string | null;
|
|
@@ -10,6 +10,10 @@ export interface ShareLandingOgOptions {
|
|
|
10
10
|
/** Description override (default: type + size). */
|
|
11
11
|
description?: string;
|
|
12
12
|
}
|
|
13
|
+
/** Lightweight public shell for Note shares. Crawlers get metadata; browsers continue to the SPA preview. */
|
|
14
|
+
export declare function renderNoteShareLandingPage(record: NoteShareRecord, previewUrl: string, options?: {
|
|
15
|
+
og?: ShareLandingOgOptions;
|
|
16
|
+
}): string;
|
|
13
17
|
/** Render the file download confirmation landing page (does not consume downloadCount). */
|
|
14
18
|
export declare function renderShareLandingPage(record: ShareRecord, downloadPath: string, options?: {
|
|
15
19
|
/** Path to open the file inline (?inline=1) for browser-native rendering. */
|
|
@@ -35,6 +35,33 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;b
|
|
|
35
35
|
.empty{text-align:center;color:#94a3b8;padding:2rem}
|
|
36
36
|
`;
|
|
37
37
|
}
|
|
38
|
+
/** Lightweight public shell for Note shares. Crawlers get metadata; browsers continue to the SPA preview. */
|
|
39
|
+
function renderNoteShareLandingPage(record, previewUrl, options) {
|
|
40
|
+
const title = escapeHtml(record.fileName);
|
|
41
|
+
const description = escapeHtml(record.description ?? "A Note shared via xopc");
|
|
42
|
+
const target = escapeHtml(previewUrl);
|
|
43
|
+
return `<!DOCTYPE html>
|
|
44
|
+
<html lang="zh">
|
|
45
|
+
<head>
|
|
46
|
+
<meta charset="utf-8">
|
|
47
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
48
|
+
<meta name="referrer" content="no-referrer">
|
|
49
|
+
<meta name="robots" content="noindex,nofollow">
|
|
50
|
+
${renderOgTags({
|
|
51
|
+
title,
|
|
52
|
+
description,
|
|
53
|
+
url: options?.og?.absoluteShareUrl ?? null,
|
|
54
|
+
image: options?.og?.absoluteThumbnailUrl ?? null
|
|
55
|
+
})}
|
|
56
|
+
<title>${title} — xopc Share</title>
|
|
57
|
+
<meta http-equiv="refresh" content="0;url=${target}">
|
|
58
|
+
</head>
|
|
59
|
+
<body>
|
|
60
|
+
<p><a href="${target}">Open shared Note</a></p>
|
|
61
|
+
<script>location.replace(${JSON.stringify(previewUrl)})<\/script>
|
|
62
|
+
</body>
|
|
63
|
+
</html>`;
|
|
64
|
+
}
|
|
38
65
|
/** Render the file download confirmation landing page (does not consume downloadCount). */
|
|
39
66
|
function renderShareLandingPage(record, downloadPath, options) {
|
|
40
67
|
const fileName = escapeHtml(record.fileName);
|
|
@@ -212,4 +239,4 @@ function renderShareExpiredPage(reason) {
|
|
|
212
239
|
</html>`;
|
|
213
240
|
}
|
|
214
241
|
//#endregion
|
|
215
|
-
export { renderFolderLandingPage, renderShareExpiredPage, renderShareLandingPage };
|
|
242
|
+
export { renderFolderLandingPage, renderNoteShareLandingPage, renderShareExpiredPage, renderShareLandingPage };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ShareRecord, ShareConfig, CreateShareParams } from './share-types.js';
|
|
1
|
+
import type { ShareRecord, ShareConfig, CreateShareParams, WorkspaceShareRecord, NoteShareRecord, DirectoryShareRecord } from './share-types.js';
|
|
2
2
|
export interface DirectoryListingEntry {
|
|
3
3
|
name: string;
|
|
4
4
|
/** Workspace/share-relative POSIX path. */
|
|
@@ -32,10 +32,31 @@ export declare class ShareStore {
|
|
|
32
32
|
create(params: CreateShareParams & {
|
|
33
33
|
workspaceRoot: string;
|
|
34
34
|
gatewayTokenHash: string;
|
|
35
|
-
}): Promise<
|
|
35
|
+
}): Promise<WorkspaceShareRecord>;
|
|
36
36
|
private createFileShare;
|
|
37
37
|
private createDirectoryShare;
|
|
38
38
|
private buildRecord;
|
|
39
|
+
createNoteShare(input: {
|
|
40
|
+
id: string;
|
|
41
|
+
sourceNoteId: string;
|
|
42
|
+
sourceVersion: number;
|
|
43
|
+
artifactRelativePath: string;
|
|
44
|
+
artifactSize: number;
|
|
45
|
+
attachmentCount: number;
|
|
46
|
+
snapshotRevision?: number;
|
|
47
|
+
fileName: string;
|
|
48
|
+
ttlMs?: number;
|
|
49
|
+
maxViews?: number | null;
|
|
50
|
+
description?: string;
|
|
51
|
+
gatewayTokenHash: string;
|
|
52
|
+
}): NoteShareRecord;
|
|
53
|
+
updateNoteSnapshot(id: string, patch: {
|
|
54
|
+
sourceVersion: number;
|
|
55
|
+
artifactSize: number;
|
|
56
|
+
attachmentCount: number;
|
|
57
|
+
fileName: string;
|
|
58
|
+
}): NoteShareRecord | null;
|
|
59
|
+
getNoteShares(noteId: string): NoteShareRecord[];
|
|
39
60
|
private persistAndAudit;
|
|
40
61
|
getById(id: string): ShareRecord | null;
|
|
41
62
|
getByToken(token: string): ShareRecord | null;
|
|
@@ -46,8 +67,15 @@ export declare class ShareStore {
|
|
|
46
67
|
};
|
|
47
68
|
/** Increment download counter (used by directory & file downloads). Debounced persist. */
|
|
48
69
|
incrementDownloadCount(id: string): void;
|
|
70
|
+
/** Atomically validate and consume one access in the single-threaded store. */
|
|
71
|
+
consumeAccess(id: string): {
|
|
72
|
+
valid: true;
|
|
73
|
+
} | {
|
|
74
|
+
valid: false;
|
|
75
|
+
reason: string;
|
|
76
|
+
};
|
|
49
77
|
/** Check if the file still exists and inode matches. */
|
|
50
|
-
validateFileIntegrity(record:
|
|
78
|
+
validateFileIntegrity(record: WorkspaceShareRecord): Promise<{
|
|
51
79
|
valid: boolean;
|
|
52
80
|
reason?: string;
|
|
53
81
|
}>;
|
|
@@ -55,7 +83,7 @@ export declare class ShareStore {
|
|
|
55
83
|
* Resolve a child path inside a directory share. Returns the absolute path
|
|
56
84
|
* if it stays within both the share root and the workspace.
|
|
57
85
|
*/
|
|
58
|
-
resolveDirectoryChild(record:
|
|
86
|
+
resolveDirectoryChild(record: DirectoryShareRecord, relativePath: string): Promise<{
|
|
59
87
|
ok: true;
|
|
60
88
|
absolutePath: string;
|
|
61
89
|
} | {
|
|
@@ -63,7 +91,7 @@ export declare class ShareStore {
|
|
|
63
91
|
reason: string;
|
|
64
92
|
}>;
|
|
65
93
|
/** List a single directory level (cached, share-root-relative). */
|
|
66
|
-
listDirectory(record:
|
|
94
|
+
listDirectory(record: DirectoryShareRecord, relativePath: string): Promise<DirectoryListing>;
|
|
67
95
|
/** Update thumbnail status. Persists immediately so generator restart is safe. */
|
|
68
96
|
setThumbnailStatus(id: string, status: 'pending' | 'ready' | 'failed'): void;
|
|
69
97
|
/** Drop the listing cache for a share (used on revoke/update). */
|
|
@@ -84,6 +112,7 @@ export declare class ShareStore {
|
|
|
84
112
|
private cleanupExpired;
|
|
85
113
|
shutdown(): void;
|
|
86
114
|
private resolveAndValidatePath;
|
|
115
|
+
private cleanupNoteArtifact;
|
|
87
116
|
}
|
|
88
117
|
export declare function resolveMimeType(fileName: string): string;
|
|
89
118
|
/** HTTP Content-Type with charset for text-like bodies (browser inline preview). */
|
|
@@ -8,7 +8,7 @@ import { logShareAudit } from "./share-audit.js";
|
|
|
8
8
|
import { join, relative, resolve } from "node:path";
|
|
9
9
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
10
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
11
|
-
import { lstat, readdir, realpath, stat } from "node:fs/promises";
|
|
11
|
+
import { lstat, readdir, realpath, rm, stat } from "node:fs/promises";
|
|
12
12
|
//#region src/share/share-store.ts
|
|
13
13
|
init_paths();
|
|
14
14
|
init_logger();
|
|
@@ -166,14 +166,13 @@ var ShareStore = class {
|
|
|
166
166
|
const id = randomUUID();
|
|
167
167
|
const token = randomBytes(32).toString("base64url");
|
|
168
168
|
const now = /* @__PURE__ */ new Date();
|
|
169
|
-
const
|
|
169
|
+
const common = {
|
|
170
170
|
id,
|
|
171
171
|
token,
|
|
172
172
|
absolutePath: input.absolutePath,
|
|
173
173
|
workspaceRelativePath: input.workspaceRelativePath,
|
|
174
174
|
workspaceRoot: input.workspaceRoot,
|
|
175
175
|
inode: input.inode,
|
|
176
|
-
kind: input.kind,
|
|
177
176
|
fileName: input.fileName,
|
|
178
177
|
fileSize: input.fileSize,
|
|
179
178
|
mimeType: input.mimeType,
|
|
@@ -183,13 +182,78 @@ var ShareStore = class {
|
|
|
183
182
|
downloadCount: 0,
|
|
184
183
|
revoked: false,
|
|
185
184
|
createdByTokenHash: input.gatewayTokenHash,
|
|
186
|
-
description: input.description
|
|
185
|
+
description: input.description
|
|
186
|
+
};
|
|
187
|
+
const record = input.kind === "directory" ? {
|
|
188
|
+
...common,
|
|
189
|
+
kind: "directory",
|
|
187
190
|
directory: input.directory
|
|
191
|
+
} : {
|
|
192
|
+
...common,
|
|
193
|
+
kind: "file"
|
|
188
194
|
};
|
|
189
195
|
this.shares.set(id, record);
|
|
190
196
|
this.tokenIndex.set(token, id);
|
|
191
197
|
return record;
|
|
192
198
|
}
|
|
199
|
+
createNoteShare(input) {
|
|
200
|
+
if (!this.config.enabled || !this.config.note.enabled) throw new Error("Note sharing is disabled");
|
|
201
|
+
if (this.getActiveShares().length >= this.config.maxActiveShares) throw new Error(`Maximum active shares reached (${this.config.maxActiveShares})`);
|
|
202
|
+
const ttlMs = input.ttlMs ?? this.config.defaultTtlMs;
|
|
203
|
+
if (ttlMs < 6e4 || ttlMs > this.config.maxTtlMs) throw new Error(`TTL must be between 60s and ${this.config.maxTtlMs / 1e3}s`);
|
|
204
|
+
if (input.maxViews !== void 0 && input.maxViews !== null && (input.maxViews < 1 || input.maxViews > 1e3)) throw new Error("maxViews must be between 1 and 1000");
|
|
205
|
+
const now = /* @__PURE__ */ new Date();
|
|
206
|
+
const record = {
|
|
207
|
+
id: input.id,
|
|
208
|
+
token: randomBytes(32).toString("base64url"),
|
|
209
|
+
kind: "note",
|
|
210
|
+
fileName: input.fileName,
|
|
211
|
+
fileSize: input.artifactSize,
|
|
212
|
+
mimeType: "application/x-xopc-note",
|
|
213
|
+
workspaceRelativePath: "",
|
|
214
|
+
sourceNoteId: input.sourceNoteId,
|
|
215
|
+
sourceVersion: input.sourceVersion,
|
|
216
|
+
artifactRelativePath: input.artifactRelativePath,
|
|
217
|
+
attachmentCount: input.attachmentCount,
|
|
218
|
+
snapshotRevision: input.snapshotRevision ?? 1,
|
|
219
|
+
assetTicketSecret: randomBytes(32).toString("base64url"),
|
|
220
|
+
createdAt: now.toISOString(),
|
|
221
|
+
expiresAt: new Date(now.getTime() + ttlMs).toISOString(),
|
|
222
|
+
maxViews: input.maxViews ?? null,
|
|
223
|
+
downloadCount: 0,
|
|
224
|
+
revoked: false,
|
|
225
|
+
createdByTokenHash: input.gatewayTokenHash,
|
|
226
|
+
description: input.description
|
|
227
|
+
};
|
|
228
|
+
this.shares.set(record.id, record);
|
|
229
|
+
this.tokenIndex.set(record.token, record.id);
|
|
230
|
+
this.persistAndAudit(record, "share.create", `Note share created: ${record.fileName}`, {
|
|
231
|
+
noteId: record.sourceNoteId,
|
|
232
|
+
sourceVersion: record.sourceVersion,
|
|
233
|
+
attachmentCount: record.attachmentCount,
|
|
234
|
+
ttlMs
|
|
235
|
+
});
|
|
236
|
+
return record;
|
|
237
|
+
}
|
|
238
|
+
updateNoteSnapshot(id, patch) {
|
|
239
|
+
const record = this.shares.get(id);
|
|
240
|
+
if (!record || record.kind !== "note") return null;
|
|
241
|
+
record.sourceVersion = patch.sourceVersion;
|
|
242
|
+
record.fileSize = patch.artifactSize;
|
|
243
|
+
record.attachmentCount = patch.attachmentCount;
|
|
244
|
+
record.fileName = patch.fileName;
|
|
245
|
+
record.snapshotRevision += 1;
|
|
246
|
+
this.persistSync();
|
|
247
|
+
logShareAudit("share.update", {
|
|
248
|
+
shareId: id,
|
|
249
|
+
noteId: record.sourceNoteId,
|
|
250
|
+
snapshotRevision: record.snapshotRevision
|
|
251
|
+
}, `Note share snapshot updated: ${record.fileName}`);
|
|
252
|
+
return record;
|
|
253
|
+
}
|
|
254
|
+
getNoteShares(noteId) {
|
|
255
|
+
return this.getAllShares().filter((record) => record.kind === "note" && record.sourceNoteId === noteId);
|
|
256
|
+
}
|
|
193
257
|
persistAndAudit(record, event, message, extra) {
|
|
194
258
|
this.persistSync();
|
|
195
259
|
logShareAudit(event, {
|
|
@@ -229,6 +293,22 @@ var ShareStore = class {
|
|
|
229
293
|
record.downloadCount++;
|
|
230
294
|
this.scheduleDebouncedPersist();
|
|
231
295
|
}
|
|
296
|
+
/** Atomically validate and consume one access in the single-threaded store. */
|
|
297
|
+
consumeAccess(id) {
|
|
298
|
+
const record = this.shares.get(id);
|
|
299
|
+
if (!record) return {
|
|
300
|
+
valid: false,
|
|
301
|
+
reason: "not_found"
|
|
302
|
+
};
|
|
303
|
+
const validation = this.validateAccess(record);
|
|
304
|
+
if (!validation.valid) return {
|
|
305
|
+
valid: false,
|
|
306
|
+
reason: validation.reason ?? "access_denied"
|
|
307
|
+
};
|
|
308
|
+
record.downloadCount++;
|
|
309
|
+
this.scheduleDebouncedPersist();
|
|
310
|
+
return { valid: true };
|
|
311
|
+
}
|
|
232
312
|
/** Check if the file still exists and inode matches. */
|
|
233
313
|
async validateFileIntegrity(record) {
|
|
234
314
|
try {
|
|
@@ -302,7 +382,6 @@ var ShareStore = class {
|
|
|
302
382
|
}
|
|
303
383
|
/** List a single directory level (cached, share-root-relative). */
|
|
304
384
|
async listDirectory(record, relativePath) {
|
|
305
|
-
if (record.kind !== "directory") throw new Error("Not a directory share");
|
|
306
385
|
const trimmed = (relativePath ?? "").replace(/^\/+/, "");
|
|
307
386
|
const cacheKey = `${record.id}::${trimmed}`;
|
|
308
387
|
const cacheTtl = this.config.directory.listingCacheMs;
|
|
@@ -376,6 +455,7 @@ var ShareStore = class {
|
|
|
376
455
|
const record = this.shares.get(id);
|
|
377
456
|
if (!record) return false;
|
|
378
457
|
record.revoked = true;
|
|
458
|
+
this.cleanupNoteArtifact(record);
|
|
379
459
|
this.invalidateListingCache(id);
|
|
380
460
|
this.persistSync();
|
|
381
461
|
logShareAudit("share.revoke", {
|
|
@@ -391,6 +471,7 @@ var ShareStore = class {
|
|
|
391
471
|
const record = this.shares.get(id);
|
|
392
472
|
if (record && !record.revoked) {
|
|
393
473
|
record.revoked = true;
|
|
474
|
+
this.cleanupNoteArtifact(record);
|
|
394
475
|
this.invalidateListingCache(id);
|
|
395
476
|
count++;
|
|
396
477
|
logShareAudit("share.revoke", {
|
|
@@ -408,6 +489,7 @@ var ShareStore = class {
|
|
|
408
489
|
let count = 0;
|
|
409
490
|
for (const record of this.shares.values()) if (!record.revoked && now >= new Date(record.expiresAt).getTime()) {
|
|
410
491
|
record.revoked = true;
|
|
492
|
+
this.cleanupNoteArtifact(record);
|
|
411
493
|
this.invalidateListingCache(record.id);
|
|
412
494
|
count++;
|
|
413
495
|
}
|
|
@@ -440,7 +522,7 @@ var ShareStore = class {
|
|
|
440
522
|
try {
|
|
441
523
|
const raw = readFileSync(path, "utf8");
|
|
442
524
|
const data = JSON.parse(raw);
|
|
443
|
-
if (data.version !== 1 || !Array.isArray(data.shares)) return;
|
|
525
|
+
if (data.version !== 1 && data.version !== 2 || !Array.isArray(data.shares)) return;
|
|
444
526
|
const now = Date.now();
|
|
445
527
|
let cleaned = 0;
|
|
446
528
|
for (const record of data.shares) {
|
|
@@ -474,7 +556,7 @@ var ShareStore = class {
|
|
|
474
556
|
}
|
|
475
557
|
}
|
|
476
558
|
writeFileSync(path, `${JSON.stringify({
|
|
477
|
-
version:
|
|
559
|
+
version: 2,
|
|
478
560
|
shares: records
|
|
479
561
|
}, null, 2)}\n`, "utf8");
|
|
480
562
|
}
|
|
@@ -499,19 +581,23 @@ var ShareStore = class {
|
|
|
499
581
|
cleanupExpired() {
|
|
500
582
|
const now = Date.now();
|
|
501
583
|
let removed = 0;
|
|
502
|
-
for (const [id, record] of this.shares)
|
|
503
|
-
|
|
504
|
-
this.
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
this.
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
584
|
+
for (const [id, record] of this.shares) {
|
|
585
|
+
const expiredMs = now - new Date(record.expiresAt).getTime();
|
|
586
|
+
if (expiredMs >= 0) this.cleanupNoteArtifact(record);
|
|
587
|
+
if (expiredMs > EXPIRED_RETENTION_MS) {
|
|
588
|
+
this.shares.delete(id);
|
|
589
|
+
this.tokenIndex.delete(record.token);
|
|
590
|
+
this.invalidateListingCache(id);
|
|
591
|
+
if (this.onCleanup) try {
|
|
592
|
+
this.onCleanup(record);
|
|
593
|
+
} catch (err) {
|
|
594
|
+
log.warn({
|
|
595
|
+
err,
|
|
596
|
+
shareId: id
|
|
597
|
+
}, "Share cleanup hook threw");
|
|
598
|
+
}
|
|
599
|
+
removed++;
|
|
513
600
|
}
|
|
514
|
-
removed++;
|
|
515
601
|
}
|
|
516
602
|
if (removed > 0) {
|
|
517
603
|
this.persistSync();
|
|
@@ -543,6 +629,26 @@ var ShareStore = class {
|
|
|
543
629
|
if (relToRoot.startsWith("..") || relToRoot.split(/[/\\]/).includes("..")) throw new Error("Path is outside workspace");
|
|
544
630
|
return abs;
|
|
545
631
|
}
|
|
632
|
+
cleanupNoteArtifact(record) {
|
|
633
|
+
if (record.kind !== "note") return;
|
|
634
|
+
const expected = join("share-artifacts", record.id);
|
|
635
|
+
if (record.artifactRelativePath !== expected) {
|
|
636
|
+
log.warn({
|
|
637
|
+
shareId: record.id,
|
|
638
|
+
artifactRelativePath: record.artifactRelativePath
|
|
639
|
+
}, "Skipped unsafe Note share artifact cleanup path");
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
rm(join(resolveStateDir(), expected), {
|
|
643
|
+
recursive: true,
|
|
644
|
+
force: true
|
|
645
|
+
}).catch((err) => {
|
|
646
|
+
log.warn({
|
|
647
|
+
err,
|
|
648
|
+
shareId: record.id
|
|
649
|
+
}, "Failed to clean Note share artifact");
|
|
650
|
+
});
|
|
651
|
+
}
|
|
546
652
|
};
|
|
547
653
|
async function scanDirectory(root, opts) {
|
|
548
654
|
let entryCount = 0;
|
|
@@ -92,8 +92,10 @@ async function runThumbnail(task, ctx) {
|
|
|
92
92
|
if (!target) return;
|
|
93
93
|
try {
|
|
94
94
|
let bytes;
|
|
95
|
-
if (task.scope === "file")
|
|
96
|
-
|
|
95
|
+
if (task.scope === "file") {
|
|
96
|
+
if (!("kind" in target) || target.kind === "note") return;
|
|
97
|
+
bytes = await renderForFile(target, ctx);
|
|
98
|
+
} else bytes = await renderForSite(target, ctx);
|
|
97
99
|
if (bytes.length > ctx.config.maxBytes) bytes = bytes.subarray(0, ctx.config.maxBytes);
|
|
98
100
|
await writeFile(getThumbnailPath(task.token), bytes);
|
|
99
101
|
if (task.scope === "file") getShareStore().setThumbnailStatus(task.recordId, "ready");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export type
|
|
1
|
+
export type WorkspaceShareKind = 'file' | 'directory';
|
|
2
|
+
export type ShareKind = WorkspaceShareKind | 'note';
|
|
2
3
|
export interface ShareDirectoryMeta {
|
|
3
4
|
/** 'browse' shows a file tree; 'zip-only' hides structure and only offers ZIP. */
|
|
4
5
|
mode: 'browse' | 'zip-only';
|
|
@@ -9,22 +10,14 @@ export interface ShareDirectoryMeta {
|
|
|
9
10
|
/** Maximum traversal depth (defense against recursive symlinks). */
|
|
10
11
|
maxDepth: number;
|
|
11
12
|
}
|
|
12
|
-
|
|
13
|
+
interface ShareRecordBase {
|
|
13
14
|
/** Unique identifier (UUIDv4) for management. */
|
|
14
15
|
id: string;
|
|
15
16
|
/** Cryptographically secure URL token (base64url, 32 bytes). */
|
|
16
17
|
token: string;
|
|
17
|
-
/**
|
|
18
|
-
absolutePath: string;
|
|
19
|
-
/** Workspace-relative POSIX path (for display). */
|
|
20
|
-
workspaceRelativePath: string;
|
|
21
|
-
/** Workspace root at creation time (for download-time re-validation). */
|
|
22
|
-
workspaceRoot: string;
|
|
23
|
-
/** File or directory inode at creation time (TOCTOU protection). */
|
|
24
|
-
inode: number;
|
|
25
|
-
/** Discriminator for downstream branching ('file' | 'directory'). */
|
|
18
|
+
/** Discriminator for downstream branching. */
|
|
26
19
|
kind: ShareKind;
|
|
27
|
-
/**
|
|
20
|
+
/** Public display name. Retained as fileName for API compatibility. */
|
|
28
21
|
fileName: string;
|
|
29
22
|
/**
|
|
30
23
|
* For files: file size in bytes (snapshot at creation).
|
|
@@ -56,6 +49,40 @@ export interface ShareRecord {
|
|
|
56
49
|
/** ISO timestamp of the last failed attempt (used for cooldown). */
|
|
57
50
|
thumbnailFailedAt?: string;
|
|
58
51
|
}
|
|
52
|
+
interface WorkspaceShareRecordBase extends ShareRecordBase {
|
|
53
|
+
kind: WorkspaceShareKind;
|
|
54
|
+
/** Resolved absolute path at creation time. */
|
|
55
|
+
absolutePath: string;
|
|
56
|
+
/** Workspace-relative POSIX path (for display). */
|
|
57
|
+
workspaceRelativePath: string;
|
|
58
|
+
/** Workspace root at creation time (for download-time re-validation). */
|
|
59
|
+
workspaceRoot: string;
|
|
60
|
+
/** File or directory inode at creation time (TOCTOU protection). */
|
|
61
|
+
inode: number;
|
|
62
|
+
}
|
|
63
|
+
export interface FileShareRecord extends WorkspaceShareRecordBase {
|
|
64
|
+
kind: 'file';
|
|
65
|
+
directory?: undefined;
|
|
66
|
+
}
|
|
67
|
+
export interface DirectoryShareRecord extends WorkspaceShareRecordBase {
|
|
68
|
+
kind: 'directory';
|
|
69
|
+
directory: ShareDirectoryMeta;
|
|
70
|
+
}
|
|
71
|
+
export interface NoteShareRecord extends ShareRecordBase {
|
|
72
|
+
kind: 'note';
|
|
73
|
+
/** Notes are state-owned objects, not workspace paths. */
|
|
74
|
+
workspaceRelativePath: '';
|
|
75
|
+
sourceNoteId: string;
|
|
76
|
+
sourceVersion: number;
|
|
77
|
+
artifactRelativePath: string;
|
|
78
|
+
attachmentCount: number;
|
|
79
|
+
snapshotRevision: number;
|
|
80
|
+
/** Private HMAC key for short-lived public asset tickets. */
|
|
81
|
+
assetTicketSecret: string;
|
|
82
|
+
directory?: undefined;
|
|
83
|
+
}
|
|
84
|
+
export type WorkspaceShareRecord = FileShareRecord | DirectoryShareRecord;
|
|
85
|
+
export type ShareRecord = WorkspaceShareRecord | NoteShareRecord;
|
|
59
86
|
export interface CreateShareParams {
|
|
60
87
|
/** Workspace-relative file path. */
|
|
61
88
|
path: string;
|
|
@@ -70,7 +97,7 @@ export interface CreateShareParams {
|
|
|
70
97
|
/** Agent id to resolve workspace root. */
|
|
71
98
|
agentId?: string;
|
|
72
99
|
/** Force directory share semantics (overrides auto-detection). */
|
|
73
|
-
kind?:
|
|
100
|
+
kind?: WorkspaceShareKind;
|
|
74
101
|
/** Directory: browse vs zip-only. Defaults to 'browse'. */
|
|
75
102
|
directoryMode?: 'browse' | 'zip-only';
|
|
76
103
|
/** Directory: cap on entry count at scan time. */
|
|
@@ -83,7 +110,7 @@ export interface CreateShareParams {
|
|
|
83
110
|
maxDepth?: number;
|
|
84
111
|
}
|
|
85
112
|
export interface ShareStoreData {
|
|
86
|
-
version: 1;
|
|
113
|
+
version: 1 | 2;
|
|
87
114
|
shares: ShareRecord[];
|
|
88
115
|
}
|
|
89
116
|
export type ShareReachability = 'public' | 'lan' | 'local-only';
|
|
@@ -115,6 +142,15 @@ export interface ShareThumbnailConfig {
|
|
|
115
142
|
/** Optional override for the loopback URL used by the headless renderer. */
|
|
116
143
|
internalGatewayUrl?: string;
|
|
117
144
|
}
|
|
145
|
+
export interface ShareNoteConfig {
|
|
146
|
+
enabled: boolean;
|
|
147
|
+
maxMarkdownBytes: number;
|
|
148
|
+
maxAttachmentCount: number;
|
|
149
|
+
maxAttachmentSize: number;
|
|
150
|
+
maxTotalSize: number;
|
|
151
|
+
assetTicketTtlMs: number;
|
|
152
|
+
revokeOnSourceDelete: boolean;
|
|
153
|
+
}
|
|
118
154
|
export interface ShareConfig {
|
|
119
155
|
enabled: boolean;
|
|
120
156
|
defaultTtlMs: number;
|
|
@@ -124,6 +160,8 @@ export interface ShareConfig {
|
|
|
124
160
|
inlinePreviewMimes: string[];
|
|
125
161
|
directory: ShareDirectoryConfig;
|
|
126
162
|
thumbnail: ShareThumbnailConfig;
|
|
163
|
+
note: ShareNoteConfig;
|
|
127
164
|
}
|
|
128
165
|
/** Default share configuration values. */
|
|
129
166
|
export declare const SHARE_CONFIG_DEFAULTS: ShareConfig;
|
|
167
|
+
export {};
|
|
@@ -34,6 +34,15 @@ const SHARE_CONFIG_DEFAULTS = {
|
|
|
34
34
|
viewportHeight: 630,
|
|
35
35
|
generationTimeoutMs: 8e3,
|
|
36
36
|
failureCooldownMs: 5 * 6e4
|
|
37
|
+
},
|
|
38
|
+
note: {
|
|
39
|
+
enabled: true,
|
|
40
|
+
maxMarkdownBytes: 2 * 1024 * 1024,
|
|
41
|
+
maxAttachmentCount: 50,
|
|
42
|
+
maxAttachmentSize: 100 * 1024 * 1024,
|
|
43
|
+
maxTotalSize: 250 * 1024 * 1024,
|
|
44
|
+
assetTicketTtlMs: 10 * 6e4,
|
|
45
|
+
revokeOnSourceDelete: true
|
|
37
46
|
}
|
|
38
47
|
};
|
|
39
48
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Readable } from 'node:stream';
|
|
2
|
-
import type {
|
|
2
|
+
import type { DirectoryShareRecord } from './share-types.js';
|
|
3
3
|
export interface ZipPlanFile {
|
|
4
4
|
/** Path within the archive (POSIX, no leading /, may contain subdirs). */
|
|
5
5
|
zipPath: string;
|
|
@@ -32,4 +32,4 @@ export interface PlanDirectoryOpts {
|
|
|
32
32
|
/** Walk depth cap. */
|
|
33
33
|
maxDepth: number;
|
|
34
34
|
}
|
|
35
|
-
export declare function planDirectoryFiles(record:
|
|
35
|
+
export declare function planDirectoryFiles(record: DirectoryShareRecord, opts: PlanDirectoryOpts): Promise<ZipPlanFile[]>;
|
|
@@ -23,9 +23,9 @@ import { parseModelRef } from "../../agent/models/selection.js";
|
|
|
23
23
|
import { buildReviewContext, resolveGitRoot } from "../../review/review-git.js";
|
|
24
24
|
import { MessageBus, MessageBusShutdownError } from "../../infra/bus/queue.js";
|
|
25
25
|
import "../../infra/bus/index.js";
|
|
26
|
-
import { prependEnvelopeTimestamp } from "../../channels/envelope-timestamp.js";
|
|
27
26
|
import { getWorkspacePath } from "../../config/workspace-path-helpers.js";
|
|
28
27
|
import "../../config/index.js";
|
|
28
|
+
import { prependEnvelopeTimestamp } from "../../channels/envelope-timestamp.js";
|
|
29
29
|
import { buildWorkflowChildTools } from "../../agent/workflow/workflow-child-tools.js";
|
|
30
30
|
import { WorkflowRunService } from "../../workflows/service/workflow-run-service.js";
|
|
31
31
|
import { WorkflowSessionBridge } from "../../workflows/service/workflow-session-bridge.js";
|
package/dist/src/tunnel/env.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { Config } from '../config/schema.js';
|
|
2
|
-
export
|
|
3
|
-
export type TunnelRegistrationSecretSource = 'env' | 'config' | 'dev_default' | 'missing';
|
|
2
|
+
export type TunnelRegistrationSecretSource = 'config' | 'dev_default' | 'missing';
|
|
4
3
|
export type TunnelRegistrationSecretMeta = {
|
|
5
4
|
configured: boolean;
|
|
6
5
|
source: TunnelRegistrationSecretSource;
|
|
7
6
|
};
|
|
8
|
-
|
|
9
|
-
export declare
|
|
7
|
+
export declare const TUNNEL_REGISTRATION_SECRET_REQUIRED_CODE = "TUNNEL_REGISTRATION_SECRET_REQUIRED";
|
|
8
|
+
export declare class TunnelRegistrationSecretError extends Error {
|
|
9
|
+
readonly code = "TUNNEL_REGISTRATION_SECRET_REQUIRED";
|
|
10
|
+
constructor(brokerUrl?: string);
|
|
11
|
+
}
|
|
12
|
+
/** True only for brokers that are safe to use with the built-in development secret. */
|
|
13
|
+
export declare function isLocalDevelopmentTunnelBroker(brokerUrl: string): boolean;
|
|
10
14
|
export declare function maskTunnelSecretForWeb(secret: string): string;
|
|
11
15
|
export declare function isMaskedTunnelSecretPatchValue(value: string): boolean;
|
|
12
16
|
/**
|
|
@@ -15,9 +19,11 @@ export declare function isMaskedTunnelSecretPatchValue(value: string): boolean;
|
|
|
15
19
|
/** Plaintext registration secret from config file only (never env). */
|
|
16
20
|
export declare function readTunnelRegistrationSecretFromConfigOnly(config: Config | undefined): string | null;
|
|
17
21
|
export declare function getTunnelRegistrationSecretMeta(config: Config | undefined, env?: NodeJS.ProcessEnv, brokerUrl?: string): TunnelRegistrationSecretMeta;
|
|
22
|
+
export declare function resolveOptionalTunnelRegistrationSecret(brokerUrl?: string, configSecret?: string): string | undefined;
|
|
23
|
+
export declare function tunnelRegistrationSecretRequiredMessage(brokerUrl?: string): string;
|
|
18
24
|
/**
|
|
19
25
|
* Registration secret for Tunnel Broker register API.
|
|
20
|
-
*
|
|
26
|
+
* Resolve `tunnel.registrationSecret` from config, with a development default for local brokers.
|
|
21
27
|
*/
|
|
22
|
-
export declare function resolveTunnelRegistrationSecret(
|
|
28
|
+
export declare function resolveTunnelRegistrationSecret(brokerUrl?: string, configSecret?: string): string;
|
|
23
29
|
export declare function resolveTunnelBrokerUrl(configBrokerUrl: string | undefined, env?: NodeJS.ProcessEnv): string;
|