@granular-software/sdk 0.4.4 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -8
- package/dist/cli/index.js +47 -12
- package/dist/index.d.mts +63 -2
- package/dist/index.d.ts +63 -2
- package/dist/index.js +66 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +66 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ The official TypeScript SDK for Granular.
|
|
|
8
8
|
|
|
9
9
|
- 🏗️ **Domain Ontology** — Define classes, properties, and relationships as a typed graph
|
|
10
10
|
- 🔧 **Class-Based Tools** — Attach instance methods, static methods, and global tools with typed I/O
|
|
11
|
-
- 🤖 **Domain Synthesis** — Auto-generated TypeScript classes with `
|
|
11
|
+
- 🤖 **Domain Synthesis** — Auto-generated TypeScript classes with `get({ path })`, `list()`, relationship accessors, and typed methods
|
|
12
12
|
- 🔒 **Secure Execution** — Run AI-generated code in isolated sandboxes
|
|
13
13
|
- 👥 **User Permissions** — Control what each user can access
|
|
14
14
|
- ⚡ **Real-time** — WebSocket-based streaming and events
|
|
@@ -33,7 +33,7 @@ Inside this monorepo, prefer the workspace package instead of installing from np
|
|
|
33
33
|
By default, the SDK resolves endpoints like this:
|
|
34
34
|
|
|
35
35
|
- Local mode (`NODE_ENV=development`): `ws://localhost:8787/granular`
|
|
36
|
-
- Production mode (default): `wss://api.
|
|
36
|
+
- Production mode (default): `wss://cf-api-gateway.arthur6084.workers.dev/granular`
|
|
37
37
|
|
|
38
38
|
Overrides:
|
|
39
39
|
|
|
@@ -147,8 +147,10 @@ await granular.registerEffects(env.sandboxId, [
|
|
|
147
147
|
const job = await env.submitJob(`
|
|
148
148
|
import { Customer } from './sandbox-tools';
|
|
149
149
|
|
|
150
|
-
//
|
|
151
|
-
const
|
|
150
|
+
// list() discovers instances; get({ path }) hydrates a specific graph object
|
|
151
|
+
const customers = await Customer.list();
|
|
152
|
+
const acme = customers.find((customer) => customer.name === 'Acme Corp');
|
|
153
|
+
if (!acme) throw new Error('Customer not found');
|
|
152
154
|
console.log(acme.name); // "Acme Corp"
|
|
153
155
|
console.log(acme.email); // "billing@acme.com"
|
|
154
156
|
|
|
@@ -340,8 +342,11 @@ export declare class Author {
|
|
|
340
342
|
|
|
341
343
|
constructor(id: string, fields?: Record<string, any>);
|
|
342
344
|
|
|
343
|
-
/**
|
|
344
|
-
static
|
|
345
|
+
/** Get a cached Author by graph path, hydrating from the graph when needed */
|
|
346
|
+
static get(query: { path: string; refresh?: boolean }): Promise<Author | null>;
|
|
347
|
+
|
|
348
|
+
/** List known Author instances */
|
|
349
|
+
static list(query?: { limit?: number; saveAs?: string; refresh?: boolean }): Promise<Author[]>;
|
|
345
350
|
|
|
346
351
|
/** Get biography of an author */
|
|
347
352
|
get_bio(input?: { detailed?: boolean }): Promise<{ bio: string; source?: string }>;
|
|
@@ -359,7 +364,9 @@ export declare class Book {
|
|
|
359
364
|
readonly isbn: string;
|
|
360
365
|
readonly published_year: number;
|
|
361
366
|
|
|
362
|
-
static
|
|
367
|
+
static get(query: { path: string; refresh?: boolean }): Promise<Book | null>;
|
|
368
|
+
|
|
369
|
+
static list(query?: { limit?: number; saveAs?: string; refresh?: boolean }): Promise<Book[]>;
|
|
363
370
|
|
|
364
371
|
/** Navigate to author (many_to_one) */
|
|
365
372
|
get_author(): Promise<Author | null>;
|
|
@@ -374,7 +381,9 @@ The LLM or user writes code against these typed classes:
|
|
|
374
381
|
```typescript
|
|
375
382
|
import { Author, Book, global_search } from './sandbox-tools';
|
|
376
383
|
|
|
377
|
-
const
|
|
384
|
+
const authors = await Author.list();
|
|
385
|
+
const tolkien = authors.find((author) => author.name === 'J.R.R. Tolkien');
|
|
386
|
+
if (!tolkien) throw new Error('Author not found');
|
|
378
387
|
console.log(tolkien.name); // "J.R.R. Tolkien"
|
|
379
388
|
|
|
380
389
|
const bio = await tolkien.get_bio({ detailed: true });
|
package/dist/cli/index.js
CHANGED
|
@@ -5387,7 +5387,7 @@ var import_dotenv = __toESM(require_main());
|
|
|
5387
5387
|
|
|
5388
5388
|
// src/endpoints.ts
|
|
5389
5389
|
var LOCAL_API_URL = "ws://localhost:8787/granular";
|
|
5390
|
-
var PRODUCTION_API_URL = "wss://api.
|
|
5390
|
+
var PRODUCTION_API_URL = "wss://cf-api-gateway.arthur6084.workers.dev/granular";
|
|
5391
5391
|
var LOCAL_AUTH_URL = "http://localhost:3000";
|
|
5392
5392
|
var PRODUCTION_AUTH_URL = "https://app.granular.software";
|
|
5393
5393
|
function readEnv(name) {
|
|
@@ -5775,6 +5775,9 @@ var ApiClient = class {
|
|
|
5775
5775
|
return false;
|
|
5776
5776
|
}
|
|
5777
5777
|
}
|
|
5778
|
+
async validateKeyOrThrow() {
|
|
5779
|
+
await this.request("/control/sandboxes");
|
|
5780
|
+
}
|
|
5778
5781
|
// ── Sandboxes ──
|
|
5779
5782
|
async listSandboxes() {
|
|
5780
5783
|
const result = await this.request("/control/sandboxes");
|
|
@@ -7768,7 +7771,31 @@ async function main() {
|
|
|
7768
7771
|
await granular.registerEffects(SANDBOX_ID, ${effectsArray});
|
|
7769
7772
|
|
|
7770
7773
|
log('Effects registered. Process kept alive for simulator. Press Ctrl+C to exit.');
|
|
7771
|
-
|
|
7774
|
+
|
|
7775
|
+
const keepAliveTimer = setInterval(() => {
|
|
7776
|
+
// Keep an active event-loop handle so Bun/Node does not exit immediately.
|
|
7777
|
+
}, 60_000);
|
|
7778
|
+
|
|
7779
|
+
await new Promise<void>((resolve) => {
|
|
7780
|
+
let shuttingDown = false;
|
|
7781
|
+
|
|
7782
|
+
const shutdown = async (signal: string) => {
|
|
7783
|
+
if (shuttingDown) return;
|
|
7784
|
+
shuttingDown = true;
|
|
7785
|
+
clearInterval(keepAliveTimer);
|
|
7786
|
+
log(\`Received \${signal}. Shutting down effects host...\`);
|
|
7787
|
+
try {
|
|
7788
|
+
await granular.disconnectEffects(SANDBOX_ID);
|
|
7789
|
+
} catch (error) {
|
|
7790
|
+
console.warn('[Effects] Failed to disconnect live effects cleanly:', error);
|
|
7791
|
+
}
|
|
7792
|
+
resolve();
|
|
7793
|
+
process.exit(0);
|
|
7794
|
+
};
|
|
7795
|
+
|
|
7796
|
+
process.once('SIGINT', () => { void shutdown('SIGINT'); });
|
|
7797
|
+
process.once('SIGTERM', () => { void shutdown('SIGTERM'); });
|
|
7798
|
+
});
|
|
7772
7799
|
}
|
|
7773
7800
|
|
|
7774
7801
|
main().catch((err) => {
|
|
@@ -7847,9 +7874,11 @@ async function initCommand(projectName, options) {
|
|
|
7847
7874
|
const apiUrl = loadApiUrl();
|
|
7848
7875
|
const api = new ApiClient(apiKey, apiUrl);
|
|
7849
7876
|
const validating = spinner("Validating API key...");
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7877
|
+
try {
|
|
7878
|
+
await api.validateKeyOrThrow();
|
|
7879
|
+
} catch (err) {
|
|
7880
|
+
const detail = err?.message ? ` (${err.message})` : "";
|
|
7881
|
+
validating.fail(` API key validation failed${detail}.`);
|
|
7853
7882
|
process.exit(1);
|
|
7854
7883
|
}
|
|
7855
7884
|
validating.succeed(" API key validated.");
|
|
@@ -8015,9 +8044,11 @@ async function loginCommand(options = {}) {
|
|
|
8015
8044
|
}
|
|
8016
8045
|
const spinner2 = spinner("Validating...");
|
|
8017
8046
|
const api = new ApiClient(apiKey, apiUrl);
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
|
|
8047
|
+
try {
|
|
8048
|
+
await api.validateKeyOrThrow();
|
|
8049
|
+
} catch (err) {
|
|
8050
|
+
const detail = err?.message ? ` (${err.message})` : "";
|
|
8051
|
+
spinner2.fail(` API key validation failed${detail}.`);
|
|
8021
8052
|
process.exit(1);
|
|
8022
8053
|
}
|
|
8023
8054
|
saveApiKey(apiKey);
|
|
@@ -8707,12 +8738,16 @@ console.log('Connected to:', env.environmentId);`);
|
|
|
8707
8738
|
if (classes.length > 0) {
|
|
8708
8739
|
const cls = classes[0];
|
|
8709
8740
|
const ClassName = cls.name.charAt(0).toUpperCase() + cls.name.slice(1);
|
|
8710
|
-
lines.push(` // 1.
|
|
8711
|
-
lines.push(` const
|
|
8712
|
-
lines.push(`
|
|
8741
|
+
lines.push(` // 1. List objects`);
|
|
8742
|
+
lines.push(` const items = await ${ClassName}.list({ limit: 10, saveAs: '${cls.name}_items' });`);
|
|
8743
|
+
lines.push(` const item = items[0] ?? null;`);
|
|
8744
|
+
lines.push(` console.log('Loaded:', item?.id);`);
|
|
8713
8745
|
lines.push(``);
|
|
8714
8746
|
lines.push(` // 2. Call instance method`);
|
|
8715
|
-
lines.push(`
|
|
8747
|
+
lines.push(` if (item) {`);
|
|
8748
|
+
lines.push(` const summary = await item.summarize({ maxLength: 100 });`);
|
|
8749
|
+
lines.push(` console.log(summary);`);
|
|
8750
|
+
lines.push(` }`);
|
|
8716
8751
|
lines.push(``);
|
|
8717
8752
|
lines.push(` // 3. Call static method`);
|
|
8718
8753
|
lines.push(` const results = await ${ClassName}.search({ query: 'test' });`);
|
package/dist/index.d.mts
CHANGED
|
@@ -88,6 +88,11 @@ interface ConnectOptions {
|
|
|
88
88
|
/** Optional stable client ID. Defaults to `client_${Date.now()}`. Use a fixed
|
|
89
89
|
* value for long-lived effect hosts so tool catalogs don't accumulate. */
|
|
90
90
|
clientId?: string;
|
|
91
|
+
/** Optional session heap seed. Each item is eagerly hydrated into the session heap on connect. */
|
|
92
|
+
initialHeap?: Array<{
|
|
93
|
+
className: string;
|
|
94
|
+
id: string;
|
|
95
|
+
}>;
|
|
91
96
|
}
|
|
92
97
|
/**
|
|
93
98
|
* A sandbox container
|
|
@@ -454,6 +459,47 @@ interface Prompt {
|
|
|
454
459
|
options?: string[];
|
|
455
460
|
defaultValue?: unknown;
|
|
456
461
|
}
|
|
462
|
+
type SessionHeapFieldType = 'string' | 'number' | 'boolean' | 'null' | 'unknown';
|
|
463
|
+
interface SessionHeapFieldValue {
|
|
464
|
+
name: string;
|
|
465
|
+
type: SessionHeapFieldType;
|
|
466
|
+
value: string | number | boolean | null;
|
|
467
|
+
}
|
|
468
|
+
interface SessionHeapEntry {
|
|
469
|
+
path: string;
|
|
470
|
+
className: string;
|
|
471
|
+
id: string;
|
|
472
|
+
label?: string | null;
|
|
473
|
+
description?: string | null;
|
|
474
|
+
prototypes: string[];
|
|
475
|
+
fields: SessionHeapFieldValue[];
|
|
476
|
+
relatedJobIds: string[];
|
|
477
|
+
source: string;
|
|
478
|
+
createdAt: number;
|
|
479
|
+
updatedAt: number;
|
|
480
|
+
}
|
|
481
|
+
interface SessionHeapList {
|
|
482
|
+
name: string;
|
|
483
|
+
className: string;
|
|
484
|
+
paths: string[];
|
|
485
|
+
relatedJobIds: string[];
|
|
486
|
+
updatedAt: number;
|
|
487
|
+
}
|
|
488
|
+
interface SessionHeapVariable {
|
|
489
|
+
name: string;
|
|
490
|
+
kind: 'entry' | 'list' | 'scalar';
|
|
491
|
+
entryPath?: string;
|
|
492
|
+
listName?: string;
|
|
493
|
+
value?: string | number | boolean | null;
|
|
494
|
+
className?: string;
|
|
495
|
+
updatedAt: number;
|
|
496
|
+
}
|
|
497
|
+
interface SessionHeapSnapshot {
|
|
498
|
+
entriesByPath: Record<string, SessionHeapEntry>;
|
|
499
|
+
listsByName: Record<string, SessionHeapList>;
|
|
500
|
+
variablesByName: Record<string, SessionHeapVariable>;
|
|
501
|
+
updatedAt: number;
|
|
502
|
+
}
|
|
457
503
|
interface WSDisconnectInfo {
|
|
458
504
|
code?: number;
|
|
459
505
|
reason?: string;
|
|
@@ -858,7 +904,8 @@ declare class Session {
|
|
|
858
904
|
* ```typescript
|
|
859
905
|
* import { Author, Book, global_search } from './sandbox-tools';
|
|
860
906
|
*
|
|
861
|
-
* const
|
|
907
|
+
* const authors = await Author.list({ limit: 10, saveAs: 'recent_authors' });
|
|
908
|
+
* const tolkien = await Author.get({ path: 'author_tolkien' });
|
|
862
909
|
* const bio = await tolkien.get_bio({ detailed: true });
|
|
863
910
|
* const books = await tolkien.get_books();
|
|
864
911
|
* ```
|
|
@@ -974,6 +1021,13 @@ declare class Environment extends Session {
|
|
|
974
1021
|
get permissionProfileId(): string;
|
|
975
1022
|
/** The GraphQL API endpoint URL */
|
|
976
1023
|
get apiEndpoint(): string;
|
|
1024
|
+
/**
|
|
1025
|
+
* Return a plain JS snapshot of the synced session heap.
|
|
1026
|
+
*
|
|
1027
|
+
* The heap lives in the Automerge document, so this method does not perform
|
|
1028
|
+
* any extra network roundtrip.
|
|
1029
|
+
*/
|
|
1030
|
+
getHeap(): SessionHeapSnapshot;
|
|
977
1031
|
private getRuntimeBaseUrl;
|
|
978
1032
|
/**
|
|
979
1033
|
* Close the session and disconnect from the sandbox.
|
|
@@ -1357,6 +1411,13 @@ declare class Granular {
|
|
|
1357
1411
|
* sandbox-scoped live catalog.
|
|
1358
1412
|
*/
|
|
1359
1413
|
unregisterEffect(sandboxNameOrId: string, name: string): Promise<void>;
|
|
1414
|
+
/**
|
|
1415
|
+
* Disconnect one sandbox-scoped effect host, or all of them when no sandbox is provided.
|
|
1416
|
+
*
|
|
1417
|
+
* This is primarily useful for long-lived helper processes such as generated
|
|
1418
|
+
* `granular-effects.ts` scripts that need to shut down cleanly on SIGINT/SIGTERM.
|
|
1419
|
+
*/
|
|
1420
|
+
disconnectEffects(sandboxNameOrId?: string): Promise<void>;
|
|
1360
1421
|
/**
|
|
1361
1422
|
* Unregister all effects for a sandbox.
|
|
1362
1423
|
*/
|
|
@@ -1427,4 +1488,4 @@ declare class Granular {
|
|
|
1427
1488
|
private request;
|
|
1428
1489
|
}
|
|
1429
1490
|
|
|
1430
|
-
export { type APIError, type AccessTokenProvider, type Assignment, type AssignmentListResponse, type Build, type BuildListResponse, type BuildPolicy, type BuildStatus, type ConnectOptions, type CreateEnvironmentData, type CreatePermissionProfileData, type CreateSandboxData, type DefineRelationshipOptions, type DeleteResponse, type DomainState, type EffectHandler, type EffectHandlerContext, type EffectInfo, type EffectSchema, type EffectWithHandler, type EffectsChangedEvent, type EndpointMode, Environment, type EnvironmentData, type EnvironmentListResponse, Granular, type GranularAuth, type GranularOptions, type GraphQLResult, type InstanceEffectHandler, type InstanceToolHandler, type Job, type JobStatus, type JobSubmitResult, type Manifest, type ManifestContent, type ManifestEffectDeclaration, type ManifestEffectSchema, type ManifestImport, type ManifestListResponse, type ManifestOperation, type ManifestPropertySpec, type ManifestRelationshipDef, type ManifestVolume, type ModelRef, type PermissionProfile, type PermissionProfileListResponse, type PermissionRules, type Prompt, type PublishEffectsResult, type PublishToolsResult, type RPCRequest, type RPCRequestFromServer, type RPCResponse, type RecordObjectOptions, type RecordObjectResult, type RecordUserOptions, type RelationshipInfo, type Sandbox, type SandboxListResponse, Session, type Subject, type SyncMessage, type ToolHandler, type ToolInfo, type ToolInvokeParams, type ToolResultParams, type ToolSchema, type ToolWithHandler, type ToolsChangedEvent, type User, WSClient, type WSClientOptions, type WSDisconnectInfo, type WSReconnectErrorInfo };
|
|
1491
|
+
export { type APIError, type AccessTokenProvider, type Assignment, type AssignmentListResponse, type Build, type BuildListResponse, type BuildPolicy, type BuildStatus, type ConnectOptions, type CreateEnvironmentData, type CreatePermissionProfileData, type CreateSandboxData, type DefineRelationshipOptions, type DeleteResponse, type DomainState, type EffectHandler, type EffectHandlerContext, type EffectInfo, type EffectSchema, type EffectWithHandler, type EffectsChangedEvent, type EndpointMode, Environment, type EnvironmentData, type EnvironmentListResponse, Granular, type GranularAuth, type GranularOptions, type GraphQLResult, type InstanceEffectHandler, type InstanceToolHandler, type Job, type JobStatus, type JobSubmitResult, type Manifest, type ManifestContent, type ManifestEffectDeclaration, type ManifestEffectSchema, type ManifestImport, type ManifestListResponse, type ManifestOperation, type ManifestPropertySpec, type ManifestRelationshipDef, type ManifestVolume, type ModelRef, type PermissionProfile, type PermissionProfileListResponse, type PermissionRules, type Prompt, type PublishEffectsResult, type PublishToolsResult, type RPCRequest, type RPCRequestFromServer, type RPCResponse, type RecordObjectOptions, type RecordObjectResult, type RecordUserOptions, type RelationshipInfo, type Sandbox, type SandboxListResponse, Session, type SessionHeapEntry, type SessionHeapFieldType, type SessionHeapFieldValue, type SessionHeapList, type SessionHeapSnapshot, type SessionHeapVariable, type Subject, type SyncMessage, type ToolHandler, type ToolInfo, type ToolInvokeParams, type ToolResultParams, type ToolSchema, type ToolWithHandler, type ToolsChangedEvent, type User, WSClient, type WSClientOptions, type WSDisconnectInfo, type WSReconnectErrorInfo };
|
package/dist/index.d.ts
CHANGED
|
@@ -88,6 +88,11 @@ interface ConnectOptions {
|
|
|
88
88
|
/** Optional stable client ID. Defaults to `client_${Date.now()}`. Use a fixed
|
|
89
89
|
* value for long-lived effect hosts so tool catalogs don't accumulate. */
|
|
90
90
|
clientId?: string;
|
|
91
|
+
/** Optional session heap seed. Each item is eagerly hydrated into the session heap on connect. */
|
|
92
|
+
initialHeap?: Array<{
|
|
93
|
+
className: string;
|
|
94
|
+
id: string;
|
|
95
|
+
}>;
|
|
91
96
|
}
|
|
92
97
|
/**
|
|
93
98
|
* A sandbox container
|
|
@@ -454,6 +459,47 @@ interface Prompt {
|
|
|
454
459
|
options?: string[];
|
|
455
460
|
defaultValue?: unknown;
|
|
456
461
|
}
|
|
462
|
+
type SessionHeapFieldType = 'string' | 'number' | 'boolean' | 'null' | 'unknown';
|
|
463
|
+
interface SessionHeapFieldValue {
|
|
464
|
+
name: string;
|
|
465
|
+
type: SessionHeapFieldType;
|
|
466
|
+
value: string | number | boolean | null;
|
|
467
|
+
}
|
|
468
|
+
interface SessionHeapEntry {
|
|
469
|
+
path: string;
|
|
470
|
+
className: string;
|
|
471
|
+
id: string;
|
|
472
|
+
label?: string | null;
|
|
473
|
+
description?: string | null;
|
|
474
|
+
prototypes: string[];
|
|
475
|
+
fields: SessionHeapFieldValue[];
|
|
476
|
+
relatedJobIds: string[];
|
|
477
|
+
source: string;
|
|
478
|
+
createdAt: number;
|
|
479
|
+
updatedAt: number;
|
|
480
|
+
}
|
|
481
|
+
interface SessionHeapList {
|
|
482
|
+
name: string;
|
|
483
|
+
className: string;
|
|
484
|
+
paths: string[];
|
|
485
|
+
relatedJobIds: string[];
|
|
486
|
+
updatedAt: number;
|
|
487
|
+
}
|
|
488
|
+
interface SessionHeapVariable {
|
|
489
|
+
name: string;
|
|
490
|
+
kind: 'entry' | 'list' | 'scalar';
|
|
491
|
+
entryPath?: string;
|
|
492
|
+
listName?: string;
|
|
493
|
+
value?: string | number | boolean | null;
|
|
494
|
+
className?: string;
|
|
495
|
+
updatedAt: number;
|
|
496
|
+
}
|
|
497
|
+
interface SessionHeapSnapshot {
|
|
498
|
+
entriesByPath: Record<string, SessionHeapEntry>;
|
|
499
|
+
listsByName: Record<string, SessionHeapList>;
|
|
500
|
+
variablesByName: Record<string, SessionHeapVariable>;
|
|
501
|
+
updatedAt: number;
|
|
502
|
+
}
|
|
457
503
|
interface WSDisconnectInfo {
|
|
458
504
|
code?: number;
|
|
459
505
|
reason?: string;
|
|
@@ -858,7 +904,8 @@ declare class Session {
|
|
|
858
904
|
* ```typescript
|
|
859
905
|
* import { Author, Book, global_search } from './sandbox-tools';
|
|
860
906
|
*
|
|
861
|
-
* const
|
|
907
|
+
* const authors = await Author.list({ limit: 10, saveAs: 'recent_authors' });
|
|
908
|
+
* const tolkien = await Author.get({ path: 'author_tolkien' });
|
|
862
909
|
* const bio = await tolkien.get_bio({ detailed: true });
|
|
863
910
|
* const books = await tolkien.get_books();
|
|
864
911
|
* ```
|
|
@@ -974,6 +1021,13 @@ declare class Environment extends Session {
|
|
|
974
1021
|
get permissionProfileId(): string;
|
|
975
1022
|
/** The GraphQL API endpoint URL */
|
|
976
1023
|
get apiEndpoint(): string;
|
|
1024
|
+
/**
|
|
1025
|
+
* Return a plain JS snapshot of the synced session heap.
|
|
1026
|
+
*
|
|
1027
|
+
* The heap lives in the Automerge document, so this method does not perform
|
|
1028
|
+
* any extra network roundtrip.
|
|
1029
|
+
*/
|
|
1030
|
+
getHeap(): SessionHeapSnapshot;
|
|
977
1031
|
private getRuntimeBaseUrl;
|
|
978
1032
|
/**
|
|
979
1033
|
* Close the session and disconnect from the sandbox.
|
|
@@ -1357,6 +1411,13 @@ declare class Granular {
|
|
|
1357
1411
|
* sandbox-scoped live catalog.
|
|
1358
1412
|
*/
|
|
1359
1413
|
unregisterEffect(sandboxNameOrId: string, name: string): Promise<void>;
|
|
1414
|
+
/**
|
|
1415
|
+
* Disconnect one sandbox-scoped effect host, or all of them when no sandbox is provided.
|
|
1416
|
+
*
|
|
1417
|
+
* This is primarily useful for long-lived helper processes such as generated
|
|
1418
|
+
* `granular-effects.ts` scripts that need to shut down cleanly on SIGINT/SIGTERM.
|
|
1419
|
+
*/
|
|
1420
|
+
disconnectEffects(sandboxNameOrId?: string): Promise<void>;
|
|
1360
1421
|
/**
|
|
1361
1422
|
* Unregister all effects for a sandbox.
|
|
1362
1423
|
*/
|
|
@@ -1427,4 +1488,4 @@ declare class Granular {
|
|
|
1427
1488
|
private request;
|
|
1428
1489
|
}
|
|
1429
1490
|
|
|
1430
|
-
export { type APIError, type AccessTokenProvider, type Assignment, type AssignmentListResponse, type Build, type BuildListResponse, type BuildPolicy, type BuildStatus, type ConnectOptions, type CreateEnvironmentData, type CreatePermissionProfileData, type CreateSandboxData, type DefineRelationshipOptions, type DeleteResponse, type DomainState, type EffectHandler, type EffectHandlerContext, type EffectInfo, type EffectSchema, type EffectWithHandler, type EffectsChangedEvent, type EndpointMode, Environment, type EnvironmentData, type EnvironmentListResponse, Granular, type GranularAuth, type GranularOptions, type GraphQLResult, type InstanceEffectHandler, type InstanceToolHandler, type Job, type JobStatus, type JobSubmitResult, type Manifest, type ManifestContent, type ManifestEffectDeclaration, type ManifestEffectSchema, type ManifestImport, type ManifestListResponse, type ManifestOperation, type ManifestPropertySpec, type ManifestRelationshipDef, type ManifestVolume, type ModelRef, type PermissionProfile, type PermissionProfileListResponse, type PermissionRules, type Prompt, type PublishEffectsResult, type PublishToolsResult, type RPCRequest, type RPCRequestFromServer, type RPCResponse, type RecordObjectOptions, type RecordObjectResult, type RecordUserOptions, type RelationshipInfo, type Sandbox, type SandboxListResponse, Session, type Subject, type SyncMessage, type ToolHandler, type ToolInfo, type ToolInvokeParams, type ToolResultParams, type ToolSchema, type ToolWithHandler, type ToolsChangedEvent, type User, WSClient, type WSClientOptions, type WSDisconnectInfo, type WSReconnectErrorInfo };
|
|
1491
|
+
export { type APIError, type AccessTokenProvider, type Assignment, type AssignmentListResponse, type Build, type BuildListResponse, type BuildPolicy, type BuildStatus, type ConnectOptions, type CreateEnvironmentData, type CreatePermissionProfileData, type CreateSandboxData, type DefineRelationshipOptions, type DeleteResponse, type DomainState, type EffectHandler, type EffectHandlerContext, type EffectInfo, type EffectSchema, type EffectWithHandler, type EffectsChangedEvent, type EndpointMode, Environment, type EnvironmentData, type EnvironmentListResponse, Granular, type GranularAuth, type GranularOptions, type GraphQLResult, type InstanceEffectHandler, type InstanceToolHandler, type Job, type JobStatus, type JobSubmitResult, type Manifest, type ManifestContent, type ManifestEffectDeclaration, type ManifestEffectSchema, type ManifestImport, type ManifestListResponse, type ManifestOperation, type ManifestPropertySpec, type ManifestRelationshipDef, type ManifestVolume, type ModelRef, type PermissionProfile, type PermissionProfileListResponse, type PermissionRules, type Prompt, type PublishEffectsResult, type PublishToolsResult, type RPCRequest, type RPCRequestFromServer, type RPCResponse, type RecordObjectOptions, type RecordObjectResult, type RecordUserOptions, type RelationshipInfo, type Sandbox, type SandboxListResponse, Session, type SessionHeapEntry, type SessionHeapFieldType, type SessionHeapFieldValue, type SessionHeapList, type SessionHeapSnapshot, type SessionHeapVariable, type Subject, type SyncMessage, type ToolHandler, type ToolInfo, type ToolInvokeParams, type ToolResultParams, type ToolSchema, type ToolWithHandler, type ToolsChangedEvent, type User, WSClient, type WSClientOptions, type WSDisconnectInfo, type WSReconnectErrorInfo };
|
package/dist/index.js
CHANGED
|
@@ -4577,7 +4577,8 @@ var Session = class {
|
|
|
4577
4577
|
* ```typescript
|
|
4578
4578
|
* import { Author, Book, global_search } from './sandbox-tools';
|
|
4579
4579
|
*
|
|
4580
|
-
* const
|
|
4580
|
+
* const authors = await Author.list({ limit: 10, saveAs: 'recent_authors' });
|
|
4581
|
+
* const tolkien = await Author.get({ path: 'author_tolkien' });
|
|
4581
4582
|
* const bio = await tolkien.get_bio({ detailed: true });
|
|
4582
4583
|
* const books = await tolkien.get_books();
|
|
4583
4584
|
* ```
|
|
@@ -5089,7 +5090,7 @@ var JobImplementation = class {
|
|
|
5089
5090
|
|
|
5090
5091
|
// src/endpoints.ts
|
|
5091
5092
|
var LOCAL_API_URL = "ws://localhost:8787/granular";
|
|
5092
|
-
var PRODUCTION_API_URL = "wss://api.
|
|
5093
|
+
var PRODUCTION_API_URL = "wss://cf-api-gateway.arthur6084.workers.dev/granular";
|
|
5093
5094
|
function readEnv(name) {
|
|
5094
5095
|
if (typeof process === "undefined" || !process.env) return void 0;
|
|
5095
5096
|
return process.env[name];
|
|
@@ -5176,6 +5177,26 @@ function buildEffectHostUrl(apiUrl, sandboxId, effectClientId, clientId) {
|
|
|
5176
5177
|
url.searchParams.set("clientId", clientId);
|
|
5177
5178
|
return url.toString();
|
|
5178
5179
|
}
|
|
5180
|
+
function createEmptyHeapSnapshot(now = Date.now()) {
|
|
5181
|
+
return {
|
|
5182
|
+
entriesByPath: {},
|
|
5183
|
+
listsByName: {},
|
|
5184
|
+
variablesByName: {},
|
|
5185
|
+
updatedAt: now
|
|
5186
|
+
};
|
|
5187
|
+
}
|
|
5188
|
+
function normalizeHeapSnapshot(raw) {
|
|
5189
|
+
if (!raw || typeof raw !== "object") {
|
|
5190
|
+
return createEmptyHeapSnapshot();
|
|
5191
|
+
}
|
|
5192
|
+
const heap = raw;
|
|
5193
|
+
return {
|
|
5194
|
+
entriesByPath: heap.entriesByPath && typeof heap.entriesByPath === "object" ? JSON.parse(JSON.stringify(heap.entriesByPath)) : {},
|
|
5195
|
+
listsByName: heap.listsByName && typeof heap.listsByName === "object" ? JSON.parse(JSON.stringify(heap.listsByName)) : {},
|
|
5196
|
+
variablesByName: heap.variablesByName && typeof heap.variablesByName === "object" ? JSON.parse(JSON.stringify(heap.variablesByName)) : {},
|
|
5197
|
+
updatedAt: typeof heap.updatedAt === "number" ? heap.updatedAt : Date.now()
|
|
5198
|
+
};
|
|
5199
|
+
}
|
|
5179
5200
|
var Environment = class _Environment extends Session {
|
|
5180
5201
|
envData;
|
|
5181
5202
|
_apiKey;
|
|
@@ -5206,6 +5227,16 @@ var Environment = class _Environment extends Session {
|
|
|
5206
5227
|
get apiEndpoint() {
|
|
5207
5228
|
return this._apiEndpoint;
|
|
5208
5229
|
}
|
|
5230
|
+
/**
|
|
5231
|
+
* Return a plain JS snapshot of the synced session heap.
|
|
5232
|
+
*
|
|
5233
|
+
* The heap lives in the Automerge document, so this method does not perform
|
|
5234
|
+
* any extra network roundtrip.
|
|
5235
|
+
*/
|
|
5236
|
+
getHeap() {
|
|
5237
|
+
const doc = this.document;
|
|
5238
|
+
return normalizeHeapSnapshot(doc?.heap);
|
|
5239
|
+
}
|
|
5209
5240
|
getRuntimeBaseUrl() {
|
|
5210
5241
|
try {
|
|
5211
5242
|
const endpoint = new URL(this._apiEndpoint);
|
|
@@ -6067,7 +6098,8 @@ var Granular = class {
|
|
|
6067
6098
|
method: "POST",
|
|
6068
6099
|
body: JSON.stringify({
|
|
6069
6100
|
environmentId: envData.environmentId,
|
|
6070
|
-
clientId
|
|
6101
|
+
clientId,
|
|
6102
|
+
initialHeap: options.initialHeap
|
|
6071
6103
|
})
|
|
6072
6104
|
});
|
|
6073
6105
|
const client = new WSClient({
|
|
@@ -6118,7 +6150,21 @@ var Granular = class {
|
|
|
6118
6150
|
const effects = Array.from(this.getSandboxEffectMap(host.sandboxId).values()).map(
|
|
6119
6151
|
(effect) => this.serializeEffect(effect)
|
|
6120
6152
|
);
|
|
6121
|
-
await host.wsClient.call("effects.publishCatalog", { effects });
|
|
6153
|
+
const result = await host.wsClient.call("effects.publishCatalog", { effects });
|
|
6154
|
+
const acceptedCount = typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
|
|
6155
|
+
const rejected = Array.isArray(result?.rejected) ? result.rejected : [];
|
|
6156
|
+
if (acceptedCount === 0 && rejected.length > 0) {
|
|
6157
|
+
const detail = rejected.map((entry) => `${entry.name || "unknown"}: ${entry.reason || "rejected"}`).join("; ");
|
|
6158
|
+
throw new Error(
|
|
6159
|
+
`Failed to publish live effects for sandbox ${host.sandboxId}: ${detail}`
|
|
6160
|
+
);
|
|
6161
|
+
}
|
|
6162
|
+
if (rejected.length > 0) {
|
|
6163
|
+
console.warn(
|
|
6164
|
+
`[Granular] Some live effects were rejected for sandbox ${host.sandboxId}:`,
|
|
6165
|
+
rejected
|
|
6166
|
+
);
|
|
6167
|
+
}
|
|
6122
6168
|
}
|
|
6123
6169
|
async syncSandboxEffectCatalog(sandboxId) {
|
|
6124
6170
|
const host = await this.ensureSandboxEffectHost(sandboxId);
|
|
@@ -6284,6 +6330,22 @@ var Granular = class {
|
|
|
6284
6330
|
}
|
|
6285
6331
|
await this.syncSandboxEffectCatalog(sandboxId);
|
|
6286
6332
|
}
|
|
6333
|
+
/**
|
|
6334
|
+
* Disconnect one sandbox-scoped effect host, or all of them when no sandbox is provided.
|
|
6335
|
+
*
|
|
6336
|
+
* This is primarily useful for long-lived helper processes such as generated
|
|
6337
|
+
* `granular-effects.ts` scripts that need to shut down cleanly on SIGINT/SIGTERM.
|
|
6338
|
+
*/
|
|
6339
|
+
async disconnectEffects(sandboxNameOrId) {
|
|
6340
|
+
if (sandboxNameOrId) {
|
|
6341
|
+
const sandbox = await this.findOrCreateSandbox(sandboxNameOrId);
|
|
6342
|
+
this.disconnectSandboxEffectHost(sandbox.sandboxId);
|
|
6343
|
+
return;
|
|
6344
|
+
}
|
|
6345
|
+
for (const sandboxId of Array.from(this.sandboxEffectHosts.keys())) {
|
|
6346
|
+
this.disconnectSandboxEffectHost(sandboxId);
|
|
6347
|
+
}
|
|
6348
|
+
}
|
|
6287
6349
|
/**
|
|
6288
6350
|
* Unregister all effects for a sandbox.
|
|
6289
6351
|
*/
|