@robono/server 0.24.0 → 0.26.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.
- package/CHANGELOG.md +8 -0
- package/HISTORY-IMPORT.md +110 -0
- package/HOSTED.md +241 -0
- package/INTEGRATION-ASSISTANT.md +103 -0
- package/README.md +27 -3
- package/SBOM.spdx.json +9 -9
- package/dist/calling-session-handle.d.ts.map +1 -1
- package/dist/calling-session-handle.js +1 -0
- package/dist/calling-session-handle.js.map +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -1
- package/dist/client.js.map +1 -1
- package/dist/generated/custom-messages.d.ts +31 -0
- package/dist/generated/custom-messages.d.ts.map +1 -0
- package/dist/generated/custom-messages.js +84 -0
- package/dist/generated/custom-messages.js.map +1 -0
- package/dist/generated/sdk-versions.d.ts +13 -0
- package/dist/generated/sdk-versions.d.ts.map +1 -0
- package/dist/generated/sdk-versions.js +4 -0
- package/dist/generated/sdk-versions.js.map +1 -0
- package/dist/history-export-cli.d.ts +4 -0
- package/dist/history-export-cli.d.ts.map +1 -0
- package/dist/history-export-cli.js +166 -0
- package/dist/history-export-cli.js.map +1 -0
- package/dist/history-export-files.d.ts +39 -0
- package/dist/history-export-files.d.ts.map +1 -0
- package/dist/history-export-files.js +119 -0
- package/dist/history-export-files.js.map +1 -0
- package/dist/history-export.d.ts +92 -0
- package/dist/history-export.d.ts.map +1 -0
- package/dist/history-export.js +78 -0
- package/dist/history-export.js.map +1 -0
- package/dist/history-import-cli.d.ts +11 -0
- package/dist/history-import-cli.d.ts.map +1 -0
- package/dist/history-import-cli.js +94 -0
- package/dist/history-import-cli.js.map +1 -0
- package/dist/history-import.d.ts +66 -0
- package/dist/history-import.d.ts.map +1 -0
- package/dist/history-import.js +69 -0
- package/dist/history-import.js.map +1 -0
- package/dist/hosted-sessions.d.ts +38 -0
- package/dist/hosted-sessions.d.ts.map +1 -0
- package/dist/hosted-sessions.js +68 -0
- package/dist/hosted-sessions.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/integration-assistant.txt +103 -0
- package/dist/managed-media.d.ts +2 -1
- package/dist/managed-media.d.ts.map +1 -1
- package/dist/managed-media.js +1 -1
- package/dist/managed-media.js.map +1 -1
- package/dist/messaging-notification-providers.d.ts +2 -3
- package/dist/messaging-notification-providers.d.ts.map +1 -1
- package/dist/messaging-notification-providers.js +1 -0
- package/dist/messaging-notification-providers.js.map +1 -1
- package/dist/messaging-push-worker.d.ts.map +1 -1
- package/dist/messaging-push-worker.js +3 -2
- package/dist/messaging-push-worker.js.map +1 -1
- package/dist/messaging.d.ts +5 -0
- package/dist/messaging.d.ts.map +1 -1
- package/dist/messaging.js +11 -2
- package/dist/messaging.js.map +1 -1
- package/dist/messenger-check.d.ts +1 -0
- package/dist/messenger-check.d.ts.map +1 -1
- package/dist/messenger-check.js +7 -5
- package/dist/messenger-check.js.map +1 -1
- package/dist/messenger-connected-templates.d.ts.map +1 -1
- package/dist/messenger-connected-templates.js +9 -6
- package/dist/messenger-connected-templates.js.map +1 -1
- package/dist/messenger-example-cli.d.ts +3 -0
- package/dist/messenger-example-cli.d.ts.map +1 -0
- package/dist/messenger-example-cli.js +47 -0
- package/dist/messenger-example-cli.js.map +1 -0
- package/dist/messenger-example.d.ts +9 -0
- package/dist/messenger-example.d.ts.map +1 -0
- package/dist/messenger-example.js +42 -0
- package/dist/messenger-example.js.map +1 -0
- package/dist/messenger-example.json +1 -0
- package/dist/messenger-framework-templates.d.ts +3 -0
- package/dist/messenger-framework-templates.d.ts.map +1 -0
- package/dist/messenger-framework-templates.js +68 -0
- package/dist/messenger-framework-templates.js.map +1 -0
- package/dist/messenger-hosted-install.d.ts +3 -0
- package/dist/messenger-hosted-install.d.ts.map +1 -0
- package/dist/messenger-hosted-install.js +109 -0
- package/dist/messenger-hosted-install.js.map +1 -0
- package/dist/messenger-hosted-templates.d.ts +6 -0
- package/dist/messenger-hosted-templates.d.ts.map +1 -0
- package/dist/messenger-hosted-templates.js +84 -0
- package/dist/messenger-hosted-templates.js.map +1 -0
- package/dist/messenger-install-cli.js +10 -7
- package/dist/messenger-install-cli.js.map +1 -1
- package/dist/messenger-install.d.ts +24 -1
- package/dist/messenger-install.d.ts.map +1 -1
- package/dist/messenger-install.js +24 -9
- package/dist/messenger-install.js.map +1 -1
- package/dist/messenger-node.d.ts.map +1 -1
- package/dist/messenger-node.js +1 -0
- package/dist/messenger-node.js.map +1 -1
- package/dist/messenger-preview-template.d.ts.map +1 -1
- package/dist/messenger-preview-template.js +1 -0
- package/dist/messenger-preview-template.js.map +1 -1
- package/dist/messenger-upgrade.js +1 -1
- package/dist/messenger-upgrade.js.map +1 -1
- package/package.json +10 -4
package/dist/messenger-check.js
CHANGED
|
@@ -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
|
|
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: '
|
|
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(
|
|
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":"AACA,kGAAkG;AAClG,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,
|
|
1
|
+
{"version":3,"file":"messenger-check.js","sourceRoot":"","sources":["../src/messenger-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messenger-connected-templates.d.ts","sourceRoot":"","sources":["../src/messenger-connected-templates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,qBAAqB,CAAC;AAEjE,MAAM,MAAM,qBAAqB,GAAC,QAAQ,GAAC,UAAU,GAAC,UAAU,CAAC;AACjE,wBAAgB,uBAAuB,CAAC,KAAK,EAAC,MAAM,CAAC,MAAM,EAAC,MAAM,CAAC,EAAC,OAAO,EAAC,uBAAuB,
|
|
1
|
+
{"version":3,"file":"messenger-connected-templates.d.ts","sourceRoot":"","sources":["../src/messenger-connected-templates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,qBAAqB,CAAC;AAEjE,MAAM,MAAM,qBAAqB,GAAC,QAAQ,GAAC,UAAU,GAAC,UAAU,CAAC;AACjE,wBAAgB,uBAAuB,CAAC,KAAK,EAAC,MAAM,CAAC,MAAM,EAAC,MAAM,CAAC,EAAC,OAAO,EAAC,uBAAuB,0BAuIlG"}
|
|
@@ -82,17 +82,20 @@ export interface RobonoAccounts {
|
|
|
82
82
|
/** Keep mounted within your signed-in app. No second login or copied session is required. */
|
|
83
83
|
export function ConnectedRobonoChat({accounts,...props}:Omit<ChatProps,'userId'|'getAccessToken'|'onReady'|'onSignOut'>&{accounts:RobonoAccounts}){
|
|
84
84
|
const [account,setAccount]=useState<RobonoAccount|null>(null),current=useRef<RobonoAccount|null>(null);
|
|
85
|
-
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);
|
|
86
86
|
const chat=useRef<Parameters<NonNullable<ChatProps['onReady']>>[0]>(null);
|
|
87
87
|
useEffect(()=>{
|
|
88
|
-
let live=true;setVersion(++sourceVersion.current);
|
|
89
|
-
|
|
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();
|
|
90
91
|
const off=accounts.subscribe(next=>{
|
|
91
92
|
if(!live)return;
|
|
92
|
-
if(current.current?.id
|
|
93
|
-
current.current=next;setAccount(
|
|
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);});
|
|
94
97
|
});
|
|
95
|
-
return()=>{live=false;sourceVersion.current++;current.current=null;off();};
|
|
98
|
+
return()=>{live=false;sourceVersion.current++;transition.current++;current.current=null;closePrevious();off();};
|
|
96
99
|
},[accounts]);
|
|
97
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;};
|
|
98
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;
|
|
@@ -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,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
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"messenger-example-cli.d.ts","sourceRoot":"","sources":["../src/messenger-example-cli.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createMessengerExample } from './messenger-example.js';
|
|
3
|
+
import spawn from 'cross-spawn';
|
|
4
|
+
const args = process.argv.slice(2), flags = new Set();
|
|
5
|
+
let directory;
|
|
6
|
+
try {
|
|
7
|
+
for (const arg of args) {
|
|
8
|
+
if (['--live', '--no-install', '--start', '--help'].includes(arg))
|
|
9
|
+
flags.add(arg);
|
|
10
|
+
else if (arg.startsWith('-') || directory)
|
|
11
|
+
throw Error('Use robono-messenger-example [new-folder] [--live] [--start] [--no-install].');
|
|
12
|
+
else
|
|
13
|
+
directory = arg;
|
|
14
|
+
}
|
|
15
|
+
if (flags.has('--help'))
|
|
16
|
+
console.log(`robono-messenger-example [new-folder] [--live] [--start] [--no-install]
|
|
17
|
+
Creates the complete supplied website example in a NEW folder.
|
|
18
|
+
Requires Node.js 22.12 or later. Does not change your Node installation.
|
|
19
|
+
Default: fictional local conversation, no account or credentials needed.
|
|
20
|
+
--live: connects to your Robono test integration; put its key in the generated private .env.
|
|
21
|
+
--start: starts the local preview after installing. Live mode needs its key configured first.
|
|
22
|
+
--no-install: writes files only. Existing folders and projects are never changed.
|
|
23
|
+
For your existing application use robono-messenger-install instead.`);
|
|
24
|
+
else {
|
|
25
|
+
const [major = 0, minor = 0] = process.versions.node.split('.').map(Number);
|
|
26
|
+
if (major < 22 || major === 22 && minor < 12)
|
|
27
|
+
throw Error('The complete example requires Node.js 22.12 or later. Select a supported Node version, then run this command again. No files were created.');
|
|
28
|
+
if (flags.has('--start') && (flags.has('--no-install') || flags.has('--live')))
|
|
29
|
+
throw Error('--start is for the local preview with dependency installation. For live mode set the test key first, then run npm start.');
|
|
30
|
+
const result = await createMessengerExample(directory ?? (flags.has('--live') ? 'robono-live-example' : 'robono-example'), { live: flags.has('--live') });
|
|
31
|
+
console.log('Created ' + result.directory);
|
|
32
|
+
const run = (command, argv) => new Promise((resolve, reject) => { const child = spawn(command, argv, { cwd: result.directory, stdio: 'inherit' }); child.once('error', reject); child.once('exit', code => code === 0 ? resolve() : reject(Error(`Command stopped (${code}). Your example files remain in ${result.directory}.`))); });
|
|
33
|
+
if (!flags.has('--no-install'))
|
|
34
|
+
await run('npm', ['install', '--no-audit', '--no-fund']);
|
|
35
|
+
if (result.live)
|
|
36
|
+
console.log('Open .env in that folder and set ROBONO_API_KEY to your test integration key. The local sign-in password is already generated in DEMO_PASSWORD. Keep this file private.');
|
|
37
|
+
if (flags.has('--start'))
|
|
38
|
+
await run('npm', ['start']);
|
|
39
|
+
else
|
|
40
|
+
console.log('In that folder, run ' + (flags.has('--no-install') ? 'npm install, then npm start.' : 'npm start.'));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.error(error instanceof Error ? error.message : 'Example setup failed.');
|
|
45
|
+
process.exitCode = 1;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=messenger-example-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messenger-example-cli.js","sourceRoot":"","sources":["../src/messenger-example-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Creates a complete local example without touching an existing project. */
|
|
2
|
+
export declare function createMessengerExample(directory: string, options?: {
|
|
3
|
+
live?: boolean;
|
|
4
|
+
}): Promise<{
|
|
5
|
+
directory: string;
|
|
6
|
+
live: boolean;
|
|
7
|
+
files: string[];
|
|
8
|
+
}>;
|
|
9
|
+
//# sourceMappingURL=messenger-example.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messenger-example.d.ts","sourceRoot":"","sources":["../src/messenger-example.ts"],"names":[],"mappings":"AAIA,6EAA6E;AAC7E,wBAAsB,sBAAsB,CAAC,SAAS,EAAC,MAAM,EAAC,OAAO,GAAC;IAAC,IAAI,CAAC,EAAC,OAAO,CAAA;CAAI;;;;GA0BvF"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { lstat, mkdir, readFile, writeFile, rm } from 'node:fs/promises';
|
|
2
|
+
import { resolve, dirname, join, isAbsolute } from 'node:path';
|
|
3
|
+
import { randomBytes } from 'node:crypto';
|
|
4
|
+
/** Creates a complete local example without touching an existing project. */
|
|
5
|
+
export async function createMessengerExample(directory, options = {}) {
|
|
6
|
+
const target = resolve(directory);
|
|
7
|
+
for (let p = dirname(target);; p = dirname(p)) {
|
|
8
|
+
const st = await lstat(p);
|
|
9
|
+
if (st.isSymbolicLink() || !st.isDirectory())
|
|
10
|
+
throw Error('Choose a directory under an existing, ordinary folder.');
|
|
11
|
+
if (p === dirname(p))
|
|
12
|
+
break;
|
|
13
|
+
}
|
|
14
|
+
const data = JSON.parse(await readFile(new URL('./messenger-example.json', import.meta.url), 'utf8'));
|
|
15
|
+
if (data.schema !== 1)
|
|
16
|
+
throw Error('This example template version is not supported.');
|
|
17
|
+
const files = data[options.live ? 'live' : 'preview'];
|
|
18
|
+
for (const [name, content] of Object.entries(files)) {
|
|
19
|
+
if (isAbsolute(name) || name.split(/[\\/]/).some(part => part === '..' || part === '') || typeof content !== 'string')
|
|
20
|
+
throw Error('Invalid example file.');
|
|
21
|
+
}
|
|
22
|
+
// An existing directory is never reused, even when empty. Avoid overwriting user work.
|
|
23
|
+
await mkdir(target);
|
|
24
|
+
try {
|
|
25
|
+
for (const [name, content] of Object.entries(files)) {
|
|
26
|
+
const file = join(target, name);
|
|
27
|
+
await mkdir(dirname(file), { recursive: true });
|
|
28
|
+
await writeFile(file, content, { flag: 'wx' });
|
|
29
|
+
}
|
|
30
|
+
if (options.live) {
|
|
31
|
+
const secret = randomBytes(24).toString('base64url');
|
|
32
|
+
const prefix = 'example-' + randomBytes(6).toString('hex');
|
|
33
|
+
await writeFile(join(target, '.env'), `# Server only: use a Robono TEST integration key.\nROBONO_API_KEY=\nDEMO_PASSWORD=${secret}\nDEMO_USER_PREFIX=${prefix}\nPORT=5188\n`, { flag: 'wx', mode: 0o600 });
|
|
34
|
+
}
|
|
35
|
+
return { directory: target, live: Boolean(options.live), files: Object.keys(files) };
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
await rm(target, { recursive: true, force: true });
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=messenger-example.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messenger-example.js","sourceRoot":"","sources":["../src/messenger-example.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"schema":1,"preview":{"package.json":"{\n \"name\": \"robono-messenger-preview\",\n \"private\": true,\n \"type\": \"module\",\n \"engines\": {\n \"node\": \">=22.12\"\n },\n \"scripts\": {\n \"start\": \"vite --host 127.0.0.1\",\n \"dev\": \"vite --host 127.0.0.1\",\n \"build\": \"tsc --noEmit && vite build\"\n },\n \"dependencies\": {\n \"@robono/messaging\": \"^0.7.0\",\n \"@robono/messaging-web\": \"^0.9.0\",\n \"react\": \"^19.2.3\",\n \"react-dom\": \"^19.2.3\",\n \"@robono/location\": \"^0.4.0\"\n },\n \"devDependencies\": {\n \"@types/react\": \"^19.2.2\",\n \"@types/react-dom\": \"^19.2.2\",\n \"typescript\": \"^6.0.3\",\n \"vite\": \"^7.3.6\"\n }\n}\n","index.html":"<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>Robono website messaging</title></head><body><div id=\"root\"><main style=\"font-family:system-ui;max-width:600px;margin:48px auto;padding:20px\"><h1>Robono website messaging</h1><p id=\"startup-message\">Opening the chat…</p><noscript>Enable JavaScript to use this example.</noscript></main></div><script>if(location.protocol==='file:')document.getElementById('startup-message').textContent='Start this example with npm start in its folder, then open http://127.0.0.1:5188 in your browser. Opening this file directly cannot connect the chat.';window.addEventListener('error',function(){var message=document.getElementById('startup-message');if(message&&location.protocol!=='file:')message.textContent='The chat could not start. Check that npm start is still running, then refresh this page.';},true);</script><script type=\"module\" src=\"/src/main.tsx\"></script></body></html>\n","tsconfig.json":"{\n \"compilerOptions\": {\n \"target\": \"ES2022\", \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\", \"moduleResolution\": \"Bundler\", \"jsx\": \"react-jsx\",\n \"strict\": true, \"skipLibCheck\": true, \"esModuleInterop\": true,\n \"noEmit\": true, \"types\": [\"vite/client\"]\n },\n \"include\": [\"src\"]\n}\n","src/main.tsx":"import React from 'react';\nimport {createRoot} from 'react-dom/client';\nimport RobonoPreview from './RobonoPreview';\ncreateRoot(document.getElementById('root')!).render(<RobonoPreview/>);\n","src/RobonoPreview.tsx":"'use client';\nimport React,{useEffect,useRef} from 'react';\nimport {mountRobonoMessenger} from '@robono/messaging-web';\nimport {defaultMessagingSettings} from '@robono/messaging';\nexport default function RobonoPreview(){\n const alice=useRef<HTMLDivElement>(null),bob=useRef<HTMLDivElement>(null);\n useEffect(()=>{\n if(!alice.current||!bob.current)return;\n const settings=defaultMessagingSettings();settings.enabled=true;\n const messages:any[]=[];\n const transport=(userId:string):typeof fetch=>async(_request,init)=>{\n const body=JSON.parse(String(init?.body??'{}')),other=userId==='alice'?'bob':'alice';let result:unknown;\n switch(body.operation){\n case 'settings':result={settings};break;\n case 'conversations':result={appearance:settings.appearance,conversations:[{id:'demo-chat',kind:'direct',contactId:other,lastMessage:messages.at(-1)??null,unreadCount:0,canSend:true}],hasMore:false,nextCursor:null};break;\n case 'list':result={settings,messages:[...messages],hasMore:false,nextCursor:null,conversation:{kind:'direct',canSend:true}};break;\n case 'send':{\n let message=messages.find(m=>m.senderId===userId&&m.clientMessageId===body.clientMessageId);\n if(!message){message={...body,id:String(messages.length+1),senderId:userId,createdAt:new Date().toISOString(),readAt:null};messages.push(message);}\n result={message};break;\n }\n case 'read':for(const m of messages)if(m.senderId!==userId)m.readAt=new Date().toISOString();result={ok:true};break;\n case 'seen':case 'inventory':result={ok:true};break;\n default:return Response.json({error:'This local preview demonstrates text only. Connect your test account to try other features.'},{status:400});\n }\n return Response.json(result);\n };\n const mount=(element:HTMLDivElement,userId:string)=>mountRobonoMessenger(element,{companyName:'Example company',userId,getAccessToken:async()=>'local-preview-only',contacts:{alice:{name:'Alice'},bob:{name:'Bob'}},endpoint:'/local-preview-never-sent',fetch:transport(userId),notifications:false,mediaUrl:false,persistence:false});\n const a=mount(alice.current,'alice'),b=mount(bob.current,'bob');return()=>{a.unmount();b.unmount();};\n },[]);\n return <main style={{padding:16,fontFamily:'system-ui'}}><h1>Try a conversation</h1><p>Local preview · Fictional Alice and Bob · Text stays in this page and disappears on reload. This does not test your live connection.</p><p>Open Bob on the left and Alice on the right, then send a message.</p><div style={{display:'flex',flexWrap:'wrap',gap:16}}><section style={{flex:'1 1 320px'}}><h2>Alice</h2><div ref={alice} style={{height:640}}/></section><section style={{flex:'1 1 320px'}}><h2>Bob</h2><div ref={bob} style={{height:640}}/></section></div></main>;\n}\n","src/vite-env.d.ts":"/// <reference types=\"vite/client\" />\n","README.md":"# Robono Messenger preview\n\nRun `npm start`, then open the printed localhost address. This uses the supplied Messenger with fictional Alice and Bob; it sends no messages to Robono and clears on reload. It demonstrates text and layout, not uploads, calls, Maps or live delivery.\n\nFor a real test connection, generate a separate example with `npx --package @robono/server robono-messenger-example --live`. For your own app, run `npx --package @robono/server robono-messenger-install` inside that app and follow https://robono.com/guides/hosted-messenger.html . Keep your existing login and server-side permissions.\n",".gitignore":"node_modules/\ndist/\n.env\n.env.*.local\n"},"live":{"package.json":"{\n \"name\": \"robono-messaging-web-example\",\n \"private\": true,\n \"type\": \"module\",\n \"engines\": {\n \"node\": \">=22.12\"\n },\n \"scripts\": {\n \"dev\": \"node --env-file-if-exists=.env server.mjs\",\n \"build\": \"tsc --noEmit && vite build\",\n \"start\": \"node --env-file-if-exists=.env server.mjs\"\n },\n \"dependencies\": {\n \"@robono/messaging\": \"^0.7.0\",\n \"@robono/messaging-web\": \"^0.9.0\",\n \"@robono/server\": \"^0.26.0\",\n \"react\": \"^19.2.3\",\n \"react-dom\": \"^19.2.3\",\n \"@robono/location\": \"^0.4.0\"\n },\n \"devDependencies\": {\n \"@types/react\": \"^19.2.2\",\n \"@types/react-dom\": \"^19.2.2\",\n \"typescript\": \"^6.0.3\",\n \"vite\": \"^7.3.6\"\n }\n}\n","server.mjs":"// Local example only. Production hosts supply their own identity/session service.\nimport http from \"node:http\";\nimport { randomBytes, timingSafeEqual } from \"node:crypto\";\nimport { pathToFileURL } from \"node:url\";\nimport * as publishedSdk from \"@robono/server\";\nexport async function startExample({\n apiKey = process.env.ROBONO_API_KEY,\n password = process.env.DEMO_PASSWORD,\n baseUrl = process.env.ROBONO_MESSAGING_URL,\n sessionsUrl,\n connectionsUrl,\n port = Number(process.env.PORT || 5188),\n userPrefix = process.env.DEMO_USER_PREFIX || \"website-demo\",\n robono: provided,\n // Repository development only. Downloaded examples use the published packages.\n workspaceSdk = process.env.ROBONO_WORKSPACE_SDK === '1',\n} = {}) {\n const {RobonoMessagingBackend,RobonoMessengerConnections,createRobonoTokenHandler} = workspaceSdk\n ? await import('../../packages/server/dist/index.js') : publishedSdk;\n if (process.env.NODE_ENV === \"production\")\n throw Error(\n \"The example sign-in is for local development. Use your own production authentication.\",\n );\n if (!password || password.length < 12)\n throw Error(\"Set DEMO_PASSWORD to at least 12 characters.\");\n if (!apiKey)\n throw Error(\"Set your test integration ROBONO_API_KEY.\");\n const robono =\n provided ??\n new RobonoMessagingBackend({ apiKey, ...(baseUrl ? { baseUrl } : {}) });\n const users = { alice: userPrefix + \"-alice\", bob: userPrefix + \"-bob\" };\n const connections=new RobonoMessengerConnections({apiKey,...(connectionsUrl?{baseUrl:connectionsUrl}:{})});\n const relationship = await connections.synchronizeContact({\n externalUserIds: Object.values(users),\n allowed: true,\n revision: 1,\n });\n const group = await robono.setGroup({\n externalGroupId: userPrefix + \"-group\",\n name: \"Website group\",\n ownerId: users.alice,\n revision: 1,\n allowed: true,\n members: Object.values(users).map((userId) => ({ userId, canSend: true })),\n });\n const conversations = [\n { id: relationship.conversationId, name: \"Direct conversation\" },\n { id: group.conversationId, name: \"Website group\" },\n ];\n const sessions = new Map(),\n attempts = new Map();\n const authenticate = async (request) => {\n const token = request.headers\n .get(\"authorization\")\n ?.replace(/^Bearer\\s+/i, \"\");\n const session = sessions.get(token);\n return session && session.expires > Date.now() ? session.userId : null;\n };\n let tokenHandler;\n const { createServer } = await import(\"vite\");\n let vite;\n const server = http.createServer(async (req, res) => {\n const send = (value, status = 200) => {\n res.writeHead(status, {\n \"content-type\": \"application/json\",\n \"cache-control\": \"no-store\",\n });\n res.end(JSON.stringify(value));\n };\n const host = \"127.0.0.1:\" + server.address().port,\n origin = \"http://\" + host;\n if (\n req.headers.host !== host ||\n (req.headers.origin && req.headers.origin !== origin)\n )\n return send({ error: { message: \"Origin not allowed.\" } }, 403);\n if (!req.url?.startsWith(\"/api/\"))\n return vite.middlewares(req, res, () =>\n send({ error: { message: \"Not found.\" } }, 404),\n );\n if (req.method !== \"POST\")\n return send({ error: { message: \"Use POST.\" } }, 405);\n try {\n let raw = \"\";\n for await (const part of req) {\n raw += part;\n if (raw.length > 65536)\n return send({ error: { message: \"Request too large.\" } }, 413);\n }\n const body = JSON.parse(raw || \"{}\");\n if (req.url === \"/api/session\") {\n const address = req.socket.remoteAddress,\n now = Date.now();\n const attempt = attempts.get(address);\n const count =\n attempt && attempt.reset > now\n ? attempt\n : { count: 0, reset: now + 60000 };\n attempts.set(address, count);\n if (++count.count > 10)\n return send({ error: { message: \"Try again in a minute.\" } }, 429);\n const received = Buffer.from(String(body.password ?? \"\")),\n expected = Buffer.from(password);\n if (\n !Object.hasOwn(users, body.user) ||\n received.length !== expected.length ||\n !timingSafeEqual(received, expected)\n )\n return send({ error: { message: \"Sign-in failed.\" } }, 401);\n const token = randomBytes(32).toString(\"base64url\");\n sessions.set(token, {\n userId: users[body.user],\n expires: now + 3600000,\n });\n return send({\n token,\n userId: users[body.user],\n conversations,\n participants: Object.fromEntries(\n Object.entries(users).map(([name, id]) => [\n id,\n { name: name === \"alice\" ? \"Alice\" : \"Bob\" },\n ]),\n ),\n });\n }\n const request = new Request(origin + req.url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: req.headers.authorization ?? \"\",\n ...(req.headers.origin?{origin:req.headers.origin}:{}),\n },\n body: raw,\n });\n if (req.url === \"/api/logout\") {\n sessions.delete(req.headers.authorization?.replace(/^Bearer\\s+/i, \"\"));\n return send({ ok: true });\n }\n if(new URL(request.url).pathname!==\"/api/robono-token\")return send({error:{message:\"Not found.\"}},404);\n const response = await tokenHandler(request);\n res.writeHead(response.status, Object.fromEntries(response.headers));\n res.end(await response.text());\n } catch {\n send({ error: { message: \"Request failed.\" } }, 503);\n }\n });\n vite = await createServer({\n root: new URL(\".\", import.meta.url).pathname,\n server: { middlewareMode: true, hmr: {server} },\n appType: \"spa\",\n cacheDir: \"node_modules/.vite-robono-example\",\n resolve: { dedupe: [\"react\", \"react-dom\", \"@robono/messaging\"], ...(workspaceSdk ? {alias:{\n '@robono/location':new URL('../../packages/location/dist/index.js',import.meta.url).pathname,\n '@robono/messaging':new URL('../../packages/messaging/dist/index.js',import.meta.url).pathname,\n '@robono/messaging-web':new URL('../../packages/messaging-web/dist/index.js',import.meta.url).pathname,\n }} : {}) },\n ...(workspaceSdk ? {optimizeDeps:{noDiscovery:true,include:['react','react-dom','react-dom/client','react/jsx-runtime','react/jsx-dev-runtime'],exclude:['@robono/messaging','@robono/messaging-web','@robono/location','make-plural/cardinals']}} : {}),\n });\n await new Promise((resolve) => server.listen(port, \"127.0.0.1\", resolve));\n tokenHandler=createRobonoTokenHandler({apiKey,authenticate,origins:[\"http://127.0.0.1:\"+server.address().port],...(sessionsUrl?{baseUrl:sessionsUrl}:{})});\n return {\n url: \"http://127.0.0.1:\" + server.address().port,\n users,\n conversations,\n async close() {\n await vite.close();\n server.closeAllConnections();\n await new Promise((resolve) => server.close(resolve));\n },\n };\n}\nif (\n process.argv[1] &&\n import.meta.url === pathToFileURL(process.argv[1]).href\n) {\n const app = await startExample();\n console.log(\"Website messaging example: \" + app.url);\n for (const signal of [\"SIGINT\", \"SIGTERM\"])\n process.once(signal, () => void app.close().then(() => process.exit()));\n}\n","index.html":"<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>Robono website messaging</title></head><body><div id=\"root\"><main style=\"font-family:system-ui;max-width:600px;margin:48px auto;padding:20px\"><h1>Robono website messaging</h1><p id=\"startup-message\">Opening the chat…</p><noscript>Enable JavaScript to use this example.</noscript></main></div><script>if(location.protocol==='file:')document.getElementById('startup-message').textContent='Start this example with npm start in its folder, then open http://127.0.0.1:5188 in your browser. Opening this file directly cannot connect the chat.';window.addEventListener('error',function(){var message=document.getElementById('startup-message');if(message&&location.protocol!=='file:')message.textContent='The chat could not start. Check that npm start is still running, then refresh this page.';},true);</script><script type=\"module\" src=\"/src/main.tsx\"></script></body></html>\n","tsconfig.json":"{\n \"compilerOptions\": {\n \"target\": \"ES2022\", \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\", \"moduleResolution\": \"Bundler\", \"jsx\": \"react-jsx\",\n \"strict\": true, \"skipLibCheck\": true, \"esModuleInterop\": true,\n \"noEmit\": true, \"types\": [\"vite/client\"]\n },\n \"include\": [\"src\"]\n}\n","src/main.tsx":"import React, { useEffect, useState, useRef } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport {mountHostedRobonoMessenger} from \"@robono/messaging-web\";\nimport {hostedRobonoTokenProvider} from \"@robono/messaging\";\nimport \"./style.css\";\ntype Session = {\n token: string;\n userId: string;\n conversations: { id: string; name: string }[];\n participants: Record<string, { name: string }>;\n};\nfunction App() {\n const [session,setSession]=useState<Session|null>(null),[error,setError]=useState(''),[busy,setBusy]=useState(false),[attempt,setAttempt]=useState(0);\n const host=useRef<HTMLDivElement>(null),messenger=useRef<Awaited<ReturnType<typeof mountHostedRobonoMessenger>>|null>(null);\n useEffect(()=>{\n if(!session||!host.current)return;\n const controller=new AbortController();let mounted:Awaited<ReturnType<typeof mountHostedRobonoMessenger>>|undefined;setError('');\n void mountHostedRobonoMessenger(host.current,{\n userId:session.userId,signal:controller.signal,\n tokenProvider:hostedRobonoTokenProvider({tokenEndpoint:'/api/robono-token',getAccessToken:async()=>session.token}),\n companyName:'Example company',contacts:session.participants,participants:session.participants,\n account:{name:session.participants[session.userId]?.name??'Example account'},style:{height:'min(700px,75dvh)'},\n }).then(value=>{if(controller.signal.aborted){void value.signOut().catch(()=>{});return;}mounted=value;messenger.current=value;}).catch(()=>{if(!controller.signal.aborted)setError('Could not connect to messaging. Check your sign-in connection.');});\n return()=>{controller.abort();if(messenger.current===mounted)messenger.current=null;mounted?.unmount();};\n },[session,attempt]);\n async function login(e: React.FormEvent<HTMLFormElement>) {\n e.preventDefault();\n setBusy(true);\n setError(\"\");\n const form = new FormData(e.currentTarget);\n try {\n const r = await fetch(\"/api/session\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(Object.fromEntries(form)),\n });\n const data = await r.json();\n if (!r.ok) throw Error(data.error?.message ?? \"Sign-in failed.\");\n setSession(data);\n } catch (e) {\n setError((e as Error).message);\n } finally {\n setBusy(false);\n }\n }\n async function logout() {\n const token = session?.token;\n try {\n await messenger.current?.signOut();\n } catch {\n setError(\"Signed out, but this browser could not erase saved drafts. Clear this site's browser data before sharing this computer.\");\n } finally {\n setSession(null);\n }\n if (token)\n await fetch(\"/api/logout\", {\n method: \"POST\",\n headers: {\n authorization: \"Bearer \" + token,\n \"content-type\": \"application/json\",\n },\n body: \"{}\",\n }).catch(() => {});\n }\n return (\n <main>\n <h1>Robono website messaging</h1>\n <p>\n This local example uses your test integration and your existing\n messaging design.\n </p>\n {!session ? (\n <form onSubmit={login}>\n <label>\n Example user\n <select name=\"user\">\n <option value=\"alice\">Alice</option>\n <option value=\"bob\">Bob</option>\n </select>\n </label>\n <label>\n Demo password\n <input\n name=\"password\"\n type=\"password\"\n required\n autoComplete=\"current-password\"\n />\n </label>\n <button disabled={busy}>Sign in</button>\n </form>\n ) : (\n <>\n <div className=\"toolbar\"><button onClick={()=>void logout()}>Sign out</button></div>\n <div ref={host} style={{height:'min(700px,75dvh)'}}/>\n </>\n )}\n {error && <p role=\"alert\">{error} {session&&<button onClick={()=>setAttempt(value=>value+1)}>Retry</button>}</p>}\n </main>\n );\n}\ncreateRoot(document.getElementById(\"root\")!).render(\n <React.StrictMode>\n <App />\n </React.StrictMode>,\n);\n","src/style.css":"body {\n margin: 0;\n background: #f4f5f2;\n color: #252b21;\n font:\n 16px system-ui,\n sans-serif;\n}\nmain {\n max-width: 960px;\n margin: 24px auto;\n padding: 0 16px;\n}\nh1 {\n font-size: 24px;\n}\nform,\n.toolbar {\n display: flex;\n gap: 12px;\n align-items: end;\n flex-wrap: wrap;\n margin: 16px 0;\n}\nform label,\n.toolbar label {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\nform input,\nform select,\n.toolbar select,\nform button,\n.toolbar button {\n font: inherit;\n padding: 10px;\n border: 1px solid #bfc6ba;\n border-radius: 8px;\n background: white;\n}\nbutton {\n cursor: pointer;\n}\nmain > section {\n border: 1px solid #cbd0c6;\n border-radius: 12px;\n}\np[role=\"alert\"] {\n color: #9b241f;\n}\n@media (max-width: 500px) {\n main {\n margin: 12px auto;\n padding: 0 8px;\n }\n h1 {\n font-size: 20px;\n }\n .toolbar {\n margin: 10px 0;\n }\n}\n",".env.example":"# Server only. Never prefix this key with VITE_. Use a TEST integration.\nROBONO_API_KEY=\n# Local demo sign-in only; replace with your own identity service in production.\nDEMO_PASSWORD=\nPORT=5188\n# Each independent example installation can choose its own fixture prefix.\nDEMO_USER_PREFIX=website-demo\n","README.md":"# Website messaging integration example\n\nThis example uses Robono's hosted Messenger. Its small local server signs Alice or Bob in and issues a short-lived user token. Messages, files, calls and Maps connect directly to Robono; they do not pass through that local server. The Robono API key stays on the server.\n\nRequirements: Node 22+, a Robono **test** integration with Messaging and Group messaging enabled. Choose the tools and appearance in **Features & preview**.\n\n```sh\ncd examples/messaging-web\nnpm install\ncp .env.example .env\n# Set ROBONO_API_KEY and a random DEMO_PASSWORD of at least 12 characters.\nnpm start\n```\n\nOpen the printed `http://127.0.0.1:5188` address in two browser profiles. Sign in as Alice and Bob with the demo password. Open the direct conversation or Website group and exchange messages. Selected photos and videos have removable thumbnails; sent images open in the supplied viewer. Interrupted sends remain available for recovery.\n\nThe default test users are `website-demo-alice` and `website-demo-bob`. Use a different `DEMO_USER_PREFIX` for independent demonstrations. The example creates these contacts and a group at revision 1. Do not reuse that prefix for real users or independently change these memberships. Sent messages and attachments remain subject to your test integration's storage, retention and usage settings after the example stops.\n\n## Use in your application\n\nThe automatic installer is the recommended starting point:\n\n```sh\nnpx --package @robono/server robono-messenger-install\n```\n\nKeep your existing sign-in. The generated `/api/robono-token` handler verifies that login and obtains a token for that verified user. Synchronize who may communicate, group membership and blocks from your own authoritative records. Pass your users' names and avatars to the supplied Messenger. No chat-forwarding server is required.\n\nThe password sign-in in this example is **local development only**. The example binds to localhost and refuses production mode. `npm run build` validates the frontend; it does not turn the example's authentication into a production login service. Never expose the demo server or put the private API key in browser files.\n\nFor notifications, register your HTTPS website origin and chat page in **Your app → Message notifications**. The installer puts the notification helper on your own website; browser rules require this small file on the same origin. Users enable alerts in the supplied Account screen. Website notifications do not require Firebase credentials. On iPhone, browser notifications require a Home Screen installation. Native iPhone/Android apps need their own Apple/Google notification credentials, as explained during setup.\n\nCall `await chat.signOut()` before ending your application's user session. This clears private saved work and revokes the Robono session. The supplied example's Sign out button follows that order.\n\nSee [the hosted setup guide](https://robono.com/guides/hosted-messenger.html) for supported frameworks, existing login connections and optional customization. Repository development can use `ROBONO_WORKSPACE_SDK=1 npm start` after building the SDK packages. Downloaded files always use the published packages.\n",".gitignore":"node_modules/\ndist/\n.env\n.env.*.local\n"}}
|
|
@@ -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":"AAMA,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,CAoElJ"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { sdkPackage } from './generated/sdk-versions.js';
|
|
2
|
+
import { join, relative } from 'node:path';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { messengerPreviewTemplates } from './messenger-preview-template.js';
|
|
5
|
+
import { hostedMessengerFiles } from './messenger-hosted-templates.js';
|
|
6
|
+
import { hostedFrameworkFiles } from './messenger-framework-templates.js';
|
|
7
|
+
import { project, appRoot, manager, installCommand, exists, safePath, recordGeneratedFiles, messengerInstallerVersion } from './messenger-install.js';
|
|
8
|
+
export async function buildHostedMessengerInstallation(options, mode) {
|
|
9
|
+
const client = await project(options.project), platform = client.deps.expo ? 'expo' : 'web';
|
|
10
|
+
const origin = new URL(options.origin);
|
|
11
|
+
if (origin.origin !== options.origin || origin.protocol !== 'https:' && !(origin.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(origin.hostname)))
|
|
12
|
+
throw Error('Use your exact HTTPS website origin.');
|
|
13
|
+
const auth = options.auth ?? (client.deps['@supabase/supabase-js'] ? 'supabase' : client.deps.firebase ? 'firebase' : 'custom');
|
|
14
|
+
if (!['custom', 'supabase', 'firebase'].includes(auth))
|
|
15
|
+
throw Error('Choose your existing sign-in provider.');
|
|
16
|
+
if (!options.auth && client.deps['@supabase/supabase-js'] && client.deps.firebase)
|
|
17
|
+
throw Error('Both sign-in providers are installed. Select --auth supabase, firebase or custom.');
|
|
18
|
+
if (platform === 'expo' && !/^[~^]?(55|56)\./.test(client.deps.expo))
|
|
19
|
+
throw Error('The supplied phone media components currently require Expo 55–56. Do not upgrade your app automatically.');
|
|
20
|
+
const tokenUrl = new URL(options.tokenEndpoint ?? '/api/robono-token', options.origin);
|
|
21
|
+
if (tokenUrl.search || tokenUrl.hash || tokenUrl.username || tokenUrl.password || tokenUrl.protocol !== 'https:' && !(tokenUrl.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(tokenUrl.hostname)))
|
|
22
|
+
throw Error('Use a token endpoint on your existing sign-in server origin.');
|
|
23
|
+
const tokenEndpoint = platform === 'web' && tokenUrl.origin === origin.origin ? tokenUrl.pathname : tokenUrl.href;
|
|
24
|
+
const server = options.serverProject ? await project(options.serverProject) : client;
|
|
25
|
+
if (platform === 'expo' && options.serverProject && server.root === client.root)
|
|
26
|
+
throw Error('Keep private sign-in files outside the phone project.');
|
|
27
|
+
const next = !!server.deps.next && platform === 'web' || !!options.serverProject && !!server.deps.next;
|
|
28
|
+
const serverBase = next ? await appRoot(server.root) : '';
|
|
29
|
+
const clientBase = await exists(join(client.root, 'src')) ? 'src' : '';
|
|
30
|
+
const templates = hostedMessengerFiles({ platform, framework: 'fetch', origin: options.origin, companyName: options.companyName, auth, tokenEndpoint });
|
|
31
|
+
const files = [], replacements = [];
|
|
32
|
+
files.push({ path: join(client.root, '.robono/ASSISTANT.md'), content: await readFile(new URL('./integration-assistant.txt', import.meta.url), 'utf8') });
|
|
33
|
+
const react = platform === 'expo' || !!client.deps.react || !!client.deps.next;
|
|
34
|
+
const framework = client.deps.vue ? 'vue' : client.deps.svelte ? 'svelte' : client.deps['@angular/core'] ? 'angular' : 'browser';
|
|
35
|
+
if (!react)
|
|
36
|
+
for (const [name, content] of Object.entries(hostedFrameworkFiles(tokenEndpoint, options.companyName, framework)))
|
|
37
|
+
files.push({ path: join(client.root, clientBase, 'robono', name), content });
|
|
38
|
+
for (const [name, value] of Object.entries(templates))
|
|
39
|
+
if (react && name.startsWith('client/')) {
|
|
40
|
+
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;
|
|
41
|
+
files.push({ path: join(client.root, clientBase, 'robono', name), content });
|
|
42
|
+
}
|
|
43
|
+
if (platform === 'web')
|
|
44
|
+
files.push({ path: join(client.root, 'public/robono-notifications/worker.js'), content: templates['public/robono-notifications/worker.js'] });
|
|
45
|
+
if (next) {
|
|
46
|
+
files.push({ path: join(server.root, '.robono/server.env.example'), content: templates['.env.example'] });
|
|
47
|
+
files.push({ path: join(server.root, serverBase, 'robono/server/robono-access.ts'), content: templates['server/robono-access.ts'] });
|
|
48
|
+
files.push({ path: join(server.root, serverBase, 'robono/server/robono-token.ts'), content: templates['server/robono-token.ts'] });
|
|
49
|
+
if (tokenUrl.pathname !== '/api/robono-token')
|
|
50
|
+
throw Error('Automatic Next.js token route uses /api/robono-token. For a custom path mount the supplied token handler in your existing route.');
|
|
51
|
+
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" });
|
|
52
|
+
}
|
|
53
|
+
if (platform === 'web' && react) {
|
|
54
|
+
const preview = messengerPreviewTemplates(), content = client.deps.vite ? preview.client.replaceAll("process.env.NODE_ENV!=='development'", '!import.meta.env.DEV') : preview.client;
|
|
55
|
+
files.push({ path: join(client.root, clientBase, 'robono/client/RobonoPreview.tsx'), content });
|
|
56
|
+
if (client.deps.next)
|
|
57
|
+
files.push({ path: join(client.root, await appRoot(client.root), 'app/robono-preview/page.tsx'), content: preview.page });
|
|
58
|
+
}
|
|
59
|
+
const notes = [`Robono-hosted ${platform === 'expo' ? 'phone' : 'website'} Messenger. No communication server needs to be deployed by you.`,
|
|
60
|
+
'Your existing backend verifies login and requests a short-lived Robono token. Keep the private Robono key there.',
|
|
61
|
+
`Sign-in endpoint: ${tokenUrl.href}. Synchronize your permitted people/groups and location grants through the server APIs.`,
|
|
62
|
+
'Pass your existing sign-in and contacts to CustomerMessenger. No new user accounts or second login.',
|
|
63
|
+
'Maps: register your website origin or both phone app identifiers in Robono Maps setup. Synchronize your own people and sharing grants.',
|
|
64
|
+
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.'];
|
|
65
|
+
const cm = await manager(client.root, client.pkg);
|
|
66
|
+
const packages = [sdkPackage('messaging'), platform === 'expo' ? sdkPackage('messaging-react-native') : sdkPackage('messaging-web'), sdkPackage('location'), ...(platform === 'expo' ? [sdkPackage('calling'), sdkPackage('calling-react-native'), sdkPackage('location-react-native'), 'react-native-webrtc@^124.0.8', 'react-native-incall-manager@^4.3.0'] : [])];
|
|
67
|
+
if (platform === 'web') {
|
|
68
|
+
if (!client.deps.react)
|
|
69
|
+
packages.push('react@^19');
|
|
70
|
+
if (!client.deps['react-dom'])
|
|
71
|
+
packages.push('react-dom@' + (client.deps.react ?? '^19'));
|
|
72
|
+
}
|
|
73
|
+
const commands = [installCommand(client.root, cm, packages)];
|
|
74
|
+
if (next)
|
|
75
|
+
commands.push(installCommand(server.root, await manager(server.root, server.pkg), [sdkPackage('server'), ...(auth === 'firebase' && !server.deps['firebase-admin'] ? ['firebase-admin@^14'] : []), ...(auth === 'supabase' && !server.deps['@supabase/supabase-js'] ? ['@supabase/supabase-js@^2'] : [])]));
|
|
76
|
+
if (platform === 'expo') {
|
|
77
|
+
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] });
|
|
78
|
+
const dynamic = await exists(join(client.root, 'app.config.js')) || await exists(join(client.root, 'app.config.ts'));
|
|
79
|
+
if (dynamic)
|
|
80
|
+
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.');
|
|
81
|
+
else {
|
|
82
|
+
const path = join(client.root, 'app.json');
|
|
83
|
+
await safePath(path);
|
|
84
|
+
const before = await readFile(path, 'utf8'), config = JSON.parse(before);
|
|
85
|
+
if (!config.expo || !Array.isArray(config.expo.plugins ?? []))
|
|
86
|
+
throw Error('Expected a valid Expo app.json.');
|
|
87
|
+
const plugins = config.expo.plugins ?? [];
|
|
88
|
+
if (!plugins.some((p) => (Array.isArray(p) ? p[0] : p) === '@robono/messaging-react-native/setup')) {
|
|
89
|
+
config.expo.plugins = [...plugins, '@robono/messaging-react-native/setup'];
|
|
90
|
+
replacements.push({ path, before, after: JSON.stringify(config, null, 2) + '\n' });
|
|
91
|
+
files.push({ path: join(client.root, '.robono/app.json.before-install'), content: before });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
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' };
|
|
96
|
+
files.push({ path: join(client.root, '.robono/setup.json'), content: JSON.stringify(setup, null, 2) + '\n' });
|
|
97
|
+
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.`;
|
|
98
|
+
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' });
|
|
99
|
+
if (mode === 'new')
|
|
100
|
+
for (const file of files) {
|
|
101
|
+
await safePath(file.path);
|
|
102
|
+
if (await exists(file.path))
|
|
103
|
+
throw Error('Already exists: ' + file.path + '. Use --upgrade or preserve your existing integration.');
|
|
104
|
+
}
|
|
105
|
+
if (mode !== 'resume')
|
|
106
|
+
recordGeneratedFiles(files, client.root, server.root);
|
|
107
|
+
return { platform, auth, files: mode === 'resume' ? [] : files, replacements: mode === 'resume' ? [] : replacements, commands, notes, setupFile: join(client.root, '.robono/setup.json') };
|
|
108
|
+
}
|
|
109
|
+
//# 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"}
|