@fiodos/web-core 0.1.0 → 0.1.1
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/dist/cjs/dropin/createFiodosAgent.js +6 -2
- package/dist/cjs/orb/devErrorBadge.d.ts +28 -0
- package/dist/cjs/orb/devErrorBadge.js +104 -0
- package/dist/esm/dropin/createFiodosAgent.js +6 -2
- package/dist/esm/orb/devErrorBadge.d.ts +28 -0
- package/dist/esm/orb/devErrorBadge.js +100 -0
- package/package.json +1 -1
- package/dist/cjs/dropin/createFyodosAgent.d.ts +0 -60
- package/dist/cjs/dropin/createFyodosAgent.js +0 -143
- package/dist/esm/dropin/createFyodosAgent.d.ts +0 -60
- package/dist/esm/dropin/createFyodosAgent.js +0 -140
|
@@ -22,6 +22,7 @@ const webStorageAdapter_1 = require("../adapters/webStorageAdapter");
|
|
|
22
22
|
const webVoiceAdapter_1 = require("../adapters/webVoiceAdapter");
|
|
23
23
|
const AgentController_1 = require("../controller/AgentController");
|
|
24
24
|
const mountOrb_1 = require("../orb/mountOrb");
|
|
25
|
+
const devErrorBadge_1 = require("../orb/devErrorBadge");
|
|
25
26
|
const clientBootstrap_1 = require("../api/clientBootstrap");
|
|
26
27
|
function defaultNavigate(route) {
|
|
27
28
|
if (typeof window !== 'undefined' && window.location)
|
|
@@ -108,9 +109,11 @@ function createFiodosAgent(options) {
|
|
|
108
109
|
if (cancelled)
|
|
109
110
|
return null;
|
|
110
111
|
if (result.status === 'no-manifest' || !result.manifest) {
|
|
112
|
+
const reason = '[fyodos] No hay manifest publicado para esta API key todavía. Ejecuta ' +
|
|
113
|
+
'`npx @fiodos/cli analyze . --publish` o publícalo desde el dashboard, y recarga.';
|
|
111
114
|
// eslint-disable-next-line no-console
|
|
112
|
-
console.warn(
|
|
113
|
-
|
|
115
|
+
console.warn(reason);
|
|
116
|
+
(0, devErrorBadge_1.showOrbDevError)(reason, { baseUrl });
|
|
114
117
|
return null;
|
|
115
118
|
}
|
|
116
119
|
// Fail loudly here (not deep inside the controller) so onError is precise.
|
|
@@ -135,6 +138,7 @@ function createFiodosAgent(options) {
|
|
|
135
138
|
const error = e instanceof Error ? e : new Error(String(e));
|
|
136
139
|
// eslint-disable-next-line no-console
|
|
137
140
|
console.error(error.message);
|
|
141
|
+
(0, devErrorBadge_1.showOrbDevError)(error.message, { baseUrl });
|
|
138
142
|
options.onError?.(error);
|
|
139
143
|
return null;
|
|
140
144
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev-only visible failure badge.
|
|
3
|
+
*
|
|
4
|
+
* When the orb cannot mount (rejected key, no published manifest, unreachable
|
|
5
|
+
* backend), the SDK otherwise renders nothing — historically a silent failure
|
|
6
|
+
* that left developers with no clue WHY the orb never appeared (only a console
|
|
7
|
+
* line that is easy to miss). This renders a small, dismissible badge where the
|
|
8
|
+
* orb would be, stating the EXACT, actionable reason.
|
|
9
|
+
*
|
|
10
|
+
* Hard rule: this is DEVELOPMENT-ONLY. In production builds the badge never
|
|
11
|
+
* renders (the orb stays invisible, exactly as before) so end users never see
|
|
12
|
+
* Fiodos diagnostics. Gating is on `process.env.NODE_ENV === 'production'`,
|
|
13
|
+
* which every major bundler (Next, Vite, webpack, esbuild) statically replaces.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* True only in a development build. Bundlers replace `process.env.NODE_ENV`
|
|
17
|
+
* with a string literal; if `process` is genuinely absent (rare unbundled use)
|
|
18
|
+
* we default to NOT showing the badge — production safety wins over visibility.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isDevEnvironment(): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Mount (or update) the dev error badge. No-op in production, in non-DOM
|
|
23
|
+
* environments (SSR), or when called repeatedly (the message is updated in
|
|
24
|
+
* place rather than stacking badges).
|
|
25
|
+
*/
|
|
26
|
+
export declare function showOrbDevError(reason: string, opts?: {
|
|
27
|
+
baseUrl?: string;
|
|
28
|
+
}): void;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Dev-only visible failure badge.
|
|
4
|
+
*
|
|
5
|
+
* When the orb cannot mount (rejected key, no published manifest, unreachable
|
|
6
|
+
* backend), the SDK otherwise renders nothing — historically a silent failure
|
|
7
|
+
* that left developers with no clue WHY the orb never appeared (only a console
|
|
8
|
+
* line that is easy to miss). This renders a small, dismissible badge where the
|
|
9
|
+
* orb would be, stating the EXACT, actionable reason.
|
|
10
|
+
*
|
|
11
|
+
* Hard rule: this is DEVELOPMENT-ONLY. In production builds the badge never
|
|
12
|
+
* renders (the orb stays invisible, exactly as before) so end users never see
|
|
13
|
+
* Fiodos diagnostics. Gating is on `process.env.NODE_ENV === 'production'`,
|
|
14
|
+
* which every major bundler (Next, Vite, webpack, esbuild) statically replaces.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.isDevEnvironment = isDevEnvironment;
|
|
18
|
+
exports.showOrbDevError = showOrbDevError;
|
|
19
|
+
const BADGE_ID = 'fiodos-dev-error-badge';
|
|
20
|
+
/**
|
|
21
|
+
* True only in a development build. Bundlers replace `process.env.NODE_ENV`
|
|
22
|
+
* with a string literal; if `process` is genuinely absent (rare unbundled use)
|
|
23
|
+
* we default to NOT showing the badge — production safety wins over visibility.
|
|
24
|
+
*/
|
|
25
|
+
function isDevEnvironment() {
|
|
26
|
+
try {
|
|
27
|
+
return process.env.NODE_ENV !== 'production';
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Mount (or update) the dev error badge. No-op in production, in non-DOM
|
|
35
|
+
* environments (SSR), or when called repeatedly (the message is updated in
|
|
36
|
+
* place rather than stacking badges).
|
|
37
|
+
*/
|
|
38
|
+
function showOrbDevError(reason, opts) {
|
|
39
|
+
if (!isDevEnvironment())
|
|
40
|
+
return;
|
|
41
|
+
if (typeof document === 'undefined' || !document.body)
|
|
42
|
+
return;
|
|
43
|
+
const message = cleanReason(reason);
|
|
44
|
+
let badge = document.getElementById(BADGE_ID);
|
|
45
|
+
if (badge) {
|
|
46
|
+
const body = badge.querySelector('[data-fiodos-badge-msg]');
|
|
47
|
+
if (body)
|
|
48
|
+
body.textContent = message;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
badge = document.createElement('div');
|
|
52
|
+
badge.id = BADGE_ID;
|
|
53
|
+
badge.setAttribute('role', 'alert');
|
|
54
|
+
badge.style.cssText = [
|
|
55
|
+
'position:fixed',
|
|
56
|
+
'bottom:20px',
|
|
57
|
+
'right:20px',
|
|
58
|
+
'z-index:2147483000',
|
|
59
|
+
'max-width:340px',
|
|
60
|
+
'padding:12px 14px',
|
|
61
|
+
'border-radius:12px',
|
|
62
|
+
'background:#1b1b1f',
|
|
63
|
+
'color:#fff',
|
|
64
|
+
"font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif",
|
|
65
|
+
'font-size:13px',
|
|
66
|
+
'line-height:1.45',
|
|
67
|
+
'box-shadow:0 8px 28px rgba(0,0,0,0.35)',
|
|
68
|
+
'border:1px solid rgba(255,255,255,0.12)',
|
|
69
|
+
].join(';');
|
|
70
|
+
const header = document.createElement('div');
|
|
71
|
+
header.style.cssText =
|
|
72
|
+
'display:flex;align-items:center;gap:6px;margin-bottom:6px;font-weight:600;color:#ffd166';
|
|
73
|
+
header.textContent = '◉ Fiodos · el orbe no se montó (solo desarrollo)';
|
|
74
|
+
const close = document.createElement('button');
|
|
75
|
+
close.textContent = '×';
|
|
76
|
+
close.setAttribute('aria-label', 'Cerrar aviso de Fiodos');
|
|
77
|
+
close.style.cssText = [
|
|
78
|
+
'margin-left:auto',
|
|
79
|
+
'background:transparent',
|
|
80
|
+
'border:0',
|
|
81
|
+
'color:rgba(255,255,255,0.6)',
|
|
82
|
+
'font-size:18px',
|
|
83
|
+
'line-height:1',
|
|
84
|
+
'cursor:pointer',
|
|
85
|
+
'padding:0 2px',
|
|
86
|
+
].join(';');
|
|
87
|
+
close.addEventListener('click', () => badge?.remove());
|
|
88
|
+
header.appendChild(close);
|
|
89
|
+
const body = document.createElement('div');
|
|
90
|
+
body.setAttribute('data-fiodos-badge-msg', '');
|
|
91
|
+
body.textContent = message;
|
|
92
|
+
const hint = document.createElement('div');
|
|
93
|
+
hint.style.cssText = 'margin-top:8px;color:rgba(255,255,255,0.55);font-size:11.5px';
|
|
94
|
+
hint.textContent =
|
|
95
|
+
'Comprueba que la API key y la URL de tu app son las del MISMO proyecto donde publicaste. Este aviso solo aparece en desarrollo.';
|
|
96
|
+
badge.appendChild(header);
|
|
97
|
+
badge.appendChild(body);
|
|
98
|
+
badge.appendChild(hint);
|
|
99
|
+
document.body.appendChild(badge);
|
|
100
|
+
}
|
|
101
|
+
/** Strip the internal "[fyodos]" prefix so the badge reads cleanly to a human. */
|
|
102
|
+
function cleanReason(reason) {
|
|
103
|
+
return reason.replace(/^\[fyodos\]\s*/i, '').trim() || 'No se pudo montar el orbe.';
|
|
104
|
+
}
|
|
@@ -19,6 +19,7 @@ import { createWebStorageAdapter } from '../adapters/webStorageAdapter.js';
|
|
|
19
19
|
import { createWebVoiceAdapter } from '../adapters/webVoiceAdapter.js';
|
|
20
20
|
import { AgentController } from '../controller/AgentController.js';
|
|
21
21
|
import { mountOrb } from '../orb/mountOrb.js';
|
|
22
|
+
import { showOrbDevError } from '../orb/devErrorBadge.js';
|
|
22
23
|
import { DEFAULT_WEB_API_URL, fetchClientManifest, sendOrbSeen } from '../api/clientBootstrap.js';
|
|
23
24
|
function defaultNavigate(route) {
|
|
24
25
|
if (typeof window !== 'undefined' && window.location)
|
|
@@ -105,9 +106,11 @@ export function createFiodosAgent(options) {
|
|
|
105
106
|
if (cancelled)
|
|
106
107
|
return null;
|
|
107
108
|
if (result.status === 'no-manifest' || !result.manifest) {
|
|
109
|
+
const reason = '[fyodos] No hay manifest publicado para esta API key todavía. Ejecuta ' +
|
|
110
|
+
'`npx @fiodos/cli analyze . --publish` o publícalo desde el dashboard, y recarga.';
|
|
108
111
|
// eslint-disable-next-line no-console
|
|
109
|
-
console.warn(
|
|
110
|
-
|
|
112
|
+
console.warn(reason);
|
|
113
|
+
showOrbDevError(reason, { baseUrl });
|
|
111
114
|
return null;
|
|
112
115
|
}
|
|
113
116
|
// Fail loudly here (not deep inside the controller) so onError is precise.
|
|
@@ -132,6 +135,7 @@ export function createFiodosAgent(options) {
|
|
|
132
135
|
const error = e instanceof Error ? e : new Error(String(e));
|
|
133
136
|
// eslint-disable-next-line no-console
|
|
134
137
|
console.error(error.message);
|
|
138
|
+
showOrbDevError(error.message, { baseUrl });
|
|
135
139
|
options.onError?.(error);
|
|
136
140
|
return null;
|
|
137
141
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev-only visible failure badge.
|
|
3
|
+
*
|
|
4
|
+
* When the orb cannot mount (rejected key, no published manifest, unreachable
|
|
5
|
+
* backend), the SDK otherwise renders nothing — historically a silent failure
|
|
6
|
+
* that left developers with no clue WHY the orb never appeared (only a console
|
|
7
|
+
* line that is easy to miss). This renders a small, dismissible badge where the
|
|
8
|
+
* orb would be, stating the EXACT, actionable reason.
|
|
9
|
+
*
|
|
10
|
+
* Hard rule: this is DEVELOPMENT-ONLY. In production builds the badge never
|
|
11
|
+
* renders (the orb stays invisible, exactly as before) so end users never see
|
|
12
|
+
* Fiodos diagnostics. Gating is on `process.env.NODE_ENV === 'production'`,
|
|
13
|
+
* which every major bundler (Next, Vite, webpack, esbuild) statically replaces.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* True only in a development build. Bundlers replace `process.env.NODE_ENV`
|
|
17
|
+
* with a string literal; if `process` is genuinely absent (rare unbundled use)
|
|
18
|
+
* we default to NOT showing the badge — production safety wins over visibility.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isDevEnvironment(): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Mount (or update) the dev error badge. No-op in production, in non-DOM
|
|
23
|
+
* environments (SSR), or when called repeatedly (the message is updated in
|
|
24
|
+
* place rather than stacking badges).
|
|
25
|
+
*/
|
|
26
|
+
export declare function showOrbDevError(reason: string, opts?: {
|
|
27
|
+
baseUrl?: string;
|
|
28
|
+
}): void;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev-only visible failure badge.
|
|
3
|
+
*
|
|
4
|
+
* When the orb cannot mount (rejected key, no published manifest, unreachable
|
|
5
|
+
* backend), the SDK otherwise renders nothing — historically a silent failure
|
|
6
|
+
* that left developers with no clue WHY the orb never appeared (only a console
|
|
7
|
+
* line that is easy to miss). This renders a small, dismissible badge where the
|
|
8
|
+
* orb would be, stating the EXACT, actionable reason.
|
|
9
|
+
*
|
|
10
|
+
* Hard rule: this is DEVELOPMENT-ONLY. In production builds the badge never
|
|
11
|
+
* renders (the orb stays invisible, exactly as before) so end users never see
|
|
12
|
+
* Fiodos diagnostics. Gating is on `process.env.NODE_ENV === 'production'`,
|
|
13
|
+
* which every major bundler (Next, Vite, webpack, esbuild) statically replaces.
|
|
14
|
+
*/
|
|
15
|
+
const BADGE_ID = 'fiodos-dev-error-badge';
|
|
16
|
+
/**
|
|
17
|
+
* True only in a development build. Bundlers replace `process.env.NODE_ENV`
|
|
18
|
+
* with a string literal; if `process` is genuinely absent (rare unbundled use)
|
|
19
|
+
* we default to NOT showing the badge — production safety wins over visibility.
|
|
20
|
+
*/
|
|
21
|
+
export function isDevEnvironment() {
|
|
22
|
+
try {
|
|
23
|
+
return process.env.NODE_ENV !== 'production';
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Mount (or update) the dev error badge. No-op in production, in non-DOM
|
|
31
|
+
* environments (SSR), or when called repeatedly (the message is updated in
|
|
32
|
+
* place rather than stacking badges).
|
|
33
|
+
*/
|
|
34
|
+
export function showOrbDevError(reason, opts) {
|
|
35
|
+
if (!isDevEnvironment())
|
|
36
|
+
return;
|
|
37
|
+
if (typeof document === 'undefined' || !document.body)
|
|
38
|
+
return;
|
|
39
|
+
const message = cleanReason(reason);
|
|
40
|
+
let badge = document.getElementById(BADGE_ID);
|
|
41
|
+
if (badge) {
|
|
42
|
+
const body = badge.querySelector('[data-fiodos-badge-msg]');
|
|
43
|
+
if (body)
|
|
44
|
+
body.textContent = message;
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
badge = document.createElement('div');
|
|
48
|
+
badge.id = BADGE_ID;
|
|
49
|
+
badge.setAttribute('role', 'alert');
|
|
50
|
+
badge.style.cssText = [
|
|
51
|
+
'position:fixed',
|
|
52
|
+
'bottom:20px',
|
|
53
|
+
'right:20px',
|
|
54
|
+
'z-index:2147483000',
|
|
55
|
+
'max-width:340px',
|
|
56
|
+
'padding:12px 14px',
|
|
57
|
+
'border-radius:12px',
|
|
58
|
+
'background:#1b1b1f',
|
|
59
|
+
'color:#fff',
|
|
60
|
+
"font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif",
|
|
61
|
+
'font-size:13px',
|
|
62
|
+
'line-height:1.45',
|
|
63
|
+
'box-shadow:0 8px 28px rgba(0,0,0,0.35)',
|
|
64
|
+
'border:1px solid rgba(255,255,255,0.12)',
|
|
65
|
+
].join(';');
|
|
66
|
+
const header = document.createElement('div');
|
|
67
|
+
header.style.cssText =
|
|
68
|
+
'display:flex;align-items:center;gap:6px;margin-bottom:6px;font-weight:600;color:#ffd166';
|
|
69
|
+
header.textContent = '◉ Fiodos · el orbe no se montó (solo desarrollo)';
|
|
70
|
+
const close = document.createElement('button');
|
|
71
|
+
close.textContent = '×';
|
|
72
|
+
close.setAttribute('aria-label', 'Cerrar aviso de Fiodos');
|
|
73
|
+
close.style.cssText = [
|
|
74
|
+
'margin-left:auto',
|
|
75
|
+
'background:transparent',
|
|
76
|
+
'border:0',
|
|
77
|
+
'color:rgba(255,255,255,0.6)',
|
|
78
|
+
'font-size:18px',
|
|
79
|
+
'line-height:1',
|
|
80
|
+
'cursor:pointer',
|
|
81
|
+
'padding:0 2px',
|
|
82
|
+
].join(';');
|
|
83
|
+
close.addEventListener('click', () => badge?.remove());
|
|
84
|
+
header.appendChild(close);
|
|
85
|
+
const body = document.createElement('div');
|
|
86
|
+
body.setAttribute('data-fiodos-badge-msg', '');
|
|
87
|
+
body.textContent = message;
|
|
88
|
+
const hint = document.createElement('div');
|
|
89
|
+
hint.style.cssText = 'margin-top:8px;color:rgba(255,255,255,0.55);font-size:11.5px';
|
|
90
|
+
hint.textContent =
|
|
91
|
+
'Comprueba que la API key y la URL de tu app son las del MISMO proyecto donde publicaste. Este aviso solo aparece en desarrollo.';
|
|
92
|
+
badge.appendChild(header);
|
|
93
|
+
badge.appendChild(body);
|
|
94
|
+
badge.appendChild(hint);
|
|
95
|
+
document.body.appendChild(badge);
|
|
96
|
+
}
|
|
97
|
+
/** Strip the internal "[fyodos]" prefix so the badge reads cleanly to a human. */
|
|
98
|
+
function cleanReason(reason) {
|
|
99
|
+
return reason.replace(/^\[fyodos\]\s*/i, '').trim() || 'No se pudo montar el orbe.';
|
|
100
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fiodos/web-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Framework-agnostic browser layer for the Fiodos agent: a vanilla AgentController (orchestrator), DOM adapters (navigation/voice/storage), HTTP client and decision engine over @fiodos/core. Shared base for @fiodos/vue, @fiodos/svelte and @fiodos/angular (no framework imports).",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"publishConfig": {
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vanilla drop-in — assembles the default browser adapters, builds an
|
|
3
|
-
* AgentController and (optionally) mounts the DOM orb in one call. Frameworks
|
|
4
|
-
* use the AgentController + their own components; this is the zero-framework
|
|
5
|
-
* path (and the reference the Vue/Svelte/Angular drop-ins follow).
|
|
6
|
-
*
|
|
7
|
-
* PARITY WITH @fyodos/react's <FyodosAgent/>: when `manifest` is omitted, the
|
|
8
|
-
* agent self-bootstraps — it fetches the published manifest by `apiKey`
|
|
9
|
-
* (GET /v1/client/manifest), assembles default browser adapters, mounts the orb
|
|
10
|
-
* and posts the `orb-seen` heartbeat. So a one-line drop-in needs only an
|
|
11
|
-
* apiKey, exactly like React. Passing a manifest keeps the fully-synchronous,
|
|
12
|
-
* manual path.
|
|
13
|
-
*/
|
|
14
|
-
import { type ActionRegistries, type AppManifest } from '@fyodos/core';
|
|
15
|
-
import { AgentController } from '../controller/AgentController';
|
|
16
|
-
import { type MountOrbOptions, type MountedOrb } from '../orb/mountOrb';
|
|
17
|
-
import type { FyodosWebAgentConfig } from '../config/types';
|
|
18
|
-
export interface CreateFyodosAgentOptions {
|
|
19
|
-
/** Backend base URL. Defaults to the public Fyodos backend. */
|
|
20
|
-
baseUrl?: string;
|
|
21
|
-
/** Client API key (x-api-key). Required when `manifest` is omitted (auto-fetch). */
|
|
22
|
-
apiKey?: string;
|
|
23
|
-
/**
|
|
24
|
-
* The validated app manifest. OPTIONAL: omit it to self-fetch the published
|
|
25
|
-
* manifest by apiKey (the React-parity drop-in path).
|
|
26
|
-
*/
|
|
27
|
-
manifest?: AppManifest;
|
|
28
|
-
/** Action handlers / context validators (defaults to empty registries). */
|
|
29
|
-
registries?: ActionRegistries;
|
|
30
|
-
/** Agent reply locale (e.g. 'es', 'en'). Defaults to the browser language. */
|
|
31
|
-
locale?: string;
|
|
32
|
-
/** STT locale (e.g. 'es-ES', 'en-US'). Defaults to the browser language. */
|
|
33
|
-
sttLocale?: string;
|
|
34
|
-
/** Host router navigate delegate. Defaults to location.assign. */
|
|
35
|
-
navigate?: (route: string) => void;
|
|
36
|
-
/** Host auth check for actions requiring auth. */
|
|
37
|
-
isAuthenticated?: () => boolean;
|
|
38
|
-
/** Voice id forwarded to the backend TTS. */
|
|
39
|
-
ttsVoice?: string | (() => string | undefined);
|
|
40
|
-
/** End-user id for rate limiting / telemetry correlation. */
|
|
41
|
-
getUserId?: () => string | null;
|
|
42
|
-
/** Mount the built-in DOM orb. Default: true. Pass false to render your own. */
|
|
43
|
-
mount?: boolean;
|
|
44
|
-
orb?: MountOrbOptions;
|
|
45
|
-
/** Escape hatch: extra config merged into the controller config. */
|
|
46
|
-
configOverrides?: Partial<FyodosWebAgentConfig>;
|
|
47
|
-
/** Called once the manifest loaded and the orb mounted (auto-fetch path). */
|
|
48
|
-
onReady?: (controller: AgentController) => void;
|
|
49
|
-
/** Called when self-bootstrap fails (network / rejected key / no manifest). */
|
|
50
|
-
onError?: (error: Error) => void;
|
|
51
|
-
}
|
|
52
|
-
export interface FyodosAgentHandle {
|
|
53
|
-
/** Null until the async self-bootstrap resolves (auto-fetch path). */
|
|
54
|
-
controller: AgentController | null;
|
|
55
|
-
orb: MountedOrb | null;
|
|
56
|
-
/** Resolves once the controller is ready (immediately on the manual path). */
|
|
57
|
-
ready: Promise<AgentController | null>;
|
|
58
|
-
destroy(): void;
|
|
59
|
-
}
|
|
60
|
-
export declare function createFyodosAgent(options: CreateFyodosAgentOptions): FyodosAgentHandle;
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createFyodosAgent = createFyodosAgent;
|
|
4
|
-
/**
|
|
5
|
-
* Vanilla drop-in — assembles the default browser adapters, builds an
|
|
6
|
-
* AgentController and (optionally) mounts the DOM orb in one call. Frameworks
|
|
7
|
-
* use the AgentController + their own components; this is the zero-framework
|
|
8
|
-
* path (and the reference the Vue/Svelte/Angular drop-ins follow).
|
|
9
|
-
*
|
|
10
|
-
* PARITY WITH @fyodos/react's <FyodosAgent/>: when `manifest` is omitted, the
|
|
11
|
-
* agent self-bootstraps — it fetches the published manifest by `apiKey`
|
|
12
|
-
* (GET /v1/client/manifest), assembles default browser adapters, mounts the orb
|
|
13
|
-
* and posts the `orb-seen` heartbeat. So a one-line drop-in needs only an
|
|
14
|
-
* apiKey, exactly like React. Passing a manifest keeps the fully-synchronous,
|
|
15
|
-
* manual path.
|
|
16
|
-
*/
|
|
17
|
-
const core_1 = require("@fyodos/core");
|
|
18
|
-
const backendClient_1 = require("../api/backendClient");
|
|
19
|
-
const backendTelemetry_1 = require("../api/backendTelemetry");
|
|
20
|
-
const webNavigationAdapter_1 = require("../adapters/webNavigationAdapter");
|
|
21
|
-
const webStorageAdapter_1 = require("../adapters/webStorageAdapter");
|
|
22
|
-
const webVoiceAdapter_1 = require("../adapters/webVoiceAdapter");
|
|
23
|
-
const AgentController_1 = require("../controller/AgentController");
|
|
24
|
-
const mountOrb_1 = require("../orb/mountOrb");
|
|
25
|
-
const clientBootstrap_1 = require("../api/clientBootstrap");
|
|
26
|
-
function defaultNavigate(route) {
|
|
27
|
-
if (typeof window !== 'undefined' && window.location)
|
|
28
|
-
window.location.assign(route);
|
|
29
|
-
}
|
|
30
|
-
function browserLocale() {
|
|
31
|
-
const lang = typeof navigator !== 'undefined' && navigator.language ? navigator.language : 'en-US';
|
|
32
|
-
return { locale: lang.split('-')[0] || 'en', sttLocale: lang };
|
|
33
|
-
}
|
|
34
|
-
/** Build the controller + adapters from a known manifest (shared by both paths). */
|
|
35
|
-
function assemble(options, manifest, baseUrl) {
|
|
36
|
-
const fallback = browserLocale();
|
|
37
|
-
const locale = options.locale ?? fallback.locale;
|
|
38
|
-
const sttLocale = options.sttLocale ?? options.locale ?? fallback.sttLocale;
|
|
39
|
-
const backend = (0, backendClient_1.createFyodosBackendClient)({
|
|
40
|
-
baseUrl,
|
|
41
|
-
apiKey: options.apiKey,
|
|
42
|
-
getUserId: options.getUserId,
|
|
43
|
-
});
|
|
44
|
-
const telemetry = (0, backendTelemetry_1.createFyodosTelemetry)({
|
|
45
|
-
baseUrl,
|
|
46
|
-
apiKey: options.apiKey,
|
|
47
|
-
getUserId: options.getUserId,
|
|
48
|
-
});
|
|
49
|
-
const config = {
|
|
50
|
-
manifest,
|
|
51
|
-
locale,
|
|
52
|
-
sttLocale,
|
|
53
|
-
navigation: (0, webNavigationAdapter_1.createWebNavigationAdapter)({ navigate: options.navigate ?? defaultNavigate }),
|
|
54
|
-
registries: options.registries ?? { handlers: {}, idempotencyCheckers: {} },
|
|
55
|
-
backend,
|
|
56
|
-
voice: (0, webVoiceAdapter_1.createWebVoiceAdapter)(),
|
|
57
|
-
storage: (0, webStorageAdapter_1.createWebStorageAdapter)(),
|
|
58
|
-
telemetry,
|
|
59
|
-
isAuthenticated: options.isAuthenticated,
|
|
60
|
-
ttsVoice: options.ttsVoice,
|
|
61
|
-
...options.configOverrides,
|
|
62
|
-
};
|
|
63
|
-
const controller = new AgentController_1.AgentController(config);
|
|
64
|
-
controller.warmUp();
|
|
65
|
-
return controller;
|
|
66
|
-
}
|
|
67
|
-
function createFyodosAgent(options) {
|
|
68
|
-
const baseUrl = (options.baseUrl ?? clientBootstrap_1.DEFAULT_WEB_API_URL).replace(/\/$/, '');
|
|
69
|
-
const shouldMount = options.mount !== false;
|
|
70
|
-
// ── Manual path: manifest provided → fully synchronous (back-compat). ───────
|
|
71
|
-
if (options.manifest) {
|
|
72
|
-
const controller = assemble(options, options.manifest, baseUrl);
|
|
73
|
-
const orb = shouldMount ? (0, mountOrb_1.mountOrb)(controller, options.orb) : null;
|
|
74
|
-
if (shouldMount && options.apiKey) {
|
|
75
|
-
void (0, clientBootstrap_1.sendOrbSeen)({ baseUrl, apiKey: options.apiKey });
|
|
76
|
-
}
|
|
77
|
-
options.onReady?.(controller);
|
|
78
|
-
const handle = {
|
|
79
|
-
controller,
|
|
80
|
-
orb,
|
|
81
|
-
ready: Promise.resolve(controller),
|
|
82
|
-
destroy() {
|
|
83
|
-
orb?.unmount();
|
|
84
|
-
controller.dispose();
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
return handle;
|
|
88
|
-
}
|
|
89
|
-
// ── Auto path (React parity): fetch manifest by apiKey, then assemble. ──────
|
|
90
|
-
const handle = {
|
|
91
|
-
controller: null,
|
|
92
|
-
orb: null,
|
|
93
|
-
ready: Promise.resolve(null),
|
|
94
|
-
destroy() {
|
|
95
|
-
cancelled = true;
|
|
96
|
-
handle.orb?.unmount();
|
|
97
|
-
handle.controller?.dispose();
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
let cancelled = false;
|
|
101
|
-
handle.ready = (async () => {
|
|
102
|
-
try {
|
|
103
|
-
if (!options.apiKey) {
|
|
104
|
-
throw new Error('[fyodos] createFyodosAgent requires either a `manifest` or an `apiKey` ' +
|
|
105
|
-
'(to self-fetch the published manifest).');
|
|
106
|
-
}
|
|
107
|
-
const result = await (0, clientBootstrap_1.fetchClientManifest)({ baseUrl, apiKey: options.apiKey });
|
|
108
|
-
if (cancelled)
|
|
109
|
-
return null;
|
|
110
|
-
if (result.status === 'no-manifest' || !result.manifest) {
|
|
111
|
-
// eslint-disable-next-line no-console
|
|
112
|
-
console.warn('[fyodos] The orb is idle: this project has no published manifest yet. ' +
|
|
113
|
-
'Run the analysis from your Fyodos dashboard, then reload.');
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
// Fail loudly here (not deep inside the controller) so onError is precise.
|
|
117
|
-
const check = (0, core_1.validateManifest)(result.manifest);
|
|
118
|
-
if (!check.valid) {
|
|
119
|
-
throw new Error(`[fyodos] Invalid manifest for "${result.manifest.appId}":\n- ${check.errors.join('\n- ')}`);
|
|
120
|
-
}
|
|
121
|
-
const controller = assemble(options, result.manifest, baseUrl);
|
|
122
|
-
if (cancelled) {
|
|
123
|
-
controller.dispose();
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
|
-
handle.controller = controller;
|
|
127
|
-
handle.orb = shouldMount ? (0, mountOrb_1.mountOrb)(controller, options.orb) : null;
|
|
128
|
-
if (shouldMount && options.apiKey) {
|
|
129
|
-
void (0, clientBootstrap_1.sendOrbSeen)({ baseUrl, apiKey: options.apiKey });
|
|
130
|
-
}
|
|
131
|
-
options.onReady?.(controller);
|
|
132
|
-
return controller;
|
|
133
|
-
}
|
|
134
|
-
catch (e) {
|
|
135
|
-
const error = e instanceof Error ? e : new Error(String(e));
|
|
136
|
-
// eslint-disable-next-line no-console
|
|
137
|
-
console.error(error.message);
|
|
138
|
-
options.onError?.(error);
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
})();
|
|
142
|
-
return handle;
|
|
143
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vanilla drop-in — assembles the default browser adapters, builds an
|
|
3
|
-
* AgentController and (optionally) mounts the DOM orb in one call. Frameworks
|
|
4
|
-
* use the AgentController + their own components; this is the zero-framework
|
|
5
|
-
* path (and the reference the Vue/Svelte/Angular drop-ins follow).
|
|
6
|
-
*
|
|
7
|
-
* PARITY WITH @fyodos/react's <FyodosAgent/>: when `manifest` is omitted, the
|
|
8
|
-
* agent self-bootstraps — it fetches the published manifest by `apiKey`
|
|
9
|
-
* (GET /v1/client/manifest), assembles default browser adapters, mounts the orb
|
|
10
|
-
* and posts the `orb-seen` heartbeat. So a one-line drop-in needs only an
|
|
11
|
-
* apiKey, exactly like React. Passing a manifest keeps the fully-synchronous,
|
|
12
|
-
* manual path.
|
|
13
|
-
*/
|
|
14
|
-
import { type ActionRegistries, type AppManifest } from '@fyodos/core';
|
|
15
|
-
import { AgentController } from '../controller/AgentController.js';
|
|
16
|
-
import { type MountOrbOptions, type MountedOrb } from '../orb/mountOrb.js';
|
|
17
|
-
import type { FyodosWebAgentConfig } from '../config/types.js';
|
|
18
|
-
export interface CreateFyodosAgentOptions {
|
|
19
|
-
/** Backend base URL. Defaults to the public Fyodos backend. */
|
|
20
|
-
baseUrl?: string;
|
|
21
|
-
/** Client API key (x-api-key). Required when `manifest` is omitted (auto-fetch). */
|
|
22
|
-
apiKey?: string;
|
|
23
|
-
/**
|
|
24
|
-
* The validated app manifest. OPTIONAL: omit it to self-fetch the published
|
|
25
|
-
* manifest by apiKey (the React-parity drop-in path).
|
|
26
|
-
*/
|
|
27
|
-
manifest?: AppManifest;
|
|
28
|
-
/** Action handlers / context validators (defaults to empty registries). */
|
|
29
|
-
registries?: ActionRegistries;
|
|
30
|
-
/** Agent reply locale (e.g. 'es', 'en'). Defaults to the browser language. */
|
|
31
|
-
locale?: string;
|
|
32
|
-
/** STT locale (e.g. 'es-ES', 'en-US'). Defaults to the browser language. */
|
|
33
|
-
sttLocale?: string;
|
|
34
|
-
/** Host router navigate delegate. Defaults to location.assign. */
|
|
35
|
-
navigate?: (route: string) => void;
|
|
36
|
-
/** Host auth check for actions requiring auth. */
|
|
37
|
-
isAuthenticated?: () => boolean;
|
|
38
|
-
/** Voice id forwarded to the backend TTS. */
|
|
39
|
-
ttsVoice?: string | (() => string | undefined);
|
|
40
|
-
/** End-user id for rate limiting / telemetry correlation. */
|
|
41
|
-
getUserId?: () => string | null;
|
|
42
|
-
/** Mount the built-in DOM orb. Default: true. Pass false to render your own. */
|
|
43
|
-
mount?: boolean;
|
|
44
|
-
orb?: MountOrbOptions;
|
|
45
|
-
/** Escape hatch: extra config merged into the controller config. */
|
|
46
|
-
configOverrides?: Partial<FyodosWebAgentConfig>;
|
|
47
|
-
/** Called once the manifest loaded and the orb mounted (auto-fetch path). */
|
|
48
|
-
onReady?: (controller: AgentController) => void;
|
|
49
|
-
/** Called when self-bootstrap fails (network / rejected key / no manifest). */
|
|
50
|
-
onError?: (error: Error) => void;
|
|
51
|
-
}
|
|
52
|
-
export interface FyodosAgentHandle {
|
|
53
|
-
/** Null until the async self-bootstrap resolves (auto-fetch path). */
|
|
54
|
-
controller: AgentController | null;
|
|
55
|
-
orb: MountedOrb | null;
|
|
56
|
-
/** Resolves once the controller is ready (immediately on the manual path). */
|
|
57
|
-
ready: Promise<AgentController | null>;
|
|
58
|
-
destroy(): void;
|
|
59
|
-
}
|
|
60
|
-
export declare function createFyodosAgent(options: CreateFyodosAgentOptions): FyodosAgentHandle;
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vanilla drop-in — assembles the default browser adapters, builds an
|
|
3
|
-
* AgentController and (optionally) mounts the DOM orb in one call. Frameworks
|
|
4
|
-
* use the AgentController + their own components; this is the zero-framework
|
|
5
|
-
* path (and the reference the Vue/Svelte/Angular drop-ins follow).
|
|
6
|
-
*
|
|
7
|
-
* PARITY WITH @fyodos/react's <FyodosAgent/>: when `manifest` is omitted, the
|
|
8
|
-
* agent self-bootstraps — it fetches the published manifest by `apiKey`
|
|
9
|
-
* (GET /v1/client/manifest), assembles default browser adapters, mounts the orb
|
|
10
|
-
* and posts the `orb-seen` heartbeat. So a one-line drop-in needs only an
|
|
11
|
-
* apiKey, exactly like React. Passing a manifest keeps the fully-synchronous,
|
|
12
|
-
* manual path.
|
|
13
|
-
*/
|
|
14
|
-
import { validateManifest } from '@fyodos/core';
|
|
15
|
-
import { createFyodosBackendClient } from '../api/backendClient.js';
|
|
16
|
-
import { createFyodosTelemetry } from '../api/backendTelemetry.js';
|
|
17
|
-
import { createWebNavigationAdapter } from '../adapters/webNavigationAdapter.js';
|
|
18
|
-
import { createWebStorageAdapter } from '../adapters/webStorageAdapter.js';
|
|
19
|
-
import { createWebVoiceAdapter } from '../adapters/webVoiceAdapter.js';
|
|
20
|
-
import { AgentController } from '../controller/AgentController.js';
|
|
21
|
-
import { mountOrb } from '../orb/mountOrb.js';
|
|
22
|
-
import { DEFAULT_WEB_API_URL, fetchClientManifest, sendOrbSeen } from '../api/clientBootstrap.js';
|
|
23
|
-
function defaultNavigate(route) {
|
|
24
|
-
if (typeof window !== 'undefined' && window.location)
|
|
25
|
-
window.location.assign(route);
|
|
26
|
-
}
|
|
27
|
-
function browserLocale() {
|
|
28
|
-
const lang = typeof navigator !== 'undefined' && navigator.language ? navigator.language : 'en-US';
|
|
29
|
-
return { locale: lang.split('-')[0] || 'en', sttLocale: lang };
|
|
30
|
-
}
|
|
31
|
-
/** Build the controller + adapters from a known manifest (shared by both paths). */
|
|
32
|
-
function assemble(options, manifest, baseUrl) {
|
|
33
|
-
const fallback = browserLocale();
|
|
34
|
-
const locale = options.locale ?? fallback.locale;
|
|
35
|
-
const sttLocale = options.sttLocale ?? options.locale ?? fallback.sttLocale;
|
|
36
|
-
const backend = createFyodosBackendClient({
|
|
37
|
-
baseUrl,
|
|
38
|
-
apiKey: options.apiKey,
|
|
39
|
-
getUserId: options.getUserId,
|
|
40
|
-
});
|
|
41
|
-
const telemetry = createFyodosTelemetry({
|
|
42
|
-
baseUrl,
|
|
43
|
-
apiKey: options.apiKey,
|
|
44
|
-
getUserId: options.getUserId,
|
|
45
|
-
});
|
|
46
|
-
const config = {
|
|
47
|
-
manifest,
|
|
48
|
-
locale,
|
|
49
|
-
sttLocale,
|
|
50
|
-
navigation: createWebNavigationAdapter({ navigate: options.navigate ?? defaultNavigate }),
|
|
51
|
-
registries: options.registries ?? { handlers: {}, idempotencyCheckers: {} },
|
|
52
|
-
backend,
|
|
53
|
-
voice: createWebVoiceAdapter(),
|
|
54
|
-
storage: createWebStorageAdapter(),
|
|
55
|
-
telemetry,
|
|
56
|
-
isAuthenticated: options.isAuthenticated,
|
|
57
|
-
ttsVoice: options.ttsVoice,
|
|
58
|
-
...options.configOverrides,
|
|
59
|
-
};
|
|
60
|
-
const controller = new AgentController(config);
|
|
61
|
-
controller.warmUp();
|
|
62
|
-
return controller;
|
|
63
|
-
}
|
|
64
|
-
export function createFyodosAgent(options) {
|
|
65
|
-
const baseUrl = (options.baseUrl ?? DEFAULT_WEB_API_URL).replace(/\/$/, '');
|
|
66
|
-
const shouldMount = options.mount !== false;
|
|
67
|
-
// ── Manual path: manifest provided → fully synchronous (back-compat). ───────
|
|
68
|
-
if (options.manifest) {
|
|
69
|
-
const controller = assemble(options, options.manifest, baseUrl);
|
|
70
|
-
const orb = shouldMount ? mountOrb(controller, options.orb) : null;
|
|
71
|
-
if (shouldMount && options.apiKey) {
|
|
72
|
-
void sendOrbSeen({ baseUrl, apiKey: options.apiKey });
|
|
73
|
-
}
|
|
74
|
-
options.onReady?.(controller);
|
|
75
|
-
const handle = {
|
|
76
|
-
controller,
|
|
77
|
-
orb,
|
|
78
|
-
ready: Promise.resolve(controller),
|
|
79
|
-
destroy() {
|
|
80
|
-
orb?.unmount();
|
|
81
|
-
controller.dispose();
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
return handle;
|
|
85
|
-
}
|
|
86
|
-
// ── Auto path (React parity): fetch manifest by apiKey, then assemble. ──────
|
|
87
|
-
const handle = {
|
|
88
|
-
controller: null,
|
|
89
|
-
orb: null,
|
|
90
|
-
ready: Promise.resolve(null),
|
|
91
|
-
destroy() {
|
|
92
|
-
cancelled = true;
|
|
93
|
-
handle.orb?.unmount();
|
|
94
|
-
handle.controller?.dispose();
|
|
95
|
-
},
|
|
96
|
-
};
|
|
97
|
-
let cancelled = false;
|
|
98
|
-
handle.ready = (async () => {
|
|
99
|
-
try {
|
|
100
|
-
if (!options.apiKey) {
|
|
101
|
-
throw new Error('[fyodos] createFyodosAgent requires either a `manifest` or an `apiKey` ' +
|
|
102
|
-
'(to self-fetch the published manifest).');
|
|
103
|
-
}
|
|
104
|
-
const result = await fetchClientManifest({ baseUrl, apiKey: options.apiKey });
|
|
105
|
-
if (cancelled)
|
|
106
|
-
return null;
|
|
107
|
-
if (result.status === 'no-manifest' || !result.manifest) {
|
|
108
|
-
// eslint-disable-next-line no-console
|
|
109
|
-
console.warn('[fyodos] The orb is idle: this project has no published manifest yet. ' +
|
|
110
|
-
'Run the analysis from your Fyodos dashboard, then reload.');
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
// Fail loudly here (not deep inside the controller) so onError is precise.
|
|
114
|
-
const check = validateManifest(result.manifest);
|
|
115
|
-
if (!check.valid) {
|
|
116
|
-
throw new Error(`[fyodos] Invalid manifest for "${result.manifest.appId}":\n- ${check.errors.join('\n- ')}`);
|
|
117
|
-
}
|
|
118
|
-
const controller = assemble(options, result.manifest, baseUrl);
|
|
119
|
-
if (cancelled) {
|
|
120
|
-
controller.dispose();
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
handle.controller = controller;
|
|
124
|
-
handle.orb = shouldMount ? mountOrb(controller, options.orb) : null;
|
|
125
|
-
if (shouldMount && options.apiKey) {
|
|
126
|
-
void sendOrbSeen({ baseUrl, apiKey: options.apiKey });
|
|
127
|
-
}
|
|
128
|
-
options.onReady?.(controller);
|
|
129
|
-
return controller;
|
|
130
|
-
}
|
|
131
|
-
catch (e) {
|
|
132
|
-
const error = e instanceof Error ? e : new Error(String(e));
|
|
133
|
-
// eslint-disable-next-line no-console
|
|
134
|
-
console.error(error.message);
|
|
135
|
-
options.onError?.(error);
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
})();
|
|
139
|
-
return handle;
|
|
140
|
-
}
|