@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/dist/index.mjs CHANGED
@@ -4555,7 +4555,8 @@ var Session = class {
4555
4555
  * ```typescript
4556
4556
  * import { Author, Book, global_search } from './sandbox-tools';
4557
4557
  *
4558
- * const tolkien = await Author.find({ id: 'tolkien' });
4558
+ * const authors = await Author.list({ limit: 10, saveAs: 'recent_authors' });
4559
+ * const tolkien = await Author.get({ path: 'author_tolkien' });
4559
4560
  * const bio = await tolkien.get_bio({ detailed: true });
4560
4561
  * const books = await tolkien.get_books();
4561
4562
  * ```
@@ -5067,7 +5068,7 @@ var JobImplementation = class {
5067
5068
 
5068
5069
  // src/endpoints.ts
5069
5070
  var LOCAL_API_URL = "ws://localhost:8787/granular";
5070
- var PRODUCTION_API_URL = "wss://api.granular.dev/v2/ws";
5071
+ var PRODUCTION_API_URL = "wss://cf-api-gateway.arthur6084.workers.dev/granular";
5071
5072
  function readEnv(name) {
5072
5073
  if (typeof process === "undefined" || !process.env) return void 0;
5073
5074
  return process.env[name];
@@ -5154,6 +5155,26 @@ function buildEffectHostUrl(apiUrl, sandboxId, effectClientId, clientId) {
5154
5155
  url.searchParams.set("clientId", clientId);
5155
5156
  return url.toString();
5156
5157
  }
5158
+ function createEmptyHeapSnapshot(now = Date.now()) {
5159
+ return {
5160
+ entriesByPath: {},
5161
+ listsByName: {},
5162
+ variablesByName: {},
5163
+ updatedAt: now
5164
+ };
5165
+ }
5166
+ function normalizeHeapSnapshot(raw) {
5167
+ if (!raw || typeof raw !== "object") {
5168
+ return createEmptyHeapSnapshot();
5169
+ }
5170
+ const heap = raw;
5171
+ return {
5172
+ entriesByPath: heap.entriesByPath && typeof heap.entriesByPath === "object" ? JSON.parse(JSON.stringify(heap.entriesByPath)) : {},
5173
+ listsByName: heap.listsByName && typeof heap.listsByName === "object" ? JSON.parse(JSON.stringify(heap.listsByName)) : {},
5174
+ variablesByName: heap.variablesByName && typeof heap.variablesByName === "object" ? JSON.parse(JSON.stringify(heap.variablesByName)) : {},
5175
+ updatedAt: typeof heap.updatedAt === "number" ? heap.updatedAt : Date.now()
5176
+ };
5177
+ }
5157
5178
  var Environment = class _Environment extends Session {
5158
5179
  envData;
5159
5180
  _apiKey;
@@ -5184,6 +5205,16 @@ var Environment = class _Environment extends Session {
5184
5205
  get apiEndpoint() {
5185
5206
  return this._apiEndpoint;
5186
5207
  }
5208
+ /**
5209
+ * Return a plain JS snapshot of the synced session heap.
5210
+ *
5211
+ * The heap lives in the Automerge document, so this method does not perform
5212
+ * any extra network roundtrip.
5213
+ */
5214
+ getHeap() {
5215
+ const doc = this.document;
5216
+ return normalizeHeapSnapshot(doc?.heap);
5217
+ }
5187
5218
  getRuntimeBaseUrl() {
5188
5219
  try {
5189
5220
  const endpoint = new URL(this._apiEndpoint);
@@ -6045,7 +6076,8 @@ var Granular = class {
6045
6076
  method: "POST",
6046
6077
  body: JSON.stringify({
6047
6078
  environmentId: envData.environmentId,
6048
- clientId
6079
+ clientId,
6080
+ initialHeap: options.initialHeap
6049
6081
  })
6050
6082
  });
6051
6083
  const client = new WSClient({
@@ -6096,7 +6128,21 @@ var Granular = class {
6096
6128
  const effects = Array.from(this.getSandboxEffectMap(host.sandboxId).values()).map(
6097
6129
  (effect) => this.serializeEffect(effect)
6098
6130
  );
6099
- await host.wsClient.call("effects.publishCatalog", { effects });
6131
+ const result = await host.wsClient.call("effects.publishCatalog", { effects });
6132
+ const acceptedCount = typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
6133
+ const rejected = Array.isArray(result?.rejected) ? result.rejected : [];
6134
+ if (acceptedCount === 0 && rejected.length > 0) {
6135
+ const detail = rejected.map((entry) => `${entry.name || "unknown"}: ${entry.reason || "rejected"}`).join("; ");
6136
+ throw new Error(
6137
+ `Failed to publish live effects for sandbox ${host.sandboxId}: ${detail}`
6138
+ );
6139
+ }
6140
+ if (rejected.length > 0) {
6141
+ console.warn(
6142
+ `[Granular] Some live effects were rejected for sandbox ${host.sandboxId}:`,
6143
+ rejected
6144
+ );
6145
+ }
6100
6146
  }
6101
6147
  async syncSandboxEffectCatalog(sandboxId) {
6102
6148
  const host = await this.ensureSandboxEffectHost(sandboxId);
@@ -6262,6 +6308,22 @@ var Granular = class {
6262
6308
  }
6263
6309
  await this.syncSandboxEffectCatalog(sandboxId);
6264
6310
  }
6311
+ /**
6312
+ * Disconnect one sandbox-scoped effect host, or all of them when no sandbox is provided.
6313
+ *
6314
+ * This is primarily useful for long-lived helper processes such as generated
6315
+ * `granular-effects.ts` scripts that need to shut down cleanly on SIGINT/SIGTERM.
6316
+ */
6317
+ async disconnectEffects(sandboxNameOrId) {
6318
+ if (sandboxNameOrId) {
6319
+ const sandbox = await this.findOrCreateSandbox(sandboxNameOrId);
6320
+ this.disconnectSandboxEffectHost(sandbox.sandboxId);
6321
+ return;
6322
+ }
6323
+ for (const sandboxId of Array.from(this.sandboxEffectHosts.keys())) {
6324
+ this.disconnectSandboxEffectHost(sandboxId);
6325
+ }
6326
+ }
6265
6327
  /**
6266
6328
  * Unregister all effects for a sandbox.
6267
6329
  */