@banatie/cli 0.1.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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +54 -0
  3. package/dist/apiClient.d.ts +102 -0
  4. package/dist/apiClient.d.ts.map +1 -0
  5. package/dist/apiClient.js +83 -0
  6. package/dist/baseUrl.d.ts +2 -0
  7. package/dist/baseUrl.d.ts.map +1 -0
  8. package/dist/baseUrl.js +7 -0
  9. package/dist/cli.d.ts +3 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +15 -0
  12. package/dist/commands/connectDirect.d.ts +3 -0
  13. package/dist/commands/connectDirect.d.ts.map +1 -0
  14. package/dist/commands/connectDirect.js +34 -0
  15. package/dist/commands/login.d.ts +3 -0
  16. package/dist/commands/login.d.ts.map +1 -0
  17. package/dist/commands/login.js +40 -0
  18. package/dist/commands/logout.d.ts +3 -0
  19. package/dist/commands/logout.d.ts.map +1 -0
  20. package/dist/commands/logout.js +21 -0
  21. package/dist/commands/projectConnect.d.ts +3 -0
  22. package/dist/commands/projectConnect.d.ts.map +1 -0
  23. package/dist/commands/projectConnect.js +66 -0
  24. package/dist/commands/projectDelete.d.ts +7 -0
  25. package/dist/commands/projectDelete.d.ts.map +1 -0
  26. package/dist/commands/projectDelete.js +99 -0
  27. package/dist/commands/projectList.d.ts +3 -0
  28. package/dist/commands/projectList.d.ts.map +1 -0
  29. package/dist/commands/projectList.js +54 -0
  30. package/dist/commands/projectNew.d.ts +3 -0
  31. package/dist/commands/projectNew.d.ts.map +1 -0
  32. package/dist/commands/projectNew.js +61 -0
  33. package/dist/commands/revoke.d.ts +3 -0
  34. package/dist/commands/revoke.d.ts.map +1 -0
  35. package/dist/commands/revoke.js +41 -0
  36. package/dist/commands/rotate.d.ts +3 -0
  37. package/dist/commands/rotate.d.ts.map +1 -0
  38. package/dist/commands/rotate.js +36 -0
  39. package/dist/commands/status.d.ts +3 -0
  40. package/dist/commands/status.d.ts.map +1 -0
  41. package/dist/commands/status.js +30 -0
  42. package/dist/commands/types.d.ts +5 -0
  43. package/dist/commands/types.d.ts.map +1 -0
  44. package/dist/commands/types.js +2 -0
  45. package/dist/config.d.ts +36 -0
  46. package/dist/config.d.ts.map +1 -0
  47. package/dist/config.js +109 -0
  48. package/dist/confirmPrompt.d.ts +2 -0
  49. package/dist/confirmPrompt.d.ts.map +1 -0
  50. package/dist/confirmPrompt.js +20 -0
  51. package/dist/dispatch.d.ts +4 -0
  52. package/dist/dispatch.d.ts.map +1 -0
  53. package/dist/dispatch.js +101 -0
  54. package/dist/index.d.ts +19 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +34 -0
  57. package/dist/preview.d.ts +2 -0
  58. package/dist/preview.d.ts.map +1 -0
  59. package/dist/preview.js +9 -0
  60. package/dist/projectConfig.d.ts +12 -0
  61. package/dist/projectConfig.d.ts.map +1 -0
  62. package/dist/projectConfig.js +40 -0
  63. package/package.json +35 -0
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.projectListCommand = void 0;
4
+ const apiClient_1 = require("../apiClient");
5
+ const baseUrl_1 = require("../baseUrl");
6
+ const config_1 = require("../config");
7
+ // `org <slug> project list`: print the organization's projects (metadata only)
8
+ // using the saved org token. Never prints any project key.
9
+ const projectListCommand = async (orgSlug) => {
10
+ const baseApiUrl = (0, baseUrl_1.resolveBaseUrl)();
11
+ const profile = (0, config_1.getProfile)(baseApiUrl, orgSlug);
12
+ if (!profile) {
13
+ return {
14
+ exitCode: 1,
15
+ lines: [
16
+ `Not logged in to "${orgSlug}" on ${baseApiUrl}.`,
17
+ `Run: banatie org ${orgSlug} login <bnt_boot-token>`,
18
+ ],
19
+ };
20
+ }
21
+ const client = new apiClient_1.BanatieApiClient(baseApiUrl);
22
+ try {
23
+ const result = await client.listProjects(profile.token);
24
+ if (result.projects.length === 0) {
25
+ return {
26
+ exitCode: 0,
27
+ lines: [
28
+ `No projects yet in "${orgSlug}".`,
29
+ `Create one: banatie org ${orgSlug} project new <project-slug>`,
30
+ ],
31
+ };
32
+ }
33
+ return {
34
+ exitCode: 0,
35
+ lines: [
36
+ `Projects in "${orgSlug}":`,
37
+ ...result.projects.map((p) => ` ${p.slug} — ${p.name} (${p.createdAt})`),
38
+ ],
39
+ };
40
+ }
41
+ catch (error) {
42
+ if (error instanceof apiClient_1.ApiError && error.status === 401) {
43
+ return {
44
+ exitCode: 1,
45
+ lines: [`Your login has expired. Run: banatie org ${orgSlug} login <bnt_boot-token>`],
46
+ };
47
+ }
48
+ return {
49
+ exitCode: 1,
50
+ lines: [error instanceof Error ? error.message : 'Project list failed.'],
51
+ };
52
+ }
53
+ };
54
+ exports.projectListCommand = projectListCommand;
@@ -0,0 +1,3 @@
1
+ import type { CommandResult } from './types';
2
+ export declare const projectNewCommand: (orgSlug: string, projectSlug: string) => Promise<CommandResult>;
3
+ //# sourceMappingURL=projectNew.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectNew.d.ts","sourceRoot":"","sources":["../../src/commands/projectNew.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAI7C,eAAO,MAAM,iBAAiB,GAC5B,SAAS,MAAM,EACf,aAAa,MAAM,KAClB,OAAO,CAAC,aAAa,CAmDvB,CAAC"}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.projectNewCommand = void 0;
4
+ const apiClient_1 = require("../apiClient");
5
+ const baseUrl_1 = require("../baseUrl");
6
+ const config_1 = require("../config");
7
+ // `org <slug> project new <project-slug>`: create a project with the saved org token
8
+ // and print its connect command + key preview (never the org token or a raw key).
9
+ const projectNewCommand = async (orgSlug, projectSlug) => {
10
+ const baseApiUrl = (0, baseUrl_1.resolveBaseUrl)();
11
+ const profile = (0, config_1.getProfile)(baseApiUrl, orgSlug);
12
+ if (!profile) {
13
+ return {
14
+ exitCode: 1,
15
+ lines: [
16
+ `Not logged in to "${orgSlug}" on ${baseApiUrl}.`,
17
+ `Run: banatie org ${orgSlug} login <bnt_boot-token>`,
18
+ ],
19
+ };
20
+ }
21
+ const client = new apiClient_1.BanatieApiClient(baseApiUrl);
22
+ try {
23
+ const result = await client.createProject(profile.token, projectSlug);
24
+ return {
25
+ exitCode: 0,
26
+ lines: [
27
+ `Created project "${result.project.slug}" (${result.project.name}) in "${orgSlug}".`,
28
+ `Key: ${result.apiKey.keyPreview}`,
29
+ 'Connect this repo:',
30
+ ` ${result.commands.connect}`,
31
+ ],
32
+ };
33
+ }
34
+ catch (error) {
35
+ if (error instanceof apiClient_1.ApiError) {
36
+ if (error.status === 409) {
37
+ return {
38
+ exitCode: 1,
39
+ lines: [`A project "${projectSlug}" already exists in "${orgSlug}".`],
40
+ };
41
+ }
42
+ if (error.status === 422) {
43
+ return {
44
+ exitCode: 1,
45
+ lines: [`Invalid project slug "${projectSlug}". Use letters, numbers, and hyphens.`],
46
+ };
47
+ }
48
+ if (error.status === 401) {
49
+ return {
50
+ exitCode: 1,
51
+ lines: [`Your login has expired. Run: banatie org ${orgSlug} login <bnt_boot-token>`],
52
+ };
53
+ }
54
+ }
55
+ return {
56
+ exitCode: 1,
57
+ lines: [error instanceof Error ? error.message : 'Project creation failed.'],
58
+ };
59
+ }
60
+ };
61
+ exports.projectNewCommand = projectNewCommand;
@@ -0,0 +1,3 @@
1
+ import type { CommandResult } from './types';
2
+ export declare const revokeCommand: (orgSlug: string) => Promise<CommandResult>;
3
+ //# sourceMappingURL=revoke.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revoke.d.ts","sourceRoot":"","sources":["../../src/commands/revoke.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAG7C,eAAO,MAAM,aAAa,GAAU,SAAS,MAAM,KAAG,OAAO,CAAC,aAAa,CAgC1E,CAAC"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.revokeCommand = void 0;
4
+ const apiClient_1 = require("../apiClient");
5
+ const baseUrl_1 = require("../baseUrl");
6
+ const config_1 = require("../config");
7
+ // `org <slug> auth revoke`: revoke the current server token, then remove local login.
8
+ const revokeCommand = async (orgSlug) => {
9
+ const baseApiUrl = (0, baseUrl_1.resolveBaseUrl)();
10
+ const profile = (0, config_1.getProfile)(baseApiUrl, orgSlug);
11
+ if (!profile) {
12
+ return { exitCode: 0, lines: [`Not logged in to "${orgSlug}" on ${baseApiUrl}.`] };
13
+ }
14
+ const client = new apiClient_1.BanatieApiClient(baseApiUrl);
15
+ try {
16
+ await client.revokeCurrentToken(profile.token);
17
+ (0, config_1.removeProfile)(baseApiUrl, orgSlug);
18
+ return {
19
+ exitCode: 0,
20
+ lines: [`Revoked the organization token for "${orgSlug}" and removed local login.`],
21
+ };
22
+ }
23
+ catch (error) {
24
+ if (error instanceof apiClient_1.ApiError && error.status === 401) {
25
+ // Already invalid/revoked server-side → clear local anyway.
26
+ (0, config_1.removeProfile)(baseApiUrl, orgSlug);
27
+ return {
28
+ exitCode: 0,
29
+ lines: [`Token for "${orgSlug}" was already invalid; removed local login.`],
30
+ };
31
+ }
32
+ return {
33
+ exitCode: 1,
34
+ lines: [
35
+ error instanceof Error ? error.message : 'Revoke failed.',
36
+ 'Local login kept. Run "auth logout" to remove it locally.',
37
+ ],
38
+ };
39
+ }
40
+ };
41
+ exports.revokeCommand = revokeCommand;
@@ -0,0 +1,3 @@
1
+ import type { CommandResult } from './types';
2
+ export declare const rotateCommand: (orgSlug: string) => Promise<CommandResult>;
3
+ //# sourceMappingURL=rotate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rotate.d.ts","sourceRoot":"","sources":["../../src/commands/rotate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAI7C,eAAO,MAAM,aAAa,GAAU,SAAS,MAAM,KAAG,OAAO,CAAC,aAAa,CAyB1E,CAAC"}
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rotateCommand = void 0;
4
+ const apiClient_1 = require("../apiClient");
5
+ const baseUrl_1 = require("../baseUrl");
6
+ const preview_1 = require("../preview");
7
+ const config_1 = require("../config");
8
+ // `org <slug> auth rotate`: rotate the current server token and store the new one.
9
+ // Never prints the old or new raw token — only a preview.
10
+ const rotateCommand = async (orgSlug) => {
11
+ const baseApiUrl = (0, baseUrl_1.resolveBaseUrl)();
12
+ const profile = (0, config_1.getProfile)(baseApiUrl, orgSlug);
13
+ if (!profile) {
14
+ return { exitCode: 0, lines: [`Not logged in to "${orgSlug}" on ${baseApiUrl}.`] };
15
+ }
16
+ const client = new apiClient_1.BanatieApiClient(baseApiUrl);
17
+ try {
18
+ const result = await client.rotateCurrentToken(profile.token);
19
+ (0, config_1.upsertProfile)({
20
+ baseApiUrl,
21
+ orgSlug,
22
+ token: result.token,
23
+ ...(profile.orgId ? { orgId: profile.orgId } : {}),
24
+ ...(profile.email ? { email: profile.email } : {}),
25
+ });
26
+ const preview = result.tokenPreview ?? (0, preview_1.previewToken)(result.token);
27
+ return {
28
+ exitCode: 0,
29
+ lines: [`Rotated the organization token for "${orgSlug}".`, `New token: ${preview}`],
30
+ };
31
+ }
32
+ catch (error) {
33
+ return { exitCode: 1, lines: [error instanceof Error ? error.message : 'Rotate failed.'] };
34
+ }
35
+ };
36
+ exports.rotateCommand = rotateCommand;
@@ -0,0 +1,3 @@
1
+ import type { CommandResult } from './types';
2
+ export declare const statusCommand: (orgSlug: string) => CommandResult;
3
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAG7C,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,KAAG,aAuB/C,CAAC"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.statusCommand = void 0;
4
+ const baseUrl_1 = require("../baseUrl");
5
+ const preview_1 = require("../preview");
6
+ const config_1 = require("../config");
7
+ // `org <slug> auth status`: report local login state (preview only, never the raw token).
8
+ const statusCommand = (orgSlug) => {
9
+ const baseApiUrl = (0, baseUrl_1.resolveBaseUrl)();
10
+ const profile = (0, config_1.getProfile)(baseApiUrl, orgSlug);
11
+ if (!profile) {
12
+ return {
13
+ exitCode: 0,
14
+ lines: [
15
+ `Not logged in to "${orgSlug}" on ${baseApiUrl}.`,
16
+ `Run: banatie org ${orgSlug} login <bnt_boot-token>`,
17
+ ],
18
+ };
19
+ }
20
+ return {
21
+ exitCode: 0,
22
+ lines: [
23
+ `Organization: ${profile.orgSlug}`,
24
+ `Backend: ${profile.baseApiUrl}`,
25
+ `Email: ${profile.email ?? 'unknown'}`,
26
+ `Token: ${(0, preview_1.previewToken)(profile.token)}`,
27
+ ],
28
+ };
29
+ };
30
+ exports.statusCommand = statusCommand;
@@ -0,0 +1,5 @@
1
+ export interface CommandResult {
2
+ exitCode: number;
3
+ lines: string[];
4
+ }
5
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/commands/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,36 @@
1
+ export interface Profile {
2
+ baseApiUrl: string;
3
+ orgSlug: string;
4
+ orgId?: string;
5
+ email?: string;
6
+ token: string;
7
+ createdAt: string;
8
+ lastUsedAt: string;
9
+ }
10
+ export type SafeProfile = Omit<Profile, 'token'>;
11
+ export interface BanatieConfig {
12
+ version: number;
13
+ profiles: Profile[];
14
+ defaults?: {
15
+ baseApiUrl: string;
16
+ orgSlug: string;
17
+ };
18
+ }
19
+ export interface UpsertProfileInput {
20
+ baseApiUrl: string;
21
+ orgSlug: string;
22
+ token: string;
23
+ orgId?: string;
24
+ email?: string;
25
+ }
26
+ export declare const getConfigDir: () => string;
27
+ export declare const getConfigPath: () => string;
28
+ export declare const profileKey: (baseApiUrl: string, orgSlug: string) => string;
29
+ export declare const readConfig: () => BanatieConfig;
30
+ export declare const writeConfig: (config: BanatieConfig) => void;
31
+ export declare const getProfile: (baseApiUrl: string, orgSlug: string) => Profile | null;
32
+ export declare const upsertProfile: (input: UpsertProfileInput) => Profile;
33
+ export declare const toSafeProfile: (profile: Profile) => SafeProfile;
34
+ export declare const listProfiles: () => SafeProfile[];
35
+ export declare const removeProfile: (baseApiUrl: string, orgSlug: string) => boolean;
36
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAGD,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACpD;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID,eAAO,MAAM,YAAY,QAAO,MACoC,CAAC;AAErE,eAAO,MAAM,aAAa,QAAO,MAAkD,CAAC;AAKpF,eAAO,MAAM,UAAU,GAAI,YAAY,MAAM,EAAE,SAAS,MAAM,KAAG,MACnB,CAAC;AAE/C,eAAO,MAAM,UAAU,QAAO,aAgB7B,CAAC;AAUF,eAAO,MAAM,WAAW,GAAI,QAAQ,aAAa,KAAG,IAQnD,CAAC;AAQF,eAAO,MAAM,UAAU,GAAI,YAAY,MAAM,EAAE,SAAS,MAAM,KAAG,OAAO,GAAG,IAI1E,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,OAAO,kBAAkB,KAAG,OAuBzD,CAAC;AAGF,eAAO,MAAM,aAAa,GAAI,SAAS,OAAO,KAAG,WAGhD,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,WAAW,EAA8C,CAAC;AAE1F,eAAO,MAAM,aAAa,GAAI,YAAY,MAAM,EAAE,SAAS,MAAM,KAAG,OAUnE,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.removeProfile = exports.listProfiles = exports.toSafeProfile = exports.upsertProfile = exports.getProfile = exports.writeConfig = exports.readConfig = exports.profileKey = exports.getConfigPath = exports.getConfigDir = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const os_1 = __importDefault(require("os"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const CONFIG_VERSION = 1;
11
+ const getConfigDir = () => process.env['BANATIE_HOME'] || path_1.default.join(os_1.default.homedir(), '.banatie');
12
+ exports.getConfigDir = getConfigDir;
13
+ const getConfigPath = () => path_1.default.join((0, exports.getConfigDir)(), 'config.json');
14
+ exports.getConfigPath = getConfigPath;
15
+ const normalizeBaseUrl = (baseApiUrl) => baseApiUrl.replace(/\/+$/, '');
16
+ // Profiles are scoped by normalized backend URL + org slug.
17
+ const profileKey = (baseApiUrl, orgSlug) => `${normalizeBaseUrl(baseApiUrl)}|${orgSlug}`;
18
+ exports.profileKey = profileKey;
19
+ const readConfig = () => {
20
+ const configPath = (0, exports.getConfigPath)();
21
+ if (!fs_1.default.existsSync(configPath)) {
22
+ return { version: CONFIG_VERSION, profiles: [] };
23
+ }
24
+ try {
25
+ const parsed = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
26
+ return {
27
+ version: parsed.version ?? CONFIG_VERSION,
28
+ profiles: Array.isArray(parsed.profiles) ? parsed.profiles : [],
29
+ ...(parsed.defaults ? { defaults: parsed.defaults } : {}),
30
+ };
31
+ }
32
+ catch {
33
+ // Corrupt/unreadable config: start fresh rather than crash a command.
34
+ return { version: CONFIG_VERSION, profiles: [] };
35
+ }
36
+ };
37
+ exports.readConfig = readConfig;
38
+ const chmodBestEffort = (target, mode) => {
39
+ try {
40
+ fs_1.default.chmodSync(target, mode);
41
+ }
42
+ catch {
43
+ // Best-effort: some filesystems don't support chmod.
44
+ }
45
+ };
46
+ const writeConfig = (config) => {
47
+ const dir = (0, exports.getConfigDir)();
48
+ fs_1.default.mkdirSync(dir, { recursive: true });
49
+ chmodBestEffort(dir, 0o700);
50
+ const configPath = (0, exports.getConfigPath)();
51
+ fs_1.default.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
52
+ chmodBestEffort(configPath, 0o600);
53
+ };
54
+ exports.writeConfig = writeConfig;
55
+ const findIndexByKey = (config, baseApiUrl, orgSlug) => {
56
+ const key = (0, exports.profileKey)(baseApiUrl, orgSlug);
57
+ return config.profiles.findIndex((p) => (0, exports.profileKey)(p.baseApiUrl, p.orgSlug) === key);
58
+ };
59
+ // Returns the full profile (including the token) for internal command use.
60
+ const getProfile = (baseApiUrl, orgSlug) => {
61
+ const config = (0, exports.readConfig)();
62
+ const index = findIndexByKey(config, baseApiUrl, orgSlug);
63
+ return index >= 0 ? config.profiles[index] : null;
64
+ };
65
+ exports.getProfile = getProfile;
66
+ const upsertProfile = (input) => {
67
+ const config = (0, exports.readConfig)();
68
+ const index = findIndexByKey(config, input.baseApiUrl, input.orgSlug);
69
+ const now = new Date().toISOString();
70
+ const createdAt = index >= 0 ? config.profiles[index].createdAt : now;
71
+ const profile = {
72
+ baseApiUrl: normalizeBaseUrl(input.baseApiUrl),
73
+ orgSlug: input.orgSlug,
74
+ token: input.token,
75
+ createdAt,
76
+ lastUsedAt: now,
77
+ ...(input.orgId ? { orgId: input.orgId } : {}),
78
+ ...(input.email ? { email: input.email } : {}),
79
+ };
80
+ if (index >= 0) {
81
+ config.profiles[index] = profile;
82
+ }
83
+ else {
84
+ config.profiles.push(profile);
85
+ }
86
+ (0, exports.writeConfig)(config);
87
+ return profile;
88
+ };
89
+ exports.upsertProfile = upsertProfile;
90
+ // Strip the token — the only shape safe for display/logging.
91
+ const toSafeProfile = (profile) => {
92
+ const { token: _token, ...safe } = profile;
93
+ return safe;
94
+ };
95
+ exports.toSafeProfile = toSafeProfile;
96
+ const listProfiles = () => (0, exports.readConfig)().profiles.map(exports.toSafeProfile);
97
+ exports.listProfiles = listProfiles;
98
+ const removeProfile = (baseApiUrl, orgSlug) => {
99
+ const config = (0, exports.readConfig)();
100
+ const key = (0, exports.profileKey)(baseApiUrl, orgSlug);
101
+ const remaining = config.profiles.filter((p) => (0, exports.profileKey)(p.baseApiUrl, p.orgSlug) !== key);
102
+ if (remaining.length === config.profiles.length) {
103
+ return false;
104
+ }
105
+ config.profiles = remaining;
106
+ (0, exports.writeConfig)(config);
107
+ return true;
108
+ };
109
+ exports.removeProfile = removeProfile;
@@ -0,0 +1,2 @@
1
+ export declare const promptDeleteConfirmation: (projectSlug: string) => Promise<boolean>;
2
+ //# sourceMappingURL=confirmPrompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirmPrompt.d.ts","sourceRoot":"","sources":["../src/confirmPrompt.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,wBAAwB,GAAI,aAAa,MAAM,KAAG,OAAO,CAAC,OAAO,CAY7E,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.promptDeleteConfirmation = void 0;
7
+ const readline_1 = __importDefault(require("readline"));
8
+ // Interactive destructive-action confirmation: the user must retype the project
9
+ // slug exactly. Node built-in readline only. Returns true only on an exact match.
10
+ const promptDeleteConfirmation = (projectSlug) => {
11
+ const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
12
+ return new Promise((resolve) => {
13
+ rl.question(`This permanently deletes project "${projectSlug}" and all its data.\n` +
14
+ `Type the project slug ("${projectSlug}") to confirm: `, (answer) => {
15
+ rl.close();
16
+ resolve(answer.trim() === projectSlug);
17
+ });
18
+ });
19
+ };
20
+ exports.promptDeleteConfirmation = promptDeleteConfirmation;
@@ -0,0 +1,4 @@
1
+ import type { CommandResult } from './commands/types';
2
+ export declare const USAGE: string;
3
+ export declare const run: (argv: string[]) => Promise<CommandResult>;
4
+ //# sourceMappingURL=dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,eAAO,MAAM,KAAK,QAYN,CAAC;AAkBb,eAAO,MAAM,GAAG,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,aAAa,CAkE/D,CAAC"}
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.run = exports.USAGE = void 0;
4
+ const login_1 = require("./commands/login");
5
+ const status_1 = require("./commands/status");
6
+ const logout_1 = require("./commands/logout");
7
+ const revoke_1 = require("./commands/revoke");
8
+ const rotate_1 = require("./commands/rotate");
9
+ const projectNew_1 = require("./commands/projectNew");
10
+ const projectList_1 = require("./commands/projectList");
11
+ const projectConnect_1 = require("./commands/projectConnect");
12
+ const projectDelete_1 = require("./commands/projectDelete");
13
+ const connectDirect_1 = require("./commands/connectDirect");
14
+ exports.USAGE = [
15
+ 'Usage:',
16
+ ' banatie org <org-slug> login <bnt_boot-token>',
17
+ ' banatie org <org-slug> auth status',
18
+ ' banatie org <org-slug> auth logout',
19
+ ' banatie org <org-slug> auth revoke',
20
+ ' banatie org <org-slug> auth rotate',
21
+ ' banatie org <org-slug> project new <project-slug>',
22
+ ' banatie org <org-slug> project list',
23
+ ' banatie org <org-slug> project connect <project-slug> --project-root <path>',
24
+ ' banatie org <org-slug> project delete <project-slug> [<one-time-token>]',
25
+ ' banatie <project-api-key> connect [--project-root <path>]',
26
+ ].join('\n');
27
+ // Extract the value after --project-root, defaulting to the current directory.
28
+ const parseProjectRoot = (args) => {
29
+ const index = args.indexOf('--project-root');
30
+ if (index >= 0 && args[index + 1]) {
31
+ return args[index + 1];
32
+ }
33
+ return '.';
34
+ };
35
+ const isProjectKeyArg = (value) => typeof value === 'string' &&
36
+ value.startsWith('bnt_') &&
37
+ !value.startsWith('bnt_org_') &&
38
+ !value.startsWith('bnt_boot_');
39
+ // Pure argv dispatcher (no process side effects) so it can be unit-tested.
40
+ const run = async (argv) => {
41
+ const [group, orgSlug, sub, ...rest] = argv;
42
+ // Direct connect: `banatie <project-api-key> connect [--project-root <path>]`
43
+ if (argv[1] === 'connect' && isProjectKeyArg(argv[0])) {
44
+ return (0, connectDirect_1.connectDirectCommand)(argv[0], parseProjectRoot(argv.slice(2)));
45
+ }
46
+ if (group !== 'org' || !orgSlug || !sub) {
47
+ return { exitCode: 1, lines: [exports.USAGE] };
48
+ }
49
+ if (sub === 'login') {
50
+ const bootToken = rest[0];
51
+ if (!bootToken) {
52
+ return { exitCode: 1, lines: ['Missing login token.', exports.USAGE] };
53
+ }
54
+ return (0, login_1.loginCommand)(orgSlug, bootToken);
55
+ }
56
+ if (sub === 'auth') {
57
+ const action = rest[0];
58
+ if (action === 'status') {
59
+ return (0, status_1.statusCommand)(orgSlug);
60
+ }
61
+ if (action === 'logout') {
62
+ return (0, logout_1.logoutCommand)(orgSlug);
63
+ }
64
+ if (action === 'revoke') {
65
+ return (0, revoke_1.revokeCommand)(orgSlug);
66
+ }
67
+ if (action === 'rotate') {
68
+ return (0, rotate_1.rotateCommand)(orgSlug);
69
+ }
70
+ return { exitCode: 1, lines: [`Unknown auth command: ${action ?? '(none)'}`, exports.USAGE] };
71
+ }
72
+ if (sub === 'project') {
73
+ const action = rest[0];
74
+ const projectSlug = rest[1];
75
+ if (action === 'new' && projectSlug) {
76
+ return (0, projectNew_1.projectNewCommand)(orgSlug, projectSlug);
77
+ }
78
+ if (action === 'list') {
79
+ return (0, projectList_1.projectListCommand)(orgSlug);
80
+ }
81
+ if (action === 'connect' && projectSlug) {
82
+ return (0, projectConnect_1.projectConnectCommand)(orgSlug, projectSlug, parseProjectRoot(rest.slice(2)));
83
+ }
84
+ if (action === 'delete' && projectSlug) {
85
+ return (0, projectDelete_1.projectDeleteCommand)(orgSlug, projectSlug, rest[2]);
86
+ }
87
+ return {
88
+ exitCode: 1,
89
+ lines: [
90
+ 'Usage:',
91
+ ' banatie org <org-slug> project new <project-slug>',
92
+ ' banatie org <org-slug> project list',
93
+ ' banatie org <org-slug> project connect <project-slug> --project-root <path>',
94
+ ' banatie org <org-slug> project delete <project-slug> [<one-time-token>]',
95
+ exports.USAGE,
96
+ ],
97
+ };
98
+ }
99
+ return { exitCode: 1, lines: [`Unknown command: ${sub}`, exports.USAGE] };
100
+ };
101
+ exports.run = run;
@@ -0,0 +1,19 @@
1
+ export * from './config';
2
+ export * from './apiClient';
3
+ export * from './baseUrl';
4
+ export * from './preview';
5
+ export * from './dispatch';
6
+ export * from './commands/login';
7
+ export * from './commands/status';
8
+ export * from './commands/logout';
9
+ export * from './commands/revoke';
10
+ export * from './commands/rotate';
11
+ export * from './commands/projectNew';
12
+ export * from './commands/projectList';
13
+ export * from './commands/projectConnect';
14
+ export * from './commands/projectDelete';
15
+ export * from './confirmPrompt';
16
+ export * from './commands/connectDirect';
17
+ export * from './projectConfig';
18
+ export * from './commands/types';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./config"), exports);
18
+ __exportStar(require("./apiClient"), exports);
19
+ __exportStar(require("./baseUrl"), exports);
20
+ __exportStar(require("./preview"), exports);
21
+ __exportStar(require("./dispatch"), exports);
22
+ __exportStar(require("./commands/login"), exports);
23
+ __exportStar(require("./commands/status"), exports);
24
+ __exportStar(require("./commands/logout"), exports);
25
+ __exportStar(require("./commands/revoke"), exports);
26
+ __exportStar(require("./commands/rotate"), exports);
27
+ __exportStar(require("./commands/projectNew"), exports);
28
+ __exportStar(require("./commands/projectList"), exports);
29
+ __exportStar(require("./commands/projectConnect"), exports);
30
+ __exportStar(require("./commands/projectDelete"), exports);
31
+ __exportStar(require("./confirmPrompt"), exports);
32
+ __exportStar(require("./commands/connectDirect"), exports);
33
+ __exportStar(require("./projectConfig"), exports);
34
+ __exportStar(require("./commands/types"), exports);
@@ -0,0 +1,2 @@
1
+ export declare const previewToken: (token: string) => string;
2
+ //# sourceMappingURL=preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,KAAG,MAG5C,CAAC"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.previewToken = void 0;
4
+ // Build a non-secret display preview of a token (never the full value).
5
+ const previewToken = (token) => {
6
+ const prefix = token.startsWith('bnt_org_') ? 'bnt_org_' : token.slice(0, 4);
7
+ return `${prefix}...${token.slice(-6)}`;
8
+ };
9
+ exports.previewToken = previewToken;