@granular-software/sdk 0.4.74 → 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,1381 +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-DBRQOSaj.mjs';
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
- private _graphqlIdempotencyKey?;
347
- constructor(granular: Granular, envData: EnvironmentData, apiKey: string, apiEndpoint: string, tokenProvider?: AccessTokenProvider, beforeMutationSend?: () => void, graphqlIdempotencyKey?: GranularOptions["graphqlIdempotencyKey"]);
348
- /** The environment ID */
349
- get environmentId(): string;
350
- /** The sandbox ID */
351
- get sandboxId(): string;
352
- /** The ontology ID */
353
- get ontologyId(): string;
354
- /** The subject ID */
355
- get subjectId(): string;
356
- /** The named environment slot, such as dev or prod */
357
- get envName(): string;
358
- /** The named environment slot, such as dev or prod */
359
- get environment(): string;
360
- /** The resolved ontology version backing this environment */
361
- get versionId(): string;
362
- /** Internal Granular user identifier for this environment */
363
- get granularId(): string;
364
- /** The permission profile ID */
365
- get permissionProfileId(): string;
366
- /** The current build policy backing this environment */
367
- get buildPolicy(): BuildPolicy;
368
- /** The current update state relative to the followed tag */
369
- get updateState(): EnvironmentData["updateState"];
370
- /** The latest setup/import run summary for this environment, when available. */
371
- get setup(): EnvironmentSetupSummary | null;
372
- /** Convenience flag for whether this environment trails the current tag target */
373
- get isOutdated(): boolean;
374
- /** The followed tag name when this environment is tag-tracked */
375
- get tag(): string | null;
376
- /** The GraphQL API endpoint URL */
377
- get apiEndpoint(): string;
378
- /** Internal auth token used for control-plane and runtime fallback requests */
379
- get authToken(): string;
380
- resolveAuthToken(): string | Promise<string>;
381
- /** Base runtime URL derived from the GraphQL endpoint */
382
- get runtimeBaseUrl(): string;
383
- syncEnvironmentData(envData: EnvironmentData): void;
384
- get sessions(): {
385
- list: (options?: Omit<ConversationSessionListOptions, "environmentId" | "sandboxId" | "subjectId">) => Promise<ConversationSessionInfo[]>;
386
- page: (options?: Omit<ConversationSessionListOptions, "environmentId" | "sandboxId" | "subjectId">) => Promise<ConversationSessionListResponse>;
387
- create: (options?: CreateSessionOptions) => Promise<EnvironmentSession>;
388
- connect: (sessionId: string, options?: {
389
- clientId?: string;
390
- }) => Promise<EnvironmentSession>;
391
- reopen: (sessionId: string, options?: {
392
- clientId?: string;
393
- }) => Promise<EnvironmentSession>;
394
- close: (sessionId: string, session?: EnvironmentSession | null) => Promise<void>;
395
- state: (options?: UserEnvironmentStateOptions) => Promise<UserEnvironmentState>;
396
- markRead: (options: MarkUserEnvironmentReadOptions) => Promise<UserEnvironmentState["readThroughSequenceBySessionId"]>;
397
- };
398
- get userEnvironmentState(): {
399
- get: (options?: UserEnvironmentStateOptions) => Promise<UserEnvironmentState>;
400
- markRead: (options: MarkUserEnvironmentReadOptions) => Promise<UserEnvironmentState["readThroughSequenceBySessionId"]>;
401
- };
402
- get data(): {
403
- record: (record: RecordObjectOptions) => Promise<RecordObjectResult>;
404
- recordMany: (records: RecordObjectOptions[], options?: RecordObjectsOptions) => Promise<RecordObjectResult[]>;
405
- import: (records: RecordObjectOptions[], options?: {
406
- batchSize?: number;
407
- }) => Promise<RecordImport>;
408
- listImports: (status?: RecordImportStatus) => Promise<RecordImport[]>;
409
- getImport: (importId: string) => Promise<RecordImport>;
410
- listImportItems: (importId: string, status?: RecordImportItem["status"]) => Promise<RecordImportItem[]>;
411
- getImportSummary: () => Promise<EnvironmentRecordImportSummary>;
412
- cancelImport: (importId: string) => Promise<RecordImport>;
413
- getAwaitingCount: () => Promise<number>;
414
- };
415
- /**
416
- * Acknowledge a declared product mutation that already happened outside a
417
- * Granular-run effect (for example, in a webhook consumer). These methods
418
- * run the declaration's pure projection mapper; they never call its handler.
419
- */
420
- get commit(): {
421
- effect: <TResult>(effect: ToolWithHandler & {
422
- commit: {
423
- kind: "effect";
424
- project: ProjectionMapper<TResult, EffectProjectionResult>;
425
- };
426
- }, productResult: TResult, options?: ExternalCommitOptions) => Promise<CommitReceipt>;
427
- transition: <TResult>(transition: {
428
- from: string;
429
- outcomes: Record<string, unknown>;
430
- effect: ToolWithHandler & {
431
- commit: {
432
- kind: "transition";
433
- project: ProjectionMapper<TResult, TransitionProjectionResult>;
434
- };
435
- };
436
- }, productResult: TResult, options?: ExternalCommitOptions) => Promise<CommitReceipt>;
437
- get: (commitId: string) => Promise<CommitReceipt>;
438
- retry: (commitId: string) => Promise<CommitReceipt>;
439
- };
440
- /** Inspect or retry the agent synchronization of a product snapshot. */
441
- get observation(): {
442
- get: (observationId: string) => Promise<ObservationReceipt>;
443
- retry: (observationId: string) => Promise<ObservationReceipt>;
444
- };
445
- private persistExternalEffect;
446
- private persistExternalTransition;
447
- private requireExternalIdentity;
448
- /**
449
- * Synchronize a versioned product snapshot without claiming an effect or
450
- * lifecycle transition. This records no transition history.
451
- */
452
- observe<TResult>(mapper: ProjectionMapper<TResult, EffectProjectionResult>, productResult: TResult): Promise<ObservationReceipt>;
453
- /**
454
- * Mirror product-owned workflow state into Granular without making Granular
455
- * own the customer application's state machine.
456
- */
457
- recordState(input: EnvironmentStateUpdateInput): Promise<RecordObjectResult>;
458
- /**
459
- * Mirror product-owned workflow state into Granular without making Granular
460
- * own the customer application's state machine.
461
- *
462
- * Example:
463
- * `await env.recordState({ className: "spend_request", id, machine: "lifecycle", state: "policy_review", source: "customer_backend" })`
464
- */
465
- state(target: EnvironmentStateTarget): EnvironmentStateProxy;
466
- get feedback(): {
467
- list: () => Promise<EnvironmentFeedbackRecord[]>;
468
- };
469
- get manualActions(): {
470
- record: (input: RecordManualActionInput) => Promise<ManualActionRecordResult>;
471
- list: (options?: ManualActionListOptions) => Promise<SessionCollectionListResult<ManualActionOccurrence>>;
472
- suggest: (options?: ManualActionSuggestionOptions) => Promise<{
473
- items: ManualActionSuggestion[];
474
- }>;
475
- };
476
- get artifactApprovals(): {
477
- list: (options?: ArtifactApprovalTaskListOptions) => Promise<SessionCollectionListResult<ArtifactApprovalTask>>;
478
- decide: (approvalTaskId: string, input: ArtifactApprovalDecisionInput) => Promise<ArtifactApprovalDecisionResult>;
479
- };
480
- /**
481
- * Sessionless environments do not own a live transport, so disconnecting the
482
- * environment handle itself is a no-op. This keeps the public surface
483
- * symmetric with `EnvironmentSession.disconnect()` and lets callers always
484
- * clean up safely without tracking whether they currently hold an environment
485
- * or a session.
486
- */
487
- disconnect(): Promise<void>;
488
- listSessions(status?: ConversationSessionListOptions["status"]): Promise<ConversationSessionInfo[]>;
489
- listSessions(options?: Omit<ConversationSessionListOptions, "environmentId" | "sandboxId" | "subjectId">): Promise<ConversationSessionInfo[]>;
490
- getUserEnvironmentState(options?: UserEnvironmentStateOptions): Promise<UserEnvironmentState>;
491
- markUserEnvironmentSessionsRead(options: MarkUserEnvironmentReadOptions): Promise<UserEnvironmentState["readThroughSequenceBySessionId"]>;
492
- createSession(options?: CreateSessionOptions): Promise<EnvironmentSession>;
493
- connectSession(sessionId: string, options?: {
494
- clientId?: string;
495
- maxReconnectAttempts?: number;
496
- reconnectDelayMs?: number;
497
- }): Promise<EnvironmentSession>;
498
- reopenSession(sessionId: string, options?: {
499
- clientId?: string;
500
- }): Promise<EnvironmentSession>;
501
- closeSession(sessionId: string, session?: EnvironmentSession | null): Promise<void>;
502
- listFeedback(): Promise<EnvironmentFeedbackRecord[]>;
503
- recordManualAction(input: RecordManualActionInput): Promise<ManualActionRecordResult>;
504
- listManualActions(options?: ManualActionListOptions): Promise<SessionCollectionListResult<ManualActionOccurrence>>;
505
- suggestManualActions(options?: ManualActionSuggestionOptions): Promise<{
506
- items: ManualActionSuggestion[];
507
- }>;
508
- listArtifactApprovals(options?: ArtifactApprovalTaskListOptions): Promise<SessionCollectionListResult<ArtifactApprovalTask>>;
509
- decideArtifactApproval(approvalTaskId: string, input: ArtifactApprovalDecisionInput): Promise<ArtifactApprovalDecisionResult>;
510
- private getRuntimeBaseUrl;
511
- private controlPlaneRequest;
512
- private static normalizeGraphPathSegment;
513
- /**
514
- * Convert a class name + application record ID into Granular's graph path.
515
- *
516
- * This mirrors the record-write path normalization used by the control plane.
517
- * Keep the original customer/system ID in `real_id`; graph paths are stable
518
- * internal addresses, not the source of truth for business identity.
519
- */
520
- static toGraphPath(className: string, id: string): string;
521
- /**
522
- * Best-effort extraction of an ID-like suffix from a graph path.
523
- *
524
- * Prefer the record's `real_id` field whenever exact customer/system IDs
525
- * matter, because graph path normalization is intentionally lossy.
526
- */
527
- static extractIdFromGraphPath(graphPath: string, className: string): string;
528
- /**
529
- * Execute a GraphQL query against the environment's graph.
530
- *
531
- * The query uses the Granular graph query language (based on Cypher/GraphQL).
532
- * Authentication is handled automatically using the SDK's API key.
533
- *
534
- * @param query - The GraphQL query string
535
- * @param variables - Optional variables for the query
536
- * @returns The query result data
537
- *
538
- * @example
539
- * ```typescript
540
- * // Read the workspace
541
- * const result = await env.graphql(
542
- * `query { model(path: "workspace") { path label submodels { path label } } }`
543
- * );
544
- * console.log(result.data);
545
- *
546
- * // Create a model
547
- * const created = await env.graphql(
548
- * `mutation { at(path: "workspace") { create_submodel(subpath: "my_node", label: "My Node", prototype: "Model") { model { path label } } } }`
549
- * );
550
- * ```
551
- */
552
- graphql<T = any>(query: string, variables?: Record<string, any>): Promise<GraphQLResult<T>>;
553
- searchRecords(query: string, options?: RecordSearchOptions): Promise<RecordSearchResult[]>;
554
- /**
555
- * Define a relationship between two model types.
556
- *
557
- * Creates both submodels (if they don't exist) and links them with
558
- * a RelationshipDef node that encodes cardinality.
559
- *
560
- * @example
561
- * ```typescript
562
- * // Author has many Books, Book has one Author
563
- * const rel = await env.defineRelationship({
564
- * model: 'author',
565
- * localSubmodel: 'books',
566
- * localIsMany: true,
567
- * foreignModel: 'book',
568
- * foreignSubmodel: 'author',
569
- * foreignIsMany: false,
570
- * });
571
- * console.log(rel.relationship_kind); // "one_to_many"
572
- * ```
573
- */
574
- defineRelationship(options: DefineRelationshipOptions): Promise<RelationshipInfo>;
575
- /**
576
- * Get all relationships for a model type.
577
- *
578
- * @param modelPath - The model type path (e.g., "author")
579
- * @returns Array of relationships from this model's perspective
580
- *
581
- * @example
582
- * ```typescript
583
- * const rels = await env.getRelationships('author');
584
- * for (const rel of rels) {
585
- * console.log(`${rel.local_submodel.path} -> ${rel.foreign_model.path} (${rel.relationship_kind})`);
586
- * }
587
- * ```
588
- */
589
- getRelationships(modelPath: string): Promise<RelationshipInfo[]>;
590
- /**
591
- * Attach a target model to a relationship submodel.
592
- *
593
- * Handles cardinality automatically:
594
- * - "One" side: sets/replaces the reference
595
- * - "Many" side: adds the target to the collection
596
- *
597
- * If the target model doesn't exist, it's created as an instance of the foreign type.
598
- * Bidirectional sync is automatic.
599
- *
600
- * @param modelPath - The model instance path (e.g., "tolkien")
601
- * @param submodelPath - The relationship submodel (e.g., "books")
602
- * @param targetPath - The target model to attach (e.g., "lord_of_the_rings")
603
- *
604
- * @example
605
- * ```typescript
606
- * // Attach a book to an author (many side)
607
- * await env.attach('tolkien', 'books', 'lord_of_the_rings');
608
- * // This also automatically sets lord_of_the_rings:author -> tolkien
609
- * ```
610
- */
611
- attach(modelPath: string, submodelPath: string, targetPath: string): Promise<void>;
612
- /**
613
- * Detach a target model from a relationship submodel.
614
- *
615
- * Handles bidirectional cleanup automatically.
616
- *
617
- * @param modelPath - The model instance path
618
- * @param submodelPath - The relationship submodel
619
- * @param targetPath - The target to detach (optional for "one" side; omit on "many" side to detach all)
620
- *
621
- * @example
622
- * ```typescript
623
- * // Detach a specific book
624
- * await env.detach('tolkien', 'books', 'lord_of_the_rings');
625
- *
626
- * // Detach all books
627
- * await env.detach('tolkien', 'books');
628
- * ```
629
- */
630
- detach(modelPath: string, submodelPath: string, targetPath?: string): Promise<void>;
631
- /**
632
- * List all related models through a relationship submodel.
633
- *
634
- * @param modelPath - The model instance path
635
- * @param submodelPath - The relationship submodel
636
- * @returns Array of related model references
637
- *
638
- * @example
639
- * ```typescript
640
- * const books = await env.listRelated('tolkien', 'books');
641
- * console.log(books); // [{ path: "lord_of_the_rings", label: "Lord of the Rings" }, ...]
642
- * ```
643
- */
644
- listRelated(modelPath: string, submodelPath: string): Promise<ModelRef[]>;
645
- /**
646
- * Apply a manifest to the current environment's graph.
647
- *
648
- * Translates each manifest operation into GraphQL mutations and executes them
649
- * in order. This is the core mechanism for creating classes, fields, and
650
- * relationships from a declarative manifest.
651
- *
652
- * @param manifest - The manifest content to apply
653
- * @returns Summary of applied operations
654
- *
655
- * @example
656
- * ```typescript
657
- * await environment.applyManifest({
658
- * schemaVersion: 2,
659
- * name: 'my-app',
660
- * volumes: [{
661
- * name: 'schema',
662
- * scope: 'sandbox',
663
- * operations: [
664
- * { create: 'author', extends: 'class', has: { name: { type: 'string' } } },
665
- * { create: 'book', extends: 'class', has: { title: { type: 'string' } } },
666
- * { defineRelationship: {
667
- * left: 'author', right: 'book',
668
- * leftSubmodel: 'books', rightSubmodel: 'author',
669
- * leftIsMany: true, rightIsMany: false,
670
- * }},
671
- * ],
672
- * }],
673
- * });
674
- * ```
675
- */
676
- applyManifest(manifest: ManifestContent): Promise<{
677
- applied: number;
678
- errors: string[];
679
- }>;
680
- /**
681
- * Resolve an alias reference like "@std/class" → "class"
682
- * Strips the alias prefix, returning the bare model path.
683
- */
684
- private _resolveAlias;
685
- private _runGraphql;
686
- private _applyFieldMetamodels;
687
- private _applyModelMetamodels;
688
- private _ensureWorkspaceToolsRoot;
689
- private _storeEffectSchemas;
690
- private _applyEffectMetamodels;
691
- private _ensureWorkspaceStreamsRoot;
692
- private _applyEventStreamDeclaration;
693
- private _applyEffectDeclaration;
694
- /**
695
- * Apply a single manifest operation via GraphQL
696
- */
697
- private _applyOperation;
698
- /**
699
- * Apply field definitions (has) to a model via GraphQL
700
- */
701
- private _applyFields;
702
- /**
703
- * Create or update an instance of a class in the graph.
704
- *
705
- * Uses `instantiate` under the hood, which has find-or-create semantics:
706
- * if an instance with the given `id` already exists for the class it is
707
- * returned; otherwise a new instance is created. Fields are then set
708
- * (overwriting previous values) and relationships are attached.
709
- *
710
- * The graph path is derived as `{className}_{id}` to ensure uniqueness
711
- * across classes (two objects of different classes may share the same
712
- * real-world ID). Relationship targets are also resolved automatically
713
- * using the foreign class from the relationship definition.
714
- *
715
- * @param options - The object specification
716
- * @returns The graph path, real-world ID, and creation status
717
- *
718
- * @example
719
- * ```typescript
720
- * // Create an author with fields
721
- * const result = await env.recordObject({
722
- * className: 'author',
723
- * id: 'tolkien',
724
- * label: 'J.R.R. Tolkien',
725
- * fields: { name: 'J.R.R. Tolkien', birth_year: 1892 },
726
- * relationships: { books: ['lotr', 'silmarillion'] },
727
- * });
728
- * // result.path → 'author_tolkien' (internal graph path)
729
- * // result.id → 'tolkien' (real-world ID)
730
- * // result.created → true
731
- * ```
732
- */
733
- recordObject(options: RecordObjectOptions): Promise<RecordObjectResult>;
734
- /**
735
- * Batch version of `recordObject()`.
736
- *
737
- * Sends rows through the control-plane **`/records/batch`** endpoint in **chunks** (default
738
- * **100** records per HTTP request) so individual requests stay bounded and gateway timeouts are
739
- * unlikely. Each chunk is retried on transient network / worker errors.
740
- *
741
- * Use the optional second argument to:
742
- * - **`batchSize`** — rows per POST (smaller = more progress events; larger = fewer round trips).
743
- * - **`concurrency`** — run up to N chunk POSTs in parallel (capped at 16) when you want lower wall time.
744
- * - **`onChunkComplete`** — hook for UIs after each chunk succeeds (row order in the returned array
745
- * always matches `records`; chunk **completion** order may differ when `concurrency > 1`).
746
- *
747
- * For **asynchronous** ingestion with worker-side batching and aggregate counters (`queued`,
748
- * `completed`, …), use **`enqueueRecordImport`** and poll **`getRecordImport`** /
749
- * **`getRecordImportSummary`** — best for very large fire-and-forget loads when immediate
750
- * synchronous commit of every row is not required.
751
- */
752
- recordObjects(records: RecordObjectOptions[], options?: RecordObjectsOptions): Promise<RecordObjectResult[]>;
753
- private executeRecordObjectsChunk;
754
- /**
755
- * Queue a background record import for this environment (async worker pipeline).
756
- *
757
- * **vs `recordObjects`:** this path accepts the full payload in one request, returns an
758
- * **`importId`**, and processes rows in the background — use **`getRecordImport`** /
759
- * **`getRecordImportSummary`** for progress. Choose it for large bulk loads where you do not
760
- * need every row committed before the HTTP call returns. Use **`recordObjects`** when you need
761
- * synchronous upserts and fine-grained chunk progress via **`onChunkComplete`**.
762
- */
763
- enqueueRecordImport(records: RecordObjectOptions[], options?: RecordImportOptions): Promise<RecordImport>;
764
- /**
765
- * List queued or completed record imports for this environment.
766
- */
767
- listRecordImports(status?: RecordImportStatus): Promise<RecordImport[]>;
768
- /**
769
- * Fetch the latest aggregate import counters for this environment.
770
- */
771
- getRecordImportSummary(): Promise<EnvironmentRecordImportSummary>;
772
- /**
773
- * Convenience helper returning queued + processing records for this environment.
774
- */
775
- getAwaitingRecordCount(): Promise<number>;
776
- /**
777
- * Fetch a single record import by id.
778
- */
779
- getRecordImport(importId: string): Promise<RecordImport>;
780
- /**
781
- * List the individual records persisted for one asynchronous import. This
782
- * makes terminal import failures diagnosable without database access.
783
- */
784
- listRecordImportItems(importId: string, status?: RecordImportItem["status"]): Promise<RecordImportItem[]>;
785
- /**
786
- * Cancel a queued/background record import.
787
- */
788
- cancelRecordImport(importId: string): Promise<RecordImport>;
789
- }
790
- /**
791
- * Live runtime session attached to one opened environment.
792
- *
793
- * This is the object returned by `environment.sessions.create()` and friends.
794
- * It owns websocket state, prompts, job execution, and the synced Automerge
795
- * document while delegating environment-level data APIs back to
796
- * `session.environment`.
797
- */
798
- declare class EnvironmentSession extends Session {
799
- readonly environment: Environment;
800
- private readonly sessionDataRoutePrefix;
801
- private readonly sessionDataHeaders;
802
- private readonly beforeMutationSend?;
803
- private heartbeatTimer;
804
- private heartbeatProbeInFlight;
805
- /** The last known graph container status, updated by checkReadiness(). */
806
- graphContainerStatus: {
807
- lastKeepAliveAt: number;
808
- status: "warming" | "hot" | "unknown";
809
- } | null;
810
- constructor(client: WSClient, environment: Environment, clientId: string, options?: {
811
- sessionDataRoutePrefix?: string;
812
- /**
813
- * Browser-only request metadata forwarded with session-data mutations.
814
- * This lets a session direct a frontend effect to the exact Dock client
815
- * that initiated a user action when multiple tabs are connected.
816
- */
817
- sessionDataHeaders?: SessionDataHeaders;
818
- /** Browser-only readiness guard checked immediately before each write. */
819
- beforeMutationSend?: () => void;
820
- initialQuota?: GranularQuotaProgress | null;
821
- });
822
- /**
823
- * Keep the browser session transport observable from the client side.
824
- * SessionDO already broadcasts a heartbeat every five seconds. Treat that
825
- * and all other inbound frames as proof of life instead of issuing an RPC:
826
- * an application RPC may be delayed by Durable Object work even while the
827
- * underlying WebSocket is healthy.
828
- */
829
- private startHeartbeat;
830
- private stopHeartbeat;
831
- hello(): Promise<{
832
- ok: boolean;
833
- environmentId?: string;
834
- docId?: string;
835
- features?: {
836
- serverHeartbeat?: boolean;
837
- hibernatingWebSocket?: boolean;
838
- };
839
- graphContainerStatus?: {
840
- lastKeepAliveAt: number;
841
- status: "warming" | "hot" | "unknown";
842
- };
843
- }>;
844
- get environmentId(): string;
845
- get sandboxId(): string;
846
- get ontologyId(): string;
847
- get subjectId(): string;
848
- get envName(): string;
849
- get tag(): string | null;
850
- get versionId(): string;
851
- get granularId(): string;
852
- get permissionProfileId(): string;
853
- get apiEndpoint(): string;
854
- get data(): {
855
- record: (record: RecordObjectOptions) => Promise<RecordObjectResult>;
856
- recordMany: (records: RecordObjectOptions[], options?: RecordObjectsOptions) => Promise<RecordObjectResult[]>;
857
- import: (records: RecordObjectOptions[], options?: {
858
- batchSize?: number;
859
- } | undefined) => Promise<RecordImport>;
860
- listImports: (status?: RecordImportStatus) => Promise<RecordImport[]>;
861
- getImport: (importId: string) => Promise<RecordImport>;
862
- listImportItems: (importId: string, status?: RecordImportItem["status"]) => Promise<RecordImportItem[]>;
863
- getImportSummary: () => Promise<EnvironmentRecordImportSummary>;
864
- cancelImport: (importId: string) => Promise<RecordImport>;
865
- getAwaitingCount: () => Promise<number>;
866
- };
867
- get feedback(): {
868
- list: () => Promise<EnvironmentFeedbackRecord[]>;
869
- };
870
- /**
871
- * Return a plain JS copy of the synced session heap.
872
- */
873
- getHeap(): SessionHeapSnapshot;
874
- private buildSessionDataUrl;
875
- private sessionDataFetch;
876
- private sessionDataRequest;
877
- /**
878
- * Fetch the live session document from the runtime DO.
879
- *
880
- * For presentation history use `feed.list()` or `transcript.list()`.
881
- * Timeline and job collections are diagnostic/execution data only.
882
- */
883
- getDocument(): Promise<SessionDocumentResult>;
884
- /**
885
- * Publish one terminal assistant reply from a trusted server integration.
886
- *
887
- * This uses the API-key-authenticated HTTP session boundary. Delegated
888
- * browser sessions cannot use it and never receive assistant feed-authoring
889
- * capability through their WebSocket.
890
- */
891
- publishAssistantReply(input: AssistantReplyPublicationInput): Promise<AssistantReplyPublicationResult>;
892
- get timeline(): {
893
- list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionTimelineEvent>>;
894
- };
895
- get jobs(): {
896
- list: (options?: SessionJobListOptions) => Promise<SessionCollectionListResult<SessionJobRecord>>;
897
- get: (jobId: string) => Promise<SessionJobRecord>;
898
- latest: (options?: Pick<SessionJobListOptions, "status">) => Promise<SessionJobRecord | null>;
899
- };
900
- get mutations(): {
901
- list: (options?: {
902
- limit?: number;
903
- compact?: boolean;
904
- }) => Promise<{
905
- items: SessionMutationView[];
906
- }>;
907
- };
908
- get artifacts(): {
909
- list: (options?: SessionArtifactListOptions) => Promise<{
910
- items: SessionArtifactRecord[];
911
- nextCursor: string | null;
912
- totalCount: number;
913
- }>;
914
- listForLatestJob: (options?: Omit<SessionArtifactListOptions, "jobId" | "latestJob">) => Promise<{
915
- items: SessionArtifactRecord[];
916
- nextCursor: string | null;
917
- totalCount: number;
918
- }>;
919
- get: (artifactId: string) => Promise<SessionArtifactRecord>;
920
- create: (artifact: Partial<SessionArtifactRecord> & {
921
- label: string;
922
- }) => Promise<SessionArtifactRecord>;
923
- acceptSuggestion: (sequence: number) => Promise<SessionArtifactRecord>;
924
- updateInputs: (artifactId: string, patch: {
925
- inputValues?: Record<string, unknown>;
926
- relationships?: Record<string, string | string[] | null>;
927
- /** Field paths whose current assistant value the user kept. */
928
- confirmFields?: string[];
929
- relationshipLabels?: Record<string, Record<string, string>>;
930
- expectedUpdatedAt?: number;
931
- }) => Promise<SessionArtifactRecord>;
932
- relationshipOptions: (artifactId: string, input: SessionArtifactRelationshipOptionsInput) => Promise<SessionArtifactRelationshipOptionsResult>;
933
- relationshipCreate: (artifactId: string, input: SessionArtifactRelationshipCreateInput) => Promise<SessionArtifactRecord>;
934
- validate: (artifactId: string) => Promise<SessionArtifactValidationResult>;
935
- execute: (artifactId: string, options: SessionArtifactExecutionOptions) => Promise<SessionArtifactExecutionResult>;
936
- approve: (artifactId: string, options: SessionArtifactApprovalOptions) => Promise<SessionArtifactExecutionResult>;
937
- cancel: (artifactId: string) => Promise<SessionArtifactRecord>;
938
- };
939
- get manualActions(): {
940
- record: (input: RecordManualActionInput) => Promise<ManualActionRecordResult>;
941
- list: (options?: ManualActionListOptions) => Promise<SessionCollectionListResult<ManualActionOccurrence>>;
942
- suggest: (options?: ManualActionSuggestionOptions) => Promise<{
943
- items: ManualActionSuggestion[];
944
- }>;
945
- };
946
- get artifactApprovals(): {
947
- list: (options?: ArtifactApprovalTaskListOptions) => Promise<SessionCollectionListResult<ArtifactApprovalTask>>;
948
- decide: (approvalTaskId: string, input: ArtifactApprovalDecisionInput) => Promise<ArtifactApprovalDecisionResult>;
949
- };
950
- get files(): {
951
- list: (options?: SessionCollectionListOptions & {
952
- status?: string | null;
953
- source?: string | null;
954
- }) => Promise<SessionCollectionListResult<SessionFileRecord>>;
955
- get: (fileId: string) => Promise<SessionFileRecord>;
956
- upload: (body: SessionFileUploadBody, options?: SessionFileUploadOptions) => Promise<SessionFileRecord>;
957
- download: (fileId: string) => Promise<ArrayBuffer>;
958
- delete: (fileId: string) => Promise<{
959
- deleted: boolean;
960
- fileId: string;
961
- }>;
962
- };
963
- get heap(): {
964
- entries: {
965
- list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionHeapEntry>>;
966
- get: (path: string) => Promise<SessionHeapEntry>;
967
- };
968
- lists: {
969
- list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionHeapList>>;
970
- get: (name: string) => Promise<SessionHeapList>;
971
- };
972
- variables: {
973
- list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionHeapVariable>>;
974
- get: (name: string) => Promise<SessionHeapVariable>;
975
- delete: (name: string) => Promise<{
976
- deleted: boolean;
977
- name: string;
978
- }>;
979
- };
980
- };
981
- get transcript(): {
982
- list: (options?: SessionCollectionListOptions) => Promise<SessionCollectionListResult<SessionTranscriptEntry>>;
983
- };
984
- graphql<T = any>(query: string, variables?: Record<string, any>): Promise<GraphQLResult<T>>;
985
- searchRecords(query: string, options?: RecordSearchOptions): Promise<RecordSearchResult[]>;
986
- mentionRecord(input: RecordMentionInput): Promise<SessionHeapEntry>;
987
- defineRelationship(options: DefineRelationshipOptions): Promise<RelationshipInfo>;
988
- getRelationships(modelPath: string): Promise<RelationshipInfo[]>;
989
- attach(modelPath: string, submodelPath: string, targetPath: string): Promise<void>;
990
- detach(modelPath: string, submodelPath: string, targetPath?: string): Promise<void>;
991
- listRelated(modelPath: string, submodelPath: string): Promise<ModelRef[]>;
992
- applyManifest(manifest: ManifestContent): Promise<{
993
- applied: number;
994
- errors: string[];
995
- }>;
996
- recordObject(options: RecordObjectOptions): Promise<RecordObjectResult>;
997
- recordState(input: EnvironmentStateUpdateInput): Promise<RecordObjectResult>;
998
- state(target: EnvironmentStateTarget): EnvironmentStateProxy;
999
- recordObjects(records: RecordObjectOptions[], options?: RecordObjectsOptions): Promise<RecordObjectResult[]>;
1000
- enqueueRecordImport(records: RecordObjectOptions[], options?: RecordImportOptions): Promise<RecordImport>;
1001
- listRecordImports(status?: RecordImportStatus): Promise<RecordImport[]>;
1002
- getRecordImportSummary(): Promise<EnvironmentRecordImportSummary>;
1003
- getAwaitingRecordCount(): Promise<number>;
1004
- getRecordImport(importId: string): Promise<RecordImport>;
1005
- cancelRecordImport(importId: string): Promise<RecordImport>;
1006
- listFeedback(): Promise<EnvironmentFeedbackRecord[]>;
1007
- /**
1008
- * Close the session and disconnect from the sandbox.
1009
- *
1010
- * Sends `client.goodbye` over WebSocket first, then issues an HTTP fallback
1011
- * to the runtime goodbye endpoint if no definitive WS-side runtime notify
1012
- * acknowledgement was observed.
1013
- */
1014
- disconnect(): Promise<void>;
1015
- /**
1016
- * Close only the socket transport without sending `client.goodbye`.
1017
- */
1018
- disconnectTransport(): void;
1019
- /**
1020
- * Backwards-compatible alias for `disconnect()`.
1021
- */
1022
- close(): Promise<void>;
1023
- /**
1024
- * Check if the graph container is ready and warm.
1025
- */
1026
- checkReadiness(): Promise<{
1027
- lastKeepAliveAt: number;
1028
- status: "warming" | "hot" | "unknown";
1029
- }>;
1030
- }
1031
- declare class OntologyHandle {
1032
- private granular;
1033
- private ontologyNameOrId;
1034
- constructor(granular: Granular, ontologyNameOrId: string);
1035
- get effects(): {
1036
- register: (effect: ToolWithHandler) => Promise<void>;
1037
- registerMany: (effects: ToolWithHandler[]) => Promise<void>;
1038
- unregister: (name: string) => Promise<void>;
1039
- clear: () => Promise<void>;
1040
- disconnect: () => Promise<void>;
1041
- };
1042
- get importer(): {
1043
- onEnvironmentCreate: (handler: EnvironmentImporterHandler) => void;
1044
- clear: () => void;
1045
- };
1046
- }
1047
- declare class Granular {
1048
- private apiKey;
1049
- private apiUrl;
1050
- private httpUrl;
1051
- private tokenProvider?;
1052
- private WebSocketCtor?;
1053
- private onUnexpectedClose?;
1054
- private onReconnectError?;
1055
- private effectHostUrl?;
1056
- private graphqlIdempotencyKey?;
1057
- private debugHttp;
1058
- /** Sandbox-level effect registry: sandboxId → (effectKey@selector → ToolWithHandler) */
1059
- private sandboxEffects;
1060
- /** Live sandbox-scoped effect hosts keyed by sandboxId */
1061
- private sandboxEffectHosts;
1062
- /** In-flight host connection promises to avoid duplicate concurrent connects */
1063
- private sandboxEffectHostPromises;
1064
- /** Ontology-bound environment importer hooks keyed by the caller's ontology identifier. */
1065
- private ontologyImporters;
1066
- /** Resolved importer hooks keyed by sandboxId for fast lookups during openEnvironment(). */
1067
- private sandboxImporters;
1068
- /**
1069
- * Create a new Granular client
1070
- * @param options - Client configuration
1071
- */
1072
- constructor(options: GranularOptions);
1073
- /**
1074
- * Return an ontology-scoped handle for effects and other ontology-level APIs.
1075
- */
1076
- ontology(ontologyNameOrId: string): OntologyHandle;
1077
- registerEnvironmentImporter(ontologyNameOrId: string, handler: EnvironmentImporterHandler): void;
1078
- clearEnvironmentImporter(ontologyNameOrId: string): void;
1079
- /**
1080
- * Records/upserts a user and prepares them for sandbox connections
1081
- *
1082
- * @param options - User options
1083
- * @returns The recorded user with both `userId` and `granularId`
1084
- *
1085
- * @example
1086
- * ```typescript
1087
- * const user = await granular.recordUser({
1088
- * userId: 'user_123',
1089
- * name: 'John Doe',
1090
- * permissions: ['agent'],
1091
- * });
1092
- * ```
1093
- */
1094
- recordUser(options: RecordUserOptions): Promise<User>;
1095
- /**
1096
- * Alias for `recordUser()` with user-facing naming that matches upsert semantics.
1097
- */
1098
- upsertUser(options: RecordUserOptions): Promise<User>;
1099
- private resolveConnectUser;
1100
- /**
1101
- * Open or resolve an ontology environment for one user without opening a session.
1102
- *
1103
- * @example
1104
- * ```typescript
1105
- * const environment = await granular.openEnvironment({
1106
- * ontology: 'my-ontology',
1107
- * tag: 'dev',
1108
- * userId: 'user_123',
1109
- * permissions: ['agent'],
1110
- * });
1111
- *
1112
- * await environment.data.record({
1113
- * className: 'customer',
1114
- * id: 'acme',
1115
- * fields: { name: 'Acme' },
1116
- * });
1117
- *
1118
- * const session = await environment.sessions.create();
1119
- * const job = await session.submitJob(`return "hello";`);
1120
- * console.log(await job.result);
1121
- * ```
1122
- */
1123
- openEnvironment(options: OpenEnvironmentOptions): Promise<Environment>;
1124
- /**
1125
- * Read the active environment selected by Granular for an already-recorded
1126
- * external user. This is intentionally read-only: browser/login code must
1127
- * not create subjects or environments as a side effect.
1128
- */
1129
- getActiveEnvironmentForUser(options: {
1130
- sandboxId: string;
1131
- tag: string;
1132
- userId: string;
1133
- slot?: string;
1134
- }): Promise<Environment | null>;
1135
- /**
1136
- * Resolve one exact environment only when Granular confirms that it belongs
1137
- * to the given external user in the requested sandbox (and, optionally,
1138
- * tag). This is deliberately read-only: callers use it to keep an already
1139
- * opened delegated workspace stable while a newer active environment is
1140
- * being prepared in the background.
1141
- */
1142
- getEnvironmentForUser(options: {
1143
- sandboxId: string;
1144
- userId: string;
1145
- environmentId: string;
1146
- tag?: string;
1147
- }): Promise<Environment | null>;
1148
- /**
1149
- * Register one reviewed, pre-existing environment as the active workspace
1150
- * for an external user. This is for a controlled migration only: it does
1151
- * not create an environment and it does not run an importer.
1152
- */
1153
- adoptEnvironmentForUser(options: AdoptEnvironmentOptions): Promise<Environment>;
1154
- /**
1155
- * Deprecated compatibility alias for `openEnvironment()`.
1156
- *
1157
- * `connect()` no longer opens a runtime session automatically.
1158
- */
1159
- connect(options: ConnectOptions): Promise<Environment>;
1160
- /**
1161
- * Run a registered environment importer against an environment that was
1162
- * opened outside this SDK instance, for example by a delegated browser flow.
1163
- *
1164
- * This uses the same setup-run and queued record-import plumbing as
1165
- * `openEnvironment()`: importer stages, expected object counts, and queued
1166
- * import counters remain visible through `environment.setup` and
1167
- * `getRecordImportSummary()`.
1168
- */
1169
- runEnvironmentImporterForEnvironment(environmentId: string, options?: RunEnvironmentImporterOptions): Promise<EnvironmentSetupSummary | null>;
1170
- private resolveRequestedTag;
1171
- private buildManagedEnvironmentName;
1172
- private isManagedEnvironmentName;
1173
- private sortEnvironmentsByRecency;
1174
- private resolveOpenEnvironmentData;
1175
- /**
1176
- * List indexed sessions using ownership filters and bounded pagination.
1177
- */
1178
- listSessions(options: ConversationSessionListOptions): Promise<ConversationSessionInfo[]>;
1179
- listSessionsPage(options: ConversationSessionListOptions): Promise<ConversationSessionListResponse>;
1180
- /**
1181
- * List active (open) sessions for an environment.
1182
- */
1183
- listOpenSessions(filters: Omit<ConversationSessionListOptions, "status"> & {
1184
- environmentId: string;
1185
- }): Promise<ConversationSessionInfo[]>;
1186
- /**
1187
- * List closed sessions for an environment (conversations that have disconnected).
1188
- */
1189
- listClosedSessions(filters: Omit<ConversationSessionListOptions, "status"> & {
1190
- environmentId: string;
1191
- }): Promise<ConversationSessionInfo[]>;
1192
- getUserEnvironmentState(options: UserEnvironmentStateOptions & {
1193
- environmentId: string;
1194
- }): Promise<UserEnvironmentState>;
1195
- markUserEnvironmentSessionsRead(options: MarkUserEnvironmentReadOptions & {
1196
- environmentId: string;
1197
- }): Promise<UserEnvironmentState["readThroughSequenceBySessionId"]>;
1198
- private normalizeConversationSession;
1199
- private normalizeUserEnvironmentState;
1200
- private static coerceIsoDate;
1201
- /**
1202
- * Create a new session (conversation) for an existing environment and connect to it.
1203
- * The runtime graph is shared across all sessions for the same environment.
1204
- */
1205
- createSession(options: {
1206
- environmentId: string;
1207
- clientId?: string;
1208
- sessionScope?: CreateSessionOptions["sessionScope"];
1209
- initialHeap?: CreateSessionOptions["initialHeap"];
1210
- }): Promise<EnvironmentSession>;
1211
- /**
1212
- * Connect to an existing open session (same conversation thread) using a freshly minted WebSocket token.
1213
- */
1214
- connectSession(options: {
1215
- sessionId: string;
1216
- clientId?: string;
1217
- maxReconnectAttempts?: number;
1218
- reconnectDelayMs?: number;
1219
- }): Promise<EnvironmentSession>;
1220
- recordOpenAIUsageSpend(usage: OpenAIUsageSpendEvent, context?: GranularSpendContext | null, options?: {
1221
- metadata?: Record<string, unknown> | null;
1222
- }): Promise<RecordOpenAIUsageSpendResult>;
1223
- /** End a session through the runtime, or disconnect its connected handle. */
1224
- closeSession(sessionId: string, environment?: EnvironmentSession | null): Promise<void>;
1225
- /**
1226
- * Re-open a closed session in the index and connect to its existing runtime document.
1227
- */
1228
- reopenSession(sessionId: string, options?: {
1229
- clientId?: string;
1230
- }): Promise<EnvironmentSession>;
1231
- private resolveEnvironmentImporter;
1232
- private maybeRunEnvironmentImporter;
1233
- private runEnvironmentImporter;
1234
- private bindEnvironmentHandle;
1235
- private bindWebSocketEnvironmentSession;
1236
- private activateEnvironment;
1237
- private getSandboxEffectMap;
1238
- private serializeEffect;
1239
- private publishSandboxEffectCatalog;
1240
- private syncSandboxEffectCatalog;
1241
- private recoverEffectHost;
1242
- private startEffectHostHeartbeat;
1243
- private stopEffectHostHeartbeat;
1244
- private synchronizeEffectHost;
1245
- private ensureSandboxEffectHost;
1246
- private disconnectSandboxEffectHost;
1247
- /**
1248
- * Register an effect (tool) for a specific sandbox.
1249
- *
1250
- * @param sandboxNameOrId - The name or ID of the sandbox
1251
- * @param effect - The tool definition and handler
1252
- */
1253
- registerEffect(sandboxNameOrId: string, effect: ToolWithHandler): Promise<void>;
1254
- /**
1255
- * Register multiple effects (tools) for a specific sandbox.
1256
- *
1257
- * batch version of `registerEffect`.
1258
- */
1259
- registerEffects(sandboxNameOrId: string, effects: ToolWithHandler[]): Promise<void>;
1260
- /**
1261
- * Unregister an effect from a sandbox.
1262
- *
1263
- * Removes it from the local sandbox registry and updates the
1264
- * sandbox-scoped live catalog.
1265
- */
1266
- unregisterEffect(sandboxNameOrId: string, name: string): Promise<void>;
1267
- /**
1268
- * Disconnect one sandbox-scoped effect host, or all of them when no sandbox is provided.
1269
- *
1270
- * This is primarily useful for long-lived helper processes such as generated
1271
- * `granular-effects.ts` scripts that need to shut down cleanly on SIGINT/SIGTERM.
1272
- */
1273
- disconnectEffects(sandboxNameOrId?: string): Promise<void>;
1274
- /**
1275
- * Unregister all effects for a sandbox.
1276
- */
1277
- unregisterAllEffects(sandboxNameOrId: string): Promise<void>;
1278
- /**
1279
- * Find a sandbox by name or create it if it doesn't exist
1280
- */
1281
- private findOrCreateSandbox;
1282
- /**
1283
- * Resolve an existing permission profile by exact name or ID.
1284
- *
1285
- * `allow-all` is the sole compatibility profile that the SDK may provision
1286
- * automatically. Every other missing reference fails closed so a typo or
1287
- * untrusted role value cannot become an allow-default profile.
1288
- */
1289
- private ensurePermissionProfile;
1290
- /**
1291
- * Ensure an assignment exists for a subject in a sandbox with a permission profile
1292
- */
1293
- private ensureAssignment;
1294
- /**
1295
- * Sandbox management API
1296
- */
1297
- get sandboxes(): {
1298
- list: () => Promise<SandboxListResponse>;
1299
- get: (id: string) => Promise<Sandbox>;
1300
- create: (data: CreateSandboxData) => Promise<Sandbox>;
1301
- update: (id: string, data: Partial<CreateSandboxData>) => Promise<Sandbox>;
1302
- delete: (id: string) => Promise<DeleteResponse>;
1303
- };
1304
- /**
1305
- * Permission Profile management for sandboxes
1306
- */
1307
- get permissionProfiles(): {
1308
- list: (sandboxId: string) => Promise<PermissionProfile[]>;
1309
- get: (sandboxId: string, profileId: string) => Promise<PermissionProfile>;
1310
- create: (sandboxId: string, data: CreatePermissionProfileData) => Promise<PermissionProfile>;
1311
- delete: (_sandboxId: string, _profileId: string) => Promise<DeleteResponse>;
1312
- };
1313
- /**
1314
- * Environment management
1315
- */
1316
- get environments(): {
1317
- list: (sandboxId: string) => Promise<EnvironmentData[]>;
1318
- get: (environmentId: string) => Promise<EnvironmentData>;
1319
- create: (sandboxId: string, data: CreateEnvironmentData) => Promise<EnvironmentData>;
1320
- delete: (environmentId: string) => Promise<DeleteResponse>;
1321
- };
1322
- /**
1323
- * Event stream operations: query, subscribe, and acknowledge stream events
1324
- */
1325
- get streams(): {
1326
- getEvents: (params: {
1327
- ontology: string;
1328
- stream: string;
1329
- environment?: string;
1330
- session?: string;
1331
- eventTypes?: string[];
1332
- since?: Date;
1333
- until?: Date;
1334
- isAcked?: boolean;
1335
- limit?: number;
1336
- offset?: number;
1337
- }) => Promise<StreamEvent[]>;
1338
- subscribe: (params: {
1339
- ontology: string;
1340
- stream: string;
1341
- environment?: string;
1342
- session?: string;
1343
- eventTypes?: string[];
1344
- since?: Date;
1345
- onEvent: (event: StreamEvent) => void;
1346
- onError?: (err: Error) => void;
1347
- pollIntervalMs?: number;
1348
- }) => StreamSubscription;
1349
- ack: (eventId: string) => Promise<void>;
1350
- ackBatch: (eventIds: string[]) => Promise<void>;
1351
- getStats: (params: {
1352
- ontology: string;
1353
- environment?: string;
1354
- }) => Promise<StreamStats[]>;
1355
- };
1356
- /**
1357
- * Subject management
1358
- */
1359
- get subjects(): {
1360
- get: (subjectId: string) => Promise<Subject>;
1361
- listAssignments: (subjectId: string) => Promise<AssignmentListResponse>;
1362
- };
1363
- /**
1364
- * @deprecated Use recordUser() instead
1365
- */
1366
- get users(): {
1367
- create: (data: {
1368
- id: string;
1369
- name?: string;
1370
- email?: string;
1371
- }) => Promise<Subject>;
1372
- get: (id: string) => Promise<Subject>;
1373
- };
1374
- private _resolveSandboxId;
1375
- /**
1376
- * Make an authenticated API request
1377
- */
1378
- private request;
1379
- }
1380
-
1381
- export { Environment as E, Granular as G, OntologyHandle as O, Session as S, WSClient as W, EnvironmentSession as a, isGraphQLMutationDocument as i };