@xopcai/xopc 0.0.84 → 0.0.85
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/feishu/src/plugin.d.ts +2 -0
- package/dist/extensions/feishu/src/plugin.js +10 -0
- package/dist/extensions/feishu/src/plugin.js.map +1 -1
- package/dist/extensions/feishu/src/workflow-progress.d.ts +27 -0
- package/dist/extensions/feishu/src/workflow-progress.js +99 -0
- package/dist/extensions/feishu/src/workflow-progress.js.map +1 -0
- package/dist/extensions/telegram/src/plugin.d.ts +2 -0
- package/dist/extensions/telegram/src/plugin.js +11 -1
- package/dist/extensions/telegram/src/plugin.js.map +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/workflow-progress.d.ts +24 -0
- package/dist/extensions/telegram/src/workflow-progress.js +73 -0
- package/dist/extensions/telegram/src/workflow-progress.js.map +1 -0
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js +158 -0
- package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js.map +1 -0
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.d.ts +2 -0
- package/dist/extensions/weixin/src/plugin.js +11 -1
- package/dist/extensions/weixin/src/plugin.js.map +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.d.ts +26 -0
- package/dist/extensions/weixin/src/workflow-progress.js +99 -0
- package/dist/extensions/weixin/src/workflow-progress.js.map +1 -0
- package/dist/gateway/static/root/assets/agents-D3_-kNlZ.js +222 -0
- package/dist/gateway/static/root/assets/apps-page-D7v7649T.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-nCaMb0a7.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-C1gZBcJV.js +8 -0
- package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +1 -0
- package/dist/gateway/static/root/assets/cron-api-CoYK0hlm.js +1 -0
- package/dist/gateway/static/root/assets/cron-page-DeGo-Vjc.js +1 -0
- package/dist/gateway/static/root/assets/dist-BTWC-BTN.js +45 -0
- package/dist/gateway/static/root/assets/{dist-CqNMNhJM.js → dist-DaK4dsss.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-gf2L0kY_.js → extension-debug-page-BZngZWbO.js} +1 -1
- package/dist/gateway/static/root/assets/extension-page-D6JSyV27.js +1 -0
- package/dist/gateway/static/root/assets/extension-settings-page-8PZcmWI7.js +1 -0
- package/dist/gateway/static/root/assets/fetch-B2MYHbWg.js +1 -0
- package/dist/gateway/static/root/assets/{field-primitives-DTtlp-l8.js → field-primitives-Zzl22MvN.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-config-api-BtIcpG0O.js +1 -0
- package/dist/gateway/static/root/assets/index-D4vM3-P7.js +4700 -0
- package/dist/gateway/static/root/assets/index-ew_2L2We.css +1 -0
- package/dist/gateway/static/root/assets/logs-page-_d4UJ-qQ.js +1 -0
- package/dist/gateway/static/root/assets/sessions-page-5N4aF2Wk.js +1 -0
- package/dist/gateway/static/root/assets/settings-form-section-D_tgb8r2.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-C18xBt4X.js +3 -0
- package/dist/gateway/static/root/assets/share-preview-page-D4EG_vM1.js +2 -0
- package/dist/gateway/static/root/assets/skills-page-sPAXhh8w.js +2 -0
- package/dist/gateway/static/root/assets/theme-store-DryYl3qD.js +1 -0
- package/dist/gateway/static/root/assets/url-BwNL6Rgk.js +3 -0
- package/dist/gateway/static/root/assets/utils-CYO9eTCM.js +1 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-Ds51havm.js +1 -0
- package/dist/gateway/static/root/index.html +7 -6
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +7 -7
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/context/workspace-seed.js +3 -3
- package/dist/src/agent/embedded/map-stream-events.js +6 -0
- package/dist/src/agent/embedded/map-stream-events.js.map +1 -1
- package/dist/src/agent/embedded/subscribe-session.js +24 -0
- package/dist/src/agent/embedded/subscribe-session.js.map +1 -1
- package/dist/src/agent/embedded/types.d.ts +19 -0
- package/dist/src/agent/goals/goal-locale.js +2 -2
- package/dist/src/agent/goals/goal-run-store.js +4 -4
- package/dist/src/agent/goals/persistent-goal-service.js +1 -1
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +2 -2
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/startup-context.d.ts +3 -0
- package/dist/src/agent/reply/startup-context.js +25 -2
- package/dist/src/agent/reply/startup-context.js.map +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service/build-direct-message-content.js +1 -1
- package/dist/src/agent/service.d.ts +1 -0
- package/dist/src/agent/service.js +10 -4
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +3 -3
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/create-share-tool.d.ts +27 -0
- package/dist/src/agent/tools/create-share-tool.js +237 -0
- package/dist/src/agent/tools/create-share-tool.js.map +1 -0
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +35 -1
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/index.d.ts +2 -0
- package/dist/src/agent/tools/index.js +3 -1
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/workflow-tool.d.ts +41 -0
- package/dist/src/agent/tools/workflow-tool.js +271 -0
- package/dist/src/agent/tools/workflow-tool.js.map +1 -0
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/agent/workflow/builtins/audit-repo.d.ts +9 -0
- package/dist/src/agent/workflow/builtins/audit-repo.js +115 -0
- package/dist/src/agent/workflow/builtins/audit-repo.js.map +1 -0
- package/dist/src/agent/workflow/builtins/index.d.ts +15 -0
- package/dist/src/agent/workflow/builtins/index.js +28 -0
- package/dist/src/agent/workflow/builtins/index.js.map +1 -0
- package/dist/src/agent/workflow/builtins/multi-perspective-review.d.ts +9 -0
- package/dist/src/agent/workflow/builtins/multi-perspective-review.js +113 -0
- package/dist/src/agent/workflow/builtins/multi-perspective-review.js.map +1 -0
- package/dist/src/agent/workflow/builtins/research.d.ts +9 -0
- package/dist/src/agent/workflow/builtins/research.js +129 -0
- package/dist/src/agent/workflow/builtins/research.js.map +1 -0
- package/dist/src/agent/workflow/catalog.d.ts +51 -0
- package/dist/src/agent/workflow/catalog.js +155 -0
- package/dist/src/agent/workflow/catalog.js.map +1 -0
- package/dist/src/agent/workflow/channel-capability.d.ts +76 -0
- package/dist/src/agent/workflow/channel-capability.js +1 -0
- package/dist/src/agent/workflow/index.d.ts +11 -0
- package/dist/src/agent/workflow/index.js +10 -0
- package/dist/src/agent/workflow/last-run-memory.d.ts +42 -0
- package/dist/src/agent/workflow/last-run-memory.js +60 -0
- package/dist/src/agent/workflow/last-run-memory.js.map +1 -0
- package/dist/src/agent/workflow/parser.d.ts +20 -0
- package/dist/src/agent/workflow/parser.js +137 -0
- package/dist/src/agent/workflow/parser.js.map +1 -0
- package/dist/src/agent/workflow/progress-broker.d.ts +80 -0
- package/dist/src/agent/workflow/progress-broker.js +263 -0
- package/dist/src/agent/workflow/progress-broker.js.map +1 -0
- package/dist/src/agent/workflow/runtime.d.ts +31 -0
- package/dist/src/agent/workflow/runtime.js +301 -0
- package/dist/src/agent/workflow/runtime.js.map +1 -0
- package/dist/src/agent/workflow/snapshot.d.ts +18 -0
- package/dist/src/agent/workflow/snapshot.js +144 -0
- package/dist/src/agent/workflow/snapshot.js.map +1 -0
- package/dist/src/agent/workflow/structured-output-tool.d.ts +33 -0
- package/dist/src/agent/workflow/structured-output-tool.js +58 -0
- package/dist/src/agent/workflow/structured-output-tool.js.map +1 -0
- package/dist/src/agent/workflow/subagent-runner.d.ts +42 -0
- package/dist/src/agent/workflow/subagent-runner.js +104 -0
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -0
- package/dist/src/agent/workflow/types.d.ts +137 -0
- package/dist/src/agent/workflow/types.js +1 -0
- package/dist/src/auth/credentials.js +3 -3
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +4 -4
- package/dist/src/browser/providers/cloakbrowser.js +4 -4
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/attachments/inbound-persist.js +1 -1
- package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/chat-commands/builtins/config.js +2 -2
- package/dist/src/chat-commands/builtins/model.js +40 -23
- package/dist/src/chat-commands/builtins/model.js.map +1 -1
- package/dist/src/chat-commands/builtins/system.js +30 -15
- package/dist/src/chat-commands/builtins/system.js.map +1 -1
- package/dist/src/chat-commands/builtins/workflow.d.ts +18 -0
- package/dist/src/chat-commands/builtins/workflow.js +167 -0
- package/dist/src/chat-commands/builtins/workflow.js.map +1 -0
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/chat-commands/format-output.d.ts +28 -0
- package/dist/src/chat-commands/format-output.js +45 -0
- package/dist/src/chat-commands/format-output.js.map +1 -0
- package/dist/src/chat-commands/index.d.ts +1 -0
- package/dist/src/chat-commands/index.js +3 -1
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/cli/commands/config.js +2 -2
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +10 -4
- package/dist/src/cli/commands/gateway/lifecycle.js.map +1 -1
- package/dist/src/cli/commands/gateway/shared.js +1 -1
- package/dist/src/cli/commands/image.js +1 -1
- package/dist/src/cli/commands/init.js +4 -4
- package/dist/src/cli/commands/onboard.js +2 -2
- package/dist/src/cli/commands/tunnel.js +2 -2
- package/dist/src/cli/utils/gateway-client.js +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +5 -5
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.js +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/public-url.d.ts +28 -0
- package/dist/src/config/public-url.js +103 -0
- package/dist/src/config/public-url.js.map +1 -0
- package/dist/src/config/schema.d.ts +82 -0
- package/dist/src/config/schema.js +130 -1
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/cron/run-log-store.js +1 -1
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +3 -3
- package/dist/src/daemon/install-plan.js.map +1 -1
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/schtasks.js +38 -1
- package/dist/src/daemon/schtasks.js.map +1 -1
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/loader.js +1 -1
- package/dist/src/extensions/lockfile.js +2 -2
- package/dist/src/gateway/agents-admin.js +2 -2
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/hono/app.js +33 -2
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/agents.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/shares.js +631 -34
- package/dist/src/gateway/hono/routes/shares.js.map +1 -1
- package/dist/src/gateway/hono/routes/site-shares.d.ts +3 -0
- package/dist/src/gateway/hono/routes/site-shares.js +228 -0
- package/dist/src/gateway/hono/routes/site-shares.js.map +1 -0
- package/dist/src/gateway/hono/routes/tunnel.js +97 -8
- package/dist/src/gateway/hono/routes/tunnel.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +5 -5
- package/dist/src/gateway/hono/sse.js +2 -2
- package/dist/src/gateway/host.d.ts +3 -1
- package/dist/src/gateway/host.js +3 -1
- package/dist/src/gateway/host.js.map +1 -1
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.d.ts +6 -0
- package/dist/src/gateway/ports.js +38 -2
- package/dist/src/gateway/ports.js.map +1 -1
- package/dist/src/gateway/public-url.d.ts +8 -0
- package/dist/src/gateway/public-url.js +10 -0
- package/dist/src/gateway/public-url.js.map +1 -0
- package/dist/src/gateway/security/origin-check.d.ts +9 -1
- package/dist/src/gateway/security/origin-check.js +4 -0
- package/dist/src/gateway/security/origin-check.js.map +1 -1
- package/dist/src/gateway/server.js +15 -0
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/service/agent-runner.js +2 -2
- package/dist/src/gateway/service/marketplace-service.js +2 -2
- package/dist/src/gateway/service/run-gateway-agent.js +2 -2
- package/dist/src/gateway/service.js +3 -2
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/i18n/goals-bundle.js +1 -1
- package/dist/src/i18n/index.d.ts +1 -0
- package/dist/src/i18n/index.js +2 -1
- package/dist/src/i18n/locales/share-tool.en.js +15 -0
- package/dist/src/i18n/locales/share-tool.en.js.map +1 -0
- package/dist/src/i18n/locales/share-tool.zh.js +15 -0
- package/dist/src/i18n/locales/share-tool.zh.js.map +1 -0
- package/dist/src/i18n/share-tool-bundle.d.ts +20 -0
- package/dist/src/i18n/share-tool-bundle.js +56 -0
- package/dist/src/i18n/share-tool-bundle.js.map +1 -0
- package/dist/src/infra/gateway-processes.js +1 -0
- package/dist/src/infra/gateway-processes.js.map +1 -1
- package/dist/src/infra/restart.js +2 -2
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-lock.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +2 -2
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/session/config-store.js +2 -2
- package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
- package/dist/src/session/parity/sessions-json-file.js +1 -1
- package/dist/src/session/parity/transcript-file-lock.js +2 -2
- package/dist/src/session/parity/transcript-paths.js +1 -1
- package/dist/src/session/search-index-cache.js +1 -1
- package/dist/src/session/search-index.js +1 -1
- package/dist/src/session/session-title.js +3 -2
- package/dist/src/session/session-title.js.map +1 -1
- package/dist/src/session/store.js +5 -5
- package/dist/src/share/share-auto.d.ts +74 -0
- package/dist/src/share/share-auto.js +247 -0
- package/dist/src/share/share-auto.js.map +1 -0
- package/dist/src/share/share-config.js +63 -4
- package/dist/src/share/share-config.js.map +1 -1
- package/dist/src/share/share-landing.d.ts +28 -2
- package/dist/src/share/share-landing.js +155 -34
- package/dist/src/share/share-landing.js.map +1 -1
- package/dist/src/share/share-store.d.ts +48 -4
- package/dist/src/share/share-store.js +322 -51
- package/dist/src/share/share-store.js.map +1 -1
- package/dist/src/share/share-thumbnail.d.ts +35 -0
- package/dist/src/share/share-thumbnail.js +277 -0
- package/dist/src/share/share-thumbnail.js.map +1 -0
- package/dist/src/share/share-types.d.ts +68 -10
- package/dist/src/share/share-types.js +18 -1
- package/dist/src/share/share-types.js.map +1 -1
- package/dist/src/share/share-url.js +1 -1
- package/dist/src/share/share-zip.d.ts +35 -0
- package/dist/src/share/share-zip.js +303 -0
- package/dist/src/share/share-zip.js.map +1 -0
- package/dist/src/share/site-proxy.d.ts +35 -0
- package/dist/src/share/site-proxy.js +234 -0
- package/dist/src/share/site-proxy.js.map +1 -0
- package/dist/src/share/site-share-config.d.ts +11 -0
- package/dist/src/share/site-share-config.js +103 -0
- package/dist/src/share/site-share-config.js.map +1 -0
- package/dist/src/share/site-share-router.d.ts +23 -0
- package/dist/src/share/site-share-router.js +147 -0
- package/dist/src/share/site-share-router.js.map +1 -0
- package/dist/src/share/site-share-store.d.ts +53 -0
- package/dist/src/share/site-share-store.js +400 -0
- package/dist/src/share/site-share-store.js.map +1 -0
- package/dist/src/share/site-share-types.d.ts +103 -0
- package/dist/src/share/site-share-types.js +41 -0
- package/dist/src/share/site-share-types.js.map +1 -0
- package/dist/src/share/site-static-serve.d.ts +10 -0
- package/dist/src/share/site-static-serve.js +145 -0
- package/dist/src/share/site-static-serve.js.map +1 -0
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-commands.js +18 -0
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui-workflow-slash.d.ts +32 -0
- package/dist/src/tui/tui-workflow-slash.js +63 -0
- package/dist/src/tui/tui-workflow-slash.js.map +1 -0
- package/dist/src/tui/tui.js +2 -2
- package/dist/src/tunnel/enable-lan-pairing.js +1 -1
- package/dist/src/tunnel/frpc-binary.js +3 -3
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/index.js +2 -2
- package/dist/src/tunnel/pair-context.d.ts +7 -1
- package/dist/src/tunnel/pair-context.js +25 -9
- package/dist/src/tunnel/pair-context.js.map +1 -1
- package/dist/src/tunnel/pair-url.d.ts +14 -1
- package/dist/src/tunnel/pair-url.js +14 -1
- package/dist/src/tunnel/pair-url.js.map +1 -1
- package/dist/src/tunnel/tunnel-service.js +2 -2
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/package.json +3 -2
- package/dist/gateway/static/root/assets/agents-tR-nNP04.js +0 -222
- package/dist/gateway/static/root/assets/apps-page-BDw6SP-d.js +0 -1
- package/dist/gateway/static/root/assets/button-KafIU8dx.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-DEFd-jj1.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-DI5FHdGe.js +0 -8
- package/dist/gateway/static/root/assets/cron-api-BSqY8LwW.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-D7lVDjcR.js +0 -1
- package/dist/gateway/static/root/assets/dist-C57OMHW8.js +0 -48
- package/dist/gateway/static/root/assets/extension-page-CQo2Xsmg.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-CZf0WoZg.js +0 -1
- package/dist/gateway/static/root/assets/fetch-2iRFmd3n.js +0 -3
- package/dist/gateway/static/root/assets/heartbeat-config-api-B0drdQEJ.js +0 -1
- package/dist/gateway/static/root/assets/index-0Gt3TG4j.js +0 -4693
- package/dist/gateway/static/root/assets/index-BuFldCsB.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-DMuORLfC.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-_UO8g6NN.js +0 -1
- package/dist/gateway/static/root/assets/settings-form-section-DkmHkknc.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-Cz8FoW_A.js +0 -3
- package/dist/gateway/static/root/assets/skills-page-HrUOxF7H.js +0 -2
- package/dist/gateway/static/root/assets/theme-store-D01dJt95.js +0 -1
- package/dist/gateway/static/root/assets/utils-BFwcR6pL.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-JF8-aqc5.js +0 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import { resolveStateDir } from "../config/paths-state.js";
|
|
1
2
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
3
|
import { init_logger } from "../utils/logger.js";
|
|
3
|
-
import { resolveStateDir } from "../config/paths-state.js";
|
|
4
4
|
import { init_paths } from "../config/paths.js";
|
|
5
|
+
import { SHARE_CONFIG_DEFAULTS } from "./share-types.js";
|
|
5
6
|
import { isPathUnderWorkspace } from "../gateway/workspace-editor-path.js";
|
|
6
7
|
import { logShareAudit } from "./share-audit.js";
|
|
7
|
-
import {
|
|
8
|
-
import { randomBytes, randomUUID } from "node:crypto";
|
|
8
|
+
import { join, relative, resolve } from "node:path";
|
|
9
9
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
11
|
+
import { lstat, readdir, realpath, stat } from "node:fs/promises";
|
|
12
12
|
//#region src/share/share-store.ts
|
|
13
13
|
init_paths();
|
|
14
14
|
init_logger();
|
|
@@ -18,17 +18,20 @@ const CLEANUP_INTERVAL_MS = 10 * 6e4;
|
|
|
18
18
|
const EXPIRED_RETENTION_MS = 1440 * 6e4;
|
|
19
19
|
const MAX_STORED_RECORDS = 500;
|
|
20
20
|
const TRUNCATE_TO = 200;
|
|
21
|
-
const
|
|
21
|
+
const COUNTER_DEBOUNCE_MS = 2e3;
|
|
22
22
|
function resolveSharesPath() {
|
|
23
23
|
return join(resolveStateDir(), SHARES_FILE);
|
|
24
24
|
}
|
|
25
25
|
var ShareStore = class {
|
|
26
26
|
shares = /* @__PURE__ */ new Map();
|
|
27
27
|
tokenIndex = /* @__PURE__ */ new Map();
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
dirty = false;
|
|
29
|
+
debounceTimer = null;
|
|
30
30
|
cleanupTimer = null;
|
|
31
31
|
config;
|
|
32
|
+
listingCache = /* @__PURE__ */ new Map();
|
|
33
|
+
/** Optional cleanup hook invoked when a share record is dropped (e.g. delete thumbnail). */
|
|
34
|
+
onCleanup = null;
|
|
32
35
|
constructor(config) {
|
|
33
36
|
this.config = {
|
|
34
37
|
...SHARE_CONFIG_DEFAULTS,
|
|
@@ -43,6 +46,10 @@ var ShareStore = class {
|
|
|
43
46
|
...config
|
|
44
47
|
};
|
|
45
48
|
}
|
|
49
|
+
/** Register a cleanup hook (idempotent — last wins). */
|
|
50
|
+
setCleanupHook(hook) {
|
|
51
|
+
this.onCleanup = hook;
|
|
52
|
+
}
|
|
46
53
|
getConfig() {
|
|
47
54
|
return { ...this.config };
|
|
48
55
|
}
|
|
@@ -57,6 +64,30 @@ var ShareStore = class {
|
|
|
57
64
|
}
|
|
58
65
|
const absolutePath = await this.resolveAndValidatePath(relPath, workspaceRoot);
|
|
59
66
|
const fileStat = await stat(absolutePath);
|
|
67
|
+
const detectedKind = fileStat.isDirectory() ? "directory" : "file";
|
|
68
|
+
const requestedKind = params.kind ?? detectedKind;
|
|
69
|
+
if (requestedKind !== detectedKind) throw new Error(`Requested share kind '${requestedKind}' does not match filesystem (got '${detectedKind}')`);
|
|
70
|
+
if (requestedKind === "file") return this.createFileShare({
|
|
71
|
+
params,
|
|
72
|
+
absolutePath,
|
|
73
|
+
fileStat,
|
|
74
|
+
relPath,
|
|
75
|
+
workspaceRoot,
|
|
76
|
+
ttlMs,
|
|
77
|
+
gatewayTokenHash
|
|
78
|
+
});
|
|
79
|
+
return this.createDirectoryShare({
|
|
80
|
+
params,
|
|
81
|
+
absolutePath,
|
|
82
|
+
fileStat,
|
|
83
|
+
relPath,
|
|
84
|
+
workspaceRoot,
|
|
85
|
+
ttlMs,
|
|
86
|
+
gatewayTokenHash
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async createFileShare(args) {
|
|
90
|
+
const { params, absolutePath, fileStat, relPath, workspaceRoot, ttlMs, gatewayTokenHash } = args;
|
|
60
91
|
if (!fileStat.isFile()) throw new Error("Path is not a regular file");
|
|
61
92
|
if (fileStat.size > this.config.maxFileSize) {
|
|
62
93
|
const maxMb = (this.config.maxFileSize / 1048576).toFixed(0);
|
|
@@ -65,42 +96,108 @@ var ShareStore = class {
|
|
|
65
96
|
if ((await lstat(absolutePath)).isSymbolicLink()) {
|
|
66
97
|
if (!isPathUnderWorkspace(workspaceRoot, await realpath(absolutePath))) throw new Error("Symlink target is outside workspace");
|
|
67
98
|
}
|
|
68
|
-
const
|
|
69
|
-
const token = randomBytes(32).toString("base64url");
|
|
70
|
-
const fileName = relPath.split("/").pop() ?? relPath;
|
|
99
|
+
const fileName = relPath.split("/").pop() || relPath;
|
|
71
100
|
const mimeType = resolveMimeType(fileName);
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
id,
|
|
75
|
-
token,
|
|
101
|
+
const record = this.buildRecord({
|
|
102
|
+
kind: "file",
|
|
76
103
|
absolutePath,
|
|
77
|
-
workspaceRelativePath: relPath,
|
|
78
104
|
workspaceRoot,
|
|
105
|
+
workspaceRelativePath: relPath,
|
|
79
106
|
inode: fileStat.ino,
|
|
80
|
-
isDirectory: false,
|
|
81
107
|
fileName,
|
|
82
108
|
fileSize: fileStat.size,
|
|
83
109
|
mimeType,
|
|
110
|
+
ttlMs,
|
|
111
|
+
maxViews: params.maxViews,
|
|
112
|
+
description: params.description,
|
|
113
|
+
gatewayTokenHash
|
|
114
|
+
});
|
|
115
|
+
this.persistAndAudit(record, "share.create", `Share created: ${record.fileName}`, {
|
|
116
|
+
fileName: record.fileName,
|
|
117
|
+
fileSize: record.fileSize,
|
|
118
|
+
ttlMs
|
|
119
|
+
});
|
|
120
|
+
return record;
|
|
121
|
+
}
|
|
122
|
+
async createDirectoryShare(args) {
|
|
123
|
+
const { params, absolutePath, fileStat, relPath, workspaceRoot, ttlMs, gatewayTokenHash } = args;
|
|
124
|
+
const dirCfg = this.config.directory;
|
|
125
|
+
if (!dirCfg.enabled) throw new Error("Directory sharing is disabled");
|
|
126
|
+
const followSymlinks = params.followSymlinks ?? false;
|
|
127
|
+
const maxDepth = params.maxDepth ?? dirCfg.maxDepth;
|
|
128
|
+
const summary = await scanDirectory(absolutePath, {
|
|
129
|
+
workspaceRoot,
|
|
130
|
+
followSymlinks,
|
|
131
|
+
maxDepth,
|
|
132
|
+
maxFileCount: Math.min(params.maxFileCount ?? dirCfg.maxFileCount, dirCfg.maxFileCount),
|
|
133
|
+
maxFolderSize: Math.min(params.maxFolderSize ?? dirCfg.maxFolderSize, dirCfg.maxFolderSize)
|
|
134
|
+
});
|
|
135
|
+
const fileName = relPath.split("/").pop() || relPath || "shared";
|
|
136
|
+
const record = this.buildRecord({
|
|
137
|
+
kind: "directory",
|
|
138
|
+
absolutePath,
|
|
139
|
+
workspaceRoot,
|
|
140
|
+
workspaceRelativePath: relPath,
|
|
141
|
+
inode: fileStat.ino,
|
|
142
|
+
fileName,
|
|
143
|
+
fileSize: summary.totalSize,
|
|
144
|
+
mimeType: "application/x-directory",
|
|
145
|
+
ttlMs,
|
|
146
|
+
maxViews: params.maxViews,
|
|
147
|
+
description: params.description,
|
|
148
|
+
gatewayTokenHash,
|
|
149
|
+
directory: {
|
|
150
|
+
mode: params.directoryMode ?? "browse",
|
|
151
|
+
entryCount: summary.entryCount,
|
|
152
|
+
followSymlinks,
|
|
153
|
+
maxDepth
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
this.persistAndAudit(record, "share.create", `Folder share created: ${record.fileName}`, {
|
|
157
|
+
fileName: record.fileName,
|
|
158
|
+
entryCount: summary.entryCount,
|
|
159
|
+
totalSize: summary.totalSize,
|
|
160
|
+
ttlMs,
|
|
161
|
+
mode: record.directory?.mode
|
|
162
|
+
});
|
|
163
|
+
return record;
|
|
164
|
+
}
|
|
165
|
+
buildRecord(input) {
|
|
166
|
+
const id = randomUUID();
|
|
167
|
+
const token = randomBytes(32).toString("base64url");
|
|
168
|
+
const now = /* @__PURE__ */ new Date();
|
|
169
|
+
const record = {
|
|
170
|
+
id,
|
|
171
|
+
token,
|
|
172
|
+
absolutePath: input.absolutePath,
|
|
173
|
+
workspaceRelativePath: input.workspaceRelativePath,
|
|
174
|
+
workspaceRoot: input.workspaceRoot,
|
|
175
|
+
inode: input.inode,
|
|
176
|
+
kind: input.kind,
|
|
177
|
+
fileName: input.fileName,
|
|
178
|
+
fileSize: input.fileSize,
|
|
179
|
+
mimeType: input.mimeType,
|
|
84
180
|
createdAt: now.toISOString(),
|
|
85
|
-
expiresAt: new Date(now.getTime() + ttlMs).toISOString(),
|
|
86
|
-
maxViews:
|
|
87
|
-
|
|
181
|
+
expiresAt: new Date(now.getTime() + input.ttlMs).toISOString(),
|
|
182
|
+
maxViews: input.maxViews ?? null,
|
|
183
|
+
downloadCount: 0,
|
|
88
184
|
revoked: false,
|
|
89
|
-
createdByTokenHash: gatewayTokenHash,
|
|
90
|
-
description:
|
|
185
|
+
createdByTokenHash: input.gatewayTokenHash,
|
|
186
|
+
description: input.description,
|
|
187
|
+
directory: input.directory
|
|
91
188
|
};
|
|
92
189
|
this.shares.set(id, record);
|
|
93
190
|
this.tokenIndex.set(token, id);
|
|
94
|
-
this.persistSync();
|
|
95
|
-
logShareAudit("share.create", {
|
|
96
|
-
shareId: id,
|
|
97
|
-
tokenPrefix: token.slice(0, 8),
|
|
98
|
-
fileName,
|
|
99
|
-
fileSize: fileStat.size,
|
|
100
|
-
ttlMs
|
|
101
|
-
}, `Share created: ${fileName}`);
|
|
102
191
|
return record;
|
|
103
192
|
}
|
|
193
|
+
persistAndAudit(record, event, message, extra) {
|
|
194
|
+
this.persistSync();
|
|
195
|
+
logShareAudit(event, {
|
|
196
|
+
shareId: record.id,
|
|
197
|
+
tokenPrefix: record.token.slice(0, 8),
|
|
198
|
+
...extra
|
|
199
|
+
}, message);
|
|
200
|
+
}
|
|
104
201
|
getById(id) {
|
|
105
202
|
return this.shares.get(id) ?? null;
|
|
106
203
|
}
|
|
@@ -119,17 +216,17 @@ var ShareStore = class {
|
|
|
119
216
|
valid: false,
|
|
120
217
|
reason: "expired"
|
|
121
218
|
};
|
|
122
|
-
if (record.maxViews !== null && record.
|
|
219
|
+
if (record.maxViews !== null && record.downloadCount >= record.maxViews) return {
|
|
123
220
|
valid: false,
|
|
124
221
|
reason: "max_views"
|
|
125
222
|
};
|
|
126
223
|
return { valid: true };
|
|
127
224
|
}
|
|
128
|
-
/** Increment
|
|
129
|
-
|
|
225
|
+
/** Increment download counter (used by directory & file downloads). Debounced persist. */
|
|
226
|
+
incrementDownloadCount(id) {
|
|
130
227
|
const record = this.shares.get(id);
|
|
131
228
|
if (!record) return;
|
|
132
|
-
record.
|
|
229
|
+
record.downloadCount++;
|
|
133
230
|
this.scheduleDebouncedPersist();
|
|
134
231
|
}
|
|
135
232
|
/** Check if the file still exists and inode matches. */
|
|
@@ -147,7 +244,7 @@ var ShareStore = class {
|
|
|
147
244
|
tokenPrefix: record.token.slice(0, 8),
|
|
148
245
|
oldInode: record.inode,
|
|
149
246
|
newInode: fileStat.ino
|
|
150
|
-
}, `Share
|
|
247
|
+
}, `Share path replaced (inode changed): ${record.fileName}`);
|
|
151
248
|
return {
|
|
152
249
|
valid: false,
|
|
153
250
|
reason: "file_deleted"
|
|
@@ -161,10 +258,125 @@ var ShareStore = class {
|
|
|
161
258
|
};
|
|
162
259
|
}
|
|
163
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Resolve a child path inside a directory share. Returns the absolute path
|
|
263
|
+
* if it stays within both the share root and the workspace.
|
|
264
|
+
*/
|
|
265
|
+
async resolveDirectoryChild(record, relativePath) {
|
|
266
|
+
if (record.kind !== "directory") return {
|
|
267
|
+
ok: false,
|
|
268
|
+
reason: "not_directory"
|
|
269
|
+
};
|
|
270
|
+
const trimmed = (relativePath ?? "").replace(/^\/+/, "").replace(/\\/g, "/");
|
|
271
|
+
if (trimmed.includes("..") || trimmed.includes("\0")) return {
|
|
272
|
+
ok: false,
|
|
273
|
+
reason: "path_traversal"
|
|
274
|
+
};
|
|
275
|
+
const abs = resolve(record.absolutePath, trimmed);
|
|
276
|
+
const relToShare = relative(record.absolutePath, abs);
|
|
277
|
+
if (relToShare.startsWith("..") || relToShare.split(/[/\\]/).includes("..")) return {
|
|
278
|
+
ok: false,
|
|
279
|
+
reason: "path_outside_share"
|
|
280
|
+
};
|
|
281
|
+
try {
|
|
282
|
+
const real = await realpath(abs);
|
|
283
|
+
if (!isPathUnderWorkspace(record.workspaceRoot, real)) return {
|
|
284
|
+
ok: false,
|
|
285
|
+
reason: "path_outside_workspace"
|
|
286
|
+
};
|
|
287
|
+
const relToShareReal = relative(record.absolutePath, real);
|
|
288
|
+
if (relToShareReal.startsWith("..") || relToShareReal.split(/[/\\]/).includes("..")) return {
|
|
289
|
+
ok: false,
|
|
290
|
+
reason: "path_outside_share"
|
|
291
|
+
};
|
|
292
|
+
return {
|
|
293
|
+
ok: true,
|
|
294
|
+
absolutePath: real
|
|
295
|
+
};
|
|
296
|
+
} catch {
|
|
297
|
+
return {
|
|
298
|
+
ok: false,
|
|
299
|
+
reason: "not_found"
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/** List a single directory level (cached, share-root-relative). */
|
|
304
|
+
async listDirectory(record, relativePath) {
|
|
305
|
+
if (record.kind !== "directory") throw new Error("Not a directory share");
|
|
306
|
+
const trimmed = (relativePath ?? "").replace(/^\/+/, "");
|
|
307
|
+
const cacheKey = `${record.id}::${trimmed}`;
|
|
308
|
+
const cacheTtl = this.config.directory.listingCacheMs;
|
|
309
|
+
const now = Date.now();
|
|
310
|
+
const cached = this.listingCache.get(cacheKey);
|
|
311
|
+
if (cached && cached.expiresAt > now) return cached.listing;
|
|
312
|
+
const resolved = await this.resolveDirectoryChild(record, trimmed);
|
|
313
|
+
if (resolved.ok !== true) throw new Error(resolved.reason);
|
|
314
|
+
const absDir = resolved.absolutePath;
|
|
315
|
+
if (!(await stat(absDir)).isDirectory()) throw new Error("not_directory");
|
|
316
|
+
const followSymlinks = record.directory?.followSymlinks ?? false;
|
|
317
|
+
const dirents = await readdir(absDir, { withFileTypes: true });
|
|
318
|
+
const entries = [];
|
|
319
|
+
let truncated = false;
|
|
320
|
+
const limit = 2e3;
|
|
321
|
+
for (const dirent of dirents) {
|
|
322
|
+
if (entries.length >= limit) {
|
|
323
|
+
truncated = true;
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
const childAbs = resolve(absDir, dirent.name);
|
|
327
|
+
try {
|
|
328
|
+
const childLstat = await lstat(childAbs);
|
|
329
|
+
if (childLstat.isSymbolicLink()) {
|
|
330
|
+
if (!followSymlinks) continue;
|
|
331
|
+
const real = await realpath(childAbs);
|
|
332
|
+
if (!isPathUnderWorkspace(record.workspaceRoot, real)) continue;
|
|
333
|
+
if (relative(record.absolutePath, real).startsWith("..")) continue;
|
|
334
|
+
}
|
|
335
|
+
const childStat = childLstat.isSymbolicLink() ? await stat(childAbs) : childLstat;
|
|
336
|
+
const childRel = trimmed ? `${trimmed}/${dirent.name}` : dirent.name;
|
|
337
|
+
entries.push({
|
|
338
|
+
name: dirent.name,
|
|
339
|
+
path: childRel,
|
|
340
|
+
isDirectory: childStat.isDirectory(),
|
|
341
|
+
size: childStat.isFile() ? childStat.size : 0,
|
|
342
|
+
mtime: childStat.mtime.toISOString(),
|
|
343
|
+
mimeType: childStat.isDirectory() ? "application/x-directory" : resolveMimeType(dirent.name)
|
|
344
|
+
});
|
|
345
|
+
} catch {}
|
|
346
|
+
}
|
|
347
|
+
entries.sort((a, b) => {
|
|
348
|
+
if (a.isDirectory !== b.isDirectory) return a.isDirectory ? -1 : 1;
|
|
349
|
+
return a.name.localeCompare(b.name);
|
|
350
|
+
});
|
|
351
|
+
const listing = {
|
|
352
|
+
path: trimmed,
|
|
353
|
+
entries,
|
|
354
|
+
truncated
|
|
355
|
+
};
|
|
356
|
+
if (cacheTtl > 0) this.listingCache.set(cacheKey, {
|
|
357
|
+
listing,
|
|
358
|
+
expiresAt: now + cacheTtl
|
|
359
|
+
});
|
|
360
|
+
return listing;
|
|
361
|
+
}
|
|
362
|
+
/** Update thumbnail status. Persists immediately so generator restart is safe. */
|
|
363
|
+
setThumbnailStatus(id, status) {
|
|
364
|
+
const record = this.shares.get(id);
|
|
365
|
+
if (!record) return;
|
|
366
|
+
record.thumbnailStatus = status;
|
|
367
|
+
if (status === "ready") record.thumbnailGeneratedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
368
|
+
if (status === "failed") record.thumbnailFailedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
369
|
+
this.persistSync();
|
|
370
|
+
}
|
|
371
|
+
/** Drop the listing cache for a share (used on revoke/update). */
|
|
372
|
+
invalidateListingCache(shareId) {
|
|
373
|
+
for (const key of this.listingCache.keys()) if (key.startsWith(`${shareId}::`)) this.listingCache.delete(key);
|
|
374
|
+
}
|
|
164
375
|
revoke(id) {
|
|
165
376
|
const record = this.shares.get(id);
|
|
166
377
|
if (!record) return false;
|
|
167
378
|
record.revoked = true;
|
|
379
|
+
this.invalidateListingCache(id);
|
|
168
380
|
this.persistSync();
|
|
169
381
|
logShareAudit("share.revoke", {
|
|
170
382
|
shareId: id,
|
|
@@ -179,6 +391,7 @@ var ShareStore = class {
|
|
|
179
391
|
const record = this.shares.get(id);
|
|
180
392
|
if (record && !record.revoked) {
|
|
181
393
|
record.revoked = true;
|
|
394
|
+
this.invalidateListingCache(id);
|
|
182
395
|
count++;
|
|
183
396
|
logShareAudit("share.revoke", {
|
|
184
397
|
shareId: id,
|
|
@@ -195,6 +408,7 @@ var ShareStore = class {
|
|
|
195
408
|
let count = 0;
|
|
196
409
|
for (const record of this.shares.values()) if (!record.revoked && now >= new Date(record.expiresAt).getTime()) {
|
|
197
410
|
record.revoked = true;
|
|
411
|
+
this.invalidateListingCache(record.id);
|
|
198
412
|
count++;
|
|
199
413
|
}
|
|
200
414
|
if (count > 0) this.persistSync();
|
|
@@ -265,16 +479,16 @@ var ShareStore = class {
|
|
|
265
479
|
}, null, 2)}\n`, "utf8");
|
|
266
480
|
}
|
|
267
481
|
scheduleDebouncedPersist() {
|
|
268
|
-
this.
|
|
269
|
-
if (this.
|
|
270
|
-
this.
|
|
271
|
-
this.
|
|
272
|
-
if (this.
|
|
273
|
-
this.
|
|
482
|
+
this.dirty = true;
|
|
483
|
+
if (this.debounceTimer) return;
|
|
484
|
+
this.debounceTimer = setTimeout(() => {
|
|
485
|
+
this.debounceTimer = null;
|
|
486
|
+
if (this.dirty) {
|
|
487
|
+
this.dirty = false;
|
|
274
488
|
this.persistSync();
|
|
275
489
|
}
|
|
276
|
-
},
|
|
277
|
-
this.
|
|
490
|
+
}, COUNTER_DEBOUNCE_MS);
|
|
491
|
+
this.debounceTimer.unref?.();
|
|
278
492
|
}
|
|
279
493
|
startCleanupTimer() {
|
|
280
494
|
this.cleanupTimer = setInterval(() => {
|
|
@@ -288,6 +502,15 @@ var ShareStore = class {
|
|
|
288
502
|
for (const [id, record] of this.shares) if (now - new Date(record.expiresAt).getTime() > EXPIRED_RETENTION_MS) {
|
|
289
503
|
this.shares.delete(id);
|
|
290
504
|
this.tokenIndex.delete(record.token);
|
|
505
|
+
this.invalidateListingCache(id);
|
|
506
|
+
if (this.onCleanup) try {
|
|
507
|
+
this.onCleanup(record);
|
|
508
|
+
} catch (err) {
|
|
509
|
+
log.warn({
|
|
510
|
+
err,
|
|
511
|
+
shareId: id
|
|
512
|
+
}, "Share cleanup hook threw");
|
|
513
|
+
}
|
|
291
514
|
removed++;
|
|
292
515
|
}
|
|
293
516
|
if (removed > 0) {
|
|
@@ -300,28 +523,63 @@ var ShareStore = class {
|
|
|
300
523
|
clearInterval(this.cleanupTimer);
|
|
301
524
|
this.cleanupTimer = null;
|
|
302
525
|
}
|
|
303
|
-
if (this.
|
|
304
|
-
clearTimeout(this.
|
|
305
|
-
this.
|
|
526
|
+
if (this.debounceTimer) {
|
|
527
|
+
clearTimeout(this.debounceTimer);
|
|
528
|
+
this.debounceTimer = null;
|
|
306
529
|
}
|
|
307
|
-
if (this.
|
|
308
|
-
this.
|
|
530
|
+
if (this.dirty) {
|
|
531
|
+
this.dirty = false;
|
|
309
532
|
this.persistSync();
|
|
310
533
|
}
|
|
534
|
+
this.listingCache.clear();
|
|
311
535
|
}
|
|
312
536
|
async resolveAndValidatePath(relPath, workspaceRoot) {
|
|
313
537
|
const trimmed = relPath.trim().replace(/\\/g, "/").replace(/^\/+/, "");
|
|
314
538
|
if (!trimmed) throw new Error("Empty path");
|
|
315
539
|
if (trimmed.includes("..")) throw new Error("Path traversal not allowed");
|
|
316
540
|
if (trimmed.includes("\0")) throw new Error("Invalid path");
|
|
317
|
-
const { resolve } = await import("node:path");
|
|
318
|
-
const { relative } = await import("node:path");
|
|
319
541
|
const abs = resolve(workspaceRoot, trimmed);
|
|
320
542
|
const relToRoot = relative(resolve(workspaceRoot), abs);
|
|
321
543
|
if (relToRoot.startsWith("..") || relToRoot.split(/[/\\]/).includes("..")) throw new Error("Path is outside workspace");
|
|
322
544
|
return abs;
|
|
323
545
|
}
|
|
324
546
|
};
|
|
547
|
+
async function scanDirectory(root, opts) {
|
|
548
|
+
let entryCount = 0;
|
|
549
|
+
let totalSize = 0;
|
|
550
|
+
async function walk(dir, depth) {
|
|
551
|
+
if (depth > opts.maxDepth) return;
|
|
552
|
+
const dirents = await readdir(dir, { withFileTypes: true });
|
|
553
|
+
for (const dirent of dirents) {
|
|
554
|
+
if (entryCount >= opts.maxFileCount) throw new Error(`Folder exceeds maxFileCount (${opts.maxFileCount})`);
|
|
555
|
+
const childAbs = resolve(dir, dirent.name);
|
|
556
|
+
const childLstat = await lstat(childAbs);
|
|
557
|
+
let effectiveStat = childLstat;
|
|
558
|
+
if (childLstat.isSymbolicLink()) {
|
|
559
|
+
if (!opts.followSymlinks) continue;
|
|
560
|
+
const real = await realpath(childAbs);
|
|
561
|
+
if (!isPathUnderWorkspace(opts.workspaceRoot, real)) throw new Error("Symlink target escapes workspace");
|
|
562
|
+
effectiveStat = await stat(childAbs);
|
|
563
|
+
}
|
|
564
|
+
if (effectiveStat.isFile()) {
|
|
565
|
+
entryCount++;
|
|
566
|
+
totalSize += effectiveStat.size;
|
|
567
|
+
if (totalSize > opts.maxFolderSize) {
|
|
568
|
+
const maxMb = (opts.maxFolderSize / 1048576).toFixed(0);
|
|
569
|
+
throw new Error(`Folder exceeds maxFolderSize (${maxMb} MB)`);
|
|
570
|
+
}
|
|
571
|
+
} else if (effectiveStat.isDirectory()) {
|
|
572
|
+
entryCount++;
|
|
573
|
+
await walk(childAbs, depth + 1);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
await walk(root, 0);
|
|
578
|
+
return {
|
|
579
|
+
entryCount,
|
|
580
|
+
totalSize
|
|
581
|
+
};
|
|
582
|
+
}
|
|
325
583
|
const MIME_BY_EXT = {
|
|
326
584
|
png: "image/png",
|
|
327
585
|
jpg: "image/jpeg",
|
|
@@ -337,6 +595,7 @@ const MIME_BY_EXT = {
|
|
|
337
595
|
html: "text/html",
|
|
338
596
|
css: "text/css",
|
|
339
597
|
js: "text/javascript",
|
|
598
|
+
mjs: "text/javascript",
|
|
340
599
|
ts: "text/typescript",
|
|
341
600
|
xml: "application/xml",
|
|
342
601
|
csv: "text/csv",
|
|
@@ -349,6 +608,12 @@ const MIME_BY_EXT = {
|
|
|
349
608
|
mp4: "video/mp4",
|
|
350
609
|
webm: "video/webm",
|
|
351
610
|
mov: "video/quicktime",
|
|
611
|
+
wasm: "application/wasm",
|
|
612
|
+
woff: "font/woff",
|
|
613
|
+
woff2: "font/woff2",
|
|
614
|
+
ttf: "font/ttf",
|
|
615
|
+
otf: "font/otf",
|
|
616
|
+
ico: "image/x-icon",
|
|
352
617
|
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
353
618
|
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
354
619
|
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
@@ -356,6 +621,12 @@ const MIME_BY_EXT = {
|
|
|
356
621
|
function resolveMimeType(fileName) {
|
|
357
622
|
return MIME_BY_EXT[fileName.split(".").pop()?.toLowerCase() ?? ""] || "application/octet-stream";
|
|
358
623
|
}
|
|
624
|
+
/** HTTP Content-Type with charset for text-like bodies (browser inline preview). */
|
|
625
|
+
function shareResponseContentType(mime) {
|
|
626
|
+
if (/;\s*charset=/i.test(mime)) return mime;
|
|
627
|
+
if (mime.startsWith("text/") || mime === "application/json" || mime === "application/javascript" || mime === "application/xml" || mime === "image/svg+xml") return `${mime}; charset=utf-8`;
|
|
628
|
+
return mime;
|
|
629
|
+
}
|
|
359
630
|
let singleton = null;
|
|
360
631
|
function getShareStore(config) {
|
|
361
632
|
if (!singleton) singleton = new ShareStore(config);
|
|
@@ -366,6 +637,6 @@ function resetShareStoreForTests() {
|
|
|
366
637
|
singleton = null;
|
|
367
638
|
}
|
|
368
639
|
//#endregion
|
|
369
|
-
export { ShareStore, getShareStore, resetShareStoreForTests };
|
|
640
|
+
export { ShareStore, getShareStore, resetShareStoreForTests, resolveMimeType, shareResponseContentType };
|
|
370
641
|
|
|
371
642
|
//# sourceMappingURL=share-store.js.map
|