@facilio/cli 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -0
  3. package/dist/commands/login.js +75 -0
  4. package/dist/commands/login.js.map +1 -0
  5. package/dist/commands/logout.js +41 -0
  6. package/dist/commands/logout.js.map +1 -0
  7. package/dist/commands/whoami.js +26 -0
  8. package/dist/commands/whoami.js.map +1 -0
  9. package/dist/core/api.js +158 -0
  10. package/dist/core/api.js.map +1 -0
  11. package/dist/core/constants.js +53 -0
  12. package/dist/core/constants.js.map +1 -0
  13. package/dist/core/credentials.js +209 -0
  14. package/dist/core/credentials.js.map +1 -0
  15. package/dist/core/identity.js +162 -0
  16. package/dist/core/identity.js.map +1 -0
  17. package/dist/core/logger.js +9 -0
  18. package/dist/core/logger.js.map +1 -0
  19. package/dist/core/prompt.js +29 -0
  20. package/dist/core/prompt.js.map +1 -0
  21. package/dist/core/regions.js +45 -0
  22. package/dist/core/regions.js.map +1 -0
  23. package/dist/core/secretStore.js +251 -0
  24. package/dist/core/secretStore.js.map +1 -0
  25. package/dist/core/wrap.js +17 -0
  26. package/dist/core/wrap.js.map +1 -0
  27. package/dist/index.js +53 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/products/connections/client.js +125 -0
  30. package/dist/products/connections/client.js.map +1 -0
  31. package/dist/products/connections/commands.js +324 -0
  32. package/dist/products/connections/commands.js.map +1 -0
  33. package/dist/products/connections/index.js +63 -0
  34. package/dist/products/connections/index.js.map +1 -0
  35. package/dist/products/connections/state.js +44 -0
  36. package/dist/products/connections/state.js.map +1 -0
  37. package/dist/products/types.js +2 -0
  38. package/dist/products/types.js.map +1 -0
  39. package/dist/products/vibe/app.js +97 -0
  40. package/dist/products/vibe/app.js.map +1 -0
  41. package/dist/products/vibe/config.js +57 -0
  42. package/dist/products/vibe/config.js.map +1 -0
  43. package/dist/products/vibe/db.js +155 -0
  44. package/dist/products/vibe/db.js.map +1 -0
  45. package/dist/products/vibe/deploy.js +92 -0
  46. package/dist/products/vibe/deploy.js.map +1 -0
  47. package/dist/products/vibe/function.js +240 -0
  48. package/dist/products/vibe/function.js.map +1 -0
  49. package/dist/products/vibe/index.js +112 -0
  50. package/dist/products/vibe/index.js.map +1 -0
  51. package/package.json +57 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Facilio
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # @facilio/cli
2
+
3
+ The unified Facilio CLI — one login for every Facilio product.
4
+
5
+ ```bash
6
+ npm install -g @facilio/cli
7
+ facilio login
8
+ facilio vibe deploy
9
+ facilio connections search create xero invoice
10
+ ```
11
+
12
+ > Migrating from `@facilio/vibe-cli`? The `vibe` binary is gone; every command
13
+ > now lives under `facilio vibe …` (e.g. `vibe deploy` → `facilio vibe deploy`).
14
+ > Your existing login session is migrated automatically on first run.
15
+
16
+ ## Universal commands
17
+
18
+ | Command | What it does |
19
+ |---|---|
20
+ | `facilio login` | Sign in via the OAuth2 device-authorization flow (RFC 8628). Works on laptops, over SSH, and inside containers — no local callback port needed. One session covers every product namespace. |
21
+ | `facilio login --api-key <key>` | Non-interactive sign-in for CI. Pass `-` to read the key from stdin (keeps it out of shell history). Use `--region <key>` (US, UK, AE, AU, …; default US) so vibe + MCP URLs resolve correctly. API-key sessions cover `vibe` commands only. |
22
+ | `facilio logout` | Revoke the token server-side (best-effort) and clear it locally. |
23
+ | `facilio whoami` | Show the active session: user, server, auth source, token expiry. |
24
+ | `facilio help [command]` | Help for any command or namespace. |
25
+
26
+ ## `facilio vibe` — build and deploy Vibe apps
27
+
28
+ | Command | What it does |
29
+ |---|---|
30
+ | `facilio vibe deploy` | Zip `build.publish`, upload, wait for deployment to finish. `--prod` marks production. Build your app yourself first (e.g. `npm run build`). |
31
+ | `facilio vibe app create` / `app list` | Create a new app (prompts for name/description/logo) / list apps in your org. |
32
+ | `facilio vibe db create\|import\|tables\|describe` | Provision the app database, import CSVs as tables, inspect schema. |
33
+ | `facilio vibe function create\|update\|list\|get\|delete\|build\|run` | Manage an app's ai-studio functions (compiled to WASM). |
34
+
35
+ Project config stays in `vibe.json` at your project root — unchanged from the
36
+ old CLI (`build.publish` points at your build output folder).
37
+
38
+ ## `facilio connections` — 1000+ integrated apps
39
+
40
+ Backed by the Facilio Connections MCP server; the CLI sends your login token
41
+ directly, so there is no separate sign-in.
42
+
43
+ | Command | What it does |
44
+ |---|---|
45
+ | `facilio connections search <query…>` | Find actions by use case, e.g. `search create xero invoice`. |
46
+ | `facilio connections schemas <slug…>` | Show an action's input JSON Schema (`--with-output` adds the output schema). |
47
+ | `facilio connections list <connection…>` | Show your connected accounts for connections (e.g. `list xero`). |
48
+ | `facilio connections link <connection>` | Authorize a connection — opens the target app's OAuth page. `--wait` blocks until ACTIVE. |
49
+ | `facilio connections unlink <connection>` | Remove your authorization (prompts to confirm; `--yes` to skip). |
50
+ | `facilio connections wait <connection…>` | Poll until connection(s) become ACTIVE (`--mode all`, `--timeout <s>`). |
51
+ | `facilio connections execute <action_slug…> --params '<json>'` | Run one or more actions. `--get-schema` prints the input schema instead of running; `--dry-run` validates args against the schema and previews the request without executing; repeat `--params` once per slug to run several in parallel; `--params -` reads stdin; `--account <slug>` targets a connected account; `--file batch.json` runs a batch. |
52
+
53
+ Every connections command accepts `--json` (raw payloads for scripts/agents),
54
+ `--mcp-url <url>` (non-production servers), and `--app <slug>` (scope all
55
+ calls to one connection).
56
+
57
+ A typical first run:
58
+
59
+ ```bash
60
+ facilio connections search create xero invoice # discover action slugs
61
+ facilio connections link xero --wait # authorize Xero, wait for ACTIVE
62
+ facilio connections schemas xero.create_invoice # see required arguments
63
+ facilio connections execute xero.create_invoice --params '{"contact_id":"…","amount":100}'
64
+ ```
65
+
66
+ ## How login works
67
+
68
+ `facilio login` uses the OAuth2 device-authorization grant (RFC 8628) — the
69
+ same model GitHub CLI, `gcloud`, and AWS SSO use. Credentials land in the OS
70
+ secret store (macOS Keychain / Linux secret-service / Windows DPAPI), with a
71
+ 0600 file fallback at `~/.facilio/credentials.json`. Access tokens refresh
72
+ automatically; concurrent invocations coordinate through a lock file so the
73
+ rotated refresh token is never burned twice.
74
+
75
+ ## Regions
76
+
77
+ The token response carries your home region key (US, AE, AU, …). Product
78
+ endpoints resolve per-region from the table in `src/core/regions.ts` at call
79
+ time — no service key is sent at login and no product URL is baked into the
80
+ session. Precedence: env override (`FACILIO_VIBE_SERVER_URL` /
81
+ `FACILIO_CONNECTIONS_SERVER_URL`) → pinned `--server` (vibe only) → region
82
+ table → default. `facilio whoami` shows the resolved endpoints.
83
+
84
+ ## Environment variables
85
+
86
+ `FACILIO_*` is canonical; the legacy `VIBE_*` names still work as fallbacks.
87
+
88
+ | Variable | Purpose |
89
+ |---|---|
90
+ | `FACILIO_API_KEY` | Zero-config CI auth (wins over any saved session). |
91
+ | `FACILIO_REGION` | Region for `FACILIO_API_KEY` sessions (US, UK, AE, AU, …; default US). |
92
+ | `FACILIO_IDENTITY_SERVER_URL` | Identity-service base URL override (was `FACILIO_IDENTITY_URL`, still honoured). |
93
+ | `FACILIO_VIBE_SERVER_URL` | Vibe product-server URL override, beats the region table (was `FACILIO_SERVER_URL`, still honoured). |
94
+ | `FACILIO_CONNECTIONS_SERVER_URL` | Connections MCP endpoint override, beats the region table (was `FACILIO_MCP_URL`, still honoured). |
95
+ | `FACILIO_CLIENT_ID` | OAuth client id override. |
96
+ | `FACILIO_NO_KEYCHAIN=1` | Force file-based credential storage (CI). |
97
+
98
+ ### Local development
99
+
100
+ Point each backend at your local stack independently — set any subset:
101
+
102
+ ```bash
103
+ export FACILIO_IDENTITY_SERVER_URL=http://localhost:8090/identity
104
+ export FACILIO_VIBE_SERVER_URL=http://localhost:8080
105
+ export FACILIO_CONNECTIONS_SERVER_URL=http://localhost:9000/mcp
106
+ ```
107
+
108
+ ## Development
109
+
110
+ ```bash
111
+ npm install
112
+ npm run dev -- --help # run from source (tsx)
113
+ npm test # vitest
114
+ npm run build # tsc → dist/
115
+ ```
116
+
117
+ Product namespaces live under `src/products/<name>/` and register their
118
+ command tree through the `ProductModule` contract in `src/products/types.ts` —
119
+ adding a new Facilio product CLI is one folder plus one line in the registry
120
+ in `src/index.ts`.
@@ -0,0 +1,75 @@
1
+ import { logger } from '../core/logger.js';
2
+ import { saveCredentials } from '../core/credentials.js';
3
+ import { deviceLogin, resolveApiKey } from '../core/identity.js';
4
+ import { VibeApi, ApiError } from '../core/api.js';
5
+ import { DEFAULT_CLIENT_ID, DEFAULT_IDENTITY_URL } from '../core/constants.js';
6
+ import { REGIONS, vibeUrlFor, normalizeRegion, regionKeys } from '../core/regions.js';
7
+ /**
8
+ * Universal sign-in: one identity session covers every product namespace
9
+ * (vibe, connections, …). Device flow by default; `--api-key` for CI.
10
+ *
11
+ * The token response carries the user's home region key (US, AE, AU, …);
12
+ * product endpoints resolve from the region→URL table in core/regions.ts,
13
+ * so no service key is sent and no per-product URL is stored — except an
14
+ * explicit `--server`, which pins the vibe-server URL for the session.
15
+ */
16
+ export async function loginCommand(opts) {
17
+ // ─── --api-key path: skip browser, validate against /api/cli/apps, save. ───
18
+ if (opts.apiKey !== undefined) {
19
+ // No token response here, so there's no home region to read — resolve it
20
+ // from --region (default US), then the region table gives vibe + MCP URLs.
21
+ const { key: region, known } = normalizeRegion(opts.region);
22
+ if (!known) {
23
+ throw new Error(`Unknown region '${opts.region}'. Valid regions: ${regionKeys().join(', ')}.`);
24
+ }
25
+ // Pin serverUrl only when --server is explicit; otherwise store it empty so
26
+ // the region table stays the source of truth (same as device-flow sessions).
27
+ const pinned = opts.server ? opts.server.replace(/\/+$/, '') : '';
28
+ const serverUrl = pinned || vibeUrlFor(region);
29
+ const apiKey = await resolveApiKey(opts.apiKey);
30
+ const api = new VibeApi(serverUrl, undefined, apiKey);
31
+ try {
32
+ // Cheap, side-effect-free call that exercises CliBearerAuthFilter.
33
+ await api.getJson('/api/cli/apps');
34
+ }
35
+ catch (err) {
36
+ if (err instanceof ApiError && err.statusCode === 401) {
37
+ throw new Error('API key rejected by server. Check the key and try again.');
38
+ }
39
+ throw err;
40
+ }
41
+ const creds = { apiKey, serverUrl: pinned, region, source: 'api-key' };
42
+ const sink = await saveCredentials(creds);
43
+ logger.success(`Logged in with API key.`);
44
+ logger.step(`Region: ${region}${pinned ? '' : ` → ${serverUrl}`}`);
45
+ logger.step(`Credentials saved to ${sink}.`);
46
+ logger.step(`Tip: for CI, prefer \`export FACILIO_API_KEY=…\` (and \`FACILIO_REGION=…\`) over saving to disk.`);
47
+ logger.warn('Note: API-key sessions cover vibe commands only; `facilio connections` needs a browser sign-in.');
48
+ return;
49
+ }
50
+ // ─── Device-authorization (RFC 8628) path: works on laptop, SSH, container ───
51
+ if (opts.region) {
52
+ logger.warn('--region is only used with --api-key; browser sign-in takes the region from your account.');
53
+ }
54
+ const clientId = (opts.clientId ?? DEFAULT_CLIENT_ID).trim();
55
+ const identityUrl = (opts.identityUrl ?? DEFAULT_IDENTITY_URL).replace(/\/+$/, '');
56
+ if (!clientId) {
57
+ throw new Error('Missing OAuth client id. Pass --client-id or set FACILIO_CLIENT_ID.');
58
+ }
59
+ const creds = await deviceLogin({ clientId, identityUrl });
60
+ if (opts.server) {
61
+ creds.serverUrl = opts.server.replace(/\/+$/, '');
62
+ }
63
+ const sink = await saveCredentials(creds);
64
+ const who = creds.user?.email ?? creds.user?.name ?? '(signed in)';
65
+ logger.success(`Logged in as ${who}.`);
66
+ if (creds.region) {
67
+ const known = creds.region in REGIONS;
68
+ logger.step(`Region: ${creds.region}${known ? '' : ' (unknown region — falling back to default URLs; check core/regions.ts)'}`);
69
+ }
70
+ else {
71
+ logger.warn('No region key in the token response — product URLs fall back to defaults/env overrides.');
72
+ }
73
+ logger.step(`Token saved to ${sink}.`);
74
+ }
75
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { request } from 'undici';
2
+ import { logger } from '../core/logger.js';
3
+ import { clearCredentials, loadCredentials } from '../core/credentials.js';
4
+ export async function logoutCommand() {
5
+ const existing = await loadCredentials();
6
+ if (!existing) {
7
+ logger.info('No active session.');
8
+ return;
9
+ }
10
+ // Device-flow sessions: best-effort server-side revoke against the home-DC
11
+ // revoke endpoint. Local removal still runs on failure so a user can always
12
+ // log out, and api-key / env sessions skip this entirely (no token to revoke).
13
+ if (existing.revokeUrl && (existing.refreshToken || existing.accessToken)) {
14
+ try {
15
+ const body = new URLSearchParams({
16
+ token: existing.refreshToken ?? existing.accessToken,
17
+ }).toString();
18
+ const res = await request(existing.revokeUrl, {
19
+ method: 'POST',
20
+ headers: {
21
+ 'content-type': 'application/x-www-form-urlencoded',
22
+ accept: 'application/json',
23
+ },
24
+ body,
25
+ });
26
+ if (res.statusCode === 200) {
27
+ logger.step('Token revoked on the server.');
28
+ }
29
+ else {
30
+ logger.warn(`Server revoke returned ${res.statusCode}; clearing local credentials anyway.`);
31
+ }
32
+ }
33
+ catch (err) {
34
+ const msg = err instanceof Error ? err.message : String(err);
35
+ logger.warn(`Could not reach revoke endpoint (${msg}); clearing local credentials anyway.`);
36
+ }
37
+ }
38
+ await clearCredentials();
39
+ logger.success('Logged out.');
40
+ }
41
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE3E,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,QAAQ,GAAG,MAAM,eAAe,EAAE,CAAC;IACzC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAClC,OAAO;IACT,CAAC;IAED,2EAA2E;IAC3E,4EAA4E;IAC5E,+EAA+E;IAC/E,IAAI,QAAQ,CAAC,SAAS,IAAI,CAAC,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC1E,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;gBAC/B,KAAK,EAAE,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,WAAY;aACtD,CAAC,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE;gBAC5C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,mCAAmC;oBACnD,MAAM,EAAE,kBAAkB;iBAC3B;gBACD,IAAI;aACL,CAAC,CAAC;YACH,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;gBAC3B,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;YAC9C,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,0BAA0B,GAAG,CAAC,UAAU,sCAAsC,CAAC,CAAC;YAC9F,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,MAAM,CAAC,IAAI,CAAC,oCAAoC,GAAG,uCAAuC,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IAED,MAAM,gBAAgB,EAAE,CAAC;IACzB,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { logger } from '../core/logger.js';
2
+ import { loadCredentials } from '../core/credentials.js';
3
+ import { mcpUrlFor, vibeUrlFor } from '../core/regions.js';
4
+ export async function whoamiCommand() {
5
+ const creds = await loadCredentials();
6
+ if (!creds) {
7
+ logger.info('Not logged in. Run `facilio login` to sign in.');
8
+ process.exitCode = 1;
9
+ return;
10
+ }
11
+ const sourceLabel = creds.source === 'env' ? 'API key (FACILIO_API_KEY env)'
12
+ : creds.source === 'api-key' ? 'API key (saved)'
13
+ : creds.source === 'device' ? 'browser sign-in (OAuth device flow)'
14
+ : creds.apiKey ? 'API key'
15
+ : 'browser sign-in';
16
+ const who = creds.user?.email
17
+ ?? creds.user?.name
18
+ ?? (creds.apiKey ? '(API key — no email)' : '(no email in token)');
19
+ logger.success(`Logged in as ${who}`);
20
+ logger.step(`Auth: ${sourceLabel}`);
21
+ if (creds.region)
22
+ logger.step(`Region: ${creds.region}`);
23
+ logger.step(`Vibe: ${vibeUrlFor(creds.region, creds.serverUrl)}`);
24
+ logger.step(`MCP: ${mcpUrlFor(creds.region)}`);
25
+ }
26
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE3D,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAC;IACtC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GACf,KAAK,CAAC,MAAM,KAAK,KAAK,CAAM,CAAC,CAAC,+BAA+B;QAC/D,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAE,CAAC,CAAC,iBAAiB;YACjD,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAG,CAAC,CAAC,qCAAqC;gBACrE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAgB,CAAC,CAAC,SAAS;oBACzC,CAAC,CAAC,iBAAiB,CAAC;IAEpB,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,KAAK;WACxB,KAAK,CAAC,IAAI,EAAE,IAAI;WAChB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;IACrE,MAAM,CAAC,OAAO,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAC;IACtC,MAAM,CAAC,IAAI,CAAC,SAAS,WAAW,EAAE,CAAC,CAAC;IACpC,IAAI,KAAK,CAAC,MAAM;QAAE,MAAM,CAAC,IAAI,CAAC,WAAW,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACzD,MAAM,CAAC,IAAI,CAAC,SAAS,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAClE,MAAM,CAAC,IAAI,CAAC,QAAQ,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,158 @@
1
+ import { request } from 'undici';
2
+ import { refreshCredentials, SessionExpiredError, } from './credentials.js';
3
+ import { vibeUrlFor } from './regions.js';
4
+ export class ApiError extends Error {
5
+ statusCode;
6
+ body;
7
+ constructor(statusCode, message, body) {
8
+ // If the server returned a useful payload (error or message field), surface it.
9
+ const detail = extractDetail(body);
10
+ super(detail ? `${message} — ${detail}` : message);
11
+ this.statusCode = statusCode;
12
+ this.body = body;
13
+ }
14
+ }
15
+ function extractDetail(body) {
16
+ if (!body || typeof body !== 'object')
17
+ return undefined;
18
+ const b = body;
19
+ if (typeof b.error === 'string')
20
+ return b.error;
21
+ if (typeof b.message === 'string')
22
+ return b.message;
23
+ return undefined;
24
+ }
25
+ export class VibeApi {
26
+ serverUrl;
27
+ token;
28
+ apiKey;
29
+ refresh;
30
+ /**
31
+ * If both `apiKey` and `token` are supplied, `apiKey` wins — matches the
32
+ * vibe-server `CliBearerAuthFilter` precedence so the credential the CLI
33
+ * thinks is in use is the same one the server will validate.
34
+ *
35
+ * `refresh`, when provided, is called exactly once on the first 401 to
36
+ * obtain a new bearer token; the request is then retried with that token.
37
+ * API-key sessions don't pass a refresh callback, so they propagate 401s
38
+ * unchanged.
39
+ */
40
+ constructor(serverUrl, token, apiKey, refresh) {
41
+ this.serverUrl = serverUrl;
42
+ this.token = token;
43
+ this.apiKey = apiKey;
44
+ this.refresh = refresh;
45
+ }
46
+ url(path) {
47
+ const base = this.serverUrl.replace(/\/+$/, '');
48
+ return `${base}${path.startsWith('/') ? path : '/' + path}`;
49
+ }
50
+ headers(extra = {}) {
51
+ const h = { accept: 'application/json', ...extra };
52
+ if (this.apiKey) {
53
+ h['x-api-key'] = this.apiKey;
54
+ }
55
+ else if (this.token) {
56
+ h.authorization = `Bearer ${this.token}`;
57
+ }
58
+ return h;
59
+ }
60
+ /**
61
+ * Single send-with-retry path shared by getJson/postJson/uploadBinary.
62
+ * On 401 with a refresh callback in play, calls refresh() to rotate the
63
+ * access token, then retries once. If refresh raises SessionExpiredError
64
+ * the 401 surfaces with that message so the user is told to re-login.
65
+ */
66
+ async send(method, path, init = {}) {
67
+ const extra = {};
68
+ if (init.contentType)
69
+ extra['content-type'] = init.contentType;
70
+ if (init.body && Buffer.isBuffer(init.body)) {
71
+ extra['content-length'] = String(init.body.length);
72
+ }
73
+ const send = () => request(this.url(path), {
74
+ method,
75
+ headers: this.headers(extra),
76
+ body: init.body,
77
+ });
78
+ let res = await send();
79
+ if (res.statusCode === 401 && this.refresh && !this.apiKey) {
80
+ // Drain so undici can release the socket before we hit the same host
81
+ // again for the retry.
82
+ await res.body.dump();
83
+ try {
84
+ this.token = await this.refresh();
85
+ }
86
+ catch (err) {
87
+ if (err instanceof SessionExpiredError) {
88
+ throw new ApiError(401, `${method} ${path} failed (401)`, { error: err.message });
89
+ }
90
+ throw err;
91
+ }
92
+ res = await send();
93
+ }
94
+ const body = await res.body.json().catch(() => null);
95
+ if (res.statusCode >= 400) {
96
+ throw new ApiError(res.statusCode, `${method} ${path} failed (${res.statusCode})`, body);
97
+ }
98
+ return body;
99
+ }
100
+ async getJson(path) {
101
+ return (await this.send('GET', path));
102
+ }
103
+ async postJson(path, payload) {
104
+ return (await this.send('POST', path, {
105
+ body: JSON.stringify(payload),
106
+ contentType: 'application/json',
107
+ }));
108
+ }
109
+ async putJson(path, payload) {
110
+ return (await this.send('PUT', path, {
111
+ body: JSON.stringify(payload),
112
+ contentType: 'application/json',
113
+ }));
114
+ }
115
+ async deleteJson(path) {
116
+ return (await this.send('DELETE', path));
117
+ }
118
+ async uploadBinary(path, data, contentType) {
119
+ return (await this.send('POST', path, { body: data, contentType }));
120
+ }
121
+ }
122
+ /**
123
+ * Refresh proactively when the access token has expired or will within this
124
+ * window. 60s covers small clock skew and avoids burning a 401 round trip on
125
+ * a token that's about to die mid-call. The reactive 401 path inside `send()`
126
+ * is the safety net for tokens revoked server-side ahead of `expiresAt`.
127
+ */
128
+ const PROACTIVE_REFRESH_SKEW_MS = 60_000;
129
+ export async function apiFromCredentials(creds) {
130
+ // Only device-flow sessions can refresh. Mutate the caller's creds in place
131
+ // after a successful refresh so any post-call inspection (e.g. logging the
132
+ // user's email) sees the rotated tokens.
133
+ const canRefresh = !creds.apiKey && !!creds.refreshToken && !!creds.tokenUrl && !!creds.clientId;
134
+ const refresh = canRefresh
135
+ ? async () => {
136
+ const fresh = await refreshCredentials(creds);
137
+ Object.assign(creds, fresh);
138
+ return fresh.accessToken;
139
+ }
140
+ : undefined;
141
+ // Proactive refresh. SessionExpiredError (refresh token rejected) surfaces
142
+ // immediately — no point making a call we know will 401. Transient errors
143
+ // (network / 5xx) fall through silently with the stale token; the reactive
144
+ // path retries on 401 if the server really does reject it.
145
+ if (refresh && creds.expiresAt && creds.expiresAt - Date.now() < PROACTIVE_REFRESH_SKEW_MS) {
146
+ try {
147
+ await refresh();
148
+ }
149
+ catch (err) {
150
+ if (err instanceof SessionExpiredError)
151
+ throw err;
152
+ }
153
+ }
154
+ // Endpoint comes from the region→URL table unless the session pinned an
155
+ // explicit serverUrl (--server / api-key / pre-region legacy sessions).
156
+ return new VibeApi(vibeUrlFor(creds.region, creds.serverUrl), creds.accessToken, creds.apiKey, refresh);
157
+ }
158
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/core/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Environment resolution: `FACILIO_*` is the canonical prefix for the unified
3
+ * CLI; the legacy `VIBE_*` names are still honoured as silent fallbacks so
4
+ * existing CI configurations keep working across the rename.
5
+ */
6
+ export function env(name) {
7
+ const v = process.env[`FACILIO_${name}`] ?? process.env[`VIBE_${name}`];
8
+ const trimmed = (v ?? '').trim();
9
+ return trimmed || undefined;
10
+ }
11
+ /**
12
+ * Per-product base-URL overrides for local development. Each backend has one
13
+ * clearly-named env var — set any subset to point that service at localhost:
14
+ *
15
+ * FACILIO_IDENTITY_SERVER_URL e.g. http://localhost:8090/identity
16
+ * FACILIO_VIBE_SERVER_URL e.g. http://localhost:8080
17
+ * FACILIO_CONNECTIONS_SERVER_URL e.g. http://localhost:9000/mcp
18
+ *
19
+ * The older single-purpose names are still honoured as fallbacks so existing
20
+ * setups keep working: FACILIO_IDENTITY_URL, FACILIO_SERVER_URL, FACILIO_MCP_URL.
21
+ */
22
+ export function identityServerEnv() {
23
+ return env('IDENTITY_SERVER_URL') || env('IDENTITY_URL');
24
+ }
25
+ export function vibeServerEnv() {
26
+ return env('VIBE_SERVER_URL') || env('SERVER_URL');
27
+ }
28
+ export function connectionsServerEnv() {
29
+ return env('CONNECTIONS_SERVER_URL') || env('MCP_URL');
30
+ }
31
+ /**
32
+ * Last-resort vibe-server URL: used only when no region is known (e.g. an
33
+ * `--api-key` / CI login) and no `--server` / env override is set. Device-flow
34
+ * sessions resolve their URL from the region table, so this fallback is prod
35
+ * (US) to match the global identity/MCP defaults — never localhost in a
36
+ * released build. Override with `FACILIO_VIBE_SERVER_URL` for local development.
37
+ */
38
+ export const DEFAULT_SERVER_URL = vibeServerEnv() || 'https://us.vibes.facilio.studio';
39
+ export const DEFAULT_CLIENT_ID = env('CLIENT_ID') || '354ea7cd2fa84bcc96a51bc2d96c5111';
40
+ /**
41
+ * Identity-service base used to bootstrap the OAuth2 device flow. The CLI hits
42
+ * identity-service directly (not via a product server's proxy) so the
43
+ * post-login homing URLs returned in the token response are honoured verbatim.
44
+ * Override with `FACILIO_IDENTITY_SERVER_URL` for non-production deployments.
45
+ */
46
+ export const DEFAULT_IDENTITY_URL = (identityServerEnv() || 'https://id.facilio.com/identity').replace(/\/+$/, '');
47
+ /**
48
+ * Facilio Connections MCP endpoint (Streamable HTTP). The CLI authenticates
49
+ * with the raw identity access token as a direct bearer — no DCR/browser
50
+ * OAuth. Override with `FACILIO_CONNECTIONS_SERVER_URL` or `--mcp-url` per command.
51
+ */
52
+ export const DEFAULT_MCP_URL = (connectionsServerEnv() || 'https://mcp.facilio.com/mcp').replace(/\/+$/, '');
53
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,GAAG,CAAC,IAAY;IAC9B,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACjC,OAAO,OAAO,IAAI,SAAS,CAAC;AAC9B,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,GAAG,CAAC,qBAAqB,CAAC,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;AAC3D,CAAC;AACD,MAAM,UAAU,aAAa;IAC3B,OAAO,GAAG,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;AACrD,CAAC;AACD,MAAM,UAAU,oBAAoB;IAClC,OAAO,GAAG,CAAC,wBAAwB,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,aAAa,EAAE,IAAI,iCAAiC,CAAC;AAEvF,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,kCAAkC,CAAC;AAExF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,iBAAiB,EAAE,IAAI,iCAAiC,CACzD,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAEtB;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,oBAAoB,EAAE,IAAI,6BAA6B,CACxD,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC"}