sharetribe-cli 1.15.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.
@@ -0,0 +1,309 @@
1
+ /**
2
+ * Process command - main entry point for process subcommands
3
+ */
4
+
5
+ import { Command } from 'commander';
6
+ import { listProcesses } from './list.js';
7
+ import { createProcess } from './create.js';
8
+ import { pushProcess } from './push.js';
9
+ import { pullProcess } from './pull.js';
10
+ import { createAlias, updateAlias, deleteAlias } from './aliases.js';
11
+ import { createOrPushAndCreateOrUpdateAlias } from './combined.js';
12
+
13
+ /**
14
+ * Registers all process subcommands
15
+ */
16
+ export function registerProcessCommands(program: Command): void {
17
+ // Register the parent 'process' command for help display
18
+ const processCmd = program
19
+ .command('process')
20
+ .description('describe a process file')
21
+ .option('--path <PROCESS_DIR>', 'path to the directory where the process.edn file is')
22
+ .option('--transition <TRANSITION_NAME>', 'transition name, e.g. transition/request to get more details of it')
23
+ .action(async (options) => {
24
+ // Process describe functionality
25
+ if (options.path) {
26
+ console.log(`Describing process at: ${options.path}`);
27
+ if (options.transition) {
28
+ console.log(`Transition: ${options.transition}`);
29
+ }
30
+ // TODO: Implement actual process file parsing and description
31
+ console.log('Process description not yet implemented');
32
+ } else {
33
+ // If no options, show help
34
+ processCmd.outputHelp();
35
+ }
36
+ });
37
+
38
+ // Register subcommands - these are registered as BOTH subcommands (for help) and top-level (for routing)
39
+
40
+ // process list (as subcommand)
41
+ processCmd
42
+ .command('list')
43
+ .description('list all transaction processes')
44
+ .option('--process <PROCESS_NAME>', 'print version and alias info of a specific process')
45
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
46
+ .action(async (options) => {
47
+ const marketplace = options.marketplace || program.opts().marketplace;
48
+ if (!marketplace) {
49
+ console.error('Error: --marketplace is required');
50
+ process.exit(1);
51
+ }
52
+ await listProcesses(marketplace, options.process);
53
+ });
54
+
55
+ // process create
56
+ processCmd
57
+ .command('create')
58
+ .description('create a new transaction process')
59
+ .requiredOption('--process <PROCESS_NAME>', 'name for the new process')
60
+ .requiredOption('--path <LOCAL_PROCESS_DIR>', 'path to the directory where the process.edn file is')
61
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
62
+ .action(async (options) => {
63
+ const marketplace = options.marketplace || program.opts().marketplace;
64
+ if (!marketplace) {
65
+ console.error('Error: --marketplace is required');
66
+ process.exit(1);
67
+ }
68
+ await createProcess(marketplace, options.process, options.path);
69
+ });
70
+
71
+ // process push
72
+ processCmd
73
+ .command('push')
74
+ .description('push a process file to the remote')
75
+ .requiredOption('--process <PROCESS_NAME>', 'name of the process')
76
+ .requiredOption('--path <LOCAL_PROCESS_DIR>', 'path to the directory where the process.edn file is')
77
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
78
+ .action(async (options) => {
79
+ const marketplace = options.marketplace || program.opts().marketplace;
80
+ if (!marketplace) {
81
+ console.error('Error: --marketplace is required');
82
+ process.exit(1);
83
+ }
84
+ await pushProcess(marketplace, options.process, options.path);
85
+ });
86
+
87
+ // process pull
88
+ processCmd
89
+ .command('pull')
90
+ .description('fetch a process file')
91
+ .requiredOption('--process <PROCESS_NAME>', 'name of the process')
92
+ .requiredOption('--path <LOCAL_PROCESS_DIR>', 'path where to save the process')
93
+ .option('--version <VERSION_NUM>', 'version number')
94
+ .option('--alias <PROCESS_ALIAS>', 'alias name')
95
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
96
+ .action(async (options) => {
97
+ const marketplace = options.marketplace || program.opts().marketplace;
98
+ if (!marketplace) {
99
+ console.error('Error: --marketplace is required');
100
+ process.exit(1);
101
+ }
102
+ await pullProcess(marketplace, options.process, options.path, options.version, options.alias);
103
+ });
104
+
105
+ // process create-alias
106
+ processCmd
107
+ .command('create-alias')
108
+ .description('create a new alias')
109
+ .requiredOption('--process <PROCESS_NAME>', 'name of the process')
110
+ .requiredOption('--version <VERSION_NUM>', 'version number')
111
+ .requiredOption('--alias <ALIAS>', 'alias name')
112
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
113
+ .allowUnknownOption(false)
114
+ .action(async (options) => {
115
+ const marketplace = options.marketplace || program.opts().marketplace;
116
+ if (!marketplace) {
117
+ console.error('Error: --marketplace is required');
118
+ process.exit(1);
119
+ }
120
+ await createAlias(marketplace, options.process, parseInt(options.version), options.alias);
121
+ });
122
+
123
+ // process update-alias
124
+ processCmd
125
+ .command('update-alias')
126
+ .description('update an existing alias')
127
+ .requiredOption('--process <PROCESS_NAME>', 'name of the process')
128
+ .requiredOption('--version <VERSION_NUM>', 'version number')
129
+ .requiredOption('--alias <ALIAS>', 'alias name')
130
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
131
+ .action(async (options) => {
132
+ const marketplace = options.marketplace || program.opts().marketplace;
133
+ if (!marketplace) {
134
+ console.error('Error: --marketplace is required');
135
+ process.exit(1);
136
+ }
137
+ await updateAlias(marketplace, options.process, parseInt(options.version), options.alias);
138
+ });
139
+
140
+ // process delete-alias
141
+ processCmd
142
+ .command('delete-alias')
143
+ .description('delete an existing alias')
144
+ .requiredOption('--process <PROCESS_NAME>', 'name of the process')
145
+ .requiredOption('--alias <ALIAS>', 'alias name')
146
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
147
+ .action(async (options) => {
148
+ const marketplace = options.marketplace || program.opts().marketplace;
149
+ if (!marketplace) {
150
+ console.error('Error: --marketplace is required');
151
+ process.exit(1);
152
+ }
153
+ await deleteAlias(marketplace, options.process, options.alias);
154
+ });
155
+
156
+ // process deploy (combined command: create-or-push-and-create-or-update-alias)
157
+ processCmd
158
+ .command('deploy')
159
+ .description('deploy a process file with alias (create/push + alias create/update)')
160
+ .requiredOption('--process <PROCESS_NAME>', 'name of the process')
161
+ .requiredOption('--path <LOCAL_PROCESS_DIR>', 'path to the directory with the process files')
162
+ .requiredOption('--alias <ALIAS>', 'alias name')
163
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
164
+ .action(async (options) => {
165
+ const marketplace = options.marketplace || program.opts().marketplace;
166
+ if (!marketplace) {
167
+ console.error('Error: --marketplace is required');
168
+ process.exit(1);
169
+ }
170
+ await createOrPushAndCreateOrUpdateAlias(
171
+ marketplace,
172
+ options.process,
173
+ options.path,
174
+ options.alias
175
+ );
176
+ });
177
+
178
+ // Register top-level command aliases for routing (hidden from help)
179
+ // These handle the routed commands like 'process-pull' that avoid Commander's parent/child option conflicts
180
+
181
+ program
182
+ .command('process-list', { hidden: true })
183
+ .description('list all transaction processes')
184
+ .option('--process <PROCESS_NAME>', 'print version and alias info of a specific process')
185
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
186
+ .action(async (options) => {
187
+ const marketplace = options.marketplace || program.opts().marketplace;
188
+ if (!marketplace) {
189
+ console.error('Error: --marketplace is required');
190
+ process.exit(1);
191
+ }
192
+ await listProcesses(marketplace, options.process);
193
+ });
194
+
195
+ program
196
+ .command('process-create', { hidden: true })
197
+ .description('create a new transaction process')
198
+ .requiredOption('--process <PROCESS_NAME>', 'name for the new process')
199
+ .requiredOption('--path <LOCAL_PROCESS_DIR>', 'path to the directory where the process.edn file is')
200
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
201
+ .action(async (options) => {
202
+ const marketplace = options.marketplace || program.opts().marketplace;
203
+ if (!marketplace) {
204
+ console.error('Error: --marketplace is required');
205
+ process.exit(1);
206
+ }
207
+ await createProcess(marketplace, options.process, options.path);
208
+ });
209
+
210
+ program
211
+ .command('process-push', { hidden: true })
212
+ .description('push a process file to the remote')
213
+ .requiredOption('--process <PROCESS_NAME>', 'name of the process')
214
+ .requiredOption('--path <LOCAL_PROCESS_DIR>', 'path to the directory where the process.edn file is')
215
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
216
+ .action(async (options) => {
217
+ const marketplace = options.marketplace || program.opts().marketplace;
218
+ if (!marketplace) {
219
+ console.error('Error: --marketplace is required');
220
+ process.exit(1);
221
+ }
222
+ await pushProcess(marketplace, options.process, options.path);
223
+ });
224
+
225
+ program
226
+ .command('process-pull', { hidden: true })
227
+ .description('fetch a process file')
228
+ .requiredOption('--process <PROCESS_NAME>', 'name of the process')
229
+ .requiredOption('--path <LOCAL_PROCESS_DIR>', 'path where to save the process')
230
+ .option('--version <VERSION_NUM>', 'version number')
231
+ .option('--alias <PROCESS_ALIAS>', 'alias name')
232
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
233
+ .action(async (options) => {
234
+ const marketplace = options.marketplace || program.opts().marketplace;
235
+ if (!marketplace) {
236
+ console.error('Error: --marketplace is required');
237
+ process.exit(1);
238
+ }
239
+ await pullProcess(marketplace, options.process, options.path, options.version, options.alias);
240
+ });
241
+
242
+ program
243
+ .command('process-create-alias', { hidden: true })
244
+ .description('create a new alias')
245
+ .requiredOption('--process <PROCESS_NAME>', 'name of the process')
246
+ .requiredOption('--version <VERSION_NUM>', 'version number')
247
+ .requiredOption('--alias <ALIAS>', 'alias name')
248
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
249
+ .action(async (options) => {
250
+ const marketplace = options.marketplace || program.opts().marketplace;
251
+ if (!marketplace) {
252
+ console.error('Error: --marketplace is required');
253
+ process.exit(1);
254
+ }
255
+ await createAlias(marketplace, options.process, parseInt(options.version), options.alias);
256
+ });
257
+
258
+ program
259
+ .command('process-update-alias', { hidden: true })
260
+ .description('update an existing alias')
261
+ .requiredOption('--process <PROCESS_NAME>', 'name of the process')
262
+ .requiredOption('--version <VERSION_NUM>', 'version number')
263
+ .requiredOption('--alias <ALIAS>', 'alias name')
264
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
265
+ .action(async (options) => {
266
+ const marketplace = options.marketplace || program.opts().marketplace;
267
+ if (!marketplace) {
268
+ console.error('Error: --marketplace is required');
269
+ process.exit(1);
270
+ }
271
+ await updateAlias(marketplace, options.process, parseInt(options.version), options.alias);
272
+ });
273
+
274
+ program
275
+ .command('process-delete-alias', { hidden: true })
276
+ .description('delete an existing alias')
277
+ .requiredOption('--process <PROCESS_NAME>', 'name of the process')
278
+ .requiredOption('--alias <ALIAS>', 'alias name')
279
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
280
+ .action(async (options) => {
281
+ const marketplace = options.marketplace || program.opts().marketplace;
282
+ if (!marketplace) {
283
+ console.error('Error: --marketplace is required');
284
+ process.exit(1);
285
+ }
286
+ await deleteAlias(marketplace, options.process, options.alias);
287
+ });
288
+
289
+ program
290
+ .command('process-deploy', { hidden: true })
291
+ .description('deploy a process file with alias (create/push + alias create/update)')
292
+ .requiredOption('--process <PROCESS_NAME>', 'name of the process')
293
+ .requiredOption('--path <LOCAL_PROCESS_DIR>', 'path to the directory with the process files')
294
+ .requiredOption('--alias <ALIAS>', 'alias name')
295
+ .option('-m, --marketplace <MARKETPLACE_ID>', 'marketplace identifier')
296
+ .action(async (options) => {
297
+ const marketplace = options.marketplace || program.opts().marketplace;
298
+ if (!marketplace) {
299
+ console.error('Error: --marketplace is required');
300
+ process.exit(1);
301
+ }
302
+ await createOrPushAndCreateOrUpdateAlias(
303
+ marketplace,
304
+ options.process,
305
+ options.path,
306
+ options.alias
307
+ );
308
+ });
309
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Process list command - lists all transaction processes
3
+ */
4
+
5
+ import {
6
+ listProcesses as sdkListProcesses,
7
+ listProcessVersions as sdkListProcessVersions,
8
+ } from 'sharetribe-flex-build-sdk';
9
+ import { printTable, printError } from '../../util/output.js';
10
+
11
+
12
+ /**
13
+ * Formats timestamp to match flex-cli format for process list
14
+ */
15
+ function formatProcessTimestamp(timestamp: string): string {
16
+ try {
17
+ const date = new Date(timestamp);
18
+ const year = date.getFullYear();
19
+ const month = String(date.getMonth() + 1).padStart(2, '0');
20
+ const day = String(date.getDate()).padStart(2, '0');
21
+ const timeString = date.toLocaleTimeString('en-US');
22
+
23
+ return `${year}-${month}-${day} ${timeString}`;
24
+ } catch {
25
+ return timestamp;
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Lists all processes for a marketplace
31
+ */
32
+ export async function listProcesses(marketplace: string, processName?: string): Promise<void> {
33
+ try {
34
+ // If processName is specified, show version history for that process
35
+ if (processName) {
36
+ const versions = await sdkListProcessVersions(undefined, marketplace, processName);
37
+
38
+ if (versions.length === 0) {
39
+ console.log(`No versions found for process: ${processName}`);
40
+ return;
41
+ }
42
+
43
+ const versionRows = versions.map((v) => ({
44
+ 'Created': formatProcessTimestamp(v.createdAt),
45
+ 'Version': v.version.toString(),
46
+ 'Aliases': v.aliases?.join(', ') || '',
47
+ 'Transactions': v.transactionCount?.toString() || '0',
48
+ }));
49
+
50
+ printTable(['Created', 'Version', 'Aliases', 'Transactions'], versionRows);
51
+ } else {
52
+ // List all processes
53
+ const processes = await sdkListProcesses(undefined, marketplace);
54
+
55
+ if (processes.length === 0) {
56
+ console.log('No processes found.');
57
+ return;
58
+ }
59
+
60
+ const processRows = processes.map((p) => ({
61
+ 'Name': p.name,
62
+ 'Latest version': p.version?.toString() || '',
63
+ }));
64
+
65
+ printTable(['Name', 'Latest version'], processRows);
66
+ }
67
+ } catch (error) {
68
+ if (error && typeof error === 'object' && 'message' in error) {
69
+ printError(error.message as string);
70
+ } else {
71
+ printError('Failed to list processes');
72
+ }
73
+ process.exit(1);
74
+ }
75
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Process pull command
3
+ */
4
+
5
+ import { getProcess } from 'sharetribe-flex-build-sdk';
6
+ import { printError, printSuccess } from '../../util/output.js';
7
+ import { writeFileSync, mkdirSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+
10
+ /**
11
+ * Pulls a process from the server
12
+ */
13
+ export async function pullProcess(
14
+ marketplace: string,
15
+ processName: string,
16
+ path: string,
17
+ version?: string,
18
+ alias?: string
19
+ ): Promise<void> {
20
+ try {
21
+ const process = await getProcess(undefined, marketplace, processName, { version, alias });
22
+
23
+ if (!process.definition) {
24
+ throw new Error('No process definition in response');
25
+ }
26
+
27
+ // Ensure directory exists (print message if creating new directory)
28
+ const { existsSync } = await import('node:fs');
29
+ const dirExists = existsSync(path);
30
+ mkdirSync(path, { recursive: true });
31
+
32
+ if (!dirExists) {
33
+ console.error(`Creating a new directory: ${path}`);
34
+ }
35
+
36
+ // Write process.edn file
37
+ const processFilePath = join(path, 'process.edn');
38
+ writeFileSync(processFilePath, process.definition, 'utf-8');
39
+
40
+ // Write email templates if they exist
41
+ const templates = process.emailTemplates || [];
42
+
43
+ if (templates && Array.isArray(templates) && templates.length > 0) {
44
+ const templatesDir = join(path, 'templates');
45
+ mkdirSync(templatesDir, { recursive: true });
46
+
47
+ for (const template of templates) {
48
+ const templateName = template.name;
49
+ const htmlContent = template.html;
50
+ const subjectContent = template.subject;
51
+
52
+ if (templateName) {
53
+ // Create subdirectory for this template
54
+ const templateSubdir = join(templatesDir, templateName);
55
+ mkdirSync(templateSubdir, { recursive: true });
56
+
57
+ // Write HTML file
58
+ if (htmlContent) {
59
+ const htmlPath = join(templateSubdir, `${templateName}-html.html`);
60
+ writeFileSync(htmlPath, htmlContent, 'utf-8');
61
+ }
62
+
63
+ // Write subject file
64
+ if (subjectContent) {
65
+ const subjectPath = join(templateSubdir, `${templateName}-subject.txt`);
66
+ writeFileSync(subjectPath, subjectContent, 'utf-8');
67
+ }
68
+ }
69
+ }
70
+ }
71
+
72
+ console.error(`Saved process to ${path}`);
73
+ } catch (error) {
74
+ if (error && typeof error === 'object' && 'message' in error) {
75
+ printError(error.message as string);
76
+ } else {
77
+ printError('Failed to pull process');
78
+ }
79
+ process.exit(1);
80
+ }
81
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Process push command
3
+ */
4
+
5
+ import { pushProcess as sdkPushProcess } from 'sharetribe-flex-build-sdk';
6
+ import { printError, printSuccess } from '../../util/output.js';
7
+ import { readFileSync, readdirSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+
10
+ /**
11
+ * Reads email templates from the templates directory
12
+ */
13
+ function readTemplates(path: string): Array<{ name: string; html: string; subject: string }> {
14
+ const templatesDir = join(path, 'templates');
15
+ const templates: Array<{ name: string; html: string; subject: string }> = [];
16
+
17
+ try {
18
+ const templateDirs = readdirSync(templatesDir);
19
+ for (const templateName of templateDirs) {
20
+ const templatePath = join(templatesDir, templateName);
21
+ const htmlFile = join(templatePath, `${templateName}-html.html`);
22
+ const subjectFile = join(templatePath, `${templateName}-subject.txt`);
23
+
24
+ try {
25
+ const html = readFileSync(htmlFile, 'utf-8');
26
+ const subject = readFileSync(subjectFile, 'utf-8');
27
+ templates.push({ name: templateName, html, subject });
28
+ } catch {
29
+ // Skip if files don't exist
30
+ }
31
+ }
32
+ } catch {
33
+ // No templates directory - return empty array
34
+ }
35
+
36
+ return templates;
37
+ }
38
+
39
+ /**
40
+ * Pushes a new version of an existing process
41
+ */
42
+ export async function pushProcess(
43
+ marketplace: string,
44
+ processName: string,
45
+ path: string
46
+ ): Promise<void> {
47
+ try {
48
+ const processFilePath = join(path, 'process.edn');
49
+ const processContent = readFileSync(processFilePath, 'utf-8');
50
+ const templates = readTemplates(path);
51
+
52
+ const result = await sdkPushProcess(undefined, marketplace, processName, processContent, templates);
53
+
54
+ if (result.noChanges) {
55
+ console.log('No changes');
56
+ } else {
57
+ printSuccess(`Version ${result.version} successfully saved for process ${processName}.`);
58
+ }
59
+ } catch (error) {
60
+ if (error && typeof error === 'object' && 'message' in error) {
61
+ printError(error.message as string);
62
+ } else {
63
+ printError('Failed to push process');
64
+ }
65
+ process.exit(1);
66
+ }
67
+ }