@instawp/cli 0.0.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +129 -0
  3. package/dist/commands/exec.d.ts +3 -0
  4. package/dist/commands/exec.js +126 -0
  5. package/dist/commands/exec.js.map +1 -0
  6. package/dist/commands/login.d.ts +2 -0
  7. package/dist/commands/login.js +63 -0
  8. package/dist/commands/login.js.map +1 -0
  9. package/dist/commands/sites.d.ts +3 -0
  10. package/dist/commands/sites.js +343 -0
  11. package/dist/commands/sites.js.map +1 -0
  12. package/dist/commands/ssh.d.ts +2 -0
  13. package/dist/commands/ssh.js +41 -0
  14. package/dist/commands/ssh.js.map +1 -0
  15. package/dist/commands/sync.d.ts +2 -0
  16. package/dist/commands/sync.js +131 -0
  17. package/dist/commands/sync.js.map +1 -0
  18. package/dist/commands/teams.d.ts +2 -0
  19. package/dist/commands/teams.js +122 -0
  20. package/dist/commands/teams.js.map +1 -0
  21. package/dist/commands/whoami.d.ts +2 -0
  22. package/dist/commands/whoami.js +60 -0
  23. package/dist/commands/whoami.js.map +1 -0
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.js +101 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/lib/api.d.ts +4 -0
  28. package/dist/lib/api.js +45 -0
  29. package/dist/lib/api.js.map +1 -0
  30. package/dist/lib/auth.d.ts +1 -0
  31. package/dist/lib/auth.js +75 -0
  32. package/dist/lib/auth.js.map +1 -0
  33. package/dist/lib/config.d.ts +11 -0
  34. package/dist/lib/config.js +66 -0
  35. package/dist/lib/config.js.map +1 -0
  36. package/dist/lib/output.d.ts +14 -0
  37. package/dist/lib/output.js +63 -0
  38. package/dist/lib/output.js.map +1 -0
  39. package/dist/lib/site-resolver.d.ts +2 -0
  40. package/dist/lib/site-resolver.js +78 -0
  41. package/dist/lib/site-resolver.js.map +1 -0
  42. package/dist/lib/ssh-connection.d.ts +8 -0
  43. package/dist/lib/ssh-connection.js +70 -0
  44. package/dist/lib/ssh-connection.js.map +1 -0
  45. package/dist/lib/ssh-keys.d.ts +2 -0
  46. package/dist/lib/ssh-keys.js +232 -0
  47. package/dist/lib/ssh-keys.js.map +1 -0
  48. package/dist/types.d.ts +76 -0
  49. package/dist/types.js +2 -0
  50. package/dist/types.js.map +1 -0
  51. package/package.json +55 -0
@@ -0,0 +1,122 @@
1
+ import { requireAuth, getClient } from '../lib/api.js';
2
+ import { success, error, table, spinner, isJsonMode } from '../lib/output.js';
3
+ async function fetchTeams() {
4
+ const client = getClient();
5
+ const res = await client.get('/teams');
6
+ return {
7
+ teams: res.data?.data || [],
8
+ current_team_id: res.data?.current_team_id ?? null,
9
+ };
10
+ }
11
+ async function resolveTeamId(teamArg) {
12
+ // If numeric, use directly
13
+ if (/^\d+$/.test(teamArg)) {
14
+ return parseInt(teamArg, 10);
15
+ }
16
+ // Otherwise, fetch teams and match by name (case-insensitive)
17
+ const { teams } = await fetchTeams();
18
+ const matches = teams.filter((t) => t.name.toLowerCase() === teamArg.toLowerCase());
19
+ if (matches.length === 0) {
20
+ error(`No team found matching "${teamArg}"`);
21
+ process.exit(1);
22
+ }
23
+ if (matches.length > 1) {
24
+ error(`Multiple teams match "${teamArg}". Use team ID instead.`);
25
+ process.exit(1);
26
+ }
27
+ return matches[0].id;
28
+ }
29
+ export function registerTeamsCommand(program) {
30
+ const teams = program
31
+ .command('teams')
32
+ .description('Manage teams');
33
+ // teams list
34
+ teams
35
+ .command('list')
36
+ .description('List all teams')
37
+ .action(async () => {
38
+ requireAuth();
39
+ const spin = spinner('Fetching teams...');
40
+ spin.start();
41
+ try {
42
+ const { teams: teamList, current_team_id } = await fetchTeams();
43
+ spin.stop();
44
+ if (teamList.length === 0) {
45
+ if (isJsonMode()) {
46
+ console.log(JSON.stringify([]));
47
+ }
48
+ else {
49
+ success('No teams found.');
50
+ }
51
+ return;
52
+ }
53
+ if (isJsonMode()) {
54
+ const rows = teamList.map((t) => ({
55
+ id: t.id,
56
+ name: t.name,
57
+ created_at: t.created_at || '',
58
+ is_current: t.id === current_team_id,
59
+ }));
60
+ console.log(JSON.stringify(rows));
61
+ return;
62
+ }
63
+ const rows = teamList.map((t) => ({
64
+ id: t.id,
65
+ name: t.id === current_team_id ? `${t.name} (current)` : t.name,
66
+ created_at: t.created_at || '',
67
+ }));
68
+ table(['ID', 'Name', 'Created At'], rows);
69
+ }
70
+ catch (err) {
71
+ spin.fail('Failed to fetch teams');
72
+ error('Could not list teams', err.response?.data?.message || err.message);
73
+ process.exit(1);
74
+ }
75
+ });
76
+ // teams members <team>
77
+ teams
78
+ .command('members <team>')
79
+ .description('List members of a team (by ID or name)')
80
+ .action(async (teamArg) => {
81
+ requireAuth();
82
+ const spin = spinner('Fetching team members...');
83
+ spin.start();
84
+ try {
85
+ const teamId = await resolveTeamId(teamArg);
86
+ const client = getClient();
87
+ const res = await client.get(`/teams/${teamId}/members`);
88
+ spin.stop();
89
+ const members = res.data?.data || [];
90
+ if (members.length === 0) {
91
+ if (isJsonMode()) {
92
+ console.log(JSON.stringify([]));
93
+ }
94
+ else {
95
+ success('No members found.');
96
+ }
97
+ return;
98
+ }
99
+ if (isJsonMode()) {
100
+ const rows = members.map((m) => ({
101
+ id: m.id,
102
+ name: m.name || '',
103
+ email: m.email || '',
104
+ }));
105
+ console.log(JSON.stringify(rows));
106
+ return;
107
+ }
108
+ const rows = members.map((m) => ({
109
+ id: m.id,
110
+ name: m.name || '',
111
+ email: m.email || '',
112
+ }));
113
+ table(['ID', 'Name', 'Email'], rows);
114
+ }
115
+ catch (err) {
116
+ spin.fail('Failed to fetch team members');
117
+ error('Could not list team members', err.response?.data?.message || err.message);
118
+ process.exit(1);
119
+ }
120
+ });
121
+ }
122
+ //# sourceMappingURL=teams.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teams.js","sourceRoot":"","sources":["../../src/commands/teams.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerWhoamiCommand(program: Command): void;
@@ -0,0 +1,60 @@
1
+ import { getToken, getUser, getApiUrl } from '../lib/config.js';
2
+ import { requireAuth, getClient } from '../lib/api.js';
3
+ import { success, error, spinner, isJsonMode } from '../lib/output.js';
4
+ export function registerWhoamiCommand(program) {
5
+ program
6
+ .command('whoami')
7
+ .description('Show current authenticated user')
8
+ .action(async () => {
9
+ requireAuth();
10
+ const spin = spinner('Checking authentication...');
11
+ spin.start();
12
+ try {
13
+ const client = getClient();
14
+ const res = await client.get('/sites', { params: { per_page: 1 } });
15
+ spin.succeed('Authenticated');
16
+ const user = getUser();
17
+ // Fetch team context (non-fatal)
18
+ let teamName;
19
+ let teamId;
20
+ try {
21
+ const teamsRes = await client.get('/teams');
22
+ const currentTeamId = teamsRes.data?.current_team_id;
23
+ if (currentTeamId) {
24
+ const teams = teamsRes.data?.data || [];
25
+ const currentTeam = teams.find((t) => t.id === currentTeamId);
26
+ if (currentTeam) {
27
+ teamId = currentTeam.id;
28
+ teamName = currentTeam.name;
29
+ }
30
+ }
31
+ }
32
+ catch {
33
+ // Team info is non-fatal — skip silently
34
+ }
35
+ const sessionData = {
36
+ api_url: getApiUrl(),
37
+ ...(user ? { name: user.name, email: user.email } : {}),
38
+ token: getToken().substring(0, 8) + '...',
39
+ };
40
+ if (isJsonMode()) {
41
+ if (teamId) {
42
+ sessionData.team_id = teamId;
43
+ sessionData.team_name = teamName;
44
+ }
45
+ }
46
+ else {
47
+ if (teamName && teamId) {
48
+ sessionData.team = `${teamName} (ID: ${teamId})`;
49
+ }
50
+ }
51
+ success('Current session', sessionData);
52
+ }
53
+ catch (err) {
54
+ spin.fail('Authentication check failed');
55
+ error('Token is no longer valid. Run `instawp login` to re-authenticate.');
56
+ process.exit(1);
57
+ }
58
+ });
59
+ }
60
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEvE,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,iCAAiC,CAAC;SAC9C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,WAAW,EAAE,CAAC;QAEd,MAAM,IAAI,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;YACpE,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;YAE9B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;YAEvB,iCAAiC;YACjC,IAAI,QAA4B,CAAC;YACjC,IAAI,MAA0B,CAAC;YAC/B,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAC5C,MAAM,aAAa,GAAG,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;gBACrD,IAAI,aAAa,EAAE,CAAC;oBAClB,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC;oBACxC,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,aAAa,CAAC,CAAC;oBACnE,IAAI,WAAW,EAAE,CAAC;wBAChB,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC;wBACxB,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC;oBAC9B,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,yCAAyC;YAC3C,CAAC;YAED,MAAM,WAAW,GAAwB;gBACvC,OAAO,EAAE,SAAS,EAAE;gBACpB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,KAAK,EAAE,QAAQ,EAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK;aAC3C,CAAC;YAEF,IAAI,UAAU,EAAE,EAAE,CAAC;gBACjB,IAAI,MAAM,EAAE,CAAC;oBACX,WAAW,CAAC,OAAO,GAAG,MAAM,CAAC;oBAC7B,WAAW,CAAC,SAAS,GAAG,QAAQ,CAAC;gBACnC,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;oBACvB,WAAW,CAAC,IAAI,GAAG,GAAG,QAAQ,SAAS,MAAM,GAAG,CAAC;gBACnD,CAAC;YACH,CAAC;YAED,OAAO,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;YACzC,KAAK,CAAC,mEAAmE,CAAC,CAAC;YAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import { setJsonMode } from './lib/output.js';
6
+ import { registerLoginCommand } from './commands/login.js';
7
+ import { registerWhoamiCommand } from './commands/whoami.js';
8
+ import { registerSitesCommand, registerCreateAlias } from './commands/sites.js';
9
+ import { registerSyncCommand } from './commands/sync.js';
10
+ import { registerSshCommand } from './commands/ssh.js';
11
+ import { registerExecCommand, registerWpCommand } from './commands/exec.js';
12
+ import { registerTeamsCommand } from './commands/teams.js';
13
+ const require = createRequire(import.meta.url);
14
+ const { version } = require('../package.json');
15
+ // Early --json detection so it works in any argv position
16
+ if (process.argv.includes('--json')) {
17
+ setJsonMode(true);
18
+ // Remove --json from argv so Commander doesn't choke on it as unknown option
19
+ process.argv = process.argv.filter(a => a !== '--json');
20
+ }
21
+ const program = new Command();
22
+ program
23
+ .name('instawp')
24
+ .description('InstaWP CLI - Create and manage WordPress sites from the terminal')
25
+ .version(version)
26
+ .enablePositionalOptions()
27
+ .option('--json', 'Output results as JSON');
28
+ // -- Auth --
29
+ registerLoginCommand(program);
30
+ registerWhoamiCommand(program);
31
+ // -- Sites --
32
+ registerSitesCommand(program);
33
+ registerCreateAlias(program);
34
+ // -- Remote access --
35
+ registerExecCommand(program);
36
+ registerWpCommand(program);
37
+ registerSshCommand(program);
38
+ registerSyncCommand(program);
39
+ // -- Teams --
40
+ registerTeamsCommand(program);
41
+ // Custom help layout
42
+ program.configureHelp({
43
+ sortSubcommands: false,
44
+ subcommandTerm: (cmd) => cmd.name() + ' ' + cmd.usage(),
45
+ });
46
+ program.addHelpText('after', () => {
47
+ const d = chalk.dim;
48
+ const c = chalk.cyan;
49
+ return `
50
+ ${d('Auth')}
51
+ ${c('login')} Authenticate with InstaWP (browser or --token)
52
+ ${c('whoami')} Show current session info
53
+
54
+ ${d('Sites')}
55
+ ${c('create')} Create a new WordPress site
56
+ ${c('sites list')} List all sites
57
+ ${c('sites delete')} Delete a site
58
+
59
+ ${d('Remote Access')}
60
+ ${c('exec')} ${d('<site>')} ${d('<cmd>')} Run any command on a site (SSH default, --api)
61
+ ${c('wp')} ${d('<site>')} ${d('<args>')} WP-CLI shorthand (exec <site> wp <args>)
62
+ ${c('ssh')} ${d('<site>')} Interactive SSH session
63
+ ${c('sync')} ${d('push|pull')} Sync wp-content via rsync
64
+
65
+ ${d('Teams')}
66
+ ${c('teams list')} List teams
67
+ ${c('teams members')} List team members
68
+
69
+ ${d('Examples')}
70
+ $ instawp login
71
+ $ instawp create --name my-site
72
+ $ instawp wp my-site plugin list
73
+ $ instawp exec my-site php -v --api
74
+ $ instawp ssh my-site
75
+ $ instawp sites list --json
76
+ `;
77
+ });
78
+ // Override default help to only show options (commands are in custom section)
79
+ program.configureHelp({
80
+ sortSubcommands: false,
81
+ formatHelp: (cmd, helper) => {
82
+ const title = helper.padWidth(cmd, helper);
83
+ const desc = cmd.description();
84
+ const ver = cmd.version() ? `v${cmd.version()}` : '';
85
+ let output = '';
86
+ output += `${desc}${ver ? ' ' + chalk.dim(ver) : ''}\n\n`;
87
+ output += `${chalk.dim('Usage:')} ${cmd.name()} [options] [command]\n`;
88
+ const opts = helper.visibleOptions(cmd);
89
+ if (opts.length) {
90
+ output += `\n${chalk.dim('Options')}\n`;
91
+ for (const opt of opts) {
92
+ const flags = opt.flags;
93
+ const desc = opt.description;
94
+ output += ` ${flags.padEnd(30)} ${desc}\n`;
95
+ }
96
+ }
97
+ return output;
98
+ },
99
+ });
100
+ program.parse();
101
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { AxiosInstance } from 'axios';
2
+ export declare function getClient(): AxiosInstance;
3
+ export declare function resetClient(): void;
4
+ export declare function requireAuth(): void;
@@ -0,0 +1,45 @@
1
+ import axios from 'axios';
2
+ import { getToken, getApiUrl, clearConfig } from './config.js';
3
+ import { error } from './output.js';
4
+ let client = null;
5
+ export function getClient() {
6
+ if (client)
7
+ return client;
8
+ const baseURL = `${getApiUrl()}/api/v2`;
9
+ client = axios.create({
10
+ baseURL,
11
+ timeout: 30000,
12
+ headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
13
+ });
14
+ client.interceptors.request.use((config) => {
15
+ const token = getToken();
16
+ if (token) {
17
+ config.headers.Authorization = `Bearer ${token}`;
18
+ }
19
+ return config;
20
+ });
21
+ client.interceptors.response.use((response) => response, (err) => {
22
+ if (err.response?.status === 401) {
23
+ clearConfig();
24
+ error('Authentication expired. Run `instawp login` to re-authenticate.');
25
+ process.exit(1);
26
+ }
27
+ if (err.response?.status === 429) {
28
+ error('Rate limited. Please wait and try again.');
29
+ process.exit(1);
30
+ }
31
+ return Promise.reject(err);
32
+ });
33
+ return client;
34
+ }
35
+ export function resetClient() {
36
+ client = null;
37
+ }
38
+ export function requireAuth() {
39
+ const token = getToken();
40
+ if (!token) {
41
+ error('Not authenticated. Run `instawp login` first.');
42
+ process.exit(1);
43
+ }
44
+ }
45
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,IAAI,MAAM,GAAyB,IAAI,CAAC;AAExC,MAAM,UAAU,SAAS;IACvB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,OAAO,GAAG,GAAG,SAAS,EAAE,SAAS,CAAC;IACxC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QACpB,OAAO;QACP,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,EAAE,QAAQ,EAAE,kBAAkB,EAAE,cAAc,EAAE,kBAAkB,EAAE;KAC9E,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACzC,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;QACzB,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,CAAC,OAAO,CAAC,aAAa,GAAG,UAAU,KAAK,EAAE,CAAC;QACnD,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAC9B,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,EACtB,CAAC,GAAe,EAAE,EAAE;QAClB,IAAI,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;YACjC,WAAW,EAAE,CAAC;YACd,KAAK,CAAC,iEAAiE,CAAC,CAAC;YACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;YACjC,KAAK,CAAC,0CAA0C,CAAC,CAAC;YAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function startOAuthFlow(): Promise<string>;
@@ -0,0 +1,75 @@
1
+ import http from 'node:http';
2
+ import { getApiUrl } from './config.js';
3
+ export async function startOAuthFlow() {
4
+ const port = await findAvailablePort(9000, 9100);
5
+ const returnUrl = `http://localhost:${port}/callback`;
6
+ const apiUrl = getApiUrl();
7
+ return new Promise((resolve, reject) => {
8
+ const timeout = setTimeout(() => {
9
+ server.close();
10
+ reject(new Error('Login timed out after 5 minutes. Try again or use --token.'));
11
+ }, 5 * 60 * 1000);
12
+ const server = http.createServer((req, res) => {
13
+ const url = new URL(req.url, `http://localhost:${port}`);
14
+ if (url.pathname === '/callback') {
15
+ const accessToken = url.searchParams.get('access_token');
16
+ const successParam = url.searchParams.get('success');
17
+ if (successParam === 'true' && accessToken) {
18
+ res.writeHead(200, { 'Content-Type': 'text/html' });
19
+ res.end(`
20
+ <html><body style="font-family: system-ui; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0;">
21
+ <div style="text-align: center;">
22
+ <h1 style="color: #22c55e;">&#10003; Authenticated</h1>
23
+ <p>You can close this window and return to the terminal.</p>
24
+ </div>
25
+ </body></html>
26
+ `);
27
+ clearTimeout(timeout);
28
+ server.close();
29
+ resolve(accessToken);
30
+ }
31
+ else {
32
+ res.writeHead(200, { 'Content-Type': 'text/html' });
33
+ res.end(`
34
+ <html><body style="font-family: system-ui; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0;">
35
+ <div style="text-align: center;">
36
+ <h1 style="color: #ef4444;">&#10007; Authentication Failed</h1>
37
+ <p>Please try again.</p>
38
+ </div>
39
+ </body></html>
40
+ `);
41
+ clearTimeout(timeout);
42
+ server.close();
43
+ reject(new Error('Authentication was denied or failed.'));
44
+ }
45
+ }
46
+ else {
47
+ res.writeHead(404);
48
+ res.end();
49
+ }
50
+ });
51
+ server.listen(port, () => {
52
+ const authorizeUrl = `${apiUrl}/authorize?source=cli&return_url=${encodeURIComponent(returnUrl)}`;
53
+ import('open').then((mod) => mod.default(authorizeUrl)).catch(() => {
54
+ console.log(`Open this URL in your browser:\n ${authorizeUrl}`);
55
+ });
56
+ });
57
+ });
58
+ }
59
+ function findAvailablePort(start, end) {
60
+ return new Promise((resolve, reject) => {
61
+ function tryPort(port) {
62
+ if (port > end) {
63
+ reject(new Error(`No available port found in range ${start}-${end}`));
64
+ return;
65
+ }
66
+ const server = http.createServer();
67
+ server.listen(port, () => {
68
+ server.close(() => resolve(port));
69
+ });
70
+ server.on('error', () => tryPort(port + 1));
71
+ }
72
+ tryPort(start);
73
+ });
74
+ }
75
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACjD,MAAM,SAAS,GAAG,oBAAoB,IAAI,WAAW,CAAC;IACtD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC,CAAC;QAClF,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAElB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAI,EAAE,oBAAoB,IAAI,EAAE,CAAC,CAAC;YAE1D,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;gBACjC,MAAM,WAAW,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;gBACzD,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAErD,IAAI,YAAY,KAAK,MAAM,IAAI,WAAW,EAAE,CAAC;oBAC3C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;oBACpD,GAAG,CAAC,GAAG,CAAC;;;;;;;WAOP,CAAC,CAAC;oBACH,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,MAAM,CAAC,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,WAAW,CAAC,CAAC;gBACvB,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;oBACpD,GAAG,CAAC,GAAG,CAAC;;;;;;;WAOP,CAAC,CAAC;oBACH,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,MAAM,CAAC,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC,CAAC;gBAC5D,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;YACvB,MAAM,YAAY,GAAG,GAAG,MAAM,oCAAoC,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;YAClG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBACjE,OAAO,CAAC,GAAG,CAAC,qCAAqC,YAAY,EAAE,CAAC,CAAC;YACnE,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAa,EAAE,GAAW;IACnD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,SAAS,OAAO,CAAC,IAAY;YAC3B,IAAI,IAAI,GAAG,GAAG,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,KAAK,CAAC,oCAAoC,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;gBACtE,OAAO;YACT,CAAC;YACD,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;gBACvB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACpC,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { UserInfo, SshConnectionCache } from '../types.js';
2
+ export declare function getToken(): string | null;
3
+ export declare function getApiUrl(): string;
4
+ export declare function setToken(token: string): void;
5
+ export declare function setUser(user: UserInfo): void;
6
+ export declare function getUser(): UserInfo | null;
7
+ export declare function setApiUrl(url: string): void;
8
+ export declare function clearConfig(): void;
9
+ export declare function getSshCache(siteId: number): SshConnectionCache | null;
10
+ export declare function setSshCache(siteId: number, entry: SshConnectionCache): void;
11
+ export declare function clearSshCache(siteId?: number): void;
@@ -0,0 +1,66 @@
1
+ import Conf from 'conf';
2
+ const SSH_CACHE_TTL = 60 * 60 * 1000; // 1 hour
3
+ const config = new Conf({
4
+ projectName: 'instawp',
5
+ schema: {
6
+ api_url: { type: 'string', default: 'https://app.instawp.io' },
7
+ token: { type: 'string', default: '' },
8
+ user: { type: 'object', default: {} },
9
+ ssh_cache: { type: 'object', default: {} },
10
+ },
11
+ });
12
+ export function getToken() {
13
+ const envToken = process.env.INSTAWP_TOKEN;
14
+ if (envToken)
15
+ return envToken;
16
+ const token = config.get('token');
17
+ return token || null;
18
+ }
19
+ export function getApiUrl() {
20
+ return (process.env.INSTAWP_API_URL || config.get('api_url'));
21
+ }
22
+ export function setToken(token) {
23
+ config.set('token', token);
24
+ }
25
+ export function setUser(user) {
26
+ config.set('user', user);
27
+ }
28
+ export function getUser() {
29
+ const user = config.get('user');
30
+ if (user && user.id)
31
+ return user;
32
+ return null;
33
+ }
34
+ export function setApiUrl(url) {
35
+ config.set('api_url', url);
36
+ }
37
+ export function clearConfig() {
38
+ config.clear();
39
+ }
40
+ export function getSshCache(siteId) {
41
+ const cache = config.get('ssh_cache');
42
+ const entry = cache?.[String(siteId)];
43
+ if (!entry)
44
+ return null;
45
+ if (Date.now() - entry.cachedAt > SSH_CACHE_TTL) {
46
+ clearSshCache(siteId);
47
+ return null;
48
+ }
49
+ return entry;
50
+ }
51
+ export function setSshCache(siteId, entry) {
52
+ const cache = config.get('ssh_cache') || {};
53
+ cache[String(siteId)] = entry;
54
+ config.set('ssh_cache', cache);
55
+ }
56
+ export function clearSshCache(siteId) {
57
+ if (siteId !== undefined) {
58
+ const cache = config.get('ssh_cache') || {};
59
+ delete cache[String(siteId)];
60
+ config.set('ssh_cache', cache);
61
+ }
62
+ else {
63
+ config.set('ssh_cache', {});
64
+ }
65
+ }
66
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { Ora } from 'ora';
2
+ export declare function setJsonMode(enabled: boolean): void;
3
+ export declare function isJsonMode(): boolean;
4
+ export declare function success(msg: string, data?: any): void;
5
+ export declare function error(msg: string, details?: any): void;
6
+ export declare function table(headers: string[], rows: Record<string, any>[]): void;
7
+ export declare function spinner(text: string): Ora | {
8
+ text: string;
9
+ start: () => any;
10
+ succeed: (t?: string) => void;
11
+ fail: (t?: string) => void;
12
+ stop: () => void;
13
+ };
14
+ export declare function info(msg: string): void;
@@ -0,0 +1,63 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import Table from 'cli-table3';
4
+ let jsonMode = false;
5
+ export function setJsonMode(enabled) {
6
+ jsonMode = enabled;
7
+ }
8
+ export function isJsonMode() {
9
+ return jsonMode;
10
+ }
11
+ export function success(msg, data) {
12
+ if (jsonMode) {
13
+ console.log(JSON.stringify({ success: true, message: msg, ...(data !== undefined ? { data } : {}) }));
14
+ }
15
+ else {
16
+ console.log(chalk.green('\u2713') + ' ' + msg);
17
+ if (data && typeof data === 'object') {
18
+ for (const [key, value] of Object.entries(data)) {
19
+ console.log(` ${chalk.dim(key + ':')} ${value}`);
20
+ }
21
+ }
22
+ }
23
+ }
24
+ export function error(msg, details) {
25
+ if (jsonMode) {
26
+ console.error(JSON.stringify({ success: false, error: msg, ...(details !== undefined ? { details } : {}) }));
27
+ }
28
+ else {
29
+ console.error(chalk.red('\u2717') + ' ' + msg);
30
+ if (details) {
31
+ console.error(chalk.dim(typeof details === 'string' ? details : JSON.stringify(details, null, 2)));
32
+ }
33
+ }
34
+ }
35
+ export function table(headers, rows) {
36
+ if (jsonMode) {
37
+ console.log(JSON.stringify(rows));
38
+ return;
39
+ }
40
+ const t = new Table({
41
+ head: headers.map(h => chalk.cyan(h)),
42
+ style: { head: [], border: [] },
43
+ });
44
+ for (const row of rows) {
45
+ t.push(headers.map(h => {
46
+ const key = h.toLowerCase().replace(/\s+/g, '_');
47
+ return String(row[key] ?? row[h] ?? '');
48
+ }));
49
+ }
50
+ console.log(t.toString());
51
+ }
52
+ export function spinner(text) {
53
+ if (jsonMode) {
54
+ return { text: '', start() { return this; }, succeed() { }, fail() { }, stop() { } };
55
+ }
56
+ return ora(text);
57
+ }
58
+ export function info(msg) {
59
+ if (!jsonMode) {
60
+ console.log(chalk.blue('\u2139') + ' ' + msg);
61
+ }
62
+ }
63
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { SiteDetails } from '../types.js';
2
+ export declare function resolveSite(identifier: string): Promise<SiteDetails>;