@granular-software/sdk 0.3.4 → 0.4.2

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.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as Automerge from '@automerge/automerge';
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-D5B8WlF4.js';
3
- export { a4 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, a2 as ManifestImport, x as ManifestListResponse, a1 as ManifestOperation, $ as ManifestPropertySpec, a0 as ManifestRelationshipDef, a3 as ManifestVolume, t as PermissionProfileListResponse, s as PermissionRules, L as Prompt, Q as RPCRequest, Y as RPCRequestFromServer, V as RPCResponse, X as SyncMessage, Z as ToolInvokeParams, _ as ToolResultParams, q as ToolSchema, N as WSDisconnectInfo, O as WSReconnectErrorInfo } from './types-D5B8WlF4.js';
2
+ import { W as WSClientOptions, T as ToolWithHandler, P as PublishToolsResult, J as Job, a as ToolHandler, I as InstanceToolHandler, E as EffectInfo, b as ToolInfo, c as EffectsChangedEvent, d as ToolsChangedEvent, D as DomainState, G as GranularOptions, R as RecordUserOptions, U as User, C as ConnectOptions, e as EnvironmentData, f as GraphQLResult, g as DefineRelationshipOptions, h as RelationshipInfo, M as ModelRef, i as ManifestContent, j as RecordObjectOptions, k as RecordObjectResult, S as SandboxListResponse, l as Sandbox, m as CreateSandboxData, n as DeleteResponse, o as PermissionProfile, p as CreatePermissionProfileData, q as CreateEnvironmentData, r as Subject, A as AssignmentListResponse } from './types-C0AVRsVR.js';
3
+ export { ag as APIError, t as AccessTokenProvider, y as Assignment, L as Build, N as BuildListResponse, B as BuildPolicy, K as BuildStatus, Y as EffectHandler, O as EffectHandlerContext, Q as EffectSchema, V as EffectWithHandler, u as EndpointMode, z as EnvironmentListResponse, v as GranularAuth, Z as InstanceEffectHandler, _ as JobStatus, $ as JobSubmitResult, F as Manifest, ac as ManifestEffectDeclaration, ab as ManifestEffectSchema, ae as ManifestImport, H as ManifestListResponse, ad as ManifestOperation, a9 as ManifestPropertySpec, aa as ManifestRelationshipDef, af as ManifestVolume, x as PermissionProfileListResponse, w as PermissionRules, a0 as Prompt, X as PublishEffectsResult, a3 as RPCRequest, a6 as RPCRequestFromServer, a4 as RPCResponse, a5 as SyncMessage, a7 as ToolInvokeParams, a8 as ToolResultParams, s as ToolSchema, a1 as WSDisconnectInfo, a2 as WSReconnectErrorInfo } from './types-C0AVRsVR.js';
4
4
  import { Doc } from '@automerge/automerge/slim';
5
5
 
6
6
  declare class WSClient {
@@ -16,9 +16,16 @@ declare class WSClient {
16
16
  doc: Automerge.Doc<Record<string, unknown>>;
17
17
  private syncState;
18
18
  private reconnectTimer;
19
+ private tokenRefreshTimer;
19
20
  private isExplicitlyDisconnected;
20
21
  private options;
21
22
  constructor(options: WSClientOptions);
23
+ private clearTokenRefreshTimer;
24
+ private decodeBase64Url;
25
+ private getTokenExpiryMs;
26
+ private scheduleTokenRefresh;
27
+ private refreshTokenInBackground;
28
+ private resolveTokenForConnect;
22
29
  /**
23
30
  * Connect to the WebSocket server
24
31
  * @returns {Promise<void>} Resolves when connection is open
@@ -82,6 +89,7 @@ declare class Session {
82
89
  /** Last known tools for diffing */
83
90
  private lastKnownTools;
84
91
  constructor(client: WSClient, clientId?: string);
92
+ private buildLegacyEffectContext;
85
93
  get document(): Doc<Record<string, unknown>>;
86
94
  get domainRevision(): string | null;
87
95
  /**
@@ -115,101 +123,11 @@ declare class Session {
115
123
  status: 'warming' | 'hot' | 'unknown';
116
124
  };
117
125
  }>;
118
- /**
119
- * Publish tools to the sandbox and register handlers for reverse-RPC.
120
- *
121
- * Tools can be:
122
- * - **Instance methods**: set `className` (handler receives `(objectId, params)`)
123
- * - **Static methods**: set `className` + `static: true` (handler receives `(params)`)
124
- * - **Global tools**: omit `className` (handler receives `(params)`)
125
- *
126
- * Both `inputSchema` and `outputSchema` accept JSON Schema objects. The
127
- * `outputSchema` drives the return type in the auto-generated TypeScript
128
- * class declarations that sandbox code imports from `./sandbox-tools`.
129
- *
130
- * This method:
131
- * 1. Extracts tool schemas (including `outputSchema`) from the provided tools
132
- * 2. Publishes them via `client.publishRawToolCatalog` RPC
133
- * 3. Registers handlers locally for `tool.invoke` RPC calls
134
- * 4. Returns the `domainRevision` needed for job submission
135
- *
136
- * @param tools - Array of tools with handlers
137
- * @param revision - Optional revision string (default: "1.0.0")
138
- * @returns PublishToolsResult with domainRevision
139
- *
140
- * @example
141
- * ```typescript
142
- * await env.publishTools([
143
- * {
144
- * name: 'get_bio',
145
- * description: 'Get biography of an author',
146
- * className: 'author',
147
- * inputSchema: { type: 'object', properties: { detailed: { type: 'boolean' } } },
148
- * outputSchema: { type: 'object', properties: { bio: { type: 'string' } }, required: ['bio'] },
149
- * handler: async (id, params) => ({ bio: `Bio of ${id}` }),
150
- * },
151
- * ]);
152
- * ```
153
- */
154
126
  publishTools(tools: ToolWithHandler[], revision?: string): Promise<PublishToolsResult>;
155
- /**
156
- * Publish a single effect (tool) to the sandbox.
157
- *
158
- * Adds the effect to the local registry and re-publishes the
159
- * full tool catalog to the server. If an effect with the same
160
- * name already exists, it is replaced.
161
- *
162
- * @param effect - The effect (tool) to publish
163
- * @returns PublishToolsResult with domainRevision
164
- *
165
- * @example
166
- * ```typescript
167
- * await env.publishEffect({
168
- * name: 'get_bio',
169
- * description: 'Get biography of an author',
170
- * className: 'author',
171
- * inputSchema: { type: 'object', properties: { detailed: { type: 'boolean' } } },
172
- * handler: async (id, params) => ({ bio: `Bio of ${id}` }),
173
- * });
174
- * ```
175
- */
176
127
  publishEffect(effect: ToolWithHandler): Promise<PublishToolsResult>;
177
- /**
178
- * Publish multiple effects (tools) at once.
179
- *
180
- * Adds all effects to the local registry and re-publishes the
181
- * full tool catalog in a single RPC call.
182
- *
183
- * @param effects - Array of effects to publish
184
- * @returns PublishToolsResult with domainRevision
185
- *
186
- * @example
187
- * ```typescript
188
- * await env.publishEffects([
189
- * { name: 'get_bio', description: '...', inputSchema: {}, handler: async (id) => ({}) },
190
- * { name: 'search', description: '...', inputSchema: {}, handler: async (params) => ({}) },
191
- * ]);
192
- * ```
193
- */
194
128
  publishEffects(effects: ToolWithHandler[]): Promise<PublishToolsResult>;
195
- /**
196
- * Remove an effect by name and re-publish the remaining catalog.
197
- *
198
- * @param name - The name of the effect to remove
199
- * @returns PublishToolsResult with domainRevision
200
- */
201
129
  unpublishEffect(name: string): Promise<PublishToolsResult>;
202
- /**
203
- * Remove all effects and publish an empty catalog.
204
- *
205
- * @returns PublishToolsResult with domainRevision
206
- */
207
130
  unpublishAllEffects(): Promise<PublishToolsResult>;
208
- /**
209
- * Internal: re-publish the full effect catalog to the server.
210
- * Called after any mutation to the effects Map.
211
- */
212
- private _syncEffects;
213
131
  /**
214
132
  * Submit a job to execute code in the sandbox.
215
133
  *
@@ -222,8 +140,8 @@ declare class Session {
222
140
  * const books = await tolkien.get_books();
223
141
  * ```
224
142
  *
225
- * Tool calls (instance methods, static methods, global functions) trigger
226
- * `tool.invoke` RPC back to this client, where the registered handlers
143
+ * Effect calls (instance methods, static methods, global functions) trigger
144
+ * `effect.invoke` RPC back to the sandbox effect host, where the registered handlers
227
145
  * execute locally and return the result to the sandbox.
228
146
  */
229
147
  submitJob(code: string, domainRevision?: string): Promise<Job>;
@@ -237,15 +155,23 @@ declare class Session {
237
155
  */
238
156
  answerPrompt(promptId: string, answer: unknown): Promise<void>;
239
157
  /**
240
- * Get the current list of available tools.
241
- * Consolidates tools from all connected clients.
158
+ * Get the current list of available effects.
159
+ * Consolidates effect declarations and live availability for the session.
160
+ */
161
+ getEffects(): EffectInfo[];
162
+ /**
163
+ * Backwards-compatible alias for `getEffects()`.
242
164
  */
243
165
  getTools(): ToolInfo[];
244
166
  /**
245
- * Subscribe to tool changes (added, removed, updated).
167
+ * Subscribe to effect changes (added, removed, updated).
246
168
  * @param callback - Function called with change events
247
169
  * @returns Unsubscribe function
248
170
  */
171
+ onEffectsChanged(callback: (event: EffectsChangedEvent) => void): () => void;
172
+ /**
173
+ * Backwards-compatible alias for `onEffectsChanged()`.
174
+ */
249
175
  onToolsChanged(callback: (event: ToolsChangedEvent) => void): () => void;
250
176
  /**
251
177
  * Get the current domain state and available tools
@@ -288,7 +214,7 @@ declare class Session {
288
214
  private setupEventHandlers;
289
215
  protected emit(event: string, data: unknown): void;
290
216
  /**
291
- * Check for changes in the tool catalog and emit 'tools:changed' if needed
217
+ * Check for changes in the effect catalog and emit change events if needed.
292
218
  */
293
219
  private checkForToolChanges;
294
220
  }
@@ -299,10 +225,10 @@ declare class Session {
299
225
  * After connecting, you can:
300
226
  * 1. Define your domain ontology via `applyManifest()` (classes, properties, relationships)
301
227
  * 2. Record object instances via `recordObject()` (with fields and relationship attachments)
302
- * 3. Publish tools via `publishTools()` (instance methods, static methods, global tools — with typed I/O)
228
+ * 3. Register sandbox-scoped effects via `granular.registerEffect()` / `granular.registerEffects()`
303
229
  * 4. Submit jobs via `submitJob()` that import auto-generated typed classes from `./sandbox-tools`
304
230
  * 5. Execute GraphQL queries via `graphql()` (authenticated automatically)
305
- * 6. List available tools via `getTools()` and listen for updates via `onToolsChanged()`
231
+ * 6. List available effects via `getEffects()` and listen for updates via `onEffectsChanged()`
306
232
  *
307
233
  * Tool calls from the sandbox automatically invoke your handlers via reverse-RPC.
308
234
  *
@@ -325,6 +251,15 @@ declare class Environment extends Session {
325
251
  get permissionProfileId(): string;
326
252
  /** The GraphQL API endpoint URL */
327
253
  get apiEndpoint(): string;
254
+ private getRuntimeBaseUrl;
255
+ /**
256
+ * Close the session and disconnect from the sandbox.
257
+ *
258
+ * Sends `client.goodbye` over WebSocket first, then issues an HTTP fallback
259
+ * to the runtime goodbye endpoint if no definitive WS-side runtime notify
260
+ * acknowledgement was observed.
261
+ */
262
+ disconnect(): Promise<void>;
328
263
  /** The last known graph container status, updated by checkReadiness() or on heartbeat */
329
264
  graphContainerStatus: {
330
265
  lastKeepAliveAt: number;
@@ -575,64 +510,23 @@ declare class Environment extends Session {
575
510
  */
576
511
  recordObject(options: RecordObjectOptions): Promise<RecordObjectResult>;
577
512
  /**
578
- * Convenience method: publish tools and get back wrapped result.
579
- * This is the main entry point for setting up tools.
580
- *
581
- * @example
582
- * ```typescript
583
- * const tools = [
584
- * {
585
- * name: 'get_weather',
586
- * description: 'Get weather for a city',
587
- * inputSchema: { type: 'object', properties: { city: { type: 'string' } } },
588
- * handler: async ({ city }) => ({ temp: 22 }),
589
- * },
590
- * ];
591
- *
592
- * const { domainRevision } = await environment.publishTools(tools);
593
- *
594
- * // Now submit jobs that use those tools
595
- * const job = await environment.submitJob(`
596
- * import { Author } from './sandbox-tools';
597
- * const weather = await Author.get_weather({ city: 'Paris' });
598
- * return weather;
599
- * `);
600
- *
601
- * const result = await job.result;
602
- * ```
513
+ * Removed: environment-scoped effect publication is no longer supported.
603
514
  */
604
515
  publishTools(tools: ToolWithHandler[], revision?: string): Promise<PublishToolsResult>;
605
516
  /**
606
- * Publish a single effect (tool) incrementally.
607
- *
608
- * Adds the effect to the local registry and re-publishes the
609
- * full tool catalog to the server. If an effect with the same
610
- * name already exists, it is replaced.
611
- *
612
- * @example
613
- * ```typescript
614
- * await env.publishEffect({
615
- * name: 'get_bio',
616
- * description: 'Get biography',
617
- * inputSchema: { type: 'object', properties: { detailed: { type: 'boolean' } } },
618
- * handler: async (params) => ({ bio: 'Hello' }),
619
- * });
620
- * ```
517
+ * Removed: environment-scoped effect publication is no longer supported.
621
518
  */
622
519
  publishEffect(effect: ToolWithHandler): Promise<PublishToolsResult>;
623
520
  /**
624
- * Publish multiple effects (tools) at once.
625
- *
626
- * Adds all effects to the local registry and re-publishes the
627
- * full tool catalog in a single RPC call.
521
+ * Removed: environment-scoped effect publication is no longer supported.
628
522
  */
629
523
  publishEffects(effects: ToolWithHandler[]): Promise<PublishToolsResult>;
630
524
  /**
631
- * Remove an effect by name and re-publish the remaining catalog.
525
+ * Removed: environment-scoped effect publication is no longer supported.
632
526
  */
633
527
  unpublishEffect(name: string): Promise<PublishToolsResult>;
634
528
  /**
635
- * Remove all effects and publish an empty catalog.
529
+ * Removed: environment-scoped effect publication is no longer supported.
636
530
  */
637
531
  unpublishAllEffects(): Promise<PublishToolsResult>;
638
532
  }
@@ -640,13 +534,16 @@ declare class Granular {
640
534
  private apiKey;
641
535
  private apiUrl;
642
536
  private httpUrl;
537
+ private tokenProvider?;
643
538
  private WebSocketCtor?;
644
539
  private onUnexpectedClose?;
645
540
  private onReconnectError?;
646
- /** Sandbox-level effect registry: sandboxId → (toolName → ToolWithHandler) */
541
+ /** Sandbox-level effect registry: sandboxId → (effectKey → ToolWithHandler) */
647
542
  private sandboxEffects;
648
- /** Active environments tracker: sandboxId Environment[] */
649
- private activeEnvironments;
543
+ /** Live sandbox-scoped effect hosts keyed by sandboxId */
544
+ private sandboxEffectHosts;
545
+ /** In-flight host connection promises to avoid duplicate concurrent connects */
546
+ private sandboxEffectHostPromises;
650
547
  /**
651
548
  * Create a new Granular client
652
549
  * @param options - Client configuration
@@ -671,8 +568,9 @@ declare class Granular {
671
568
  /**
672
569
  * Connect to a sandbox and establish a real-time environment session.
673
570
  *
674
- * After connecting, use `environment.publishTools()` to register tools,
675
- * then `environment.submitJob()` to execute code that uses those tools.
571
+ * Effects are registered at the sandbox level via `granular.registerEffect()`
572
+ * or `granular.registerEffects()`. Sessions pick up live availability from
573
+ * the sandbox registry automatically.
676
574
  *
677
575
  * @param options - Connection options
678
576
  * @returns An active environment session
@@ -689,10 +587,12 @@ declare class Granular {
689
587
  * user,
690
588
  * });
691
589
  *
692
- * // Publish tools
693
- * await environment.publishTools([
694
- * { name: 'greet', description: 'Say hello', inputSchema: {}, handler: async () => 'Hello!' },
695
- * ]);
590
+ * await granular.registerEffect('my-sandbox', {
591
+ * name: 'greet',
592
+ * description: 'Say hello',
593
+ * inputSchema: { type: 'object', properties: {} },
594
+ * handler: async () => 'Hello!',
595
+ * });
696
596
  *
697
597
  * // Submit job
698
598
  * const job = await environment.submitJob(`
@@ -704,13 +604,19 @@ declare class Granular {
704
604
  * ```
705
605
  */
706
606
  connect(options: ConnectOptions): Promise<Environment>;
607
+ private activateEnvironment;
608
+ private getSandboxEffectMap;
609
+ private serializeEffect;
610
+ private publishSandboxEffectCatalog;
611
+ private syncSandboxEffectCatalog;
612
+ private startEffectHostHeartbeat;
613
+ private stopEffectHostHeartbeat;
614
+ private synchronizeEffectHost;
615
+ private ensureSandboxEffectHost;
616
+ private disconnectSandboxEffectHost;
707
617
  /**
708
618
  * Register an effect (tool) for a specific sandbox.
709
619
  *
710
- * The effect will be automatically published to:
711
- * 1. Any currently active environments for this sandbox
712
- * 2. Any new environments created/connected for this sandbox
713
- *
714
620
  * @param sandboxNameOrId - The name or ID of the sandbox
715
621
  * @param effect - The tool definition and handler
716
622
  */
@@ -724,8 +630,8 @@ declare class Granular {
724
630
  /**
725
631
  * Unregister an effect from a sandbox.
726
632
  *
727
- * Removes it from the local registry and unpublishes it from
728
- * all active environments.
633
+ * Removes it from the local sandbox registry and updates the
634
+ * sandbox-scoped live catalog.
729
635
  */
730
636
  unregisterEffect(sandboxNameOrId: string, name: string): Promise<void>;
731
637
  /**
@@ -798,4 +704,4 @@ declare class Granular {
798
704
  private request;
799
705
  }
800
706
 
801
- 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 };
707
+ export { AssignmentListResponse, ConnectOptions, CreateEnvironmentData, CreatePermissionProfileData, CreateSandboxData, DefineRelationshipOptions, DeleteResponse, DomainState, EffectInfo, EffectsChangedEvent, 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 };