@eide/foir-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 (91) hide show
  1. package/dist/auth/credentials.d.ts +29 -0
  2. package/dist/auth/credentials.d.ts.map +1 -0
  3. package/dist/auth/credentials.js +79 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +74 -0
  7. package/dist/commands/api-keys.d.ts +4 -0
  8. package/dist/commands/api-keys.d.ts.map +1 -0
  9. package/dist/commands/api-keys.js +127 -0
  10. package/dist/commands/context.d.ts +4 -0
  11. package/dist/commands/context.d.ts.map +1 -0
  12. package/dist/commands/context.js +92 -0
  13. package/dist/commands/customers.d.ts +4 -0
  14. package/dist/commands/customers.d.ts.map +1 -0
  15. package/dist/commands/customers.js +120 -0
  16. package/dist/commands/experiments.d.ts +4 -0
  17. package/dist/commands/experiments.d.ts.map +1 -0
  18. package/dist/commands/experiments.js +177 -0
  19. package/dist/commands/extensions.d.ts +4 -0
  20. package/dist/commands/extensions.d.ts.map +1 -0
  21. package/dist/commands/extensions.js +94 -0
  22. package/dist/commands/files.d.ts +4 -0
  23. package/dist/commands/files.d.ts.map +1 -0
  24. package/dist/commands/files.js +143 -0
  25. package/dist/commands/locales.d.ts +4 -0
  26. package/dist/commands/locales.d.ts.map +1 -0
  27. package/dist/commands/locales.js +126 -0
  28. package/dist/commands/login.d.ts +4 -0
  29. package/dist/commands/login.d.ts.map +1 -0
  30. package/dist/commands/login.js +125 -0
  31. package/dist/commands/logout.d.ts +4 -0
  32. package/dist/commands/logout.d.ts.map +1 -0
  33. package/dist/commands/logout.js +16 -0
  34. package/dist/commands/media.d.ts +4 -0
  35. package/dist/commands/media.d.ts.map +1 -0
  36. package/dist/commands/media.js +44 -0
  37. package/dist/commands/models.d.ts +4 -0
  38. package/dist/commands/models.d.ts.map +1 -0
  39. package/dist/commands/models.js +155 -0
  40. package/dist/commands/notes.d.ts +4 -0
  41. package/dist/commands/notes.d.ts.map +1 -0
  42. package/dist/commands/notes.js +120 -0
  43. package/dist/commands/notifications.d.ts +4 -0
  44. package/dist/commands/notifications.d.ts.map +1 -0
  45. package/dist/commands/notifications.js +73 -0
  46. package/dist/commands/operations.d.ts +4 -0
  47. package/dist/commands/operations.d.ts.map +1 -0
  48. package/dist/commands/operations.js +161 -0
  49. package/dist/commands/records.d.ts +4 -0
  50. package/dist/commands/records.d.ts.map +1 -0
  51. package/dist/commands/records.js +216 -0
  52. package/dist/commands/schedules.d.ts +4 -0
  53. package/dist/commands/schedules.d.ts.map +1 -0
  54. package/dist/commands/schedules.js +150 -0
  55. package/dist/commands/search.d.ts +4 -0
  56. package/dist/commands/search.d.ts.map +1 -0
  57. package/dist/commands/search.js +60 -0
  58. package/dist/commands/segments.d.ts +4 -0
  59. package/dist/commands/segments.d.ts.map +1 -0
  60. package/dist/commands/segments.js +143 -0
  61. package/dist/commands/select-project.d.ts +4 -0
  62. package/dist/commands/select-project.d.ts.map +1 -0
  63. package/dist/commands/select-project.js +144 -0
  64. package/dist/commands/settings.d.ts +4 -0
  65. package/dist/commands/settings.d.ts.map +1 -0
  66. package/dist/commands/settings.js +113 -0
  67. package/dist/commands/variant-catalog.d.ts +4 -0
  68. package/dist/commands/variant-catalog.d.ts.map +1 -0
  69. package/dist/commands/variant-catalog.js +111 -0
  70. package/dist/commands/whoami.d.ts +4 -0
  71. package/dist/commands/whoami.d.ts.map +1 -0
  72. package/dist/commands/whoami.js +50 -0
  73. package/dist/graphql/queries.d.ts +101 -0
  74. package/dist/graphql/queries.d.ts.map +1 -0
  75. package/dist/graphql/queries.js +373 -0
  76. package/dist/lib/client.d.ts +17 -0
  77. package/dist/lib/client.d.ts.map +1 -0
  78. package/dist/lib/client.js +61 -0
  79. package/dist/lib/config.d.ts +12 -0
  80. package/dist/lib/config.d.ts.map +1 -0
  81. package/dist/lib/config.js +8 -0
  82. package/dist/lib/errors.d.ts +6 -0
  83. package/dist/lib/errors.d.ts.map +1 -0
  84. package/dist/lib/errors.js +62 -0
  85. package/dist/lib/input.d.ts +36 -0
  86. package/dist/lib/input.d.ts.map +1 -0
  87. package/dist/lib/input.js +106 -0
  88. package/dist/lib/output.d.ts +31 -0
  89. package/dist/lib/output.d.ts.map +1 -0
  90. package/dist/lib/output.js +107 -0
  91. package/package.json +59 -0
@@ -0,0 +1,177 @@
1
+ import { withErrorHandler } from '../lib/errors.js';
2
+ import { createClient } from '../lib/client.js';
3
+ import { formatOutput, formatList, timeAgo, success } from '../lib/output.js';
4
+ import { parseInputData, isUUID, confirmAction } from '../lib/input.js';
5
+ import { EXPERIMENTS, EXPERIMENT, EXPERIMENT_BY_KEY, CREATE_EXPERIMENT, UPDATE_EXPERIMENT, DELETE_EXPERIMENT, START_EXPERIMENT, PAUSE_EXPERIMENT, RESUME_EXPERIMENT, END_EXPERIMENT, EXPERIMENT_STATS, } from '../graphql/queries.js';
6
+ export function registerExperimentsCommands(program, globalOpts) {
7
+ const experiments = program
8
+ .command('experiments')
9
+ .description('Manage experiments');
10
+ // list
11
+ experiments
12
+ .command('list')
13
+ .description('List experiments')
14
+ .option('--status <status>', 'Filter by status')
15
+ .option('--active', 'Only active experiments')
16
+ .option('--limit <n>', 'Max results', '50')
17
+ .option('--offset <n>', 'Skip results', '0')
18
+ .action(withErrorHandler(globalOpts, async (cmdOpts) => {
19
+ const opts = globalOpts();
20
+ const client = await createClient(opts);
21
+ const data = await client.request(EXPERIMENTS, {
22
+ status: cmdOpts.status,
23
+ isActive: cmdOpts.active ? true : undefined,
24
+ limit: parseInt(String(cmdOpts.limit ?? '50'), 10),
25
+ offset: parseInt(String(cmdOpts.offset ?? '0'), 10),
26
+ });
27
+ formatList(data.experiments, opts, {
28
+ columns: [
29
+ { key: 'id', header: 'ID', width: 28 },
30
+ { key: 'key', header: 'Key', width: 20 },
31
+ { key: 'name', header: 'Name', width: 24 },
32
+ { key: 'status', header: 'Status', width: 12 },
33
+ {
34
+ key: 'isActive',
35
+ header: 'Active',
36
+ width: 8,
37
+ format: (v) => (v ? 'yes' : 'no'),
38
+ },
39
+ {
40
+ key: 'updatedAt',
41
+ header: 'Updated',
42
+ width: 12,
43
+ format: (v) => timeAgo(v),
44
+ },
45
+ ],
46
+ });
47
+ }));
48
+ // get
49
+ experiments
50
+ .command('get <idOrKey>')
51
+ .description('Get an experiment by ID or key')
52
+ .action(withErrorHandler(globalOpts, async (idOrKey) => {
53
+ const opts = globalOpts();
54
+ const client = await createClient(opts);
55
+ let result;
56
+ if (isUUID(idOrKey)) {
57
+ const data = await client.request(EXPERIMENT, { id: idOrKey });
58
+ result = data.experiment;
59
+ }
60
+ else {
61
+ const data = await client.request(EXPERIMENT_BY_KEY, { key: idOrKey });
62
+ result = data.experimentByKey;
63
+ }
64
+ if (!result)
65
+ throw new Error(`Experiment "${idOrKey}" not found.`);
66
+ formatOutput(result, opts);
67
+ }));
68
+ // create
69
+ experiments
70
+ .command('create')
71
+ .description('Create a new experiment')
72
+ .option('-d, --data <json>', 'Experiment data as JSON')
73
+ .option('-f, --file <path>', 'Read data from file')
74
+ .action(withErrorHandler(globalOpts, async (cmdOpts) => {
75
+ const opts = globalOpts();
76
+ const client = await createClient(opts);
77
+ const input = await parseInputData(cmdOpts);
78
+ const data = await client.request(CREATE_EXPERIMENT, { input });
79
+ formatOutput(data.createExperiment, opts);
80
+ if (!(opts.json || opts.jsonl || opts.quiet))
81
+ success(`Created experiment ${data.createExperiment.key}`);
82
+ }));
83
+ // update
84
+ experiments
85
+ .command('update <id>')
86
+ .description('Update an experiment')
87
+ .option('-d, --data <json>', 'Experiment data as JSON')
88
+ .option('-f, --file <path>', 'Read data from file')
89
+ .action(withErrorHandler(globalOpts, async (id, cmdOpts) => {
90
+ const opts = globalOpts();
91
+ const client = await createClient(opts);
92
+ const input = await parseInputData(cmdOpts);
93
+ const data = await client.request(UPDATE_EXPERIMENT, { id, input });
94
+ formatOutput(data.updateExperiment, opts);
95
+ if (!(opts.json || opts.jsonl || opts.quiet))
96
+ success(`Updated experiment ${id}`);
97
+ }));
98
+ // delete
99
+ experiments
100
+ .command('delete <id>')
101
+ .description('Delete an experiment')
102
+ .option('--confirm', 'Skip confirmation prompt')
103
+ .action(withErrorHandler(globalOpts, async (id, cmdOpts) => {
104
+ const opts = globalOpts();
105
+ const confirmed = await confirmAction(`Delete experiment ${id}?`, {
106
+ confirm: !!cmdOpts.confirm,
107
+ });
108
+ if (!confirmed) {
109
+ console.log('Aborted.');
110
+ return;
111
+ }
112
+ const client = await createClient(opts);
113
+ await client.request(DELETE_EXPERIMENT, { id });
114
+ if (opts.json || opts.jsonl)
115
+ formatOutput({ deleted: true, id }, opts);
116
+ else
117
+ success(`Deleted experiment ${id}`);
118
+ }));
119
+ // start
120
+ experiments
121
+ .command('start <id>')
122
+ .description('Start an experiment')
123
+ .action(withErrorHandler(globalOpts, async (id) => {
124
+ const opts = globalOpts();
125
+ const client = await createClient(opts);
126
+ const data = await client.request(START_EXPERIMENT, { experimentId: id });
127
+ formatOutput(data.startExperiment, opts);
128
+ if (!(opts.json || opts.jsonl || opts.quiet))
129
+ success('Experiment started');
130
+ }));
131
+ // pause
132
+ experiments
133
+ .command('pause <id>')
134
+ .description('Pause a running experiment')
135
+ .action(withErrorHandler(globalOpts, async (id) => {
136
+ const opts = globalOpts();
137
+ const client = await createClient(opts);
138
+ const data = await client.request(PAUSE_EXPERIMENT, { experimentId: id });
139
+ formatOutput(data.pauseExperiment, opts);
140
+ if (!(opts.json || opts.jsonl || opts.quiet))
141
+ success('Experiment paused');
142
+ }));
143
+ // resume
144
+ experiments
145
+ .command('resume <id>')
146
+ .description('Resume a paused experiment')
147
+ .action(withErrorHandler(globalOpts, async (id) => {
148
+ const opts = globalOpts();
149
+ const client = await createClient(opts);
150
+ const data = await client.request(RESUME_EXPERIMENT, { experimentId: id });
151
+ formatOutput(data.resumeExperiment, opts);
152
+ if (!(opts.json || opts.jsonl || opts.quiet))
153
+ success('Experiment resumed');
154
+ }));
155
+ // end
156
+ experiments
157
+ .command('end <id>')
158
+ .description('End an experiment')
159
+ .action(withErrorHandler(globalOpts, async (id) => {
160
+ const opts = globalOpts();
161
+ const client = await createClient(opts);
162
+ const data = await client.request(END_EXPERIMENT, { experimentId: id });
163
+ formatOutput(data.endExperiment, opts);
164
+ if (!(opts.json || opts.jsonl || opts.quiet))
165
+ success('Experiment ended');
166
+ }));
167
+ // stats
168
+ experiments
169
+ .command('stats <id>')
170
+ .description('Get experiment statistics')
171
+ .action(withErrorHandler(globalOpts, async (id) => {
172
+ const opts = globalOpts();
173
+ const client = await createClient(opts);
174
+ const data = await client.request(EXPERIMENT_STATS, { experimentId: id });
175
+ formatOutput(data.experimentStats, opts);
176
+ }));
177
+ }
@@ -0,0 +1,4 @@
1
+ import type { Command } from 'commander';
2
+ import type { GlobalOptions } from '../lib/config.js';
3
+ export declare function registerExtensionsCommands(program: Command, globalOpts: () => GlobalOptions): void;
4
+ //# sourceMappingURL=extensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../../src/commands/extensions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAatD,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,aAAa,GAC9B,IAAI,CA8GN"}
@@ -0,0 +1,94 @@
1
+ import { withErrorHandler } from '../lib/errors.js';
2
+ import { createClient } from '../lib/client.js';
3
+ import { formatOutput, formatList, success } from '../lib/output.js';
4
+ import { parseInputData, isUUID } from '../lib/input.js';
5
+ import { EXTENSIONS, EXTENSION, EXTENSION_BY_KEY, REGISTER_EXTENSION, TRIGGER_EXTENSION_SYNC, } from '../graphql/queries.js';
6
+ export function registerExtensionsCommands(program, globalOpts) {
7
+ const extensions = program
8
+ .command('extensions')
9
+ .description('Manage extensions');
10
+ // list
11
+ extensions
12
+ .command('list')
13
+ .description('List extensions')
14
+ .option('--type <type>', 'Filter by extension type')
15
+ .option('--enabled', 'Only enabled extensions')
16
+ .option('--limit <n>', 'Max results', '50')
17
+ .action(withErrorHandler(globalOpts, async (cmdOpts) => {
18
+ const opts = globalOpts();
19
+ const client = await createClient(opts);
20
+ const data = await client.request(EXTENSIONS, {
21
+ extensionType: cmdOpts.type,
22
+ enabled: cmdOpts.enabled ? true : undefined,
23
+ limit: parseInt(String(cmdOpts.limit ?? '50'), 10),
24
+ });
25
+ formatList(data.extensions, opts, {
26
+ columns: [
27
+ { key: 'id', header: 'ID', width: 28 },
28
+ { key: 'key', header: 'Key', width: 20 },
29
+ { key: 'name', header: 'Name', width: 24 },
30
+ { key: 'extensionType', header: 'Type', width: 14 },
31
+ {
32
+ key: 'enabled',
33
+ header: 'Enabled',
34
+ width: 8,
35
+ format: (v) => (v ? 'yes' : 'no'),
36
+ },
37
+ { key: 'syncStatus', header: 'Sync', width: 10 },
38
+ ],
39
+ });
40
+ }));
41
+ // get
42
+ extensions
43
+ .command('get <idOrKey>')
44
+ .description('Get an extension by ID or key')
45
+ .action(withErrorHandler(globalOpts, async (idOrKey) => {
46
+ const opts = globalOpts();
47
+ const client = await createClient(opts);
48
+ let result;
49
+ if (isUUID(idOrKey)) {
50
+ const data = await client.request(EXTENSION, { id: idOrKey });
51
+ result = data.extension;
52
+ }
53
+ else {
54
+ const data = await client.request(EXTENSION_BY_KEY, { key: idOrKey });
55
+ result = data.extensionByKey;
56
+ }
57
+ if (!result)
58
+ throw new Error(`Extension "${idOrKey}" not found.`);
59
+ formatOutput(result, opts);
60
+ }));
61
+ // register
62
+ extensions
63
+ .command('register')
64
+ .description('Register a new extension')
65
+ .option('-d, --data <json>', 'Extension data as JSON')
66
+ .option('-f, --file <path>', 'Read data from file')
67
+ .action(withErrorHandler(globalOpts, async (cmdOpts) => {
68
+ const opts = globalOpts();
69
+ const client = await createClient(opts);
70
+ const input = await parseInputData(cmdOpts);
71
+ const data = await client.request(REGISTER_EXTENSION, { input });
72
+ formatOutput(data.registerExtension, opts);
73
+ if (!(opts.json || opts.jsonl || opts.quiet))
74
+ success(`Registered extension ${data.registerExtension.key}`);
75
+ }));
76
+ // sync
77
+ extensions
78
+ .command('sync <id>')
79
+ .description('Trigger data sync for an extension')
80
+ .action(withErrorHandler(globalOpts, async (id) => {
81
+ const opts = globalOpts();
82
+ const client = await createClient(opts);
83
+ const data = await client.request(TRIGGER_EXTENSION_SYNC, { extensionId: id });
84
+ if (opts.json || opts.jsonl) {
85
+ formatOutput(data.triggerExtensionSync, opts);
86
+ }
87
+ else if (data.triggerExtensionSync.success) {
88
+ success('Extension sync triggered');
89
+ }
90
+ else {
91
+ throw new Error(data.triggerExtensionSync.error ?? 'Sync failed');
92
+ }
93
+ }));
94
+ }
@@ -0,0 +1,4 @@
1
+ import type { Command } from 'commander';
2
+ import type { GlobalOptions } from '../lib/config.js';
3
+ export declare function registerFilesCommands(program: Command, globalOpts: () => GlobalOptions): void;
4
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/commands/files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AActD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,aAAa,GAC9B,IAAI,CAoKN"}
@@ -0,0 +1,143 @@
1
+ import { withErrorHandler } from '../lib/errors.js';
2
+ import { createClient } from '../lib/client.js';
3
+ import { formatOutput, formatList, timeAgo, success } from '../lib/output.js';
4
+ import { confirmAction } from '../lib/input.js';
5
+ import { FILES, FILE, FILE_STORAGE_USAGE, UPDATE_FILE, UPDATE_FILE_METADATA, DELETE_FILE, } from '../graphql/queries.js';
6
+ export function registerFilesCommands(program, globalOpts) {
7
+ const files = program
8
+ .command('files')
9
+ .description('Manage files (for upload, use `foir media upload`)');
10
+ // list
11
+ files
12
+ .command('list')
13
+ .description('List files')
14
+ .option('--folder <folder>', 'Filter by folder')
15
+ .option('--mime-type <type>', 'Filter by MIME type')
16
+ .option('--search <term>', 'Search by filename')
17
+ .option('--limit <n>', 'Max results', '50')
18
+ .option('--offset <n>', 'Skip results', '0')
19
+ .action(withErrorHandler(globalOpts, async (cmdOpts) => {
20
+ const opts = globalOpts();
21
+ const client = await createClient(opts);
22
+ const data = await client.request(FILES, {
23
+ folder: cmdOpts.folder,
24
+ mimeType: cmdOpts.mimeType,
25
+ search: cmdOpts.search,
26
+ limit: parseInt(cmdOpts.limit ?? '50', 10),
27
+ offset: parseInt(cmdOpts.offset ?? '0', 10),
28
+ });
29
+ formatList(data.files.items, opts, {
30
+ columns: [
31
+ { key: 'id', header: 'ID', width: 28 },
32
+ { key: 'filename', header: 'Filename', width: 30 },
33
+ { key: 'mimeType', header: 'Type', width: 16 },
34
+ {
35
+ key: 'size',
36
+ header: 'Size',
37
+ width: 10,
38
+ format: (v) => formatBytes(v),
39
+ },
40
+ { key: 'folder', header: 'Folder', width: 14 },
41
+ {
42
+ key: 'createdAt',
43
+ header: 'Created',
44
+ width: 12,
45
+ format: (v) => timeAgo(v),
46
+ },
47
+ ],
48
+ total: data.files.total,
49
+ });
50
+ }));
51
+ // get
52
+ files
53
+ .command('get <id>')
54
+ .description('Get a file by ID')
55
+ .action(withErrorHandler(globalOpts, async (id) => {
56
+ const opts = globalOpts();
57
+ const client = await createClient(opts);
58
+ const data = await client.request(FILE, { id });
59
+ if (!data.file)
60
+ throw new Error(`File "${id}" not found.`);
61
+ formatOutput(data.file, opts);
62
+ }));
63
+ // usage
64
+ files
65
+ .command('usage')
66
+ .description('Get storage usage statistics')
67
+ .action(withErrorHandler(globalOpts, async () => {
68
+ const opts = globalOpts();
69
+ const client = await createClient(opts);
70
+ const data = await client.request(FILE_STORAGE_USAGE);
71
+ formatOutput(data.fileStorageUsage, opts);
72
+ }));
73
+ // update
74
+ files
75
+ .command('update <id>')
76
+ .description('Update file properties')
77
+ .option('--filename <name>', 'New filename')
78
+ .option('--folder <folder>', 'Move to folder')
79
+ .option('--tags <tags>', 'Comma-separated tags')
80
+ .action(withErrorHandler(globalOpts, async (id, cmdOpts) => {
81
+ const opts = globalOpts();
82
+ const client = await createClient(opts);
83
+ const vars = { id };
84
+ if (cmdOpts.filename)
85
+ vars.filename = cmdOpts.filename;
86
+ if (cmdOpts.folder)
87
+ vars.folder = cmdOpts.folder;
88
+ if (cmdOpts.tags)
89
+ vars.tags = cmdOpts.tags.split(',').map((t) => t.trim());
90
+ const data = await client.request(UPDATE_FILE, vars);
91
+ formatOutput(data.updateFile, opts);
92
+ if (!(opts.json || opts.jsonl || opts.quiet))
93
+ success(`Updated file ${id}`);
94
+ }));
95
+ // update-metadata
96
+ files
97
+ .command('update-metadata <id>')
98
+ .description('Update file metadata (alt text, caption, description)')
99
+ .option('--alt-text <text>', 'Alt text')
100
+ .option('--caption <text>', 'Caption')
101
+ .option('--description <text>', 'Description')
102
+ .action(withErrorHandler(globalOpts, async (id, cmdOpts) => {
103
+ const opts = globalOpts();
104
+ const client = await createClient(opts);
105
+ const data = await client.request(UPDATE_FILE_METADATA, {
106
+ id,
107
+ altText: cmdOpts.altText,
108
+ caption: cmdOpts.caption,
109
+ description: cmdOpts.description,
110
+ });
111
+ formatOutput(data.updateFileMetadata, opts);
112
+ if (!(opts.json || opts.jsonl || opts.quiet))
113
+ success(`Updated metadata for file ${id}`);
114
+ }));
115
+ // delete
116
+ files
117
+ .command('delete <id>')
118
+ .description('Delete a file')
119
+ .option('--confirm', 'Skip confirmation prompt')
120
+ .action(withErrorHandler(globalOpts, async (id, cmdOpts) => {
121
+ const opts = globalOpts();
122
+ const confirmed = await confirmAction(`Delete file ${id}?`, {
123
+ confirm: !!cmdOpts.confirm,
124
+ });
125
+ if (!confirmed) {
126
+ console.log('Aborted.');
127
+ return;
128
+ }
129
+ const client = await createClient(opts);
130
+ await client.request(DELETE_FILE, { id });
131
+ if (opts.json || opts.jsonl)
132
+ formatOutput({ deleted: true, id }, opts);
133
+ else
134
+ success(`Deleted file ${id}`);
135
+ }));
136
+ }
137
+ function formatBytes(bytes) {
138
+ if (!bytes || bytes === 0)
139
+ return '0 B';
140
+ const units = ['B', 'KB', 'MB', 'GB'];
141
+ const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
142
+ return `${(bytes / Math.pow(1024, i)).toFixed(i === 0 ? 0 : 1)} ${units[i]}`;
143
+ }
@@ -0,0 +1,4 @@
1
+ import type { Command } from 'commander';
2
+ import type { GlobalOptions } from '../lib/config.js';
3
+ export declare function registerLocalesCommands(program: Command, globalOpts: () => GlobalOptions): void;
4
+ //# sourceMappingURL=locales.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../src/commands/locales.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAetD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,aAAa,GAC9B,IAAI,CA4JN"}
@@ -0,0 +1,126 @@
1
+ import { withErrorHandler } from '../lib/errors.js';
2
+ import { createClient } from '../lib/client.js';
3
+ import { formatOutput, formatList, success } from '../lib/output.js';
4
+ import { parseInputData, confirmAction } from '../lib/input.js';
5
+ import { LOCALES, LOCALE, LOCALE_BY_CODE, DEFAULT_LOCALE, CREATE_LOCALE, UPDATE_LOCALE, DELETE_LOCALE, } from '../graphql/queries.js';
6
+ export function registerLocalesCommands(program, globalOpts) {
7
+ const locales = program.command('locales').description('Manage locales');
8
+ // list
9
+ locales
10
+ .command('list')
11
+ .description('List locales')
12
+ .option('--include-inactive', 'Include inactive locales')
13
+ .option('--limit <n>', 'Max results', '50')
14
+ .action(withErrorHandler(globalOpts, async (cmdOpts) => {
15
+ const opts = globalOpts();
16
+ const client = await createClient(opts);
17
+ const data = await client.request(LOCALES, {
18
+ includeInactive: !!cmdOpts.includeInactive,
19
+ limit: parseInt(String(cmdOpts.limit ?? '50'), 10),
20
+ });
21
+ formatList(data.locales, opts, {
22
+ columns: [
23
+ { key: 'code', header: 'Code', width: 8 },
24
+ { key: 'name', header: 'Name', width: 20 },
25
+ { key: 'nativeName', header: 'Native', width: 20 },
26
+ {
27
+ key: 'isDefault',
28
+ header: 'Default',
29
+ width: 8,
30
+ format: (v) => (v ? 'yes' : ''),
31
+ },
32
+ {
33
+ key: 'isActive',
34
+ header: 'Active',
35
+ width: 8,
36
+ format: (v) => (v ? 'yes' : 'no'),
37
+ },
38
+ { key: 'direction', header: 'Dir', width: 4 },
39
+ ],
40
+ });
41
+ }));
42
+ // get
43
+ locales
44
+ .command('get <idOrCode>')
45
+ .description('Get a locale by ID or code')
46
+ .action(withErrorHandler(globalOpts, async (idOrCode) => {
47
+ const opts = globalOpts();
48
+ const client = await createClient(opts);
49
+ let result;
50
+ // Locale codes are short (e.g. "en", "en-US") — not UUIDs
51
+ if (/^[0-9a-f]{8}-/.test(idOrCode)) {
52
+ const data = await client.request(LOCALE, { id: idOrCode });
53
+ result = data.locale;
54
+ }
55
+ else {
56
+ const data = await client.request(LOCALE_BY_CODE, { code: idOrCode });
57
+ result = data.localeByCode;
58
+ }
59
+ if (!result)
60
+ throw new Error(`Locale "${idOrCode}" not found.`);
61
+ formatOutput(result, opts);
62
+ }));
63
+ // default
64
+ locales
65
+ .command('default')
66
+ .description('Get the default locale')
67
+ .action(withErrorHandler(globalOpts, async () => {
68
+ const opts = globalOpts();
69
+ const client = await createClient(opts);
70
+ const data = await client.request(DEFAULT_LOCALE);
71
+ if (!data.defaultLocale)
72
+ throw new Error('No default locale configured.');
73
+ formatOutput(data.defaultLocale, opts);
74
+ }));
75
+ // create
76
+ locales
77
+ .command('create')
78
+ .description('Create a new locale')
79
+ .option('-d, --data <json>', 'Locale data as JSON')
80
+ .option('-f, --file <path>', 'Read data from file')
81
+ .action(withErrorHandler(globalOpts, async (cmdOpts) => {
82
+ const opts = globalOpts();
83
+ const client = await createClient(opts);
84
+ const input = await parseInputData(cmdOpts);
85
+ const data = await client.request(CREATE_LOCALE, { input });
86
+ formatOutput(data.createLocale, opts);
87
+ if (!(opts.json || opts.jsonl || opts.quiet))
88
+ success(`Created locale ${data.createLocale.code}`);
89
+ }));
90
+ // update
91
+ locales
92
+ .command('update <id>')
93
+ .description('Update a locale')
94
+ .option('-d, --data <json>', 'Locale data as JSON')
95
+ .option('-f, --file <path>', 'Read data from file')
96
+ .action(withErrorHandler(globalOpts, async (id, cmdOpts) => {
97
+ const opts = globalOpts();
98
+ const client = await createClient(opts);
99
+ const input = await parseInputData(cmdOpts);
100
+ const data = await client.request(UPDATE_LOCALE, { id, input });
101
+ formatOutput(data.updateLocale, opts);
102
+ if (!(opts.json || opts.jsonl || opts.quiet))
103
+ success(`Updated locale ${data.updateLocale.code}`);
104
+ }));
105
+ // delete
106
+ locales
107
+ .command('delete <id>')
108
+ .description('Delete a locale')
109
+ .option('--confirm', 'Skip confirmation prompt')
110
+ .action(withErrorHandler(globalOpts, async (id, cmdOpts) => {
111
+ const opts = globalOpts();
112
+ const confirmed = await confirmAction(`Delete locale ${id}?`, {
113
+ confirm: !!cmdOpts.confirm,
114
+ });
115
+ if (!confirmed) {
116
+ console.log('Aborted.');
117
+ return;
118
+ }
119
+ const client = await createClient(opts);
120
+ await client.request(DELETE_LOCALE, { id });
121
+ if (opts.json || opts.jsonl)
122
+ formatOutput({ deleted: true, id }, opts);
123
+ else
124
+ success(`Deleted locale ${id}`);
125
+ }));
126
+ }
@@ -0,0 +1,4 @@
1
+ import type { Command } from 'commander';
2
+ import { type GlobalOptions } from '../lib/config.js';
3
+ export declare function registerLoginCommand(program: Command, globalOpts: () => GlobalOptions): void;
4
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AA4KjE,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,aAAa,GAC9B,IAAI,CASN"}