@rool-dev/extension 0.3.6-dev.49b43e8 → 0.3.7-dev.0ed6638

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 CHANGED
@@ -183,6 +183,7 @@ These are Svelte 5 `$state` properties — use them directly in templates or `$e
183
183
  | `role` | `RoolUserRole` | User's role (`owner`, `admin`, `editor`, `viewer`) |
184
184
  | `linkAccess` | `LinkAccess` | URL sharing level |
185
185
  | `userId` | `string` | Current user's ID |
186
+ | `user` | `BridgeUser` | Current user info (`{ id, name, email }`) |
186
187
  | `isReadOnly` | `boolean` | True if viewer role |
187
188
 
188
189
  ### Object Operations
@@ -409,10 +410,20 @@ Extensions run in a sandboxed iframe (`allow-scripts allow-same-origin`). The ho
409
410
 
410
411
  The bridge protocol:
411
412
  1. Extension sends `rool:ready`
412
- 2. Host responds with `rool:init` (channel metadata, schema, space info)
413
+ 2. Host responds with `rool:init` (channel metadata, schema, space info, user identity)
413
414
  3. Extension calls channel methods → `rool:request` → host executes → `rool:response`
414
415
  4. Host pushes real-time events → `rool:event` → extension updates reactive state
415
416
 
417
+ When creating a bridge host, pass `user` so the extension can display the current user's name:
418
+
419
+ ```typescript
420
+ const host = createBridgeHost({
421
+ channel,
422
+ iframe,
423
+ user: { id: currentUser.id, name: currentUser.name, email: currentUser.email },
424
+ });
425
+ ```
426
+
416
427
  ## CLI Commands
417
428
 
418
429
  | Command | Description |
@@ -431,6 +442,7 @@ import type {
431
442
  ReactiveObject,
432
443
  ReactiveWatch,
433
444
  WatchOptions,
445
+ BridgeUser,
434
446
  RoolObject,
435
447
  RoolObjectStat,
436
448
  SpaceSchema,
@@ -71,6 +71,7 @@ export declare class DevHostController {
71
71
  registerIframe(tabId: string, el: HTMLIFrameElement): void;
72
72
  unregisterIframe(tabId: string): void;
73
73
  logout(): void;
74
+ private get _bridgeUser();
74
75
  private _bindBridge;
75
76
  private _bindAllBridges;
76
77
  private _destroyTab;
@@ -1 +1 @@
1
- {"version":3,"file":"DevHostController.d.ts","sourceRoot":"","sources":["../../src/dev/DevHostController.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAe,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAExF,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAO5D,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AAqBnD,qBAAa,iBAAiB;IAE5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAGtC,MAAM,EAAG,UAAU,CAAC;IAGpB,MAAM,EAAE,aAAa,EAAE,CAAM;IAC7B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IACrC,UAAU,EAAE,MAAM,CAAqB;IACvC,WAAW,EAAE,WAAW,CAAS;IACjC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAuB;IACrD,GAAG,EAAE,WAAW,CAAC;IACjB,mBAAmB,EAAE,sBAAsB,EAAE,CAAM;IACnD,qBAAqB,EAAE,MAAM,EAAE,CAAM;IACrC,gBAAgB,EAAE,OAAO,CAAS;IAClC,YAAY,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,CAAU;IAC5E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IACrC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGjC,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,SAAS,CAAyC;IAC1D,OAAO,CAAC,WAAW,CAAkC;IAGrD,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,KAAK,CAAsB;IAGnC,OAAO,CAAC,SAAS,CAAS;gBAGxB,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;QAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;KAC9B,EACD,QAAQ,EAAE,MAAM,IAAI,EACpB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAoB3B,IAAI,IAAI,IAAI,YAAY,EAAE,CAoBzB;IAMK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA+DrB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0DjD;;;;;;OAMG;IACG,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB1D;;;OAGG;IACH,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAiBpC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAkExB,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBnD,aAAa,IAAI,IAAI;IAUrB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,iBAAiB,GAAG,IAAI;IAK1D,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQrC,MAAM,IAAI,IAAI;IASd,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,6BAA6B;IAYrC;;;OAGG;YACW,aAAa;IA4B3B,OAAO,CAAC,YAAY;CAKrB"}
1
+ {"version":3,"file":"DevHostController.d.ts","sourceRoot":"","sources":["../../src/dev/DevHostController.ts"],"names":[],"mappings":"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"}
@@ -358,11 +358,15 @@ export class DevHostController {
358
358
  // ---------------------------------------------------------------------------
359
359
  // Private helpers
360
360
  // ---------------------------------------------------------------------------
361
+ get _bridgeUser() {
362
+ const cu = this.client.currentUser; // Always available after boot() authenticates
363
+ return { id: cu.id, name: cu.name, email: cu.email };
364
+ }
361
365
  _bindBridge(tabId) {
362
366
  const el = this.iframeEls[tabId];
363
367
  const ch = this.channels[tabId];
364
368
  if (el && ch && !this.bridgeHosts[tabId]) {
365
- this.bridgeHosts[tabId] = createBridgeHost({ channel: ch, iframe: el });
369
+ this.bridgeHosts[tabId] = createBridgeHost({ channel: ch, iframe: el, user: this._bridgeUser });
366
370
  }
367
371
  }
368
372
  _bindAllBridges() {
@@ -5638,8 +5638,8 @@ var GraphQLClient = class {
5638
5638
  }
5639
5639
  async prompt(spaceId, prompt, channelId, conversationId, options) {
5640
5640
  return (await this.request(`
5641
- mutation Prompt($spaceId: String!, $prompt: String!, $objectIds: [String!], $responseSchema: JSON, $channelId: String!, $conversationId: String!, $effort: PromptEffort, $ephemeral: Boolean, $readOnly: Boolean, $attachments: [String!], $interactionId: String!) {
5642
- prompt(spaceId: $spaceId, prompt: $prompt, objectIds: $objectIds, responseSchema: $responseSchema, channelId: $channelId, conversationId: $conversationId, effort: $effort, ephemeral: $ephemeral, readOnly: $readOnly, attachments: $attachments, interactionId: $interactionId) {
5641
+ mutation Prompt($spaceId: String!, $prompt: String!, $objectIds: [String!], $responseSchema: JSON, $channelId: String!, $conversationId: String!, $effort: PromptEffort, $ephemeral: Boolean, $readOnly: Boolean, $attachments: [String!], $interactionId: String!, $parentInteractionId: String) {
5642
+ prompt(spaceId: $spaceId, prompt: $prompt, objectIds: $objectIds, responseSchema: $responseSchema, channelId: $channelId, conversationId: $conversationId, effort: $effort, ephemeral: $ephemeral, readOnly: $readOnly, attachments: $attachments, interactionId: $interactionId, parentInteractionId: $parentInteractionId) {
5643
5643
  message
5644
5644
  modifiedObjectIds
5645
5645
  }
@@ -5655,7 +5655,8 @@ var GraphQLClient = class {
5655
5655
  ephemeral: options.ephemeral,
5656
5656
  readOnly: options.readOnly,
5657
5657
  attachments: options.attachmentUrls,
5658
- interactionId: options.interactionId
5658
+ interactionId: options.interactionId,
5659
+ parentInteractionId: options.parentInteractionId
5659
5660
  })).prompt;
5660
5661
  }
5661
5662
  async getAccount() {
@@ -7220,6 +7221,29 @@ function generateEntityId() {
7220
7221
  for (let i = 0; i < 6; i++) result += ID_CHARS[Math.floor(Math.random() * 62)];
7221
7222
  return result;
7222
7223
  }
7224
+ /** Walk from a leaf interaction up through parentId to root, return in root→leaf order. */
7225
+ function walkBranch(interactions, leafId) {
7226
+ const path = [];
7227
+ let currentId = leafId;
7228
+ while (currentId) {
7229
+ const ix = interactions[currentId];
7230
+ if (!ix) break;
7231
+ path.push(ix);
7232
+ currentId = ix.parentId;
7233
+ }
7234
+ return path.reverse();
7235
+ }
7236
+ /** Find the default leaf: the most recent interaction by timestamp that has no children. */
7237
+ function findDefaultLeaf(interactions) {
7238
+ if (!interactions || Array.isArray(interactions)) return void 0;
7239
+ const childSet = /* @__PURE__ */ new Set();
7240
+ for (const ix of Object.values(interactions)) if (ix.parentId) childSet.add(ix.parentId);
7241
+ let best;
7242
+ for (const ix of Object.values(interactions)) if (!childSet.has(ix.id)) {
7243
+ if (!best || ix.timestamp > best.timestamp) best = ix;
7244
+ }
7245
+ return best?.id;
7246
+ }
7223
7247
  var OBJECT_COLLECT_TIMEOUT = 3e4;
7224
7248
  /**
7225
7249
  * A channel is a space + channelId pair.
@@ -7260,6 +7284,7 @@ var RoolChannel = class extends EventEmitter {
7260
7284
  _objectIds;
7261
7285
  _objectStats;
7262
7286
  _hasConnected = false;
7287
+ _activeLeaves = /* @__PURE__ */ new Map();
7263
7288
  _pendingMutations = /* @__PURE__ */ new Map();
7264
7289
  _objectResolvers = /* @__PURE__ */ new Map();
7265
7290
  _objectBuffer = /* @__PURE__ */ new Map();
@@ -7350,14 +7375,62 @@ var RoolChannel = class extends EventEmitter {
7350
7375
  return this._channel?.extensionUrl ?? null;
7351
7376
  }
7352
7377
  /**
7353
- * Get interactions for the current conversation.
7378
+ * Get the active branch of the current conversation as a flat array (root → leaf).
7379
+ * Walks from the active leaf up through parentId pointers.
7354
7380
  */
7355
7381
  getInteractions() {
7356
7382
  return this._getInteractionsImpl(this._conversationId);
7357
7383
  }
7358
7384
  /** @internal */
7359
7385
  _getInteractionsImpl(conversationId) {
7360
- return this._channel?.conversations[conversationId]?.interactions ?? [];
7386
+ const interactions = this._channel?.conversations[conversationId]?.interactions;
7387
+ if (!interactions) return [];
7388
+ if (Array.isArray(interactions)) return interactions;
7389
+ const leafId = this._getActiveLeafImpl(conversationId);
7390
+ if (!leafId) return [];
7391
+ return walkBranch(interactions, leafId);
7392
+ }
7393
+ /**
7394
+ * Get the full interaction tree for a conversation as a record.
7395
+ * For clients that need to render branch navigation UI.
7396
+ */
7397
+ getTree() {
7398
+ return this._getTreeImpl(this._conversationId);
7399
+ }
7400
+ /** @internal */
7401
+ _getTreeImpl(conversationId) {
7402
+ const interactions = this._channel?.conversations[conversationId]?.interactions;
7403
+ if (!interactions || Array.isArray(interactions)) return {};
7404
+ return interactions;
7405
+ }
7406
+ /**
7407
+ * Get the active leaf interaction ID for a conversation.
7408
+ * Returns undefined if the conversation has no interactions.
7409
+ */
7410
+ get activeLeafId() {
7411
+ return this._getActiveLeafImpl(this._conversationId);
7412
+ }
7413
+ /** @internal */
7414
+ _getActiveLeafImpl(conversationId) {
7415
+ return this._activeLeaves.get(conversationId) ?? findDefaultLeaf(this._channel?.conversations[conversationId]?.interactions);
7416
+ }
7417
+ /**
7418
+ * Set the active leaf for a conversation (switch branches).
7419
+ * Emits a conversationUpdated event so reactive wrappers refresh.
7420
+ */
7421
+ setActiveLeaf(interactionId) {
7422
+ this._setActiveLeafImpl(interactionId, this._conversationId);
7423
+ }
7424
+ /** @internal */
7425
+ _setActiveLeafImpl(interactionId, conversationId) {
7426
+ const interactions = this._channel?.conversations[conversationId]?.interactions;
7427
+ if (!interactions || Array.isArray(interactions) || !interactions[interactionId]) throw new Error(`Interaction "${interactionId}" not found in conversation "${conversationId}"`);
7428
+ this._activeLeaves.set(conversationId, interactionId);
7429
+ this.emit("conversationUpdated", {
7430
+ conversationId,
7431
+ channelId: this._channelId,
7432
+ source: "local_user"
7433
+ });
7361
7434
  }
7362
7435
  /**
7363
7436
  * Get all conversations in this channel.
@@ -7371,7 +7444,7 @@ var RoolChannel = class extends EventEmitter {
7371
7444
  systemInstruction: conv.systemInstruction ?? null,
7372
7445
  createdAt: conv.createdAt,
7373
7446
  createdBy: conv.createdBy,
7374
- interactionCount: conv.interactions.length
7447
+ interactionCount: Object.keys(conv.interactions).length
7375
7448
  }));
7376
7449
  }
7377
7450
  /**
@@ -7780,7 +7853,7 @@ var RoolChannel = class extends EventEmitter {
7780
7853
  if (!this._channel.conversations[conversationId]) this._channel.conversations[conversationId] = {
7781
7854
  createdAt: Date.now(),
7782
7855
  createdBy: this._userId,
7783
- interactions: []
7856
+ interactions: {}
7784
7857
  };
7785
7858
  }
7786
7859
  /**
@@ -7822,14 +7895,17 @@ var RoolChannel = class extends EventEmitter {
7822
7895
  }
7823
7896
  /** @internal */
7824
7897
  async _promptImpl(prompt, options, conversationId) {
7825
- const { attachments, ...rest } = options ?? {};
7898
+ const { attachments, parentInteractionId: explicitParent, ...rest } = options ?? {};
7826
7899
  let attachmentUrls;
7827
7900
  if (attachments?.length) attachmentUrls = await Promise.all(attachments.map((file) => this.mediaClient.upload(this._id, file)));
7901
+ const parentInteractionId = explicitParent !== void 0 ? explicitParent : this._getActiveLeafImpl(conversationId) ?? null;
7828
7902
  const interactionId = generateEntityId();
7903
+ this._activeLeaves.set(conversationId, interactionId);
7829
7904
  const result = await this.graphqlClient.prompt(this._id, prompt, this._channelId, conversationId, {
7830
7905
  ...rest,
7831
7906
  attachmentUrls,
7832
- interactionId
7907
+ interactionId,
7908
+ parentInteractionId
7833
7909
  });
7834
7910
  const objects = [];
7835
7911
  const missing = [];
@@ -8015,6 +8091,15 @@ var RoolChannel = class extends EventEmitter {
8015
8091
  if (event.conversation) this._channel.conversations[event.conversationId] = event.conversation;
8016
8092
  else delete this._channel.conversations[event.conversationId];
8017
8093
  if (JSON.stringify(prev) === JSON.stringify(event.conversation)) break;
8094
+ if (event.conversation && !Array.isArray(event.conversation.interactions)) {
8095
+ const currentLeaf = this._getActiveLeafImpl(event.conversationId);
8096
+ if (currentLeaf) {
8097
+ for (const ix of Object.values(event.conversation.interactions)) if (ix.parentId === currentLeaf && ix.id !== currentLeaf) {
8098
+ this._activeLeaves.set(event.conversationId, ix.id);
8099
+ break;
8100
+ }
8101
+ }
8102
+ }
8018
8103
  this.emit("conversationUpdated", {
8019
8104
  conversationId: event.conversationId,
8020
8105
  channelId: event.channelId,
@@ -8123,10 +8208,22 @@ var ConversationHandle = class {
8123
8208
  get conversationId() {
8124
8209
  return this._conversationId;
8125
8210
  }
8126
- /** Get interactions for this conversation. */
8211
+ /** Get the active branch of this conversation as a flat array (root → leaf). */
8127
8212
  getInteractions() {
8128
8213
  return this._channel._getInteractionsImpl(this._conversationId);
8129
8214
  }
8215
+ /** Get the full interaction tree as a record. */
8216
+ getTree() {
8217
+ return this._channel._getTreeImpl(this._conversationId);
8218
+ }
8219
+ /** Get the active leaf interaction ID, or undefined if empty. */
8220
+ get activeLeafId() {
8221
+ return this._channel._getActiveLeafImpl(this._conversationId);
8222
+ }
8223
+ /** Switch to a different branch by setting the active leaf. */
8224
+ setActiveLeaf(interactionId) {
8225
+ this._channel._setActiveLeafImpl(interactionId, this._conversationId);
8226
+ }
8130
8227
  /** Get the system instruction for this conversation. */
8131
8228
  getSystemInstruction() {
8132
8229
  return this._channel._getSystemInstructionImpl(this._conversationId);
@@ -8871,6 +8968,9 @@ var ALLOWED_METHODS = new Set([
8871
8968
  "alterCollection",
8872
8969
  "dropCollection",
8873
8970
  "getInteractions",
8971
+ "getTree",
8972
+ "setActiveLeaf",
8973
+ "getActiveLeafId",
8874
8974
  "getConversations",
8875
8975
  "getSystemInstruction",
8876
8976
  "setSystemInstruction",
@@ -8889,6 +8989,9 @@ var ALLOWED_METHODS = new Set([
8889
8989
  ]);
8890
8990
  var CONVERSATION_METHODS = new Set([
8891
8991
  "getInteractions",
8992
+ "getTree",
8993
+ "setActiveLeaf",
8994
+ "getActiveLeafId",
8892
8995
  "getSystemInstruction",
8893
8996
  "setSystemInstruction",
8894
8997
  "renameConversation",
@@ -8903,14 +9006,17 @@ var CONVERSATION_METHODS = new Set([
8903
9006
  "setMetadata"
8904
9007
  ]);
8905
9008
  var CONVERSATION_METHOD_MAP = { "renameConversation": "rename" };
9009
+ var GETTER_MAP = { "getActiveLeafId": "activeLeafId" };
8906
9010
  var BridgeHost = class {
8907
9011
  channel;
8908
9012
  iframe;
9013
+ user;
8909
9014
  eventCleanups = [];
8910
9015
  _destroyed = false;
8911
9016
  constructor(options) {
8912
9017
  this.channel = options.channel;
8913
9018
  this.iframe = options.iframe;
9019
+ this.user = options.user;
8914
9020
  window.addEventListener("message", this._onMessage);
8915
9021
  for (const eventName of FORWARDED_EVENTS) {
8916
9022
  const handler = (data) => {
@@ -8935,6 +9041,7 @@ var BridgeHost = class {
8935
9041
  role: this.channel.role,
8936
9042
  linkAccess: this.channel.linkAccess,
8937
9043
  userId: this.channel.userId,
9044
+ user: this.user,
8938
9045
  schema: this.channel.getSchema(),
8939
9046
  metadata: this.channel.getAllMetadata()
8940
9047
  };
@@ -8969,6 +9076,7 @@ var BridgeHost = class {
8969
9076
  target = this.channel.conversation(conversationId);
8970
9077
  methodName = CONVERSATION_METHOD_MAP[method] ?? method;
8971
9078
  }
9079
+ if (GETTER_MAP[methodName]) methodName = GETTER_MAP[methodName];
8972
9080
  const fn = target[methodName];
8973
9081
  let result;
8974
9082
  if (typeof fn === "function") {
@@ -9307,12 +9415,21 @@ var DevHostController = class {
9307
9415
  this.client.logout();
9308
9416
  window.location.reload();
9309
9417
  }
9418
+ get _bridgeUser() {
9419
+ const cu = this.client.currentUser;
9420
+ return {
9421
+ id: cu.id,
9422
+ name: cu.name,
9423
+ email: cu.email
9424
+ };
9425
+ }
9310
9426
  _bindBridge(tabId) {
9311
9427
  const el = this.iframeEls[tabId];
9312
9428
  const ch = this.channels[tabId];
9313
9429
  if (el && ch && !this.bridgeHosts[tabId]) this.bridgeHosts[tabId] = createBridgeHost({
9314
9430
  channel: ch,
9315
- iframe: el
9431
+ iframe: el,
9432
+ user: this._bridgeUser
9316
9433
  });
9317
9434
  }
9318
9435
  _bindAllBridges() {