@kortix/sdk 0.11.0 → 0.12.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.
Files changed (214) hide show
  1. package/README.md +110 -73
  2. package/dist/browser/cache/idb-sync-cache-key.d.ts +2 -0
  3. package/dist/browser/cache/idb-sync-cache-key.d.ts.map +1 -0
  4. package/dist/browser/cache/idb-sync-cache-key.js +7 -0
  5. package/dist/browser/cache/idb-sync-cache-key.js.map +1 -0
  6. package/dist/browser/cache/idb-sync-cache.d.ts +3 -3
  7. package/dist/browser/cache/idb-sync-cache.d.ts.map +1 -1
  8. package/dist/browser/cache/idb-sync-cache.js +49 -26
  9. package/dist/browser/cache/idb-sync-cache.js.map +1 -1
  10. package/dist/browser/session-sync/session-cache-ownership.d.ts +36 -0
  11. package/dist/browser/session-sync/session-cache-ownership.d.ts.map +1 -0
  12. package/dist/browser/session-sync/session-cache-ownership.js +66 -0
  13. package/dist/browser/session-sync/session-cache-ownership.js.map +1 -0
  14. package/dist/browser/session-sync/session-sync-registry.d.ts +8 -6
  15. package/dist/browser/session-sync/session-sync-registry.d.ts.map +1 -1
  16. package/dist/browser/session-sync/session-sync-registry.js +86 -33
  17. package/dist/browser/session-sync/session-sync-registry.js.map +1 -1
  18. package/dist/browser/session-sync/session-transcript-cache.d.ts +55 -0
  19. package/dist/browser/session-sync/session-transcript-cache.d.ts.map +1 -0
  20. package/dist/browser/session-sync/session-transcript-cache.js +69 -0
  21. package/dist/browser/session-sync/session-transcript-cache.js.map +1 -0
  22. package/dist/core/client/kortix.d.ts +72 -25
  23. package/dist/core/client/kortix.d.ts.map +1 -1
  24. package/dist/core/client/kortix.js +76 -17
  25. package/dist/core/client/kortix.js.map +1 -1
  26. package/dist/core/rest/platform-client/host-boundary.d.ts +7 -0
  27. package/dist/core/rest/platform-client/host-boundary.d.ts.map +1 -1
  28. package/dist/core/rest/platform-client/host-boundary.js +14 -0
  29. package/dist/core/rest/platform-client/host-boundary.js.map +1 -1
  30. package/dist/core/rest/projects-client/access.d.ts +1 -2
  31. package/dist/core/rest/projects-client/access.d.ts.map +1 -1
  32. package/dist/core/rest/projects-client/access.js +9 -6
  33. package/dist/core/rest/projects-client/access.js.map +1 -1
  34. package/dist/core/rest/projects-client/agent-config.d.ts +15 -7
  35. package/dist/core/rest/projects-client/agent-config.d.ts.map +1 -1
  36. package/dist/core/rest/projects-client/agent-config.js +43 -2
  37. package/dist/core/rest/projects-client/agent-config.js.map +1 -1
  38. package/dist/core/rest/projects-client/agent-scope.d.ts +4 -0
  39. package/dist/core/rest/projects-client/agent-scope.d.ts.map +1 -1
  40. package/dist/core/rest/projects-client/agent-scope.js +34 -1
  41. package/dist/core/rest/projects-client/agent-scope.js.map +1 -1
  42. package/dist/core/rest/projects-client/audit.d.ts +34 -0
  43. package/dist/core/rest/projects-client/audit.d.ts.map +1 -1
  44. package/dist/core/rest/projects-client/audit.js +49 -4
  45. package/dist/core/rest/projects-client/audit.js.map +1 -1
  46. package/dist/core/rest/projects-client/billing.d.ts +26 -14
  47. package/dist/core/rest/projects-client/billing.d.ts.map +1 -1
  48. package/dist/core/rest/projects-client/billing.js +4 -5
  49. package/dist/core/rest/projects-client/billing.js.map +1 -1
  50. package/dist/core/rest/projects-client/connectors.d.ts +106 -45
  51. package/dist/core/rest/projects-client/connectors.d.ts.map +1 -1
  52. package/dist/core/rest/projects-client/connectors.js +95 -58
  53. package/dist/core/rest/projects-client/connectors.js.map +1 -1
  54. package/dist/core/rest/projects-client/github.d.ts +7 -1
  55. package/dist/core/rest/projects-client/github.d.ts.map +1 -1
  56. package/dist/core/rest/projects-client/github.js.map +1 -1
  57. package/dist/core/rest/projects-client/iam.d.ts +17 -0
  58. package/dist/core/rest/projects-client/iam.d.ts.map +1 -1
  59. package/dist/core/rest/projects-client/iam.js +14 -0
  60. package/dist/core/rest/projects-client/iam.js.map +1 -1
  61. package/dist/core/rest/projects-client/index.d.ts +2 -0
  62. package/dist/core/rest/projects-client/index.d.ts.map +1 -1
  63. package/dist/core/rest/projects-client/index.js +2 -0
  64. package/dist/core/rest/projects-client/index.js.map +1 -1
  65. package/dist/core/rest/projects-client/model-enablement.d.ts +9 -0
  66. package/dist/core/rest/projects-client/model-enablement.d.ts.map +1 -0
  67. package/dist/core/rest/projects-client/model-enablement.js +16 -0
  68. package/dist/core/rest/projects-client/model-enablement.js.map +1 -0
  69. package/dist/core/rest/projects-client/policies.d.ts +18 -0
  70. package/dist/core/rest/projects-client/policies.d.ts.map +1 -1
  71. package/dist/core/rest/projects-client/policies.js.map +1 -1
  72. package/dist/core/rest/projects-client/projects.d.ts +87 -1
  73. package/dist/core/rest/projects-client/projects.d.ts.map +1 -1
  74. package/dist/core/rest/projects-client/projects.js +8 -0
  75. package/dist/core/rest/projects-client/projects.js.map +1 -1
  76. package/dist/core/rest/projects-client/sandbox.d.ts +50 -0
  77. package/dist/core/rest/projects-client/sandbox.d.ts.map +1 -1
  78. package/dist/core/rest/projects-client/sandbox.js.map +1 -1
  79. package/dist/core/rest/projects-client/session-costs.d.ts +102 -0
  80. package/dist/core/rest/projects-client/session-costs.d.ts.map +1 -0
  81. package/dist/core/rest/projects-client/session-costs.js +25 -0
  82. package/dist/core/rest/projects-client/session-costs.js.map +1 -0
  83. package/dist/core/rest/projects-client/session-sandbox.d.ts +0 -2
  84. package/dist/core/rest/projects-client/session-sandbox.d.ts.map +1 -1
  85. package/dist/core/rest/projects-client/session-sandbox.js +1 -10
  86. package/dist/core/rest/projects-client/session-sandbox.js.map +1 -1
  87. package/dist/core/rest/projects-client/sessions.d.ts +94 -44
  88. package/dist/core/rest/projects-client/sessions.d.ts.map +1 -1
  89. package/dist/core/rest/projects-client/sessions.js +9 -15
  90. package/dist/core/rest/projects-client/sessions.js.map +1 -1
  91. package/dist/core/rest/projects-client/setup-links.d.ts +37 -0
  92. package/dist/core/rest/projects-client/setup-links.d.ts.map +1 -1
  93. package/dist/core/rest/projects-client/setup-links.js +11 -0
  94. package/dist/core/rest/projects-client/setup-links.js.map +1 -1
  95. package/dist/core/session/index.d.ts +1 -1
  96. package/dist/core/session/index.d.ts.map +1 -1
  97. package/dist/core/session/index.js +1 -1
  98. package/dist/core/session/index.js.map +1 -1
  99. package/dist/core/session/preview-auth.d.ts +32 -0
  100. package/dist/core/session/preview-auth.d.ts.map +1 -0
  101. package/dist/core/session/preview-auth.js +53 -0
  102. package/dist/core/session/preview-auth.js.map +1 -0
  103. package/dist/core/session/server-store/url-helpers.d.ts.map +1 -1
  104. package/dist/core/session/server-store/url-helpers.js +5 -3
  105. package/dist/core/session/server-store/url-helpers.js.map +1 -1
  106. package/dist/core/session-sync/session-sync-controller.d.ts +12 -1
  107. package/dist/core/session-sync/session-sync-controller.d.ts.map +1 -1
  108. package/dist/core/session-sync/session-sync-controller.js +34 -2
  109. package/dist/core/session-sync/session-sync-controller.js.map +1 -1
  110. package/dist/index.d.ts +1 -2
  111. package/dist/index.d.ts.map +1 -1
  112. package/dist/index.js +0 -1
  113. package/dist/index.js.map +1 -1
  114. package/dist/kortix.esm.min.js +19 -24
  115. package/dist/kortix.global.js +19 -24
  116. package/dist/platform/auth-core.d.ts +5 -3
  117. package/dist/platform/auth-core.d.ts.map +1 -1
  118. package/dist/platform/auth-core.js +6 -4
  119. package/dist/platform/auth-core.js.map +1 -1
  120. package/dist/react/index.d.ts +1 -2
  121. package/dist/react/index.d.ts.map +1 -1
  122. package/dist/react/index.js +0 -1
  123. package/dist/react/index.js.map +1 -1
  124. package/dist/react/model-flatten.d.ts +20 -0
  125. package/dist/react/model-flatten.d.ts.map +1 -1
  126. package/dist/react/model-flatten.js +12 -0
  127. package/dist/react/model-flatten.js.map +1 -1
  128. package/dist/react/opencode.d.ts +4 -3
  129. package/dist/react/opencode.d.ts.map +1 -1
  130. package/dist/react/opencode.js +4 -3
  131. package/dist/react/opencode.js.map +1 -1
  132. package/dist/react/provider-selection.d.ts +9 -0
  133. package/dist/react/provider-selection.d.ts.map +1 -1
  134. package/dist/react/provider-selection.js +23 -0
  135. package/dist/react/provider-selection.js.map +1 -1
  136. package/dist/react/session-title-sync.d.ts +9 -5
  137. package/dist/react/session-title-sync.d.ts.map +1 -1
  138. package/dist/react/session-title-sync.js +14 -10
  139. package/dist/react/session-title-sync.js.map +1 -1
  140. package/dist/react/use-canonical-opencode-session.d.ts +2 -2
  141. package/dist/react/use-canonical-opencode-session.d.ts.map +1 -1
  142. package/dist/react/use-model-enablement.d.ts +25 -0
  143. package/dist/react/use-model-enablement.d.ts.map +1 -0
  144. package/dist/react/use-model-enablement.js +92 -0
  145. package/dist/react/use-model-enablement.js.map +1 -0
  146. package/dist/react/use-model-store.d.ts +6 -14
  147. package/dist/react/use-model-store.d.ts.map +1 -1
  148. package/dist/react/use-model-store.js +30 -52
  149. package/dist/react/use-model-store.js.map +1 -1
  150. package/dist/react/use-opencode-events/handle-event.d.ts.map +1 -1
  151. package/dist/react/use-opencode-events/handle-event.js +103 -41
  152. package/dist/react/use-opencode-events/handle-event.js.map +1 -1
  153. package/dist/react/use-opencode-local.d.ts +5 -4
  154. package/dist/react/use-opencode-local.d.ts.map +1 -1
  155. package/dist/react/use-opencode-local.js +20 -37
  156. package/dist/react/use-opencode-local.js.map +1 -1
  157. package/dist/react/use-opencode-sessions/keys.d.ts +3 -1
  158. package/dist/react/use-opencode-sessions/keys.d.ts.map +1 -1
  159. package/dist/react/use-opencode-sessions/keys.js +2 -0
  160. package/dist/react/use-opencode-sessions/keys.js.map +1 -1
  161. package/dist/react/use-opencode-sessions/sessions.d.ts.map +1 -1
  162. package/dist/react/use-opencode-sessions/sessions.js +16 -7
  163. package/dist/react/use-opencode-sessions/sessions.js.map +1 -1
  164. package/dist/react/use-opencode-sessions/shared.d.ts +3 -2
  165. package/dist/react/use-opencode-sessions/shared.d.ts.map +1 -1
  166. package/dist/react/use-opencode-sessions/shared.js +6 -3
  167. package/dist/react/use-opencode-sessions/shared.js.map +1 -1
  168. package/dist/react/use-opencode-sessions/sharing.js +2 -2
  169. package/dist/react/use-opencode-sessions/sharing.js.map +1 -1
  170. package/dist/react/use-session-sync.d.ts +13 -1
  171. package/dist/react/use-session-sync.d.ts.map +1 -1
  172. package/dist/react/use-session-sync.js +85 -17
  173. package/dist/react/use-session-sync.js.map +1 -1
  174. package/dist/react/use-session.d.ts +60 -40
  175. package/dist/react/use-session.d.ts.map +1 -1
  176. package/dist/react/use-session.js +160 -202
  177. package/dist/react/use-session.js.map +1 -1
  178. package/package.json +2 -2
  179. package/dist/core/acp/client.d.ts +0 -45
  180. package/dist/core/acp/client.d.ts.map +0 -1
  181. package/dist/core/acp/client.js +0 -277
  182. package/dist/core/acp/client.js.map +0 -1
  183. package/dist/core/acp/index.d.ts +0 -5
  184. package/dist/core/acp/index.d.ts.map +0 -1
  185. package/dist/core/acp/index.js +0 -5
  186. package/dist/core/acp/index.js.map +0 -1
  187. package/dist/core/acp/projection.d.ts +0 -23
  188. package/dist/core/acp/projection.d.ts.map +0 -1
  189. package/dist/core/acp/projection.js +0 -603
  190. package/dist/core/acp/projection.js.map +0 -1
  191. package/dist/core/acp/session-controller.d.ts +0 -90
  192. package/dist/core/acp/session-controller.d.ts.map +0 -1
  193. package/dist/core/acp/session-controller.js +0 -530
  194. package/dist/core/acp/session-controller.js.map +0 -1
  195. package/dist/core/acp/types.d.ts +0 -66
  196. package/dist/core/acp/types.d.ts.map +0 -1
  197. package/dist/core/acp/types.js +0 -21
  198. package/dist/core/acp/types.js.map +0 -1
  199. package/dist/core/session/runtime-transport.d.ts +0 -16
  200. package/dist/core/session/runtime-transport.d.ts.map +0 -1
  201. package/dist/core/session/runtime-transport.js +0 -30
  202. package/dist/core/session/runtime-transport.js.map +0 -1
  203. package/dist/react/session-busy.d.ts +0 -8
  204. package/dist/react/session-busy.d.ts.map +0 -1
  205. package/dist/react/session-busy.js +0 -4
  206. package/dist/react/session-busy.js.map +0 -1
  207. package/dist/react/use-acp-session-runtime.d.ts +0 -34
  208. package/dist/react/use-acp-session-runtime.d.ts.map +0 -1
  209. package/dist/react/use-acp-session-runtime.js +0 -84
  210. package/dist/react/use-acp-session-runtime.js.map +0 -1
  211. package/dist/react/use-admin-users.d.ts +0 -98
  212. package/dist/react/use-admin-users.d.ts.map +0 -1
  213. package/dist/react/use-admin-users.js +0 -121
  214. package/dist/react/use-admin-users.js.map +0 -1
package/README.md CHANGED
@@ -24,9 +24,12 @@ npm install @kortix/sdk
24
24
  ```
25
25
 
26
26
  ```ts
27
- import { createKortix } from '@kortix/sdk';
27
+ import { createKortix } from "@kortix/sdk";
28
28
 
29
- const kortix = createKortix({ backendUrl: 'https://api.kortix.com/v1', getToken });
29
+ const kortix = createKortix({
30
+ backendUrl: "https://api.kortix.com/v1",
31
+ getToken,
32
+ });
30
33
  await kortix.projects.list();
31
34
  ```
32
35
 
@@ -53,10 +56,10 @@ no build step required:
53
56
  `@kortix/sdk` is the canonical entry — everything framework-free lives there.
54
57
  Three others exist, each for a reason that fits in one sentence:
55
58
 
56
- | Entry | Why it can't live at root |
57
- |---|---|
58
- | `@kortix/sdk/react` | React is a peer dependency |
59
- | `@kortix/sdk/server` | imports `node:async_hooks` |
59
+ | Entry | Why it can't live at root |
60
+ | ------------------------ | --------------------------- |
61
+ | `@kortix/sdk/react` | React is a peer dependency |
62
+ | `@kortix/sdk/server` | imports `node:async_hooks` |
60
63
  | `@kortix/sdk/internal/*` | unsupported, outside semver |
61
64
 
62
65
  Older subpaths (`@kortix/sdk/projects-client`, `/turns`, …) still work and are
@@ -70,46 +73,70 @@ table for the full list (20 of them).
70
73
  ## Quick start
71
74
 
72
75
  ```ts
73
- import { createKortix } from '@kortix/sdk';
76
+ import { createKortix } from "@kortix/sdk";
74
77
 
75
78
  const kortix = createKortix({
76
- backendUrl: 'https://api.kortix.com/v1',
77
- getToken: () => supabase.auth.getSession().then(s => s.data.session?.access_token ?? null),
79
+ backendUrl: "https://api.kortix.com/v1",
80
+ getToken: () =>
81
+ supabase.auth
82
+ .getSession()
83
+ .then((s) => s.data.session?.access_token ?? null),
78
84
  });
79
85
 
80
86
  // Projects
81
87
  const projects = await kortix.projects.list();
82
- const detail = await kortix.project(pid).detail();
83
- await kortix.project(pid).secrets.upsert({ name: 'STRIPE_API_KEY', value });
88
+ const detail = await kortix.project(pid).detail();
89
+ await kortix.project(pid).secrets.upsert({ name: "STRIPE_API_KEY", value });
84
90
  const visibleSessions = await kortix.project(pid).sessions.list();
85
- const projectInventory = await kortix.project(pid).sessions.list({ scope: 'project' }); // manager only
91
+ const projectInventory = await kortix
92
+ .project(pid)
93
+ .sessions.list({ scope: "project" }); // manager only
86
94
  const warm = await kortix.project(pid).sessions.ensureWarm();
87
- await kortix.project(pid).sessions.claimWarm({ session_id: warm.session.session_id });
95
+ await kortix
96
+ .project(pid)
97
+ .sessions.claimWarm({ session_id: warm.session.session_id });
88
98
 
89
99
  // Sessions (id-bound handle)
90
100
  const s = kortix.session(pid, sid);
91
- await s.send('Build me a widget'); // provisions/resumes if needed, then prompts
92
- await s.rewind(userMessageId); // stages a reversible rollback on this session
93
- await s.restoreRewind(); // restores the removed path before the next prompt
101
+ const cost = await s.cost(); // reads finalized LLM + compute cost; no runtime start
102
+ await s.send("Build me a widget"); // provisions/resumes if needed, then prompts
103
+ await s.rewind(userMessageId); // stages a reversible rollback on this session
104
+ await s.restoreRewind(); // restores the removed path before the next prompt
94
105
  await s.previews();
95
106
 
96
- // Lower level: the typed opencode client for THIS session's runtime.
107
+ // Lower level: the typed OpenCode REST compatibility client for THIS sandbox.
97
108
  // `.runtime` throws until the runtime is resolved, and the runtime is keyed by
98
109
  // the OpenCode session id (NOT the Kortix `sid`) — resolve both via ensureReady.
99
110
  const { opencodeSessionId } = await s.ensureReady();
100
111
  await s.runtime.session.prompt({ sessionID: opencodeSessionId, parts });
101
112
  ```
102
113
 
103
- ### React runtime transport
114
+ For OpenCode REST sessions, `send()` reads the persisted session model and
115
+ agent before the first prompt on a handle. This prevents a snapshot-inherited
116
+ OpenCode session from reusing stale snapshot defaults. A per-call choice
117
+ overrides a `setModel()` or `setAgent()` choice. A handle choice overrides the
118
+ persisted session default.
119
+
120
+ ### React runtime
104
121
 
105
- `useSession(projectId, sessionId)` uses the transport selected by `POST /start`.
106
- The default is the OpenCode REST client. A project with the `acp_runtime`
107
- experiment uses OpenCode ACP through the authenticated sandbox bridge.
108
- The hook keeps one return shape for both transports. It routes messages,
109
- message rewind and restore, cancellation, commands, permissions, and questions
110
- inside the SDK. A host does not construct ACP routes or branch on the selected
111
- transport. Disable `acp_runtime` to return that project to REST without a
112
- frontend deployment.
122
+ `useSession(projectId, sessionId)` opens the OpenCode REST runtime returned by
123
+ `POST /start`. The hook owns messages, rewind and restore, cancellation,
124
+ commands, permissions, and questions. Hosts do not construct runtime routes.
125
+
126
+ A server-rendered host can seed a known OpenCode pin while `/start` runs:
127
+
128
+ ```tsx
129
+ useSession(projectId, sessionId, {
130
+ initialOpenCodeSessionId: persistedSession.opencode_session_id,
131
+ });
132
+ ```
133
+
134
+ Use only a pin that the host authorized for the same `(projectId, sessionId)`.
135
+ The seed hydrates cached content. It does not choose the runtime identity.
136
+ The pin returned by `/start` always replaces a stale seed. The SDK also scopes
137
+ OpenCode query and synchronization controllers to the sandbox runtime. Two
138
+ sandboxes cannot share browser cache state when a snapshot exposes the same
139
+ OpenCode id during adoption.
113
140
 
114
141
  ## The facade surface
115
142
 
@@ -119,13 +146,13 @@ exhaustive — see `API-MAP.md` for the full per-domain surface:
119
146
  | namespace | what |
120
147
  |---|---|
121
148
  | `kortix.projects` | list · get · detail · create · provision · update · archive · llmCatalog · modelPicker · sandboxTemplates · sessions (+ more: `listForAccount`, `sandboxHealth`, `createSession`) |
122
- | `kortix.accounts` | list · get · create · members · invites · `tokens.{list,create,revoke}` (account-scoped CLI PATs, `kortix_pat_…`) · `audit.{log,export,webhooks.*}` (Enterprise audit trail) (+ more: `updateName`, `leave`, `invite`, `removeMember`, `updateMemberRole`) |
123
- | `kortix.billing` | entitlement/usage reads: `accountState` · `accountStateMinimal` · `transactions` · `transactionsSummary` · `creditBreakdown` · `usageHistory` · `tierConfigurations` — plus a curated mutation surface: `checkout.{createSession,confirmSession}` · `subscription.{createPortalSession,cancel,reactivate,scheduleDowngrade,cancelScheduledChange,prorationPreview}` · `credits.{purchase,autoTopupSettings,configureAutoTopup}` |
149
+ | `kortix.accounts` | list · get · create · members · invites · `tokens.{list,create,revoke}` (account-scoped CLI PATs, `kortix_pat_…`) · `audit.{log,export,webhooks.*}` (filterable project/session reconstruction log) (+ more: `updateName`, `leave`, `invite`, `removeMember`, `updateMemberRole`) |
150
+ | `kortix.billing` | entitlement/usage reads: `accountState` · `accountStateMinimal` · `transactions` · `transactionsSummary` · `creditBreakdown` · `usageHistory` · `usageRollup` · `sessionCosts.{list,get}` · `tierConfigurations` — plus a curated mutation surface: `checkout.{createSession,confirmSession}` · `subscription.{createPortalSession,cancel,reactivate,scheduleDowngrade,cancelScheduledChange,prorationPreview}` · `credits.{purchase,autoTopupSettings,configureAutoTopup}` |
124
151
  | `kortix.marketplace` | public marketplace catalog browse + sources (not project-scoped): `items` · `item` · `itemFile` · `marketplaces` · `featured` · `sources.{list,add,remove}` — distinct from the install-scoped `project(id).marketplace` |
125
152
  | `kortix.validateToken()` | pasted-API-key validation helper — `GET /accounts/me`, never throws, resolves `{valid, identity?, error?}` |
126
153
  | `kortix.project(id)` | id-bound handle: `.secrets` · `.access` · `.connectors` · `.policies` · `.triggers` · `.files` · `.git` · `.changeRequests` (incl. `requestChanges`) · `.sessions` · `.tokens` (project-scoped CLI PATs — the `KORTIX_TOKEN` shape) · `.marketplace` / `.registry` (install/update/remove catalog items) · `.setupLinks.{requestSecret,requestConnector}` (agent-minted secret-entry / connector links) · `.validateManifest` · `.gitToken` · `.setDefaultAgent(name)` · `.session(sid)` (+ more namespaces: `.review`, `.approvals`, `.gateway` (incl. `.routing` and `.playground`), `.channels`, `.modelDefaults`, `.sandbox`) |
127
- | `kortix.session(pid, sid)` | id-bound handle: lifecycle (`get`/`update`/`delete`/`start`/`restart`/`stop`/`setSharing`/`previews`/`commit`/`publicShares`/`ensureReady`) · `send`/`abort`/`rewind`/`restoreRewind`/`setModel`/`setAgent` (opinionated prompt wrappers) · `stream()` (live SSE, framework-free) · `transcript()` (compact server-side transcript read) · `.files` (the 12-op workspace-files surface, bound to THIS session's own runtime) · **its own runtime** (`health`/`previewUrl`/`proxyUrl` sandbox resolved for you) + `.runtime` (the typed opencode client) |
128
- | `kortix.runtime()` | the opencode v2 client for the active sandbox (escape hatch) |
154
+ | `kortix.session(pid, sid)` | id-bound handle: lifecycle (`get`/`update`/`delete`/`start`/`restart`/`stop`/`setSharing`/`previews`/`commit`/`publicShares`/`ensureReady`) · finalized `cost()` · `send`/`abort`/`rewind`/`restoreRewind`/`setModel`/`setAgent` · `transcript()` · `.files` · runtime URL helpers (`health`/`previewUrl`/`proxyUrl`) · OpenCode REST compatibility escape hatches: `stream()` and `.runtime` |
155
+ | `kortix.runtime()` | the OpenCode v2 compatibility client for the active sandbox; use a session-scoped handle in multi-tenant code |
129
156
 
130
157
  Runnable, self-contained scripts for the highest-value flows live in
131
158
  [`examples/`](./examples): list projects with a PAT, send + stream, the
@@ -140,7 +167,7 @@ to the agent only as one `KORTIX_SESSION_CONTEXT` JSON envelope:
140
167
 
141
168
  ```ts
142
169
  await kortix.project(projectId).sessions.create({
143
- runtime_context: { workspace_id: 'org_123', locale: 'de' },
170
+ runtime_context: { workspace_id: "org_123", locale: "de" },
144
171
  });
145
172
  ```
146
173
 
@@ -151,27 +178,27 @@ credential endpoint, and pass only the non-secret profile id at session create:
151
178
  ```ts
152
179
  const project = kortix.project(projectId);
153
180
  const profile = await project.connectors.profiles.reconcile({
154
- connector_alias: 'customer-data',
155
- owner_type: 'external',
181
+ connector_alias: "customer-data",
182
+ owner_type: "external",
156
183
  owner_id: wrapperUserId,
157
- label: 'Customer data',
184
+ label: "Customer data",
158
185
  metadata: { tenant_ref: wrapperTenantReference },
159
186
  });
160
187
 
161
188
  // Omit `auth` when creating to apply source-advertised authentication.
162
189
  const auth = await project.connectors.auth.discover({
163
- slug: 'hubspot',
164
- provider: 'postman',
165
- spec: 'https://github.com/HubSpot/HubSpot-public-api-spec-collection',
190
+ slug: "hubspot",
191
+ provider: "postman",
192
+ spec: "https://github.com/HubSpot/HubSpot-public-api-spec-collection",
166
193
  });
167
194
  await project.connectors.profiles.updateCredential(profile.profile_id, {
168
195
  value: shortLivedCapability,
169
- kind: 'secret',
196
+ kind: "secret",
170
197
  });
171
198
  await project.sessions.create({
172
- runtime_context: { locale: 'de' },
199
+ runtime_context: { locale: "de" },
173
200
  connector_bindings: {
174
- 'customer-data': { profile_id: profile.profile_id },
201
+ "customer-data": { profile_id: profile.profile_id },
175
202
  },
176
203
  });
177
204
  ```
@@ -182,8 +209,8 @@ token:
182
209
 
183
210
  ```ts
184
211
  const profile = await project.connectors.profiles.reconcileMember({
185
- connector_alias: 'gmail',
186
- label: 'My Gmail',
212
+ connector_alias: "gmail",
213
+ label: "My Gmail",
187
214
  });
188
215
  await project.connectors.profiles.pipedreamConnect(profile.profile_id);
189
216
  // Complete OAuth, then:
@@ -201,7 +228,8 @@ restart. Credentials are encrypted server-side and are never returned, placed
201
228
  in `KORTIX_SESSION_CONTEXT`, or injected into the sandbox environment. Raw env
202
229
  and MCP configuration are not session-create inputs.
203
230
 
204
- `session.stream()` is a thin facade over the framework-free `openEventStream`
231
+ For OpenCode REST sessions, `session.stream()` is a thin facade over the
232
+ framework-free `openEventStream`
205
233
  primitive (also exported directly, for hosts that want to manage the client
206
234
  themselves): it resolves THIS handle's own runtime (`ensureReady()`), connects
207
235
  to that runtime's SSE endpoint, and hands you a `close()`-able handle. No React
@@ -217,6 +245,8 @@ const handle = await kortix.session(pid, sid).stream({
217
245
  handle.close();
218
246
  ```
219
247
 
248
+ `session.stream()` emits OpenCode v2 events. Use `useSession()` in React.
249
+
220
250
  `@kortix/sdk/react`'s `useOpenCodeEventStream` uses the exact same primitive
221
251
  under the hood — it just also writes into the React Query cache.
222
252
 
@@ -234,12 +264,12 @@ in-flight request.
234
264
  it statically imports `node:async_hooks`) fixes this with `AsyncLocalStorage`:
235
265
 
236
266
  ```ts
237
- import { createScopedKortix } from '@kortix/sdk/server';
267
+ import { createScopedKortix } from "@kortix/sdk/server";
238
268
 
239
269
  // Express/Hono/Bun.serve — any per-request handler. One scoped client PER
240
270
  // REQUEST; each end user's token stays isolated to that request's own async
241
271
  // call tree, even across `await`s, even under concurrency.
242
- app.get('/projects', async (req, res) => {
272
+ app.get("/projects", async (req, res) => {
243
273
  const kortix = createScopedKortix({
244
274
  backendUrl: process.env.KORTIX_API_URL!,
245
275
  getToken: async () => resolveKortixTokenFor(req), // per-end-user PAT/token
@@ -255,7 +285,7 @@ it never writes the process-global singleton. For middleware-style wrapping of
255
285
  an entire request body instead, use the lower-level primitive:
256
286
 
257
287
  ```ts
258
- import { runWithKortix } from '@kortix/sdk/server';
288
+ import { runWithKortix } from "@kortix/sdk/server";
259
289
 
260
290
  app.use(async (req, res, next) => {
261
291
  await runWithKortix(
@@ -286,8 +316,8 @@ renderer for **every** part kind at compile time, so a new part type is a
286
316
  build error at your call site instead of a silent drop in production:
287
317
 
288
318
  ```tsx
289
- import { renderParts, type PartRenderers } from '@kortix/sdk/react';
290
- import { classifyTurn } from '@kortix/sdk/turns';
319
+ import { renderParts, type PartRenderers } from "@kortix/sdk/react";
320
+ import { classifyTurn } from "@kortix/sdk/turns";
291
321
 
292
322
  const renderers: PartRenderers<React.ReactNode> = {
293
323
  text: (p) => <Markdown>{p.text}</Markdown>,
@@ -298,16 +328,21 @@ const renderers: PartRenderers<React.ReactNode> = {
298
328
  patch: (p) => <DiffStat files={p.fileCount} />,
299
329
  retry: (p) => <Note>{`retrying (attempt ${p.attempt})`}</Note>,
300
330
  compaction: () => <Note>context compacted</Note>,
301
- snapshot: () => null, // internal checkpoint hash — nothing to show
302
- agent: () => null, // inline @mention, already in the sibling text
303
- step: () => null, // model-step bookkeeping
304
- unknown: () => null, // forward-compat: newer server than client
331
+ snapshot: () => null, // internal checkpoint hash — nothing to show
332
+ agent: () => null, // inline @mention, already in the sibling text
333
+ step: () => null, // model-step bookkeeping
334
+ unknown: () => null, // forward-compat: newer server than client
305
335
  };
306
336
 
307
337
  function Turn({ message }: { message: MessageWithParts }) {
308
338
  const { parts, error, isEmpty } = classifyTurn(message);
309
339
  if (isEmpty && !error) return null;
310
- return <>{renderParts(parts, renderers)}{error && <TurnFailed {...error} />}</>;
340
+ return (
341
+ <>
342
+ {renderParts(parts, renderers)}
343
+ {error && <TurnFailed {...error} />}
344
+ </>
345
+ );
311
346
  }
312
347
  ```
313
348
 
@@ -346,17 +381,19 @@ The canonical server-side wrapper shape — catch a 402 and pass the payload
346
381
  through to your own client for re-billing, instead of leaking a Kortix error:
347
382
 
348
383
  ```ts
349
- import { ApiError, AuthError, BillingError } from '@kortix/sdk';
384
+ import { ApiError, AuthError, BillingError } from "@kortix/sdk";
350
385
 
351
386
  try {
352
387
  await kortix.session(pid, sid).send(prompt);
353
388
  } catch (err) {
354
389
  if (err instanceof BillingError) {
355
390
  // 402 — surface the upgrade/cost payload under YOUR billing story.
356
- return res.status(402).json({ reason: 'quota', detail: err.detail });
391
+ return res.status(402).json({ reason: "quota", detail: err.detail });
357
392
  }
358
- if (err instanceof AuthError) return res.status(401).json({ error: 'not authenticated' });
359
- if (err instanceof ApiError) return res.status(err.status ?? 502).json({ error: err.message });
393
+ if (err instanceof AuthError)
394
+ return res.status(401).json({ error: "not authenticated" });
395
+ if (err instanceof ApiError)
396
+ return res.status(err.status ?? 502).json({ error: err.message });
360
397
  throw err;
361
398
  }
362
399
  ```
@@ -379,19 +416,19 @@ Stable, tree-shakeable surfaces (also reachable via the facade). Not exhaustive
379
416
  `./sandbox-connection-store`, `./opencode-pending-store`, `./session/url`,
380
417
  `./idb-sync-cache`):
381
418
 
382
- | import | provides |
383
- |---|---|
384
- | `@kortix/sdk` | `createKortix`, `configureKortix`, `files`, the error classes, `classifyPart`/`classifyTurn`, `narrowChatEvent`, `openEventStream`, domain result types |
385
- | `@kortix/sdk/server` | **Node/Bun only** — `runWithKortix`, `createScopedKortix`, `getScopedConfig` (per-request config isolation; see "Kortix as a Backend") |
386
- | `@kortix/sdk/react` | every `useOpenCode*` hook + providers (reactive data), `useSession`, `useChatTurns`/`renderParts`, domain hooks (`useProjectSecrets`/`useProjectTriggers`/`useChangeRequests`) |
387
- | `@kortix/sdk/turns` | framework-free part/turn classification (`classifyPart`, `classifyTurn`, `toolInfo`, turn grouping/cost helpers) |
388
- | `@kortix/sdk/files` | workspace file ops (daemon `/file` + `/find`): `listFiles`, `readFile`, `readBlob`, `getFileStatus`, `findFiles`, `findText`, `uploadFile`, `deleteFile`, `mkdir`, `renameFile`, … |
389
- | `@kortix/sdk/session` | a session's runtime surface — `getSessionHealth`/`isRuntimeReady` + proxy/preview URL builders (`rewriteLocalhostUrl`, `proxyLocalhostUrl`, `detectLocalhostUrls`, …) + preview-auth helpers. **No "sandbox" in the public surface** — a session owns its runtime |
390
- | `@kortix/sdk/opencode-client` | `getClient`, `getClientForUrl` + the **full opencode v2 type surface** (`Event`, `Part`, `Message`, `Session`, `Pty`, `Config`, …) |
391
- | `@kortix/sdk/projects-client` | the raw REST functions (the facade wraps these) |
392
- | `@kortix/sdk/auth` | `authenticatedFetch`, token accessors |
393
- | `@kortix/sdk/api-client` | the raw `backendApi` primitive — host code should go through the facade or another subpath module instead of calling this directly |
394
- | `@kortix/sdk/server-store` · `@kortix/sdk/sync-store` | active-sandbox state · live message/part/status store |
419
+ | import | provides |
420
+ | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
421
+ | `@kortix/sdk` | `createKortix`, `configureKortix`, `files`, the error classes, `classifyPart`/`classifyTurn`, `narrowChatEvent`, `openEventStream`, domain result types |
422
+ | `@kortix/sdk/server` | **Node/Bun only** — `runWithKortix`, `createScopedKortix`, `getScopedConfig` (per-request config isolation; see "Kortix as a Backend") |
423
+ | `@kortix/sdk/react` | every `useOpenCode*` hook + providers (reactive data), `useSession`, `useChatTurns`/`renderParts`, domain hooks (`useProjectSecrets`/`useProjectTriggers`/`useChangeRequests`) |
424
+ | `@kortix/sdk/turns` | framework-free part/turn classification (`classifyPart`, `classifyTurn`, `toolInfo`, turn grouping/cost helpers) |
425
+ | `@kortix/sdk/files` | workspace file ops (daemon `/file` + `/find`): `listFiles`, `readFile`, `readBlob`, `getFileStatus`, `findFiles`, `findText`, `uploadFile`, `deleteFile`, `mkdir`, `renameFile`, … |
426
+ | `@kortix/sdk/session` | a session's runtime surface — `getSessionHealth`/`isRuntimeReady` + proxy/preview URL builders (`rewriteLocalhostUrl`, `proxyLocalhostUrl`, `detectLocalhostUrls`, …) + preview-auth helpers. **No "sandbox" in the public surface** — a session owns its runtime |
427
+ | `@kortix/sdk/opencode-client` | `getClient`, `getClientForUrl` + the **full opencode v2 type surface** (`Event`, `Part`, `Message`, `Session`, `Pty`, `Config`, …) |
428
+ | `@kortix/sdk/projects-client` | the raw REST functions (the facade wraps these) |
429
+ | `@kortix/sdk/auth` | `authenticatedFetch`, token accessors |
430
+ | `@kortix/sdk/api-client` | the raw `backendApi` primitive — host code should go through the facade or another subpath module instead of calling this directly |
431
+ | `@kortix/sdk/server-store` · `@kortix/sdk/sync-store` | active-sandbox state · live message/part/status store |
395
432
 
396
433
  ## Configuration
397
434
 
@@ -447,6 +484,6 @@ pnpm --filter @kortix/sdk typecheck # package + examples/ (examples/tsconfig.js
447
484
  pnpm --filter @kortix/sdk test # facade, files, react hooks, turns, transcript, session url/health, projects-client domains
448
485
  ```
449
486
 
450
- See **`API-MAP.md`** for the complete endpoint catalogue (REST + opencode runtime)
451
- and per-domain SDK coverage status, and **`CHANGELOG.md`** for what changed per
452
- release.
487
+ See **`API-MAP.md`** for the complete endpoint catalogue. It covers the Kortix
488
+ REST API and OpenCode REST runtime. See **`CHANGELOG.md`** for
489
+ per-release changes.
@@ -0,0 +1,2 @@
1
+ export declare function buildSessionCacheKey(userScope: string, openCodeSessionId: string, kortixSessionScope?: string): string;
2
+ //# sourceMappingURL=idb-sync-cache-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idb-sync-cache-key.d.ts","sourceRoot":"","sources":["../../../src/browser/cache/idb-sync-cache-key.ts"],"names":[],"mappings":"AAAA,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,EACzB,kBAAkB,CAAC,EAAE,MAAM,GAC1B,MAAM,CAKR"}
@@ -0,0 +1,7 @@
1
+ export function buildSessionCacheKey(userScope, openCodeSessionId, kortixSessionScope) {
2
+ if (!kortixSessionScope) {
3
+ return `${userScope}:session:${openCodeSessionId}`;
4
+ }
5
+ return `${userScope}:kortix-session:${encodeURIComponent(kortixSessionScope)}`;
6
+ }
7
+ //# sourceMappingURL=idb-sync-cache-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idb-sync-cache-key.js","sourceRoot":"","sources":["../../../src/browser/cache/idb-sync-cache-key.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,oBAAoB,CAClC,SAAiB,EACjB,iBAAyB,EACzB,kBAA2B;IAE3B,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACxB,OAAO,GAAG,SAAS,YAAY,iBAAiB,EAAE,CAAC;IACrD,CAAC;IACD,OAAO,GAAG,SAAS,mBAAmB,kBAAkB,CAAC,kBAAkB,CAAC,EAAE,CAAC;AACjF,CAAC"}
@@ -5,14 +5,14 @@
5
5
  * Schema: one object store "sessions" keyed by cacheKey, each entry holds
6
6
  * { cacheKey, userId, sessionId, messages, parts, updatedAt }.
7
7
  */
8
- export declare function saveSessionToIDB(sessionId: string, messages: any[], parts: Record<string, any[]>): Promise<void>;
8
+ export declare function saveSessionToIDB(sessionId: string, messages: any[], parts: Record<string, any[]>, kortixSessionScope?: string): Promise<void>;
9
9
  export declare function flushIDBWrites(): Promise<void>;
10
- export declare function loadSessionFromIDB(sessionId: string): Promise<{
10
+ export declare function loadSessionFromIDB(sessionId: string, kortixSessionScope?: string): Promise<{
11
11
  messages: any[];
12
12
  parts: Record<string, any[]>;
13
13
  } | null>;
14
14
  export declare function loadAllSessionIdsFromIDB(): Promise<string[]>;
15
- export declare function deleteSessionFromIDB(sessionId: string): Promise<void>;
15
+ export declare function deleteSessionFromIDB(sessionId: string, kortixSessionScope?: string): Promise<void>;
16
16
  export declare function clearSessionIDBCache(): Promise<void>;
17
17
  export declare function pruneIDBCache(): Promise<void>;
18
18
  //# sourceMappingURL=idb-sync-cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"idb-sync-cache.d.ts","sourceRoot":"","sources":["../../../src/browser/cache/idb-sync-cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAuGH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,GAAG,EAAE,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAC3B,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAgB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAK9C;AAED,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;CAAE,GAAG,IAAI,CAAC,CAuBnE;AAED,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAiBlE;AAED,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3E;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAa1D;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CA0BnD"}
1
+ {"version":3,"file":"idb-sync-cache.d.ts","sourceRoot":"","sources":["../../../src/browser/cache/idb-sync-cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAmHH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,GAAG,EAAE,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,EAC5B,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,IAAI,CAAC,CAef;AAED,wBAAgB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAK9C;AAED,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC;IAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;CAAE,GAAG,IAAI,CAAC,CA4BnE;AAED,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAiBlE;AAED,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAa1D;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CA6BnD"}
@@ -6,9 +6,10 @@
6
6
  * { cacheKey, userId, sessionId, messages, parts, updatedAt }.
7
7
  */
8
8
  import { platformConfig } from '../../core/http/config.js';
9
- const DB_NAME = "kortix-session-cache";
9
+ import { buildSessionCacheKey } from './idb-sync-cache-key.js';
10
+ const DB_NAME = 'kortix-session-cache';
10
11
  const DB_VERSION = 2;
11
- const STORE_NAME = "sessions";
12
+ const STORE_NAME = 'sessions';
12
13
  const MAX_CACHED_SESSIONS = 50;
13
14
  const MAX_SESSION_AGE_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
14
15
  async function getCurrentCacheScope() {
@@ -20,16 +21,13 @@ async function getCurrentCacheScope() {
20
21
  return null;
21
22
  }
22
23
  }
23
- function buildCacheKey(scope, sessionId) {
24
- return `${scope}:session:${sessionId}`;
25
- }
26
24
  let dbPromise = null;
27
25
  function openDB() {
28
26
  if (dbPromise)
29
27
  return dbPromise;
30
28
  dbPromise = new Promise((resolve, reject) => {
31
- if (typeof indexedDB === "undefined") {
32
- reject(new Error("IndexedDB not available"));
29
+ if (typeof indexedDB === 'undefined') {
30
+ reject(new Error('IndexedDB not available'));
33
31
  return;
34
32
  }
35
33
  const req = indexedDB.open(DB_NAME, DB_VERSION);
@@ -39,7 +37,7 @@ function openDB() {
39
37
  db.deleteObjectStore(STORE_NAME);
40
38
  }
41
39
  if (!db.objectStoreNames.contains(STORE_NAME)) {
42
- db.createObjectStore(STORE_NAME, { keyPath: "cacheKey" });
40
+ db.createObjectStore(STORE_NAME, { keyPath: 'cacheKey' });
43
41
  }
44
42
  };
45
43
  req.onsuccess = () => resolve(req.result);
@@ -53,17 +51,25 @@ function openDB() {
53
51
  const pendingWrites = new Map();
54
52
  let flushTimer = null;
55
53
  const FLUSH_INTERVAL_MS = 500;
54
+ // The caps below are only real if something enforces them. Prune once per page
55
+ // load, off the back of the first flush, so the cache cannot grow forever
56
+ // without any host having to remember to call it.
57
+ let prunedThisLoad = false;
56
58
  async function flushPendingWrites() {
57
59
  flushTimer = null;
58
60
  if (pendingWrites.size === 0)
59
61
  return;
62
+ if (!prunedThisLoad) {
63
+ prunedThisLoad = true;
64
+ void pruneIDBCache();
65
+ }
60
66
  const batch = new Map(pendingWrites);
61
67
  pendingWrites.clear();
62
68
  try {
63
69
  const db = await openDB();
64
- const tx = db.transaction(STORE_NAME, "readwrite");
70
+ const tx = db.transaction(STORE_NAME, 'readwrite');
65
71
  const store = tx.objectStore(STORE_NAME);
66
- for (const [cacheKey, { scope, sessionId, messages, parts }] of batch) {
72
+ for (const [cacheKey, { scope, sessionId, kortixSessionScope, messages, parts }] of batch) {
67
73
  const partsForSession = {};
68
74
  for (const msg of messages) {
69
75
  if (parts[msg.id]) {
@@ -74,6 +80,7 @@ async function flushPendingWrites() {
74
80
  cacheKey,
75
81
  userId: scope,
76
82
  sessionId,
83
+ kortixSessionScope,
77
84
  messages,
78
85
  parts: partsForSession,
79
86
  updatedAt: Date.now(),
@@ -88,12 +95,18 @@ async function flushPendingWrites() {
88
95
  // Non-critical
89
96
  }
90
97
  }
91
- export async function saveSessionToIDB(sessionId, messages, parts) {
98
+ export async function saveSessionToIDB(sessionId, messages, parts, kortixSessionScope) {
92
99
  const scope = await getCurrentCacheScope();
93
100
  if (!scope)
94
101
  return;
95
- const cacheKey = buildCacheKey(scope, sessionId);
96
- pendingWrites.set(cacheKey, { scope, sessionId, messages, parts });
102
+ const cacheKey = buildSessionCacheKey(scope, sessionId, kortixSessionScope);
103
+ pendingWrites.set(cacheKey, {
104
+ scope,
105
+ sessionId,
106
+ kortixSessionScope,
107
+ messages,
108
+ parts,
109
+ });
97
110
  if (!flushTimer) {
98
111
  flushTimer = setTimeout(flushPendingWrites, FLUSH_INTERVAL_MS);
99
112
  }
@@ -104,25 +117,32 @@ export function flushIDBWrites() {
104
117
  }
105
118
  return flushPendingWrites();
106
119
  }
107
- export async function loadSessionFromIDB(sessionId) {
120
+ export async function loadSessionFromIDB(sessionId, kortixSessionScope) {
108
121
  try {
109
122
  const scope = await getCurrentCacheScope();
110
123
  if (!scope)
111
124
  return null;
112
125
  const db = await openDB();
113
- const tx = db.transaction(STORE_NAME, "readonly");
126
+ const tx = db.transaction(STORE_NAME, 'readonly');
114
127
  const store = tx.objectStore(STORE_NAME);
115
- const req = store.get(buildCacheKey(scope, sessionId));
128
+ const req = store.get(buildSessionCacheKey(scope, sessionId, kortixSessionScope));
116
129
  const result = await new Promise((resolve, reject) => {
117
130
  req.onsuccess = () => resolve(req.result);
118
131
  req.onerror = () => reject(req.error);
119
132
  });
120
133
  if (!result)
121
134
  return null;
122
- if (result.userId !== scope || result.sessionId !== sessionId)
135
+ if (result.userId !== scope)
123
136
  return null;
137
+ if (kortixSessionScope) {
138
+ if (result.kortixSessionScope !== kortixSessionScope)
139
+ return null;
140
+ }
141
+ else if (result.sessionId !== sessionId) {
142
+ return null;
143
+ }
124
144
  if (Date.now() - result.updatedAt > MAX_SESSION_AGE_MS) {
125
- deleteSessionFromIDB(sessionId);
145
+ deleteSessionFromIDB(sessionId, kortixSessionScope);
126
146
  return null;
127
147
  }
128
148
  return { messages: result.messages, parts: result.parts };
@@ -137,7 +157,7 @@ export async function loadAllSessionIdsFromIDB() {
137
157
  if (!scope)
138
158
  return [];
139
159
  const db = await openDB();
140
- const tx = db.transaction(STORE_NAME, "readonly");
160
+ const tx = db.transaction(STORE_NAME, 'readonly');
141
161
  const store = tx.objectStore(STORE_NAME);
142
162
  const req = store.getAll();
143
163
  const entries = await new Promise((resolve, reject) => {
@@ -150,14 +170,14 @@ export async function loadAllSessionIdsFromIDB() {
150
170
  return [];
151
171
  }
152
172
  }
153
- export async function deleteSessionFromIDB(sessionId) {
173
+ export async function deleteSessionFromIDB(sessionId, kortixSessionScope) {
154
174
  try {
155
175
  const scope = await getCurrentCacheScope();
156
176
  if (!scope)
157
177
  return;
158
178
  const db = await openDB();
159
- const tx = db.transaction(STORE_NAME, "readwrite");
160
- tx.objectStore(STORE_NAME).delete(buildCacheKey(scope, sessionId));
179
+ const tx = db.transaction(STORE_NAME, 'readwrite');
180
+ tx.objectStore(STORE_NAME).delete(buildSessionCacheKey(scope, sessionId, kortixSessionScope));
161
181
  }
162
182
  catch {
163
183
  // ignore
@@ -171,7 +191,7 @@ export async function clearSessionIDBCache() {
171
191
  flushTimer = null;
172
192
  }
173
193
  const db = await openDB();
174
- const tx = db.transaction(STORE_NAME, "readwrite");
194
+ const tx = db.transaction(STORE_NAME, 'readwrite');
175
195
  tx.objectStore(STORE_NAME).clear();
176
196
  }
177
197
  catch {
@@ -181,7 +201,7 @@ export async function clearSessionIDBCache() {
181
201
  export async function pruneIDBCache() {
182
202
  try {
183
203
  const db = await openDB();
184
- const tx = db.transaction(STORE_NAME, "readwrite");
204
+ const tx = db.transaction(STORE_NAME, 'readwrite');
185
205
  const store = tx.objectStore(STORE_NAME);
186
206
  const req = store.getAll();
187
207
  const entries = await new Promise((resolve, reject) => {
@@ -189,16 +209,19 @@ export async function pruneIDBCache() {
189
209
  req.onerror = () => reject(req.error);
190
210
  });
191
211
  const now = Date.now();
212
+ // Delete by `cacheKey` — it is the store's keyPath. Deleting by `sessionId`
213
+ // matched no record, so prune silently kept every entry forever and the
214
+ // 50-session / 7-day caps were never enforced.
192
215
  const stale = entries.filter((e) => now - e.updatedAt > MAX_SESSION_AGE_MS);
193
216
  for (const e of stale) {
194
- store.delete(e.sessionId);
217
+ store.delete(e.cacheKey);
195
218
  }
196
219
  const fresh = entries
197
220
  .filter((e) => now - e.updatedAt <= MAX_SESSION_AGE_MS)
198
221
  .sort((a, b) => b.updatedAt - a.updatedAt);
199
222
  if (fresh.length > MAX_CACHED_SESSIONS) {
200
223
  for (const e of fresh.slice(MAX_CACHED_SESSIONS)) {
201
- store.delete(e.sessionId);
224
+ store.delete(e.cacheKey);
202
225
  }
203
226
  }
204
227
  }
@@ -1 +1 @@
1
- {"version":3,"file":"idb-sync-cache.js","sourceRoot":"","sources":["../../../src/browser/cache/idb-sync-cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"idb-sync-cache.js","sourceRoot":"","sources":["../../../src/browser/cache/idb-sync-cache.ts"],"names":[],"mappings":"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"}