@granular-software/sdk 0.2.0 → 0.3.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/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as Automerge from '@automerge/automerge';
2
- import { Doc } from '@automerge/automerge';
3
- import { W as WSClientOptions, T as ToolWithHandler, P as PublishToolsResult, J as Job, a as ToolHandler, I as InstanceToolHandler, D as DomainState, G as GranularOptions, R as RecordUserOptions, U as User, C as ConnectOptions, E as EnvironmentData, b as GraphQLResult, c as DefineRelationshipOptions, d as RelationshipInfo, M as ModelRef, e as ManifestContent, f as RecordObjectOptions, g as RecordObjectResult, S as SandboxListResponse, h as Sandbox, i as CreateSandboxData, j as DeleteResponse, k as PermissionProfile, l as CreatePermissionProfileData, m as CreateEnvironmentData, n as Subject, A as AssignmentListResponse } from './types-D46q5WTh.mjs';
4
- export { $ as APIError, r as Assignment, w as Build, x as BuildListResponse, B as BuildPolicy, v as BuildStatus, s as EnvironmentListResponse, y as JobStatus, z as JobSubmitResult, t as Manifest, Z as ManifestImport, u as ManifestListResponse, Y as ManifestOperation, V as ManifestPropertySpec, X as ManifestRelationshipDef, _ as ManifestVolume, q as PermissionProfileListResponse, p as PermissionRules, F as Prompt, H as RPCRequest, N as RPCRequestFromServer, K as RPCResponse, L as SyncMessage, O as ToolInvokeParams, Q as ToolResultParams, o as ToolSchema } from './types-D46q5WTh.mjs';
2
+ import { W as WSClientOptions, T as ToolWithHandler, P as PublishToolsResult, J as Job, a as ToolHandler, I as InstanceToolHandler, b as ToolInfo, c as ToolsChangedEvent, D as DomainState, G as GranularOptions, R as RecordUserOptions, U as User, C as ConnectOptions, E as EnvironmentData, d as GraphQLResult, e as DefineRelationshipOptions, f as RelationshipInfo, M as ModelRef, g as ManifestContent, h as RecordObjectOptions, i as RecordObjectResult, S as SandboxListResponse, j as Sandbox, k as CreateSandboxData, l as DeleteResponse, m as PermissionProfile, n as CreatePermissionProfileData, o as CreateEnvironmentData, p as Subject, A as AssignmentListResponse } from './types-CnX4jXYQ.mjs';
3
+ export { a2 as APIError, u as Assignment, z as Build, F as BuildListResponse, B as BuildPolicy, y as BuildStatus, v as EnvironmentListResponse, r as GranularAuth, H as JobStatus, K as JobSubmitResult, w as Manifest, a0 as ManifestImport, x as ManifestListResponse, $ as ManifestOperation, Z as ManifestPropertySpec, _ as ManifestRelationshipDef, a1 as ManifestVolume, t as PermissionProfileListResponse, s as PermissionRules, L as Prompt, N as RPCRequest, V as RPCRequestFromServer, O as RPCResponse, Q as SyncMessage, X as ToolInvokeParams, Y as ToolResultParams, q as ToolSchema } from './types-CnX4jXYQ.mjs';
4
+ import { Doc } from '@automerge/automerge/slim';
5
5
 
6
6
  declare class WSClient {
7
7
  private ws;
@@ -17,6 +17,7 @@ declare class WSClient {
17
17
  private syncState;
18
18
  private reconnectTimer;
19
19
  private isExplicitlyDisconnected;
20
+ private options;
20
21
  constructor(options: WSClientOptions);
21
22
  /**
22
23
  * Connect to the WebSocket server
@@ -73,6 +74,10 @@ declare class Session {
73
74
  /** Tracks which tools are instance methods (className set, not static) */
74
75
  private instanceTools;
75
76
  private currentDomainRevision;
77
+ /** Local effect registry: name → full ToolWithHandler */
78
+ private effects;
79
+ /** Last known tools for diffing */
80
+ private lastKnownTools;
76
81
  constructor(client: WSClient, clientId?: string);
77
82
  get document(): Doc<Record<string, unknown>>;
78
83
  get domainRevision(): string | null;
@@ -102,6 +107,10 @@ declare class Session {
102
107
  ok: boolean;
103
108
  environmentId?: string;
104
109
  docId?: string;
110
+ graphContainerStatus?: {
111
+ lastKeepAliveAt: number;
112
+ status: 'warming' | 'hot' | 'unknown';
113
+ };
105
114
  }>;
106
115
  /**
107
116
  * Publish tools to the sandbox and register handlers for reverse-RPC.
@@ -140,6 +149,64 @@ declare class Session {
140
149
  * ```
141
150
  */
142
151
  publishTools(tools: ToolWithHandler[], revision?: string): Promise<PublishToolsResult>;
152
+ /**
153
+ * Publish a single effect (tool) to the sandbox.
154
+ *
155
+ * Adds the effect to the local registry and re-publishes the
156
+ * full tool catalog to the server. If an effect with the same
157
+ * name already exists, it is replaced.
158
+ *
159
+ * @param effect - The effect (tool) to publish
160
+ * @returns PublishToolsResult with domainRevision
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * await env.publishEffect({
165
+ * name: 'get_bio',
166
+ * description: 'Get biography of an author',
167
+ * className: 'author',
168
+ * inputSchema: { type: 'object', properties: { detailed: { type: 'boolean' } } },
169
+ * handler: async (id, params) => ({ bio: `Bio of ${id}` }),
170
+ * });
171
+ * ```
172
+ */
173
+ publishEffect(effect: ToolWithHandler): Promise<PublishToolsResult>;
174
+ /**
175
+ * Publish multiple effects (tools) at once.
176
+ *
177
+ * Adds all effects to the local registry and re-publishes the
178
+ * full tool catalog in a single RPC call.
179
+ *
180
+ * @param effects - Array of effects to publish
181
+ * @returns PublishToolsResult with domainRevision
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * await env.publishEffects([
186
+ * { name: 'get_bio', description: '...', inputSchema: {}, handler: async (id) => ({}) },
187
+ * { name: 'search', description: '...', inputSchema: {}, handler: async (params) => ({}) },
188
+ * ]);
189
+ * ```
190
+ */
191
+ publishEffects(effects: ToolWithHandler[]): Promise<PublishToolsResult>;
192
+ /**
193
+ * Remove an effect by name and re-publish the remaining catalog.
194
+ *
195
+ * @param name - The name of the effect to remove
196
+ * @returns PublishToolsResult with domainRevision
197
+ */
198
+ unpublishEffect(name: string): Promise<PublishToolsResult>;
199
+ /**
200
+ * Remove all effects and publish an empty catalog.
201
+ *
202
+ * @returns PublishToolsResult with domainRevision
203
+ */
204
+ unpublishAllEffects(): Promise<PublishToolsResult>;
205
+ /**
206
+ * Internal: re-publish the full effect catalog to the server.
207
+ * Called after any mutation to the effects Map.
208
+ */
209
+ private _syncEffects;
143
210
  /**
144
211
  * Submit a job to execute code in the sandbox.
145
212
  *
@@ -166,26 +233,35 @@ declare class Session {
166
233
  * Respond to a prompt request from the sandbox
167
234
  */
168
235
  answerPrompt(promptId: string, answer: unknown): Promise<void>;
236
+ /**
237
+ * Get the current list of available tools.
238
+ * Consolidates tools from all connected clients.
239
+ */
240
+ getTools(): ToolInfo[];
241
+ /**
242
+ * Subscribe to tool changes (added, removed, updated).
243
+ * @param callback - Function called with change events
244
+ * @returns Unsubscribe function
245
+ */
246
+ onToolsChanged(callback: (event: ToolsChangedEvent) => void): () => void;
169
247
  /**
170
248
  * Get the current domain state and available tools
171
249
  */
172
250
  getDomain(): Promise<DomainState>;
173
251
  /**
174
- * Get auto-generated TypeScript class declarations for the current domain.
175
- *
176
- * Returns typed declarations including:
177
- * - Classes with readonly properties (from manifest)
178
- * - `static find(query: { id: string })` for each class
179
- * - Instance methods with typed input/output (from `publishTools` with `className`)
180
- * - Static methods (from `publishTools` with `className` + `static: true`)
181
- * - Relationship accessors (`get_books()`, `get_author()`, etc.)
182
- * - Global tool functions (from `publishTools` without `className`)
183
- *
184
- * Pass this documentation to LLMs so they can write correct typed code
185
- * that imports from `./sandbox-tools`.
186
- *
187
- * Falls back to generating markdown docs from the domain summary if
188
- * the synthesis server is unavailable.
252
+ * Fetch a domain package part from the backend (no fallback).
253
+ */
254
+ private fetchDomainPart;
255
+ /**
256
+ * Get TypeScript class declarations for the current domain (for LLM/code gen).
257
+ */
258
+ getDomainTypes(): Promise<string>;
259
+ /**
260
+ * Get Markdown documentation for the current domain (human-readable).
261
+ */
262
+ getDomainDocs(): Promise<string>;
263
+ /**
264
+ * Get domain documentation for LLMs. Returns types (preferred) or fallback.
189
265
  */
190
266
  getDomainDocumentation(): Promise<string>;
191
267
  /**
@@ -207,7 +283,11 @@ declare class Session {
207
283
  off(event: string, handler: (data: unknown) => void): void;
208
284
  private setupToolInvokeHandler;
209
285
  private setupEventHandlers;
210
- private emit;
286
+ protected emit(event: string, data: unknown): void;
287
+ /**
288
+ * Check for changes in the tool catalog and emit 'tools:changed' if needed
289
+ */
290
+ private checkForToolChanges;
211
291
  }
212
292
 
213
293
  /**
@@ -219,6 +299,7 @@ declare class Session {
219
299
  * 3. Publish tools via `publishTools()` (instance methods, static methods, global tools — with typed I/O)
220
300
  * 4. Submit jobs via `submitJob()` that import auto-generated typed classes from `./sandbox-tools`
221
301
  * 5. Execute GraphQL queries via `graphql()` (authenticated automatically)
302
+ * 6. List available tools via `getTools()` and listen for updates via `onToolsChanged()`
222
303
  *
223
304
  * Tool calls from the sandbox automatically invoke your handlers via reverse-RPC.
224
305
  *
@@ -241,6 +322,39 @@ declare class Environment extends Session {
241
322
  get permissionProfileId(): string;
242
323
  /** The GraphQL API endpoint URL */
243
324
  get apiEndpoint(): string;
325
+ /** The last known graph container status, updated by checkReadiness() or on heartbeat */
326
+ graphContainerStatus: {
327
+ lastKeepAliveAt: number;
328
+ status: 'warming' | 'hot' | 'unknown';
329
+ } | null;
330
+ /**
331
+ * Check if the graph container is ready and warm.
332
+ *
333
+ * Sends a lightweight heartbeat RPC to the Session DO which internally
334
+ * pings the FalkorDB container. The response includes `graphContainerStatus`,
335
+ * which is stored locally and emitted as a `readiness` event.
336
+ *
337
+ * Use this method to proactively warm the graph container before any
338
+ * GraphQL query that requires it, or to poll the container's state in
339
+ * the background.
340
+ *
341
+ * @returns The current graph container status object
342
+ *
343
+ * @example
344
+ * ```typescript
345
+ * const status = await env.checkReadiness();
346
+ * console.log(status.status); // 'hot' | 'warming' | 'unknown'
347
+ *
348
+ * // Or listen for live updates
349
+ * env.on('readiness', (status) => {
350
+ * console.log('Graph is now:', status.status);
351
+ * });
352
+ * ```
353
+ */
354
+ checkReadiness(): Promise<{
355
+ lastKeepAliveAt: number;
356
+ status: 'warming' | 'hot' | 'unknown';
357
+ }>;
244
358
  /**
245
359
  * Convert a class name + real-world ID into a unique graph path.
246
360
  *
@@ -485,11 +599,49 @@ declare class Environment extends Session {
485
599
  * ```
486
600
  */
487
601
  publishTools(tools: ToolWithHandler[], revision?: string): Promise<PublishToolsResult>;
602
+ /**
603
+ * Publish a single effect (tool) incrementally.
604
+ *
605
+ * Adds the effect to the local registry and re-publishes the
606
+ * full tool catalog to the server. If an effect with the same
607
+ * name already exists, it is replaced.
608
+ *
609
+ * @example
610
+ * ```typescript
611
+ * await env.publishEffect({
612
+ * name: 'get_bio',
613
+ * description: 'Get biography',
614
+ * inputSchema: { type: 'object', properties: { detailed: { type: 'boolean' } } },
615
+ * handler: async (params) => ({ bio: 'Hello' }),
616
+ * });
617
+ * ```
618
+ */
619
+ publishEffect(effect: ToolWithHandler): Promise<PublishToolsResult>;
620
+ /**
621
+ * Publish multiple effects (tools) at once.
622
+ *
623
+ * Adds all effects to the local registry and re-publishes the
624
+ * full tool catalog in a single RPC call.
625
+ */
626
+ publishEffects(effects: ToolWithHandler[]): Promise<PublishToolsResult>;
627
+ /**
628
+ * Remove an effect by name and re-publish the remaining catalog.
629
+ */
630
+ unpublishEffect(name: string): Promise<PublishToolsResult>;
631
+ /**
632
+ * Remove all effects and publish an empty catalog.
633
+ */
634
+ unpublishAllEffects(): Promise<PublishToolsResult>;
488
635
  }
489
636
  declare class Granular {
490
637
  private apiKey;
491
638
  private apiUrl;
492
639
  private httpUrl;
640
+ private WebSocketCtor?;
641
+ /** Sandbox-level effect registry: sandboxId → (toolName → ToolWithHandler) */
642
+ private sandboxEffects;
643
+ /** Active environments tracker: sandboxId → Environment[] */
644
+ private activeEnvironments;
493
645
  /**
494
646
  * Create a new Granular client
495
647
  * @param options - Client configuration
@@ -547,6 +699,34 @@ declare class Granular {
547
699
  * ```
548
700
  */
549
701
  connect(options: ConnectOptions): Promise<Environment>;
702
+ /**
703
+ * Register an effect (tool) for a specific sandbox.
704
+ *
705
+ * The effect will be automatically published to:
706
+ * 1. Any currently active environments for this sandbox
707
+ * 2. Any new environments created/connected for this sandbox
708
+ *
709
+ * @param sandboxNameOrId - The name or ID of the sandbox
710
+ * @param effect - The tool definition and handler
711
+ */
712
+ registerEffect(sandboxNameOrId: string, effect: ToolWithHandler): Promise<void>;
713
+ /**
714
+ * Register multiple effects (tools) for a specific sandbox.
715
+ *
716
+ * batch version of `registerEffect`.
717
+ */
718
+ registerEffects(sandboxNameOrId: string, effects: ToolWithHandler[]): Promise<void>;
719
+ /**
720
+ * Unregister an effect from a sandbox.
721
+ *
722
+ * Removes it from the local registry and unpublishes it from
723
+ * all active environments.
724
+ */
725
+ unregisterEffect(sandboxNameOrId: string, name: string): Promise<void>;
726
+ /**
727
+ * Unregister all effects for a sandbox.
728
+ */
729
+ unregisterAllEffects(sandboxNameOrId: string): Promise<void>;
550
730
  /**
551
731
  * Find a sandbox by name or create it if it doesn't exist
552
732
  */
@@ -613,4 +793,4 @@ declare class Granular {
613
793
  private request;
614
794
  }
615
795
 
616
- export { AssignmentListResponse, ConnectOptions, CreateEnvironmentData, CreatePermissionProfileData, CreateSandboxData, DefineRelationshipOptions, DeleteResponse, DomainState, Environment, EnvironmentData, Granular, GranularOptions, GraphQLResult, InstanceToolHandler, Job, ManifestContent, ModelRef, PermissionProfile, PublishToolsResult, RecordObjectOptions, RecordObjectResult, RecordUserOptions, RelationshipInfo, Sandbox, SandboxListResponse, Session, Subject, ToolHandler, ToolWithHandler, User, WSClient, WSClientOptions };
796
+ export { AssignmentListResponse, ConnectOptions, CreateEnvironmentData, CreatePermissionProfileData, CreateSandboxData, DefineRelationshipOptions, DeleteResponse, DomainState, Environment, EnvironmentData, Granular, GranularOptions, GraphQLResult, InstanceToolHandler, Job, ManifestContent, ModelRef, PermissionProfile, PublishToolsResult, RecordObjectOptions, RecordObjectResult, RecordUserOptions, RelationshipInfo, Sandbox, SandboxListResponse, Session, Subject, ToolHandler, ToolInfo, ToolWithHandler, ToolsChangedEvent, User, WSClient, WSClientOptions };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as Automerge from '@automerge/automerge';
2
- import { Doc } from '@automerge/automerge';
3
- import { W as WSClientOptions, T as ToolWithHandler, P as PublishToolsResult, J as Job, a as ToolHandler, I as InstanceToolHandler, D as DomainState, G as GranularOptions, R as RecordUserOptions, U as User, C as ConnectOptions, E as EnvironmentData, b as GraphQLResult, c as DefineRelationshipOptions, d as RelationshipInfo, M as ModelRef, e as ManifestContent, f as RecordObjectOptions, g as RecordObjectResult, S as SandboxListResponse, h as Sandbox, i as CreateSandboxData, j as DeleteResponse, k as PermissionProfile, l as CreatePermissionProfileData, m as CreateEnvironmentData, n as Subject, A as AssignmentListResponse } from './types-D46q5WTh.js';
4
- export { $ as APIError, r as Assignment, w as Build, x as BuildListResponse, B as BuildPolicy, v as BuildStatus, s as EnvironmentListResponse, y as JobStatus, z as JobSubmitResult, t as Manifest, Z as ManifestImport, u as ManifestListResponse, Y as ManifestOperation, V as ManifestPropertySpec, X as ManifestRelationshipDef, _ as ManifestVolume, q as PermissionProfileListResponse, p as PermissionRules, F as Prompt, H as RPCRequest, N as RPCRequestFromServer, K as RPCResponse, L as SyncMessage, O as ToolInvokeParams, Q as ToolResultParams, o as ToolSchema } from './types-D46q5WTh.js';
2
+ import { W as WSClientOptions, T as ToolWithHandler, P as PublishToolsResult, J as Job, a as ToolHandler, I as InstanceToolHandler, b as ToolInfo, c as ToolsChangedEvent, D as DomainState, G as GranularOptions, R as RecordUserOptions, U as User, C as ConnectOptions, E as EnvironmentData, d as GraphQLResult, e as DefineRelationshipOptions, f as RelationshipInfo, M as ModelRef, g as ManifestContent, h as RecordObjectOptions, i as RecordObjectResult, S as SandboxListResponse, j as Sandbox, k as CreateSandboxData, l as DeleteResponse, m as PermissionProfile, n as CreatePermissionProfileData, o as CreateEnvironmentData, p as Subject, A as AssignmentListResponse } from './types-CnX4jXYQ.js';
3
+ export { a2 as APIError, u as Assignment, z as Build, F as BuildListResponse, B as BuildPolicy, y as BuildStatus, v as EnvironmentListResponse, r as GranularAuth, H as JobStatus, K as JobSubmitResult, w as Manifest, a0 as ManifestImport, x as ManifestListResponse, $ as ManifestOperation, Z as ManifestPropertySpec, _ as ManifestRelationshipDef, a1 as ManifestVolume, t as PermissionProfileListResponse, s as PermissionRules, L as Prompt, N as RPCRequest, V as RPCRequestFromServer, O as RPCResponse, Q as SyncMessage, X as ToolInvokeParams, Y as ToolResultParams, q as ToolSchema } from './types-CnX4jXYQ.js';
4
+ import { Doc } from '@automerge/automerge/slim';
5
5
 
6
6
  declare class WSClient {
7
7
  private ws;
@@ -17,6 +17,7 @@ declare class WSClient {
17
17
  private syncState;
18
18
  private reconnectTimer;
19
19
  private isExplicitlyDisconnected;
20
+ private options;
20
21
  constructor(options: WSClientOptions);
21
22
  /**
22
23
  * Connect to the WebSocket server
@@ -73,6 +74,10 @@ declare class Session {
73
74
  /** Tracks which tools are instance methods (className set, not static) */
74
75
  private instanceTools;
75
76
  private currentDomainRevision;
77
+ /** Local effect registry: name → full ToolWithHandler */
78
+ private effects;
79
+ /** Last known tools for diffing */
80
+ private lastKnownTools;
76
81
  constructor(client: WSClient, clientId?: string);
77
82
  get document(): Doc<Record<string, unknown>>;
78
83
  get domainRevision(): string | null;
@@ -102,6 +107,10 @@ declare class Session {
102
107
  ok: boolean;
103
108
  environmentId?: string;
104
109
  docId?: string;
110
+ graphContainerStatus?: {
111
+ lastKeepAliveAt: number;
112
+ status: 'warming' | 'hot' | 'unknown';
113
+ };
105
114
  }>;
106
115
  /**
107
116
  * Publish tools to the sandbox and register handlers for reverse-RPC.
@@ -140,6 +149,64 @@ declare class Session {
140
149
  * ```
141
150
  */
142
151
  publishTools(tools: ToolWithHandler[], revision?: string): Promise<PublishToolsResult>;
152
+ /**
153
+ * Publish a single effect (tool) to the sandbox.
154
+ *
155
+ * Adds the effect to the local registry and re-publishes the
156
+ * full tool catalog to the server. If an effect with the same
157
+ * name already exists, it is replaced.
158
+ *
159
+ * @param effect - The effect (tool) to publish
160
+ * @returns PublishToolsResult with domainRevision
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * await env.publishEffect({
165
+ * name: 'get_bio',
166
+ * description: 'Get biography of an author',
167
+ * className: 'author',
168
+ * inputSchema: { type: 'object', properties: { detailed: { type: 'boolean' } } },
169
+ * handler: async (id, params) => ({ bio: `Bio of ${id}` }),
170
+ * });
171
+ * ```
172
+ */
173
+ publishEffect(effect: ToolWithHandler): Promise<PublishToolsResult>;
174
+ /**
175
+ * Publish multiple effects (tools) at once.
176
+ *
177
+ * Adds all effects to the local registry and re-publishes the
178
+ * full tool catalog in a single RPC call.
179
+ *
180
+ * @param effects - Array of effects to publish
181
+ * @returns PublishToolsResult with domainRevision
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * await env.publishEffects([
186
+ * { name: 'get_bio', description: '...', inputSchema: {}, handler: async (id) => ({}) },
187
+ * { name: 'search', description: '...', inputSchema: {}, handler: async (params) => ({}) },
188
+ * ]);
189
+ * ```
190
+ */
191
+ publishEffects(effects: ToolWithHandler[]): Promise<PublishToolsResult>;
192
+ /**
193
+ * Remove an effect by name and re-publish the remaining catalog.
194
+ *
195
+ * @param name - The name of the effect to remove
196
+ * @returns PublishToolsResult with domainRevision
197
+ */
198
+ unpublishEffect(name: string): Promise<PublishToolsResult>;
199
+ /**
200
+ * Remove all effects and publish an empty catalog.
201
+ *
202
+ * @returns PublishToolsResult with domainRevision
203
+ */
204
+ unpublishAllEffects(): Promise<PublishToolsResult>;
205
+ /**
206
+ * Internal: re-publish the full effect catalog to the server.
207
+ * Called after any mutation to the effects Map.
208
+ */
209
+ private _syncEffects;
143
210
  /**
144
211
  * Submit a job to execute code in the sandbox.
145
212
  *
@@ -166,26 +233,35 @@ declare class Session {
166
233
  * Respond to a prompt request from the sandbox
167
234
  */
168
235
  answerPrompt(promptId: string, answer: unknown): Promise<void>;
236
+ /**
237
+ * Get the current list of available tools.
238
+ * Consolidates tools from all connected clients.
239
+ */
240
+ getTools(): ToolInfo[];
241
+ /**
242
+ * Subscribe to tool changes (added, removed, updated).
243
+ * @param callback - Function called with change events
244
+ * @returns Unsubscribe function
245
+ */
246
+ onToolsChanged(callback: (event: ToolsChangedEvent) => void): () => void;
169
247
  /**
170
248
  * Get the current domain state and available tools
171
249
  */
172
250
  getDomain(): Promise<DomainState>;
173
251
  /**
174
- * Get auto-generated TypeScript class declarations for the current domain.
175
- *
176
- * Returns typed declarations including:
177
- * - Classes with readonly properties (from manifest)
178
- * - `static find(query: { id: string })` for each class
179
- * - Instance methods with typed input/output (from `publishTools` with `className`)
180
- * - Static methods (from `publishTools` with `className` + `static: true`)
181
- * - Relationship accessors (`get_books()`, `get_author()`, etc.)
182
- * - Global tool functions (from `publishTools` without `className`)
183
- *
184
- * Pass this documentation to LLMs so they can write correct typed code
185
- * that imports from `./sandbox-tools`.
186
- *
187
- * Falls back to generating markdown docs from the domain summary if
188
- * the synthesis server is unavailable.
252
+ * Fetch a domain package part from the backend (no fallback).
253
+ */
254
+ private fetchDomainPart;
255
+ /**
256
+ * Get TypeScript class declarations for the current domain (for LLM/code gen).
257
+ */
258
+ getDomainTypes(): Promise<string>;
259
+ /**
260
+ * Get Markdown documentation for the current domain (human-readable).
261
+ */
262
+ getDomainDocs(): Promise<string>;
263
+ /**
264
+ * Get domain documentation for LLMs. Returns types (preferred) or fallback.
189
265
  */
190
266
  getDomainDocumentation(): Promise<string>;
191
267
  /**
@@ -207,7 +283,11 @@ declare class Session {
207
283
  off(event: string, handler: (data: unknown) => void): void;
208
284
  private setupToolInvokeHandler;
209
285
  private setupEventHandlers;
210
- private emit;
286
+ protected emit(event: string, data: unknown): void;
287
+ /**
288
+ * Check for changes in the tool catalog and emit 'tools:changed' if needed
289
+ */
290
+ private checkForToolChanges;
211
291
  }
212
292
 
213
293
  /**
@@ -219,6 +299,7 @@ declare class Session {
219
299
  * 3. Publish tools via `publishTools()` (instance methods, static methods, global tools — with typed I/O)
220
300
  * 4. Submit jobs via `submitJob()` that import auto-generated typed classes from `./sandbox-tools`
221
301
  * 5. Execute GraphQL queries via `graphql()` (authenticated automatically)
302
+ * 6. List available tools via `getTools()` and listen for updates via `onToolsChanged()`
222
303
  *
223
304
  * Tool calls from the sandbox automatically invoke your handlers via reverse-RPC.
224
305
  *
@@ -241,6 +322,39 @@ declare class Environment extends Session {
241
322
  get permissionProfileId(): string;
242
323
  /** The GraphQL API endpoint URL */
243
324
  get apiEndpoint(): string;
325
+ /** The last known graph container status, updated by checkReadiness() or on heartbeat */
326
+ graphContainerStatus: {
327
+ lastKeepAliveAt: number;
328
+ status: 'warming' | 'hot' | 'unknown';
329
+ } | null;
330
+ /**
331
+ * Check if the graph container is ready and warm.
332
+ *
333
+ * Sends a lightweight heartbeat RPC to the Session DO which internally
334
+ * pings the FalkorDB container. The response includes `graphContainerStatus`,
335
+ * which is stored locally and emitted as a `readiness` event.
336
+ *
337
+ * Use this method to proactively warm the graph container before any
338
+ * GraphQL query that requires it, or to poll the container's state in
339
+ * the background.
340
+ *
341
+ * @returns The current graph container status object
342
+ *
343
+ * @example
344
+ * ```typescript
345
+ * const status = await env.checkReadiness();
346
+ * console.log(status.status); // 'hot' | 'warming' | 'unknown'
347
+ *
348
+ * // Or listen for live updates
349
+ * env.on('readiness', (status) => {
350
+ * console.log('Graph is now:', status.status);
351
+ * });
352
+ * ```
353
+ */
354
+ checkReadiness(): Promise<{
355
+ lastKeepAliveAt: number;
356
+ status: 'warming' | 'hot' | 'unknown';
357
+ }>;
244
358
  /**
245
359
  * Convert a class name + real-world ID into a unique graph path.
246
360
  *
@@ -485,11 +599,49 @@ declare class Environment extends Session {
485
599
  * ```
486
600
  */
487
601
  publishTools(tools: ToolWithHandler[], revision?: string): Promise<PublishToolsResult>;
602
+ /**
603
+ * Publish a single effect (tool) incrementally.
604
+ *
605
+ * Adds the effect to the local registry and re-publishes the
606
+ * full tool catalog to the server. If an effect with the same
607
+ * name already exists, it is replaced.
608
+ *
609
+ * @example
610
+ * ```typescript
611
+ * await env.publishEffect({
612
+ * name: 'get_bio',
613
+ * description: 'Get biography',
614
+ * inputSchema: { type: 'object', properties: { detailed: { type: 'boolean' } } },
615
+ * handler: async (params) => ({ bio: 'Hello' }),
616
+ * });
617
+ * ```
618
+ */
619
+ publishEffect(effect: ToolWithHandler): Promise<PublishToolsResult>;
620
+ /**
621
+ * Publish multiple effects (tools) at once.
622
+ *
623
+ * Adds all effects to the local registry and re-publishes the
624
+ * full tool catalog in a single RPC call.
625
+ */
626
+ publishEffects(effects: ToolWithHandler[]): Promise<PublishToolsResult>;
627
+ /**
628
+ * Remove an effect by name and re-publish the remaining catalog.
629
+ */
630
+ unpublishEffect(name: string): Promise<PublishToolsResult>;
631
+ /**
632
+ * Remove all effects and publish an empty catalog.
633
+ */
634
+ unpublishAllEffects(): Promise<PublishToolsResult>;
488
635
  }
489
636
  declare class Granular {
490
637
  private apiKey;
491
638
  private apiUrl;
492
639
  private httpUrl;
640
+ private WebSocketCtor?;
641
+ /** Sandbox-level effect registry: sandboxId → (toolName → ToolWithHandler) */
642
+ private sandboxEffects;
643
+ /** Active environments tracker: sandboxId → Environment[] */
644
+ private activeEnvironments;
493
645
  /**
494
646
  * Create a new Granular client
495
647
  * @param options - Client configuration
@@ -547,6 +699,34 @@ declare class Granular {
547
699
  * ```
548
700
  */
549
701
  connect(options: ConnectOptions): Promise<Environment>;
702
+ /**
703
+ * Register an effect (tool) for a specific sandbox.
704
+ *
705
+ * The effect will be automatically published to:
706
+ * 1. Any currently active environments for this sandbox
707
+ * 2. Any new environments created/connected for this sandbox
708
+ *
709
+ * @param sandboxNameOrId - The name or ID of the sandbox
710
+ * @param effect - The tool definition and handler
711
+ */
712
+ registerEffect(sandboxNameOrId: string, effect: ToolWithHandler): Promise<void>;
713
+ /**
714
+ * Register multiple effects (tools) for a specific sandbox.
715
+ *
716
+ * batch version of `registerEffect`.
717
+ */
718
+ registerEffects(sandboxNameOrId: string, effects: ToolWithHandler[]): Promise<void>;
719
+ /**
720
+ * Unregister an effect from a sandbox.
721
+ *
722
+ * Removes it from the local registry and unpublishes it from
723
+ * all active environments.
724
+ */
725
+ unregisterEffect(sandboxNameOrId: string, name: string): Promise<void>;
726
+ /**
727
+ * Unregister all effects for a sandbox.
728
+ */
729
+ unregisterAllEffects(sandboxNameOrId: string): Promise<void>;
550
730
  /**
551
731
  * Find a sandbox by name or create it if it doesn't exist
552
732
  */
@@ -613,4 +793,4 @@ declare class Granular {
613
793
  private request;
614
794
  }
615
795
 
616
- export { AssignmentListResponse, ConnectOptions, CreateEnvironmentData, CreatePermissionProfileData, CreateSandboxData, DefineRelationshipOptions, DeleteResponse, DomainState, Environment, EnvironmentData, Granular, GranularOptions, GraphQLResult, InstanceToolHandler, Job, ManifestContent, ModelRef, PermissionProfile, PublishToolsResult, RecordObjectOptions, RecordObjectResult, RecordUserOptions, RelationshipInfo, Sandbox, SandboxListResponse, Session, Subject, ToolHandler, ToolWithHandler, User, WSClient, WSClientOptions };
796
+ export { AssignmentListResponse, ConnectOptions, CreateEnvironmentData, CreatePermissionProfileData, CreateSandboxData, DefineRelationshipOptions, DeleteResponse, DomainState, Environment, EnvironmentData, Granular, GranularOptions, GraphQLResult, InstanceToolHandler, Job, ManifestContent, ModelRef, PermissionProfile, PublishToolsResult, RecordObjectOptions, RecordObjectResult, RecordUserOptions, RelationshipInfo, Sandbox, SandboxListResponse, Session, Subject, ToolHandler, ToolInfo, ToolWithHandler, ToolsChangedEvent, User, WSClient, WSClientOptions };