@robono/server 0.23.1 → 0.25.0

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.
Files changed (74) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/HISTORY-IMPORT.md +97 -0
  3. package/HOSTED.md +241 -0
  4. package/README.md +28 -3
  5. package/SBOM.spdx.json +9 -9
  6. package/dist/calling-session-handle.d.ts.map +1 -1
  7. package/dist/calling-session-handle.js +1 -0
  8. package/dist/calling-session-handle.js.map +1 -1
  9. package/dist/history-import-cli.d.ts +11 -0
  10. package/dist/history-import-cli.d.ts.map +1 -0
  11. package/dist/history-import-cli.js +83 -0
  12. package/dist/history-import-cli.js.map +1 -0
  13. package/dist/history-import.d.ts +64 -0
  14. package/dist/history-import.d.ts.map +1 -0
  15. package/dist/history-import.js +69 -0
  16. package/dist/history-import.js.map +1 -0
  17. package/dist/hosted-sessions.d.ts +38 -0
  18. package/dist/hosted-sessions.d.ts.map +1 -0
  19. package/dist/hosted-sessions.js +68 -0
  20. package/dist/hosted-sessions.js.map +1 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +2 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/managed-media.d.ts +2 -1
  26. package/dist/managed-media.d.ts.map +1 -1
  27. package/dist/managed-media.js +1 -1
  28. package/dist/managed-media.js.map +1 -1
  29. package/dist/messaging-notification-providers.d.ts +51 -1
  30. package/dist/messaging-notification-providers.d.ts.map +1 -1
  31. package/dist/messaging-notification-providers.js +28 -5
  32. package/dist/messaging-notification-providers.js.map +1 -1
  33. package/dist/messaging-notifications.d.ts +2 -0
  34. package/dist/messaging-notifications.d.ts.map +1 -1
  35. package/dist/messaging-push-worker.d.ts.map +1 -1
  36. package/dist/messaging-push-worker.js +3 -2
  37. package/dist/messaging-push-worker.js.map +1 -1
  38. package/dist/messenger-check.d.ts +1 -0
  39. package/dist/messenger-check.d.ts.map +1 -1
  40. package/dist/messenger-check.js +7 -5
  41. package/dist/messenger-check.js.map +1 -1
  42. package/dist/messenger-connected-templates.js +15 -15
  43. package/dist/messenger-connected-templates.js.map +1 -1
  44. package/dist/messenger-framework-templates.d.ts +3 -0
  45. package/dist/messenger-framework-templates.d.ts.map +1 -0
  46. package/dist/messenger-framework-templates.js +68 -0
  47. package/dist/messenger-framework-templates.js.map +1 -0
  48. package/dist/messenger-hosted-install.d.ts +3 -0
  49. package/dist/messenger-hosted-install.d.ts.map +1 -0
  50. package/dist/messenger-hosted-install.js +107 -0
  51. package/dist/messenger-hosted-install.js.map +1 -0
  52. package/dist/messenger-hosted-templates.d.ts +6 -0
  53. package/dist/messenger-hosted-templates.d.ts.map +1 -0
  54. package/dist/messenger-hosted-templates.js +84 -0
  55. package/dist/messenger-hosted-templates.js.map +1 -0
  56. package/dist/messenger-init.d.ts.map +1 -1
  57. package/dist/messenger-init.js +8 -14
  58. package/dist/messenger-init.js.map +1 -1
  59. package/dist/messenger-install-cli.js +10 -7
  60. package/dist/messenger-install-cli.js.map +1 -1
  61. package/dist/messenger-install.d.ts +24 -1
  62. package/dist/messenger-install.d.ts.map +1 -1
  63. package/dist/messenger-install.js +32 -15
  64. package/dist/messenger-install.js.map +1 -1
  65. package/dist/messenger-node.d.ts.map +1 -1
  66. package/dist/messenger-node.js +1 -0
  67. package/dist/messenger-node.js.map +1 -1
  68. package/dist/messenger-upgrade.js +1 -1
  69. package/dist/messenger-upgrade.js.map +1 -1
  70. package/dist/messenger.d.ts +5 -1
  71. package/dist/messenger.d.ts.map +1 -1
  72. package/dist/messenger.js +14 -8
  73. package/dist/messenger.js.map +1 -1
  74. package/package.json +6 -3
@@ -1,8 +1,9 @@
1
1
  /** Served from the customer's existing combined route; never replaces their PWA worker. */
2
2
  export const messagingPushWorkerSource = String.raw `
3
3
  'use strict';
4
+ const databaseName='robono-notifications:'+self.registration.scope;
4
5
  const store=async(value,write=false)=>new Promise((resolve,reject)=>{
5
- const request=indexedDB.open('robono-notifications',1);
6
+ const request=indexedDB.open(databaseName,1);
6
7
  request.onupgradeneeded=()=>request.result.createObjectStore('state');
7
8
  request.onerror=()=>reject(Error('Notification storage unavailable'));
8
9
  request.onsuccess=()=>{const db=request.result,tx=db.transaction('state',write?'readwrite':'readonly'),s=tx.objectStore('state');
@@ -10,7 +11,7 @@ const store=async(value,write=false)=>new Promise((resolve,reject)=>{
10
11
  });
11
12
  // Keep dismissal ordering across worker restarts. Provider delivery order is not guaranteed.
12
13
  const callOrder=async(d)=>new Promise((resolve,reject)=>{
13
- const request=indexedDB.open('robono-notifications',1);
14
+ const request=indexedDB.open(databaseName,1);
14
15
  request.onupgradeneeded=()=>request.result.createObjectStore('state');
15
16
  request.onerror=()=>reject(Error('Notification storage unavailable'));
16
17
  request.onsuccess=()=>{const db=request.result,tx=db.transaction('state','readwrite'),s=tx.objectStore('state'),read=s.get('calls');let allowed=false;
@@ -1 +1 @@
1
- {"version":3,"file":"messaging-push-worker.js","sourceRoot":"","sources":["../src/messaging-push-worker.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,CAAC,MAAM,yBAAyB,GAAC,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDhD,CAAC"}
1
+ {"version":3,"file":"messaging-push-worker.js","sourceRoot":"","sources":["../src/messaging-push-worker.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,CAAC,MAAM,yBAAyB,GAAC,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDhD,CAAC"}
@@ -8,6 +8,7 @@ export declare function checkRobonoMessengerSetup(options: {
8
8
  endpoint: string;
9
9
  accessToken: string;
10
10
  origin: string;
11
+ workerUrl?: string;
11
12
  fetch?: typeof fetch;
12
13
  }): Promise<MessengerSetupCheck[]>;
13
14
  //# sourceMappingURL=messenger-check.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messenger-check.d.ts","sourceRoot":"","sources":["../src/messenger-check.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAAE,IAAI,EAAC,MAAM,CAAC;IAAA,MAAM,EAAC,QAAQ,GAAC,QAAQ,GAAC,cAAc,CAAC;IAAA,MAAM,EAAC,MAAM,CAAA;CAAC;AACxG,kGAAkG;AAClG,wBAAsB,yBAAyB,CAAC,OAAO,EAAC;IAAC,QAAQ,EAAC,MAAM,CAAC;IAAA,WAAW,EAAC,MAAM,CAAC;IAAA,MAAM,EAAC,MAAM,CAAC;IAAA,KAAK,CAAC,EAAC,OAAO,KAAK,CAAA;CAAC,GAAE,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAiB7J"}
1
+ {"version":3,"file":"messenger-check.d.ts","sourceRoot":"","sources":["../src/messenger-check.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAAE,IAAI,EAAC,MAAM,CAAC;IAAA,MAAM,EAAC,QAAQ,GAAC,QAAQ,GAAC,cAAc,CAAC;IAAA,MAAM,EAAC,MAAM,CAAA;CAAC;AACxG,kGAAkG;AAClG,wBAAsB,yBAAyB,CAAC,OAAO,EAAC;IAAC,QAAQ,EAAC,MAAM,CAAC;IAAA,WAAW,EAAC,MAAM,CAAC;IAAA,MAAM,EAAC,MAAM,CAAC;IAAA,SAAS,CAAC,EAAC,MAAM,CAAC;IAAA,KAAK,CAAC,EAAC,OAAO,KAAK,CAAA;CAAC,GAAE,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAiB/K"}
@@ -1,8 +1,8 @@
1
1
  /** Runs from the customer's computer/server. Never sends their login token to Robono's portal. */
2
2
  export async function checkRobonoMessengerSetup(options) {
3
- const url = new URL(options.endpoint), origin = new URL(options.origin);
4
- if (url.username || url.password || url.hash || url.origin !== origin.origin || origin.origin !== options.origin || !(url.protocol === 'https:' || url.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname)))
5
- throw Error('Use your exact website origin and an HTTPS messaging route on that origin (localhost may use HTTP).');
3
+ const url = new URL(options.endpoint), origin = new URL(options.origin), hosted = /^https:\/\/(?:[a-z0-9-]+\.)?api\.robono\.com\/v1\/messenger$/.test(options.endpoint);
4
+ if (url.username || url.password || url.hash || !hosted && url.origin !== origin.origin || origin.origin !== options.origin || !(url.protocol === 'https:' || url.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname)))
5
+ throw Error('Use your exact website origin and your HTTPS messaging route or Robono hosted endpoint (localhost may use HTTP).');
6
6
  if (!options.accessToken.trim())
7
7
  throw Error('Supply a test user’s current login token, not your Robono network key.');
8
8
  const request = options.fetch ?? fetch, checks = [];
@@ -17,9 +17,11 @@ export async function checkRobonoMessengerSetup(options) {
17
17
  await run('Website protection', async () => { const r = await post({ operation: 'settings' }, true, 'https://robono-invalid-origin.example'); return { status: r.status === 403 ? 'passed' : 'failed', detail: r.status === 403 ? 'Other websites are rejected.' : 'Reject unknown browser origins; do not use a wildcard.' }; });
18
18
  await run('Signed-in messaging', async () => { const r = await post({ operation: 'settings' }), d = await r.json(); return { status: r.ok && d.settings ? 'passed' : 'failed', detail: r.ok && d.settings ? 'The test user can load messaging settings.' : 'Connect the test user’s sign-in and current messaging permission.' }; });
19
19
  await run('Contacts and conversations', async () => { const r = await post({ operation: 'conversations' }), d = await r.json(); const rows = d.conversations; return { status: !r.ok || !Array.isArray(rows) ? 'failed' : rows.length ? 'passed' : 'needs-action', detail: !r.ok || !Array.isArray(rows) ? 'The signed-in user cannot load chats.' : rows.length ? 'Authorized chats are available.' : 'Connect a second test user and synchronize their permitted relationship.' }; });
20
- await run('Server-only operations', async () => { const r = await post({ operation: 'erase-user', userId: 'robono-check-never-delete' }); return { status: r.status === 403 ? 'passed' : 'failed', detail: r.status === 403 ? 'Account deletion is blocked from the public chat route.' : 'The browser route must reject server-only account operations.' }; });
20
+ await run('Server-only operations', async () => { const r = await post({ operation: 'report-list' }); return { status: r.status === 403 ? 'passed' : 'failed', detail: r.status === 403 ? 'Server-only administration is blocked from the public chat route.' : 'The browser route must reject server-only account operations.' }; });
21
21
  await run('Notification connection', async () => { const r = await post({ operation: 'notification-status' }, true, options.origin, 'notifications'), d = await r.json(); return { status: !r.ok || !Array.isArray(d.providers) ? 'failed' : d.providers.length ? 'passed' : 'needs-action', detail: !r.ok ? 'Update the server package and enable managed notifications.' : d.providers?.length ? 'Connected providers: ' + d.providers.filter((name) => ['apns', 'fcm', 'web', 'apple', 'google'].includes(String(name))).join(', ') + '. A real background alert still needs testing.' : 'Connect website, Apple or Google settings in Your app → Message notifications.' }; });
22
- await run('Browser notification helper', async () => { const u = new URL(url); u.searchParams.set('service', 'push-worker'); const r = await request(u, { redirect: 'error', signal: AbortSignal.timeout(15000) }); const ok = r.ok && r.headers.get('content-type')?.includes('javascript') && r.headers.get('service-worker-allowed') === '/robono-notifications/'; return { status: ok ? 'passed' : 'needs-action', detail: ok ? 'Your route serves the browser helper without replacing an existing worker.' : 'For browser alerts, mount GET as well as POST on the combined route.' }; });
22
+ await run('Browser notification helper', async () => { const u = hosted ? new URL(options.workerUrl ?? '/robono-notifications/worker.js', origin) : new URL(url); if (!hosted)
23
+ u.searchParams.set('service', 'push-worker'); if (u.origin !== origin.origin || u.username || u.password)
24
+ throw Error('The browser helper must be on your website.'); const r = await request(u, { redirect: 'error', signal: AbortSignal.timeout(15000) }); const ok = r.ok && r.headers.get('content-type')?.includes('javascript') && (hosted && u.pathname === '/robono-notifications/worker.js' || r.headers.get('service-worker-allowed') === '/robono-notifications/'); return { status: ok ? 'passed' : 'needs-action', detail: ok ? 'Your route serves the browser helper without replacing an existing worker.' : hosted ? 'Publish the included public/robono-notifications/worker.js on your website.' : 'For browser alerts, mount GET as well as POST on the combined route.' }; });
23
25
  await run('Call configuration', async () => { const r = await post({ operation: 'setup' }, true, options.origin, 'calling'), d = await r.json(); return { status: r.ok && d.features ? 'passed' : 'failed', detail: r.ok && d.features ? (d.features.voice || d.features.video ? 'The supplied call screens can read the selected voice/video options. A real call still needs testing.' : 'Calling is not selected for this project.') : 'Connect calling permissions on the combined route and update the server package.' }; });
24
26
  await run('Maps connection', async () => { const r = await post({ operation: 'settings' }, true, options.origin, 'location'), d = await r.json(); return { status: r.ok && d.settings ? 'passed' : 'failed', detail: r.ok && d.settings ? (d.settings.enabled ? 'Maps settings load through the same signed-in route. Register the website or both phone app IDs in Maps setup before opening real maps.' : 'Maps is not selected for this project.') : 'Connect location permissions on the combined route and update the server package.' }; });
25
27
  return checks;
@@ -1 +1 @@
1
- {"version":3,"file":"messenger-check.js","sourceRoot":"","sources":["../src/messenger-check.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"messenger-check.js","sourceRoot":"","sources":["../src/messenger-check.ts"],"names":[],"mappings":"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"}
@@ -26,14 +26,11 @@ const provider=getApps().find(app=>app.name==='robono-auth')??initializeApp({cre
26
26
  verify=firebaseMessengerAuthentication(getAuth(provider));
27
27
  return verify(request);
28
28
  }`;
29
- files['server/robono-access.ts'] = `import type {MessengerAccess} from '@robono/server';\n${setup}\n\n// Keep YOUR current eligibility, suspension and membership checks here.
30
- // Signing in does not grant permission to every conversation.
31
- // Account-level settings and calling.session/calling.setup have no conversation ID.
32
- // Chat calls, media and extras need their own current permissions; location uses
33
- // directed viewer grants. Do not treat every operation as sending a text.
34
- export async function authorize(access:MessengerAccess):Promise<boolean>{
35
- throw Error('Connect your existing messaging permission check in robono-access.ts');
36
- }
29
+ files['server/robono-access.ts'] = `${setup}\n
30
+ // Robono checks your server-supplied contacts, group memberships and location
31
+ // grants. Add extra customer-specific restrictions with authorize in robono.ts
32
+ // only when your application needs them. Keep suspended accounts revoked.
33
+ export const authorize = undefined;
37
34
  `;
38
35
  files['.env.example'] += provider === 'supabase' ? '# Existing NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY\n# (or NEXT_PUBLIC_SUPABASE_ANON_KEY) are reused when present. Otherwise set:\n# SUPABASE_URL=\n# SUPABASE_PUBLISHABLE_KEY=\n' : '# Server only: path to your existing Firebase service-account file, or workload identity.\nGOOGLE_APPLICATION_CREDENTIALS=\n';
39
36
  }
@@ -85,17 +82,20 @@ export interface RobonoAccounts {
85
82
  /** Keep mounted within your signed-in app. No second login or copied session is required. */
86
83
  export function ConnectedRobonoChat({accounts,...props}:Omit<ChatProps,'userId'|'getAccessToken'|'onReady'|'onSignOut'>&{accounts:RobonoAccounts}){
87
84
  const [account,setAccount]=useState<RobonoAccount|null>(null),current=useRef<RobonoAccount|null>(null);
88
- const sourceVersion=useRef(0),[version,setVersion]=useState(0);
85
+ const sourceVersion=useRef(0),transition=useRef(0),cleanup=useRef<Promise<unknown>>(Promise.resolve()),[version,setVersion]=useState(0);
89
86
  const chat=useRef<Parameters<NonNullable<ChatProps['onReady']>>[0]>(null);
90
87
  useEffect(()=>{
91
- let live=true;setVersion(++sourceVersion.current);
92
- if(current.current){void chat.current?.signOut().catch(()=>{});chat.current=null;current.current=null;setAccount(null);}
88
+ let live=true;setVersion(++sourceVersion.current);setAccount(null);current.current=null;
89
+ const closePrevious=()=>{const previous=chat.current;chat.current=null;if(previous){const closing=previous.signOut();cleanup.current=Promise.allSettled([cleanup.current,closing]);}};
90
+ closePrevious();
93
91
  const off=accounts.subscribe(next=>{
94
92
  if(!live)return;
95
- if(current.current?.id!==next?.id){void chat.current?.signOut().catch(()=>{});chat.current=null;}
96
- current.current=next;setAccount(next);
93
+ if(current.current?.id===next?.id){current.current=next;setAccount(previous=>previous?next:null);return;}
94
+ const change=++transition.current;closePrevious();current.current=next;setAccount(null);
95
+ // Finish old notification/sharing cleanup before the next account registers.
96
+ void cleanup.current.then(()=>{if(live&&change===transition.current)setAccount(current.current);});
97
97
  });
98
- return()=>{live=false;sourceVersion.current++;current.current=null;off();};
98
+ return()=>{live=false;sourceVersion.current++;transition.current++;current.current=null;closePrevious();off();};
99
99
  },[accounts]);
100
100
  const token=async()=>{const active=current.current;if(!active||active.id!==account?.id||sourceVersion.current!==version)throw Error('Account changed.');const value=await active.getAccessToken();if(current.current?.id!==active.id||sourceVersion.current!==version)throw Error('Account changed.');return value;};
101
101
  return account?<RobonoChat key={version+':'+account.id} {...props} userId={account.id} getAccessToken={token} onReady={value=>{chat.current=value;}} onSignOut={async()=>{try{await chat.current?.signOut();}finally{await accounts.signOut();}}}/>:null;
@@ -134,7 +134,7 @@ export function robonoAccounts(auth:Auth):RobonoAccounts{
134
134
  }}:null),()=>listener(null));},signOut:()=>signOut(auth)};
135
135
  }
136
136
  `;
137
- files['ROBONO-SETUP.md'] += `\n## Connected accounts\n${provider === 'custom' ? 'Implement the small RobonoAccounts interface using your existing verified sign-in client.' : 'Import CustomerMessenger and pass your existing ' + (provider === 'supabase' ? 'Supabase client' : 'Firebase Auth instance') + ' as auth. The account wrapper is included.'} Pass your current contact dictionary as contacts; names and avatars update without restarting the chat. The connected screen listens for sign-in, sign-out and account switching. It uses a fresh token for each request and never substitutes one account’s token for another.\n\nKeep CustomerMessenger mounted in your signed-in application. Add setupChecks during development for a connection check using your existing login; no copied tokens are needed. The panel is hidden in production. Keep your own account suspension and permission checks in robono-access.ts; provider identity verification does not replace them. Missing permission code intentionally denies access. For explicit host sign-out, unregister messaging before revoking your session when possible. If the provider session has already expired, local content is still cleared; synchronize revoked account access on the server so notifications are also blocked.\n`;
137
+ files['ROBONO-SETUP.md'] += `\n## Connected accounts\n${provider === 'custom' ? 'Implement the small RobonoAccounts interface using your existing verified sign-in client.' : 'Import CustomerMessenger and pass your existing ' + (provider === 'supabase' ? 'Supabase client' : 'Firebase Auth instance') + ' as auth. The account wrapper is included.'} Pass your current contact dictionary as contacts; names and avatars update without restarting the chat. The connected screen listens for sign-in, sign-out and account switching. It uses a fresh token for each request and never substitutes one account’s token for another.\n\nKeep CustomerMessenger mounted in your signed-in application. Add setupChecks during development for a connection check using your existing login; no copied tokens are needed. The panel is hidden in production. The standard permissions:'robono' mode enforces the contacts, group membership, feature permissions and Maps sharing grants you synchronize with Robono. No per-button permission handler is needed. Keep your sign-in account suspension current. Add authorize in robono.ts only for additional business restrictions. For explicit host sign-out, unregister messaging before revoking your session when possible. If the provider session has already expired, local content is still cleared; synchronize revoked account access on the server so notifications are also blocked.\n`;
138
138
  Object.assign(files, customerMessengerTemplates(options));
139
139
  return files;
140
140
  }
@@ -1 +1 @@
1
- {"version":3,"file":"messenger-connected-templates.js","sourceRoot":"","sources":["../src/messenger-connected-templates.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,0BAA0B,EAAC,MAAM,mCAAmC,CAAC;AAE7E,MAAM,UAAU,uBAAuB,CAAC,KAA2B,EAAC,OAA+B;IAClG,MAAM,QAAQ,GAAC,OAAO,CAAC,IAAI,IAAE,QAAQ,EAAC,GAAG,GAAC,OAAO,CAAC,QAAQ,KAAG,KAAK,EAAC,CAAC,GAAC,IAAI,CAAC,SAAS,CAAC;IACpF,IAAG,CAAC,CAAC,QAAQ,EAAC,UAAU,EAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAC,MAAM,KAAK,CAAC,8CAA8C,CAAC,CAAC;IACpH,IAAG,QAAQ,KAAG,QAAQ,EAAC,CAAC;QACvB,MAAM,KAAK,GAAC,QAAQ,KAAG,UAAU,CAAA,CAAC,CAAA;;;;;;;;;;;EAWlC,CAAA,CAAC,CAAA;;;;;;;;;;EAUD,CAAC;QACD,KAAK,CAAC,yBAAyB,CAAC,GAAC,yDAAyD,KAAK;;;;;;;;CAQhG,CAAC;QACA,KAAK,CAAC,cAAc,CAAC,IAAE,QAAQ,KAAG,UAAU,CAAA,CAAC,CAAA,4MAA4M,CAAA,CAAC,CAAA,8HAA8H,CAAC;IAC1X,CAAC;IACD,KAAK,CAAC,uBAAuB,CAAC,GAAC,GAAG,CAAA,CAAC,CAAA;;;;;;;;;;;wFAWoD,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;;;;;;;CAO7G,CAAA,CAAC,CAAA;;;;;;;;mDAQiD,CAAC,CAAC,OAAO,CAAC,MAAM,GAAC,aAAa,CAAC;;;;;6EAKL,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;;CAElG,CAAC;IACD,KAAK,CAAC,gCAAgC,CAAC,GAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCxC,CAAC;IACD,IAAG,QAAQ,KAAG,UAAU;QAAC,KAAK,CAAC,2BAA2B,CAAC,GAAC;;;;;;;;;;;;;;;;CAgB5D,CAAC;IACD,IAAG,QAAQ,KAAG,UAAU;QAAC,KAAK,CAAC,2BAA2B,CAAC,GAAC;;;;;;;;;;CAU5D,CAAC;IACD,KAAK,CAAC,iBAAiB,CAAC,IAAE,4BAA4B,QAAQ,KAAG,QAAQ,CAAA,CAAC,CAAA,2FAA2F,CAAA,CAAC,CAAA,kDAAkD,GAAC,CAAC,QAAQ,KAAG,UAAU,CAAA,CAAC,CAAA,iBAAiB,CAAA,CAAC,CAAA,wBAAwB,CAAC,GAAC,4CAA4C,+5BAA+5B,CAAC;IACxuC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC;IACzD,OAAO,KAAK,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"messenger-connected-templates.js","sourceRoot":"","sources":["../src/messenger-connected-templates.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,0BAA0B,EAAC,MAAM,mCAAmC,CAAC;AAE7E,MAAM,UAAU,uBAAuB,CAAC,KAA2B,EAAC,OAA+B;IAClG,MAAM,QAAQ,GAAC,OAAO,CAAC,IAAI,IAAE,QAAQ,EAAC,GAAG,GAAC,OAAO,CAAC,QAAQ,KAAG,KAAK,EAAC,CAAC,GAAC,IAAI,CAAC,SAAS,CAAC;IACpF,IAAG,CAAC,CAAC,QAAQ,EAAC,UAAU,EAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAC,MAAM,KAAK,CAAC,8CAA8C,CAAC,CAAC;IACpH,IAAG,QAAQ,KAAG,QAAQ,EAAC,CAAC;QACvB,MAAM,KAAK,GAAC,QAAQ,KAAG,UAAU,CAAA,CAAC,CAAA;;;;;;;;;;;EAWlC,CAAA,CAAC,CAAA;;;;;;;;;;EAUD,CAAC;QACD,KAAK,CAAC,yBAAyB,CAAC,GAAC,GAAG,KAAK;;;;;CAK1C,CAAC;QACA,KAAK,CAAC,cAAc,CAAC,IAAE,QAAQ,KAAG,UAAU,CAAA,CAAC,CAAA,4MAA4M,CAAA,CAAC,CAAA,8HAA8H,CAAC;IAC1X,CAAC;IACD,KAAK,CAAC,uBAAuB,CAAC,GAAC,GAAG,CAAA,CAAC,CAAA;;;;;;;;;;;wFAWoD,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;;;;;;;CAO7G,CAAA,CAAC,CAAA;;;;;;;;mDAQiD,CAAC,CAAC,OAAO,CAAC,MAAM,GAAC,aAAa,CAAC;;;;;6EAKL,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;;CAElG,CAAC;IACD,KAAK,CAAC,gCAAgC,CAAC,GAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCxC,CAAC;IACD,IAAG,QAAQ,KAAG,UAAU;QAAC,KAAK,CAAC,2BAA2B,CAAC,GAAC;;;;;;;;;;;;;;;;CAgB5D,CAAC;IACD,IAAG,QAAQ,KAAG,UAAU;QAAC,KAAK,CAAC,2BAA2B,CAAC,GAAC;;;;;;;;;;CAU5D,CAAC;IACD,KAAK,CAAC,iBAAiB,CAAC,IAAE,4BAA4B,QAAQ,KAAG,QAAQ,CAAA,CAAC,CAAA,2FAA2F,CAAA,CAAC,CAAA,kDAAkD,GAAC,CAAC,QAAQ,KAAG,UAAU,CAAA,CAAC,CAAA,iBAAiB,CAAA,CAAC,CAAA,wBAAwB,CAAC,GAAC,4CAA4C,iiCAAiiC,CAAC;IAC12C,MAAM,CAAC,MAAM,CAAC,KAAK,EAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC;IACzD,OAAO,KAAK,CAAC;AACd,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Thin host-framework adapters; all chat behavior remains the supplied UI. */
2
+ export declare function hostedFrameworkFiles(tokenEndpoint: string, companyName: string, framework: 'vue' | 'svelte' | 'angular' | 'browser'): Record<string, string>;
3
+ //# sourceMappingURL=messenger-framework-templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messenger-framework-templates.d.ts","sourceRoot":"","sources":["../src/messenger-framework-templates.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAAC,aAAa,EAAC,MAAM,EAAC,WAAW,EAAC,MAAM,EAAC,SAAS,EAAC,KAAK,GAAC,QAAQ,GAAC,SAAS,GAAC,SAAS,0BA8DxH"}
@@ -0,0 +1,68 @@
1
+ /** Thin host-framework adapters; all chat behavior remains the supplied UI. */
2
+ export function hostedFrameworkFiles(tokenEndpoint, companyName, framework) {
3
+ const files = {};
4
+ files['mount.ts'] = `import {mountHostedRobonoMessenger} from '@robono/messaging-web';
5
+ import {hostedRobonoTokenProvider,createRobonoLocalizer,type RobonoLocale} from '@robono/messaging';
6
+ export type {RobonoLocale} from '@robono/messaging';
7
+ export interface MessengerAccount {userId:string;getAccessToken:()=>Promise<string>}
8
+ export type Contacts=Record<string,{name:string;avatarUrl?:string;phoneNumber?:string}>;
9
+ export function createMessengerMount(element:HTMLElement,onError:(message:string)=>void){
10
+ let generation=0,account:MessengerAccount|null=null,chat:Awaited<ReturnType<typeof mountHostedRobonoMessenger>>|null=null,contacts:Contacts={},interfaceLocale:RobonoLocale|undefined,pending:AbortController|null=null,cleanup:Promise<unknown>=Promise.resolve();
11
+ const mount={
12
+ update(next:MessengerAccount|null,people:Contacts={},locale?:RobonoLocale){
13
+ interfaceLocale=locale;contacts=people;if(account?.userId===next?.userId){account=next;chat?.updateContacts(contacts);chat?.updateLocale(interfaceLocale);return;}
14
+ const version=++generation;pending?.abort();const previous=chat;chat=null;account=next;
15
+ if(previous)cleanup=Promise.allSettled([cleanup,previous.signOut()]);if(!next)return;
16
+ const controller=new AbortController();pending=controller;onError('');
17
+ const getAccessToken=async()=>{if(generation!==version||account?.userId!==next.userId)throw Error('Account changed.');const token=await account.getAccessToken();if(generation!==version)throw Error('Account changed.');return token;};
18
+ void cleanup.then(()=>{if(controller.signal.aborted)throw Error('Account changed.');return mountHostedRobonoMessenger(element,{userId:next.userId,companyName:${JSON.stringify(companyName)},contacts,interfaceLocale,signal:controller.signal,tokenProvider:hostedRobonoTokenProvider({tokenEndpoint:${JSON.stringify(tokenEndpoint)},getAccessToken})});}).then(value=>{if(generation!==version){void value.signOut().catch(()=>{});return;}chat=value;chat.updateContacts(contacts);chat.updateLocale(interfaceLocale);}).catch(()=>{if(generation===version)onError(createRobonoLocalizer(interfaceLocale).text('Could not connect to messaging. Check your sign-in connection.'));}).finally(()=>{if(generation===version)pending=null;});
19
+ },
20
+ text(source:string){return createRobonoLocalizer(interfaceLocale).text(source);},
21
+ retry(){const previous=account;account=null;mount.update(previous,contacts,interfaceLocale);},
22
+ dispose(){generation++;pending?.abort();chat?.unmount();chat=null;account=null;},
23
+ };
24
+ return mount;
25
+ }
26
+ `;
27
+ if (framework === 'vue')
28
+ files['RobonoMessenger.vue'] = `<script setup lang="ts">
29
+ import {ref,onMounted,onBeforeUnmount,watch} from 'vue';
30
+ import {createMessengerMount,type MessengerAccount,type Contacts,type RobonoLocale} from './mount';
31
+ const props=defineProps<{account:MessengerAccount|null;contacts?:Contacts;interfaceLocale?:RobonoLocale}>();
32
+ const element=ref<HTMLElement|null>(null),error=ref('');let mount:ReturnType<typeof createMessengerMount>|undefined;
33
+ onMounted(()=>{mount=createMessengerMount(element.value!,value=>error.value=value);mount.update(props.account,props.contacts,props.interfaceLocale);});
34
+ watch(()=>[props.account,props.contacts,props.interfaceLocale] as const,()=>mount?.update(props.account,props.contacts,props.interfaceLocale),{deep:true});
35
+ onBeforeUnmount(()=>mount?.dispose());
36
+ </script>
37
+ <template><div class="robono"><p v-if="error" role="alert">{{error}} <button type="button" @click="mount?.retry()">{{mount?.text('Retry')??'Retry'}}</button></p><div ref="element" class="chat"/></div></template>
38
+ <style scoped>.robono,.chat{height:100%;min-height:400px}</style>
39
+ `;
40
+ if (framework === 'svelte')
41
+ files['RobonoMessenger.svelte'] = `<script lang="ts">
42
+ import {onMount} from 'svelte';
43
+ import {createMessengerMount,type MessengerAccount,type Contacts,type RobonoLocale} from './mount';
44
+ export let account:MessengerAccount|null=null;export let contacts:Contacts={};export let interfaceLocale:RobonoLocale|undefined=undefined;
45
+ let element:HTMLDivElement,error='',mount:ReturnType<typeof createMessengerMount>|undefined;
46
+ onMount(()=>{mount=createMessengerMount(element,value=>error=value);mount.update(account,contacts,interfaceLocale);return()=>mount?.dispose();});
47
+ $: mount?.update(account,contacts,interfaceLocale);
48
+ </script>
49
+ {#if error}<p role="alert">{error} <button type="button" on:click={()=>mount?.retry()}>{mount?.text('Retry')??'Retry'}</button></p>{/if}
50
+ <div bind:this={element} style="height:100%;min-height:400px"></div>
51
+ `;
52
+ if (framework === 'angular')
53
+ files['robono-messenger.component.ts'] = `import {Component,ElementRef,Input,ViewChild,AfterViewInit,OnChanges,OnDestroy,ChangeDetectorRef} from '@angular/core';
54
+ import {createMessengerMount,type MessengerAccount,type Contacts,type RobonoLocale} from './mount';
55
+ @Component({selector:'robono-messenger',standalone:true,template:'<p role="alert" [hidden]="!error">{{error}} <button type="button" (click)="retry()">{{retryLabel}}</button></p><div #chat style="height:100%;min-height:400px"></div>',styles:[':host{display:block;height:100%}']})
56
+ export class RobonoMessengerComponent implements AfterViewInit,OnChanges,OnDestroy{
57
+ @Input() account:MessengerAccount|null=null;@Input() contacts:Contacts={};@Input() interfaceLocale?:RobonoLocale;@ViewChild('chat',{static:true}) element!:ElementRef<HTMLElement>;error='';
58
+ private mount?:ReturnType<typeof createMessengerMount>;constructor(private changes:ChangeDetectorRef){}
59
+ ngAfterViewInit(){this.mount=createMessengerMount(this.element.nativeElement,value=>{this.error=value;this.changes.markForCheck();});this.ngOnChanges();}
60
+ ngOnChanges(){this.mount?.update(this.account,this.contacts,this.interfaceLocale);}
61
+ get retryLabel(){return this.mount?.text('Retry')??'Retry';}
62
+ retry(){this.mount?.retry();}
63
+ ngOnDestroy(){this.mount?.dispose();}
64
+ }
65
+ `;
66
+ return files;
67
+ }
68
+ //# sourceMappingURL=messenger-framework-templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messenger-framework-templates.js","sourceRoot":"","sources":["../src/messenger-framework-templates.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,UAAU,oBAAoB,CAAC,aAAoB,EAAC,WAAkB,EAAC,SAA4C;IACxH,MAAM,KAAK,GAAuB,EAAE,CAAC;IACrC,KAAK,CAAC,UAAU,CAAC,GAAC;;;;;;;;;;;;;;mKAcgJ,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,6GAA6G,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC;;;;;;;;CAQvU,CAAC;IACD,IAAG,SAAS,KAAG,KAAK;QAAC,KAAK,CAAC,qBAAqB,CAAC,GAAC;;;;;;;;;;;CAWlD,CAAC;IACD,IAAG,SAAS,KAAG,QAAQ;QAAC,KAAK,CAAC,wBAAwB,CAAC,GAAC;;;;;;;;;;CAUxD,CAAC;IACD,IAAG,SAAS,KAAG,SAAS;QAAC,KAAK,CAAC,+BAA+B,CAAC,GAAC;;;;;;;;;;;;CAYhE,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type MessengerInstallOptions, type MessengerInstallPlan } from './messenger-install.js';
2
+ export declare function buildHostedMessengerInstallation(options: MessengerInstallOptions, mode: 'new' | 'resume' | 'upgrade'): Promise<MessengerInstallPlan>;
3
+ //# sourceMappingURL=messenger-hosted-install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messenger-hosted-install.d.ts","sourceRoot":"","sources":["../src/messenger-hosted-install.ts"],"names":[],"mappings":"AAKA,OAAO,EAAuG,KAAK,uBAAuB,EAAC,KAAK,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAEpM,wBAAsB,gCAAgC,CAAC,OAAO,EAAC,uBAAuB,EAAC,IAAI,EAAC,KAAK,GAAC,QAAQ,GAAC,SAAS,GAAE,OAAO,CAAC,oBAAoB,CAAC,CAmElJ"}
@@ -0,0 +1,107 @@
1
+ import { join, relative } from 'node:path';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { messengerPreviewTemplates } from './messenger-preview-template.js';
4
+ import { hostedMessengerFiles } from './messenger-hosted-templates.js';
5
+ import { hostedFrameworkFiles } from './messenger-framework-templates.js';
6
+ import { project, appRoot, manager, installCommand, exists, safePath, recordGeneratedFiles, messengerInstallerVersion } from './messenger-install.js';
7
+ export async function buildHostedMessengerInstallation(options, mode) {
8
+ const client = await project(options.project), platform = client.deps.expo ? 'expo' : 'web';
9
+ const origin = new URL(options.origin);
10
+ if (origin.origin !== options.origin || origin.protocol !== 'https:' && !(origin.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(origin.hostname)))
11
+ throw Error('Use your exact HTTPS website origin.');
12
+ const auth = options.auth ?? (client.deps['@supabase/supabase-js'] ? 'supabase' : client.deps.firebase ? 'firebase' : 'custom');
13
+ if (!['custom', 'supabase', 'firebase'].includes(auth))
14
+ throw Error('Choose your existing sign-in provider.');
15
+ if (!options.auth && client.deps['@supabase/supabase-js'] && client.deps.firebase)
16
+ throw Error('Both sign-in providers are installed. Select --auth supabase, firebase or custom.');
17
+ if (platform === 'expo' && !/^[~^]?(55|56)\./.test(client.deps.expo))
18
+ throw Error('The supplied phone media components currently require Expo 55–56. Do not upgrade your app automatically.');
19
+ const tokenUrl = new URL(options.tokenEndpoint ?? '/api/robono-token', options.origin);
20
+ if (tokenUrl.search || tokenUrl.hash || tokenUrl.username || tokenUrl.password || tokenUrl.protocol !== 'https:' && !(tokenUrl.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(tokenUrl.hostname)))
21
+ throw Error('Use a token endpoint on your existing sign-in server origin.');
22
+ const tokenEndpoint = platform === 'web' && tokenUrl.origin === origin.origin ? tokenUrl.pathname : tokenUrl.href;
23
+ const server = options.serverProject ? await project(options.serverProject) : client;
24
+ if (platform === 'expo' && options.serverProject && server.root === client.root)
25
+ throw Error('Keep private sign-in files outside the phone project.');
26
+ const next = !!server.deps.next && platform === 'web' || !!options.serverProject && !!server.deps.next;
27
+ const serverBase = next ? await appRoot(server.root) : '';
28
+ const clientBase = await exists(join(client.root, 'src')) ? 'src' : '';
29
+ const templates = hostedMessengerFiles({ platform, framework: 'fetch', origin: options.origin, companyName: options.companyName, auth, tokenEndpoint });
30
+ const files = [], replacements = [];
31
+ const react = platform === 'expo' || !!client.deps.react || !!client.deps.next;
32
+ const framework = client.deps.vue ? 'vue' : client.deps.svelte ? 'svelte' : client.deps['@angular/core'] ? 'angular' : 'browser';
33
+ if (!react)
34
+ for (const [name, content] of Object.entries(hostedFrameworkFiles(tokenEndpoint, options.companyName, framework)))
35
+ files.push({ path: join(client.root, clientBase, 'robono', name), content });
36
+ for (const [name, value] of Object.entries(templates))
37
+ if (react && name.startsWith('client/')) {
38
+ const content = client.deps.vite ? value.replaceAll("process.env.NODE_ENV==='development'", 'import.meta.env.DEV').replaceAll("process.env.NODE_ENV!=='development'", '!import.meta.env.DEV') : value;
39
+ files.push({ path: join(client.root, clientBase, 'robono', name), content });
40
+ }
41
+ if (platform === 'web')
42
+ files.push({ path: join(client.root, 'public/robono-notifications/worker.js'), content: templates['public/robono-notifications/worker.js'] });
43
+ if (next) {
44
+ files.push({ path: join(server.root, '.robono/server.env.example'), content: templates['.env.example'] });
45
+ files.push({ path: join(server.root, serverBase, 'robono/server/robono-access.ts'), content: templates['server/robono-access.ts'] });
46
+ files.push({ path: join(server.root, serverBase, 'robono/server/robono-token.ts'), content: templates['server/robono-token.ts'] });
47
+ if (tokenUrl.pathname !== '/api/robono-token')
48
+ throw Error('Automatic Next.js token route uses /api/robono-token. For a custom path mount the supplied token handler in your existing route.');
49
+ files.push({ path: join(server.root, serverBase, 'app/api/robono-token/route.ts'), content: "import {issueRobonoToken} from '../../../robono/server/robono-token';\nexport const runtime='nodejs';\nexport const POST=issueRobonoToken;\nexport const OPTIONS=issueRobonoToken;\n" });
50
+ }
51
+ if (platform === 'web' && react) {
52
+ const preview = messengerPreviewTemplates(), content = client.deps.vite ? preview.client.replaceAll("process.env.NODE_ENV!=='development'", '!import.meta.env.DEV') : preview.client;
53
+ files.push({ path: join(client.root, clientBase, 'robono/client/RobonoPreview.tsx'), content });
54
+ if (client.deps.next)
55
+ files.push({ path: join(client.root, await appRoot(client.root), 'app/robono-preview/page.tsx'), content: preview.page });
56
+ }
57
+ const notes = [`Robono-hosted ${platform === 'expo' ? 'phone' : 'website'} Messenger. No communication server needs to be deployed by you.`,
58
+ 'Your existing backend verifies login and requests a short-lived Robono token. Keep the private Robono key there.',
59
+ `Sign-in endpoint: ${tokenUrl.href}. Synchronize your permitted people/groups and location grants through the server APIs.`,
60
+ 'Pass your existing sign-in and contacts to CustomerMessenger. No new user accounts or second login.',
61
+ 'Maps: register your website origin or both phone app identifiers in Robono Maps setup. Synchronize your own people and sharing grants.',
62
+ platform === 'expo' ? 'Supply Apple/Google notification credentials in Robono and rebuild both apps.' : 'The installer includes the static browser notification worker. It runs on your website; Robono sends the notifications.'];
63
+ const cm = await manager(client.root, client.pkg);
64
+ const packages = ['@robono/messaging@^0.6.0', platform === 'expo' ? '@robono/messaging-react-native@^0.9.0' : '@robono/messaging-web@^0.8.0', '@robono/location@^0.3.0', ...(platform === 'expo' ? ['@robono/calling@^0.4.0', '@robono/calling-react-native@^0.7.0', '@robono/location-react-native@^0.3.0', 'react-native-webrtc@^124.0.8', 'react-native-incall-manager@^4.3.0'] : [])];
65
+ if (platform === 'web') {
66
+ if (!client.deps.react)
67
+ packages.push('react@^19');
68
+ if (!client.deps['react-dom'])
69
+ packages.push('react-dom@' + (client.deps.react ?? '^19'));
70
+ }
71
+ const commands = [installCommand(client.root, cm, packages)];
72
+ if (next)
73
+ commands.push(installCommand(server.root, await manager(server.root, server.pkg), ['@robono/server@^0.25.0', ...(auth === 'firebase' && !server.deps['firebase-admin'] ? ['firebase-admin@^14'] : []), ...(auth === 'supabase' && !server.deps['@supabase/supabase-js'] ? ['@supabase/supabase-js@^2'] : [])]));
74
+ if (platform === 'expo') {
75
+ commands.push({ cwd: client.root, command: process.execPath, args: [join(client.root, 'node_modules/expo/bin/cli'), 'install', 'expo-audio', 'expo-image-picker', 'expo-document-picker', 'expo-file-system', 'expo-sharing', 'expo-video', 'expo-haptics', 'expo-asset', 'expo-crypto', 'react-native-safe-area-context', 'react-native-svg', 'expo-clipboard', 'expo-image-manipulator', 'expo-video-thumbnails', 'react-native-webview', 'expo-blur', 'expo-notifications', 'expo-secure-store', 'expo-location', 'expo-task-manager', 'expo-sensors', 'expo-constants', 'react-native-maps', '--' + cm] });
76
+ const dynamic = await exists(join(client.root, 'app.config.js')) || await exists(join(client.root, 'app.config.ts'));
77
+ if (dynamic)
78
+ notes.push('Your Expo config is code. Add @robono/messaging-react-native/setup to its plugins array; all required Robono plugins are grouped there. Existing code is preserved.');
79
+ else {
80
+ const path = join(client.root, 'app.json');
81
+ await safePath(path);
82
+ const before = await readFile(path, 'utf8'), config = JSON.parse(before);
83
+ if (!config.expo || !Array.isArray(config.expo.plugins ?? []))
84
+ throw Error('Expected a valid Expo app.json.');
85
+ const plugins = config.expo.plugins ?? [];
86
+ if (!plugins.some((p) => (Array.isArray(p) ? p[0] : p) === '@robono/messaging-react-native/setup')) {
87
+ config.expo.plugins = [...plugins, '@robono/messaging-react-native/setup'];
88
+ replacements.push({ path, before, after: JSON.stringify(config, null, 2) + '\n' });
89
+ files.push({ path: join(client.root, '.robono/app.json.before-install'), content: before });
90
+ }
91
+ }
92
+ }
93
+ const setup = { schema: 3, installerVersion: messengerInstallerVersion, connection: 'hosted', layout: 'hosted', clientBase, serverBase, serverProject: relative(client.root, server.root) || '.', platform, auth, companyName: options.companyName, origin: options.origin, tokenEndpoint: tokenUrl.href, dependencies: 'pending' };
94
+ files.push({ path: join(client.root, '.robono/setup.json'), content: JSON.stringify(setup, null, 2) + '\n' });
95
+ const ui = react ? 'Import CustomerMessenger from ' + join(clientBase, 'robono/client/CustomerMessenger') + '. Pass ' + (auth === 'custom' ? 'accounts (the generated RobonoAccounts interface)' : 'auth (your existing ' + auth + ' client)') + ' and contacts.' : `Use the generated ${framework} component in ${join(clientBase, 'robono')}. Pass account with your signed-in userId/getAccessToken and contacts. The mount.ts adapter owns the Robono UI; keep your existing framework.`;
96
+ files.push({ path: join(client.root, '.robono/SETUP.md'), content: '# Connect to Robono hosting\n\n' + notes.map(n => '- ' + n).join('\n') + '\n\n## Your sign-in\n' + (next ? 'The token route and provider verification files are included. Set ROBONO_API_KEY privately on that server. Custom sign-in: implement authenticate in robono-access.ts.' : 'Use the small token endpoint example in the hosted setup guide for your existing server language. It verifies your login and returns a Robono session. No Node communication server is needed.') + '\n\n## Interface\n' + ui + ' Keep mounted while signed in. Give the website component a height.\n\n## Account changes\nThe supplied account wrapper clears the old account. Await its signOut before ending your login. Synchronize suspended/deleted accounts and revoke their Robono sessions from your server.\n\n## Safe updates\n--resume finishes dependencies. --upgrade preserves your edited files and saves proposals for review.\n' });
97
+ if (mode === 'new')
98
+ for (const file of files) {
99
+ await safePath(file.path);
100
+ if (await exists(file.path))
101
+ throw Error('Already exists: ' + file.path + '. Use --upgrade or preserve your existing integration.');
102
+ }
103
+ if (mode !== 'resume')
104
+ recordGeneratedFiles(files, client.root, server.root);
105
+ return { platform, auth, files: mode === 'resume' ? [] : files, replacements: mode === 'resume' ? [] : replacements, commands, notes, setupFile: join(client.root, '.robono/setup.json') };
106
+ }
107
+ //# sourceMappingURL=messenger-hosted-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messenger-hosted-install.js","sourceRoot":"","sources":["../src/messenger-hosted-install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type MessengerStarterOptions } from './messenger-init.js';
2
+ /** Reuse the account lifecycle, replacing only transport ownership. */
3
+ export declare function hostedMessengerFiles(options: MessengerStarterOptions & {
4
+ tokenEndpoint: string;
5
+ }): Record<string, string>;
6
+ //# sourceMappingURL=messenger-hosted-templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messenger-hosted-templates.d.ts","sourceRoot":"","sources":["../src/messenger-hosted-templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,uBAAuB,EAAC,MAAM,qBAAqB,CAAC;AAGvF,uEAAuE;AACvE,wBAAgB,oBAAoB,CAAC,OAAO,EAAC,uBAAuB,GAAC;IAAC,aAAa,EAAC,MAAM,CAAA;CAAC,0BA+E1F"}
@@ -0,0 +1,84 @@
1
+ import { messengerStarterFiles } from './messenger-init.js';
2
+ import { messagingPushWorkerSource } from './messaging-push-worker.js';
3
+ /** Reuse the account lifecycle, replacing only transport ownership. */
4
+ export function hostedMessengerFiles(options) {
5
+ const files = messengerStarterFiles(options), q = JSON.stringify, web = options.platform === 'web';
6
+ files['client/RobonoChat.tsx'] = web ? `'use client';
7
+ import {useEffect,useRef,useState} from 'react';
8
+ import {mountHostedRobonoMessenger} from '@robono/messaging-web';
9
+ import {hostedRobonoTokenProvider,createRobonoLocalizer} from '@robono/messaging';
10
+ type Options=Parameters<typeof mountHostedRobonoMessenger>[1];
11
+ type Connection=Awaited<ReturnType<typeof mountHostedRobonoMessenger>>;
12
+ export function RobonoChat({userId,getAccessToken,contacts,interfaceLocale,onReady,onSignOut}:{userId:string;getAccessToken:()=>Promise<string>;contacts?:Options['contacts'];interfaceLocale?:Options['interfaceLocale'];onSignOut?:()=>Promise<void>;onReady?:(chat:Connection|null)=>void}){
13
+ const ui=createRobonoLocalizer(interfaceLocale);
14
+ const element=useRef<HTMLDivElement>(null),active=useRef<Connection|null>(null),latest=useRef({userId,getAccessToken,contacts,interfaceLocale,onReady,onSignOut});
15
+ const [error,setError]=useState(''),[attempt,setAttempt]=useState(0);
16
+ latest.current={userId,getAccessToken,contacts,interfaceLocale,onReady,onSignOut};
17
+ useEffect(()=>{
18
+ if(!element.current)return;
19
+ const controller=new AbortController();setError('');
20
+ const getToken=async()=>{if(latest.current.userId!==userId)throw Error('Account changed.');const value=await latest.current.getAccessToken();if(latest.current.userId!==userId||controller.signal.aborted)throw Error('Account changed.');return value;};
21
+ void mountHostedRobonoMessenger(element.current,{userId,companyName:${q(options.companyName)},contacts:latest.current.contacts,interfaceLocale,signal:controller.signal,tokenProvider:hostedRobonoTokenProvider({tokenEndpoint:${q(options.tokenEndpoint)},getAccessToken:getToken}),account:{name:'Account',onSignOut:async()=>{await latest.current.onSignOut?.();}}}).then(chat=>{
22
+ if(controller.signal.aborted){void chat.signOut().catch(()=>{});return;}
23
+ active.current=chat;chat.updateContacts(latest.current.contacts);chat.updateLocale(latest.current.interfaceLocale);latest.current.onReady?.(chat);
24
+ }).catch(()=>{if(!controller.signal.aborted)setError('Could not connect to messaging. Check your sign-in connection.');});
25
+ return()=>{controller.abort();latest.current.onReady?.(null);active.current?.unmount();active.current=null;};
26
+ },[userId,attempt]);
27
+ useEffect(()=>{active.current?.updateContacts(contacts);},[contacts]);
28
+ useEffect(()=>{active.current?.updateLocale(interfaceLocale);},[interfaceLocale]);
29
+ return <div style={{height:'100%',minHeight:400}}>{error&&<div role="alert">{ui.text(error)} <button onClick={()=>setAttempt(x=>x+1)}>{ui.text('Retry')}</button></div>}<div ref={element} style={{height:'100%'}}/></div>;
30
+ }
31
+ ` : `import React,{useEffect,useRef,useState} from 'react';
32
+ import {Text,View,Pressable} from 'react-native';
33
+ import {createHostedExpoMessenger,ExpoMessenger,type ExpoMessengerProps} from '@robono/messaging-react-native/expo';
34
+ import {hostedRobonoTokenProvider,createRobonoLocalizer} from '@robono/messaging';
35
+ type Connection=Awaited<ReturnType<typeof createHostedExpoMessenger>>;
36
+ export function RobonoChat({userId,getAccessToken,contacts,interfaceLocale,isCallActive,onReady,onSignOut}:{userId:string;getAccessToken:()=>Promise<string>;contacts?:ExpoMessengerProps['contacts'];interfaceLocale?:ExpoMessengerProps['interfaceLocale'];isCallActive?:()=>boolean;onSignOut?:()=>Promise<void>;onReady?:(connection:Connection|null)=>void}){
37
+ const ui=createRobonoLocalizer(interfaceLocale);
38
+ const latest=useRef({userId,getAccessToken,contacts,isCallActive,onReady});latest.current={userId,getAccessToken,contacts,isCallActive,onReady};
39
+ const [active,setActive]=useState<{userId:string;connection:Connection}|null>(null),[error,setError]=useState(''),[attempt,setAttempt]=useState(0);
40
+ useEffect(()=>{
41
+ const controller=new AbortController();let connection:Connection|undefined;setError('');setActive(null);
42
+ const getToken=async()=>{if(latest.current.userId!==userId)throw Error('Account changed.');const value=await latest.current.getAccessToken();if(latest.current.userId!==userId||controller.signal.aborted)throw Error('Account changed.');return value;};
43
+ void createHostedExpoMessenger({userId,signal:controller.signal,tokenProvider:hostedRobonoTokenProvider({tokenEndpoint:${q(options.tokenEndpoint)},getAccessToken:getToken}),people:()=>latest.current.contacts??{},isCallActive:()=>latest.current.isCallActive?.()??false}).then(value=>{
44
+ if(controller.signal.aborted){void value.signOut().catch(()=>{});return;}
45
+ connection=value;setActive({userId,connection});latest.current.onReady?.(connection);
46
+ }).catch(()=>{if(!controller.signal.aborted)setError('Could not connect to messaging. Check your sign-in connection.');});
47
+ return()=>{controller.abort();latest.current.onReady?.(null);connection?.dispose();};
48
+ },[userId,attempt]);
49
+ if(error)return <View><Text accessibilityRole="alert">{ui.text(error)}</Text><Pressable accessibilityRole="button" onPress={()=>setAttempt(x=>x+1)}><Text>{ui.text('Retry')}</Text></Pressable></View>;
50
+ if(!active||active.userId!==userId)return null;
51
+ return <ExpoMessenger interfaceLocale={interfaceLocale} {...active.connection} userId={userId} companyName={${q(options.companyName)}} contacts={contacts} account={onSignOut?{name:'Account',onSignOut}:undefined}/>;
52
+ }
53
+ `;
54
+ // Diagnostics use the same signed-in account and always revoke their temporary session.
55
+ files['client/check-messenger-connection.ts'] = `import {hostedRobonoTokenProvider,createRobonoLocalizer} from '@robono/messaging';
56
+ export interface ConnectionCheck {name:string;status:'passed'|'failed'|'needs-action';detail:string}
57
+ export async function checkMessengerConnection(getAccessToken:()=>Promise<string>,signal:AbortSignal):Promise<ConnectionCheck[]>{
58
+ const checks:ConnectionCheck[]=[];
59
+ const session=await hostedRobonoTokenProvider({tokenEndpoint:${q(options.tokenEndpoint)},getAccessToken})();
60
+ try{
61
+ for(const [name,service,operation]of [['Messaging','messages','settings'],['Contacts','messages','conversations'],['Calling','calling','setup'],['Maps','location','settings'],['Notifications','notifications','notification-status']]){
62
+ if(signal.aborted)break;
63
+ try{
64
+ const response=await fetch(session.endpoint+'?service='+service,{method:'POST',credentials:'omit',redirect:'error',signal:AbortSignal.any([signal,AbortSignal.timeout(15000)]),headers:{authorization:'Bearer '+session.token,'content-type':'application/json'},body:JSON.stringify({operation})});
65
+ const data=await response.json();const available=response.ok&&(service==='calling'?!!data.features:operation==='conversations'?Array.isArray(data.conversations):service==='notifications'?Array.isArray(data.providers):!!data.settings);
66
+ const empty=available&&(operation==='conversations'&&!data.conversations.length||service==='notifications'&&!data.providers.length);
67
+ checks.push({name,status:!available?'failed':empty?'needs-action':'passed',detail:!available?'Check the service connection and permissions.':empty?service==='notifications'?'Connect your website or Apple/Google notification settings.':'Connect the people who may communicate.':'Connected.'});
68
+ }catch{checks.push({name,status:'failed',detail:'Could not reach this service. Check the connection and try again.'});}
69
+ }
70
+ return checks;
71
+ }finally{await fetch(session.endpoint+'?service=session',{method:'POST',credentials:'omit',redirect:'error',signal:AbortSignal.timeout(10000),headers:{authorization:'Bearer '+session.token,'content-type':'application/json'},body:'{"operation":"sign-out"}'}).catch(()=>{});}
72
+ }
73
+ `;
74
+ files['server/robono-token.ts'] = `import {createRobonoTokenHandler} from '@robono/server';
75
+ import {authenticate} from './robono-access';
76
+ export async function issueRobonoToken(request:Request){
77
+ const apiKey=process.env.ROBONO_API_KEY;if(!apiKey)throw Error('Set ROBONO_API_KEY privately on your existing sign-in server.');
78
+ return createRobonoTokenHandler({apiKey,authenticate,origins:process.env.ROBONO_ALLOWED_ORIGINS?.split(',').map(value=>value.trim()).filter(Boolean)??[${q(options.origin)}]})(request);
79
+ }
80
+ `;
81
+ files['public/robono-notifications/worker.js'] = messagingPushWorkerSource;
82
+ return files;
83
+ }
84
+ //# sourceMappingURL=messenger-hosted-templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messenger-hosted-templates.js","sourceRoot":"","sources":["../src/messenger-hosted-templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,qBAAqB,EAA8B,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAC,yBAAyB,EAAC,MAAM,4BAA4B,CAAC;AAErE,uEAAuE;AACvE,MAAM,UAAU,oBAAoB,CAAC,OAAsD;IAC1F,MAAM,KAAK,GAAC,qBAAqB,CAAC,OAAO,CAAC,EAAC,CAAC,GAAC,IAAI,CAAC,SAAS,EAAC,GAAG,GAAC,OAAO,CAAC,QAAQ,KAAG,KAAK,CAAC;IACzF,KAAK,CAAC,uBAAuB,CAAC,GAAC,GAAG,CAAA,CAAC,CAAA;;;;;;;;;;;;;;;wEAeoC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,qIAAqI,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;;;;;;;;;;CAU1P,CAAA,CAAC,CAAA;;;;;;;;;;;;2HAYyH,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;;;;;;;;+GAQpC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;;CAEpI,CAAC;IACD,wFAAwF;IACxF,KAAK,CAAC,sCAAsC,CAAC,GAAC;;;;gEAIiB,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;;;;;;;;;;;;;;CAcvF,CAAC;IACD,KAAK,CAAC,wBAAwB,CAAC,GAAC;;;;0JAIyH,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;;CAE1K,CAAC;IACD,KAAK,CAAC,uCAAuC,CAAC,GAAC,yBAAyB,CAAC;IACzE,OAAO,KAAK,CAAC;AACd,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"messenger-init.d.ts","sourceRoot":"","sources":["../src/messenger-init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,qBAAqB,EAAC,MAAM,oCAAoC,CAAC;AAGtG,MAAM,WAAW,uBAAuB;IAAE,QAAQ,EAAC,KAAK,GAAC,MAAM,CAAC;IAAA,SAAS,EAAC,MAAM,GAAC,OAAO,CAAC;IAAA,MAAM,EAAC,MAAM,CAAC;IAAA,WAAW,EAAC,MAAM,CAAC;IAAA,IAAI,CAAC,EAAC,qBAAqB,CAAA;CAAC;AACtJ,4FAA4F;AAC5F,wBAAgB,qBAAqB,CAAC,OAAO,EAAC,uBAAuB,GAAE,MAAM,CAAC,MAAM,EAAC,MAAM,CAAC,CAoF3F;AACD,uFAAuF;AACvF,wBAAsB,qBAAqB,CAAC,WAAW,EAAC,MAAM,EAAC,OAAO,EAAC,uBAAuB,qBAc7F"}
1
+ {"version":3,"file":"messenger-init.d.ts","sourceRoot":"","sources":["../src/messenger-init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,qBAAqB,EAAC,MAAM,oCAAoC,CAAC;AAGtG,MAAM,WAAW,uBAAuB;IAAE,QAAQ,EAAC,KAAK,GAAC,MAAM,CAAC;IAAA,SAAS,EAAC,MAAM,GAAC,OAAO,CAAC;IAAA,MAAM,EAAC,MAAM,CAAC;IAAA,WAAW,EAAC,MAAM,CAAC;IAAA,IAAI,CAAC,EAAC,qBAAqB,CAAA;CAAC;AACtJ,4FAA4F;AAC5F,wBAAgB,qBAAqB,CAAC,OAAO,EAAC,uBAAuB,GAAE,MAAM,CAAC,MAAM,EAAC,MAAM,CAAC,CA8E3F;AACD,uFAAuF;AACvF,wBAAsB,qBAAqB,CAAC,WAAW,EAAC,MAAM,EAAC,OAAO,EAAC,uBAAuB,qBAc7F"}