@parix/cli 0.1.8 → 0.1.9

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 (73) hide show
  1. package/dist/cli.cjs +4296 -35
  2. package/package.json +2 -2
  3. package/dist/cli.d.cts +0 -2
  4. package/dist/cli.d.ts +0 -2
  5. package/dist/cli.js +0 -36
  6. package/dist/commands/api.cjs +0 -81
  7. package/dist/commands/api.d.cts +0 -2
  8. package/dist/commands/api.d.ts +0 -2
  9. package/dist/commands/api.js +0 -78
  10. package/dist/commands/auth.cjs +0 -131
  11. package/dist/commands/auth.d.cts +0 -2
  12. package/dist/commands/auth.d.ts +0 -2
  13. package/dist/commands/auth.js +0 -128
  14. package/dist/commands/database.cjs +0 -259
  15. package/dist/commands/database.d.cts +0 -2
  16. package/dist/commands/database.d.ts +0 -2
  17. package/dist/commands/database.js +0 -256
  18. package/dist/commands/skill-content.cjs +0 -77
  19. package/dist/commands/skill-content.d.cts +0 -1
  20. package/dist/commands/skill-content.d.ts +0 -1
  21. package/dist/commands/skill-content.js +0 -74
  22. package/dist/commands/skill.cjs +0 -10
  23. package/dist/commands/skill.d.cts +0 -2
  24. package/dist/commands/skill.d.ts +0 -2
  25. package/dist/commands/skill.js +0 -7
  26. package/dist/commands/tb.cjs +0 -254
  27. package/dist/commands/tb.d.cts +0 -2
  28. package/dist/commands/tb.d.ts +0 -2
  29. package/dist/commands/tb.js +0 -251
  30. package/dist/lib/api-client.cjs +0 -44
  31. package/dist/lib/api-client.d.cts +0 -10
  32. package/dist/lib/api-client.d.ts +0 -10
  33. package/dist/lib/api-client.js +0 -40
  34. package/dist/lib/config.cjs +0 -24
  35. package/dist/lib/config.d.cts +0 -10
  36. package/dist/lib/config.d.ts +0 -10
  37. package/dist/lib/config.js +0 -18
  38. package/dist/lib/loopback-server.cjs +0 -180
  39. package/dist/lib/loopback-server.d.cts +0 -20
  40. package/dist/lib/loopback-server.d.ts +0 -20
  41. package/dist/lib/loopback-server.js +0 -177
  42. package/dist/lib/oauth-api.cjs +0 -73
  43. package/dist/lib/oauth-api.d.cts +0 -31
  44. package/dist/lib/oauth-api.d.ts +0 -31
  45. package/dist/lib/oauth-api.js +0 -68
  46. package/dist/lib/oauth-session.cjs +0 -108
  47. package/dist/lib/oauth-session.d.cts +0 -32
  48. package/dist/lib/oauth-session.d.ts +0 -32
  49. package/dist/lib/oauth-session.js +0 -103
  50. package/dist/lib/oauth.cjs +0 -58
  51. package/dist/lib/oauth.d.cts +0 -19
  52. package/dist/lib/oauth.d.ts +0 -19
  53. package/dist/lib/oauth.js +0 -49
  54. package/dist/lib/open-url.cjs +0 -38
  55. package/dist/lib/open-url.d.cts +0 -1
  56. package/dist/lib/open-url.d.ts +0 -1
  57. package/dist/lib/open-url.js +0 -32
  58. package/dist/lib/output.cjs +0 -20
  59. package/dist/lib/output.d.cts +0 -6
  60. package/dist/lib/output.d.ts +0 -6
  61. package/dist/lib/output.js +0 -15
  62. package/dist/lib/parix-api.cjs +0 -59
  63. package/dist/lib/parix-api.d.cts +0 -12
  64. package/dist/lib/parix-api.d.ts +0 -12
  65. package/dist/lib/parix-api.js +0 -55
  66. package/dist/lib/session.cjs +0 -80
  67. package/dist/lib/session.d.cts +0 -28
  68. package/dist/lib/session.d.ts +0 -28
  69. package/dist/lib/session.js +0 -74
  70. package/dist/lib/tb-payloads.cjs +0 -258
  71. package/dist/lib/tb-payloads.d.cts +0 -66
  72. package/dist/lib/tb-payloads.d.ts +0 -66
  73. package/dist/lib/tb-payloads.js +0 -249
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@parix/cli",
3
3
  "description": "Parix command line interface",
4
4
  "type": "module",
5
- "version": "0.1.8",
5
+ "version": "0.1.9",
6
6
  "bin": {
7
7
  "parix": "dist/cli.cjs"
8
8
  },
@@ -29,7 +29,7 @@
29
29
  "node": ">=20"
30
30
  },
31
31
  "scripts": {
32
- "build": "zshy && node scripts/normalize-package-bin.mjs && chmod +x dist/cli.cjs",
32
+ "build": "bun build ./src/cli.ts --outfile=dist/cli.cjs --target=node --format=cjs && node scripts/normalize-package-bin.mjs && node scripts/ensure-cli-shebang.mjs && chmod +x dist/cli.cjs",
33
33
  "build:link": "bun run build && bun link",
34
34
  "fmt": "oxfmt --write src test scripts package.json tsconfig.json .oxlintrc.json .oxfmtrc.json commitlint.config.js",
35
35
  "fmt:check": "oxfmt --check src test scripts package.json tsconfig.json .oxlintrc.json .oxfmtrc.json commitlint.config.js",
package/dist/cli.d.cts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/dist/cli.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/dist/cli.js DELETED
@@ -1,36 +0,0 @@
1
- #!/usr/bin/env node
2
- import { log } from '@clack/prompts';
3
- import { Command } from 'commander';
4
- import { createRequire } from 'node:module';
5
- import { createApiCommand } from "./commands/api.js";
6
- import { createAuthCommand } from "./commands/auth.js";
7
- import { createDatabaseCommand } from "./commands/database.js";
8
- import { createSkillCommand } from "./commands/skill.js";
9
- import { createTbCommand } from "./commands/tb.js";
10
- const loadPackageJson = createRequire(import.meta.url);
11
- const packageJson = loadPackageJson('../package.json');
12
- async function main() {
13
- const program = new Command();
14
- program
15
- .name('parix')
16
- .version(packageJson.version, '-v, --version')
17
- .description('Parix command line interface')
18
- .showHelpAfterError()
19
- .addCommand(createAuthCommand())
20
- .addCommand(createApiCommand())
21
- .addCommand(createDatabaseCommand())
22
- .addCommand(createSkillCommand())
23
- .addCommand(createTbCommand());
24
- await program.parseAsync(process.argv);
25
- }
26
- main()
27
- .then(() => {
28
- // CLIs that open HTTP servers / use undici fetch can leave sockets that keep
29
- // Node alive after the command is done. Exit explicitly once work is finished.
30
- process.exit(process.exitCode ?? 0);
31
- })
32
- .catch((error) => {
33
- const message = error instanceof Error ? error.message : String(error);
34
- log.error(message);
35
- process.exit(1);
36
- });
@@ -1,81 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createApiCommand = createApiCommand;
4
- const prompts_1 = require("@clack/prompts");
5
- const commander_1 = require("commander");
6
- const api_client_1 = require("../lib/api-client.cjs");
7
- const config_1 = require("../lib/config.cjs");
8
- const session_1 = require("../lib/session.cjs");
9
- function createApiCommand() {
10
- return new commander_1.Command('api')
11
- .description('Make an authenticated API request with the stored bearer token')
12
- .argument('<path>', 'Relative API path or absolute URL')
13
- .option('-X, --method <method>', 'HTTP method', 'GET')
14
- .option('-d, --body <body>', 'Raw request body')
15
- .option('-H, --header <header>', 'Additional header in key:value form', collectValues, [])
16
- .option('-b, --base-url <url>', 'Override the stored base URL')
17
- .action(async (requestPath, options) => {
18
- await handleApiRequest(requestPath, options);
19
- });
20
- }
21
- async function handleApiRequest(requestPath, options) {
22
- const storedSession = await (0, session_1.readStoredSession)();
23
- if (!storedSession) {
24
- throw new Error('No local session found. Run `parix auth login` first.');
25
- }
26
- const baseUrl = (0, config_1.resolveBaseUrl)(options.baseUrl, storedSession);
27
- const headers = parseHeaders(options.header ?? []);
28
- const body = options.body ?? undefined;
29
- if (body && !hasHeader(headers, 'content-type')) {
30
- headers.set('content-type', 'application/json');
31
- }
32
- const client = new api_client_1.ApiClient({
33
- session: {
34
- ...storedSession,
35
- baseUrl,
36
- },
37
- });
38
- const response = await client.request(requestPath, {
39
- method: options.method ?? 'GET',
40
- headers,
41
- body,
42
- });
43
- const contentType = response.headers.get('content-type') ?? 'unknown';
44
- const payload = await response.text();
45
- (0, prompts_1.note)([`Status: ${response.status} ${response.statusText}`, `Content-Type: ${contentType}`].join('\n'), 'Response');
46
- if (contentType.includes('application/json') && payload.length > 0) {
47
- try {
48
- prompts_1.log.message(JSON.stringify(JSON.parse(payload), null, 2));
49
- (0, prompts_1.outro)('Request completed');
50
- return;
51
- }
52
- catch { }
53
- }
54
- if (payload.length > 0) {
55
- prompts_1.log.message(payload);
56
- }
57
- (0, prompts_1.outro)('Request completed');
58
- }
59
- function collectValues(value, previous) {
60
- previous.push(value);
61
- return previous;
62
- }
63
- function parseHeaders(values) {
64
- const headers = new Headers();
65
- for (const value of values) {
66
- const separatorIndex = value.indexOf(':');
67
- if (separatorIndex <= 0) {
68
- throw new Error(`Invalid header format: ${value}. Use key:value.`);
69
- }
70
- const key = value.slice(0, separatorIndex).trim();
71
- const headerValue = value.slice(separatorIndex + 1).trim();
72
- if (!key) {
73
- throw new Error(`Invalid header name: ${value}`);
74
- }
75
- headers.set(key, headerValue);
76
- }
77
- return headers;
78
- }
79
- function hasHeader(headers, name) {
80
- return headers.has(name) || headers.has(name.toLowerCase());
81
- }
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function createApiCommand(): Command;
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function createApiCommand(): Command;
@@ -1,78 +0,0 @@
1
- import { log, note, outro } from '@clack/prompts';
2
- import { Command } from 'commander';
3
- import { ApiClient } from "../lib/api-client.js";
4
- import { resolveBaseUrl } from "../lib/config.js";
5
- import { readStoredSession } from "../lib/session.js";
6
- export function createApiCommand() {
7
- return new Command('api')
8
- .description('Make an authenticated API request with the stored bearer token')
9
- .argument('<path>', 'Relative API path or absolute URL')
10
- .option('-X, --method <method>', 'HTTP method', 'GET')
11
- .option('-d, --body <body>', 'Raw request body')
12
- .option('-H, --header <header>', 'Additional header in key:value form', collectValues, [])
13
- .option('-b, --base-url <url>', 'Override the stored base URL')
14
- .action(async (requestPath, options) => {
15
- await handleApiRequest(requestPath, options);
16
- });
17
- }
18
- async function handleApiRequest(requestPath, options) {
19
- const storedSession = await readStoredSession();
20
- if (!storedSession) {
21
- throw new Error('No local session found. Run `parix auth login` first.');
22
- }
23
- const baseUrl = resolveBaseUrl(options.baseUrl, storedSession);
24
- const headers = parseHeaders(options.header ?? []);
25
- const body = options.body ?? undefined;
26
- if (body && !hasHeader(headers, 'content-type')) {
27
- headers.set('content-type', 'application/json');
28
- }
29
- const client = new ApiClient({
30
- session: {
31
- ...storedSession,
32
- baseUrl,
33
- },
34
- });
35
- const response = await client.request(requestPath, {
36
- method: options.method ?? 'GET',
37
- headers,
38
- body,
39
- });
40
- const contentType = response.headers.get('content-type') ?? 'unknown';
41
- const payload = await response.text();
42
- note([`Status: ${response.status} ${response.statusText}`, `Content-Type: ${contentType}`].join('\n'), 'Response');
43
- if (contentType.includes('application/json') && payload.length > 0) {
44
- try {
45
- log.message(JSON.stringify(JSON.parse(payload), null, 2));
46
- outro('Request completed');
47
- return;
48
- }
49
- catch { }
50
- }
51
- if (payload.length > 0) {
52
- log.message(payload);
53
- }
54
- outro('Request completed');
55
- }
56
- function collectValues(value, previous) {
57
- previous.push(value);
58
- return previous;
59
- }
60
- function parseHeaders(values) {
61
- const headers = new Headers();
62
- for (const value of values) {
63
- const separatorIndex = value.indexOf(':');
64
- if (separatorIndex <= 0) {
65
- throw new Error(`Invalid header format: ${value}. Use key:value.`);
66
- }
67
- const key = value.slice(0, separatorIndex).trim();
68
- const headerValue = value.slice(separatorIndex + 1).trim();
69
- if (!key) {
70
- throw new Error(`Invalid header name: ${value}`);
71
- }
72
- headers.set(key, headerValue);
73
- }
74
- return headers;
75
- }
76
- function hasHeader(headers, name) {
77
- return headers.has(name) || headers.has(name.toLowerCase());
78
- }
@@ -1,131 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createAuthCommand = createAuthCommand;
4
- const prompts_1 = require("@clack/prompts");
5
- const commander_1 = require("commander");
6
- const config_1 = require("../lib/config.cjs");
7
- const loopback_server_1 = require("../lib/loopback-server.cjs");
8
- const oauth_1 = require("../lib/oauth.cjs");
9
- const oauth_api_1 = require("../lib/oauth-api.cjs");
10
- const oauth_session_1 = require("../lib/oauth-session.cjs");
11
- const open_url_1 = require("../lib/open-url.cjs");
12
- const session_1 = require("../lib/session.cjs");
13
- const DEFAULT_OIDC_PROMPT = 'consent';
14
- function createAuthCommand() {
15
- const auth = new commander_1.Command('auth').description('Authenticate with Parix');
16
- auth
17
- .command('login')
18
- .description('Sign in with OAuth consent and PKCE')
19
- .option('-b, --base-url <url>', 'Parix base URL')
20
- .option('-p, --port <port>', 'Loopback callback port', config_1.parsePortOption)
21
- .option('--prompt <prompt>', 'OAuth prompt override', DEFAULT_OIDC_PROMPT)
22
- .action(async (options) => {
23
- await handleLogin(options);
24
- });
25
- auth
26
- .command('status')
27
- .description('Show the current authenticated session')
28
- .option('-b, --base-url <url>', 'Override the stored base URL')
29
- .action(async (options) => {
30
- await handleStatus(options);
31
- });
32
- auth
33
- .command('logout')
34
- .description('Remove the local session file')
35
- .action(async () => {
36
- await (0, session_1.clearStoredSession)();
37
- (0, prompts_1.outro)(`Removed local session at ${session_1.SESSION_FILE_PATH}`);
38
- });
39
- return auth;
40
- }
41
- async function handleLogin(options) {
42
- (0, prompts_1.intro)('Parix sign in');
43
- const storedSession = await (0, session_1.readStoredSession)();
44
- const baseUrl = (0, config_1.resolveBaseUrl)(options.baseUrl, storedSession, { useStoredSession: false });
45
- const loopbackServer = await (0, loopback_server_1.startLoopbackServer)({
46
- callbackPath: oauth_1.PARIX_LOCAL_CALLBACK_PATH,
47
- port: options.port,
48
- successPage: {
49
- redirectUrl: new URL(oauth_1.CLI_OAUTH_CONSENT_GRANTED_PATH, baseUrl).toString(),
50
- },
51
- timeoutMs: config_1.LOGIN_TIMEOUT_MS,
52
- });
53
- try {
54
- const pkcePair = (0, oauth_1.createPkcePair)();
55
- const state = (0, oauth_1.buildCliState)(loopbackServer.callbackUrl);
56
- loopbackServer.setState(state);
57
- const browserUrl = (0, oauth_1.buildAuthorizeUrl)({
58
- baseUrl,
59
- codeChallenge: pkcePair.codeChallenge,
60
- prompt: options.prompt,
61
- state,
62
- });
63
- const prepareSpinner = (0, prompts_1.spinner)();
64
- prepareSpinner.start('Preparing browser sign-in');
65
- prepareSpinner.stop('Browser sign-in ready');
66
- const opened = await (0, open_url_1.openUrlInBrowser)(browserUrl);
67
- (0, prompts_1.note)(opened ? browserUrl : `Open this URL manually:\n${browserUrl}`, opened ? 'Opened browser URL' : 'Manual browser URL');
68
- const waitSpinner = (0, prompts_1.spinner)();
69
- waitSpinner.start('Waiting for browser callback');
70
- const callbackResult = await loopbackServer.waitForResult();
71
- waitSpinner.stop('Received browser callback');
72
- // Shut down the loopback server before token exchange so browser keep-alive
73
- // sockets cannot keep the process open after sign-in completes.
74
- await loopbackServer.close().catch(() => { });
75
- const tokenSet = await (0, oauth_api_1.exchangeAuthorizationCode)({
76
- baseUrl,
77
- code: callbackResult.code,
78
- codeVerifier: pkcePair.codeVerifier,
79
- });
80
- const nextSession = await (0, oauth_session_1.createStoredSession)({
81
- baseUrl,
82
- createdAt: storedSession?.createdAt,
83
- tokenSet,
84
- });
85
- await (0, session_1.writeStoredSession)(nextSession);
86
- (0, prompts_1.note)(session_1.SESSION_FILE_PATH, 'Stored session file');
87
- (0, prompts_1.outro)(`Signed in as ${formatUserLabel(nextSession.user)}`);
88
- }
89
- finally {
90
- await loopbackServer.close().catch(() => { });
91
- }
92
- }
93
- async function handleStatus(options) {
94
- (0, prompts_1.intro)('Parix auth status');
95
- const storedSession = await (0, session_1.readStoredSession)();
96
- if (!storedSession) {
97
- prompts_1.log.warn(`No local session found at ${session_1.SESSION_FILE_PATH}`);
98
- process.exitCode = 1;
99
- return;
100
- }
101
- const baseUrl = (0, config_1.resolveBaseUrl)(options.baseUrl, storedSession);
102
- try {
103
- const refreshedSession = await (0, oauth_session_1.hydrateStoredSessionOrganization)(await (0, oauth_session_1.ensureFreshSession)({
104
- ...storedSession,
105
- baseUrl,
106
- }));
107
- const userInfo = await (0, oauth_api_1.fetchOAuthUserInfo)({
108
- accessToken: refreshedSession.accessToken,
109
- baseUrl,
110
- });
111
- (0, prompts_1.note)([
112
- `User: ${userInfo.email ?? formatUserLabel(refreshedSession.user)}`,
113
- `Base URL: ${baseUrl}`,
114
- `Expires: ${refreshedSession.accessTokenExpiresAt}`,
115
- `Scopes: ${refreshedSession.scopes.join(', ')}`,
116
- `Organization: ${refreshedSession.organization.name ?? 'none'}`,
117
- `Organization slug: ${refreshedSession.organization.slug ?? 'none'}`,
118
- `Member role: ${refreshedSession.organization.memberRole ?? 'none'}`,
119
- `Session file: ${session_1.SESSION_FILE_PATH}`,
120
- ].join('\n'), 'Authenticated session');
121
- (0, prompts_1.outro)('Session is valid');
122
- }
123
- catch (error) {
124
- const message = error instanceof Error ? error.message : String(error);
125
- prompts_1.log.warn(`Stored session is invalid: ${message}`);
126
- process.exitCode = 1;
127
- }
128
- }
129
- function formatUserLabel(user) {
130
- return user.email ?? user.name ?? user.id;
131
- }
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function createAuthCommand(): Command;
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function createAuthCommand(): Command;
@@ -1,128 +0,0 @@
1
- import { intro, log, note, outro, spinner } from '@clack/prompts';
2
- import { Command } from 'commander';
3
- import { LOGIN_TIMEOUT_MS, parsePortOption, resolveBaseUrl } from "../lib/config.js";
4
- import { startLoopbackServer } from "../lib/loopback-server.js";
5
- import { buildAuthorizeUrl, buildCliState, CLI_OAUTH_CONSENT_GRANTED_PATH, createPkcePair, PARIX_LOCAL_CALLBACK_PATH, } from "../lib/oauth.js";
6
- import { exchangeAuthorizationCode, fetchOAuthUserInfo } from "../lib/oauth-api.js";
7
- import { createStoredSession, ensureFreshSession, hydrateStoredSessionOrganization } from "../lib/oauth-session.js";
8
- import { openUrlInBrowser } from "../lib/open-url.js";
9
- import { clearStoredSession, readStoredSession, SESSION_FILE_PATH, writeStoredSession } from "../lib/session.js";
10
- const DEFAULT_OIDC_PROMPT = 'consent';
11
- export function createAuthCommand() {
12
- const auth = new Command('auth').description('Authenticate with Parix');
13
- auth
14
- .command('login')
15
- .description('Sign in with OAuth consent and PKCE')
16
- .option('-b, --base-url <url>', 'Parix base URL')
17
- .option('-p, --port <port>', 'Loopback callback port', parsePortOption)
18
- .option('--prompt <prompt>', 'OAuth prompt override', DEFAULT_OIDC_PROMPT)
19
- .action(async (options) => {
20
- await handleLogin(options);
21
- });
22
- auth
23
- .command('status')
24
- .description('Show the current authenticated session')
25
- .option('-b, --base-url <url>', 'Override the stored base URL')
26
- .action(async (options) => {
27
- await handleStatus(options);
28
- });
29
- auth
30
- .command('logout')
31
- .description('Remove the local session file')
32
- .action(async () => {
33
- await clearStoredSession();
34
- outro(`Removed local session at ${SESSION_FILE_PATH}`);
35
- });
36
- return auth;
37
- }
38
- async function handleLogin(options) {
39
- intro('Parix sign in');
40
- const storedSession = await readStoredSession();
41
- const baseUrl = resolveBaseUrl(options.baseUrl, storedSession, { useStoredSession: false });
42
- const loopbackServer = await startLoopbackServer({
43
- callbackPath: PARIX_LOCAL_CALLBACK_PATH,
44
- port: options.port,
45
- successPage: {
46
- redirectUrl: new URL(CLI_OAUTH_CONSENT_GRANTED_PATH, baseUrl).toString(),
47
- },
48
- timeoutMs: LOGIN_TIMEOUT_MS,
49
- });
50
- try {
51
- const pkcePair = createPkcePair();
52
- const state = buildCliState(loopbackServer.callbackUrl);
53
- loopbackServer.setState(state);
54
- const browserUrl = buildAuthorizeUrl({
55
- baseUrl,
56
- codeChallenge: pkcePair.codeChallenge,
57
- prompt: options.prompt,
58
- state,
59
- });
60
- const prepareSpinner = spinner();
61
- prepareSpinner.start('Preparing browser sign-in');
62
- prepareSpinner.stop('Browser sign-in ready');
63
- const opened = await openUrlInBrowser(browserUrl);
64
- note(opened ? browserUrl : `Open this URL manually:\n${browserUrl}`, opened ? 'Opened browser URL' : 'Manual browser URL');
65
- const waitSpinner = spinner();
66
- waitSpinner.start('Waiting for browser callback');
67
- const callbackResult = await loopbackServer.waitForResult();
68
- waitSpinner.stop('Received browser callback');
69
- // Shut down the loopback server before token exchange so browser keep-alive
70
- // sockets cannot keep the process open after sign-in completes.
71
- await loopbackServer.close().catch(() => { });
72
- const tokenSet = await exchangeAuthorizationCode({
73
- baseUrl,
74
- code: callbackResult.code,
75
- codeVerifier: pkcePair.codeVerifier,
76
- });
77
- const nextSession = await createStoredSession({
78
- baseUrl,
79
- createdAt: storedSession?.createdAt,
80
- tokenSet,
81
- });
82
- await writeStoredSession(nextSession);
83
- note(SESSION_FILE_PATH, 'Stored session file');
84
- outro(`Signed in as ${formatUserLabel(nextSession.user)}`);
85
- }
86
- finally {
87
- await loopbackServer.close().catch(() => { });
88
- }
89
- }
90
- async function handleStatus(options) {
91
- intro('Parix auth status');
92
- const storedSession = await readStoredSession();
93
- if (!storedSession) {
94
- log.warn(`No local session found at ${SESSION_FILE_PATH}`);
95
- process.exitCode = 1;
96
- return;
97
- }
98
- const baseUrl = resolveBaseUrl(options.baseUrl, storedSession);
99
- try {
100
- const refreshedSession = await hydrateStoredSessionOrganization(await ensureFreshSession({
101
- ...storedSession,
102
- baseUrl,
103
- }));
104
- const userInfo = await fetchOAuthUserInfo({
105
- accessToken: refreshedSession.accessToken,
106
- baseUrl,
107
- });
108
- note([
109
- `User: ${userInfo.email ?? formatUserLabel(refreshedSession.user)}`,
110
- `Base URL: ${baseUrl}`,
111
- `Expires: ${refreshedSession.accessTokenExpiresAt}`,
112
- `Scopes: ${refreshedSession.scopes.join(', ')}`,
113
- `Organization: ${refreshedSession.organization.name ?? 'none'}`,
114
- `Organization slug: ${refreshedSession.organization.slug ?? 'none'}`,
115
- `Member role: ${refreshedSession.organization.memberRole ?? 'none'}`,
116
- `Session file: ${SESSION_FILE_PATH}`,
117
- ].join('\n'), 'Authenticated session');
118
- outro('Session is valid');
119
- }
120
- catch (error) {
121
- const message = error instanceof Error ? error.message : String(error);
122
- log.warn(`Stored session is invalid: ${message}`);
123
- process.exitCode = 1;
124
- }
125
- }
126
- function formatUserLabel(user) {
127
- return user.email ?? user.name ?? user.id;
128
- }