@fiodos/web-core 0.1.0 → 0.1.2

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.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_WEB_API_URL = void 0;
4
4
  exports.fetchClientManifest = fetchClientManifest;
5
5
  exports.sendOrbSeen = sendOrbSeen;
6
+ const version_1 = require("../version");
6
7
  /**
7
8
  * Default public Fiodos backend, mirrored from @fiodos/react's DEFAULT_API_URL.
8
9
  * A drop-in that only receives an apiKey talks to this unless apiUrl is given.
@@ -59,7 +60,13 @@ async function sendOrbSeen(opts) {
59
60
  await fetch(`${baseUrl}/v1/client/orb-seen`, {
60
61
  method: 'POST',
61
62
  headers: { 'Content-Type': 'application/json', 'x-api-key': opts.apiKey },
62
- body: JSON.stringify({ platform: opts.platform ?? detectPlatform() }),
63
+ // sdkVersion/sdkPackage let the dashboard surface an "update available"
64
+ // notice when the running orb is older than the latest published SDK.
65
+ body: JSON.stringify({
66
+ platform: opts.platform ?? detectPlatform(),
67
+ sdkVersion: version_1.SDK_VERSION,
68
+ sdkPackage: version_1.SDK_PACKAGE,
69
+ }),
63
70
  });
64
71
  }
65
72
  catch {
@@ -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('[fyodos] The orb is idle: this project has no published manifest yet. ' +
113
- 'Run the analysis from your Fiodos dashboard, then reload.');
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
  }
@@ -7,6 +7,7 @@
7
7
  * reactive wrappers around THIS package, so they share identical agent
8
8
  * behaviour and security. No framework imports live here.
9
9
  */
10
+ export { SDK_VERSION, SDK_PACKAGE } from './version';
10
11
  export { AgentController } from './controller/AgentController';
11
12
  export type { AgentState, AgentExchange } from './controller/AgentController';
12
13
  export { createFiodosAgent } from './dropin/createFiodosAgent';
package/dist/cjs/index.js CHANGED
@@ -9,7 +9,11 @@
9
9
  * behaviour and security. No framework imports live here.
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.classifyPendingReply = exports.decideAction = exports.resolveUiMessages = exports.DEFAULT_AGENT_TIMINGS = exports.createSpeechSession = exports.createScreenContextStore = exports.createBridge = exports.isAgentApiError = exports.AgentApiError = exports.createFiodosTelemetry = exports.buildManifestPayload = exports.createFiodosBackendClient = exports.createWebVoiceAdapter = exports.BACK_ROUTE = exports.createWebNavigationAdapter = exports.createWebStorageAdapter = exports.watchPublishedConfig = exports.DEFAULT_ORB_APPEARANCE = exports.buildKeyboardChip = exports.createOrbVisual = exports.mountOrb = exports.sendOrbSeen = exports.fetchClientManifest = exports.DEFAULT_WEB_API_URL = exports.createFiodosAgent = exports.AgentController = void 0;
12
+ exports.classifyPendingReply = exports.decideAction = exports.resolveUiMessages = exports.DEFAULT_AGENT_TIMINGS = exports.createSpeechSession = exports.createScreenContextStore = exports.createBridge = exports.isAgentApiError = exports.AgentApiError = exports.createFiodosTelemetry = exports.buildManifestPayload = exports.createFiodosBackendClient = exports.createWebVoiceAdapter = exports.BACK_ROUTE = exports.createWebNavigationAdapter = exports.createWebStorageAdapter = exports.watchPublishedConfig = exports.DEFAULT_ORB_APPEARANCE = exports.buildKeyboardChip = exports.createOrbVisual = exports.mountOrb = exports.sendOrbSeen = exports.fetchClientManifest = exports.DEFAULT_WEB_API_URL = exports.createFiodosAgent = exports.AgentController = exports.SDK_PACKAGE = exports.SDK_VERSION = void 0;
13
+ // ── Version (reported by the orb heartbeat) ───────────────────────────────────
14
+ var version_1 = require("./version");
15
+ Object.defineProperty(exports, "SDK_VERSION", { enumerable: true, get: function () { return version_1.SDK_VERSION; } });
16
+ Object.defineProperty(exports, "SDK_PACKAGE", { enumerable: true, get: function () { return version_1.SDK_PACKAGE; } });
13
17
  // ── Orchestrator ──────────────────────────────────────────────────────────────
14
18
  var AgentController_1 = require("./controller/AgentController");
15
19
  Object.defineProperty(exports, "AgentController", { enumerable: true, get: function () { return AgentController_1.AgentController; } });
@@ -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
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * SDK version reported by the orb heartbeat (POST /v1/client/orb-seen) so the
3
+ * dashboard can tell the developer when a newer SDK is available.
4
+ *
5
+ * Auto-generated by scripts/sync-sdk-version.mjs from package.json. Do not edit
6
+ * by hand — change package.json `version` and re-run the sync/release script.
7
+ */
8
+ export declare const SDK_VERSION = "0.1.2";
9
+ export declare const SDK_PACKAGE = "@fiodos/web-core";
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SDK_PACKAGE = exports.SDK_VERSION = void 0;
4
+ /**
5
+ * SDK version reported by the orb heartbeat (POST /v1/client/orb-seen) so the
6
+ * dashboard can tell the developer when a newer SDK is available.
7
+ *
8
+ * Auto-generated by scripts/sync-sdk-version.mjs from package.json. Do not edit
9
+ * by hand — change package.json `version` and re-run the sync/release script.
10
+ */
11
+ exports.SDK_VERSION = '0.1.2';
12
+ exports.SDK_PACKAGE = '@fiodos/web-core';
@@ -1,3 +1,4 @@
1
+ import { SDK_VERSION, SDK_PACKAGE } from '../version.js';
1
2
  /**
2
3
  * Default public Fiodos backend, mirrored from @fiodos/react's DEFAULT_API_URL.
3
4
  * A drop-in that only receives an apiKey talks to this unless apiUrl is given.
@@ -54,7 +55,13 @@ export async function sendOrbSeen(opts) {
54
55
  await fetch(`${baseUrl}/v1/client/orb-seen`, {
55
56
  method: 'POST',
56
57
  headers: { 'Content-Type': 'application/json', 'x-api-key': opts.apiKey },
57
- body: JSON.stringify({ platform: opts.platform ?? detectPlatform() }),
58
+ // sdkVersion/sdkPackage let the dashboard surface an "update available"
59
+ // notice when the running orb is older than the latest published SDK.
60
+ body: JSON.stringify({
61
+ platform: opts.platform ?? detectPlatform(),
62
+ sdkVersion: SDK_VERSION,
63
+ sdkPackage: SDK_PACKAGE,
64
+ }),
58
65
  });
59
66
  }
60
67
  catch {
@@ -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('[fyodos] The orb is idle: this project has no published manifest yet. ' +
110
- 'Run the analysis from your Fiodos dashboard, then reload.');
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
  }
@@ -7,6 +7,7 @@
7
7
  * reactive wrappers around THIS package, so they share identical agent
8
8
  * behaviour and security. No framework imports live here.
9
9
  */
10
+ export { SDK_VERSION, SDK_PACKAGE } from './version.js';
10
11
  export { AgentController } from './controller/AgentController.js';
11
12
  export type { AgentState, AgentExchange } from './controller/AgentController.js';
12
13
  export { createFiodosAgent } from './dropin/createFiodosAgent.js';
package/dist/esm/index.js CHANGED
@@ -7,6 +7,8 @@
7
7
  * reactive wrappers around THIS package, so they share identical agent
8
8
  * behaviour and security. No framework imports live here.
9
9
  */
10
+ // ── Version (reported by the orb heartbeat) ───────────────────────────────────
11
+ export { SDK_VERSION, SDK_PACKAGE } from './version.js';
10
12
  // ── Orchestrator ──────────────────────────────────────────────────────────────
11
13
  export { AgentController } from './controller/AgentController.js';
12
14
  // ── Drop-in (zero-wiring) ─────────────────────────────────────────────────────
@@ -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
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * SDK version reported by the orb heartbeat (POST /v1/client/orb-seen) so the
3
+ * dashboard can tell the developer when a newer SDK is available.
4
+ *
5
+ * Auto-generated by scripts/sync-sdk-version.mjs from package.json. Do not edit
6
+ * by hand — change package.json `version` and re-run the sync/release script.
7
+ */
8
+ export declare const SDK_VERSION = "0.1.2";
9
+ export declare const SDK_PACKAGE = "@fiodos/web-core";
@@ -0,0 +1,9 @@
1
+ /**
2
+ * SDK version reported by the orb heartbeat (POST /v1/client/orb-seen) so the
3
+ * dashboard can tell the developer when a newer SDK is available.
4
+ *
5
+ * Auto-generated by scripts/sync-sdk-version.mjs from package.json. Do not edit
6
+ * by hand — change package.json `version` and re-run the sync/release script.
7
+ */
8
+ export const SDK_VERSION = '0.1.2';
9
+ export const SDK_PACKAGE = '@fiodos/web-core';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiodos/web-core",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
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": {
@@ -28,7 +28,7 @@
28
28
  "test": "node --import tsx --test test/*.test.ts"
29
29
  },
30
30
  "dependencies": {
31
- "@fiodos/core": "0.1.0"
31
+ "@fiodos/core": "^0.1.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^22.0.0",
@@ -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
- }