@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.
- package/LICENSE +21 -0
- package/README.md +120 -0
- package/dist/commands/login.js +75 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.js +41 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/whoami.js +26 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/core/api.js +158 -0
- package/dist/core/api.js.map +1 -0
- package/dist/core/constants.js +53 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/credentials.js +209 -0
- package/dist/core/credentials.js.map +1 -0
- package/dist/core/identity.js +162 -0
- package/dist/core/identity.js.map +1 -0
- package/dist/core/logger.js +9 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/prompt.js +29 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/regions.js +45 -0
- package/dist/core/regions.js.map +1 -0
- package/dist/core/secretStore.js +251 -0
- package/dist/core/secretStore.js.map +1 -0
- package/dist/core/wrap.js +17 -0
- package/dist/core/wrap.js.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/products/connections/client.js +125 -0
- package/dist/products/connections/client.js.map +1 -0
- package/dist/products/connections/commands.js +324 -0
- package/dist/products/connections/commands.js.map +1 -0
- package/dist/products/connections/index.js +63 -0
- package/dist/products/connections/index.js.map +1 -0
- package/dist/products/connections/state.js +44 -0
- package/dist/products/connections/state.js.map +1 -0
- package/dist/products/types.js +2 -0
- package/dist/products/types.js.map +1 -0
- package/dist/products/vibe/app.js +97 -0
- package/dist/products/vibe/app.js.map +1 -0
- package/dist/products/vibe/config.js +57 -0
- package/dist/products/vibe/config.js.map +1 -0
- package/dist/products/vibe/db.js +155 -0
- package/dist/products/vibe/db.js.map +1 -0
- package/dist/products/vibe/deploy.js +92 -0
- package/dist/products/vibe/deploy.js.map +1 -0
- package/dist/products/vibe/function.js +240 -0
- package/dist/products/vibe/function.js.map +1 -0
- package/dist/products/vibe/index.js +112 -0
- package/dist/products/vibe/index.js.map +1 -0
- 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"}
|
package/dist/core/api.js
ADDED
|
@@ -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"}
|