@robono/server 0.24.0 → 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.
- package/CHANGELOG.md +4 -0
- package/HISTORY-IMPORT.md +97 -0
- package/HOSTED.md +241 -0
- package/README.md +11 -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/history-import-cli.d.ts +11 -0
- package/dist/history-import-cli.d.ts.map +1 -0
- package/dist/history-import-cli.js +83 -0
- package/dist/history-import-cli.js.map +1 -0
- package/dist/history-import.d.ts +64 -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 +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- 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.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/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-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 +107 -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 +23 -0
- package/dist/messenger-install.d.ts.map +1 -1
- package/dist/messenger-install.js +22 -8
- 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-upgrade.js +1 -1
- package/dist/messenger-upgrade.js.map +1 -1
- package/package.json +6 -3
|
@@ -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":"AAAA,OAAO,EAAC,IAAI,EAAC,QAAQ,EAAS,MAAM,WAAW,CAAC;AAChD,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAC,yBAAyB,EAAC,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAC,oBAAoB,EAAC,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAC,oBAAoB,EAAC,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAC,OAAO,EAAC,OAAO,EAAC,OAAO,EAAC,cAAc,EAAC,MAAM,EAAC,QAAQ,EAAC,oBAAoB,EAAC,yBAAyB,EAAwD,MAAM,wBAAwB,CAAC;AAEpM,MAAM,CAAC,KAAK,UAAU,gCAAgC,CAAC,OAA+B,EAAC,IAA6B;IACnH,MAAM,MAAM,GAAC,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAC,QAAQ,GAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAA,CAAC,CAAA,MAAM,CAAA,CAAC,CAAA,KAAK,CAAC;IACnF,MAAM,MAAM,GAAC,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,IAAG,MAAM,CAAC,MAAM,KAAG,OAAO,CAAC,MAAM,IAAE,MAAM,CAAC,QAAQ,KAAG,QAAQ,IAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAG,OAAO,IAAE,CAAC,WAAW,EAAC,WAAW,EAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAAC,MAAM,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC7M,MAAM,IAAI,GAAC,OAAO,CAAC,IAAI,IAAE,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA,CAAC,CAAA,UAAU,CAAA,CAAC,CAAA,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAA,CAAC,CAAA,UAAU,CAAA,CAAC,CAAA,QAAQ,CAAC,CAAC;IACpH,IAAG,CAAC,CAAC,QAAQ,EAAC,UAAU,EAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAC,MAAM,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC1G,IAAG,CAAC,OAAO,CAAC,IAAI,IAAE,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,IAAE,MAAM,CAAC,IAAI,CAAC,QAAQ;QAAC,MAAM,KAAK,CAAC,mFAAmF,CAAC,CAAC;IAC9K,IAAG,QAAQ,KAAG,MAAM,IAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAK,CAAC;QAAC,MAAM,KAAK,CAAC,0GAA0G,CAAC,CAAC;IACzL,MAAM,QAAQ,GAAC,IAAI,GAAG,CAAC,OAAO,CAAC,aAAa,IAAE,mBAAmB,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAClF,IAAG,QAAQ,CAAC,MAAM,IAAE,QAAQ,CAAC,IAAI,IAAE,QAAQ,CAAC,QAAQ,IAAE,QAAQ,CAAC,QAAQ,IAAE,QAAQ,CAAC,QAAQ,KAAG,QAAQ,IAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,KAAG,OAAO,IAAE,CAAC,WAAW,EAAC,WAAW,EAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAAC,MAAM,KAAK,CAAC,8DAA8D,CAAC,CAAC;IACjR,MAAM,aAAa,GAAC,QAAQ,KAAG,KAAK,IAAE,QAAQ,CAAC,MAAM,KAAG,MAAM,CAAC,MAAM,CAAA,CAAC,CAAA,QAAQ,CAAC,QAAQ,CAAA,CAAC,CAAA,QAAQ,CAAC,IAAI,CAAC;IACtG,MAAM,MAAM,GAAC,OAAO,CAAC,aAAa,CAAA,CAAC,CAAA,MAAM,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAA,CAAC,CAAA,MAAM,CAAC;IAC/E,IAAG,QAAQ,KAAG,MAAM,IAAE,OAAO,CAAC,aAAa,IAAE,MAAM,CAAC,IAAI,KAAG,MAAM,CAAC,IAAI;QAAC,MAAM,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC5I,MAAM,IAAI,GAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAE,QAAQ,KAAG,KAAK,IAAE,CAAC,CAAC,OAAO,CAAC,aAAa,IAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;IAC7F,MAAM,UAAU,GAAC,IAAI,CAAA,CAAC,CAAA,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA,CAAC,CAAA,EAAE,CAAC;IACpD,MAAM,UAAU,GAAC,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,KAAK,CAAC,CAAC,CAAA,CAAC,CAAA,KAAK,CAAA,CAAC,CAAA,EAAE,CAAC;IAChE,MAAM,SAAS,GAAC,oBAAoB,CAAC,EAAC,QAAQ,EAAC,SAAS,EAAC,OAAO,EAAC,MAAM,EAAC,OAAO,CAAC,MAAM,EAAC,WAAW,EAAC,OAAO,CAAC,WAAW,EAAC,IAAI,EAAC,aAAa,EAAC,CAAC,CAAC;IAC5I,MAAM,KAAK,GAA+B,EAAE,EAAC,YAAY,GAAsC,EAAE,CAAC;IAClG,MAAM,KAAK,GAAC,QAAQ,KAAG,MAAM,IAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,IAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;IACvE,MAAM,SAAS,GAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAA,CAAC,CAAA,KAAK,CAAA,CAAC,CAAA,MAAM,CAAC,IAAI,CAAC,MAAM,CAAA,CAAC,CAAA,QAAQ,CAAA,CAAC,CAAA,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA,CAAC,CAAA,SAAS,CAAA,CAAC,CAAA,SAAS,CAAC;IACnH,IAAG,CAAC,KAAK;QAAC,KAAI,MAAM,CAAC,IAAI,EAAC,OAAO,CAAC,IAAG,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,aAAa,EAAC,OAAO,CAAC,WAAW,EAAC,SAAS,CAAC,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,UAAU,EAAC,QAAQ,EAAC,IAAI,CAAC,EAAC,OAAO,EAAC,CAAC,CAAC;IAC7L,KAAI,MAAM,CAAC,IAAI,EAAC,KAAK,CAAC,IAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;QAAC,IAAG,KAAK,IAAE,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAC,CAAC;YACxF,MAAM,OAAO,GAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAA,CAAC,CAAA,KAAK,CAAC,UAAU,CAAC,sCAAsC,EAAC,qBAAqB,CAAC,CAAC,UAAU,CAAC,sCAAsC,EAAC,sBAAsB,CAAC,CAAA,CAAC,CAAA,KAAK,CAAC;YAC9L,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,UAAU,EAAC,QAAQ,EAAC,IAAI,CAAC,EAAC,OAAO,EAAC,CAAC,CAAC;QACvE,CAAC;IACD,IAAG,QAAQ,KAAG,KAAK;QAAC,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,uCAAuC,CAAC,EAAC,OAAO,EAAC,SAAS,CAAC,uCAAuC,CAAE,EAAC,CAAC,CAAC;IAC7J,IAAG,IAAI,EAAC,CAAC;QACR,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,4BAA4B,CAAC,EAAC,OAAO,EAAC,SAAS,CAAC,cAAc,CAAE,EAAC,CAAC,CAAC;QACrG,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,UAAU,EAAC,gCAAgC,CAAC,EAAC,OAAO,EAAC,SAAS,CAAC,yBAAyB,CAAE,EAAC,CAAC,CAAC;QAC/H,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,UAAU,EAAC,+BAA+B,CAAC,EAAC,OAAO,EAAC,SAAS,CAAC,wBAAwB,CAAE,EAAC,CAAC,CAAC;QAC7H,IAAG,QAAQ,CAAC,QAAQ,KAAG,mBAAmB;YAAC,MAAM,KAAK,CAAC,kIAAkI,CAAC,CAAC;QAC3L,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,UAAU,EAAC,+BAA+B,CAAC,EAAC,OAAO,EAAC,sLAAsL,EAAC,CAAC,CAAC;IAChR,CAAC;IACD,IAAG,QAAQ,KAAG,KAAK,IAAE,KAAK,EAAC,CAAC;QAC3B,MAAM,OAAO,GAAC,yBAAyB,EAAE,EAAC,OAAO,GAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAA,CAAC,CAAA,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,sCAAsC,EAAC,sBAAsB,CAAC,CAAA,CAAC,CAAA,OAAO,CAAC,MAAM,CAAC;QAC3K,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,UAAU,EAAC,iCAAiC,CAAC,EAAC,OAAO,EAAC,CAAC,CAAC;QAC1F,IAAG,MAAM,CAAC,IAAI,CAAC,IAAI;YAAC,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAC,6BAA6B,CAAC,EAAC,OAAO,EAAC,OAAO,CAAC,IAAI,EAAC,CAAC,CAAC;IACxI,CAAC;IACD,MAAM,KAAK,GAAC,CAAC,iBAAiB,QAAQ,KAAG,MAAM,CAAA,CAAC,CAAA,OAAO,CAAA,CAAC,CAAA,SAAS,kEAAkE;QAClI,kHAAkH;QAClH,qBAAqB,QAAQ,CAAC,IAAI,yFAAyF;QAC3H,qGAAqG;QACrG,wIAAwI;QACxI,QAAQ,KAAG,MAAM,CAAA,CAAC,CAAA,+EAA+E,CAAA,CAAC,CAAA,yHAAyH,CAAC,CAAC;IAC9N,MAAM,EAAE,GAAC,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAC,CAAC,0BAA0B,EAAC,QAAQ,KAAG,MAAM,CAAA,CAAC,CAAA,uCAAuC,CAAA,CAAC,CAAA,8BAA8B,EAAC,yBAAyB,EAAC,GAAG,CAAC,QAAQ,KAAG,MAAM,CAAA,CAAC,CAAA,CAAC,wBAAwB,EAAC,qCAAqC,EAAC,sCAAsC,EAAC,8BAA8B,EAAC,oCAAoC,CAAC,CAAA,CAAC,CAAA,EAAE,CAAC,CAAC,CAAC;IACrW,IAAG,QAAQ,KAAG,KAAK,EAAC,CAAC;QAAA,IAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK;YAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAAA,IAAG,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;YAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,GAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,IAAE,KAAK,CAAC,CAAC,CAAC;IAAA,CAAC;IAC3J,MAAM,QAAQ,GAAC,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,EAAC,EAAE,EAAC,QAAQ,CAAC,CAAC,CAAC;IACzD,IAAG,IAAI;QAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,EAAC,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAC,MAAM,CAAC,GAAG,CAAC,EAAC,CAAC,wBAAwB,EAAC,GAAG,CAAC,IAAI,KAAG,UAAU,IAAE,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA,CAAC,CAAA,CAAC,oBAAoB,CAAC,CAAA,CAAC,CAAA,EAAE,CAAC,EAAC,GAAG,CAAC,IAAI,KAAG,UAAU,IAAE,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA,CAAC,CAAA,CAAC,0BAA0B,CAAC,CAAA,CAAC,CAAA,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACnS,IAAG,QAAQ,KAAG,MAAM,EAAC,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,EAAC,GAAG,EAAC,MAAM,CAAC,IAAI,EAAC,OAAO,EAAC,OAAO,CAAC,QAAQ,EAAC,IAAI,EAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,2BAA2B,CAAC,EAAC,SAAS,EAAC,YAAY,EAAC,mBAAmB,EAAC,sBAAsB,EAAC,kBAAkB,EAAC,cAAc,EAAC,YAAY,EAAC,cAAc,EAAC,YAAY,EAAC,aAAa,EAAC,gCAAgC,EAAC,kBAAkB,EAAC,gBAAgB,EAAC,wBAAwB,EAAC,uBAAuB,EAAC,sBAAsB,EAAC,WAAW,EAAC,oBAAoB,EAAC,mBAAmB,EAAC,eAAe,EAAC,mBAAmB,EAAC,cAAc,EAAC,gBAAgB,EAAC,mBAAmB,EAAC,IAAI,GAAC,EAAE,CAAC,EAAC,CAAC,CAAC;QAC5iB,MAAM,OAAO,GAAC,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,eAAe,CAAC,CAAC,IAAE,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,eAAe,CAAC,CAAC,CAAC;QAC/G,IAAG,OAAO;YAAC,KAAK,CAAC,IAAI,CAAC,qKAAqK,CAAC,CAAC;aACzL,CAAC;YACJ,MAAM,IAAI,GAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,UAAU,CAAC,CAAC;YAAA,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;YAAA,MAAM,MAAM,GAAC,MAAM,QAAQ,CAAC,IAAI,EAAC,MAAM,CAAC,EAAC,MAAM,GAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAChI,IAAG,CAAC,MAAM,CAAC,IAAI,IAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,IAAE,EAAE,CAAC;gBAAC,MAAM,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACxG,MAAM,OAAO,GAAC,MAAM,CAAC,IAAI,CAAC,OAAO,IAAE,EAAE,CAAC;YACtC,IAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAK,EAAC,EAAE,CAAA,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA,CAAC,CAAA,CAAC,CAAC,CAAC,CAAC,CAAA,CAAC,CAAA,CAAC,CAAC,KAAG,sCAAsC,CAAC,EAAC,CAAC;gBAAA,MAAM,CAAC,IAAI,CAAC,OAAO,GAAC,CAAC,GAAG,OAAO,EAAC,sCAAsC,CAAC,CAAC;gBAAA,YAAY,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,MAAM,EAAC,KAAK,EAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAC,IAAI,EAAC,CAAC,CAAC,GAAC,IAAI,EAAC,CAAC,CAAC;gBAAA,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,iCAAiC,CAAC,EAAC,OAAO,EAAC,MAAM,EAAC,CAAC,CAAC;YAAA,CAAC;QACzU,CAAC;IACF,CAAC;IACD,MAAM,KAAK,GAAC,EAAC,MAAM,EAAC,CAAC,EAAC,gBAAgB,EAAC,yBAAyB,EAAC,UAAU,EAAC,QAAQ,EAAC,MAAM,EAAC,QAAQ,EAAC,UAAU,EAAC,UAAU,EAAC,aAAa,EAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAC,MAAM,CAAC,IAAI,CAAC,IAAE,GAAG,EAAC,QAAQ,EAAC,IAAI,EAAC,WAAW,EAAC,OAAO,CAAC,WAAW,EAAC,MAAM,EAAC,OAAO,CAAC,MAAM,EAAC,aAAa,EAAC,QAAQ,CAAC,IAAI,EAAC,YAAY,EAAC,SAAS,EAAC,CAAC;IACxS,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,oBAAoB,CAAC,EAAC,OAAO,EAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAC,IAAI,EAAC,CAAC,CAAC,GAAC,IAAI,EAAC,CAAC,CAAC;IACpG,MAAM,EAAE,GAAC,KAAK,CAAA,CAAC,CAAA,gCAAgC,GAAC,IAAI,CAAC,UAAU,EAAC,iCAAiC,CAAC,GAAC,SAAS,GAAC,CAAC,IAAI,KAAG,QAAQ,CAAA,CAAC,CAAA,mDAAmD,CAAA,CAAC,CAAA,sBAAsB,GAAC,IAAI,GAAC,UAAU,CAAC,GAAC,gBAAgB,CAAA,CAAC,CAAA,qBAAqB,SAAS,iBAAiB,IAAI,CAAC,UAAU,EAAC,QAAQ,CAAC,+IAA+I,CAAC;IACnc,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,kBAAkB,CAAC,EAAC,OAAO,EAAC,iCAAiC,GAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA,EAAE,CAAA,IAAI,GAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAC,uBAAuB,GAAC,CAAC,IAAI,CAAA,CAAC,CAAA,wKAAwK,CAAA,CAAC,CAAA,gMAAgM,CAAC,GAAC,oBAAoB,GAAC,EAAE,GAAC,mZAAmZ,EAAC,CAAC,CAAC;IACv7B,IAAG,IAAI,KAAG,KAAK;QAAC,KAAI,MAAM,IAAI,IAAI,KAAK,EAAC,CAAC;YAAA,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAA,IAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAC,MAAM,KAAK,CAAC,kBAAkB,GAAC,IAAI,CAAC,IAAI,GAAC,wDAAwD,CAAC,CAAC;QAAA,CAAC;IAClM,IAAG,IAAI,KAAG,QAAQ;QAAC,oBAAoB,CAAC,KAAK,EAAC,MAAM,CAAC,IAAI,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvE,OAAO,EAAC,QAAQ,EAAC,IAAI,EAAC,KAAK,EAAC,IAAI,KAAG,QAAQ,CAAA,CAAC,CAAA,EAAE,CAAA,CAAC,CAAA,KAAK,EAAC,YAAY,EAAC,IAAI,KAAG,QAAQ,CAAA,CAAC,CAAA,EAAE,CAAA,CAAC,CAAA,YAAY,EAAC,QAAQ,EAAC,KAAK,EAAC,SAAS,EAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAC,oBAAoB,CAAC,EAAC,CAAC;AACpK,CAAC"}
|
|
@@ -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"}
|
|
@@ -9,25 +9,28 @@ let prompt;
|
|
|
9
9
|
try {
|
|
10
10
|
for (let i = 0; i < args.length; i++) {
|
|
11
11
|
const arg = args[i];
|
|
12
|
-
if (['--help', '--yes', '--dry-run', '--no-install', '--check', '--json', '--resume', '--upgrade'].includes(arg)) {
|
|
12
|
+
if (['--help', '--yes', '--dry-run', '--no-install', '--check', '--json', '--resume', '--upgrade', '--self-hosted'].includes(arg)) {
|
|
13
13
|
flags.add(arg);
|
|
14
14
|
continue;
|
|
15
15
|
}
|
|
16
|
-
if (!['--project', '--server-project', '--origin', '--company', '--auth'].includes(arg) || !args[i + 1] || args[i + 1].startsWith('--') || values[arg])
|
|
16
|
+
if (!['--project', '--server-project', '--origin', '--company', '--auth', '--token-endpoint'].includes(arg) || !args[i + 1] || args[i + 1].startsWith('--') || values[arg])
|
|
17
17
|
throw Error('Unknown or missing option. Use --help.');
|
|
18
18
|
values[arg] = args[++i];
|
|
19
19
|
}
|
|
20
20
|
if (flags.has('--help')) {
|
|
21
21
|
console.log(`robono-messenger-install [--project .] [--server-project ../server] [--auth supabase|firebase|custom] --origin https://your-company.com --company "Your company"
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
Installs the Robono-hosted Messenger and matching packages into your existing app.
|
|
23
|
+
--token-endpoint selects your existing sign-in server endpoint; the default is /api/robono-token.
|
|
24
|
+
Your backend only verifies login and issues short-lived sessions. Communication traffic goes directly to Robono.
|
|
25
|
+
Next.js can receive the token route automatically. Other backends use the supplied language examples.
|
|
26
|
+
Existing screens and .env files are preserved. --self-hosted keeps the advanced customer-hosted adapter.
|
|
24
27
|
--dry-run lists the exact files and commands without changing anything.
|
|
25
28
|
--yes applies that plan without an interactive prompt. --no-install writes files only.
|
|
26
29
|
--resume finishes package installation using your saved setup, preserving all existing integration code.
|
|
27
30
|
--upgrade updates unchanged generated files, backs them up, and saves proposals for edited files. Use --dry-run first to review.
|
|
28
|
-
React + Vite
|
|
31
|
+
React + Vite can stay on static hosting when using Robono hosting; your existing sign-in service issues tokens.
|
|
29
32
|
--check shows one setup checklist; set the three ROBONO_* test variables to include live checks. --json prints a shareable checklist.
|
|
30
|
-
|
|
33
|
+
Hosted setup uses your existing sign-in. The optional --self-hosted preview uses fictional people.`);
|
|
31
34
|
}
|
|
32
35
|
else if (flags.has('--check')) {
|
|
33
36
|
if (flags.has('--upgrade') || flags.has('--resume'))
|
|
@@ -68,7 +71,7 @@ The development-only /robono-preview route uses fictional people and never sends
|
|
|
68
71
|
const auth = values['--auth'];
|
|
69
72
|
if (auth && !['custom', 'supabase', 'firebase'].includes(auth))
|
|
70
73
|
throw Error('Choose custom, supabase or firebase.');
|
|
71
|
-
const plan = flags.has('--upgrade') ? await planMessengerUpgrade(values['--project'] ?? '.', values['--company'] ? { companyName: values['--company'] } : {}) : flags.has('--resume') ? await planMessengerInstallationResume(values['--project'] ?? '.') : await planMessengerInstallation({ project: values['--project'] ?? '.', origin: origin, companyName: companyName, ...(values['--server-project'] ? { serverProject: values['--server-project'] } : {}), ...(auth ? { auth: auth } : {}) });
|
|
74
|
+
const plan = flags.has('--upgrade') ? await planMessengerUpgrade(values['--project'] ?? '.', values['--company'] ? { companyName: values['--company'] } : {}) : flags.has('--resume') ? await planMessengerInstallationResume(values['--project'] ?? '.') : await planMessengerInstallation({ project: values['--project'] ?? '.', origin: origin, companyName: companyName, ...(values['--server-project'] ? { serverProject: values['--server-project'] } : {}), ...(auth ? { auth: auth } : {}), connection: flags.has('--self-hosted') ? 'self-hosted' : 'hosted', ...(values['--token-endpoint'] ? { tokenEndpoint: values['--token-endpoint'] } : {}) });
|
|
72
75
|
for (const file of plan.files)
|
|
73
76
|
console.log('Create: ' + file.path);
|
|
74
77
|
for (const file of plan.replacements)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messenger-install-cli.js","sourceRoot":"","sources":["../src/messenger-install-cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAC,eAAe,EAAC,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAC,KAAK,EAAC,MAAM,EAAC,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAC,yBAAyB,EAAC,+BAA+B,EAAC,0BAA0B,EAAC,8BAA8B,EAAC,MAAM,wBAAwB,CAAC;AAC3J,OAAO,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAC,yBAAyB,EAAC,MAAM,sBAAsB,CAAC;AAC/D,MAAM,IAAI,GAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAC,MAAM,GAAuB,EAAE,EAAC,KAAK,GAAC,IAAI,GAAG,EAAU,CAAC;AACzF,IAAI,MAAmD,CAAC;AACxD,IAAG,CAAC;IACH,KAAI,IAAI,CAAC,GAAC,CAAC,EAAC,CAAC,GAAC,IAAI,CAAC,MAAM,EAAC,CAAC,EAAE,EAAC,CAAC;QAC9B,MAAM,GAAG,GAAC,IAAI,CAAC,CAAC,CAAE,CAAC;QACnB,IAAG,CAAC,QAAQ,EAAC,OAAO,EAAC,WAAW,EAAC,cAAc,EAAC,SAAS,EAAC,QAAQ,EAAC,UAAU,EAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAC,CAAC;YAAA,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAAA,SAAS;QAAA,CAAC;
|
|
1
|
+
{"version":3,"file":"messenger-install-cli.js","sourceRoot":"","sources":["../src/messenger-install-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,14 @@ export interface MessengerInstallOptions {
|
|
|
4
4
|
origin: string;
|
|
5
5
|
companyName: string;
|
|
6
6
|
auth?: 'custom' | 'supabase' | 'firebase';
|
|
7
|
+
connection?: 'hosted' | 'self-hosted';
|
|
8
|
+
tokenEndpoint?: string;
|
|
7
9
|
}
|
|
10
|
+
type Manifest = {
|
|
11
|
+
dependencies?: Record<string, string>;
|
|
12
|
+
devDependencies?: Record<string, string>;
|
|
13
|
+
packageManager?: string;
|
|
14
|
+
};
|
|
8
15
|
export interface MessengerInstallPlan {
|
|
9
16
|
platform: 'web' | 'expo';
|
|
10
17
|
auth: 'custom' | 'supabase' | 'firebase';
|
|
@@ -28,12 +35,27 @@ export interface MessengerInstallPlan {
|
|
|
28
35
|
export declare const messengerInstallerVersion = "0.24.0";
|
|
29
36
|
export declare const generatedHash: (content: string) => string;
|
|
30
37
|
export declare function generatedKey(file: string, client: string, server: string): string;
|
|
38
|
+
export declare function recordGeneratedFiles(files: MessengerInstallPlan['files'], client: string, server: string): void;
|
|
31
39
|
export declare function exists(file: string): Promise<boolean>;
|
|
40
|
+
export declare function project(directory: string): Promise<{
|
|
41
|
+
root: string;
|
|
42
|
+
pkg: Manifest;
|
|
43
|
+
deps: {
|
|
44
|
+
[x: string]: string;
|
|
45
|
+
};
|
|
46
|
+
}>;
|
|
32
47
|
export declare function safePath(file: string): Promise<void>;
|
|
33
48
|
export declare function readMessengerSetup(file: string): Promise<{
|
|
34
49
|
text: string;
|
|
35
50
|
setup: any;
|
|
36
51
|
}>;
|
|
52
|
+
export declare function appRoot(root: string): Promise<string>;
|
|
53
|
+
export declare function installCommand(root: string, manager: string, packages: string[]): {
|
|
54
|
+
cwd: string;
|
|
55
|
+
command: string;
|
|
56
|
+
args: string[];
|
|
57
|
+
};
|
|
58
|
+
export declare function manager(root: string, pkg: Manifest): Promise<string>;
|
|
37
59
|
export declare function planMessengerInstallation(options: MessengerInstallOptions): Promise<MessengerInstallPlan>;
|
|
38
60
|
export declare function buildMessengerInstallation(options: MessengerInstallOptions, mode: 'new' | 'resume' | 'upgrade'): Promise<MessengerInstallPlan>;
|
|
39
61
|
/** Reconstruct trusted package commands; never execute commands from saved metadata. */
|
|
@@ -45,4 +67,5 @@ export declare function messengerInstallationChecklist(directory: string): Promi
|
|
|
45
67
|
status: string;
|
|
46
68
|
detail: string;
|
|
47
69
|
}[]>;
|
|
70
|
+
export {};
|
|
48
71
|
//# sourceMappingURL=messenger-install.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messenger-install.d.ts","sourceRoot":"","sources":["../src/messenger-install.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"messenger-install.d.ts","sourceRoot":"","sources":["../src/messenger-install.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,uBAAuB;IAAE,OAAO,EAAC,MAAM,CAAC;IAAA,aAAa,CAAC,EAAC,MAAM,CAAC;IAAA,MAAM,EAAC,MAAM,CAAC;IAAA,WAAW,EAAC,MAAM,CAAC;IAAA,IAAI,CAAC,EAAC,QAAQ,GAAC,UAAU,GAAC,UAAU,CAAC;IAAA,UAAU,CAAC,EAAC,QAAQ,GAAC,aAAa,CAAC;IAAA,aAAa,CAAC,EAAC,MAAM,CAAA;CAAC;AAC9M,KAAK,QAAQ,GAAC;IAAC,YAAY,CAAC,EAAC,MAAM,CAAC,MAAM,EAAC,MAAM,CAAC,CAAC;IAAA,eAAe,CAAC,EAAC,MAAM,CAAC,MAAM,EAAC,MAAM,CAAC,CAAC;IAAA,cAAc,CAAC,EAAC,MAAM,CAAA;CAAC,CAAC;AAClH,MAAM,WAAW,oBAAoB;IAAE,QAAQ,EAAC,KAAK,GAAC,MAAM,CAAC;IAAA,IAAI,EAAC,QAAQ,GAAC,UAAU,GAAC,UAAU,CAAC;IAAA,KAAK,EAAC;QAAC,IAAI,EAAC,MAAM,CAAC;QAAA,OAAO,EAAC,MAAM,CAAA;KAAC,EAAE,CAAC;IAAA,YAAY,EAAC;QAAC,IAAI,EAAC,MAAM,CAAC;QAAA,MAAM,EAAC,MAAM,CAAC;QAAA,KAAK,EAAC,MAAM,CAAA;KAAC,EAAE,CAAC;IAAA,QAAQ,EAAC;QAAC,GAAG,EAAC,MAAM,CAAC;QAAA,OAAO,EAAC,MAAM,CAAC;QAAA,IAAI,EAAC,MAAM,EAAE,CAAA;KAAC,EAAE,CAAC;IAAA,KAAK,EAAC,MAAM,EAAE,CAAC;IAAA,SAAS,CAAC,EAAC,MAAM,CAAA;CAAC;AACpR,eAAO,MAAM,yBAAyB,WAAS,CAAC;AAChD,eAAO,MAAM,aAAa,GAAE,SAAQ,MAAM,WAAqD,CAAC;AAChG,wBAAgB,YAAY,CAAC,IAAI,EAAC,MAAM,EAAC,MAAM,EAAC,MAAM,EAAC,MAAM,EAAC,MAAM,UAInE;AACD,wBAAgB,oBAAoB,CAAC,KAAK,EAAC,oBAAoB,CAAC,OAAO,CAAC,EAAC,MAAM,EAAC,MAAM,EAAC,MAAM,EAAC,MAAM,QAKnG;AACD,wBAAsB,MAAM,CAAC,IAAI,EAAC,MAAM,oBAAqH;AAC7J,wBAAsB,OAAO,CAAC,SAAS,EAAC,MAAM;;;;;;GAK7C;AACD,wBAAsB,QAAQ,CAAC,IAAI,EAAC,MAAM,iBAGzC;AACD,wBAAsB,kBAAkB,CAAC,IAAI,EAAC,MAAM;;;GAMnD;AACD,wBAAsB,OAAO,CAAC,IAAI,EAAC,MAAM,mBAGxC;AACD,wBAAgB,cAAc,CAAC,IAAI,EAAC,MAAM,EAAC,OAAO,EAAC,MAAM,EAAC,QAAQ,EAAC,MAAM,EAAE;;;;EAG1E;AACD,wBAAsB,OAAO,CAAC,IAAI,EAAC,MAAM,EAAC,GAAG,EAAC,QAAQ,mBAQrD;AACD,wBAAsB,yBAAyB,CAAC,OAAO,EAAC,uBAAuB,GAAE,OAAO,CAAC,oBAAoB,CAAC,CAE7G;AACD,wBAAsB,0BAA0B,CAAC,OAAO,EAAC,uBAAuB,EAAC,IAAI,EAAC,KAAK,GAAC,QAAQ,GAAC,SAAS,GAAE,OAAO,CAAC,oBAAoB,CAAC,CAuF5I;AACD,wFAAwF;AACxF,wBAAsB,+BAA+B,CAAC,SAAS,EAAC,MAAM,GAAE,OAAO,CAAC,oBAAoB,CAAC,CAapG;AAaD,yFAAyF;AACzF,wBAAsB,0BAA0B,CAAC,IAAI,EAAC,oBAAoB,EAAC,OAAO,UAAK,iBAoCtF;AACD,wBAAsB,8BAA8B,CAAC,SAAS,EAAC,MAAM;;;;KA+BpE"}
|
|
@@ -5,6 +5,7 @@ import { readFile, writeFile, mkdir, lstat, realpath, unlink, rename } from 'nod
|
|
|
5
5
|
import { resolve, join, dirname, relative, isAbsolute } from 'node:path';
|
|
6
6
|
import spawn from 'cross-spawn';
|
|
7
7
|
import { messengerStarterFiles } from './messenger-init.js';
|
|
8
|
+
import { buildHostedMessengerInstallation } from './messenger-hosted-install.js';
|
|
8
9
|
export const messengerInstallerVersion = '0.24.0';
|
|
9
10
|
export const generatedHash = (content) => createHash('sha256').update(content).digest('hex');
|
|
10
11
|
export function generatedKey(file, client, server) {
|
|
@@ -12,7 +13,7 @@ export function generatedKey(file, client, server) {
|
|
|
12
13
|
const scope = server !== client && !isAbsolute(local) && local !== '..' && !local.startsWith('../') && !local.startsWith('..\\') ? 'server' : 'client';
|
|
13
14
|
return scope + ':' + relative(scope === 'server' ? server : client, file).split('\\').join('/');
|
|
14
15
|
}
|
|
15
|
-
function recordGeneratedFiles(files, client, server) {
|
|
16
|
+
export function recordGeneratedFiles(files, client, server) {
|
|
16
17
|
const metadata = files.find(file => file.path === join(client, '.robono/setup.json'));
|
|
17
18
|
const setup = JSON.parse(metadata.content);
|
|
18
19
|
setup.generated = Object.fromEntries(files.filter(file => file !== metadata && !file.path.endsWith('.before-install')).map(file => [generatedKey(file.path, client, server), generatedHash(file.content)]));
|
|
@@ -27,7 +28,7 @@ catch (e) {
|
|
|
27
28
|
return false;
|
|
28
29
|
throw e;
|
|
29
30
|
} }
|
|
30
|
-
async function project(directory) {
|
|
31
|
+
export async function project(directory) {
|
|
31
32
|
const root = resolve(directory);
|
|
32
33
|
if (await realpath(root) !== root)
|
|
33
34
|
throw Error('Use a project path without symbolic links.');
|
|
@@ -64,7 +65,7 @@ export async function readMessengerSetup(file) {
|
|
|
64
65
|
throw Error('Saved Robono setup is not valid JSON. It was not changed.');
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
|
-
async function appRoot(root) {
|
|
68
|
+
export async function appRoot(root) {
|
|
68
69
|
for (const base of ['src', ''])
|
|
69
70
|
if (await exists(join(root, base, 'app'))) {
|
|
70
71
|
await safePath(join(root, base, 'app'));
|
|
@@ -72,12 +73,12 @@ async function appRoot(root) {
|
|
|
72
73
|
}
|
|
73
74
|
throw Error('Automatic website installation supports Next.js App Router. Create its app directory first, or use robono-messenger-init for another server.');
|
|
74
75
|
}
|
|
75
|
-
function installCommand(root, manager, packages) {
|
|
76
|
+
export function installCommand(root, manager, packages) {
|
|
76
77
|
if (!['npm', 'pnpm', 'yarn'].includes(manager))
|
|
77
78
|
throw Error('Supported package managers: npm, pnpm, yarn.');
|
|
78
79
|
return { cwd: root, command: manager, args: manager === 'npm' ? ['install', '--ignore-scripts', '--', ...packages] : manager === 'pnpm' ? ['add', '--ignore-scripts', '--', ...packages] : ['add', '--ignore-scripts', ...packages] };
|
|
79
80
|
}
|
|
80
|
-
async function manager(root, pkg) {
|
|
81
|
+
export async function manager(root, pkg) {
|
|
81
82
|
const locks = [];
|
|
82
83
|
for (const [file, name] of [['package-lock.json', 'npm'], ['pnpm-lock.yaml', 'pnpm'], ['yarn.lock', 'yarn']])
|
|
83
84
|
if (await exists(join(root, file)))
|
|
@@ -95,6 +96,8 @@ export async function planMessengerInstallation(options) {
|
|
|
95
96
|
return buildMessengerInstallation(options, 'new');
|
|
96
97
|
}
|
|
97
98
|
export async function buildMessengerInstallation(options, mode) {
|
|
99
|
+
if (options.connection === 'hosted')
|
|
100
|
+
return buildHostedMessengerInstallation(options, mode);
|
|
98
101
|
const resume = mode === 'resume';
|
|
99
102
|
const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(Number);
|
|
100
103
|
if (nodeMajor < 22 || nodeMajor === 22 && nodeMinor < 12)
|
|
@@ -147,8 +150,8 @@ export async function buildMessengerInstallation(options, mode) {
|
|
|
147
150
|
files.push({ path: join(client.root, '.robono/setup.json'), content: JSON.stringify(setup, null, 2) + '\n' });
|
|
148
151
|
files.push({ path: join(client.root, '.robono/SETUP.md'), content: '# Connect your messenger\n\n' + notes.map(x => '- ' + x).join('\n') + '\n\n## Connect your screen\n' + (auth === 'custom' ? 'Implement RobonoAccounts from client/ConnectedRobonoChat.tsx using your existing sign-in. Render <CustomerMessenger accounts={yourAccounts} contacts={yourContacts}/>.' : 'Import CustomerMessenger from the generated client/CustomerMessenger.tsx. Render <CustomerMessenger auth={yourExistingSignInClient} contacts={yourContacts}/>.') + ' Give the messenger an area with a height. Keep it mounted in your signed-in application. It follows account changes; names and avatars update without restarting chat. For Supabase use its client; for Firebase use its Auth instance.\n\n## Allow the right people\nThe generated server uses Robono-managed permissions. Your sign-in supplies the verified account; Robono checks the contacts, groups and Maps viewer grants supplied by your server. An optional authorize callback in robono-access.ts can add extra business restrictions. When a friendship changes, call synchronizeFriendship(getMessenger(), friendship) on your server. Use revisions from your database; group membership uses getMessenger().robono.setGroup. You do not need to write a permission handler for each action. Existing custom authorize functions remain connected during safe upgrades.\n\n## Sign-out\nThe messenger account menu clears local content and unregisters notifications before provider sign-out. If your own account menu signs out first, provider events still clear the visible chat. Keep account suspension and relationship revocation synchronized with Robono; an expired session cannot reliably unregister a remote device. Never substitute another account’s token.\n\n## Check the connection\nDuring development, add setupChecks to CustomerMessenger and press Check connection after signing in to your app. It uses your current login; no copied tokens are needed. It checks settings, available chats and notification configuration without sending a message. This optional panel is hidden in production.\n\nRun robono-messenger-install --check for the local checklist. For additional command-line security checks, set ROBONO_MESSENGER_URL, ROBONO_WEBSITE_ORIGIN and ROBONO_TEST_USER_TOKEN locally. Add --json for a shareable report without secrets. No local checker can prove your complete permission rules; test denied accounts and cross-account access too.\n\n## Safe upgrades\nRun robono-messenger-install --upgrade --dry-run to review, then --upgrade to apply. Unchanged generated files are backed up and updated. Edited files stay untouched; review .robono/upgrade-report.json for proposed changes.\n\n## Interrupted installation\nRun robono-messenger-install --resume from the same project. It reinstalls the required packages without replacing your integration code, screens or environment files.\n\n## Server configuration\nSet ROBONO_API_KEY privately on the server. Use ROBONO_ALLOWED_ORIGINS for your production website addresses instead of editing generated code. Never use a wildcard. Existing Next.js Supabase public settings are reused; see server.env.example.\n\n## Notifications\nFor website alerts configure your HTTPS origin and chat path. For iPhone, upload your APNs .p8 key, key ID, Team ID and Bundle ID in Robono. For Android, configure google-services.json in your app and upload the Firebase messaging service account privately in Robono. Never put private keys in client code. The supplied phone Messenger automatically registers system incoming calls using these credentials; there is no additional push database or background sign-in service to build. The Apple key must permit the app’s VoIP topic. Build both apps after native dependency changes.\n\n## Maps, weather and tracking\nThe supplied Messenger connects these through the same signed-in backend. Choose Maps placement in Robono: inside messaging, a separate Maps page, or both. Standalone Maps appears in the main menu when selected. Permissions for sharing still come from your server; never create grants in phone or browser code.\n\nFor web map display, register the exact HTTPS origin in Robono Maps. For phones, register the iPhone Bundle ID and Android package plus signing fingerprint. Download each registration to .robono/maps-ios.json and .robono/maps-android.json in the phone project, run --upgrade, and rebuild both apps. Keep these platform-restricted map keys out of public examples. Provider billing and private provider keys remain managed by Robono. Your users choose when to share location; background sharing asks for the phone permission. Browser sharing ends when the page is hidden. Movement is independent of location: iPhone movement requires the app open, Android supports its visible service, and browser movement requires a supported device and visible page. Ordinary messaging and weather do not require map registration.\n\n## Local preview\nOpen /robono-preview on your Next.js development server. It uses the actual web messenger with fictional Alice and Bob and local text only. It sends no customer requests and returns 404 in production.\n' });
|
|
149
152
|
files.push({ path: join(server.root, '.robono/server.env.example'), content: templates['.env.example'] });
|
|
150
|
-
const serverPackages = ['@robono/server@^0.
|
|
151
|
-
const clientPackages = ['@robono/location@^0.
|
|
153
|
+
const serverPackages = ['@robono/server@^0.25.0', ...(platform === 'expo' ? ['@robono/location@^0.3.0', '@robono/messaging@^0.6.0', '@robono/messaging-web@^0.8.0'] : []), ...(auth === 'supabase' ? ['@supabase/supabase-js@^2'] : auth === 'firebase' ? ['firebase-admin@^14'] : [])];
|
|
154
|
+
const clientPackages = ['@robono/location@^0.3.0', ...(platform === 'expo' ? ['@robono/location-react-native@^0.3.0', '@robono/calling@^0.4.0', '@robono/calling-react-native@^0.7.0', 'react-native-webrtc@^124.0.8', 'react-native-incall-manager@^4.3.0'] : []), '@robono/messaging@^0.6.0', `@robono/messaging-${platform === 'web' ? 'web' : 'react-native'}@^${platform === 'web' ? '0.8.0' : '0.9.0'}`, ...(auth === 'supabase' ? ['@supabase/supabase-js@^2'] : auth === 'firebase' ? ['firebase@^13'] : [])];
|
|
152
155
|
const packageName = (spec) => spec.slice(0, spec.lastIndexOf('@'));
|
|
153
156
|
const keepExistingProvider = (spec, deps) => !['firebase', 'firebase-admin', '@supabase/supabase-js'].includes(packageName(spec)) || !deps[packageName(spec)];
|
|
154
157
|
const serverInstall = serverPackages.filter(spec => keepExistingProvider(spec, server.deps)), clientInstall = clientPackages.filter(spec => keepExistingProvider(spec, client.deps));
|
|
@@ -225,6 +228,8 @@ export async function planMessengerInstallationResume(directory) {
|
|
|
225
228
|
const root = resolve(directory), setupFile = join(root, '.robono/setup.json');
|
|
226
229
|
await safePath(setupFile);
|
|
227
230
|
const { setup } = await readMessengerSetup(setupFile);
|
|
231
|
+
if (setup.connection === 'hosted')
|
|
232
|
+
return buildHostedMessengerInstallation({ project: root, origin: setup.origin, companyName: setup.companyName, auth: setup.auth, connection: 'hosted', tokenEndpoint: setup.tokenEndpoint, ...(setup.serverProject && setup.serverProject !== '.' ? { serverProject: resolve(root, setup.serverProject) } : {}) }, 'resume');
|
|
228
233
|
if (![1, 2, 3].includes(setup.schema) || !['web', 'expo'].includes(setup.platform) || !['custom', 'supabase', 'firebase'].includes(setup.auth) || typeof setup.origin !== 'string' || typeof setup.serverProject !== 'string' || setup.companyName !== undefined && typeof setup.companyName !== 'string')
|
|
229
234
|
throw Error('Invalid saved setup. Keep your integration files and run --check.');
|
|
230
235
|
const server = resolve(root, setup.serverProject), base = setup.layout === 'vite' ? '' : await appRoot(server);
|
|
@@ -350,6 +355,15 @@ export async function messengerInstallationChecklist(directory) {
|
|
|
350
355
|
if (!await exists(file))
|
|
351
356
|
return [{ name: 'Install files', status: 'needs-action', detail: 'Run robono-messenger-install in your Next.js, React/Vite or Expo project.' }];
|
|
352
357
|
const { setup } = await readMessengerSetup(file);
|
|
358
|
+
if (setup.connection === 'hosted')
|
|
359
|
+
return [
|
|
360
|
+
{ name: 'Robono hosting', status: 'configured', detail: 'Communication requests go directly to Robono. Your application only issues verified sign-in sessions.' },
|
|
361
|
+
{ name: 'Package installation', status: setup.dependencies === 'installed' ? 'configured' : 'needs-action', detail: setup.dependencies === 'installed' ? 'Packages installed.' : 'Run --resume to finish package installation.' },
|
|
362
|
+
{ name: 'Sign-in connection', status: 'needs-action', detail: 'Connect the generated token route to your existing verified login. Keep ROBONO_API_KEY on that server only.' },
|
|
363
|
+
{ name: 'People and permissions', status: 'needs-action', detail: 'Supply your contacts, memberships and Maps sharing grants through the server APIs.' },
|
|
364
|
+
{ name: 'Notifications', status: 'needs-action', detail: setup.platform === 'expo' ? 'Connect Apple/Google credentials in Robono and rebuild the apps.' : 'Keep public/robono-notifications/worker.js on your website and register its origin in Robono.' },
|
|
365
|
+
...(setup.pendingReview?.length ? [{ name: 'Upgrade review', status: 'needs-action', detail: 'Review preserved edits and proposals in .robono/upgrade-report.json.' }] : []),
|
|
366
|
+
];
|
|
353
367
|
const server = resolve(root, setup.serverProject), base = setup.layout === 'vite' ? '' : await appRoot(server);
|
|
354
368
|
const permissionFile = setup.layout === 'vite' ? join(root, '.robono/server/robono-access.ts') : join(server, base, 'robono/server/robono-access.ts');
|
|
355
369
|
const permission = await readFile(permissionFile, 'utf8').catch(() => 'Connect your existing messaging permission');
|
|
@@ -419,7 +433,7 @@ async function planViteInstallation(options, client, mode) {
|
|
|
419
433
|
files.push({ path: join(client.root, '.robono/server.env.example'), content: templates['.env.example'] + 'ROBONO_PUBLIC_ORIGIN=' + options.origin + '\n' });
|
|
420
434
|
files.push({ path: join(client.root, '.robono/SETUP.md'), content: '# Connect your React website\n\n' + notes.map(note => '- ' + note).join('\n') + '\n\n## Connect accounts and conversations\n' + (auth === 'custom' ? 'Implement authenticate in .robono/server/robono-access.ts and the RobonoAccounts interface using your existing sign-in. Pass accounts to CustomerMessenger.' : 'Identity checks are supplied. Pass your existing sign-in client as auth to CustomerMessenger. The generated server uses Robono-managed contacts, memberships and sharing permissions. Add authorize in .robono/server/robono-access.ts only for additional business rules.') + ' Synchronize permitted friendships and group membership from your server using synchronizeFriendship and getMessenger().robono.setGroup. Give the component your contact names and avatars. Provider credentials and the Robono key remain server-only. Browser notifications are configured in Your app → Message notifications. No Apple/Google private key is required for browser alerts.\n' + '\n\n## Safe upgrades\nRun robono-messenger-install --upgrade. Unchanged generated files update automatically. Edited files are preserved and proposed updates are listed in .robono/upgrade-report.json. Review proposed changes before applying them. --resume finishes interrupted dependency installation; it does not overwrite your code.\n' });
|
|
421
435
|
const managerName = await manager(client.root, client.pkg);
|
|
422
|
-
const runtime = ['@robono/location@^0.
|
|
436
|
+
const runtime = ['@robono/location@^0.3.0', '@robono/server@^0.25.0', '@robono/messaging@^0.6.0', '@robono/messaging-web@^0.8.0', ...(auth === 'supabase' && !client.deps['@supabase/supabase-js'] ? ['@supabase/supabase-js@^2'] : []), ...(auth === 'firebase' ? [...(!client.deps.firebase ? ['firebase@^13'] : []), ...(!client.deps['firebase-admin'] ? ['firebase-admin@^14'] : [])] : [])];
|
|
423
437
|
const dev = ['tsx@^4.23.15', 'typescript@^6', '@types/node@^22'].filter(spec => !client.deps[spec.slice(0, spec.lastIndexOf('@'))]);
|
|
424
438
|
if (updateVite) {
|
|
425
439
|
(client.pkg.dependencies?.vite ? runtime : dev).push('vite@^' + patched);
|