toolroll 0.9.54 → 0.9.55
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/CHANGELOG.md +9 -0
- package/README.md +5 -4
- package/dist/agent-onboard.js +4 -1
- package/dist/approval-rules-ui.d.ts +3 -2
- package/dist/approval-rules-ui.js +15 -20
- package/dist/assignment-ui.d.ts +3 -2
- package/dist/assignment-ui.js +4 -11
- package/dist/backup-ui.d.ts +2 -1
- package/dist/backup-ui.js +16 -27
- package/dist/brand-mark.d.ts +3 -2
- package/dist/brand-mark.js +4 -4
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +25 -25
- package/dist/browser-shell.d.ts +2 -1
- package/dist/browser-shell.js +9 -9
- package/dist/browser-workspace.d.ts +2 -3
- package/dist/browser-workspace.js +0 -3
- package/dist/chat-polish.d.ts +5 -4
- package/dist/chat-polish.js +9 -10
- package/dist/check-levels-ui.d.ts +2 -1
- package/dist/check-levels-ui.js +26 -53
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +9 -3
- package/dist/coding-shipping-ui.d.ts +2 -1
- package/dist/coding-shipping-ui.js +6 -6
- package/dist/coding-ui.d.ts +3 -1
- package/dist/coding-ui.js +30 -29
- package/dist/contracts/cli.d.ts +1 -3
- package/dist/contracts/console-api.d.ts +1 -1
- package/dist/contracts/console-api.js +6 -5
- package/dist/contracts/health.d.ts +1 -3
- package/dist/control-ui.d.ts +5 -4
- package/dist/control-ui.js +9 -34
- package/dist/credentials-ui.d.ts +5 -4
- package/dist/credentials-ui.js +23 -24
- package/dist/demo-chat.d.ts +3 -3
- package/dist/demo-chat.js +29 -76
- package/dist/discord-settings.d.ts +3 -2
- package/dist/discord-settings.js +17 -42
- package/dist/envelope.js +10 -0
- package/dist/evidence-pack.d.ts +2 -1
- package/dist/evidence-pack.js +45 -49
- package/dist/export-ui.d.ts +7 -2
- package/dist/export-ui.js +4 -10
- package/dist/flow-gallery-ui.d.ts +4 -3
- package/dist/flow-gallery-ui.js +28 -43
- package/dist/flow-starters-ui.d.ts +2 -1
- package/dist/flow-starters-ui.js +12 -15
- package/dist/flow-triggers.d.ts +1 -0
- package/dist/flow-triggers.js +16 -14
- package/dist/flows-ui.d.ts +4 -3
- package/dist/flows-ui.js +19 -30
- package/dist/flows.js +2 -1
- package/dist/guides.js +108 -3
- package/dist/html.d.ts +76 -0
- package/dist/html.js +173 -0
- package/dist/integrations-ui.d.ts +2 -1
- package/dist/integrations-ui.js +19 -23
- package/dist/kits-ui.d.ts +5 -4
- package/dist/kits-ui.js +18 -20
- package/dist/knowledge-ui.d.ts +6 -5
- package/dist/knowledge-ui.js +26 -25
- package/dist/lead-context.d.ts +11 -1
- package/dist/lead-context.js +6 -8
- package/dist/ledger-view.d.ts +2 -1
- package/dist/ledger-view.js +27 -29
- package/dist/limits-ui.d.ts +2 -1
- package/dist/limits-ui.js +7 -7
- package/dist/live-bus.d.ts +50 -8
- package/dist/live-bus.js +133 -50
- package/dist/mcp-oauth.js +35 -36
- package/dist/models-ui.d.ts +2 -1
- package/dist/models-ui.js +25 -35
- package/dist/monitoring-ui.d.ts +4 -3
- package/dist/monitoring-ui.js +13 -26
- package/dist/openrouter-models.d.ts +2 -1
- package/dist/openrouter-models.js +5 -9
- package/dist/operate.js +11 -7
- package/dist/people-audit-ui.d.ts +2 -1
- package/dist/people-audit-ui.js +13 -13
- package/dist/policy-ui.d.ts +3 -2
- package/dist/policy-ui.js +17 -23
- package/dist/project-delete-ui.d.ts +4 -3
- package/dist/project-delete-ui.js +15 -27
- package/dist/pull-request-ui.d.ts +2 -1
- package/dist/pull-request-ui.js +17 -32
- package/dist/recipe-ui.d.ts +8 -7
- package/dist/recipe-ui.js +39 -32
- package/dist/release-adapters.d.ts +60 -0
- package/dist/release-adapters.js +435 -0
- package/dist/release-cli.d.ts +24 -0
- package/dist/release-cli.js +181 -0
- package/dist/release-gate.d.ts +80 -0
- package/dist/release-gate.js +150 -0
- package/dist/release-links.d.ts +29 -0
- package/dist/release-links.js +102 -0
- package/dist/release.d.ts +331 -0
- package/dist/release.js +550 -0
- package/dist/reply-shape.d.ts +2 -1
- package/dist/reply-shape.js +5 -5
- package/dist/repository-context-ui.d.ts +2 -1
- package/dist/repository-context-ui.js +2 -7
- package/dist/request-budget-ui.d.ts +2 -1
- package/dist/request-budget-ui.js +16 -16
- package/dist/result-review.d.ts +2 -3
- package/dist/result-review.js +3 -9
- package/dist/retention-ui.d.ts +7 -1
- package/dist/retention-ui.js +7 -11
- package/dist/serve.d.ts +11 -2
- package/dist/serve.js +69 -58
- package/dist/server/chat.d.ts +3 -6
- package/dist/server/chat.js +969 -1006
- package/dist/server/chrome.d.ts +291 -0
- package/dist/server/chrome.js +747 -0
- package/dist/server/console.css +2819 -0
- package/dist/server/flows.d.ts +2 -6
- package/dist/server/flows.js +840 -766
- package/dist/server/guards.d.ts +1 -1
- package/dist/server/guards.js +5 -2
- package/dist/server/handler-context.d.ts +1 -1
- package/dist/server/handler-context.js +1 -1
- package/dist/server/handler-registry.d.ts +8 -6
- package/dist/server/handler-registry.js +14 -2
- package/dist/server/http.d.ts +274 -0
- package/dist/server/http.js +239 -0
- package/dist/server/live.d.ts +34 -0
- package/dist/server/live.js +309 -0
- package/dist/server/pages.d.ts +2 -6
- package/dist/server/pages.js +808 -789
- package/dist/server/people-tokens.d.ts +1 -6
- package/dist/server/people-tokens.js +580 -572
- package/dist/server/remote.d.ts +4 -7
- package/dist/server/remote.js +37 -70
- package/dist/server/render-chat.d.ts +402 -0
- package/dist/server/render-chat.js +927 -0
- package/dist/server/render-pages.d.ts +535 -0
- package/dist/server/render-pages.js +1277 -0
- package/dist/server/render-people.d.ts +32 -0
- package/dist/server/render-people.js +121 -0
- package/dist/server/render-results.d.ts +744 -0
- package/dist/server/render-results.js +2237 -0
- package/dist/server/render-settings.d.ts +147 -0
- package/dist/server/render-settings.js +577 -0
- package/dist/server/render-tasks.d.ts +632 -0
- package/dist/server/render-tasks.js +2345 -0
- package/dist/server/request-context.d.ts +46 -0
- package/dist/server/request-context.js +17 -0
- package/dist/server/route-table.d.ts +25 -3
- package/dist/server/route-table.js +163 -75
- package/dist/server/runtime.d.ts +15 -7
- package/dist/server/runtime.js +7 -1
- package/dist/server/session.d.ts +138 -0
- package/dist/server/session.js +94 -0
- package/dist/server/settings.d.ts +1 -5
- package/dist/server/settings.js +2181 -2117
- package/dist/server/task-views.d.ts +11 -4
- package/dist/server/task-views.js +26 -22
- package/dist/server/tasks.d.ts +9 -9
- package/dist/server/tasks.js +1486 -1418
- package/dist/server-telemetry.d.ts +4 -3
- package/dist/server-telemetry.js +4 -8
- package/dist/skills-ui.d.ts +4 -3
- package/dist/skills-ui.js +14 -17
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +2 -1
- package/dist/slack-settings.d.ts +3 -2
- package/dist/slack-settings.js +17 -42
- package/dist/spend-ui.d.ts +2 -1
- package/dist/spend-ui.js +9 -32
- package/dist/sso-ui.d.ts +3 -2
- package/dist/sso-ui.js +26 -27
- package/dist/storage-ui.d.ts +2 -1
- package/dist/storage-ui.js +14 -33
- package/dist/surface.js +14 -3
- package/dist/task-composer.d.ts +2 -1
- package/dist/task-composer.js +7 -7
- package/dist/task-status.d.ts +4 -3
- package/dist/task-status.js +15 -16
- package/dist/team-http.d.ts +5 -9
- package/dist/team-http.js +5 -63
- package/dist/team-ui.d.ts +2 -1
- package/dist/team-ui.js +2 -5
- package/dist/teammates-ui.d.ts +5 -4
- package/dist/teammates-ui.js +61 -90
- package/dist/teams-settings.d.ts +3 -2
- package/dist/teams-settings.js +20 -31
- package/dist/telegram-settings.d.ts +3 -2
- package/dist/telegram-settings.js +14 -25
- package/dist/toolroll-update-ui.d.ts +3 -2
- package/dist/toolroll-update-ui.js +35 -39
- package/dist/tools-ui.d.ts +5 -2
- package/dist/tools-ui.js +31 -31
- package/dist/when-html.d.ts +11 -3
- package/dist/when-html.js +5 -6
- package/dist/workspace-ui.d.ts +4 -2
- package/dist/workspace-ui.js +10 -10
- package/package.json +1 -1
- package/dist/server/shared.d.ts +0 -3151
- package/dist/server/shared.js +0 -12001
package/dist/server/runtime.d.ts
CHANGED
|
@@ -32,7 +32,13 @@ import { createTeamRuntime } from '../team-runtime.js';
|
|
|
32
32
|
import { type ToolsView } from "../tools-ui.js";
|
|
33
33
|
import { type ReviewFacts } from "../workspace-ui.js";
|
|
34
34
|
import { WorktreePool } from "../worktree.js";
|
|
35
|
-
import {
|
|
35
|
+
import { type Chrome, type Screen } from "./chrome.js";
|
|
36
|
+
import { type ServeOptions } from "./http.js";
|
|
37
|
+
import { type ChatEnablement, type LiveTurn, type ReplacedThread, type TaskChatFocus } from "./render-chat.js";
|
|
38
|
+
import { type ProjectPeek } from "./render-pages.js";
|
|
39
|
+
import { type ResultDetail } from "./render-results.js";
|
|
40
|
+
import { taskBody, type PlanContractView, type PlanRevisionLedgerView, type RevisionDocView, type RevisionView, type RouteView } from "./render-tasks.js";
|
|
41
|
+
import { PersistentSessions, type Session, type SsoIntent, type Who } from "./session.js";
|
|
36
42
|
export interface ServerRuntime {
|
|
37
43
|
codingActorAllowed: (actor: {
|
|
38
44
|
name: string;
|
|
@@ -42,7 +48,7 @@ export interface ServerRuntime {
|
|
|
42
48
|
codingProjectAllowed: (repo: string) => boolean;
|
|
43
49
|
store: Store;
|
|
44
50
|
sendScreen: (response: ServerResponse, status: number, s: Screen) => void;
|
|
45
|
-
chromeFor: (project: string | null, active: Chrome["active"], listPane?:
|
|
51
|
+
chromeFor: (project: string | null, active: Chrome["active"], listPane?: import("../html.js").Html, scope?: Chrome["scope"]) => Chrome;
|
|
46
52
|
visible: (repo: string | null) => boolean;
|
|
47
53
|
managedRepos: () => string[];
|
|
48
54
|
codingProblem: string | undefined;
|
|
@@ -107,7 +113,8 @@ export interface ServerRuntime {
|
|
|
107
113
|
}) => VerifiedApprover | null;
|
|
108
114
|
chatScopeOf: (focusTask: TaskChatFocus | null, chatProject: string | null) => MateThreadScope;
|
|
109
115
|
liveTurns: Map<number, LiveTurn>;
|
|
110
|
-
|
|
116
|
+
/** A lead reply started on a thread: pages with that conversation open follow it (server/live.ts). */
|
|
117
|
+
liveTurnStarted: (thread: number) => void;
|
|
111
118
|
mateConversationRows: (who: Who & {
|
|
112
119
|
via: "cookie";
|
|
113
120
|
}, principal: VerifiedApprover, focusTask: TaskChatFocus | null, now: Date, chatProject?: string | null) => {
|
|
@@ -255,18 +262,19 @@ export interface ServerRuntime {
|
|
|
255
262
|
} | null;
|
|
256
263
|
CHAT_CANDIDATE_TTL_MS: number;
|
|
257
264
|
CHAT_CANDIDATES_PER_APPROVER: 9;
|
|
258
|
-
peekSay: (message: string, final?: boolean) =>
|
|
265
|
+
peekSay: (message: string, final?: boolean) => import("../html.js").Html;
|
|
259
266
|
peekCache: Map<string, {
|
|
260
|
-
fragment:
|
|
267
|
+
fragment: import("../html.js").Html;
|
|
268
|
+
bytes: number;
|
|
261
269
|
at: number;
|
|
262
270
|
}>;
|
|
263
271
|
PEEK_CACHE_TTL_MS: 10000;
|
|
264
272
|
peekCacheBytes: number;
|
|
265
|
-
peekInFlight: Map<string, Promise<
|
|
273
|
+
peekInFlight: Map<string, Promise<import("../html.js").Html>>;
|
|
266
274
|
PEEK_GLOBAL_INFLIGHT: 4;
|
|
267
275
|
peekBySession: Map<string, number>;
|
|
268
276
|
PEEK_SESSION_INFLIGHT: 2;
|
|
269
|
-
peekName: (path: string) =>
|
|
277
|
+
peekName: (path: string) => import("../html.js").Html;
|
|
270
278
|
PEEK_FRAGMENT_BYTES: number;
|
|
271
279
|
peekEvict: () => void;
|
|
272
280
|
allowedHost: (host: string | undefined) => boolean;
|
package/dist/server/runtime.js
CHANGED
|
@@ -22,4 +22,10 @@ import { createTeamRuntime } from '../team-runtime.js';
|
|
|
22
22
|
import {} from "../tools-ui.js";
|
|
23
23
|
import {} from "../workspace-ui.js";
|
|
24
24
|
import { WorktreePool } from "../worktree.js";
|
|
25
|
-
import {
|
|
25
|
+
import {} from "./chrome.js";
|
|
26
|
+
import {} from "./http.js";
|
|
27
|
+
import {} from "./render-chat.js";
|
|
28
|
+
import {} from "./render-pages.js";
|
|
29
|
+
import {} from "./render-results.js";
|
|
30
|
+
import { taskBody } from "./render-tasks.js";
|
|
31
|
+
import { PersistentSessions } from "./session.js";
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/** Browser sessions and the signed-in caller of a request. */
|
|
2
|
+
import { type ChatDraft } from "../converse.js";
|
|
3
|
+
import { type Principal } from "../operate-remote.js";
|
|
4
|
+
import { type Store } from "../store.js";
|
|
5
|
+
import { type Server } from "node:http";
|
|
6
|
+
/** A user agent, reduced to safe display words — never echoed raw. */
|
|
7
|
+
export declare function oneLineUa(raw: string | string[] | undefined): string;
|
|
8
|
+
export declare const SESSION_COOKIE = "standing-orders_session";
|
|
9
|
+
/** Stands in for "no project" in a ceiling: no folder resolves to it, so it admits nothing. */
|
|
10
|
+
export declare const NO_PROJECT = "/\0no-project";
|
|
11
|
+
/** Where `up`'s one-time sign-in link points, and how long it works. */
|
|
12
|
+
export declare const SIGN_IN_LINK_PATH = "/login/once/";
|
|
13
|
+
export declare const SIGN_IN_LINK_MS: number;
|
|
14
|
+
/** A cookie idles out after half a day and dies outright after a week. */
|
|
15
|
+
export declare const SESSION_IDLE_MS: number;
|
|
16
|
+
export declare const SESSION_ABSOLUTE_MS: number;
|
|
17
|
+
/** An approval nonce is a rendered form, not a standing right — it ages out fast. */
|
|
18
|
+
export declare const NONCE_TTL_MS: number;
|
|
19
|
+
export declare const NONCE_CAP = 500;
|
|
20
|
+
/** Read-only fragment polls that must never refresh session activity (arc 1). */
|
|
21
|
+
export declare const NO_TOUCH_FRAGMENTS: ReadonlySet<string>;
|
|
22
|
+
export type Session = {
|
|
23
|
+
name: string;
|
|
24
|
+
csrf: string;
|
|
25
|
+
/** v29: the account's standing at login — the central gate reads it;
|
|
26
|
+
* the revocation cascade kills the session outright. */
|
|
27
|
+
role: "approver" | "viewer";
|
|
28
|
+
/** The approver generation at login: credential rotation kills the cookie. */
|
|
29
|
+
generation: number;
|
|
30
|
+
createdAt: number;
|
|
31
|
+
lastSeen: number;
|
|
32
|
+
/** The open project — a VIEW FILTER chosen inside the ceiling, never authorization. */
|
|
33
|
+
project: string | null;
|
|
34
|
+
/** Bumped on every open: stale tabs carry the revision they were rendered under. */
|
|
35
|
+
projectRevision: number;
|
|
36
|
+
/** v100: signed in with the identity provider, and when it last checked them (a step-up within 10 minutes needs no password). */
|
|
37
|
+
sso?: {
|
|
38
|
+
at: number;
|
|
39
|
+
};
|
|
40
|
+
/** v101: the browser and address it signed in from, for the person to recognise it. */
|
|
41
|
+
agent?: string | null;
|
|
42
|
+
address?: string | null;
|
|
43
|
+
/** Onboarding preview records (arc: repo onboarding, finding 14) —
|
|
44
|
+
* session-held, swept at mint, at most 3, consumed exactly once. */
|
|
45
|
+
onboard?: Map<string, {
|
|
46
|
+
nameWithOwner: string;
|
|
47
|
+
rootIndex: number;
|
|
48
|
+
target: string;
|
|
49
|
+
diskUsageKib: number | null;
|
|
50
|
+
large: boolean;
|
|
51
|
+
mintedAt: number;
|
|
52
|
+
}>;
|
|
53
|
+
/** When this session last READ the board — the anchor for "since you
|
|
54
|
+
* last looked". Full page loads move it; fragment polls never do. */
|
|
55
|
+
sawBoardAt: number | null;
|
|
56
|
+
/** Fleet chat (v13): drafts and the last reply live HERE and nowhere
|
|
57
|
+
* durable — restart or logout loses them by design (v2 finding 12). */
|
|
58
|
+
chat?: SessionChat;
|
|
59
|
+
/** Editor links (arc 6): the SESSION's half of the activation — "this
|
|
60
|
+
* browser runs on the machine that holds the worktrees" is a statement
|
|
61
|
+
* only the person at the browser can make. Dies with the session. */
|
|
62
|
+
editorLinks?: boolean;
|
|
63
|
+
};
|
|
64
|
+
export type ChatCandidate = {
|
|
65
|
+
key: string;
|
|
66
|
+
draft: ChatDraft;
|
|
67
|
+
/** Resolved server-side at parse time from the opaque repoId. */
|
|
68
|
+
repoPath: string;
|
|
69
|
+
provider: string;
|
|
70
|
+
approver: string;
|
|
71
|
+
/** Digest of the frozen explicit repo list at turn time — filing
|
|
72
|
+
* re-proves it (v2 new finding 5). */
|
|
73
|
+
ceilingDigest: string;
|
|
74
|
+
createdAt: number;
|
|
75
|
+
state: "pending" | "filing";
|
|
76
|
+
};
|
|
77
|
+
export type SessionChat = {
|
|
78
|
+
candidates: Map<string, ChatCandidate>;
|
|
79
|
+
lastTurn: {
|
|
80
|
+
id: number;
|
|
81
|
+
reply: string | null;
|
|
82
|
+
staticError: string | null;
|
|
83
|
+
proposalsDiscarded: boolean;
|
|
84
|
+
} | null;
|
|
85
|
+
};
|
|
86
|
+
/** One rendered approval form: who saw which digest of which task, once. */
|
|
87
|
+
export type ApprovalNonce = {
|
|
88
|
+
name: string;
|
|
89
|
+
taskId: string;
|
|
90
|
+
digest: string;
|
|
91
|
+
expiresAt: number;
|
|
92
|
+
};
|
|
93
|
+
export type Who = {
|
|
94
|
+
name: string;
|
|
95
|
+
via: "cookie";
|
|
96
|
+
session: Session;
|
|
97
|
+
role: "approver" | "viewer";
|
|
98
|
+
} | {
|
|
99
|
+
name: string;
|
|
100
|
+
via: "bearer";
|
|
101
|
+
role: "approver" | "viewer"; /** v101: the API token it came with. */
|
|
102
|
+
token?: string;
|
|
103
|
+
/** The complete proved API-token authority, retained across body reads. */ principal?: Principal;
|
|
104
|
+
generation: number;
|
|
105
|
+
};
|
|
106
|
+
/** The browser session of a caller its route admits only through a browser sign-in (the row's callers or role). */
|
|
107
|
+
export declare function browserCaller(who: Who): Extract<Who, {
|
|
108
|
+
via: "cookie";
|
|
109
|
+
}>;
|
|
110
|
+
/**
|
|
111
|
+
* v101: browser sessions in memory and in the database (by a hash of the
|
|
112
|
+
* cookie, never the cookie), so a restart signs no one out and a person can
|
|
113
|
+
* see and end their sessions. The in-memory map is the working set; a cookie
|
|
114
|
+
* it hasn't seen is looked up by its hash.
|
|
115
|
+
*/
|
|
116
|
+
export declare class PersistentSessions extends Map<string, Session> {
|
|
117
|
+
private readonly db;
|
|
118
|
+
private readonly ids;
|
|
119
|
+
private readonly savedAt;
|
|
120
|
+
constructor(db: Store);
|
|
121
|
+
static hash(id: string): string;
|
|
122
|
+
set(id: string, session: Session): this;
|
|
123
|
+
delete(id: string): boolean;
|
|
124
|
+
/** Keep a changed session (its project, its provider check); `seen` only once a minute. */
|
|
125
|
+
persist(session: Session, seen?: boolean): void;
|
|
126
|
+
/** A cookie from before a restart, if its session is still kept. */
|
|
127
|
+
load(id: string): Session | null;
|
|
128
|
+
/** End one session by its kept hash (from the Sessions page). */
|
|
129
|
+
endByHash(idHash: string): void;
|
|
130
|
+
hashOf(session: Session): string | null;
|
|
131
|
+
}
|
|
132
|
+
/** The console's server, and the one-time sign-in link `up` opens: a path on this server, or null for no such approver.
|
|
133
|
+
* closeCoding starts the coding shutdown on its own, ahead of the rest of a stop; close() awaits the same promise. */
|
|
134
|
+
export type DecisionServer = Server & {
|
|
135
|
+
mintSignInLink(account: string): string | null;
|
|
136
|
+
closeCoding(): Promise<void>;
|
|
137
|
+
};
|
|
138
|
+
export type SsoIntent = "sign-in" | "reauth" | "link";
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/** Browser sessions and the signed-in caller of a request. */
|
|
2
|
+
import {} from "../converse.js";
|
|
3
|
+
import {} from "../operate-remote.js";
|
|
4
|
+
import {} from "../store.js";
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import {} from "node:http";
|
|
7
|
+
/** A user agent, reduced to safe display words — never echoed raw. */
|
|
8
|
+
export function oneLineUa(raw) {
|
|
9
|
+
const text = Array.isArray(raw) ? (raw[0] ?? "") : (raw ?? "");
|
|
10
|
+
if (/iphone|ipad/i.test(text))
|
|
11
|
+
return "an iPhone or iPad";
|
|
12
|
+
if (/android/i.test(text))
|
|
13
|
+
return "an Android device";
|
|
14
|
+
if (/mac os/i.test(text))
|
|
15
|
+
return "a Mac";
|
|
16
|
+
if (/windows/i.test(text))
|
|
17
|
+
return "a Windows machine";
|
|
18
|
+
return "a device";
|
|
19
|
+
}
|
|
20
|
+
export const SESSION_COOKIE = "standing-orders_session";
|
|
21
|
+
/** Stands in for "no project" in a ceiling: no folder resolves to it, so it admits nothing. */
|
|
22
|
+
export const NO_PROJECT = "/\0no-project";
|
|
23
|
+
/** Where `up`'s one-time sign-in link points, and how long it works. */
|
|
24
|
+
export const SIGN_IN_LINK_PATH = "/login/once/";
|
|
25
|
+
export const SIGN_IN_LINK_MS = 10 * 60_000;
|
|
26
|
+
/** A cookie idles out after half a day and dies outright after a week. */
|
|
27
|
+
export const SESSION_IDLE_MS = 12 * 60 * 60_000;
|
|
28
|
+
export const SESSION_ABSOLUTE_MS = 7 * 24 * 60 * 60_000;
|
|
29
|
+
/** An approval nonce is a rendered form, not a standing right — it ages out fast. */
|
|
30
|
+
export const NONCE_TTL_MS = 15 * 60_000;
|
|
31
|
+
export const NONCE_CAP = 500;
|
|
32
|
+
/** Read-only fragment polls that must never refresh session activity (arc 1). */
|
|
33
|
+
export const NO_TOUCH_FRAGMENTS = new Set(["1", "facts", "peek", "rail", "transcript"]);
|
|
34
|
+
/** The browser session of a caller its route admits only through a browser sign-in (the row's callers or role). */
|
|
35
|
+
export function browserCaller(who) {
|
|
36
|
+
if (who.via !== "cookie")
|
|
37
|
+
throw new Error("A browser-only route reached its handler without a browser session.");
|
|
38
|
+
return who;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* v101: browser sessions in memory and in the database (by a hash of the
|
|
42
|
+
* cookie, never the cookie), so a restart signs no one out and a person can
|
|
43
|
+
* see and end their sessions. The in-memory map is the working set; a cookie
|
|
44
|
+
* it hasn't seen is looked up by its hash.
|
|
45
|
+
*/
|
|
46
|
+
export class PersistentSessions extends Map {
|
|
47
|
+
db;
|
|
48
|
+
ids = new WeakMap();
|
|
49
|
+
savedAt = new WeakMap();
|
|
50
|
+
constructor(db) {
|
|
51
|
+
super();
|
|
52
|
+
this.db = db;
|
|
53
|
+
}
|
|
54
|
+
static hash(id) { return createHash("sha256").update(id, "utf8").digest("hex"); }
|
|
55
|
+
set(id, session) {
|
|
56
|
+
super.set(id, session);
|
|
57
|
+
this.ids.set(session, id);
|
|
58
|
+
this.persist(session);
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
delete(id) {
|
|
62
|
+
this.db.dropWebSession(PersistentSessions.hash(id));
|
|
63
|
+
return super.delete(id);
|
|
64
|
+
}
|
|
65
|
+
/** Keep a changed session (its project, its provider check); `seen` only once a minute. */
|
|
66
|
+
persist(session, seen = false) {
|
|
67
|
+
const id = this.ids.get(session);
|
|
68
|
+
if (id === undefined || (seen && Date.now() - (this.savedAt.get(session) ?? 0) < 60_000))
|
|
69
|
+
return;
|
|
70
|
+
this.savedAt.set(session, Date.now());
|
|
71
|
+
this.db.saveWebSession({ idHash: PersistentSessions.hash(id), account: session.name, csrf: session.csrf, role: session.role, generation: session.generation, createdAt: session.createdAt,
|
|
72
|
+
lastSeen: session.lastSeen, project: session.project, projectRevision: session.projectRevision, ssoAt: session.sso?.at ?? null, agent: session.agent ?? null, address: session.address ?? null });
|
|
73
|
+
}
|
|
74
|
+
/** A cookie from before a restart, if its session is still kept. */
|
|
75
|
+
load(id) {
|
|
76
|
+
const row = this.db.webSession(PersistentSessions.hash(id));
|
|
77
|
+
if (row === null)
|
|
78
|
+
return null;
|
|
79
|
+
const session = { name: row.account, csrf: row.csrf, role: row.role, generation: row.generation, createdAt: row.createdAt, lastSeen: row.lastSeen, sawBoardAt: null,
|
|
80
|
+
project: row.project, projectRevision: row.projectRevision, agent: row.agent, address: row.address, ...(row.ssoAt === null ? {} : { sso: { at: row.ssoAt } }) };
|
|
81
|
+
super.set(id, session);
|
|
82
|
+
this.ids.set(session, id);
|
|
83
|
+
this.savedAt.set(session, Date.now());
|
|
84
|
+
return session;
|
|
85
|
+
}
|
|
86
|
+
/** End one session by its kept hash (from the Sessions page). */
|
|
87
|
+
endByHash(idHash) {
|
|
88
|
+
for (const id of [...this.keys()])
|
|
89
|
+
if (PersistentSessions.hash(id) === idHash)
|
|
90
|
+
super.delete(id);
|
|
91
|
+
this.db.dropWebSession(idHash);
|
|
92
|
+
}
|
|
93
|
+
hashOf(session) { const id = this.ids.get(session); return id === undefined ? null : PersistentSessions.hash(id); }
|
|
94
|
+
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import type { HandlerContext } from './handler-context.js';
|
|
2
|
-
import type { Registration } from './handler-registry.js';
|
|
3
1
|
import type { ServerRuntime } from './runtime.js';
|
|
4
2
|
import { type RoleView } from "../models-ui.js";
|
|
5
3
|
export declare function createSettingsHandlers(runtime: ServerRuntime): {
|
|
6
|
-
registrations: Registration[];
|
|
7
|
-
get: (ctx: HandlerContext) => Promise<void>;
|
|
8
|
-
post: (ctx: HandlerContext) => Promise<void>;
|
|
4
|
+
registrations: import("./handler-registry.js").Registration[];
|
|
9
5
|
modelsView: (canManage: boolean, csrf: string, now: Date, said: string | null, problem: string | null) => {
|
|
10
6
|
runtimes: import("../model-catalog.js").RuntimeState[];
|
|
11
7
|
watch: import("../model-catalog.js").WatchState;
|