@kortix/sdk 0.12.8 → 0.13.1
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 +3 -6
- package/dist/browser/session-sync/session-sync-registry.d.ts +7 -2
- package/dist/browser/session-sync/session-sync-registry.d.ts.map +1 -1
- package/dist/browser/session-sync/session-sync-registry.js +33 -44
- package/dist/browser/session-sync/session-sync-registry.js.map +1 -1
- package/dist/browser/session-sync/session-transcript-cache.d.ts +9 -2
- package/dist/browser/session-sync/session-transcript-cache.d.ts.map +1 -1
- package/dist/browser/session-sync/session-transcript-cache.js +15 -5
- package/dist/browser/session-sync/session-transcript-cache.js.map +1 -1
- package/dist/browser/stores/opencode-compaction-store.d.ts +9 -3
- package/dist/browser/stores/opencode-compaction-store.d.ts.map +1 -1
- package/dist/browser/stores/opencode-compaction-store.js +5 -12
- package/dist/browser/stores/opencode-compaction-store.js.map +1 -1
- package/dist/browser/stores/sandbox-connection-store.d.ts +28 -17
- package/dist/browser/stores/sandbox-connection-store.d.ts.map +1 -1
- package/dist/browser/stores/sandbox-connection-store.js +32 -84
- package/dist/browser/stores/sandbox-connection-store.js.map +1 -1
- package/dist/browser/stores/session-working-store.d.ts +73 -0
- package/dist/browser/stores/session-working-store.d.ts.map +1 -0
- package/dist/browser/stores/session-working-store.js +86 -0
- package/dist/browser/stores/session-working-store.js.map +1 -0
- package/dist/browser/stores/sync-store/types.d.ts +14 -4
- package/dist/browser/stores/sync-store/types.d.ts.map +1 -1
- package/dist/browser/stores/sync-store.d.ts +179 -4
- package/dist/browser/stores/sync-store.d.ts.map +1 -1
- package/dist/browser/stores/sync-store.js +777 -65
- package/dist/browser/stores/sync-store.js.map +1 -1
- package/dist/core/client/kortix.d.ts +95 -0
- package/dist/core/client/kortix.d.ts.map +1 -1
- package/dist/core/client/kortix.js +78 -0
- package/dist/core/client/kortix.js.map +1 -1
- package/dist/core/files/client.d.ts +50 -2
- package/dist/core/files/client.d.ts.map +1 -1
- package/dist/core/files/client.js +253 -44
- package/dist/core/files/client.js.map +1 -1
- package/dist/core/files/types.d.ts +11 -0
- package/dist/core/files/types.d.ts.map +1 -1
- package/dist/core/http/abort-error.d.ts +89 -0
- package/dist/core/http/abort-error.d.ts.map +1 -0
- package/dist/core/http/abort-error.js +190 -0
- package/dist/core/http/abort-error.js.map +1 -0
- package/dist/core/http/api-client.d.ts.map +1 -1
- package/dist/core/http/api-client.js +18 -4
- package/dist/core/http/api-client.js.map +1 -1
- package/dist/core/http/opencode-errors.d.ts +7 -0
- package/dist/core/http/opencode-errors.d.ts.map +1 -1
- package/dist/core/http/opencode-errors.js +45 -13
- package/dist/core/http/opencode-errors.js.map +1 -1
- package/dist/core/rest/platform-client/github-app.d.ts +13 -0
- package/dist/core/rest/platform-client/github-app.d.ts.map +1 -1
- package/dist/core/rest/platform-client/github-app.js +2 -0
- package/dist/core/rest/platform-client/github-app.js.map +1 -1
- package/dist/core/rest/platform-client/members.d.ts +10 -64
- package/dist/core/rest/platform-client/members.d.ts.map +1 -1
- package/dist/core/rest/platform-client/members.js +10 -28
- package/dist/core/rest/platform-client/members.js.map +1 -1
- package/dist/core/rest/projects-client/accounts.d.ts +30 -5
- package/dist/core/rest/projects-client/accounts.d.ts.map +1 -1
- package/dist/core/rest/projects-client/accounts.js +1 -1
- package/dist/core/rest/projects-client/accounts.js.map +1 -1
- package/dist/core/rest/projects-client/apps.d.ts +13 -0
- package/dist/core/rest/projects-client/apps.d.ts.map +1 -1
- package/dist/core/rest/projects-client/apps.js.map +1 -1
- package/dist/core/rest/projects-client/assignments.d.ts +114 -0
- package/dist/core/rest/projects-client/assignments.d.ts.map +1 -0
- package/dist/core/rest/projects-client/assignments.js +91 -0
- package/dist/core/rest/projects-client/assignments.js.map +1 -0
- package/dist/core/rest/projects-client/billing.d.ts +10 -1
- package/dist/core/rest/projects-client/billing.d.ts.map +1 -1
- package/dist/core/rest/projects-client/billing.js +11 -2
- package/dist/core/rest/projects-client/billing.js.map +1 -1
- package/dist/core/rest/projects-client/connectors.d.ts +69 -1
- package/dist/core/rest/projects-client/connectors.d.ts.map +1 -1
- package/dist/core/rest/projects-client/connectors.js +17 -0
- package/dist/core/rest/projects-client/connectors.js.map +1 -1
- package/dist/core/rest/projects-client/files.js +2 -2
- package/dist/core/rest/projects-client/files.js.map +1 -1
- package/dist/core/rest/projects-client/gateway.d.ts +51 -0
- package/dist/core/rest/projects-client/gateway.d.ts.map +1 -1
- package/dist/core/rest/projects-client/gateway.js.map +1 -1
- package/dist/core/rest/projects-client/iam.d.ts +51 -3
- package/dist/core/rest/projects-client/iam.d.ts.map +1 -1
- package/dist/core/rest/projects-client/iam.js +18 -1
- package/dist/core/rest/projects-client/iam.js.map +1 -1
- package/dist/core/rest/projects-client/index.d.ts +1 -0
- package/dist/core/rest/projects-client/index.d.ts.map +1 -1
- package/dist/core/rest/projects-client/index.js +1 -0
- package/dist/core/rest/projects-client/index.js.map +1 -1
- package/dist/core/rest/projects-client/projects.d.ts +1 -1
- package/dist/core/rest/projects-client/projects.d.ts.map +1 -1
- package/dist/core/rest/projects-client/projects.js +2 -0
- package/dist/core/rest/projects-client/projects.js.map +1 -1
- package/dist/core/rest/projects-client/secrets.d.ts +19 -1
- package/dist/core/rest/projects-client/secrets.d.ts.map +1 -1
- package/dist/core/rest/projects-client/secrets.js +1 -1
- package/dist/core/rest/projects-client/secrets.js.map +1 -1
- package/dist/core/rest/projects-client/session-costs.d.ts +33 -0
- package/dist/core/rest/projects-client/session-costs.d.ts.map +1 -1
- package/dist/core/rest/projects-client/session-costs.js.map +1 -1
- package/dist/core/rest/projects-client/sessions.d.ts +261 -2
- package/dist/core/rest/projects-client/sessions.d.ts.map +1 -1
- package/dist/core/rest/projects-client/sessions.js +106 -4
- package/dist/core/rest/projects-client/sessions.js.map +1 -1
- package/dist/core/rest/projects-client/shared.d.ts +10 -1
- package/dist/core/rest/projects-client/shared.d.ts.map +1 -1
- package/dist/core/rest/projects-client/shared.js.map +1 -1
- package/dist/core/rest/projects-client/tokens.d.ts +13 -1
- package/dist/core/rest/projects-client/tokens.d.ts.map +1 -1
- package/dist/core/rest/projects-client/tokens.js +7 -2
- package/dist/core/rest/projects-client/tokens.js.map +1 -1
- package/dist/core/rest/projects-client/triggers.d.ts +69 -2
- package/dist/core/rest/projects-client/triggers.d.ts.map +1 -1
- package/dist/core/rest/projects-client/triggers.js +1 -1
- package/dist/core/rest/projects-client/triggers.js.map +1 -1
- package/dist/core/session/compaction.d.ts +98 -0
- package/dist/core/session/compaction.d.ts.map +1 -0
- package/dist/core/session/compaction.js +108 -0
- package/dist/core/session/compaction.js.map +1 -0
- package/dist/core/session/health.d.ts +22 -0
- package/dist/core/session/health.d.ts.map +1 -1
- package/dist/core/session/health.js +31 -5
- package/dist/core/session/health.js.map +1 -1
- package/dist/core/session/index.d.ts +2 -0
- package/dist/core/session/index.d.ts.map +1 -1
- package/dist/core/session/index.js +2 -0
- package/dist/core/session/index.js.map +1 -1
- package/dist/core/session/message-queue.d.ts +79 -15
- package/dist/core/session/message-queue.d.ts.map +1 -1
- package/dist/core/session/message-queue.js +73 -27
- package/dist/core/session/message-queue.js.map +1 -1
- package/dist/core/session/rewind.d.ts +76 -10
- package/dist/core/session/rewind.d.ts.map +1 -1
- package/dist/core/session/rewind.js +68 -11
- package/dist/core/session/rewind.js.map +1 -1
- package/dist/core/session/working.d.ts +241 -0
- package/dist/core/session/working.d.ts.map +1 -0
- package/dist/core/session/working.js +261 -0
- package/dist/core/session/working.js.map +1 -0
- package/dist/core/session-sync/session-sync-controller.d.ts +35 -20
- package/dist/core/session-sync/session-sync-controller.d.ts.map +1 -1
- package/dist/core/session-sync/session-sync-controller.js +48 -115
- package/dist/core/session-sync/session-sync-controller.js.map +1 -1
- package/dist/core/stream/event-stream.d.ts +22 -0
- package/dist/core/stream/event-stream.d.ts.map +1 -1
- package/dist/core/stream/event-stream.js +132 -36
- package/dist/core/stream/event-stream.js.map +1 -1
- package/dist/core/turns/grouping.d.ts +18 -2
- package/dist/core/turns/grouping.d.ts.map +1 -1
- package/dist/core/turns/grouping.js +45 -2
- package/dist/core/turns/grouping.js.map +1 -1
- package/dist/core/turns/index.d.ts +1 -0
- package/dist/core/turns/index.d.ts.map +1 -1
- package/dist/core/turns/index.js +1 -0
- package/dist/core/turns/index.js.map +1 -1
- package/dist/core/turns/open-turn.d.ts +81 -0
- package/dist/core/turns/open-turn.d.ts.map +1 -0
- package/dist/core/turns/open-turn.js +77 -0
- package/dist/core/turns/open-turn.js.map +1 -0
- package/dist/core/turns/state.js +26 -26
- package/dist/core/turns/state.js.map +1 -1
- package/dist/core/turns/types.d.ts +5 -0
- package/dist/core/turns/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/kortix.esm.min.js +25 -25
- package/dist/kortix.global.js +25 -25
- package/dist/node/server.d.ts.map +1 -1
- package/dist/node/server.js +14 -2
- package/dist/node/server.js.map +1 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +7 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/initial-session-pin.d.ts +17 -0
- package/dist/react/initial-session-pin.d.ts.map +1 -1
- package/dist/react/initial-session-pin.js +58 -0
- package/dist/react/initial-session-pin.js.map +1 -1
- package/dist/react/opencode.d.ts +6 -2
- package/dist/react/opencode.d.ts.map +1 -1
- package/dist/react/opencode.js +5 -1
- package/dist/react/opencode.js.map +1 -1
- package/dist/react/prefetch-session-start.d.ts +10 -4
- package/dist/react/prefetch-session-start.d.ts.map +1 -1
- package/dist/react/prefetch-session-start.js +10 -4
- package/dist/react/prefetch-session-start.js.map +1 -1
- package/dist/react/query-contracts.d.ts +2 -0
- package/dist/react/query-contracts.d.ts.map +1 -1
- package/dist/react/query-contracts.js +2 -0
- package/dist/react/query-contracts.js.map +1 -1
- package/dist/react/query-keys.d.ts +13 -2
- package/dist/react/query-keys.d.ts.map +1 -1
- package/dist/react/query-keys.js +13 -2
- package/dist/react/query-keys.js.map +1 -1
- package/dist/react/session-start-stash.d.ts +25 -0
- package/dist/react/session-start-stash.d.ts.map +1 -1
- package/dist/react/session-start-stash.js +34 -3
- package/dist/react/session-start-stash.js.map +1 -1
- package/dist/react/session-title-sync.d.ts +5 -1
- package/dist/react/session-title-sync.d.ts.map +1 -1
- package/dist/react/session-title-sync.js +16 -4
- package/dist/react/session-title-sync.js.map +1 -1
- package/dist/react/use-can.d.ts +105 -0
- package/dist/react/use-can.d.ts.map +1 -0
- package/dist/react/use-can.js +190 -0
- package/dist/react/use-can.js.map +1 -0
- package/dist/react/use-canonical-opencode-session.d.ts +6 -1
- package/dist/react/use-canonical-opencode-session.d.ts.map +1 -1
- package/dist/react/use-canonical-opencode-session.js +46 -3
- package/dist/react/use-canonical-opencode-session.js.map +1 -1
- package/dist/react/use-opencode-events/handle-event.d.ts +10 -0
- package/dist/react/use-opencode-events/handle-event.d.ts.map +1 -1
- package/dist/react/use-opencode-events/handle-event.js +76 -7
- package/dist/react/use-opencode-events/handle-event.js.map +1 -1
- package/dist/react/use-opencode-events/helpers.d.ts +21 -8
- package/dist/react/use-opencode-events/helpers.d.ts.map +1 -1
- package/dist/react/use-opencode-events/helpers.js +25 -26
- package/dist/react/use-opencode-events/helpers.js.map +1 -1
- package/dist/react/use-opencode-events/index.d.ts.map +1 -1
- package/dist/react/use-opencode-events/index.js +43 -26
- package/dist/react/use-opencode-events/index.js.map +1 -1
- package/dist/react/use-opencode-events/use-event-stream-refs.d.ts.map +1 -1
- package/dist/react/use-opencode-events/use-event-stream-refs.js +66 -3
- package/dist/react/use-opencode-events/use-event-stream-refs.js.map +1 -1
- package/dist/react/use-opencode-local.d.ts +17 -0
- package/dist/react/use-opencode-local.d.ts.map +1 -1
- package/dist/react/use-opencode-local.js +41 -7
- package/dist/react/use-opencode-local.js.map +1 -1
- package/dist/react/use-opencode-sessions/messages.d.ts +101 -1
- package/dist/react/use-opencode-sessions/messages.d.ts.map +1 -1
- package/dist/react/use-opencode-sessions/messages.js +481 -63
- package/dist/react/use-opencode-sessions/messages.js.map +1 -1
- package/dist/react/use-project-apps.d.ts +24 -1
- package/dist/react/use-project-apps.d.ts.map +1 -1
- package/dist/react/use-project-apps.js +5 -3
- package/dist/react/use-project-apps.js.map +1 -1
- package/dist/react/use-runtime-boot-stalled.d.ts +32 -0
- package/dist/react/use-runtime-boot-stalled.d.ts.map +1 -0
- package/dist/react/use-runtime-boot-stalled.js +48 -0
- package/dist/react/use-runtime-boot-stalled.js.map +1 -0
- package/dist/react/use-runtime-reconnect.d.ts +67 -1
- package/dist/react/use-runtime-reconnect.d.ts.map +1 -1
- package/dist/react/use-runtime-reconnect.js +116 -18
- package/dist/react/use-runtime-reconnect.js.map +1 -1
- package/dist/react/use-session-prompts.d.ts +113 -0
- package/dist/react/use-session-prompts.d.ts.map +1 -0
- package/dist/react/use-session-prompts.js +250 -0
- package/dist/react/use-session-prompts.js.map +1 -0
- package/dist/react/use-session-send.d.ts +169 -20
- package/dist/react/use-session-send.d.ts.map +1 -1
- package/dist/react/use-session-send.js +183 -30
- package/dist/react/use-session-send.js.map +1 -1
- package/dist/react/use-session-sync.d.ts +35 -2
- package/dist/react/use-session-sync.d.ts.map +1 -1
- package/dist/react/use-session-sync.js +49 -11
- package/dist/react/use-session-sync.js.map +1 -1
- package/dist/react/use-session-working.d.ts +57 -0
- package/dist/react/use-session-working.d.ts.map +1 -0
- package/dist/react/use-session-working.js +178 -0
- package/dist/react/use-session-working.js.map +1 -0
- package/dist/react/use-session.d.ts +131 -5
- package/dist/react/use-session.d.ts.map +1 -1
- package/dist/react/use-session.js +358 -69
- package/dist/react/use-session.js.map +1 -1
- package/package.json +2 -2
- package/dist/browser/stores/tab-store.d.ts +0 -91
- package/dist/browser/stores/tab-store.d.ts.map +0 -1
- package/dist/browser/stores/tab-store.js +0 -369
- package/dist/browser/stores/tab-store.js.map +0 -1
- package/dist/core/session/send-queue.d.ts +0 -70
- package/dist/core/session/send-queue.d.ts.map +0 -1
- package/dist/core/session/send-queue.js +0 -116
- package/dist/core/session/send-queue.js.map +0 -1
|
@@ -6,7 +6,27 @@
|
|
|
6
6
|
* that's how the chosen model/agent/variant apply to the opening turn. Owned by
|
|
7
7
|
* the SDK so the producer (new-session screen) and consumer (`useSession`)
|
|
8
8
|
* share one contract.
|
|
9
|
+
*
|
|
10
|
+
* ## Two producer styles
|
|
11
|
+
*
|
|
12
|
+
* A host with an inbox client (apps/web) writes a PICKS-ONLY stash
|
|
13
|
+
* (`prompt: ''`): the prompt itself becomes a durable server row at session
|
|
14
|
+
* create (or via `startSessionWithPrompt`), and only the model/agent/variant
|
|
15
|
+
* hand-off still travels here. An empty prompt therefore round-trips — see
|
|
16
|
+
* the picks-only test — and `useSession`'s replay sends nothing for it. A
|
|
17
|
+
* host without one (apps/whitelabel-demo, the golden thin-SDK reference)
|
|
18
|
+
* writes the full stash and the replay path delivers it exactly as always.
|
|
9
19
|
*/
|
|
20
|
+
/**
|
|
21
|
+
* How long a stash stays deliverable. A stash is a hand-off for the
|
|
22
|
+
* navigation that wrote it — a failed replay restores it (re-stamped), but
|
|
23
|
+
* one that then sits unconsumed is a stale prompt, and replaying it into the
|
|
24
|
+
* session's by-then-real conversation on a much later visit is exactly the
|
|
25
|
+
* mis-delivery the warm-session work exists to prevent. 10 minutes matches
|
|
26
|
+
* the API's own bound for "how stale can a delivery be and still count"
|
|
27
|
+
* (UNDELIVERED_PROMPT_STARVATION_MS).
|
|
28
|
+
*/
|
|
29
|
+
export const START_STASH_TTL_MS = 10 * 60_000;
|
|
10
30
|
export function startStashKey(sessionId) {
|
|
11
31
|
return `kortix:start:${sessionId}`;
|
|
12
32
|
}
|
|
@@ -22,7 +42,7 @@ function sanitizeStartStash(stash) {
|
|
|
22
42
|
}
|
|
23
43
|
export function writeStartStash(sessionId, stash) {
|
|
24
44
|
try {
|
|
25
|
-
sessionStorage.setItem(startStashKey(sessionId), JSON.stringify(sanitizeStartStash(stash)));
|
|
45
|
+
sessionStorage.setItem(startStashKey(sessionId), JSON.stringify({ ...sanitizeStartStash(stash), at: Date.now() }));
|
|
26
46
|
}
|
|
27
47
|
catch { }
|
|
28
48
|
}
|
|
@@ -97,8 +117,19 @@ function clearLegacyStash(sessionId) {
|
|
|
97
117
|
export function readStartStash(sessionId) {
|
|
98
118
|
try {
|
|
99
119
|
const raw = sessionStorage.getItem(startStashKey(sessionId));
|
|
100
|
-
if (raw)
|
|
101
|
-
|
|
120
|
+
if (raw) {
|
|
121
|
+
const stash = JSON.parse(raw);
|
|
122
|
+
// Expired: dead hand-off, not a pending prompt. Clear it so nothing —
|
|
123
|
+
// including the legacy fallback below — can resurrect it.
|
|
124
|
+
if (typeof stash.at === 'number' && Date.now() - stash.at > START_STASH_TTL_MS) {
|
|
125
|
+
clearStartStash(sessionId);
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
// The stamp is a storage detail — consumers get the hand-off payload
|
|
129
|
+
// exactly as it was written.
|
|
130
|
+
const { at: _at, ...payload } = stash;
|
|
131
|
+
return sanitizeStartStash(payload);
|
|
132
|
+
}
|
|
102
133
|
}
|
|
103
134
|
catch {
|
|
104
135
|
// fall through to the legacy shape
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-start-stash.js","sourceRoot":"","sources":["../../src/react/session-start-stash.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"session-start-stash.js","sourceRoot":"","sources":["../../src/react/session-start-stash.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { QueryClient } from '@tanstack/react-query';
|
|
2
|
-
type SessionTitleQueryClient = Pick<QueryClient, 'getQueryData' | 'refetchQueries'
|
|
2
|
+
type SessionTitleQueryClient = Pick<QueryClient, 'getQueryData' | 'refetchQueries'> & {
|
|
3
|
+
/** Optional so lean test fakes (and older callers) keep working; a real
|
|
4
|
+
* QueryClient always has it. */
|
|
5
|
+
getQueryState?: QueryClient['getQueryState'];
|
|
6
|
+
};
|
|
3
7
|
interface SessionTitleRefreshOptions {
|
|
4
8
|
delaysMs?: number[];
|
|
5
9
|
signal?: AbortSignal;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-title-sync.d.ts","sourceRoot":"","sources":["../../src/react/session-title-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"session-title-sync.d.ts","sourceRoot":"","sources":["../../src/react/session-title-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAKzD,KAAK,uBAAuB,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,GAAG,gBAAgB,CAAC,GAAG;IACpF;qCACiC;IACjC,aAAa,CAAC,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC;CAC9C,CAAC;AAEF,UAAU,0BAA0B;IAClC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AAmFD;;;;;GAKG;AACH,wBAAsB,qCAAqC,CACzD,WAAW,EAAE,uBAAuB,EACpC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,OAAO,CAAC,CAYlB;AAED;;;;;GAKG;AACH,wBAAsB,6BAA6B,CACjD,WAAW,EAAE,uBAAuB,EACpC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,OAAO,CAAC,CAIlB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sessionStartKey } from '../core/rest/projects-client/index.js';
|
|
1
2
|
import { qk } from './query-keys.js';
|
|
2
3
|
const DEFAULT_TITLE_REFRESH_DELAYS_MS = [0, 5_000, 5_000, 10_000, 10_000, 15_000, 20_000];
|
|
3
4
|
function readRealTitle(value) {
|
|
@@ -30,15 +31,26 @@ function cachedSessionHasTitle(queryClient, projectId, sessionId) {
|
|
|
30
31
|
});
|
|
31
32
|
}
|
|
32
33
|
function refetchSessionTitleQueries(queryClient, projectId, sessionId) {
|
|
34
|
+
// An adopted warm session is revealed by /start dropping `metadata.warm`.
|
|
35
|
+
// While THIS session's /start is still in flight, a sessions-list refetch
|
|
36
|
+
// can beat it, observe the row still hidden, and overwrite the adopting
|
|
37
|
+
// tab's optimistic seed (warm-session-seed.ts in apps/web) — so the list
|
|
38
|
+
// half waits for the next ladder pass. The detail refetch stays: the
|
|
39
|
+
// session route serves the owner regardless of the marker.
|
|
40
|
+
const startFetching = queryClient.getQueryState?.(sessionStartKey(projectId, sessionId))?.fetchStatus === 'fetching';
|
|
33
41
|
return Promise.all([
|
|
34
42
|
// The broad sessions-family prefix, not just the default-scope list: it
|
|
35
43
|
// reaches the list in EVERY scope plus every session/messages entry
|
|
36
44
|
// beneath it, so a manager-only 'project'-scope reader picks up the
|
|
37
45
|
// resolved title too, not only the default 'visible' one.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
...(startFetching
|
|
47
|
+
? []
|
|
48
|
+
: [
|
|
49
|
+
queryClient.refetchQueries({
|
|
50
|
+
queryKey: qk.project.sessionsScope(projectId),
|
|
51
|
+
type: 'active',
|
|
52
|
+
}),
|
|
53
|
+
]),
|
|
42
54
|
queryClient.refetchQueries({
|
|
43
55
|
queryKey: qk.project.session(projectId, sessionId),
|
|
44
56
|
type: 'active',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-title-sync.js","sourceRoot":"","sources":["../../src/react/session-title-sync.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"session-title-sync.js","sourceRoot":"","sources":["../../src/react/session-title-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `useCan` / `useCans` — the ONLY client-side authorization read.
|
|
3
|
+
*
|
|
4
|
+
* Relocated from `apps/web/src/lib/use-permission.ts` + `use-project-can.ts`.
|
|
5
|
+
* They were host-local, so every other host (the whitelabel demo, mobile) had
|
|
6
|
+
* no probe at all and fell back to reading a role literal off a row — which is
|
|
7
|
+
* exactly the bug the canonical model deletes: a member holding a custom role
|
|
8
|
+
* that grants `project.members.manage` is invisible to `role === 'manager'`.
|
|
9
|
+
*
|
|
10
|
+
* Ask for the LEAF the route asserts (`project.gitops.push`), never for a role.
|
|
11
|
+
* The engine answers; the client renders the answer.
|
|
12
|
+
*
|
|
13
|
+
* NOT a security boundary — the API re-checks every mutating route. This only
|
|
14
|
+
* decides what to show and enable.
|
|
15
|
+
*
|
|
16
|
+
* ### Cache contract
|
|
17
|
+
*
|
|
18
|
+
* A verdict is cached for 5 minutes. That is only safe because every
|
|
19
|
+
* assignment write calls `invalidatePermissionProbes`, so a revoke is visible
|
|
20
|
+
* on the next render rather than up to five minutes later. If you add a write
|
|
21
|
+
* path that changes an assignment, it calls that function. No exceptions.
|
|
22
|
+
*/
|
|
23
|
+
import { type QueryClient } from '@tanstack/react-query';
|
|
24
|
+
import { type PermissionProbeInput, type ResourceType } from '../core/rest/projects-client/index.js';
|
|
25
|
+
/** A probe verdict. `allowed` is true only when the engine said so — loading
|
|
26
|
+
* and error both read false, so a gate defaults to hidden/disabled. */
|
|
27
|
+
export interface CanResult {
|
|
28
|
+
allowed: boolean;
|
|
29
|
+
/** The engine's reason, e.g. `super_admin`, `role`, `not_a_member`,
|
|
30
|
+
* `agent_scope_insufficient`. Drives "why can Alice do this?" tooltips. */
|
|
31
|
+
reason: string | null;
|
|
32
|
+
isLoading: boolean;
|
|
33
|
+
isError: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* What the action is being asked about.
|
|
37
|
+
*
|
|
38
|
+
* - `{ accountId }` — an account-scope action (`member.update`, `role.create`).
|
|
39
|
+
* - `{ accountId, resource }` — narrowed to one account object (a group, a member).
|
|
40
|
+
* - `{ projectId }` — a project-scope action. The owning account is resolved
|
|
41
|
+
* from the shared project cache; pass `accountId` when you already hold it
|
|
42
|
+
* and the probe runs on the FIRST render instead of after a second fetch.
|
|
43
|
+
*/
|
|
44
|
+
export type CanTarget = {
|
|
45
|
+
accountId: string | undefined;
|
|
46
|
+
projectId?: undefined;
|
|
47
|
+
resource?: {
|
|
48
|
+
type: Exclude<ResourceType, 'account'>;
|
|
49
|
+
id: string;
|
|
50
|
+
};
|
|
51
|
+
} | {
|
|
52
|
+
projectId: string | undefined;
|
|
53
|
+
accountId?: string;
|
|
54
|
+
resource?: undefined;
|
|
55
|
+
};
|
|
56
|
+
export interface CanOptions {
|
|
57
|
+
/** Probe as this user instead of the caller. A host with its own auth
|
|
58
|
+
* context passes it here rather than making the SDK depend on that context;
|
|
59
|
+
* omitted, the SDK resolves the caller from `GET /accounts/me`. */
|
|
60
|
+
userId?: string;
|
|
61
|
+
}
|
|
62
|
+
/** The single-probe cache key. Kept as a flat literal (not under `qk`) because
|
|
63
|
+
* it predates that factory and both `apps/web` and its tests address it. */
|
|
64
|
+
export declare const permissionProbeKey: (accountId: string | undefined, userId: string | undefined, action: string, target?: {
|
|
65
|
+
resourceType?: string;
|
|
66
|
+
resourceId?: string;
|
|
67
|
+
}) => readonly ["iam-permission", string | undefined, string | undefined, string, string | null, string | null];
|
|
68
|
+
/** The batch cache key. Keyed on the probe LIST so adding or removing a probe
|
|
69
|
+
* refetches; the signature is action+target per probe, never object identity,
|
|
70
|
+
* which React swaps every render. */
|
|
71
|
+
export declare const permissionProbeBatchKey: (accountId: string | undefined, userId: string | undefined, probes: readonly PermissionProbeInput[]) => readonly ["iam-permission-batch", string | undefined, string | undefined, string];
|
|
72
|
+
/** Can this principal perform `action` on this target? */
|
|
73
|
+
export declare function useCan(target: CanTarget, action: string, options?: CanOptions): CanResult;
|
|
74
|
+
/**
|
|
75
|
+
* Batch variant — ONE roundtrip for N actions on the same target. Returns a map
|
|
76
|
+
* keyed by action, so a caller reads `caps[ACTION].allowed`.
|
|
77
|
+
*
|
|
78
|
+
* `actions` must be stable across renders (module-level or memoized): the query
|
|
79
|
+
* key is derived from the list.
|
|
80
|
+
*/
|
|
81
|
+
export declare function useCans(target: CanTarget, actions: readonly string[], options?: CanOptions): Record<string, CanResult>;
|
|
82
|
+
/**
|
|
83
|
+
* Probe on behalf of ANOTHER member — the "what can this person actually do"
|
|
84
|
+
* admin panels. Returns one result per input, in order. The caller needs
|
|
85
|
+
* `member.read` on the account; the server enforces it.
|
|
86
|
+
*
|
|
87
|
+
* Kept probe-shaped (not action-shaped like `useCans`) because these panels mix
|
|
88
|
+
* account and project targets in one request.
|
|
89
|
+
*/
|
|
90
|
+
export declare function usePermissionsFor(accountId: string | undefined, memberUserId: string | undefined, probes: PermissionProbeInput[]): CanResult[];
|
|
91
|
+
/**
|
|
92
|
+
* Bust the probe cache after an assignment write. **Every** write that creates,
|
|
93
|
+
* changes or revokes an assignment calls this — a 5-minute stale window on an
|
|
94
|
+
* authorization verdict is a revoke that has not happened yet.
|
|
95
|
+
*
|
|
96
|
+
* Scope it as tightly as you honestly can: an account+user pair when you know
|
|
97
|
+
* whose access changed, the account when a group or a role definition changed
|
|
98
|
+
* (that moves verdicts for principals you cannot enumerate client-side), and
|
|
99
|
+
* everything only when you know nothing.
|
|
100
|
+
*/
|
|
101
|
+
export declare function invalidatePermissionProbes(queryClient: Pick<QueryClient, 'invalidateQueries'>, scope: {
|
|
102
|
+
accountId?: string;
|
|
103
|
+
userId?: string;
|
|
104
|
+
}): Promise<void>;
|
|
105
|
+
//# sourceMappingURL=use-can.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-can.d.ts","sourceRoot":"","sources":["../../src/react/use-can.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAKL,KAAK,oBAAoB,EACzB,KAAK,YAAY,EAClB,MAAM,8BAA8B,CAAC;AAItC;wEACwE;AACxE,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB;gFAC4E;IAC5E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GACjB;IACE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CACnE,GACD;IAAE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAEhF,MAAM,WAAW,UAAU;IACzB;;wEAEoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID;6EAC6E;AAC7E,eAAO,MAAM,kBAAkB,GAC7B,WAAW,MAAM,GAAG,SAAS,EAC7B,QAAQ,MAAM,GAAG,SAAS,EAC1B,QAAQ,MAAM,EACd,SAAS;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,8GAS7C,CAAC;AAEb;;sCAEsC;AACtC,eAAO,MAAM,uBAAuB,GAClC,WAAW,MAAM,GAAG,SAAS,EAC7B,QAAQ,MAAM,GAAG,SAAS,EAC1B,QAAQ,SAAS,oBAAoB,EAAE,sFAO7B,CAAC;AAsDb,0DAA0D;AAC1D,wBAAgB,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,SAAS,CAwBzF;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CACrB,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,OAAO,CAAC,EAAE,UAAU,GACnB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CA8B3B;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,MAAM,EAAE,oBAAoB,EAAE,GAC7B,SAAS,EAAE,CAoBb;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,mBAAmB,CAAC,EACnD,KAAK,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C,OAAO,CAAC,IAAI,CAAC,CAKf"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
/**
|
|
3
|
+
* `useCan` / `useCans` — the ONLY client-side authorization read.
|
|
4
|
+
*
|
|
5
|
+
* Relocated from `apps/web/src/lib/use-permission.ts` + `use-project-can.ts`.
|
|
6
|
+
* They were host-local, so every other host (the whitelabel demo, mobile) had
|
|
7
|
+
* no probe at all and fell back to reading a role literal off a row — which is
|
|
8
|
+
* exactly the bug the canonical model deletes: a member holding a custom role
|
|
9
|
+
* that grants `project.members.manage` is invisible to `role === 'manager'`.
|
|
10
|
+
*
|
|
11
|
+
* Ask for the LEAF the route asserts (`project.gitops.push`), never for a role.
|
|
12
|
+
* The engine answers; the client renders the answer.
|
|
13
|
+
*
|
|
14
|
+
* NOT a security boundary — the API re-checks every mutating route. This only
|
|
15
|
+
* decides what to show and enable.
|
|
16
|
+
*
|
|
17
|
+
* ### Cache contract
|
|
18
|
+
*
|
|
19
|
+
* A verdict is cached for 5 minutes. That is only safe because every
|
|
20
|
+
* assignment write calls `invalidatePermissionProbes`, so a revoke is visible
|
|
21
|
+
* on the next render rather than up to five minutes later. If you add a write
|
|
22
|
+
* path that changes an assignment, it calls that function. No exceptions.
|
|
23
|
+
*/
|
|
24
|
+
import { useQuery } from '@tanstack/react-query';
|
|
25
|
+
import { getProject, probeEffectivePermission, probeEffectivePermissions, validateToken, } from '../core/rest/projects-client/index.js';
|
|
26
|
+
import { contract } from './query-contracts.js';
|
|
27
|
+
import { qk } from './query-keys.js';
|
|
28
|
+
const PROBE_STALE_MS = 5 * 60_000;
|
|
29
|
+
/** The single-probe cache key. Kept as a flat literal (not under `qk`) because
|
|
30
|
+
* it predates that factory and both `apps/web` and its tests address it. */
|
|
31
|
+
export const permissionProbeKey = (accountId, userId, action, target) => [
|
|
32
|
+
'iam-permission',
|
|
33
|
+
accountId,
|
|
34
|
+
userId,
|
|
35
|
+
action,
|
|
36
|
+
target?.resourceType ?? null,
|
|
37
|
+
target?.resourceId ?? null,
|
|
38
|
+
];
|
|
39
|
+
/** The batch cache key. Keyed on the probe LIST so adding or removing a probe
|
|
40
|
+
* refetches; the signature is action+target per probe, never object identity,
|
|
41
|
+
* which React swaps every render. */
|
|
42
|
+
export const permissionProbeBatchKey = (accountId, userId, probes) => [
|
|
43
|
+
'iam-permission-batch',
|
|
44
|
+
accountId,
|
|
45
|
+
userId,
|
|
46
|
+
probes.map((p) => `${p.action}|${p.resourceType ?? ''}|${p.resourceId ?? ''}`).join(','),
|
|
47
|
+
];
|
|
48
|
+
/** Identity of the calling principal, for hosts that do not inject one. */
|
|
49
|
+
const identityKey = ['iam-identity', 'me'];
|
|
50
|
+
function useProbeUserId(explicit) {
|
|
51
|
+
const query = useQuery({
|
|
52
|
+
queryKey: identityKey,
|
|
53
|
+
queryFn: async () => (await validateToken()).identity ?? null,
|
|
54
|
+
enabled: !explicit,
|
|
55
|
+
staleTime: Infinity,
|
|
56
|
+
});
|
|
57
|
+
return explicit ?? query.data?.user_id;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Resolve the account that owns a project. A DISABLED react-query query reports
|
|
61
|
+
* `isLoading === false` in v5, so callers must not read the unresolved window
|
|
62
|
+
* as a denial — `pending()` below converts it to "still loading".
|
|
63
|
+
*/
|
|
64
|
+
function useOwningAccountId(projectId, accountIdHint) {
|
|
65
|
+
const { data } = useQuery({
|
|
66
|
+
queryKey: qk.project.summary(projectId ?? ''),
|
|
67
|
+
queryFn: () => getProject(projectId),
|
|
68
|
+
enabled: !!projectId && !accountIdHint,
|
|
69
|
+
...contract('config'),
|
|
70
|
+
});
|
|
71
|
+
return projectId ? (accountIdHint ?? data?.account_id) : undefined;
|
|
72
|
+
}
|
|
73
|
+
const pending = () => ({
|
|
74
|
+
allowed: false,
|
|
75
|
+
reason: null,
|
|
76
|
+
isLoading: true,
|
|
77
|
+
isError: false,
|
|
78
|
+
});
|
|
79
|
+
/** Everything a target resolves to: the account to ask, and the probe target. */
|
|
80
|
+
function useResolvedTarget(target) {
|
|
81
|
+
const isProject = 'projectId' in target && target.projectId !== undefined;
|
|
82
|
+
const projectId = 'projectId' in target ? target.projectId : undefined;
|
|
83
|
+
const owningAccountId = useOwningAccountId(projectId, target.accountId);
|
|
84
|
+
const accountId = isProject ? owningAccountId : target.accountId;
|
|
85
|
+
const probeTarget = isProject
|
|
86
|
+
? { resourceType: 'project', resourceId: projectId }
|
|
87
|
+
: target.resource
|
|
88
|
+
? { resourceType: target.resource.type, resourceId: target.resource.id }
|
|
89
|
+
: undefined;
|
|
90
|
+
return { accountId, probeTarget, resolved: !!accountId && (!isProject || !!projectId) };
|
|
91
|
+
}
|
|
92
|
+
/** Can this principal perform `action` on this target? */
|
|
93
|
+
export function useCan(target, action, options) {
|
|
94
|
+
const userId = useProbeUserId(options?.userId);
|
|
95
|
+
const { accountId, probeTarget, resolved } = useResolvedTarget(target);
|
|
96
|
+
const enabled = resolved && !!userId;
|
|
97
|
+
const query = useQuery({
|
|
98
|
+
queryKey: permissionProbeKey(accountId, userId, action, probeTarget),
|
|
99
|
+
queryFn: () => probeEffectivePermission(accountId, userId, (probeTarget ? { action, ...probeTarget } : { action })),
|
|
100
|
+
enabled,
|
|
101
|
+
staleTime: PROBE_STALE_MS,
|
|
102
|
+
});
|
|
103
|
+
if (!enabled)
|
|
104
|
+
return pending();
|
|
105
|
+
return {
|
|
106
|
+
allowed: query.data?.allowed === true,
|
|
107
|
+
reason: query.data?.reason ?? null,
|
|
108
|
+
isLoading: query.isLoading,
|
|
109
|
+
isError: query.isError,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Batch variant — ONE roundtrip for N actions on the same target. Returns a map
|
|
114
|
+
* keyed by action, so a caller reads `caps[ACTION].allowed`.
|
|
115
|
+
*
|
|
116
|
+
* `actions` must be stable across renders (module-level or memoized): the query
|
|
117
|
+
* key is derived from the list.
|
|
118
|
+
*/
|
|
119
|
+
export function useCans(target, actions, options) {
|
|
120
|
+
const userId = useProbeUserId(options?.userId);
|
|
121
|
+
const { accountId, probeTarget, resolved } = useResolvedTarget(target);
|
|
122
|
+
const probes = actions.map((action) => (probeTarget ? { action, ...probeTarget } : { action }));
|
|
123
|
+
const enabled = resolved && !!userId && probes.length > 0;
|
|
124
|
+
const query = useQuery({
|
|
125
|
+
queryKey: permissionProbeBatchKey(accountId, userId, probes),
|
|
126
|
+
queryFn: () => probeEffectivePermissions(accountId, userId, probes),
|
|
127
|
+
enabled,
|
|
128
|
+
staleTime: PROBE_STALE_MS,
|
|
129
|
+
});
|
|
130
|
+
const map = {};
|
|
131
|
+
actions.forEach((action, i) => {
|
|
132
|
+
if (!enabled) {
|
|
133
|
+
map[action] = pending();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const hit = query.data?.[i];
|
|
137
|
+
map[action] = {
|
|
138
|
+
allowed: hit?.allowed === true,
|
|
139
|
+
reason: hit?.reason ?? null,
|
|
140
|
+
isLoading: query.isLoading,
|
|
141
|
+
isError: query.isError,
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
return map;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Probe on behalf of ANOTHER member — the "what can this person actually do"
|
|
148
|
+
* admin panels. Returns one result per input, in order. The caller needs
|
|
149
|
+
* `member.read` on the account; the server enforces it.
|
|
150
|
+
*
|
|
151
|
+
* Kept probe-shaped (not action-shaped like `useCans`) because these panels mix
|
|
152
|
+
* account and project targets in one request.
|
|
153
|
+
*/
|
|
154
|
+
export function usePermissionsFor(accountId, memberUserId, probes) {
|
|
155
|
+
const enabled = !!accountId && !!memberUserId && probes.length > 0;
|
|
156
|
+
const query = useQuery({
|
|
157
|
+
queryKey: permissionProbeBatchKey(accountId, memberUserId, probes),
|
|
158
|
+
queryFn: () => probeEffectivePermissions(accountId, memberUserId, probes),
|
|
159
|
+
enabled,
|
|
160
|
+
staleTime: PROBE_STALE_MS,
|
|
161
|
+
});
|
|
162
|
+
return probes.map((_, i) => {
|
|
163
|
+
if (!enabled)
|
|
164
|
+
return pending();
|
|
165
|
+
const hit = query.data?.[i];
|
|
166
|
+
return {
|
|
167
|
+
allowed: hit?.allowed === true,
|
|
168
|
+
reason: hit?.reason ?? null,
|
|
169
|
+
isLoading: query.isLoading,
|
|
170
|
+
isError: query.isError,
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Bust the probe cache after an assignment write. **Every** write that creates,
|
|
176
|
+
* changes or revokes an assignment calls this — a 5-minute stale window on an
|
|
177
|
+
* authorization verdict is a revoke that has not happened yet.
|
|
178
|
+
*
|
|
179
|
+
* Scope it as tightly as you honestly can: an account+user pair when you know
|
|
180
|
+
* whose access changed, the account when a group or a role definition changed
|
|
181
|
+
* (that moves verdicts for principals you cannot enumerate client-side), and
|
|
182
|
+
* everything only when you know nothing.
|
|
183
|
+
*/
|
|
184
|
+
export function invalidatePermissionProbes(queryClient, scope) {
|
|
185
|
+
const suffix = [scope.accountId, scope.userId].filter((s) => !!s);
|
|
186
|
+
queryClient.invalidateQueries({ queryKey: ['iam-permission', ...suffix] });
|
|
187
|
+
queryClient.invalidateQueries({ queryKey: ['iam-permission-batch', ...suffix] });
|
|
188
|
+
return Promise.resolve();
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=use-can.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-can.js","sourceRoot":"","sources":["../../src/react/use-can.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,QAAQ,EAAoB,MAAM,uBAAuB,CAAC;AACnE,OAAO,EACL,UAAU,EACV,wBAAwB,EACxB,yBAAyB,EACzB,aAAa,GAGd,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAqClC,MAAM,cAAc,GAAG,CAAC,GAAG,MAAM,CAAC;AAElC;6EAC6E;AAC7E,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,SAA6B,EAC7B,MAA0B,EAC1B,MAAc,EACd,MAAuD,EACvD,EAAE,CACF;IACE,gBAAgB;IAChB,SAAS;IACT,MAAM;IACN,MAAM;IACN,MAAM,EAAE,YAAY,IAAI,IAAI;IAC5B,MAAM,EAAE,UAAU,IAAI,IAAI;CAClB,CAAC;AAEb;;sCAEsC;AACtC,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,SAA6B,EAC7B,MAA0B,EAC1B,MAAuC,EACvC,EAAE,CACF;IACE,sBAAsB;IACtB,SAAS;IACT,MAAM;IACN,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,YAAY,IAAI,EAAE,IAAI,CAAC,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;CAChF,CAAC;AAEb,2EAA2E;AAC3E,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,IAAI,CAAU,CAAC;AAEpD,SAAS,cAAc,CAAC,QAA4B;IAClD,MAAM,KAAK,GAAG,QAAQ,CAAC;QACrB,QAAQ,EAAE,WAAW;QACrB,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,aAAa,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI;QAC7D,OAAO,EAAE,CAAC,QAAQ;QAClB,SAAS,EAAE,QAAQ;KACpB,CAAC,CAAC;IACH,OAAO,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CACzB,SAA6B,EAC7B,aAAiC;IAEjC,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;QACxB,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;QAC7C,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,SAAmB,CAAC;QAC9C,OAAO,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC,aAAa;QACtC,GAAG,QAAQ,CAAC,QAAQ,CAAC;KACtB,CAAC,CAAC;IACH,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,aAAa,IAAI,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACrE,CAAC;AAED,MAAM,OAAO,GAAG,GAAc,EAAE,CAAC,CAAC;IAChC,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,IAAI;IACZ,SAAS,EAAE,IAAI;IACf,OAAO,EAAE,KAAK;CACf,CAAC,CAAC;AAEH,iFAAiF;AACjF,SAAS,iBAAiB,CAAC,MAAiB;IAC1C,MAAM,SAAS,GAAG,WAAW,IAAI,MAAM,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC;IAC1E,MAAM,SAAS,GAAG,WAAW,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,MAAM,eAAe,GAAG,kBAAkB,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;IACjE,MAAM,WAAW,GAA+D,SAAS;QACvF,CAAC,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,SAAmB,EAAE;QAC9D,CAAC,CAAC,MAAM,CAAC,QAAQ;YACf,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE;YACxE,CAAC,CAAC,SAAS,CAAC;IAChB,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC;AAC1F,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,MAAM,CAAC,MAAiB,EAAE,MAAc,EAAE,OAAoB;IAC5E,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/C,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACvE,MAAM,OAAO,GAAG,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC;IAErC,MAAM,KAAK,GAAG,QAAQ,CAAC;QACrB,QAAQ,EAAE,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC;QACpE,OAAO,EAAE,GAAG,EAAE,CACZ,wBAAwB,CACtB,SAAmB,EACnB,MAAgB,EAChB,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAyB,CAChF;QACH,OAAO;QACP,SAAS,EAAE,cAAc;KAC1B,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO;QAAE,OAAO,OAAO,EAAE,CAAC;IAC/B,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI;QACrC,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,IAAI,IAAI;QAClC,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CACrB,MAAiB,EACjB,OAA0B,EAC1B,OAAoB;IAEpB,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/C,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACvE,MAAM,MAAM,GAA2B,OAAO,CAAC,GAAG,CAChD,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAyB,CAC5F,CAAC;IACF,MAAM,OAAO,GAAG,QAAQ,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAE1D,MAAM,KAAK,GAAG,QAAQ,CAAC;QACrB,QAAQ,EAAE,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC;QAC5D,OAAO,EAAE,GAAG,EAAE,CAAC,yBAAyB,CAAC,SAAmB,EAAE,MAAgB,EAAE,MAAM,CAAC;QACvF,OAAO;QACP,SAAS,EAAE,cAAc;KAC1B,CAAC,CAAC;IAEH,MAAM,GAAG,GAA8B,EAAE,CAAC;IAC1C,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5B,GAAG,CAAC,MAAM,CAAC,GAAG;YACZ,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI;YAC9B,MAAM,EAAE,GAAG,EAAE,MAAM,IAAI,IAAI;YAC3B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAA6B,EAC7B,YAAgC,EAChC,MAA8B;IAE9B,MAAM,OAAO,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,YAAY,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACnE,MAAM,KAAK,GAAG,QAAQ,CAAC;QACrB,QAAQ,EAAE,uBAAuB,CAAC,SAAS,EAAE,YAAY,EAAE,MAAM,CAAC;QAClE,OAAO,EAAE,GAAG,EAAE,CACZ,yBAAyB,CAAC,SAAmB,EAAE,YAAsB,EAAE,MAAM,CAAC;QAChF,OAAO;QACP,SAAS,EAAE,cAAc;KAC1B,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACzB,IAAI,CAAC,OAAO;YAAE,OAAO,OAAO,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5B,OAAO;YACL,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI;YAC9B,MAAM,EAAE,GAAG,EAAE,MAAM,IAAI,IAAI;YAC3B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CACxC,WAAmD,EACnD,KAA8C;IAE9C,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,gBAAgB,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3E,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,sBAAsB,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;IACjF,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -8,7 +8,12 @@ import { type Session } from './use-opencode-sessions/index.js';
|
|
|
8
8
|
* the client (the old client-side `ensure-opencode` mutation caused the
|
|
9
9
|
* "session replaced / data lost" drift). It just surfaces the pin:
|
|
10
10
|
* 1. the value /start handed us this render (`pinFromStart`), else
|
|
11
|
-
* 2. the
|
|
11
|
+
* 2. the host's own warm-list pin (`initialPin`), else
|
|
12
|
+
* 3. the persisted row (`getProjectSession`) once its REST read resolves,
|
|
13
|
+
* or — before it does — this browser's own synchronous local mirror of
|
|
14
|
+
* the last canonical id seen for this session (T6). The local
|
|
15
|
+
* mirror exists ONLY to cover the gap before (3)'s network read lands;
|
|
16
|
+
* it never outranks it once loaded, and neither ever outranks (1).
|
|
12
17
|
*
|
|
13
18
|
* The OpenCode session list is still read (read-only) for ?oc deep-links and
|
|
14
19
|
* sidebar sub-session rendering.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-canonical-opencode-session.d.ts","sourceRoot":"","sources":["../../src/react/use-canonical-opencode-session.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-canonical-opencode-session.d.ts","sourceRoot":"","sources":["../../src/react/use-canonical-opencode-session.ts"],"names":[],"mappings":"AAUA,OAAO,EAAuB,KAAK,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAa5E;;;;;;;;;;;;;;;;;;GAkBG;AAEH;gFACgF;AAChF,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED,MAAM,WAAW,wBAAwB;IACvC,kFAAkF;IAClF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,yEAAyE;IACzE,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B,GAAG,wBAAwB,CAqE3B"}
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
2
|
+
import { useEffect, useLayoutEffect, useState } from 'react';
|
|
3
|
+
import { readPersistedSessionPin, resolvePersistedPin, resolveSessionPin, writePersistedSessionPin, } from './initial-session-pin.js';
|
|
3
4
|
import { useOpenCodeSessions } from './use-opencode-sessions/index.js';
|
|
4
5
|
import { useProjectSession } from './use-project-session.js';
|
|
6
|
+
// SSR-safe: `localStorage` does not exist on the server, and reading it
|
|
7
|
+
// during render (rather than an effect) would make the client's FIRST
|
|
8
|
+
// hydration render disagree with the server-rendered HTML. Mirrors
|
|
9
|
+
// `useSession`'s own `useIsomorphicLayoutEffect` (T5) for the exact
|
|
10
|
+
// same reason — a `useLayoutEffect` commits its state update before the
|
|
11
|
+
// browser paints, so the corrected value is on screen for the user's very
|
|
12
|
+
// first frame instead of trailing one visible "empty" frame behind a plain
|
|
13
|
+
// `useEffect`.
|
|
14
|
+
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
|
5
15
|
/**
|
|
6
16
|
* OpenCode ↔ Kortix session mapping — READ side.
|
|
7
17
|
*
|
|
@@ -11,7 +21,12 @@ import { useProjectSession } from './use-project-session.js';
|
|
|
11
21
|
* the client (the old client-side `ensure-opencode` mutation caused the
|
|
12
22
|
* "session replaced / data lost" drift). It just surfaces the pin:
|
|
13
23
|
* 1. the value /start handed us this render (`pinFromStart`), else
|
|
14
|
-
* 2. the
|
|
24
|
+
* 2. the host's own warm-list pin (`initialPin`), else
|
|
25
|
+
* 3. the persisted row (`getProjectSession`) once its REST read resolves,
|
|
26
|
+
* or — before it does — this browser's own synchronous local mirror of
|
|
27
|
+
* the last canonical id seen for this session (T6). The local
|
|
28
|
+
* mirror exists ONLY to cover the gap before (3)'s network read lands;
|
|
29
|
+
* it never outranks it once loaded, and neither ever outranks (1).
|
|
15
30
|
*
|
|
16
31
|
* The OpenCode session list is still read (read-only) for ?oc deep-links and
|
|
17
32
|
* sidebar sub-session rendering.
|
|
@@ -44,12 +59,40 @@ export function useCanonicalOpenCodeSession(params) {
|
|
|
44
59
|
const projectSessionQuery = useProjectSession(projectId, sessionId, {
|
|
45
60
|
enabled: !pinFromStart && !initialPin,
|
|
46
61
|
});
|
|
47
|
-
const
|
|
62
|
+
const networkPin = projectSessionQuery.data?.opencode_session_id ?? null;
|
|
63
|
+
// T6 — a synchronous local mirror of the persisted pin, so a cold
|
|
64
|
+
// mount (no /start response yet, no host-warm `initialPin`) can still
|
|
65
|
+
// resolve `rootSessionId` on frame one instead of waiting out a network
|
|
66
|
+
// round trip. `useState(null)` matches what a server render sees (no
|
|
67
|
+
// `localStorage`), so hydration never disagrees with the server-rendered
|
|
68
|
+
// HTML; the layout effect below then corrects it to the real cached value
|
|
69
|
+
// before the browser paints — see the module-level comment on
|
|
70
|
+
// `useIsomorphicLayoutEffect`.
|
|
71
|
+
const [cachedPin, setCachedPin] = useState(null);
|
|
72
|
+
useIsomorphicLayoutEffect(() => {
|
|
73
|
+
setCachedPin(readPersistedSessionPin(projectId, sessionId));
|
|
74
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
75
|
+
}, [projectId, sessionId]);
|
|
76
|
+
const pin = resolvePersistedPin({ networkPin, cachedPin });
|
|
48
77
|
const rootSessionId = resolveSessionPin({
|
|
49
78
|
startPin: pinFromStart,
|
|
50
79
|
initialPin,
|
|
51
80
|
persistedPin: pin,
|
|
52
81
|
});
|
|
82
|
+
// Mirror a freshly-resolved canonical id back to disk so the NEXT mount of
|
|
83
|
+
// this (projectId, sessionId) can paint synchronously via `cachedPin`
|
|
84
|
+
// above. Scoped to the two AUTHORITATIVE, resolved-this-render sources —
|
|
85
|
+
// /start and the host's warm session-list pin — never to `pin` itself,
|
|
86
|
+
// which would just echo `cachedPin` back to its own key on every render
|
|
87
|
+
// this session is cold. This is also the write half of stale-pin
|
|
88
|
+
// convergence: a re-pinned session's fresh /start id overwrites whatever
|
|
89
|
+
// stale id a previous visit left behind, so the session AFTER this one
|
|
90
|
+
// reads the corrected value instead of the one that just got replaced.
|
|
91
|
+
const freshPin = pinFromStart ?? initialPin ?? null;
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (freshPin)
|
|
94
|
+
writePersistedSessionPin(projectId, sessionId, freshPin);
|
|
95
|
+
}, [projectId, sessionId, freshPin]);
|
|
53
96
|
return {
|
|
54
97
|
rootSessionId,
|
|
55
98
|
sessions: sessionsQuery.data ?? [],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-canonical-opencode-session.js","sourceRoot":"","sources":["../../src/react/use-canonical-opencode-session.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"use-canonical-opencode-session.js","sourceRoot":"","sources":["../../src/react/use-canonical-opencode-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,8 @@ import type { RefObject } from 'react';
|
|
|
4
4
|
import { getClient } from '../../core/runtime/client.js';
|
|
5
5
|
import { type SessionSyncReason } from '../../core/session-sync/session-sync-controller.js';
|
|
6
6
|
import type { NormalizeDiagnosticPaths, OpenCodeEvent } from './types.js';
|
|
7
|
+
/** See `createEventHandler`'s `userPartsGraceMs`. */
|
|
8
|
+
export declare const USER_PARTS_GRACE_MS = 1500;
|
|
7
9
|
/** Builds the SSE event handler; all closure dependencies are injected. */
|
|
8
10
|
export declare function createEventHandler(deps: {
|
|
9
11
|
queryClient: QueryClient;
|
|
@@ -18,6 +20,14 @@ export declare function createEventHandler(deps: {
|
|
|
18
20
|
markSessionAbortedLocally: RefObject<(sessionID: string, message?: string) => void>;
|
|
19
21
|
fetchLspDiagnosticsDebounced: RefObject<() => void>;
|
|
20
22
|
reconcileSessionTail?: (sessionID: string, reason: SessionSyncReason) => Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* How long a USER `message.updated` may sit with no parts before the tail is
|
|
25
|
+
* re-read. The runtime emits the info frame and the text part separately;
|
|
26
|
+
* lose the part (a stream reconnect during the boot hand-off) and the
|
|
27
|
+
* transcript shows an empty bubble until a reload. Injected so tests can
|
|
28
|
+
* make it immediate.
|
|
29
|
+
*/
|
|
30
|
+
userPartsGraceMs?: number;
|
|
21
31
|
/** The route-scoped project this SSE connection belongs to — see
|
|
22
32
|
* `refetchKortixSessionMirrors`'s doc comment for why this can't default
|
|
23
33
|
* to "every project". Optional only so existing test harnesses that don't
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handle-event.d.ts","sourceRoot":"","sources":["../../../src/react/use-opencode-events/handle-event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EACV,KAAK,IAAI,gBAAgB,EACzB,iBAAiB,EACjB,eAAe,EAChB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"handle-event.d.ts","sourceRoot":"","sources":["../../../src/react/use-opencode-events/handle-event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EACV,KAAK,IAAI,gBAAgB,EACzB,iBAAiB,EACjB,eAAe,EAChB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAWvC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,iDAAiD,CAAC;AAazD,OAAO,KAAK,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEvE,qDAAqD;AACrD,eAAO,MAAM,mBAAmB,OAAQ,CAAC;AAEzC,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;IACrC,cAAc,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,aAAa,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAChD,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,WAAW,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IAC5C,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,wBAAwB,EAAE,SAAS,CAAC,wBAAwB,CAAC,CAAC;IAC9D,yBAAyB,EAAE,SAAS,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC;IACpF,4BAA4B,EAAE,SAAS,CAAC,MAAM,IAAI,CAAC,CAAC;IACpD,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvF;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;6DAIyD;IACzD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,WAqC6B,aAAa,UA0jB1C"}
|