@granular-software/sdk 0.4.73 → 0.4.75

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.
@@ -1,1379 +0,0 @@
1
- import { dv as WSClientOptions, ab as SessionFeedApi, bf as GranularQuotaProgress, T as ToolWithHandler, t as PublishToolsResult, cl as Job, u as ToolHandler, I as InstanceToolHandler, co as UserMessageInput, cp as UserMessageAppendResult, c8 as EffectInfo, n as Prompt, c7 as ToolInfo, ca as EffectsChangedEvent, c9 as ToolsChangedEvent, D as DomainState, ae as FeedListTransport, aX as GranularOptions, e1 as EnvironmentImporter, a_ as RecordUserOptions, aZ as User, b0 as OpenEnvironmentOptions, E as EnvironmentData, aW as AccessTokenProvider, bp as BuildPolicy, d_ as EnvironmentSetupSummary, b6 as ConversationSessionListOptions, b4 as ConversationSessionInfo, b7 as ConversationSessionListResponse, b3 as CreateSessionOptions, h as RecordObjectOptions, dN as RecordObjectResult, dP as RecordObjectsOptions, dW as RecordImport, dS as RecordImportStatus, dV as RecordImportItem, a as EnvironmentRecordImportSummary, cj as EnvironmentFeedbackRecord, m as SessionHeapSnapshot, dh as SessionDocumentResult, cq as AssistantReplyPublicationInput, cr as AssistantReplyPublicationResult, di as SessionCollectionListOptions, dk as SessionCollectionListResult, cu as SessionTimelineEvent, dj as SessionJobListOptions, da as SessionJobRecord, bT as SessionMutationView, cN as SessionArtifactListOptions, r as SessionArtifactRecord, cP as SessionArtifactRelationshipOptionsInput, cR as SessionArtifactRelationshipOptionsResult, cS as SessionArtifactRelationshipCreateInput, cO as SessionArtifactValidationResult, cU as SessionArtifactExecutionOptions, cT as SessionArtifactExecutionResult, cV as SessionArtifactApprovalOptions, d3 as RecordManualActionInput, d5 as ManualActionRecordResult, d6 as ManualActionListOptions, d4 as ManualActionOccurrence, d8 as ManualActionSuggestionOptions, d7 as ManualActionSuggestion, cY as ArtifactApprovalTaskListOptions, cX as ArtifactApprovalTask, cZ as ArtifactApprovalDecisionInput, c_ as ArtifactApprovalDecisionResult, cy as SessionFileRecord, d9 as SessionFileUploadOptions, S as SessionHeapEntry, k as SessionHeapList, dd as SessionHeapVariable, o as SessionTranscriptEntry, ev as GraphQLResult, df as RecordSearchOptions, de as RecordSearchResult, dg as RecordMentionInput, dG as DefineRelationshipOptions, dF as RelationshipInfo, dE as ModelRef, i as ManifestContent, dK as EnvironmentStateUpdateInput, dI as EnvironmentStateTarget, dM as EnvironmentStateProxy, dR as RecordImportOptions, dr as UserEnvironmentStateOptions, dq as UserEnvironmentState, ds as MarkUserEnvironmentReadOptions, d as ProjectionMapper, bM as EffectProjectionResult, bR as ExternalCommitOptions, C as CommitReceipt, bN as TransitionProjectionResult, bS as ObservationReceipt, b1 as AdoptEnvironmentOptions, b2 as ConnectOptions, dY as RunEnvironmentImporterOptions, aJ as OpenAIUsageSpendEvent, aI as GranularSpendContext, aL as RecordOpenAIUsageSpendResult, bi as SandboxListResponse, bg as Sandbox, bh as CreateSandboxData, ex as DeleteResponse, bk as PermissionProfile, bl as CreatePermissionProfileData, bs as CreateEnvironmentData, ey as StreamEvent, ez as StreamSubscription, eA as StreamStats, a$ as Subject, bo as AssignmentListResponse } from './spend-k8V2Y1Tt.js';
2
- import * as Automerge from '@automerge/automerge';
3
- import { Doc } from '@automerge/automerge/slim';
4
-
5
- interface CanonicalDocumentQuarantine {
6
- documentEpoch: number;
7
- documentRevision: number;
8
- error: Error;
9
- }
10
- declare class WSClient {
11
- private ws;
12
- private url;
13
- private sessionId;
14
- private token;
15
- private messageQueue;
16
- private pendingRpcPeriodStartedAt;
17
- private rpcHandlers;
18
- private eventHandlers;
19
- private canonicalDocumentQuarantineHandlers;
20
- private nextRpcId;
21
- doc: Automerge.Doc<Record<string, unknown>>;
22
- private reconnectTimer;
23
- private tokenRefreshTimer;
24
- private isExplicitlyDisconnected;
25
- private reconnectAttempts;
26
- private connectPromise;
27
- private connectionEpoch;
28
- private cancelConnectAttempt;
29
- private documentRepairRequired;
30
- private canonicalDocumentActivated;
31
- private lastInboundActivityAt;
32
- private options;
33
- constructor(options: WSClientOptions);
34
- get currentSessionId(): string;
35
- isTransportOpen(): boolean;
36
- hasPendingRpcRequests(): boolean;
37
- hasRecentlyPendingRpcPeriod(maxAgeMs: number, now?: number): boolean;
38
- private removePendingRpc;
39
- /**
40
- * Whether the current socket has delivered any frame recently. SessionDO
41
- * broadcasts a one-way heartbeat every five seconds, so this measures the
42
- * transport without adding an RPC that can be delayed by application work.
43
- */
44
- hasRecentInboundActivity(maxAgeMs: number, now?: number): boolean;
45
- seedDocumentSnapshot(document: Record<string, unknown> | Uint8Array | null | undefined): void;
46
- saveDocumentSnapshot(): Uint8Array;
47
- private clearTokenRefreshTimer;
48
- private decodeBase64Url;
49
- private getTokenExpiryMs;
50
- private scheduleTokenRefresh;
51
- private refreshTokenInBackground;
52
- private resolveTokenForConnect;
53
- /**
54
- * Connect to the WebSocket server
55
- * @returns {Promise<void>} Resolves when connection is open
56
- */
57
- connect(options?: {
58
- signal?: AbortSignal;
59
- }): Promise<void>;
60
- /**
61
- * Mark the current transport as unusable and schedule the normal reconnect
62
- * path. Browser WebSockets can remain in OPEN state after a proxy/worker
63
- * restart, so a timed-out heartbeat must revoke the stale socket explicitly.
64
- */
65
- reportTransportFailure(reason?: unknown): void;
66
- private connectAttempt;
67
- private normalizeReason;
68
- private rejectPending;
69
- private emitReconnectErrorMessage;
70
- private scheduleReconnectAttempt;
71
- private buildDisconnectError;
72
- private decodeDocumentBytes;
73
- private rememberCanonicalActivation;
74
- private canAcceptDocumentReplacement;
75
- private exposeCanonicalQuarantine;
76
- private canonicalReplacementError;
77
- private assertIncrementalDocumentIsSafe;
78
- private requireDocumentResync;
79
- private handleDisconnect;
80
- private handleMessage;
81
- /**
82
- * Make an RPC call to the server
83
- * @param {string} method - RPC method name
84
- * @param {unknown} params - Request parameters
85
- * @returns {Promise<unknown>} Response result
86
- * @throws {Error} If connection is closed or timeout occurs
87
- */
88
- call(method: string, params: unknown): Promise<unknown>;
89
- private handleIncomingRpc;
90
- /**
91
- * Subscribe to client events
92
- * @param {string} event - Event name
93
- * @param {Function} handler - Event handler
94
- */
95
- on(event: string, handler: (params: unknown) => void): void;
96
- /**
97
- * Subscribe to rejected canonical replacement metadata without exposing the
98
- * malformed document through the public sync stream.
99
- *
100
- * @internal Session uses this to quarantine only its feed projection.
101
- */
102
- onCanonicalDocumentQuarantine(handler: (quarantine: CanonicalDocumentQuarantine) => void): () => void;
103
- /**
104
- * Register an RPC handler for incoming server requests
105
- * @param {string} method - RPC method name
106
- * @param {Function} handler - Handler function
107
- */
108
- registerRpcHandler(method: string, handler: (params: unknown) => Promise<unknown>): void;
109
- /**
110
- * Unsubscribe from client events
111
- * @param {string} event - Event name
112
- * @param {Function} handler - Handler to remove
113
- */
114
- off(event: string, handler: (params: unknown) => void): void;
115
- /**
116
- * Emit an event locally
117
- * @param {string} event - Event name
118
- * @param params - Event data
119
- */
120
- emit(event: string, params: unknown): void;
121
- /**
122
- * Disconnect the WebSocket and clear state
123
- */
124
- disconnect(options?: {
125
- reason?: string;
126
- }): void;
127
- }
128
-
129
- declare class Session {
130
- protected client: WSClient;
131
- private clientId;
132
- private initialQuota;
133
- private jobsMap;
134
- private eventListeners;
135
- private toolHandlers;
136
- /** Tracks which tools are instance methods (className set, not static) */
137
- private instanceTools;
138
- private currentDomainRevision;
139
- /** Local effect registry: name → full ToolWithHandler */
140
- private effects;
141
- /** Last known tools for diffing */
142
- private lastKnownTools;
143
- /** Last seen live prompts, keyed by prompt id, for answer normalization */
144
- private promptCache;
145
- /** Prompt ids locally answered before the document sync catches up. */
146
- private hiddenPromptIds;
147
- private domainPackagePartCache;
148
- private domainPackagePartPromises;
149
- private domainPackageFetchQueue;
150
- private readonly feedController;
151
- readonly feed: SessionFeedApi;
152
- constructor(client: WSClient, clientId?: string, options?: {
153
- initialQuota?: GranularQuotaProgress | null;
154
- });
155
- private extractDomainRevisionFromDoc;
156
- /**
157
- * Prompt delivery is deliberately event-driven while a socket is live, but
158
- * an existing session can be attached from a fresh tab/client after the
159
- * event was originally sent. Rebuild that client's prompt cache from the
160
- * canonical document on every sync so an open durable prompt remains
161
- * actionable after reconnect without manufacturing a second prompt.
162
- */
163
- private reconcilePromptCacheFromCanonicalDocument;
164
- private buildDirectedInvocationEffectContext;
165
- private createDirectedInvocationFeedbackContext;
166
- get document(): Doc<Record<string, unknown>>;
167
- get quota(): GranularQuotaProgress | null;
168
- getQuota(): GranularQuotaProgress | null;
169
- get sessionId(): string;
170
- get domainRevision(): string | null;
171
- /**
172
- * Make a raw RPC call to the session's Durable Object.
173
- *
174
- * Use this when you need to call an RPC method that doesn't have a
175
- * dedicated wrapper method on the Session/Environment class.
176
- *
177
- * @param method - RPC method name (e.g. 'domain.fetchPackagePart')
178
- * @param params - Request parameters
179
- * @returns The raw RPC response
180
- *
181
- * @example
182
- * ```typescript
183
- * const result = await env.rpc('domain.fetchPackagePart', {
184
- * moduleSpecifier: '@sandbox/domain',
185
- * part: 'types',
186
- * });
187
- * ```
188
- */
189
- rpc<T = unknown>(method: string, params?: Record<string, unknown>): Promise<T>;
190
- /**
191
- * Send client hello to establish the session
192
- */
193
- hello(): Promise<{
194
- ok: boolean;
195
- environmentId?: string;
196
- docId?: string;
197
- features?: {
198
- /** Whether the server sends application-level heartbeat frames. */
199
- serverHeartbeat?: boolean;
200
- /** Whether the server expects a hibernatable WebSocket lifecycle. */
201
- hibernatingWebSocket?: boolean;
202
- };
203
- graphContainerStatus?: {
204
- lastKeepAliveAt: number;
205
- status: "warming" | "hot" | "unknown";
206
- };
207
- }>;
208
- publishTools(tools: ToolWithHandler[], revision?: string): Promise<PublishToolsResult>;
209
- publishEffect(effect: ToolWithHandler): Promise<PublishToolsResult>;
210
- publishEffects(effects: ToolWithHandler[]): Promise<PublishToolsResult>;
211
- unpublishEffect(name: string): Promise<PublishToolsResult>;
212
- unpublishAllEffects(): Promise<PublishToolsResult>;
213
- /**
214
- * Submit a job to execute code in the sandbox.
215
- *
216
- * The code can import typed classes from Harness v3 runtime modules:
217
- * ```typescript
218
- * import { Author } from "@granular/domain/Author";
219
- * import { Book } from "@granular/domain/Book";
220
- * import { global_search } from "@granular/actions/backend";
221
- *
222
- * const totalAuthors = await Author.count();
223
- * const firstAuthorsPage = await Author.page({ page: 1, perPage: 10, saveAs: 'recent_authors' });
224
- * const authors = firstAuthorsPage.items;
225
- * const tolkien = await Author.get({ path: 'author_tolkien' });
226
- * const bio = await tolkien.get_bio({ detailed: true });
227
- * const books = await tolkien.get_books();
228
- * for await (const author of Author.iterate({ perPage: 100, maxItems: 500 })) {
229
- * console.log(author.id);
230
- * }
231
- * ```
232
- *
233
- * Effect calls (instance methods, static methods, global functions) trigger
234
- * `effect.invoke` RPC back to the sandbox effect host, where the registered handlers
235
- * execute locally and return the result to the sandbox.
236
- */
237
- submitJob(code: string, domainRevisionOrOptions?: string | {
238
- domainRevision?: string;
239
- metadata?: Record<string, unknown>;
240
- agent?: Record<string, unknown>;
241
- }): Promise<Job>;
242
- /**
243
- * Register a handler for a specific tool.
244
- * @param isInstance - If true, handler will receive (id, params) for instance method dispatch.
245
- */
246
- registerToolHandler(name: string, handler: ToolHandler | InstanceToolHandler, isInstance?: boolean): void;
247
- /**
248
- * Respond to a prompt request from the sandbox
249
- */
250
- answerPrompt(promptId: string, answer: unknown): Promise<void>;
251
- appendUserMessage(input: UserMessageInput): Promise<UserMessageAppendResult>;
252
- /**
253
- * Get the current list of available effects.
254
- * Consolidates effect declarations and live availability for the session.
255
- */
256
- getEffects(): EffectInfo[];
257
- /**
258
- * Return the currently open prompt payloads known to this session.
259
- *
260
- * These come from live `prompt` / `prompt.request` websocket events and
261
- * preserve the exact shape used by `answerPrompt(...)`.
262
- */
263
- getPrompts(): Prompt[];
264
- getHiddenPromptIds(): string[];
265
- /**
266
- * Backwards-compatible alias for `getEffects()`.
267
- */
268
- getTools(): ToolInfo[];
269
- /**
270
- * Subscribe to effect changes (added, removed, updated).
271
- * @param callback - Function called with change events
272
- * @returns Unsubscribe function
273
- */
274
- onEffectsChanged(callback: (event: EffectsChangedEvent) => void): () => void;
275
- /**
276
- * Backwards-compatible alias for `onEffectsChanged()`.
277
- */
278
- onToolsChanged(callback: (event: ToolsChangedEvent) => void): () => void;
279
- /**
280
- * Get the current domain state and available tools
281
- */
282
- getDomain(): Promise<DomainState>;
283
- /**
284
- * Fetch a domain package part from the backend (no fallback).
285
- */
286
- private fetchDomainPart;
287
- /**
288
- * Get TypeScript class declarations for the current domain (for LLM/code gen).
289
- */
290
- getDomainTypes(): Promise<string>;
291
- /**
292
- * Get Markdown documentation for the current domain (human-readable).
293
- */
294
- getDomainDocs(): Promise<string>;
295
- /**
296
- * Get domain documentation for LLMs. Returns types (preferred) or fallback.
297
- */
298
- getDomainDocumentation(): Promise<string>;
299
- /**
300
- * Generate markdown documentation from the domain summary.
301
- * Class-aware: groups tools by class with property/relationship info.
302
- */
303
- private generateFallbackDocs;
304
- /**
305
- * Close the session and disconnect from the sandbox
306
- */
307
- disconnect(): Promise<void>;
308
- /** Stop feed repair work without detaching a reconnectable transport. */
309
- protected disposeSessionFeed(): void;
310
- /**
311
- * Subscribe to session events
312
- */
313
- on(event: string, handler: (data: unknown) => void): () => void;
314
- /**
315
- * Unsubscribe from session events
316
- */
317
- off(event: string, handler: (data: unknown) => void): void;
318
- protected setFeedListTransport(transport: FeedListTransport | null): void;
319
- private setupToolInvokeHandler;
320
- private setupEventHandlers;
321
- protected emit(event: string, data: unknown): void;
322
- /**
323
- * Check for changes in the effect catalog and emit change events if needed.
324
- */
325
- private checkForToolChanges;
326
- }
327
-
328
- type SessionFileUploadBody = Blob | ArrayBuffer | Uint8Array | string;
329
- type SessionDataHeaders = any;
330
- type EnvironmentImporterHandler = (importer: EnvironmentImporter) => Promise<void> | void;
331
- declare function isGraphQLMutationDocument(query: unknown): boolean;
332
- /**
333
- * Environment is the sessionless handle for one resolved ontology environment.
334
- *
335
- * Use it to query or mutate environment data directly, or to open live runtime
336
- * sessions through `environment.sessions.*` when you need jobs, prompts, or a
337
- * synced Automerge document.
338
- */
339
- declare class Environment {
340
- private granular;
341
- private envData;
342
- private _apiKey;
343
- private _apiEndpoint;
344
- private _tokenProvider?;
345
- private _beforeMutationSend?;
346
- constructor(granular: Granular, envData: EnvironmentData, apiKey: string, apiEndpoint: string, tokenProvider?: AccessTokenProvider, beforeMutationSend?: () => void);
347
- /** The environment ID */
348
- get environmentId(): string;
349
- /** The sandbox ID */
350
- get sandboxId(): string;
351
- /** The ontology ID */
352
- get ontologyId(): string;
353
- /** The subject ID */
354
- get subjectId(): string;
355
- /** The named environment slot, such as dev or prod */
356
- get envName(): string;
357
- /** The named environment slot, such as dev or prod */
358
- get environment(): string;
359
- /** The resolved ontology version backing this environment */
360
- get versionId(): string;
361
- /** Internal Granular user identifier for this environment */
362
- get granularId(): string;
363
- /** The permission profile ID */
364
- get permissionProfileId(): string;
365
- /** The current build policy backing this environment */
366
- get buildPolicy(): BuildPolicy;
367
- /** The current update state relative to the followed tag */
368
- get updateState(): EnvironmentData["updateState"];
369
- /** The latest setup/import run summary for this environment, when available. */
370
- get setup(): EnvironmentSetupSummary | null;
371
- /** Convenience flag for whether this environment trails the current tag target */
372
- get isOutdated(): boolean;
373
- /** The followed tag name when this environment is tag-tracked */
374
- get tag(): string | null;
375
- /** The GraphQL API endpoint URL */
376
- get apiEndpoint(): string;
377
- /** Internal auth token used for control-plane and runtime fallback requests */
378
- get authToken(): string;
379
- resolveAuthToken(): string | Promise<string>;
380
- /** Base runtime URL derived from the GraphQL endpoint */
381
- get runtimeBaseUrl(): string;
382
- syncEnvironmentData(envData: EnvironmentData): void;
383
- get sessions(): {
384
- list: (options?: Omit<ConversationSessionListOptions, "environmentId" | "sandboxId" | "subjectId">) => Promise<ConversationSessionInfo[]>;
385
- page: (options?: Omit<ConversationSessionListOptions, "environmentId" | "sandboxId" | "subjectId">) => Promise<ConversationSessionListResponse>;
386
- create: (options?: CreateSessionOptions) => Promise<EnvironmentSession>;
387
- connect: (sessionId: string, options?: {
388
- clientId?: string;
389
- }) => Promise<EnvironmentSession>;
390
- reopen: (sessionId: string, options?: {
391
- clientId?: string;
392
- }) => Promise<EnvironmentSession>;
393
- close: (sessionId: string, session?: EnvironmentSession | null) => Promise<void>;
394
- state: (options?: UserEnvironmentStateOptions) => Promise<UserEnvironmentState>;
395
- markRead: (options: MarkUserEnvironmentReadOptions) => Promise<UserEnvironmentState["readThroughSequenceBySessionId"]>;
396
- };
397
- get userEnvironmentState(): {
398
- get: (options?: UserEnvironmentStateOptions) => Promise<UserEnvironmentState>;
399
- markRead: (options: MarkUserEnvironmentReadOptions) => Promise<UserEnvironmentState["readThroughSequenceBySessionId"]>;
400
- };
401
- get data(): {
402
- record: (record: RecordObjectOptions) => Promise<RecordObjectResult>;
403
- recordMany: (records: RecordObjectOptions[], options?: RecordObjectsOptions) => Promise<RecordObjectResult[]>;
404
- import: (records: RecordObjectOptions[], options?: {
405
- batchSize?: number;
406
- }) => Promise<RecordImport>;
407
- listImports: (status?: RecordImportStatus) => Promise<RecordImport[]>;
408
- getImport: (importId: string) => Promise<RecordImport>;
409
- listImportItems: (importId: string, status?: RecordImportItem["status"]) => Promise<RecordImportItem[]>;
410
- getImportSummary: () => Promise<EnvironmentRecordImportSummary>;
411
- cancelImport: (importId: string) => Promise<RecordImport>;
412
- getAwaitingCount: () => Promise<number>;
413
- };
414
- /**
415
- * Acknowledge a declared product mutation that already happened outside a
416
- * Granular-run effect (for example, in a webhook consumer). These methods
417
- * run the declaration's pure projection mapper; they never call its handler.
418
- */
419
- get commit(): {
420
- effect: <TResult>(effect: ToolWithHandler & {
421
- commit: {
422
- kind: "effect";
423
- project: ProjectionMapper<TResult, EffectProjectionResult>;
424
- };
425
- }, productResult: TResult, options?: ExternalCommitOptions) => Promise<CommitReceipt>;
426
- transition: <TResult>(transition: {
427
- from: string;
428
- outcomes: Record<string, unknown>;
429
- effect: ToolWithHandler & {
430
- commit: {
431
- kind: "transition";
432
- project: ProjectionMapper<TResult, TransitionProjectionResult>;
433
- };
434
- };
435
- }, productResult: TResult, options?: ExternalCommitOptions) => Promise<CommitReceipt>;
436
- get: (commitId: string) => Promise<CommitReceipt>;
437
- retry: (commitId: string) => Promise<CommitReceipt>;
438
- };
439
- /** Inspect or retry the agent synchronization of a product snapshot. */
440
- get observation(): {
441
- get: (observationId: string) => Promise<ObservationReceipt>;
442
- retry: (observationId: string) => Promise<ObservationReceipt>;
443
- };
444
- private persistExternalEffect;
445
- private persistExternalTransition;
446
- private requireExternalIdentity;
447
- /**
448
- * Synchronize a versioned product snapshot without claiming an effect or
449
- * lifecycle transition. This records no transition history.
450
- */
451
- observe<TResult>(mapper: ProjectionMapper<TResult, EffectProjectionResult>, productResult: TResult): Promise<ObservationReceipt>;
452
- /**
453
- * Mirror product-owned workflow state into Granular without making Granular
454
- * own the customer application's state machine.
455
- */
456
- recordState(input: EnvironmentStateUpdateInput): Promise<RecordObjectResult>;
457
- /**
458
- * Mirror product-owned workflow state into Granular without making Granular
459
- * own the customer application's state machine.
460
- *
461
- * Example:
462
- * `await env.recordState({ className: "spend_request", id, machine: "lifecycle", state: "policy_review", source: "customer_backend" })`
463
- */
464
- state(target: EnvironmentStateTarget): EnvironmentStateProxy;
465
- get feedback(): {
466
- list: () => Promise<EnvironmentFeedbackRecord[]>;
467
- };
468
- get manualActions(): {
469
- record: (input: RecordManualActionInput) => Promise<ManualActionRecordResult>;
470
- list: (options?: ManualActionListOptions) => Promise<SessionCollectionListResult<ManualActionOccurrence>>;
471
- suggest: (options?: ManualActionSuggestionOptions) => Promise<{
472
- items: ManualActionSuggestion[];
473
- }>;
474
- };
475
- get artifactApprovals(): {
476
- list: (options?: ArtifactApprovalTaskListOptions) => Promise<SessionCollectionListResult<ArtifactApprovalTask>>;
477
- decide: (approvalTaskId: string, input: ArtifactApprovalDecisionInput) => Promise<ArtifactApprovalDecisionResult>;
478
- };
479
- /**
480
- * Sessionless environments do not own a live transport, so disconnecting the
481
- * environment handle itself is a no-op. This keeps the public surface
482
- * symmetric with `EnvironmentSession.disconnect()` and lets callers always
483
- * clean up safely without tracking whether they currently hold an environment
484
- * or a session.
485
- */
486
- disconnect(): Promise<void>;
487
- listSessions(status?: ConversationSessionListOptions["status"]): Promise<ConversationSessionInfo[]>;
488
- listSessions(options?: Omit<ConversationSessionListOptions, "environmentId" | "sandboxId" | "subjectId">): Promise<ConversationSessionInfo[]>;
489
- getUserEnvironmentState(options?: UserEnvironmentStateOptions): Promise<UserEnvironmentState>;
490
- markUserEnvironmentSessionsRead(options: MarkUserEnvironmentReadOptions): Promise<UserEnvironmentState["readThroughSequenceBySessionId"]>;
491
- createSession(options?: CreateSessionOptions): Promise<EnvironmentSession>;
492
- connectSession(sessionId: string, options?: {
493
- clientId?: string;
494
- maxReconnectAttempts?: number;
495
- reconnectDelayMs?: number;
496
- }): Promise<EnvironmentSession>;
497
- reopenSession(sessionId: string, options?: {
498
- clientId?: string;
499
- }): Promise<EnvironmentSession>;
500
- closeSession(sessionId: string, session?: EnvironmentSession | null): Promise<void>;
501
- listFeedback(): Promise<EnvironmentFeedbackRecord[]>;
502
- recordManualAction(input: RecordManualActionInput): Promise<ManualActionRecordResult>;
503
- listManualActions(options?: ManualActionListOptions): Promise<SessionCollectionListResult<ManualActionOccurrence>>;
504
- suggestManualActions(options?: ManualActionSuggestionOptions): Promise<{
505
- items: ManualActionSuggestion[];
506
- }>;
507
- listArtifactApprovals(options?: ArtifactApprovalTaskListOptions): Promise<SessionCollectionListResult<ArtifactApprovalTask>>;
508
- decideArtifactApproval(approvalTaskId: string, input: ArtifactApprovalDecisionInput): Promise<ArtifactApprovalDecisionResult>;
509
- private getRuntimeBaseUrl;
510
- private controlPlaneRequest;
511
- private static normalizeGraphPathSegment;
512
- /**
513
- * Convert a class name + application record ID into Granular's graph path.
514
- *
515
- * This mirrors the record-write path normalization used by the control plane.
516
- * Keep the original customer/system ID in `real_id`; graph paths are stable
517
- * internal addresses, not the source of truth for business identity.
518
- */
519
- static toGraphPath(className: string, id: string): string;
520
- /**
521
- * Best-effort extraction of an ID-like suffix from a graph path.
522
- *
523
- * Prefer the record's `real_id` field whenever exact customer/system IDs
524
- * matter, because graph path normalization is intentionally lossy.
525
- */
526
- static extractIdFromGraphPath(graphPath: string, className: string): string;
527
- /**
528
- * Execute a GraphQL query against the environment's graph.
529
- *
530
- * The query uses the Granular graph query language (based on Cypher/GraphQL).
531
- * Authentication is handled automatically using the SDK's API key.
532
- *
533
- * @param query - The GraphQL query string
534
- * @param variables - Optional variables for the query
535
- * @returns The query result data
536
- *
537
- * @example
538
- * ```typescript
539
- * // Read the workspace
540
- * const result = await env.graphql(
541
- * `query { model(path: "workspace") { path label submodels { path label } } }`
542
- * );
543
- * console.log(result.data);
544
- *
545
- * // Create a model
546
- * const created = await env.graphql(
547
- * `mutation { at(path: "workspace") { create_submodel(subpath: "my_node", label: "My Node", prototype: "Model") { model { path label } } } }`
548
- * );
549
- * ```
550
- */
551
- graphql<T = any>(query: string, variables?: Record<string, any>): Promise<GraphQLResult<T>>;
552
- searchRecords(query: string, options?: RecordSearchOptions): Promise<RecordSearchResult[]>;
553
- /**
554
- * Define a relationship between two model types.
555
- *
556
- * Creates both submodels (if they don't exist) and links them with
557
- * a RelationshipDef node that encodes cardinality.
558
- *
559
- * @example
560
- * ```typescript
561
- * // Author has many Books, Book has one Author
562
- * const rel = await env.defineRelationship({
563
- * model: 'author',
564
- * localSubmodel: 'books',
565
- * localIsMany: true,
566
- * foreignModel: 'book',
567
- * foreignSubmodel: 'author',
568
- * foreignIsMany: false,
569
- * });
570
- * console.log(rel.relationship_kind); // "one_to_many"
571
- * ```
572
- */
573
- defineRelationship(options: DefineRelationshipOptions): Promise<RelationshipInfo>;
574
- /**
575
- * Get all relationships for a model type.
576
- *
577
- * @param modelPath - The model type path (e.g., "author")
578
- * @returns Array of relationships from this model's perspective
579
- *
580
- * @example
581
- * ```typescript
582
- * const rels = await env.getRelationships('author');
583
- * for (const rel of rels) {
584
- * console.log(`${rel.local_submodel.path} -> ${rel.foreign_model.path} (${rel.relationship_kind})`);
585
- * }
586
- * ```
587
- */
588
- getRelationships(modelPath: string): Promise<RelationshipInfo[]>;
589
- /**
590
- * Attach a target model to a relationship submodel.
591
- *
592
- * Handles cardinality automatically:
593
- * - "One" side: sets/replaces the reference
594
- * - "Many" side: adds the target to the collection
595
- *
596
- * If the target model doesn't exist, it's created as an instance of the foreign type.
597
- * Bidirectional sync is automatic.
598
- *
599
- * @param modelPath - The model instance path (e.g., "tolkien")
600
- * @param submodelPath - The relationship submodel (e.g., "books")
601
- * @param targetPath - The target model to attach (e.g., "lord_of_the_rings")
602
- *
603
- * @example
604
- * ```typescript
605
- * // Attach a book to an author (many side)
606
- * await env.attach('tolkien', 'books', 'lord_of_the_rings');
607
- * // This also automatically sets lord_of_the_rings:author -> tolkien
608
- * ```
609
- */
610
- attach(modelPath: string, submodelPath: string, targetPath: string): Promise<void>;
611
- /**
612
- * Detach a target model from a relationship submodel.
613
- *
614
- * Handles bidirectional cleanup automatically.
615
- *
616
- * @param modelPath - The model instance path
617
- * @param submodelPath - The relationship submodel
618
- * @param targetPath - The target to detach (optional for "one" side; omit on "many" side to detach all)
619
- *
620
- * @example
621
- * ```typescript
622
- * // Detach a specific book
623
- * await env.detach('tolkien', 'books', 'lord_of_the_rings');
624
- *
625
- * // Detach all books
626
- * await env.detach('tolkien', 'books');
627
- * ```
628
- */
629
- detach(modelPath: string, submodelPath: string, targetPath?: string): Promise<void>;
630
- /**
631
- * List all related models through a relationship submodel.
632
- *
633
- * @param modelPath - The model instance path
634
- * @param submodelPath - The relationship submodel
635
- * @returns Array of related model references
636
- *
637
- * @example
638
- * ```typescript
639
- * const books = await env.listRelated('tolkien', 'books');
640
- * console.log(books); // [{ path: "lord_of_the_rings", label: "Lord of the Rings" }, ...]
641
- * ```
642
- */
643
- listRelated(modelPath: string, submodelPath: string): Promise<ModelRef[]>;
644
- /**
645
- * Apply a manifest to the current environment's graph.
646
- *
647
- * Translates each manifest operation into GraphQL mutations and executes them
648
- * in order. This is the core mechanism for creating classes, fields, and
649
- * relationships from a declarative manifest.
650
- *
651
- * @param manifest - The manifest content to apply
652
- * @returns Summary of applied operations
653
- *
654
- * @example
655
- * ```typescript
656
- * await environment.applyManifest({
657
- * schemaVersion: 2,
658
- * name: 'my-app',
659
- * volumes: [{
660
- * name: 'schema',
661
- * scope: 'sandbox',
662
- * operations: [
663
- * { create: 'author', extends: 'class', has: { name: { type: 'string' } } },
664
- * { create: 'book', extends: 'class', has: { title: { type: 'string' } } },
665
- * { defineRelationship: {
666
- * left: 'author', right: 'book',
667
- * leftSubmodel: 'books', rightSubmodel: 'author',
668
- * leftIsMany: true, rightIsMany: false,
669
- * }},
670
- * ],
671
- * }],
672
- * });
673
- * ```
674
- */
675
- applyManifest(manifest: ManifestContent): Promise<{
676
- applied: number;
677
- errors: string[];
678
- }>;
679
- /**
680
- * Resolve an alias reference like "@std/class" → "class"
681
- * Strips the alias prefix, returning the bare model path.
682
- */
683
- private _resolveAlias;
684
- private _runGraphql;
685
- private _applyFieldMetamodels;
686
- private _applyModelMetamodels;
687
- private _ensureWorkspaceToolsRoot;
688
- private _storeEffectSchemas;
689
- private _applyEffectMetamodels;
690
- private _ensureWorkspaceStreamsRoot;
691
- private _applyEventStreamDeclaration;
692
- private _applyEffectDeclaration;
693
- /**
694
- * Apply a single manifest operation via GraphQL
695
- */
696
- private _applyOperation;
697
- /**
698
- * Apply field definitions (has) to a model via GraphQL
699
- */
700
- private _applyFields;
701
- /**
702
- * Create or update an instance of a class in the graph.
703
- *
704
- * Uses `instantiate` under the hood, which has find-or-create semantics:
705
- * if an instance with the given `id` already exists for the class it is
706
- * returned; otherwise a new instance is created. Fields are then set
707
- * (overwriting previous values) and relationships are attached.
708
- *
709
- * The graph path is derived as `{className}_{id}` to ensure uniqueness
710
- * across classes (two objects of different classes may share the same
711
- * real-world ID). Relationship targets are also resolved automatically
712
- * using the foreign class from the relationship definition.
713
- *
714
- * @param options - The object specification
715
- * @returns The graph path, real-world ID, and creation status
716
- *
717
- * @example
718
- * ```typescript
719
- * // Create an author with fields
720
- * const result = await env.recordObject({
721
- * className: 'author',
722
- * id: 'tolkien',
723
- * label: 'J.R.R. Tolkien',
724
- * fields: { name: 'J.R.R. Tolkien', birth_year: 1892 },
725
- * relationships: { books: ['lotr', 'silmarillion'] },
726
- * });
727
- * // result.path → 'author_tolkien' (internal graph path)
728
- * // result.id → 'tolkien' (real-world ID)
729
- * // result.created → true
730
- * ```
731
- */
732
- recordObject(options: RecordObjectOptions): Promise<RecordObjectResult>;
733
- /**
734
- * Batch version of `recordObject()`.
735
- *
736
- * Sends rows through the control-plane **`/records/batch`** endpoint in **chunks** (default
737
- * **100** records per HTTP request) so individual requests stay bounded and gateway timeouts are
738
- * unlikely. Each chunk is retried on transient network / worker errors.
739
- *
740
- * Use the optional second argument to:
741
- * - **`batchSize`** — rows per POST (smaller = more progress events; larger = fewer round trips).
742
- * - **`concurrency`** — run up to N chunk POSTs in parallel (capped at 16) when you want lower wall time.
743
- * - **`onChunkComplete`** — hook for UIs after each chunk succeeds (row order in the returned array
744
- * always matches `records`; chunk **completion** order may differ when `concurrency > 1`).
745
- *
746
- * For **asynchronous** ingestion with worker-side batching and aggregate counters (`queued`,
747
- * `completed`, …), use **`enqueueRecordImport`** and poll **`getRecordImport`** /
748
- * **`getRecordImportSummary`** — best for very large fire-and-forget loads when immediate
749
- * synchronous commit of every row is not required.
750
- */
751
- recordObjects(records: RecordObjectOptions[], options?: RecordObjectsOptions): Promise<RecordObjectResult[]>;
752
- private executeRecordObjectsChunk;
753
- /**
754
- * Queue a background record import for this environment (async worker pipeline).
755
- *
756
- * **vs `recordObjects`:** this path accepts the full payload in one request, returns an
757
- * **`importId`**, and processes rows in the background — use **`getRecordImport`** /
758
- * **`getRecordImportSummary`** for progress. Choose it for large bulk loads where you do not
759
- * need every row committed before the HTTP call returns. Use **`recordObjects`** when you need
760
- * synchronous upserts and fine-grained chunk progress via **`onChunkComplete`**.
761
- */
762
- enqueueRecordImport(records: RecordObjectOptions[], options?: RecordImportOptions): Promise<RecordImport>;
763
- /**
764
- * List queued or completed record imports for this environment.
765
- */
766
- listRecordImports(status?: RecordImportStatus): Promise<RecordImport[]>;
767
- /**
768
- * Fetch the latest aggregate import counters for this environment.
769
- */
770
- getRecordImportSummary(): Promise<EnvironmentRecordImportSummary>;
771
- /**
772
- * Convenience helper returning queued + processing records for this environment.
773
- */
774
- getAwaitingRecordCount(): Promise<number>;
775
- /**
776
- * Fetch a single record import by id.
777
- */
778
- getRecordImport(importId: string): Promise<RecordImport>;
779
- /**
780
- * List the individual records persisted for one asynchronous import. This
781
- * makes terminal import failures diagnosable without database access.
782
- */
783
- listRecordImportItems(importId: string, status?: RecordImportItem["status"]): Promise<RecordImportItem[]>;
784
- /**
785
- * Cancel a queued/background record import.
786
- */
787
- cancelRecordImport(importId: string): Promise<RecordImport>;
788
- }
789
- /**
790
- * Live runtime session attached to one opened environment.
791
- *
792
- * This is the object returned by `environment.sessions.create()` and friends.
793
- * It owns websocket state, prompts, job execution, and the synced Automerge
794
- * document while delegating environment-level data APIs back to
795
- * `session.environment`.
796
- */
797
- declare class EnvironmentSession extends Session {
798
- readonly environment: Environment;
799
- private readonly sessionDataRoutePrefix;
800
- private readonly sessionDataHeaders;
801
- private readonly beforeMutationSend?;
802
- private heartbeatTimer;
803
- private heartbeatProbeInFlight;
804
- /** The last known graph container status, updated by checkReadiness(). */
805
- graphContainerStatus: {
806
- lastKeepAliveAt: number;
807
- status: "warming" | "hot" | "unknown";
808
- } | null;
809
- constructor(client: WSClient, environment: Environment, clientId: string, options?: {
810
- sessionDataRoutePrefix?: string;
811
- /**
812
- * Browser-only request metadata forwarded with session-data mutations.
813
- * This lets a session direct a frontend effect to the exact Dock client
814
- * that initiated a user action when multiple tabs are connected.
815
- */
816
- sessionDataHeaders?: SessionDataHeaders;
817
- /** Browser-only readiness guard checked immediately before each write. */
818
- beforeMutationSend?: () => void;
819
- initialQuota?: GranularQuotaProgress | null;
820
- });
821
- /**
822
- * Keep the browser session transport observable from the client side.
823
- * SessionDO already broadcasts a heartbeat every five seconds. Treat that
824
- * and all other inbound frames as proof of life instead of issuing an RPC:
825
- * an application RPC may be delayed by Durable Object work even while the
826
- * underlying WebSocket is healthy.
827
- */
828
- private startHeartbeat;
829
- private stopHeartbeat;
830
- hello(): Promise<{
831
- ok: boolean;
832
- environmentId?: string;
833
- docId?: string;
834
- features?: {
835
- serverHeartbeat?: boolean;
836
- hibernatingWebSocket?: boolean;
837
- };
838
- graphContainerStatus?: {
839
- lastKeepAliveAt: number;
840
- status: "warming" | "hot" | "unknown";
841
- };
842
- }>;
843
- get environmentId(): string;
844
- get sandboxId(): string;
845
- get ontologyId(): string;
846
- get subjectId(): string;
847
- get envName(): string;
848
- get tag(): string | null;
849
- get versionId(): string;
850
- get granularId(): string;
851
- get permissionProfileId(): string;
852
- get apiEndpoint(): string;
853
- get data(): {
854
- record: (record: RecordObjectOptions) => Promise<RecordObjectResult>;
855
- recordMany: (records: RecordObjectOptions[], options?: RecordObjectsOptions) => Promise<RecordObjectResult[]>;
856
- import: (records: RecordObjectOptions[], options?: {
857
- batchSize?: number;
858
- } | undefined) => Promise<RecordImport>;
859
- listImports: (status?: RecordImportStatus) => Promise<RecordImport[]>;
860
- getImport: (importId: string) => Promise<RecordImport>;
861
- listImportItems: (importId: string, status?: RecordImportItem["status"]) => Promise<RecordImportItem[]>;
862
- getImportSummary: () => Promise<EnvironmentRecordImportSummary>;
863
- cancelImport: (importId: string) => Promise<RecordImport>;
864
- getAwaitingCount: () => Promise<number>;
865
- };
866
- get feedback(): {
867
- list: () => Promise<EnvironmentFeedbackRecord[]>;
868
- };
869
- /**
870
- * Return a plain JS copy of the synced session heap.
871
- */
872
- getHeap(): SessionHeapSnapshot;
873
- private buildSessionDataUrl;
874
- private sessionDataFetch;
875
- private sessionDataRequest;
876
- /**
877
- * Fetch the live session document from the runtime DO.
878
- *
879
- * For presentation history use `feed.list()` or `transcript.list()`.
880
- * Timeline and job collections are diagnostic/execution data only.
881
- */
882
- getDocument(): Promise<SessionDocumentResult>;
883
- /**
884
- * Publish one terminal assistant reply from a trusted server integration.
885
- *
886
- * This uses the API-key-authenticated HTTP session boundary. Delegated
887
- * browser sessions cannot use it and never receive assistant feed-authoring
888
- * capability through their WebSocket.
889
- */
890
- publishAssistantReply(input: AssistantReplyPublicationInput): Promise<AssistantReplyPublicationResult>;
891
- get timeline(): {
892
- list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionTimelineEvent>>;
893
- };
894
- get jobs(): {
895
- list: (options?: SessionJobListOptions) => Promise<SessionCollectionListResult<SessionJobRecord>>;
896
- get: (jobId: string) => Promise<SessionJobRecord>;
897
- latest: (options?: Pick<SessionJobListOptions, "status">) => Promise<SessionJobRecord | null>;
898
- };
899
- get mutations(): {
900
- list: (options?: {
901
- limit?: number;
902
- compact?: boolean;
903
- }) => Promise<{
904
- items: SessionMutationView[];
905
- }>;
906
- };
907
- get artifacts(): {
908
- list: (options?: SessionArtifactListOptions) => Promise<{
909
- items: SessionArtifactRecord[];
910
- nextCursor: string | null;
911
- totalCount: number;
912
- }>;
913
- listForLatestJob: (options?: Omit<SessionArtifactListOptions, "jobId" | "latestJob">) => Promise<{
914
- items: SessionArtifactRecord[];
915
- nextCursor: string | null;
916
- totalCount: number;
917
- }>;
918
- get: (artifactId: string) => Promise<SessionArtifactRecord>;
919
- create: (artifact: Partial<SessionArtifactRecord> & {
920
- label: string;
921
- }) => Promise<SessionArtifactRecord>;
922
- acceptSuggestion: (sequence: number) => Promise<SessionArtifactRecord>;
923
- updateInputs: (artifactId: string, patch: {
924
- inputValues?: Record<string, unknown>;
925
- relationships?: Record<string, string | string[] | null>;
926
- /** Field paths whose current assistant value the user kept. */
927
- confirmFields?: string[];
928
- relationshipLabels?: Record<string, Record<string, string>>;
929
- expectedUpdatedAt?: number;
930
- }) => Promise<SessionArtifactRecord>;
931
- relationshipOptions: (artifactId: string, input: SessionArtifactRelationshipOptionsInput) => Promise<SessionArtifactRelationshipOptionsResult>;
932
- relationshipCreate: (artifactId: string, input: SessionArtifactRelationshipCreateInput) => Promise<SessionArtifactRecord>;
933
- validate: (artifactId: string) => Promise<SessionArtifactValidationResult>;
934
- execute: (artifactId: string, options: SessionArtifactExecutionOptions) => Promise<SessionArtifactExecutionResult>;
935
- approve: (artifactId: string, options: SessionArtifactApprovalOptions) => Promise<SessionArtifactExecutionResult>;
936
- cancel: (artifactId: string) => Promise<SessionArtifactRecord>;
937
- };
938
- get manualActions(): {
939
- record: (input: RecordManualActionInput) => Promise<ManualActionRecordResult>;
940
- list: (options?: ManualActionListOptions) => Promise<SessionCollectionListResult<ManualActionOccurrence>>;
941
- suggest: (options?: ManualActionSuggestionOptions) => Promise<{
942
- items: ManualActionSuggestion[];
943
- }>;
944
- };
945
- get artifactApprovals(): {
946
- list: (options?: ArtifactApprovalTaskListOptions) => Promise<SessionCollectionListResult<ArtifactApprovalTask>>;
947
- decide: (approvalTaskId: string, input: ArtifactApprovalDecisionInput) => Promise<ArtifactApprovalDecisionResult>;
948
- };
949
- get files(): {
950
- list: (options?: SessionCollectionListOptions & {
951
- status?: string | null;
952
- source?: string | null;
953
- }) => Promise<SessionCollectionListResult<SessionFileRecord>>;
954
- get: (fileId: string) => Promise<SessionFileRecord>;
955
- upload: (body: SessionFileUploadBody, options?: SessionFileUploadOptions) => Promise<SessionFileRecord>;
956
- download: (fileId: string) => Promise<ArrayBuffer>;
957
- delete: (fileId: string) => Promise<{
958
- deleted: boolean;
959
- fileId: string;
960
- }>;
961
- };
962
- get heap(): {
963
- entries: {
964
- list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionHeapEntry>>;
965
- get: (path: string) => Promise<SessionHeapEntry>;
966
- };
967
- lists: {
968
- list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionHeapList>>;
969
- get: (name: string) => Promise<SessionHeapList>;
970
- };
971
- variables: {
972
- list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionHeapVariable>>;
973
- get: (name: string) => Promise<SessionHeapVariable>;
974
- delete: (name: string) => Promise<{
975
- deleted: boolean;
976
- name: string;
977
- }>;
978
- };
979
- };
980
- get transcript(): {
981
- list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionTranscriptEntry>>;
982
- };
983
- graphql<T = any>(query: string, variables?: Record<string, any>): Promise<GraphQLResult<T>>;
984
- searchRecords(query: string, options?: RecordSearchOptions): Promise<RecordSearchResult[]>;
985
- mentionRecord(input: RecordMentionInput): Promise<SessionHeapEntry>;
986
- defineRelationship(options: DefineRelationshipOptions): Promise<RelationshipInfo>;
987
- getRelationships(modelPath: string): Promise<RelationshipInfo[]>;
988
- attach(modelPath: string, submodelPath: string, targetPath: string): Promise<void>;
989
- detach(modelPath: string, submodelPath: string, targetPath?: string): Promise<void>;
990
- listRelated(modelPath: string, submodelPath: string): Promise<ModelRef[]>;
991
- applyManifest(manifest: ManifestContent): Promise<{
992
- applied: number;
993
- errors: string[];
994
- }>;
995
- recordObject(options: RecordObjectOptions): Promise<RecordObjectResult>;
996
- recordState(input: EnvironmentStateUpdateInput): Promise<RecordObjectResult>;
997
- state(target: EnvironmentStateTarget): EnvironmentStateProxy;
998
- recordObjects(records: RecordObjectOptions[], options?: RecordObjectsOptions): Promise<RecordObjectResult[]>;
999
- enqueueRecordImport(records: RecordObjectOptions[], options?: RecordImportOptions): Promise<RecordImport>;
1000
- listRecordImports(status?: RecordImportStatus): Promise<RecordImport[]>;
1001
- getRecordImportSummary(): Promise<EnvironmentRecordImportSummary>;
1002
- getAwaitingRecordCount(): Promise<number>;
1003
- getRecordImport(importId: string): Promise<RecordImport>;
1004
- cancelRecordImport(importId: string): Promise<RecordImport>;
1005
- listFeedback(): Promise<EnvironmentFeedbackRecord[]>;
1006
- /**
1007
- * Close the session and disconnect from the sandbox.
1008
- *
1009
- * Sends `client.goodbye` over WebSocket first, then issues an HTTP fallback
1010
- * to the runtime goodbye endpoint if no definitive WS-side runtime notify
1011
- * acknowledgement was observed.
1012
- */
1013
- disconnect(): Promise<void>;
1014
- /**
1015
- * Close only the socket transport without sending `client.goodbye`.
1016
- */
1017
- disconnectTransport(): void;
1018
- /**
1019
- * Backwards-compatible alias for `disconnect()`.
1020
- */
1021
- close(): Promise<void>;
1022
- /**
1023
- * Check if the graph container is ready and warm.
1024
- */
1025
- checkReadiness(): Promise<{
1026
- lastKeepAliveAt: number;
1027
- status: "warming" | "hot" | "unknown";
1028
- }>;
1029
- }
1030
- declare class OntologyHandle {
1031
- private granular;
1032
- private ontologyNameOrId;
1033
- constructor(granular: Granular, ontologyNameOrId: string);
1034
- get effects(): {
1035
- register: (effect: ToolWithHandler) => Promise<void>;
1036
- registerMany: (effects: ToolWithHandler[]) => Promise<void>;
1037
- unregister: (name: string) => Promise<void>;
1038
- clear: () => Promise<void>;
1039
- disconnect: () => Promise<void>;
1040
- };
1041
- get importer(): {
1042
- onEnvironmentCreate: (handler: EnvironmentImporterHandler) => void;
1043
- clear: () => void;
1044
- };
1045
- }
1046
- declare class Granular {
1047
- private apiKey;
1048
- private apiUrl;
1049
- private httpUrl;
1050
- private tokenProvider?;
1051
- private WebSocketCtor?;
1052
- private onUnexpectedClose?;
1053
- private onReconnectError?;
1054
- private effectHostUrl?;
1055
- private debugHttp;
1056
- /** Sandbox-level effect registry: sandboxId → (effectKey@selector → ToolWithHandler) */
1057
- private sandboxEffects;
1058
- /** Live sandbox-scoped effect hosts keyed by sandboxId */
1059
- private sandboxEffectHosts;
1060
- /** In-flight host connection promises to avoid duplicate concurrent connects */
1061
- private sandboxEffectHostPromises;
1062
- /** Ontology-bound environment importer hooks keyed by the caller's ontology identifier. */
1063
- private ontologyImporters;
1064
- /** Resolved importer hooks keyed by sandboxId for fast lookups during openEnvironment(). */
1065
- private sandboxImporters;
1066
- /**
1067
- * Create a new Granular client
1068
- * @param options - Client configuration
1069
- */
1070
- constructor(options: GranularOptions);
1071
- /**
1072
- * Return an ontology-scoped handle for effects and other ontology-level APIs.
1073
- */
1074
- ontology(ontologyNameOrId: string): OntologyHandle;
1075
- registerEnvironmentImporter(ontologyNameOrId: string, handler: EnvironmentImporterHandler): void;
1076
- clearEnvironmentImporter(ontologyNameOrId: string): void;
1077
- /**
1078
- * Records/upserts a user and prepares them for sandbox connections
1079
- *
1080
- * @param options - User options
1081
- * @returns The recorded user with both `userId` and `granularId`
1082
- *
1083
- * @example
1084
- * ```typescript
1085
- * const user = await granular.recordUser({
1086
- * userId: 'user_123',
1087
- * name: 'John Doe',
1088
- * permissions: ['agent'],
1089
- * });
1090
- * ```
1091
- */
1092
- recordUser(options: RecordUserOptions): Promise<User>;
1093
- /**
1094
- * Alias for `recordUser()` with user-facing naming that matches upsert semantics.
1095
- */
1096
- upsertUser(options: RecordUserOptions): Promise<User>;
1097
- private resolveConnectUser;
1098
- /**
1099
- * Open or resolve an ontology environment for one user without opening a session.
1100
- *
1101
- * @example
1102
- * ```typescript
1103
- * const environment = await granular.openEnvironment({
1104
- * ontology: 'my-ontology',
1105
- * tag: 'dev',
1106
- * userId: 'user_123',
1107
- * permissions: ['agent'],
1108
- * });
1109
- *
1110
- * await environment.data.record({
1111
- * className: 'customer',
1112
- * id: 'acme',
1113
- * fields: { name: 'Acme' },
1114
- * });
1115
- *
1116
- * const session = await environment.sessions.create();
1117
- * const job = await session.submitJob(`return "hello";`);
1118
- * console.log(await job.result);
1119
- * ```
1120
- */
1121
- openEnvironment(options: OpenEnvironmentOptions): Promise<Environment>;
1122
- /**
1123
- * Read the active environment selected by Granular for an already-recorded
1124
- * external user. This is intentionally read-only: browser/login code must
1125
- * not create subjects or environments as a side effect.
1126
- */
1127
- getActiveEnvironmentForUser(options: {
1128
- sandboxId: string;
1129
- tag: string;
1130
- userId: string;
1131
- slot?: string;
1132
- }): Promise<Environment | null>;
1133
- /**
1134
- * Resolve one exact environment only when Granular confirms that it belongs
1135
- * to the given external user in the requested sandbox (and, optionally,
1136
- * tag). This is deliberately read-only: callers use it to keep an already
1137
- * opened delegated workspace stable while a newer active environment is
1138
- * being prepared in the background.
1139
- */
1140
- getEnvironmentForUser(options: {
1141
- sandboxId: string;
1142
- userId: string;
1143
- environmentId: string;
1144
- tag?: string;
1145
- }): Promise<Environment | null>;
1146
- /**
1147
- * Register one reviewed, pre-existing environment as the active workspace
1148
- * for an external user. This is for a controlled migration only: it does
1149
- * not create an environment and it does not run an importer.
1150
- */
1151
- adoptEnvironmentForUser(options: AdoptEnvironmentOptions): Promise<Environment>;
1152
- /**
1153
- * Deprecated compatibility alias for `openEnvironment()`.
1154
- *
1155
- * `connect()` no longer opens a runtime session automatically.
1156
- */
1157
- connect(options: ConnectOptions): Promise<Environment>;
1158
- /**
1159
- * Run a registered environment importer against an environment that was
1160
- * opened outside this SDK instance, for example by a delegated browser flow.
1161
- *
1162
- * This uses the same setup-run and queued record-import plumbing as
1163
- * `openEnvironment()`: importer stages, expected object counts, and queued
1164
- * import counters remain visible through `environment.setup` and
1165
- * `getRecordImportSummary()`.
1166
- */
1167
- runEnvironmentImporterForEnvironment(environmentId: string, options?: RunEnvironmentImporterOptions): Promise<EnvironmentSetupSummary | null>;
1168
- private resolveRequestedTag;
1169
- private buildManagedEnvironmentName;
1170
- private isManagedEnvironmentName;
1171
- private sortEnvironmentsByRecency;
1172
- private resolveOpenEnvironmentData;
1173
- /**
1174
- * List indexed sessions using ownership filters and bounded pagination.
1175
- */
1176
- listSessions(options: ConversationSessionListOptions): Promise<ConversationSessionInfo[]>;
1177
- listSessionsPage(options: ConversationSessionListOptions): Promise<ConversationSessionListResponse>;
1178
- /**
1179
- * List active (open) sessions for an environment.
1180
- */
1181
- listOpenSessions(filters: Omit<ConversationSessionListOptions, "status"> & {
1182
- environmentId: string;
1183
- }): Promise<ConversationSessionInfo[]>;
1184
- /**
1185
- * List closed sessions for an environment (conversations that have disconnected).
1186
- */
1187
- listClosedSessions(filters: Omit<ConversationSessionListOptions, "status"> & {
1188
- environmentId: string;
1189
- }): Promise<ConversationSessionInfo[]>;
1190
- getUserEnvironmentState(options: UserEnvironmentStateOptions & {
1191
- environmentId: string;
1192
- }): Promise<UserEnvironmentState>;
1193
- markUserEnvironmentSessionsRead(options: MarkUserEnvironmentReadOptions & {
1194
- environmentId: string;
1195
- }): Promise<UserEnvironmentState["readThroughSequenceBySessionId"]>;
1196
- private normalizeConversationSession;
1197
- private normalizeUserEnvironmentState;
1198
- private static coerceIsoDate;
1199
- /**
1200
- * Create a new session (conversation) for an existing environment and connect to it.
1201
- * The runtime graph is shared across all sessions for the same environment.
1202
- */
1203
- createSession(options: {
1204
- environmentId: string;
1205
- clientId?: string;
1206
- sessionScope?: CreateSessionOptions["sessionScope"];
1207
- initialHeap?: CreateSessionOptions["initialHeap"];
1208
- }): Promise<EnvironmentSession>;
1209
- /**
1210
- * Connect to an existing open session (same conversation thread) using a freshly minted WebSocket token.
1211
- */
1212
- connectSession(options: {
1213
- sessionId: string;
1214
- clientId?: string;
1215
- maxReconnectAttempts?: number;
1216
- reconnectDelayMs?: number;
1217
- }): Promise<EnvironmentSession>;
1218
- recordOpenAIUsageSpend(usage: OpenAIUsageSpendEvent, context?: GranularSpendContext | null, options?: {
1219
- metadata?: Record<string, unknown> | null;
1220
- }): Promise<RecordOpenAIUsageSpendResult>;
1221
- /** End a session through the runtime, or disconnect its connected handle. */
1222
- closeSession(sessionId: string, environment?: EnvironmentSession | null): Promise<void>;
1223
- /**
1224
- * Re-open a closed session in the index and connect to its existing runtime document.
1225
- */
1226
- reopenSession(sessionId: string, options?: {
1227
- clientId?: string;
1228
- }): Promise<EnvironmentSession>;
1229
- private resolveEnvironmentImporter;
1230
- private maybeRunEnvironmentImporter;
1231
- private runEnvironmentImporter;
1232
- private bindEnvironmentHandle;
1233
- private bindWebSocketEnvironmentSession;
1234
- private activateEnvironment;
1235
- private getSandboxEffectMap;
1236
- private serializeEffect;
1237
- private publishSandboxEffectCatalog;
1238
- private syncSandboxEffectCatalog;
1239
- private recoverEffectHost;
1240
- private startEffectHostHeartbeat;
1241
- private stopEffectHostHeartbeat;
1242
- private synchronizeEffectHost;
1243
- private ensureSandboxEffectHost;
1244
- private disconnectSandboxEffectHost;
1245
- /**
1246
- * Register an effect (tool) for a specific sandbox.
1247
- *
1248
- * @param sandboxNameOrId - The name or ID of the sandbox
1249
- * @param effect - The tool definition and handler
1250
- */
1251
- registerEffect(sandboxNameOrId: string, effect: ToolWithHandler): Promise<void>;
1252
- /**
1253
- * Register multiple effects (tools) for a specific sandbox.
1254
- *
1255
- * batch version of `registerEffect`.
1256
- */
1257
- registerEffects(sandboxNameOrId: string, effects: ToolWithHandler[]): Promise<void>;
1258
- /**
1259
- * Unregister an effect from a sandbox.
1260
- *
1261
- * Removes it from the local sandbox registry and updates the
1262
- * sandbox-scoped live catalog.
1263
- */
1264
- unregisterEffect(sandboxNameOrId: string, name: string): Promise<void>;
1265
- /**
1266
- * Disconnect one sandbox-scoped effect host, or all of them when no sandbox is provided.
1267
- *
1268
- * This is primarily useful for long-lived helper processes such as generated
1269
- * `granular-effects.ts` scripts that need to shut down cleanly on SIGINT/SIGTERM.
1270
- */
1271
- disconnectEffects(sandboxNameOrId?: string): Promise<void>;
1272
- /**
1273
- * Unregister all effects for a sandbox.
1274
- */
1275
- unregisterAllEffects(sandboxNameOrId: string): Promise<void>;
1276
- /**
1277
- * Find a sandbox by name or create it if it doesn't exist
1278
- */
1279
- private findOrCreateSandbox;
1280
- /**
1281
- * Resolve an existing permission profile by exact name or ID.
1282
- *
1283
- * `allow-all` is the sole compatibility profile that the SDK may provision
1284
- * automatically. Every other missing reference fails closed so a typo or
1285
- * untrusted role value cannot become an allow-default profile.
1286
- */
1287
- private ensurePermissionProfile;
1288
- /**
1289
- * Ensure an assignment exists for a subject in a sandbox with a permission profile
1290
- */
1291
- private ensureAssignment;
1292
- /**
1293
- * Sandbox management API
1294
- */
1295
- get sandboxes(): {
1296
- list: () => Promise<SandboxListResponse>;
1297
- get: (id: string) => Promise<Sandbox>;
1298
- create: (data: CreateSandboxData) => Promise<Sandbox>;
1299
- update: (id: string, data: Partial<CreateSandboxData>) => Promise<Sandbox>;
1300
- delete: (id: string) => Promise<DeleteResponse>;
1301
- };
1302
- /**
1303
- * Permission Profile management for sandboxes
1304
- */
1305
- get permissionProfiles(): {
1306
- list: (sandboxId: string) => Promise<PermissionProfile[]>;
1307
- get: (sandboxId: string, profileId: string) => Promise<PermissionProfile>;
1308
- create: (sandboxId: string, data: CreatePermissionProfileData) => Promise<PermissionProfile>;
1309
- delete: (_sandboxId: string, _profileId: string) => Promise<DeleteResponse>;
1310
- };
1311
- /**
1312
- * Environment management
1313
- */
1314
- get environments(): {
1315
- list: (sandboxId: string) => Promise<EnvironmentData[]>;
1316
- get: (environmentId: string) => Promise<EnvironmentData>;
1317
- create: (sandboxId: string, data: CreateEnvironmentData) => Promise<EnvironmentData>;
1318
- delete: (environmentId: string) => Promise<DeleteResponse>;
1319
- };
1320
- /**
1321
- * Event stream operations: query, subscribe, and acknowledge stream events
1322
- */
1323
- get streams(): {
1324
- getEvents: (params: {
1325
- ontology: string;
1326
- stream: string;
1327
- environment?: string;
1328
- session?: string;
1329
- eventTypes?: string[];
1330
- since?: Date;
1331
- until?: Date;
1332
- isAcked?: boolean;
1333
- limit?: number;
1334
- offset?: number;
1335
- }) => Promise<StreamEvent[]>;
1336
- subscribe: (params: {
1337
- ontology: string;
1338
- stream: string;
1339
- environment?: string;
1340
- session?: string;
1341
- eventTypes?: string[];
1342
- since?: Date;
1343
- onEvent: (event: StreamEvent) => void;
1344
- onError?: (err: Error) => void;
1345
- pollIntervalMs?: number;
1346
- }) => StreamSubscription;
1347
- ack: (eventId: string) => Promise<void>;
1348
- ackBatch: (eventIds: string[]) => Promise<void>;
1349
- getStats: (params: {
1350
- ontology: string;
1351
- environment?: string;
1352
- }) => Promise<StreamStats[]>;
1353
- };
1354
- /**
1355
- * Subject management
1356
- */
1357
- get subjects(): {
1358
- get: (subjectId: string) => Promise<Subject>;
1359
- listAssignments: (subjectId: string) => Promise<AssignmentListResponse>;
1360
- };
1361
- /**
1362
- * @deprecated Use recordUser() instead
1363
- */
1364
- get users(): {
1365
- create: (data: {
1366
- id: string;
1367
- name?: string;
1368
- email?: string;
1369
- }) => Promise<Subject>;
1370
- get: (id: string) => Promise<Subject>;
1371
- };
1372
- private _resolveSandboxId;
1373
- /**
1374
- * Make an authenticated API request
1375
- */
1376
- private request;
1377
- }
1378
-
1379
- export { Environment as E, Granular as G, OntologyHandle as O, Session as S, WSClient as W, EnvironmentSession as a, isGraphQLMutationDocument as i };