@granular-software/sdk 0.4.29 → 0.4.30

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/cli/index.js CHANGED
@@ -14230,17 +14230,8 @@ var searchableMetamodelPackage = defineMetamodelPackage({
14230
14230
  }
14231
14231
  },
14232
14232
  domain: {
14233
- applyToPropertyIR(propertyIR, propertySummary) {
14234
- if (String(propertySummary.type || "").toLowerCase() !== "string" || propertySummary.searchable === false) {
14235
- return propertyIR;
14236
- }
14237
- return {
14238
- ...propertyIR,
14239
- docs: [
14240
- ...propertyIR.docs,
14241
- propertySummary.searchablePhonetic ? "Searchable via `search` using FalkorDB full-text query syntax with phonetic matching enabled." : "Searchable via `search` using FalkorDB full-text query syntax."
14242
- ]
14243
- };
14233
+ applyToPropertyIR(propertyIR, _propertySummary) {
14234
+ return propertyIR;
14244
14235
  }
14245
14236
  }
14246
14237
  });
@@ -19520,17 +19511,40 @@ function buildEffectMetamodelMutations(toolPath, spec) {
19520
19511
 
19521
19512
  // src/client.ts
19522
19513
  var STANDARD_MODULES_OPERATIONS = [
19523
- { create: "entity", has: { id: { value: "auto-generated" }, createdAt: { value: void 0 } } },
19514
+ {
19515
+ create: "entity",
19516
+ has: { id: { value: "auto-generated" }, createdAt: { value: void 0 } }
19517
+ },
19524
19518
  { create: "class", extends: "entity", has: {} },
19525
- { create: "user", extends: "entity", has: { email: { value: void 0 }, firstName: { value: void 0 }, lastName: { value: void 0 } } },
19526
- { create: "company", extends: "entity", has: { name: { value: void 0 }, website: { value: void 0 } } },
19519
+ {
19520
+ create: "user",
19521
+ extends: "entity",
19522
+ has: {
19523
+ email: { value: void 0 },
19524
+ firstName: { value: void 0 },
19525
+ lastName: { value: void 0 }
19526
+ }
19527
+ },
19528
+ {
19529
+ create: "company",
19530
+ extends: "entity",
19531
+ has: { name: { value: void 0 }, website: { value: void 0 } }
19532
+ },
19527
19533
  { create: "string", has: {} },
19528
19534
  { create: "number", has: {} },
19529
19535
  { create: "boolean", has: {} },
19530
- { create: "tool_parameter", has: { name: { value: void 0 }, type: { value: "string" }, description: { value: void 0 }, required: { value: false } } }
19536
+ {
19537
+ create: "tool_parameter",
19538
+ has: {
19539
+ name: { value: void 0 },
19540
+ type: { value: "string" },
19541
+ description: { value: void 0 },
19542
+ required: { value: false }
19543
+ }
19544
+ }
19531
19545
  ];
19532
19546
  var BUILTIN_MODULES = {
19533
- "standard_modules": STANDARD_MODULES_OPERATIONS
19547
+ standard_modules: STANDARD_MODULES_OPERATIONS
19534
19548
  };
19535
19549
  var DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE = 100;
19536
19550
  var MAX_RECORD_OBJECTS_CONCURRENCY = 16;
@@ -19565,7 +19579,9 @@ function isRetryableLocalWorkerRestart(status, body, url) {
19565
19579
  }
19566
19580
  function isRetryableRecordObjectsError(error2) {
19567
19581
  const message = error2 instanceof Error ? error2.message : String(error2);
19568
- return /worker restarted mid-request|econnreset|network|socket connection was closed unexpectedly|timed out/i.test(message);
19582
+ return /worker restarted mid-request|econnreset|network|socket connection was closed unexpectedly|timed out/i.test(
19583
+ message
19584
+ );
19569
19585
  }
19570
19586
  function computeEffectKey2(effect) {
19571
19587
  const attachedClass = effect.className?.trim();
@@ -19642,7 +19658,10 @@ function normalizeUser(user) {
19642
19658
  };
19643
19659
  }
19644
19660
  function normalizeEnvironmentData(environment) {
19645
- const buildPolicy = environment.buildPolicy || environment.tracking || (environment.tagId ? { mode: "tag", tagId: environment.tagId } : { mode: "pinned", versionId: environment.versionId || environment.buildId });
19661
+ const buildPolicy = environment.buildPolicy || environment.tracking || (environment.tagId ? { mode: "tag", tagId: environment.tagId } : {
19662
+ mode: "pinned",
19663
+ versionId: environment.versionId || environment.buildId
19664
+ });
19646
19665
  const environmentName = environment.environment || environment.envName || "prod";
19647
19666
  return {
19648
19667
  ...environment,
@@ -19736,14 +19755,16 @@ var Environment = class extends Session {
19736
19755
  const response = await fetch(url, {
19737
19756
  ...options,
19738
19757
  headers: {
19739
- "Authorization": `Bearer ${this._apiKey}`,
19758
+ Authorization: `Bearer ${this._apiKey}`,
19740
19759
  "Content-Type": "application/json",
19741
- "Connection": "close",
19760
+ Connection: "close",
19742
19761
  ...options.headers
19743
19762
  }
19744
19763
  });
19745
19764
  if (!response.ok) {
19746
- throw new Error(`Control Plane API Error (${response.status}): ${await response.text()}`);
19765
+ throw new Error(
19766
+ `Control Plane API Error (${response.status}): ${await response.text()}`
19767
+ );
19747
19768
  }
19748
19769
  return response.json();
19749
19770
  }
@@ -19757,9 +19778,12 @@ var Environment = class extends Session {
19757
19778
  async disconnect() {
19758
19779
  let wsNotifiedRuntime = false;
19759
19780
  try {
19760
- const goodbye = await this.rpc("client.goodbye", {
19761
- timestamp: Date.now()
19762
- });
19781
+ const goodbye = await this.rpc(
19782
+ "client.goodbye",
19783
+ {
19784
+ timestamp: Date.now()
19785
+ }
19786
+ );
19763
19787
  wsNotifiedRuntime = Boolean(goodbye?.ok && goodbye?.via);
19764
19788
  } catch {
19765
19789
  wsNotifiedRuntime = false;
@@ -19773,8 +19797,8 @@ var Environment = class extends Session {
19773
19797
  method: "POST",
19774
19798
  headers: {
19775
19799
  "Content-Type": "application/json",
19776
- "Authorization": `Bearer ${this._apiKey}`,
19777
- "Connection": "close"
19800
+ Authorization: `Bearer ${this._apiKey}`,
19801
+ Connection: "close"
19778
19802
  },
19779
19803
  body: JSON.stringify({
19780
19804
  reason: "sdk_disconnect_http_fallback",
@@ -19787,6 +19811,15 @@ var Environment = class extends Session {
19787
19811
  }
19788
19812
  this.client.disconnect();
19789
19813
  }
19814
+ /**
19815
+ * Close only the socket transport without sending `client.goodbye`.
19816
+ *
19817
+ * Use this when the caller intends to immediately reattach to the same
19818
+ * session after an unexpected disconnect.
19819
+ */
19820
+ disconnectTransport() {
19821
+ this.client.disconnect();
19822
+ }
19790
19823
  // ==================== GRAPH CONTAINER READINESS ====================
19791
19824
  /** The last known graph container status, updated by checkReadiness() or on heartbeat */
19792
19825
  graphContainerStatus = null;
@@ -19852,14 +19885,14 @@ var Environment = class extends Session {
19852
19885
  }
19853
19886
  /**
19854
19887
  * Execute a GraphQL query against the environment's graph.
19855
- *
19888
+ *
19856
19889
  * The query uses the Granular graph query language (based on Cypher/GraphQL).
19857
19890
  * Authentication is handled automatically using the SDK's API key.
19858
- *
19891
+ *
19859
19892
  * @param query - The GraphQL query string
19860
19893
  * @param variables - Optional variables for the query
19861
19894
  * @returns The query result data
19862
- *
19895
+ *
19863
19896
  * @example
19864
19897
  * ```typescript
19865
19898
  * // Read the workspace
@@ -19867,7 +19900,7 @@ var Environment = class extends Session {
19867
19900
  * `query { model(path: "workspace") { path label submodels { path label } } }`
19868
19901
  * );
19869
19902
  * console.log(result.data);
19870
- *
19903
+ *
19871
19904
  * // Create a model
19872
19905
  * const created = await env.graphql(
19873
19906
  * `mutation { at(path: "workspace") { create_submodel(subpath: "my_node", label: "My Node", prototype: "Model") { model { path label } } } }`
@@ -19879,7 +19912,7 @@ var Environment = class extends Session {
19879
19912
  method: "POST",
19880
19913
  headers: {
19881
19914
  "Content-Type": "application/json",
19882
- "Authorization": `Bearer ${this._apiKey}`
19915
+ Authorization: `Bearer ${this._apiKey}`
19883
19916
  },
19884
19917
  body: JSON.stringify({
19885
19918
  environmentId: this.environmentId,
@@ -19896,10 +19929,10 @@ var Environment = class extends Session {
19896
19929
  // ==================== RELATIONSHIP METHODS ====================
19897
19930
  /**
19898
19931
  * Define a relationship between two model types.
19899
- *
19932
+ *
19900
19933
  * Creates both submodels (if they don't exist) and links them with
19901
19934
  * a RelationshipDef node that encodes cardinality.
19902
- *
19935
+ *
19903
19936
  * @example
19904
19937
  * ```typescript
19905
19938
  * // Author has many Books, Book has one Author
@@ -19959,10 +19992,10 @@ var Environment = class extends Session {
19959
19992
  }
19960
19993
  /**
19961
19994
  * Get all relationships for a model type.
19962
- *
19995
+ *
19963
19996
  * @param modelPath - The model type path (e.g., "author")
19964
19997
  * @returns Array of relationships from this model's perspective
19965
- *
19998
+ *
19966
19999
  * @example
19967
20000
  * ```typescript
19968
20001
  * const rels = await env.getRelationships('author');
@@ -19995,18 +20028,18 @@ var Environment = class extends Session {
19995
20028
  }
19996
20029
  /**
19997
20030
  * Attach a target model to a relationship submodel.
19998
- *
20031
+ *
19999
20032
  * Handles cardinality automatically:
20000
20033
  * - "One" side: sets/replaces the reference
20001
20034
  * - "Many" side: adds the target to the collection
20002
- *
20035
+ *
20003
20036
  * If the target model doesn't exist, it's created as an instance of the foreign type.
20004
20037
  * Bidirectional sync is automatic.
20005
- *
20038
+ *
20006
20039
  * @param modelPath - The model instance path (e.g., "tolkien")
20007
20040
  * @param submodelPath - The relationship submodel (e.g., "books")
20008
20041
  * @param targetPath - The target model to attach (e.g., "lord_of_the_rings")
20009
- *
20042
+ *
20010
20043
  * @example
20011
20044
  * ```typescript
20012
20045
  * // Attach a book to an author (many side)
@@ -20033,18 +20066,18 @@ var Environment = class extends Session {
20033
20066
  }
20034
20067
  /**
20035
20068
  * Detach a target model from a relationship submodel.
20036
- *
20069
+ *
20037
20070
  * Handles bidirectional cleanup automatically.
20038
- *
20071
+ *
20039
20072
  * @param modelPath - The model instance path
20040
20073
  * @param submodelPath - The relationship submodel
20041
20074
  * @param targetPath - The target to detach (optional for "one" side; omit on "many" side to detach all)
20042
- *
20075
+ *
20043
20076
  * @example
20044
20077
  * ```typescript
20045
20078
  * // Detach a specific book
20046
20079
  * await env.detach('tolkien', 'books', 'lord_of_the_rings');
20047
- *
20080
+ *
20048
20081
  * // Detach all books
20049
20082
  * await env.detach('tolkien', 'books');
20050
20083
  * ```
@@ -20068,11 +20101,11 @@ var Environment = class extends Session {
20068
20101
  }
20069
20102
  /**
20070
20103
  * List all related models through a relationship submodel.
20071
- *
20104
+ *
20072
20105
  * @param modelPath - The model instance path
20073
20106
  * @param submodelPath - The relationship submodel
20074
20107
  * @returns Array of related model references
20075
- *
20108
+ *
20076
20109
  * @example
20077
20110
  * ```typescript
20078
20111
  * const books = await env.listRelated('tolkien', 'books');
@@ -20096,14 +20129,14 @@ var Environment = class extends Session {
20096
20129
  }
20097
20130
  /**
20098
20131
  * Apply a manifest to the current environment's graph.
20099
- *
20132
+ *
20100
20133
  * Translates each manifest operation into GraphQL mutations and executes them
20101
20134
  * in order. This is the core mechanism for creating classes, fields, and
20102
20135
  * relationships from a declarative manifest.
20103
- *
20136
+ *
20104
20137
  * @param manifest - The manifest content to apply
20105
20138
  * @returns Summary of applied operations
20106
- *
20139
+ *
20107
20140
  * @example
20108
20141
  * ```typescript
20109
20142
  * await environment.applyManifest({
@@ -20141,12 +20174,16 @@ var Environment = class extends Session {
20141
20174
  applied++;
20142
20175
  } catch (err) {
20143
20176
  if (!err.message?.includes("already exists")) {
20144
- errors.push(`Import ${imp.name} operation failed: ${err.message}`);
20177
+ errors.push(
20178
+ `Import ${imp.name} operation failed: ${err.message}`
20179
+ );
20145
20180
  }
20146
20181
  }
20147
20182
  }
20148
20183
  } else {
20149
- errors.push(`Unknown module: "${imp.name}" (only built-in modules are supported)`);
20184
+ errors.push(
20185
+ `Unknown module: "${imp.name}" (only built-in modules are supported)`
20186
+ );
20150
20187
  }
20151
20188
  }
20152
20189
  }
@@ -20230,7 +20267,10 @@ var Environment = class extends Session {
20230
20267
  }
20231
20268
  }
20232
20269
  async _applyEffectMetamodels(toolPath, metamodels) {
20233
- for (const mutation of buildEffectMetamodelMutations(toolPath, metamodels)) {
20270
+ for (const mutation of buildEffectMetamodelMutations(
20271
+ toolPath,
20272
+ metamodels
20273
+ )) {
20234
20274
  await this._runGraphql(mutation.query, mutation.label);
20235
20275
  }
20236
20276
  }
@@ -20279,7 +20319,9 @@ var Environment = class extends Session {
20279
20319
  }
20280
20320
  if (eventType.payloadSchema?.properties) {
20281
20321
  const fieldSpecs = {};
20282
- for (const [propName, propSchema] of Object.entries(eventType.payloadSchema.properties)) {
20322
+ for (const [propName, propSchema] of Object.entries(
20323
+ eventType.payloadSchema.properties
20324
+ )) {
20283
20325
  const schema = propSchema;
20284
20326
  fieldSpecs[propName] = {
20285
20327
  type: schema.type ?? "string",
@@ -20562,7 +20604,9 @@ var Environment = class extends Session {
20562
20604
  const wave = plans.slice(waveStart, waveStart + concurrency);
20563
20605
  await Promise.all(
20564
20606
  wave.map(async (plan) => {
20565
- const { items, durationMs } = await this.executeRecordObjectsChunk(plan.slice);
20607
+ const { items, durationMs } = await this.executeRecordObjectsChunk(
20608
+ plan.slice
20609
+ );
20566
20610
  if (items.length !== plan.slice.length) {
20567
20611
  throw new Error(
20568
20612
  `recordObjects: chunk ${plan.chunkIndex + 1} returned ${items.length} results, expected ${plan.slice.length}`
@@ -20592,13 +20636,10 @@ var Environment = class extends Session {
20592
20636
  let lastError;
20593
20637
  for (let attempt = 1; attempt <= DEFAULT_DIRECT_RECORD_OBJECTS_RETRY_COUNT; attempt += 1) {
20594
20638
  try {
20595
- const response = await this.controlPlaneRequest(
20596
- `/control/environments/${this.environmentId}/records/batch`,
20597
- {
20598
- method: "POST",
20599
- body: JSON.stringify({ records: chunk })
20600
- }
20601
- );
20639
+ const response = await this.controlPlaneRequest(`/control/environments/${this.environmentId}/records/batch`, {
20640
+ method: "POST",
20641
+ body: JSON.stringify({ records: chunk })
20642
+ });
20602
20643
  const items = Array.isArray(response.items) ? response.items : [];
20603
20644
  return { items, durationMs: Date.now() - wallStart };
20604
20645
  } catch (error2) {
@@ -20661,7 +20702,9 @@ var Environment = class extends Session {
20661
20702
  * Fetch a single record import by id.
20662
20703
  */
20663
20704
  async getRecordImport(importId) {
20664
- return this.controlPlaneRequest(`/control/record-imports/${importId}`);
20705
+ return this.controlPlaneRequest(
20706
+ `/control/record-imports/${importId}`
20707
+ );
20665
20708
  }
20666
20709
  /**
20667
20710
  * Cancel a queued/background record import.
@@ -20728,7 +20771,9 @@ var Granular = class _Granular {
20728
20771
  constructor(options) {
20729
20772
  const auth = options.token ?? options.apiKey;
20730
20773
  if (!auth) {
20731
- throw new Error("Granular client requires either apiKey or token. Set GRANULAR_API_KEY or GRANULAR_TOKEN, or pass one in options.");
20774
+ throw new Error(
20775
+ "Granular client requires either apiKey or token. Set GRANULAR_API_KEY or GRANULAR_TOKEN, or pass one in options."
20776
+ );
20732
20777
  }
20733
20778
  this.apiUrl = resolveApiUrl(options.apiUrl, options.endpointMode);
20734
20779
  this.apiKey = resolveAuthTokenForApiUrl(auth, this.apiUrl);
@@ -20740,10 +20785,10 @@ var Granular = class _Granular {
20740
20785
  }
20741
20786
  /**
20742
20787
  * Records/upserts a user and prepares them for sandbox connections
20743
- *
20788
+ *
20744
20789
  * @param options - User options
20745
20790
  * @returns The recorded user with both `userId` and `granularId`
20746
- *
20791
+ *
20747
20792
  * @example
20748
20793
  * ```typescript
20749
20794
  * const user = await granular.recordUser({
@@ -20754,14 +20799,16 @@ var Granular = class _Granular {
20754
20799
  * ```
20755
20800
  */
20756
20801
  async recordUser(options) {
20757
- const subject = normalizeSubject(await this.request("/control/subjects", {
20758
- method: "POST",
20759
- body: JSON.stringify({
20760
- identityId: options.userId,
20761
- name: options.name,
20762
- email: options.email
20802
+ const subject = normalizeSubject(
20803
+ await this.request("/control/subjects", {
20804
+ method: "POST",
20805
+ body: JSON.stringify({
20806
+ identityId: options.userId,
20807
+ name: options.name,
20808
+ email: options.email
20809
+ })
20763
20810
  })
20764
- }));
20811
+ );
20765
20812
  return normalizeUser({
20766
20813
  granularId: subject.granularId,
20767
20814
  userId: options.userId,
@@ -20808,18 +20855,20 @@ var Granular = class _Granular {
20808
20855
  permissions: options.permissions || []
20809
20856
  };
20810
20857
  }
20811
- throw new Error("connect() requires either userId, granularId, or a user object returned by recordUser().");
20858
+ throw new Error(
20859
+ "connect() requires either userId, granularId, or a user object returned by recordUser()."
20860
+ );
20812
20861
  }
20813
20862
  /**
20814
20863
  * Connect to an ontology environment and establish a real-time session.
20815
- *
20864
+ *
20816
20865
  * Effects are registered at the sandbox level via `granular.registerEffect()`
20817
20866
  * or `granular.registerEffects()`. Sessions pick up live availability from
20818
20867
  * the sandbox registry automatically.
20819
- *
20868
+ *
20820
20869
  * @param options - Connection options
20821
20870
  * @returns An active environment session
20822
- *
20871
+ *
20823
20872
  * @example
20824
20873
  * ```typescript
20825
20874
  * const environment = await granular.connect({
@@ -20828,23 +20877,23 @@ var Granular = class _Granular {
20828
20877
  * userId: 'user_123',
20829
20878
  * permissions: ['agent'],
20830
20879
  * });
20831
- *
20880
+ *
20832
20881
  * await granular.registerEffect('my-sandbox', {
20833
20882
  * name: 'greet',
20834
20883
  * description: 'Say hello',
20835
20884
  * inputSchema: { type: 'object', properties: {} },
20836
20885
  * handler: async () => 'Hello!',
20837
20886
  * });
20838
- *
20887
+ *
20839
20888
  * // Submit job
20840
20889
  * const job = await environment.submitJob(`
20841
20890
  * import { tools } from './sandbox-tools';
20842
20891
  * return await tools.greet({});
20843
20892
  * `);
20844
- *
20893
+ *
20845
20894
  * console.log(await job.result); // 'Hello!'
20846
20895
  * ```
20847
- */
20896
+ */
20848
20897
  async connect(options) {
20849
20898
  const clientId = options.clientId || `client_${Date.now()}`;
20850
20899
  const ontology = options.ontology;
@@ -20859,8 +20908,15 @@ var Granular = class _Granular {
20859
20908
  const user = await this.resolveConnectUser(options);
20860
20909
  const sandbox = await this.findOrCreateSandbox(ontology);
20861
20910
  for (const profileName of user.permissions) {
20862
- const profileId = await this.ensurePermissionProfile(sandbox.sandboxId, profileName);
20863
- await this.ensureAssignment(user.granularId, sandbox.sandboxId, profileId);
20911
+ const profileId = await this.ensurePermissionProfile(
20912
+ sandbox.sandboxId,
20913
+ profileName
20914
+ );
20915
+ await this.ensureAssignment(
20916
+ user.granularId,
20917
+ sandbox.sandboxId,
20918
+ profileId
20919
+ );
20864
20920
  }
20865
20921
  const envData = await this.environments.create(sandbox.sandboxId, {
20866
20922
  subjectId: user.granularId,
@@ -20912,7 +20968,9 @@ var Granular = class _Granular {
20912
20968
  createdAt: _Granular.coerceIsoDate(row.createdAt ?? row.created_at),
20913
20969
  lastSeenAt: _Granular.coerceIsoDate(row.lastSeenAt ?? row.last_seen_at),
20914
20970
  summary: row.summary != null ? String(row.summary) : null,
20915
- summaryUpdatedAt: row.summaryUpdatedAt != null || row.summary_updated_at != null ? _Granular.coerceIsoDate(row.summaryUpdatedAt ?? row.summary_updated_at) : null,
20971
+ summaryUpdatedAt: row.summaryUpdatedAt != null || row.summary_updated_at != null ? _Granular.coerceIsoDate(
20972
+ row.summaryUpdatedAt ?? row.summary_updated_at
20973
+ ) : null,
20916
20974
  subjectId: row.subjectId != null ? String(row.subjectId) : null,
20917
20975
  jobCount: typeof row.jobCount === "number" ? row.jobCount : void 0,
20918
20976
  toolCallCount: typeof row.toolCallCount === "number" ? row.toolCallCount : void 0
@@ -21002,7 +21060,13 @@ var Granular = class _Granular {
21002
21060
  });
21003
21061
  await client.connect();
21004
21062
  const graphqlEndpoint = `${this.httpUrl}/orchestrator/graphql`;
21005
- const environment = new Environment(client, envData, clientId, this.apiKey, graphqlEndpoint);
21063
+ const environment = new Environment(
21064
+ client,
21065
+ envData,
21066
+ clientId,
21067
+ this.apiKey,
21068
+ graphqlEndpoint
21069
+ );
21006
21070
  await environment.hello();
21007
21071
  return environment;
21008
21072
  }
@@ -21036,14 +21100,18 @@ var Granular = class _Granular {
21036
21100
  };
21037
21101
  }
21038
21102
  async publishSandboxEffectCatalog(host) {
21039
- const effects2 = Array.from(this.getSandboxEffectMap(host.sandboxId).values()).map(
21040
- (effect) => this.serializeEffect(effect)
21041
- );
21042
- const result = await host.wsClient.call("effects.publishCatalog", { effects: effects2 });
21103
+ const effects2 = Array.from(
21104
+ this.getSandboxEffectMap(host.sandboxId).values()
21105
+ ).map((effect) => this.serializeEffect(effect));
21106
+ const result = await host.wsClient.call("effects.publishCatalog", {
21107
+ effects: effects2
21108
+ });
21043
21109
  const acceptedCount = typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
21044
21110
  const rejected = Array.isArray(result?.rejected) ? result.rejected : [];
21045
21111
  if (acceptedCount === 0 && rejected.length > 0) {
21046
- const detail = rejected.map((entry) => `${entry.name || "unknown"}: ${entry.reason || "rejected"}`).join("; ");
21112
+ const detail = rejected.map(
21113
+ (entry) => `${entry.name || "unknown"}: ${entry.reason || "rejected"}`
21114
+ ).join("; ");
21047
21115
  throw new Error(
21048
21116
  `Failed to publish live effects for sandbox ${host.sandboxId}: ${detail}`
21049
21117
  );
@@ -21077,13 +21145,15 @@ var Granular = class _Granular {
21077
21145
  disconnectError
21078
21146
  );
21079
21147
  }
21080
- void this.ensureSandboxEffectHost(host.sandboxId).catch((reconnectError) => {
21081
- console.error(
21082
- `[Granular] Failed to recover effect host for sandbox ${host.sandboxId} after heartbeat failure:`,
21083
- reconnectError
21084
- );
21085
- console.error("[Granular] Original heartbeat failure:", error2);
21086
- });
21148
+ void this.ensureSandboxEffectHost(host.sandboxId).catch(
21149
+ (reconnectError) => {
21150
+ console.error(
21151
+ `[Granular] Failed to recover effect host for sandbox ${host.sandboxId} after heartbeat failure:`,
21152
+ reconnectError
21153
+ );
21154
+ console.error("[Granular] Original heartbeat failure:", error2);
21155
+ }
21156
+ );
21087
21157
  }
21088
21158
  startEffectHostHeartbeat(host) {
21089
21159
  if (host.heartbeatTimer) {
@@ -21104,9 +21174,15 @@ var Granular = class _Granular {
21104
21174
  host.heartbeatInFlight = false;
21105
21175
  });
21106
21176
  };
21107
- sendHeartbeat("[Granular] Initial effect host heartbeat failed for sandbox", false);
21177
+ sendHeartbeat(
21178
+ "[Granular] Initial effect host heartbeat failed for sandbox",
21179
+ false
21180
+ );
21108
21181
  host.heartbeatTimer = setInterval(() => {
21109
- sendHeartbeat("[Granular] Effect host heartbeat failed for sandbox", true);
21182
+ sendHeartbeat(
21183
+ "[Granular] Effect host heartbeat failed for sandbox",
21184
+ true
21185
+ );
21110
21186
  }, 1e4);
21111
21187
  }
21112
21188
  stopEffectHostHeartbeat(host) {
@@ -21138,7 +21214,12 @@ var Granular = class _Granular {
21138
21214
  const effectClientId = crypto.randomUUID();
21139
21215
  const clientId = `effect-host:${sandboxId}:${effectClientId}`;
21140
21216
  const wsClient = new WSClient({
21141
- url: buildEffectHostUrl(this.apiUrl, sandboxId, effectClientId, clientId),
21217
+ url: buildEffectHostUrl(
21218
+ this.apiUrl,
21219
+ sandboxId,
21220
+ effectClientId,
21221
+ clientId
21222
+ ),
21142
21223
  sessionId: `effect-host:${effectClientId}`,
21143
21224
  token: this.apiKey,
21144
21225
  tokenProvider: this.tokenProvider,
@@ -21157,7 +21238,10 @@ var Granular = class _Granular {
21157
21238
  };
21158
21239
  wsClient.registerRpcHandler("effect.invoke", async (params) => {
21159
21240
  const request = params;
21160
- return invokeRegisteredEffect(this.getSandboxEffectMap(sandboxId), request);
21241
+ return invokeRegisteredEffect(
21242
+ this.getSandboxEffectMap(sandboxId),
21243
+ request
21244
+ );
21161
21245
  });
21162
21246
  wsClient.on("open", () => {
21163
21247
  void this.synchronizeEffectHost(host).catch((error2) => {
@@ -21205,7 +21289,7 @@ var Granular = class _Granular {
21205
21289
  }
21206
21290
  /**
21207
21291
  * Register multiple effects (tools) for a specific sandbox.
21208
- *
21292
+ *
21209
21293
  * batch version of `registerEffect`.
21210
21294
  */
21211
21295
  async registerEffects(sandboxNameOrId, effects2) {
@@ -21219,7 +21303,7 @@ var Granular = class _Granular {
21219
21303
  }
21220
21304
  /**
21221
21305
  * Unregister an effect from a sandbox.
21222
- *
21306
+ *
21223
21307
  * Removes it from the local sandbox registry and updates the
21224
21308
  * sandbox-scoped live catalog.
21225
21309
  */
@@ -21318,27 +21402,31 @@ var Granular = class _Granular {
21318
21402
  const assignments = await this.request(
21319
21403
  `/control/subjects/${subjectId}/assignments`
21320
21404
  );
21321
- const existing = assignments.items.find(
21322
- (a) => a.sandboxId === sandboxId
21323
- );
21405
+ const existing = assignments.items.find((a) => a.sandboxId === sandboxId);
21324
21406
  if (existing) {
21325
21407
  if (existing.permissionProfileId === permissionProfileId) {
21326
21408
  return;
21327
21409
  }
21328
- await this.request(`/control/assignments/${existing.assignmentId}`, {
21329
- method: "DELETE"
21330
- });
21410
+ await this.request(
21411
+ `/control/assignments/${existing.assignmentId}`,
21412
+ {
21413
+ method: "DELETE"
21414
+ }
21415
+ );
21331
21416
  }
21332
21417
  } catch {
21333
21418
  }
21334
- await this.request(`/control/subjects/${subjectId}/assignments`, {
21335
- method: "POST",
21336
- body: JSON.stringify({
21337
- sandboxId,
21338
- subjectId,
21339
- permissionProfileId
21340
- })
21341
- });
21419
+ await this.request(
21420
+ `/control/subjects/${subjectId}/assignments`,
21421
+ {
21422
+ method: "POST",
21423
+ body: JSON.stringify({
21424
+ sandboxId,
21425
+ subjectId,
21426
+ permissionProfileId
21427
+ })
21428
+ }
21429
+ );
21342
21430
  }
21343
21431
  /**
21344
21432
  * Sandbox management API
@@ -21418,23 +21506,33 @@ var Granular = class _Granular {
21418
21506
  },
21419
21507
  get: async (environmentId) => {
21420
21508
  return normalizeEnvironmentData(
21421
- await this.request(`/control/environments/${environmentId}`)
21509
+ await this.request(
21510
+ `/control/environments/${environmentId}`
21511
+ )
21422
21512
  );
21423
21513
  },
21424
21514
  create: async (sandboxId, data) => {
21425
21515
  const environmentName = data.environment || data.envName;
21426
- return normalizeEnvironmentData(await this.request(`/control/sandboxes/${sandboxId}/environments`, {
21427
- method: "POST",
21428
- body: JSON.stringify({
21429
- ...data,
21430
- envName: environmentName
21431
- })
21432
- }));
21516
+ return normalizeEnvironmentData(
21517
+ await this.request(
21518
+ `/control/sandboxes/${sandboxId}/environments`,
21519
+ {
21520
+ method: "POST",
21521
+ body: JSON.stringify({
21522
+ ...data,
21523
+ envName: environmentName
21524
+ })
21525
+ }
21526
+ )
21527
+ );
21433
21528
  },
21434
21529
  delete: async (environmentId) => {
21435
- return this.request(`/control/environments/${environmentId}`, {
21436
- method: "DELETE"
21437
- });
21530
+ return this.request(
21531
+ `/control/environments/${environmentId}`,
21532
+ {
21533
+ method: "DELETE"
21534
+ }
21535
+ );
21438
21536
  }
21439
21537
  };
21440
21538
  }
@@ -21454,10 +21552,13 @@ var Granular = class _Granular {
21454
21552
  }
21455
21553
  if (params.since) query.set("since", params.since.toISOString());
21456
21554
  if (params.until) query.set("until", params.until.toISOString());
21457
- if (params.isAcked !== void 0) query.set("isAcked", params.isAcked ? "1" : "0");
21555
+ if (params.isAcked !== void 0)
21556
+ query.set("isAcked", params.isAcked ? "1" : "0");
21458
21557
  if (params.limit) query.set("limit", String(params.limit));
21459
21558
  if (params.offset) query.set("offset", String(params.offset));
21460
- const result = await this.request(`/control/stream-events?${query.toString()}`);
21559
+ const result = await this.request(
21560
+ `/control/stream-events?${query.toString()}`
21561
+ );
21461
21562
  return (result.items || []).map((row) => ({
21462
21563
  eventId: row.event_id,
21463
21564
  streamName: row.stream_name,
@@ -21488,7 +21589,9 @@ var Granular = class _Granular {
21488
21589
  since: cursor,
21489
21590
  limit: 100
21490
21591
  });
21491
- const orderedEvents = [...events].sort((a, b) => a.createdAt - b.createdAt);
21592
+ const orderedEvents = [...events].sort(
21593
+ (a, b) => a.createdAt - b.createdAt
21594
+ );
21492
21595
  for (const event of orderedEvents) {
21493
21596
  if (seenEventIds.has(event.eventId)) {
21494
21597
  continue;
@@ -21501,15 +21604,19 @@ var Granular = class _Granular {
21501
21604
  params.onEvent(event);
21502
21605
  }
21503
21606
  } catch (err) {
21504
- params.onError?.(err instanceof Error ? err : new Error(String(err)));
21607
+ params.onError?.(
21608
+ err instanceof Error ? err : new Error(String(err))
21609
+ );
21505
21610
  }
21506
21611
  await new Promise((resolve2) => setTimeout(resolve2, interval));
21507
21612
  }
21508
21613
  };
21509
21614
  poll();
21510
- return { unsubscribe: () => {
21511
- running = false;
21512
- } };
21615
+ return {
21616
+ unsubscribe: () => {
21617
+ running = false;
21618
+ }
21619
+ };
21513
21620
  },
21514
21621
  ack: async (eventId) => {
21515
21622
  await this.request("/control/stream-events/ack", {
@@ -21527,7 +21634,9 @@ var Granular = class _Granular {
21527
21634
  const sandbox = await this._resolveSandboxId(params.ontology);
21528
21635
  const query = new URLSearchParams({ sandboxId: sandbox });
21529
21636
  if (params.environment) query.set("environmentId", params.environment);
21530
- const result = await this.request(`/control/stream-events/stats?${query.toString()}`);
21637
+ const result = await this.request(
21638
+ `/control/stream-events/stats?${query.toString()}`
21639
+ );
21531
21640
  return (result.items || []).map((row) => ({
21532
21641
  streamName: row.stream_name,
21533
21642
  eventType: row.event_type,
@@ -21545,10 +21654,14 @@ var Granular = class _Granular {
21545
21654
  get subjects() {
21546
21655
  return {
21547
21656
  get: async (subjectId) => {
21548
- return normalizeSubject(await this.request(`/control/subjects/${subjectId}`));
21657
+ return normalizeSubject(
21658
+ await this.request(`/control/subjects/${subjectId}`)
21659
+ );
21549
21660
  },
21550
21661
  listAssignments: async (subjectId) => {
21551
- return this.request(`/control/subjects/${subjectId}/assignments`);
21662
+ return this.request(
21663
+ `/control/subjects/${subjectId}/assignments`
21664
+ );
21552
21665
  }
21553
21666
  };
21554
21667
  }
@@ -21558,24 +21671,31 @@ var Granular = class _Granular {
21558
21671
  get users() {
21559
21672
  return {
21560
21673
  create: async (data) => {
21561
- return normalizeSubject(await this.request("/control/subjects", {
21562
- method: "POST",
21563
- body: JSON.stringify({
21564
- identityId: data.id,
21565
- name: data.name,
21566
- email: data.email
21674
+ return normalizeSubject(
21675
+ await this.request("/control/subjects", {
21676
+ method: "POST",
21677
+ body: JSON.stringify({
21678
+ identityId: data.id,
21679
+ name: data.name,
21680
+ email: data.email
21681
+ })
21567
21682
  })
21568
- }));
21683
+ );
21569
21684
  },
21570
21685
  get: async (id) => {
21571
- return normalizeSubject(await this.request(`/control/subjects/${id}`));
21686
+ return normalizeSubject(
21687
+ await this.request(`/control/subjects/${id}`)
21688
+ );
21572
21689
  }
21573
21690
  };
21574
21691
  }
21575
21692
  async _resolveSandboxId(ontologyNameOrId) {
21576
21693
  if (ontologyNameOrId.startsWith("sbx_")) return ontologyNameOrId;
21577
- const result = await this.request(`/control/sandboxes?name=${encodeURIComponent(ontologyNameOrId)}`);
21578
- if (result.items.length === 0) throw new Error(`Ontology not found: ${ontologyNameOrId}`);
21694
+ const result = await this.request(
21695
+ `/control/sandboxes?name=${encodeURIComponent(ontologyNameOrId)}`
21696
+ );
21697
+ if (result.items.length === 0)
21698
+ throw new Error(`Ontology not found: ${ontologyNameOrId}`);
21579
21699
  return result.items[0].sandboxId;
21580
21700
  }
21581
21701
  /**
@@ -21590,9 +21710,9 @@ var Granular = class _Granular {
21590
21710
  const response = await fetch(url, {
21591
21711
  ...options,
21592
21712
  headers: {
21593
- "Authorization": `Bearer ${this.apiKey}`,
21713
+ Authorization: `Bearer ${this.apiKey}`,
21594
21714
  "Content-Type": "application/json",
21595
- "Connection": "close",
21715
+ Connection: "close",
21596
21716
  ...options.headers
21597
21717
  }
21598
21718
  });
@@ -21603,7 +21723,11 @@ var Granular = class _Granular {
21603
21723
  return response.json();
21604
21724
  }
21605
21725
  const errorText = await response.text();
21606
- const retryable = isRetryableLocalWorkerRestart(response.status, errorText, url);
21726
+ const retryable = isRetryableLocalWorkerRestart(
21727
+ response.status,
21728
+ errorText,
21729
+ url
21730
+ );
21607
21731
  if (retryable && attempt < LOCAL_CONTROL_REQUEST_RETRY_COUNT) {
21608
21732
  if (this.debugHttp) {
21609
21733
  console.warn(