@ahmedramez-org/nexus-chat 1.0.0-beta.17 → 1.0.0-beta.18

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.
@@ -280,6 +280,24 @@ export async function checkHostContract(options, checkOptions = {}) {
280
280
  });
281
281
  ensure(new Set(chars).size === chars.length, 'a trigger is listed twice.');
282
282
  });
283
+ const sessionLink = chat?.sessionLink;
284
+ if (!sessionLink) {
285
+ checks.skip('chat.sessionLink', 'links reopen a conversation', 'No session link declared.');
286
+ }
287
+ else {
288
+ await checks.run('chat.sessionLink', 'links reopen a conversation', () => {
289
+ const link = sessionLink('contract-check-session');
290
+ let absolute = false;
291
+ try {
292
+ absolute = typeof link === 'string' && /^https?:$/.test(new URL(link).protocol);
293
+ }
294
+ catch {
295
+ // A relative path throws: the link must carry the host's origin.
296
+ }
297
+ ensure(absolute, `chat.sessionLink must return an absolute URL; received ${JSON.stringify(link)}.`);
298
+ ensure(link.includes('contract-check-session'), 'chat.sessionLink must carry the conversation id.');
299
+ });
300
+ }
283
301
  await checks.run('actions', 'each action has can() and run()', () => {
284
302
  Object.entries(actions ?? {}).forEach(([name, action]) => {
285
303
  if (action === undefined)
@@ -292,6 +292,13 @@ export interface NexusChatChat {
292
292
  beforeSend?(request: {
293
293
  prompt: string;
294
294
  }): SendAddition | Promise<SendAddition>;
295
+ /**
296
+ * The absolute URL that reopens a saved conversation in this host (the
297
+ * instance root plus the conversation id, for example
298
+ * `https://host/incorta/?chat-session-id=<id>`, in the page query before any hash route, which in-app redirects never drop). The host reads that URL
299
+ * back and calls `handle.openSession`. Absent: no Copy link.
300
+ */
301
+ sessionLink?(sessionId: string): string;
295
302
  }
296
303
  export type OpenIntent = {
297
304
  type: 'open-dashboard';
@@ -456,6 +463,13 @@ export interface NexusChatHandle {
456
463
  * gates: the agent must support the kind; `false` when refused).
457
464
  */
458
465
  attach(kind: Exclude<ContextKind, 'file'>, item: ContextItem): boolean;
466
+ /**
467
+ * Opens a saved conversation by its id (a `chat.sessionLink` the host read
468
+ * back from its URL). A conversation with no messages, or one the backend
469
+ * refuses (deleted, someone else's), stays closed and the chat says so.
470
+ * While an unsent question is still being recovered nothing opens.
471
+ */
472
+ openSession(sessionId: string): void;
459
473
  }
460
474
  /** The federated entry point `nexusChat/mount`. */
461
475
  export type NexusChatMount = (element: HTMLElement, options: NexusChatOptions) => NexusChatHandle;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ahmedramez-org/nexus-chat",
3
- "version": "1.0.0-beta.17",
3
+ "version": "1.0.0-beta.18",
4
4
  "description": "NexusChat for any app: a connector and React component that load the prebuilt chat from IncortaCopilot (or a pinned copy), and the host contract types and checks.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {