@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.
- package/dist/auth/credentials.d.ts +29 -0
- package/dist/auth/credentials.d.ts.map +1 -0
- package/dist/auth/credentials.js +79 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +74 -0
- package/dist/commands/api-keys.d.ts +4 -0
- package/dist/commands/api-keys.d.ts.map +1 -0
- package/dist/commands/api-keys.js +127 -0
- package/dist/commands/context.d.ts +4 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +92 -0
- package/dist/commands/customers.d.ts +4 -0
- package/dist/commands/customers.d.ts.map +1 -0
- package/dist/commands/customers.js +120 -0
- package/dist/commands/experiments.d.ts +4 -0
- package/dist/commands/experiments.d.ts.map +1 -0
- package/dist/commands/experiments.js +177 -0
- package/dist/commands/extensions.d.ts +4 -0
- package/dist/commands/extensions.d.ts.map +1 -0
- package/dist/commands/extensions.js +94 -0
- package/dist/commands/files.d.ts +4 -0
- package/dist/commands/files.d.ts.map +1 -0
- package/dist/commands/files.js +143 -0
- package/dist/commands/locales.d.ts +4 -0
- package/dist/commands/locales.d.ts.map +1 -0
- package/dist/commands/locales.js +126 -0
- package/dist/commands/login.d.ts +4 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +125 -0
- package/dist/commands/logout.d.ts +4 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +16 -0
- package/dist/commands/media.d.ts +4 -0
- package/dist/commands/media.d.ts.map +1 -0
- package/dist/commands/media.js +44 -0
- package/dist/commands/models.d.ts +4 -0
- package/dist/commands/models.d.ts.map +1 -0
- package/dist/commands/models.js +155 -0
- package/dist/commands/notes.d.ts +4 -0
- package/dist/commands/notes.d.ts.map +1 -0
- package/dist/commands/notes.js +120 -0
- package/dist/commands/notifications.d.ts +4 -0
- package/dist/commands/notifications.d.ts.map +1 -0
- package/dist/commands/notifications.js +73 -0
- package/dist/commands/operations.d.ts +4 -0
- package/dist/commands/operations.d.ts.map +1 -0
- package/dist/commands/operations.js +161 -0
- package/dist/commands/records.d.ts +4 -0
- package/dist/commands/records.d.ts.map +1 -0
- package/dist/commands/records.js +216 -0
- package/dist/commands/schedules.d.ts +4 -0
- package/dist/commands/schedules.d.ts.map +1 -0
- package/dist/commands/schedules.js +150 -0
- package/dist/commands/search.d.ts +4 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +60 -0
- package/dist/commands/segments.d.ts +4 -0
- package/dist/commands/segments.d.ts.map +1 -0
- package/dist/commands/segments.js +143 -0
- package/dist/commands/select-project.d.ts +4 -0
- package/dist/commands/select-project.d.ts.map +1 -0
- package/dist/commands/select-project.js +144 -0
- package/dist/commands/settings.d.ts +4 -0
- package/dist/commands/settings.d.ts.map +1 -0
- package/dist/commands/settings.js +113 -0
- package/dist/commands/variant-catalog.d.ts +4 -0
- package/dist/commands/variant-catalog.d.ts.map +1 -0
- package/dist/commands/variant-catalog.js +111 -0
- package/dist/commands/whoami.d.ts +4 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +50 -0
- package/dist/graphql/queries.d.ts +101 -0
- package/dist/graphql/queries.d.ts.map +1 -0
- package/dist/graphql/queries.js +373 -0
- package/dist/lib/client.d.ts +17 -0
- package/dist/lib/client.d.ts.map +1 -0
- package/dist/lib/client.js +61 -0
- package/dist/lib/config.d.ts +12 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +8 -0
- package/dist/lib/errors.d.ts +6 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +62 -0
- package/dist/lib/input.d.ts +36 -0
- package/dist/lib/input.d.ts.map +1 -0
- package/dist/lib/input.js +106 -0
- package/dist/lib/output.d.ts +31 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +107 -0
- 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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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"}
|