@songsid/agend 2.2.0-alpha.9 → 2.2.0-beta.10
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/README.md +1 -1
- package/README.zh-TW.md +1 -1
- package/dist/agent-cli-instructions.md +16 -9
- package/dist/agent-cli.js +15 -7
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +21 -9
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-whats-new.d.ts +47 -0
- package/dist/agent-whats-new.js +147 -0
- package/dist/agent-whats-new.js.map +1 -0
- package/dist/auth-api.d.ts +2 -2
- package/dist/auth-api.js +4 -2
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/antigravity.d.ts +3 -0
- package/dist/backend/antigravity.js +9 -0
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-carry.d.ts +22 -0
- package/dist/backend/claude-carry.js +170 -0
- package/dist/backend/claude-carry.js.map +1 -0
- package/dist/backend/claude-code.d.ts +65 -2
- package/dist/backend/claude-code.js +226 -33
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-metadata.d.ts +33 -0
- package/dist/backend/codex-metadata.js +122 -18
- package/dist/backend/codex-metadata.js.map +1 -1
- package/dist/backend/codex.d.ts +3 -0
- package/dist/backend/codex.js +17 -1
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/credential-profile.d.ts +40 -3
- package/dist/backend/credential-profile.js +113 -5
- package/dist/backend/credential-profile.js.map +1 -1
- package/dist/backend/effort-metadata.d.ts +1 -1
- package/dist/backend/effort-metadata.js +3 -2
- package/dist/backend/effort-metadata.js.map +1 -1
- package/dist/backend/grok.d.ts +4 -0
- package/dist/backend/grok.js +14 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro-engine-ledger.d.ts +5 -0
- package/dist/backend/kiro-engine-ledger.js +20 -0
- package/dist/backend/kiro-engine-ledger.js.map +1 -1
- package/dist/backend/kiro-identity.d.ts +6 -0
- package/dist/backend/kiro-identity.js +19 -5
- package/dist/backend/kiro-identity.js.map +1 -1
- package/dist/backend/kiro.d.ts +39 -3
- package/dist/backend/kiro.js +143 -19
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/launch-effort.d.ts +33 -0
- package/dist/backend/launch-effort.js +123 -0
- package/dist/backend/launch-effort.js.map +1 -0
- package/dist/backend/muse.d.ts +84 -0
- package/dist/backend/muse.js +449 -53
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +33 -4
- package/dist/backend/types.js +2 -1
- package/dist/backend/types.js.map +1 -1
- package/dist/backend-command.d.ts +91 -0
- package/dist/backend-command.js +122 -0
- package/dist/backend-command.js.map +1 -0
- package/dist/background-work-ended.d.ts +18 -0
- package/dist/background-work-ended.js +30 -0
- package/dist/background-work-ended.js.map +1 -0
- package/dist/cache-service.d.ts +2 -0
- package/dist/cache-service.js +2 -1
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +26 -1
- package/dist/channel/adapters/discord.js +98 -3
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +26 -2
- package/dist/channel/adapters/telegram.js +123 -19
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-server.js +9 -1
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.d.ts +11 -0
- package/dist/channel/mcp-tools.js +24 -13
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/message-edit-errors.d.ts +5 -0
- package/dist/channel/message-edit-errors.js +24 -0
- package/dist/channel/message-edit-errors.js.map +1 -0
- package/dist/channel/telegram-markdown.d.ts +6 -0
- package/dist/channel/telegram-markdown.js +104 -0
- package/dist/channel/telegram-markdown.js.map +1 -0
- package/dist/channel/tool-router.js +9 -3
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/channel/types.d.ts +41 -3
- package/dist/cli.js +133 -28
- package/dist/cli.js.map +1 -1
- package/dist/command-table.d.ts +2 -2
- package/dist/command-table.js +6 -3
- package/dist/command-table.js.map +1 -1
- package/dist/config-validator.js +59 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/cross-instance-envelope.d.ts +15 -2
- package/dist/cross-instance-envelope.js +29 -5
- package/dist/cross-instance-envelope.js.map +1 -1
- package/dist/daemon.d.ts +156 -1
- package/dist/daemon.js +764 -89
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +62 -7
- package/dist/delivery-outbox.js +309 -22
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-reconciliation.d.ts +18 -1
- package/dist/delivery-reconciliation.js +67 -2
- package/dist/delivery-reconciliation.js.map +1 -1
- package/dist/fleet-context.d.ts +10 -1
- package/dist/fleet-manager.d.ts +352 -10
- package/dist/fleet-manager.js +1925 -175
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/backend-providers/SKILL.md +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +92 -21
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +27 -3
- package/dist/general-knowledge/skills/delegation-playbook/SKILL.md +8 -8
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +5 -5
- package/dist/general-knowledge/skills/fleet-health/SKILL.md +4 -4
- package/dist/general-knowledge/skills/fleet-restart/SKILL.md +13 -13
- package/dist/general-knowledge/skills/instance-lifecycle/SKILL.md +3 -2
- package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +6 -0
- package/dist/general-knowledge/skills/model-discovery/SKILL.md +9 -9
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +8 -2
- package/dist/general-knowledge/skills/scheduling/SKILL.md +5 -3
- package/dist/general-knowledge/skills/session-management/SKILL.md +6 -5
- package/dist/general-knowledge/skills/tui-effort/SKILL.md +2 -2
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +8 -3
- package/dist/general-knowledge/steering/core-rules.md +8 -7
- package/dist/host-memory.d.ts +10 -0
- package/dist/host-memory.js +33 -1
- package/dist/host-memory.js.map +1 -1
- package/dist/human-delivery-receipts.d.ts +83 -0
- package/dist/human-delivery-receipts.js +194 -0
- package/dist/human-delivery-receipts.js.map +1 -0
- package/dist/instance-avatar.d.ts +36 -0
- package/dist/instance-avatar.js +57 -0
- package/dist/instance-avatar.js.map +1 -0
- package/dist/instance-config-impact.js +6 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +29 -6
- package/dist/instance-lifecycle.js +79 -28
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +3 -1
- package/dist/instructions.js +11 -8
- package/dist/instructions.js.map +1 -1
- package/dist/kiro-log-gate.d.ts +42 -0
- package/dist/kiro-log-gate.js +39 -0
- package/dist/kiro-log-gate.js.map +1 -0
- package/dist/locale.js +204 -44
- package/dist/locale.js.map +1 -1
- package/dist/log-service.d.ts +99 -0
- package/dist/log-service.js +243 -0
- package/dist/log-service.js.map +1 -0
- package/dist/log-steps.d.ts +169 -0
- package/dist/log-steps.js +858 -0
- package/dist/log-steps.js.map +1 -0
- package/dist/login-controller.d.ts +20 -3
- package/dist/login-controller.js +71 -19
- package/dist/login-controller.js.map +1 -1
- package/dist/login-flows.d.ts +5 -2
- package/dist/login-flows.js +5 -4
- package/dist/login-flows.js.map +1 -1
- package/dist/memory-pressure.d.ts +13 -1
- package/dist/memory-pressure.js +50 -10
- package/dist/memory-pressure.js.map +1 -1
- package/dist/needs-you-hub.js +2 -0
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you-live.d.ts +6 -0
- package/dist/needs-you-live.js +23 -3
- package/dist/needs-you-live.js.map +1 -1
- package/dist/next-steps.js +1 -1
- package/dist/next-steps.js.map +1 -1
- package/dist/outbound-handlers.d.ts +100 -0
- package/dist/outbound-handlers.js +263 -96
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +26 -15
- package/dist/outbound-schemas.js +24 -7
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-link-progress.d.ts +1 -1
- package/dist/public-link-progress.js +8 -2
- package/dist/public-link-progress.js.map +1 -1
- package/dist/public-preview.d.ts +101 -0
- package/dist/public-preview.js +236 -0
- package/dist/public-preview.js.map +1 -0
- package/dist/public-web-gateway.js +11 -4
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +24 -1
- package/dist/public-web-link.js +63 -9
- package/dist/public-web-link.js.map +1 -1
- package/dist/reply-buttons-controller.d.ts +3 -0
- package/dist/reply-buttons-controller.js +3 -2
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/restart-guard.d.ts +6 -3
- package/dist/restart-guard.js +6 -3
- package/dist/restart-guard.js.map +1 -1
- package/dist/restart-progress.d.ts +33 -0
- package/dist/restart-progress.js +30 -0
- package/dist/restart-progress.js.map +1 -1
- package/dist/service-activation.d.ts +15 -7
- package/dist/service-activation.js +46 -29
- package/dist/service-activation.js.map +1 -1
- package/dist/service-installer.d.ts +31 -0
- package/dist/service-installer.js +41 -2
- package/dist/service-installer.js.map +1 -1
- package/dist/settings-api.js +85 -25
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +72 -1
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +28 -4
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.js +7 -0
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/setup-form.d.ts +1 -1
- package/dist/setup-form.js +1 -1
- package/dist/spawn-gate.js +5 -1
- package/dist/spawn-gate.js.map +1 -1
- package/dist/spawn-hold-reply.d.ts +12 -0
- package/dist/spawn-hold-reply.js +39 -0
- package/dist/spawn-hold-reply.js.map +1 -0
- package/dist/status-emojis.d.ts +10 -3
- package/dist/status-emojis.js +11 -2
- package/dist/status-emojis.js.map +1 -1
- package/dist/systemd-peer-bus.d.ts +95 -0
- package/dist/systemd-peer-bus.js +430 -0
- package/dist/systemd-peer-bus.js.map +1 -0
- package/dist/systemd-runtime.d.ts +27 -1
- package/dist/systemd-runtime.js +69 -7
- package/dist/systemd-runtime.js.map +1 -1
- package/dist/tips.js +4 -4
- package/dist/tips.js.map +1 -1
- package/dist/tool-progress.js +3 -2
- package/dist/tool-progress.js.map +1 -1
- package/dist/topic-commands.d.ts +42 -2
- package/dist/topic-commands.js +92 -7
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-delta-reader.d.ts +3 -3
- package/dist/transcript-delta-reader.js +8 -8
- package/dist/transcript-delta-reader.js.map +1 -1
- package/dist/transcript-jsonl.d.ts +80 -3
- package/dist/transcript-jsonl.js +147 -10
- package/dist/transcript-jsonl.js.map +1 -1
- package/dist/transcript-monitor.d.ts +19 -0
- package/dist/transcript-monitor.js +87 -15
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-sources.d.ts +78 -0
- package/dist/transcript-sources.js +375 -64
- package/dist/transcript-sources.js.map +1 -1
- package/dist/transcript-turns.d.ts +15 -2
- package/dist/transcript-turns.js +15 -2
- package/dist/transcript-turns.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +7 -15
- package/dist/tunnel/cloudflared.js +36 -1
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/purpose-lane.d.ts +5 -1
- package/dist/tunnel/purpose-lane.js +14 -7
- package/dist/tunnel/purpose-lane.js.map +1 -1
- package/dist/tunnel/types.d.ts +5 -1
- package/dist/tunnel/types.js.map +1 -1
- package/dist/turn-resume.d.ts +2 -0
- package/dist/turn-resume.js +1 -1
- package/dist/turn-resume.js.map +1 -1
- package/dist/types.d.ts +25 -0
- package/dist/ui/chat-commands.js +1 -0
- package/dist/ui/chat-emojis.js +33 -0
- package/dist/ui/chat-mentions.js +63 -0
- package/dist/ui/chat-render.js +42 -2
- package/dist/ui/chat-store.js +2 -2
- package/dist/ui/chat-strings.js +38 -20
- package/dist/ui/chat-thread.js +69 -12
- package/dist/ui/chat-time.js +80 -0
- package/dist/ui/panel-chat.js +39 -10
- package/dist/ui/panel-details.js +2 -0
- package/dist/ui/panel-fleet.js +199 -57
- package/dist/ui/panel-log.js +428 -0
- package/dist/ui/panel-needs.js +6 -2
- package/dist/ui/panel-settings.js +137 -32
- package/dist/ui/preview-panel.js +55 -15
- package/dist/ui/preview-status.js +28 -0
- package/dist/ui/preview.js +44 -3
- package/dist/ui/settings-dialogs.js +7 -2
- package/dist/ui/settings-model.js +2 -1
- package/dist/ui/settings-strings.js +46 -4
- package/dist/ui/settings-token.js +1 -1
- package/dist/ui/shared/app-i18n.js +43 -17
- package/dist/ui/shared/app-prefs.js +250 -0
- package/dist/ui/shared/app-route.js +7 -2
- package/dist/ui/shared/app-shell.js +165 -8
- package/dist/ui/shared/app-store.js +5 -1
- package/dist/ui/shared/app-stream.js +23 -5
- package/dist/ui/shared/app.css +159 -23
- package/dist/ui/shared/app.js +11 -1
- package/dist/ui/shared/fonts/README.md +1 -1
- package/dist/ui/shared/header-tools.js +55 -5
- package/dist/ui/shared/instance-nav.js +241 -45
- package/dist/ui/shared/instance-switch.js +4 -4
- package/dist/ui/shared/panel-view.js +6 -0
- package/dist/ui/shared/signin.js +7 -7
- package/dist/ui/shared/theme.js +39 -7
- package/dist/ui/shared/tokens.css +10 -1
- package/dist/ui/shared/ui-icons.js +1 -0
- package/dist/ui/shared/usage-dialog.js +23 -5
- package/dist/ui/shared/view-strings.js +32 -4
- package/dist/ui/signin.html +1 -1
- package/dist/unrecognised-prompt.d.ts +23 -0
- package/dist/unrecognised-prompt.js +74 -0
- package/dist/unrecognised-prompt.js.map +1 -0
- package/dist/update-install.d.ts +28 -2
- package/dist/update-install.js +22 -4
- package/dist/update-install.js.map +1 -1
- package/dist/update-marker.d.ts +51 -0
- package/dist/update-marker.js +61 -0
- package/dist/update-marker.js.map +1 -1
- package/dist/update-preflight.d.ts +100 -0
- package/dist/update-preflight.js +264 -0
- package/dist/update-preflight.js.map +1 -0
- package/dist/updater-caller.d.ts +31 -0
- package/dist/updater-caller.js +109 -0
- package/dist/updater-caller.js.map +1 -0
- package/dist/usage/i18n-keys.d.ts +1 -1
- package/dist/usage/i18n-keys.js +1 -1
- package/dist/usage/i18n-keys.js.map +1 -1
- package/dist/usage/providers.d.ts +34 -5
- package/dist/usage/providers.js +160 -27
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/statusline-usage.d.ts +6 -2
- package/dist/usage/statusline-usage.js +10 -4
- package/dist/usage/statusline-usage.js.map +1 -1
- package/dist/view-api.d.ts +1 -1
- package/dist/view-api.js +38 -8
- package/dist/view-api.js.map +1 -1
- package/dist/wake-coordinator.d.ts +11 -0
- package/dist/wake-coordinator.js +38 -4
- package/dist/wake-coordinator.js.map +1 -1
- package/dist/web-api.d.ts +49 -2
- package/dist/web-api.js +421 -31
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.d.ts +2 -2
- package/dist/web-auth.js +9 -4
- package/dist/web-auth.js.map +1 -1
- package/dist/web-commands.d.ts +27 -4
- package/dist/web-commands.js +19 -4
- package/dist/web-commands.js.map +1 -1
- package/dist/web-host-guard.d.ts +3 -11
- package/dist/web-host-guard.js +3 -12
- package/dist/web-host-guard.js.map +1 -1
- package/dist/web-images.d.ts +47 -0
- package/dist/web-images.js +169 -0
- package/dist/web-images.js.map +1 -0
- package/dist/web-mentions.d.ts +44 -0
- package/dist/web-mentions.js +75 -0
- package/dist/web-mentions.js.map +1 -0
- package/dist/web-prefs.d.ts +63 -0
- package/dist/web-prefs.js +265 -0
- package/dist/web-prefs.js.map +1 -0
- package/dist/web-preview.d.ts +14 -1
- package/dist/web-preview.js +35 -13
- package/dist/web-preview.js.map +1 -1
- package/dist/web-reply-files.d.ts +45 -0
- package/dist/web-reply-files.js +223 -0
- package/dist/web-reply-files.js.map +1 -0
- package/dist/web-schedules.d.ts +12 -0
- package/dist/web-schedules.js +34 -0
- package/dist/web-schedules.js.map +1 -0
- package/dist/web-server-drain.d.ts +10 -0
- package/dist/web-server-drain.js +50 -0
- package/dist/web-server-drain.js.map +1 -0
- package/dist/web-session.d.ts +36 -1
- package/dist/web-session.js +53 -6
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +23 -0
- package/dist/web-settings-patch.js +77 -0
- package/dist/web-settings-patch.js.map +1 -0
- package/dist/web-shell-routes.d.ts +5 -1
- package/dist/web-shell-routes.js +10 -1
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/web-upload.d.ts +17 -4
- package/dist/web-upload.js +64 -13
- package/dist/web-upload.js.map +1 -1
- package/dist/workflow-templates/default.md +1 -1
- package/package.json +1 -1
- package/templates/launchd.plist.ejs +3 -1
- package/templates/systemd.service.ejs +2 -1
package/dist/web-host-guard.js
CHANGED
|
@@ -103,24 +103,15 @@ export function applyWebSecurityHeaders(res) {
|
|
|
103
103
|
res.setHeader("Cache-Control", "no-store");
|
|
104
104
|
}
|
|
105
105
|
/**
|
|
106
|
-
* The
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* source only: script still cannot connect or post anywhere but this origin. What it gives up is that Discord sees the
|
|
110
|
-
* viewer's address when the editor is open (the request carries no referrer — EmojiImg sets no-referrer).
|
|
111
|
-
*/
|
|
112
|
-
export const DISCORD_EMOJI_IMG_SRC = "https://cdn.discordapp.com/emojis/";
|
|
113
|
-
/**
|
|
114
|
-
* The panel policy for one response: WEB_CONTENT_SECURITY_POLICY with this response's nonce for scripts and styles,
|
|
115
|
-
* Discord's emoji CDN for images (DISCORD_EMOJI_IMG_SRC),
|
|
116
|
-
* and — for /ui only, when a preview origin was chosen for this load (#1306) — `frame-src <preview origin>/frame`:
|
|
106
|
+
* The panel policy for one response: WEB_CONTENT_SECURITY_POLICY with this response's nonce for scripts and styles —
|
|
107
|
+
* images stay 'self' (#1630: Discord's emoji pictures come from the dashboard's own /ui/img/emoji/, so no remote image
|
|
108
|
+
* source is admitted any more, and Discord never sees a viewer's address) — and — for /ui only, when a preview origin was chosen for this load (#1306) — `frame-src <preview origin>/frame`:
|
|
117
109
|
* path-scoped, so nothing else of that origin can be framed or navigated to. Without it, frames fall back to
|
|
118
110
|
* default-src 'self'.
|
|
119
111
|
*/
|
|
120
112
|
export function panelContentSecurityPolicy(nonce, opts = {}) {
|
|
121
113
|
let policy = rewriteDirective(WEB_CONTENT_SECURITY_POLICY, "script-src 'self'", `script-src 'self' 'nonce-${nonce}'`);
|
|
122
114
|
policy = rewriteDirective(policy, "style-src 'self'", `style-src 'self' 'nonce-${nonce}'`);
|
|
123
|
-
policy = rewriteDirective(policy, "img-src 'self' data: blob:", `img-src 'self' data: blob: ${DISCORD_EMOJI_IMG_SRC}`);
|
|
124
115
|
if (opts.frameSrc)
|
|
125
116
|
policy = `${policy}; frame-src ${opts.frameSrc}`;
|
|
126
117
|
// #1589: the app shell's audio/video — exactly <dashboard origin>/ui/file/ (or 'none'); without it media falls back
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-host-guard.js","sourceRoot":"","sources":["../src/web-host-guard.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"web-host-guard.js","sourceRoot":"","sources":["../src/web-host-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { StickerPreview } from "./channel/types.js";
|
|
2
|
+
export declare const WEB_IMAGE_MAX_AGE_MS: number;
|
|
3
|
+
export declare const WEB_IMAGE_RETRY_MS: number;
|
|
4
|
+
/** Files not refreshed for this long (an emoji no longer used, a removed connection) are deleted on the next write. */
|
|
5
|
+
export declare const WEB_IMAGE_PRUNE_MS: number;
|
|
6
|
+
export declare const WEB_IMAGE_MAX_BYTES: number;
|
|
7
|
+
/** The picture type of an uploaded file by its extension (View's profile avatars), or null for anything else. */
|
|
8
|
+
export declare function imageMimeForFile(name: string): string | null;
|
|
9
|
+
export interface CachedImage {
|
|
10
|
+
readonly bytes: Buffer;
|
|
11
|
+
readonly mime: string;
|
|
12
|
+
readonly version: string;
|
|
13
|
+
}
|
|
14
|
+
/** What a fetch found: the picture, or null when there is none (the bot has no avatar). Throws when it failed. */
|
|
15
|
+
export type ImageLoader = () => Promise<StickerPreview | null>;
|
|
16
|
+
export declare class WebImageCache {
|
|
17
|
+
private readonly opts;
|
|
18
|
+
private readonly inflight;
|
|
19
|
+
/** key → when it may be asked again (monotonic ms), after a failure or a "none". */
|
|
20
|
+
private readonly quietUntil;
|
|
21
|
+
constructor(opts: {
|
|
22
|
+
dir: string;
|
|
23
|
+
now?: () => number;
|
|
24
|
+
mono?: () => number;
|
|
25
|
+
maxAgeMs?: number;
|
|
26
|
+
retryMs?: number;
|
|
27
|
+
onError?: (key: string, err: unknown) => void;
|
|
28
|
+
});
|
|
29
|
+
private get now();
|
|
30
|
+
private get mono();
|
|
31
|
+
private base;
|
|
32
|
+
private find;
|
|
33
|
+
private stale;
|
|
34
|
+
/** What is on disk now (fresh or stale), as a version for the page's URL; a stale or missing one is refreshed in the background. */
|
|
35
|
+
peek(key: string, loader: ImageLoader): {
|
|
36
|
+
version: string;
|
|
37
|
+
} | null;
|
|
38
|
+
/** The bytes on disk, or null. Never fetches. */
|
|
39
|
+
read(key: string): CachedImage | null;
|
|
40
|
+
/** The bytes, fetching first when nothing is on disk yet (a stale file is served and refreshed behind). */
|
|
41
|
+
get(key: string, loader: ImageLoader): Promise<CachedImage | null>;
|
|
42
|
+
/** One fetch per key at a time; none while the key is quiet (after a failure or a "none"). Never throws. */
|
|
43
|
+
refresh(key: string, loader: ImageLoader): Promise<void>;
|
|
44
|
+
private write;
|
|
45
|
+
private remove;
|
|
46
|
+
private prune;
|
|
47
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #1630: images the web app shows that come from a chat platform — a bot's own avatar, a Discord server's custom
|
|
3
|
+
* emoji — fetched on the host with the token the adapter already holds, kept on disk, and served same-origin (the page
|
|
4
|
+
* never loads cdn.discordapp.com or a Telegram file URL, and CSP img-src stays 'self').
|
|
5
|
+
*
|
|
6
|
+
* - On disk under `<AGEND_HOME>/cache/<kind>/`, one file per key, named by a hash of the key (a key never becomes a
|
|
7
|
+
* path), written to a temp file and renamed.
|
|
8
|
+
* - Refreshed at most once a day: the file's age is wall-clock (mtime — it must survive a restart). A stale file is
|
|
9
|
+
* still served while the refresh runs in the background.
|
|
10
|
+
* - A failed fetch keeps the file it had; the key is then not retried for an hour. A fetch that says there is no image
|
|
11
|
+
* (a bot with no avatar) removes the file, and is not asked again for a day. Those two waits are in-memory durations:
|
|
12
|
+
* monotonic clock.
|
|
13
|
+
* - Never more than one fetch per key at a time. Nothing here blocks a caller: `peek` starts a refresh and returns
|
|
14
|
+
* what is on disk now; only `get` (a first request for an emoji nobody has fetched yet) waits for one.
|
|
15
|
+
*/
|
|
16
|
+
import { createHash } from "node:crypto";
|
|
17
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
import { performance } from "node:perf_hooks";
|
|
20
|
+
export const WEB_IMAGE_MAX_AGE_MS = 24 * 60 * 60_000;
|
|
21
|
+
export const WEB_IMAGE_RETRY_MS = 60 * 60_000;
|
|
22
|
+
/** Files not refreshed for this long (an emoji no longer used, a removed connection) are deleted on the next write. */
|
|
23
|
+
export const WEB_IMAGE_PRUNE_MS = 30 * WEB_IMAGE_MAX_AGE_MS;
|
|
24
|
+
export const WEB_IMAGE_MAX_BYTES = 256 * 1024;
|
|
25
|
+
const MIME = { png: "image/png", jpg: "image/jpeg", webp: "image/webp", gif: "image/gif" };
|
|
26
|
+
const EXTS = Object.keys(MIME);
|
|
27
|
+
/** The picture type of an uploaded file by its extension (View's profile avatars), or null for anything else. */
|
|
28
|
+
export function imageMimeForFile(name) {
|
|
29
|
+
const ext = /\.([a-z]+)$/i.exec(name)?.[1]?.toLowerCase();
|
|
30
|
+
return ext === "jpeg" ? MIME.jpg : ext && Object.hasOwn(MIME, ext) ? MIME[ext] : null;
|
|
31
|
+
}
|
|
32
|
+
export class WebImageCache {
|
|
33
|
+
opts;
|
|
34
|
+
inflight = new Map();
|
|
35
|
+
/** key → when it may be asked again (monotonic ms), after a failure or a "none". */
|
|
36
|
+
quietUntil = new Map();
|
|
37
|
+
constructor(opts) {
|
|
38
|
+
this.opts = opts;
|
|
39
|
+
}
|
|
40
|
+
get now() { return (this.opts.now ?? Date.now)(); }
|
|
41
|
+
get mono() { return (this.opts.mono ?? (() => performance.now()))(); }
|
|
42
|
+
base(key) { return createHash("sha256").update(key).digest("hex").slice(0, 32); }
|
|
43
|
+
find(key) {
|
|
44
|
+
const base = this.base(key);
|
|
45
|
+
for (const ext of EXTS) {
|
|
46
|
+
const path = join(this.opts.dir, `${base}.${ext}`);
|
|
47
|
+
try {
|
|
48
|
+
if (existsSync(path))
|
|
49
|
+
return { path, ext, mtimeMs: statSync(path).mtimeMs };
|
|
50
|
+
}
|
|
51
|
+
catch { /* raced with a refresh */ }
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
stale(mtimeMs) { return this.now - mtimeMs >= (this.opts.maxAgeMs ?? WEB_IMAGE_MAX_AGE_MS); }
|
|
56
|
+
/** What is on disk now (fresh or stale), as a version for the page's URL; a stale or missing one is refreshed in the background. */
|
|
57
|
+
peek(key, loader) {
|
|
58
|
+
const found = this.find(key);
|
|
59
|
+
if (!found || this.stale(found.mtimeMs))
|
|
60
|
+
void this.refresh(key, loader);
|
|
61
|
+
return found ? { version: Math.floor(found.mtimeMs).toString(36) } : null;
|
|
62
|
+
}
|
|
63
|
+
/** The bytes on disk, or null. Never fetches. */
|
|
64
|
+
read(key) {
|
|
65
|
+
const found = this.find(key);
|
|
66
|
+
if (!found)
|
|
67
|
+
return null;
|
|
68
|
+
try {
|
|
69
|
+
return { bytes: readFileSync(found.path), mime: MIME[found.ext], version: Math.floor(found.mtimeMs).toString(36) };
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** The bytes, fetching first when nothing is on disk yet (a stale file is served and refreshed behind). */
|
|
76
|
+
async get(key, loader) {
|
|
77
|
+
const found = this.find(key);
|
|
78
|
+
if (!found)
|
|
79
|
+
await this.refresh(key, loader);
|
|
80
|
+
else if (this.stale(found.mtimeMs))
|
|
81
|
+
void this.refresh(key, loader);
|
|
82
|
+
return this.read(key);
|
|
83
|
+
}
|
|
84
|
+
/** One fetch per key at a time; none while the key is quiet (after a failure or a "none"). Never throws. */
|
|
85
|
+
refresh(key, loader) {
|
|
86
|
+
const running = this.inflight.get(key);
|
|
87
|
+
if (running)
|
|
88
|
+
return running;
|
|
89
|
+
const quiet = this.quietUntil.get(key);
|
|
90
|
+
if (quiet !== undefined && this.mono < quiet)
|
|
91
|
+
return Promise.resolve();
|
|
92
|
+
// Started on a later tick, after it is registered: a loader that throws at once must still release the key.
|
|
93
|
+
const run = Promise.resolve().then(async () => {
|
|
94
|
+
try {
|
|
95
|
+
const got = await loader();
|
|
96
|
+
if (!got) {
|
|
97
|
+
this.remove(key);
|
|
98
|
+
this.quietUntil.set(key, this.mono + (this.opts.maxAgeMs ?? WEB_IMAGE_MAX_AGE_MS));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (!MIME[got.ext] || got.bytes.length === 0 || got.bytes.length > WEB_IMAGE_MAX_BYTES)
|
|
102
|
+
throw new Error("not a usable image");
|
|
103
|
+
this.write(key, got);
|
|
104
|
+
this.quietUntil.delete(key);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
this.quietUntil.set(key, this.mono + (this.opts.retryMs ?? WEB_IMAGE_RETRY_MS));
|
|
108
|
+
this.opts.onError?.(key, err);
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
if (this.inflight.get(key) === run)
|
|
112
|
+
this.inflight.delete(key);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
this.inflight.set(key, run);
|
|
116
|
+
return run;
|
|
117
|
+
}
|
|
118
|
+
write(key, image) {
|
|
119
|
+
mkdirSync(this.opts.dir, { recursive: true, mode: 0o700 });
|
|
120
|
+
const base = this.base(key), path = join(this.opts.dir, `${base}.${image.ext}`);
|
|
121
|
+
const tmp = `${path}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
122
|
+
try {
|
|
123
|
+
writeFileSync(tmp, image.bytes, { mode: 0o600 });
|
|
124
|
+
renameSync(tmp, path);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
try {
|
|
128
|
+
unlinkSync(tmp);
|
|
129
|
+
}
|
|
130
|
+
catch { /* never created */ }
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
133
|
+
for (const ext of EXTS)
|
|
134
|
+
if (ext !== image.ext) {
|
|
135
|
+
try {
|
|
136
|
+
unlinkSync(join(this.opts.dir, `${base}.${ext}`));
|
|
137
|
+
}
|
|
138
|
+
catch { /* none */ }
|
|
139
|
+
}
|
|
140
|
+
this.prune();
|
|
141
|
+
}
|
|
142
|
+
remove(key) {
|
|
143
|
+
const base = this.base(key);
|
|
144
|
+
for (const ext of EXTS) {
|
|
145
|
+
try {
|
|
146
|
+
unlinkSync(join(this.opts.dir, `${base}.${ext}`));
|
|
147
|
+
}
|
|
148
|
+
catch { /* none */ }
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
prune() {
|
|
152
|
+
let names;
|
|
153
|
+
try {
|
|
154
|
+
names = readdirSync(this.opts.dir);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
for (const name of names) {
|
|
160
|
+
const path = join(this.opts.dir, name);
|
|
161
|
+
try {
|
|
162
|
+
if (this.now - statSync(path).mtimeMs > WEB_IMAGE_PRUNE_MS)
|
|
163
|
+
unlinkSync(path);
|
|
164
|
+
}
|
|
165
|
+
catch { /* raced */ }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=web-images.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-images.js","sourceRoot":"","sources":["../src/web-images.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #1682: the names the web chat shows for Discord mentions (`<@id>`, `<@&id>`, `<#id>`) — design: the comment on #1682.
|
|
3
|
+
*
|
|
4
|
+
* Asked by id, a few at a time (GET /ui/mentions?u=…&r=…&c=…: the ids a page found in what it rendered), answered
|
|
5
|
+
* without any Discord request: the fleet's own bots (their instance's label — fleet.yaml and the View profiles in
|
|
6
|
+
* profiles.db), the people seen on inbound messages (a bounded LRU), and what the Discord adapters already hold in
|
|
7
|
+
* their caches. A page never gets a directory: only the names of the ids it asked for.
|
|
8
|
+
*/
|
|
9
|
+
export type MentionKind = "u" | "r" | "c";
|
|
10
|
+
export interface MentionQuery {
|
|
11
|
+
u: string[];
|
|
12
|
+
r: string[];
|
|
13
|
+
c: string[];
|
|
14
|
+
}
|
|
15
|
+
export type MentionNames = {
|
|
16
|
+
u: Record<string, string>;
|
|
17
|
+
r: Record<string, string>;
|
|
18
|
+
c: Record<string, string>;
|
|
19
|
+
};
|
|
20
|
+
/** At most this many ids in one request (all kinds together). */
|
|
21
|
+
export declare const MAX_MENTION_IDS = 100;
|
|
22
|
+
/** People remembered from inbound messages. */
|
|
23
|
+
export declare const MAX_SEEN_USERS = 1000;
|
|
24
|
+
/** `?u=1,2&r=3&c=4` → the ids, or why not: digits only (a Discord id), at most MAX_MENTION_IDS, no other parameter. */
|
|
25
|
+
export declare function parseMentionQuery(params: URLSearchParams): {
|
|
26
|
+
ok: true;
|
|
27
|
+
query: MentionQuery;
|
|
28
|
+
} | {
|
|
29
|
+
ok: false;
|
|
30
|
+
error: string;
|
|
31
|
+
};
|
|
32
|
+
/** The people seen on inbound messages: id → the name they wrote under, most recent last; the oldest go first. */
|
|
33
|
+
export declare class SeenUsers {
|
|
34
|
+
private readonly max;
|
|
35
|
+
private readonly names;
|
|
36
|
+
constructor(max?: number);
|
|
37
|
+
record(id: string, name: string): void;
|
|
38
|
+
get(id: string): string | undefined;
|
|
39
|
+
get size(): number;
|
|
40
|
+
}
|
|
41
|
+
/** One source of names: what it knows for the asked ids (leaving out what it does not). */
|
|
42
|
+
export type MentionSource = (query: MentionQuery) => Partial<MentionNames>;
|
|
43
|
+
/** The names for a query from the sources, in order: the first that knows an id names it. Own keys only. */
|
|
44
|
+
export declare function resolveMentions(query: MentionQuery, sources: MentionSource[]): MentionNames;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** At most this many ids in one request (all kinds together). */
|
|
2
|
+
export const MAX_MENTION_IDS = 100;
|
|
3
|
+
/** People remembered from inbound messages. */
|
|
4
|
+
export const MAX_SEEN_USERS = 1000;
|
|
5
|
+
const SNOWFLAKE = /^\d{15,25}$/;
|
|
6
|
+
/** `?u=1,2&r=3&c=4` → the ids, or why not: digits only (a Discord id), at most MAX_MENTION_IDS, no other parameter. */
|
|
7
|
+
export function parseMentionQuery(params) {
|
|
8
|
+
const query = { u: [], r: [], c: [] };
|
|
9
|
+
let total = 0;
|
|
10
|
+
for (const key of params.keys())
|
|
11
|
+
if (key !== "u" && key !== "r" && key !== "c")
|
|
12
|
+
return { ok: false, error: `unknown parameter: ${key.slice(0, 16)}` };
|
|
13
|
+
for (const kind of ["u", "r", "c"]) {
|
|
14
|
+
for (const raw of params.getAll(kind)) {
|
|
15
|
+
for (const id of raw.split(",")) {
|
|
16
|
+
if (!id)
|
|
17
|
+
continue;
|
|
18
|
+
if (!SNOWFLAKE.test(id))
|
|
19
|
+
return { ok: false, error: "ids are Discord ids (digits)" };
|
|
20
|
+
if (!query[kind].includes(id)) {
|
|
21
|
+
query[kind].push(id);
|
|
22
|
+
total++;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (total > MAX_MENTION_IDS)
|
|
28
|
+
return { ok: false, error: `at most ${MAX_MENTION_IDS} ids` };
|
|
29
|
+
return { ok: true, query };
|
|
30
|
+
}
|
|
31
|
+
/** The people seen on inbound messages: id → the name they wrote under, most recent last; the oldest go first. */
|
|
32
|
+
export class SeenUsers {
|
|
33
|
+
max;
|
|
34
|
+
names = new Map();
|
|
35
|
+
constructor(max = MAX_SEEN_USERS) {
|
|
36
|
+
this.max = max;
|
|
37
|
+
}
|
|
38
|
+
record(id, name) {
|
|
39
|
+
if (!SNOWFLAKE.test(id) || typeof name !== "string" || !name.trim())
|
|
40
|
+
return;
|
|
41
|
+
this.names.delete(id);
|
|
42
|
+
this.names.set(id, name.trim().slice(0, 100));
|
|
43
|
+
while (this.names.size > this.max)
|
|
44
|
+
this.names.delete(this.names.keys().next().value);
|
|
45
|
+
}
|
|
46
|
+
get(id) { return this.names.get(id); }
|
|
47
|
+
get size() { return this.names.size; }
|
|
48
|
+
}
|
|
49
|
+
/** The names for a query from the sources, in order: the first that knows an id names it. Own keys only. */
|
|
50
|
+
export function resolveMentions(query, sources) {
|
|
51
|
+
const out = { u: Object.create(null), r: Object.create(null), c: Object.create(null) };
|
|
52
|
+
for (const source of sources) {
|
|
53
|
+
let found;
|
|
54
|
+
try {
|
|
55
|
+
found = source(query);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
for (const kind of ["u", "r", "c"]) {
|
|
61
|
+
const got = found[kind];
|
|
62
|
+
if (!got)
|
|
63
|
+
continue;
|
|
64
|
+
for (const id of query[kind]) {
|
|
65
|
+
if (Object.hasOwn(out[kind], id) || !Object.hasOwn(got, id))
|
|
66
|
+
continue;
|
|
67
|
+
const name = got[id];
|
|
68
|
+
if (typeof name === "string" && name.trim())
|
|
69
|
+
out[kind][id] = name.trim().slice(0, 100);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { u: { ...out.u }, r: { ...out.r }, c: { ...out.c } };
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=web-mentions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-mentions.js","sourceRoot":"","sources":["../src/web-mentions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export declare const WEB_PREFS_FILE = "web-prefs.json";
|
|
2
|
+
export declare const OPERATOR = "operator";
|
|
3
|
+
/** #1664: at most this many favorites. */
|
|
4
|
+
export declare const MAX_FAVORITES = 50;
|
|
5
|
+
export declare const WEB_PREF_KEYS: readonly string[];
|
|
6
|
+
export declare function isWebPrefKey(key: string): boolean;
|
|
7
|
+
export interface WebPrefsView {
|
|
8
|
+
/** Every key that is set, and its value (a key not set has its default: the page's own). */
|
|
9
|
+
readonly values: Record<string, unknown>;
|
|
10
|
+
readonly rev: number;
|
|
11
|
+
/** The file could not be read: these are the defaults, and writes are refused until it is fixed. */
|
|
12
|
+
readonly unreadable?: true;
|
|
13
|
+
}
|
|
14
|
+
export type WebPrefsWrite = {
|
|
15
|
+
ok: true;
|
|
16
|
+
view: WebPrefsView;
|
|
17
|
+
changed: string[];
|
|
18
|
+
} | {
|
|
19
|
+
ok: false;
|
|
20
|
+
status: 400 | 503;
|
|
21
|
+
error: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* A request's `set`: own keys only, each known, each valid — or the first reason it is not. All or nothing.
|
|
25
|
+
* `exists`: whether an instance of that name is in the fleet now (#1664: a favorite must be one).
|
|
26
|
+
*/
|
|
27
|
+
export declare function parseWebPrefsPatch(set: unknown, exists?: (name: string) => boolean): {
|
|
28
|
+
ok: true;
|
|
29
|
+
patch: Map<string, unknown>;
|
|
30
|
+
} | {
|
|
31
|
+
ok: false;
|
|
32
|
+
error: string;
|
|
33
|
+
};
|
|
34
|
+
export declare class WebPrefsStore {
|
|
35
|
+
private readonly dir;
|
|
36
|
+
private readonly opts;
|
|
37
|
+
private state;
|
|
38
|
+
/**
|
|
39
|
+
* `exists` (#1664): whether an instance of that name is in the fleet now — a favorite that is not is never served,
|
|
40
|
+
* and is never accepted.
|
|
41
|
+
*/
|
|
42
|
+
constructor(dir: string, opts?: {
|
|
43
|
+
now?: () => number;
|
|
44
|
+
write?: (path: string, data: string) => void;
|
|
45
|
+
exists?: (name: string) => boolean;
|
|
46
|
+
});
|
|
47
|
+
/** parseWebPrefsPatch against this fleet. */
|
|
48
|
+
parsePatch(set: unknown): ReturnType<typeof parseWebPrefsPatch>;
|
|
49
|
+
get path(): string;
|
|
50
|
+
private load;
|
|
51
|
+
read(identity?: string): WebPrefsView;
|
|
52
|
+
rev(): number;
|
|
53
|
+
/** #1664: an instance was removed — drop it from every favorites list (a write, and a new rev, only if one had it). */
|
|
54
|
+
forgetInstance(name: string): void;
|
|
55
|
+
private viewOf;
|
|
56
|
+
/**
|
|
57
|
+
* Set (or, with null, clear) the patch's keys. `onlyIfUnset`: a device's first upload of what it had locally — only
|
|
58
|
+
* the keys the host does not have yet are taken, so the first device to arrive wins and the host wins from then on.
|
|
59
|
+
*/
|
|
60
|
+
write(identity: string, patch: Map<string, unknown>, opts?: {
|
|
61
|
+
onlyIfUnset?: boolean;
|
|
62
|
+
}): WebPrefsWrite;
|
|
63
|
+
}
|