@sentio/cli 3.4.1 → 3.4.2-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -150515,6 +150515,31 @@ async function postApiJson(apiPath, context, body, query) {
150515
150515
  }
150516
150516
  return await response.json();
150517
150517
  }
150518
+ async function putApiJson(apiPath, context, body, query) {
150519
+ const url5 = getApiUrl(apiPath, context.host);
150520
+ if (query) {
150521
+ for (const [key, value] of Object.entries(query)) {
150522
+ if (value !== void 0) {
150523
+ url5.searchParams.set(key, String(value));
150524
+ }
150525
+ }
150526
+ }
150527
+ const response = await fetch(url5.href, {
150528
+ method: "PUT",
150529
+ headers: {
150530
+ ...body !== void 0 ? { "Content-Type": "application/json" } : {},
150531
+ ...context.headers
150532
+ },
150533
+ body: body !== void 0 ? JSON.stringify(body) : void 0
150534
+ });
150535
+ if (!response.ok) {
150536
+ const text = await response.text();
150537
+ throw new CliError(
150538
+ `Sentio API request failed: ${response.status} ${response.statusText}${text ? ` - ${text}` : ""}`
150539
+ );
150540
+ }
150541
+ return await response.json();
150542
+ }
150518
150543
  function parseStructuredInput(content, source, filename) {
150519
150544
  if (!content.trim()) {
150520
150545
  throw new CliError(`Expected JSON or YAML in ${source}, but it was empty.`);
@@ -151913,6 +151938,9 @@ function createProcessorCommand() {
151913
151938
  processorCommand.addCommand(createProcessorStatusCommand());
151914
151939
  processorCommand.addCommand(createProcessorSourceCommand());
151915
151940
  processorCommand.addCommand(createProcessorActivatePendingCommand());
151941
+ processorCommand.addCommand(createProcessorPauseCommand());
151942
+ processorCommand.addCommand(createProcessorResumeCommand());
151943
+ processorCommand.addCommand(createProcessorStopCommand());
151916
151944
  return processorCommand;
151917
151945
  }
151918
151946
  function createProcessorStatusCommand() {
@@ -151942,7 +151970,7 @@ function createProcessorActivatePendingCommand() {
151942
151970
  withSharedProjectOptions3(
151943
151971
  withAuthOptions3(new Command("activate-pending").description("Activate the pending version"))
151944
151972
  )
151945
- ).showHelpAfterError().action(async (options, command) => {
151973
+ ).showHelpAfterError().option("-y, --yes", "Bypass confirmation").action(async (options, command) => {
151946
151974
  try {
151947
151975
  await runActivatePending(options);
151948
151976
  } catch (error) {
@@ -151950,6 +151978,39 @@ function createProcessorActivatePendingCommand() {
151950
151978
  }
151951
151979
  });
151952
151980
  }
151981
+ function createProcessorPauseCommand() {
151982
+ return withOutputOptions3(
151983
+ withSharedProjectOptions3(withAuthOptions3(new Command("pause").description("Pause a processor")))
151984
+ ).showHelpAfterError().argument("[processorId]", "ID of the processor").option("--reason <reason>", "Reason for pausing").option("-y, --yes", "Bypass confirmation").action(async (processorId, options, command) => {
151985
+ try {
151986
+ await runProcessorPause(processorId, options);
151987
+ } catch (error) {
151988
+ handleProcessorCommandError(error, command);
151989
+ }
151990
+ });
151991
+ }
151992
+ function createProcessorResumeCommand() {
151993
+ return withOutputOptions3(
151994
+ withSharedProjectOptions3(withAuthOptions3(new Command("resume").description("Resume a processor")))
151995
+ ).showHelpAfterError().argument("[processorId]", "ID of the processor").option("-y, --yes", "Bypass confirmation").action(async (processorId, options, command) => {
151996
+ try {
151997
+ await runProcessorResume(processorId, options);
151998
+ } catch (error) {
151999
+ handleProcessorCommandError(error, command);
152000
+ }
152001
+ });
152002
+ }
152003
+ function createProcessorStopCommand() {
152004
+ return withOutputOptions3(
152005
+ withSharedProjectOptions3(withAuthOptions3(new Command("stop").description("Stop a processor")))
152006
+ ).showHelpAfterError().argument("[processorId]", "ID of the processor").option("-y, --yes", "Bypass confirmation").action(async (processorId, options, command) => {
152007
+ try {
152008
+ await runProcessorStop(processorId, options);
152009
+ } catch (error) {
152010
+ handleProcessorCommandError(error, command);
152011
+ }
152012
+ });
152013
+ }
151953
152014
  async function runProcessorStatus(options) {
151954
152015
  const context = createApiContext(options);
151955
152016
  const project = await resolveProjectRef(options, context, { ownerSlug: true });
@@ -151998,6 +152059,32 @@ async function runProcessorSource(options) {
151998
152059
  async function runActivatePending(options) {
151999
152060
  const context = createApiContext(options);
152000
152061
  const project = await resolveProjectRef(options, context, { ownerSlug: true });
152062
+ const statusResponse = await import_api5.ProcessorService.getProcessorStatusV2({
152063
+ path: {
152064
+ owner: project.owner,
152065
+ slug: project.slug
152066
+ },
152067
+ query: { version: "ALL" },
152068
+ headers: context.headers
152069
+ });
152070
+ const data = unwrapApiResult(statusResponse);
152071
+ const processors = Array.isArray(data.processors) ? data.processors : [];
152072
+ const activeProcessor = processors.find((p7) => asString3(p7.versionState) === "ACTIVE");
152073
+ const pendingProcessor = processors.find((p7) => asString3(p7.versionState) === "PENDING");
152074
+ if (!pendingProcessor) {
152075
+ throw new CliError(`No pending version found for project ${project.owner}/${project.slug}.`);
152076
+ }
152077
+ if (!options.yes) {
152078
+ let message = `Activate the pending version ${asNumber(pendingProcessor.version)}. Are you sure you want to proceed?`;
152079
+ if (activeProcessor) {
152080
+ message = `Activate the pending version ${asNumber(pendingProcessor.version)} may obsolete the active version ${asNumber(activeProcessor.version)}. Are you sure you want to proceed?`;
152081
+ }
152082
+ const isConfirmed = await confirm(message);
152083
+ if (!isConfirmed) {
152084
+ console.log("Activation cancelled.");
152085
+ return;
152086
+ }
152087
+ }
152001
152088
  const response = await import_api5.ProcessorService.activatePendingVersion({
152002
152089
  path: {
152003
152090
  owner: project.owner,
@@ -152010,6 +152097,73 @@ async function runActivatePending(options) {
152010
152097
  ...unwrapApiResult(response)
152011
152098
  });
152012
152099
  }
152100
+ async function resolveAndConfirmProcessor(actionName, processorId, options) {
152101
+ const context = createApiContext(options);
152102
+ let resolvedProcessorId = processorId;
152103
+ let versionToConfirm = "";
152104
+ if (!resolvedProcessorId) {
152105
+ const project = await resolveProjectRef(options, context, { ownerSlug: true });
152106
+ const statusResponse = await import_api5.ProcessorService.getProcessorStatusV2({
152107
+ path: {
152108
+ owner: project.owner,
152109
+ slug: project.slug
152110
+ },
152111
+ query: { version: "ACTIVE" },
152112
+ headers: context.headers
152113
+ });
152114
+ const data = unwrapApiResult(statusResponse);
152115
+ const processors = Array.isArray(data.processors) ? data.processors : [];
152116
+ const activeProcessor = processors.find((p7) => asString3(p7.versionState) === "ACTIVE");
152117
+ if (!activeProcessor || !activeProcessor.processorId) {
152118
+ throw new CliError(
152119
+ `No active processor found for project ${project.owner}/${project.slug}. Please specify a processorId.`
152120
+ );
152121
+ }
152122
+ resolvedProcessorId = asString3(activeProcessor.processorId);
152123
+ versionToConfirm = `version ${asNumber(activeProcessor.version)} of project ${project.owner}/${project.slug}`;
152124
+ } else {
152125
+ versionToConfirm = `processor ${resolvedProcessorId}`;
152126
+ }
152127
+ if (!options.yes) {
152128
+ const isConfirmed = await confirm(`Are you sure you want to ${actionName} ${versionToConfirm}?`);
152129
+ if (!isConfirmed) {
152130
+ console.log(`${actionName.charAt(0).toUpperCase() + actionName.slice(1)} cancelled.`);
152131
+ return void 0;
152132
+ }
152133
+ }
152134
+ return resolvedProcessorId;
152135
+ }
152136
+ async function runProcessorPause(processorId, options) {
152137
+ const resolvedProcessorId = await resolveAndConfirmProcessor("pause", processorId, options);
152138
+ if (!resolvedProcessorId) return;
152139
+ const context = createApiContext(options);
152140
+ const response = await putApiJson(`/api/v1/processors/${resolvedProcessorId}/pause`, context, {
152141
+ reason: options.reason
152142
+ });
152143
+ printOutput3(options, { processorId: resolvedProcessorId, action: "paused", ...response });
152144
+ }
152145
+ async function runProcessorResume(processorId, options) {
152146
+ const resolvedProcessorId = await resolveAndConfirmProcessor("resume", processorId, options);
152147
+ if (!resolvedProcessorId) return;
152148
+ const context = createApiContext(options);
152149
+ const response = await putApiJson(`/api/v1/processors/${resolvedProcessorId}/resume`, context);
152150
+ printOutput3(options, {
152151
+ processorId: resolvedProcessorId,
152152
+ action: "resumed",
152153
+ ...response
152154
+ });
152155
+ }
152156
+ async function runProcessorStop(processorId, options) {
152157
+ const resolvedProcessorId = await resolveAndConfirmProcessor("stop", processorId, options);
152158
+ if (!resolvedProcessorId) return;
152159
+ const context = createApiContext(options);
152160
+ const response = await postApiJson(`/api/v1/processors/stop`, context, { processorId: resolvedProcessorId });
152161
+ printOutput3(options, {
152162
+ processorId: resolvedProcessorId,
152163
+ action: "stopped",
152164
+ ...response
152165
+ });
152166
+ }
152013
152167
  function withAuthOptions3(command) {
152014
152168
  return command.option("--host <host>", "Override Sentio host").option("--api-key <key>", "Use an explicit API key instead of saved credentials").option("--token <token>", "Use an explicit bearer token instead of saved credentials");
152015
152169
  }
@@ -152090,6 +152244,10 @@ function formatOutput2(data) {
152090
152244
  const objectData = data;
152091
152245
  return `Pending processor version activated for ${asString3(objectData.project) ?? "<project>"}.`;
152092
152246
  }
152247
+ if (data && typeof data === "object" && "action" in data && "processorId" in data) {
152248
+ const objectData = data;
152249
+ return `Processor ${asString3(objectData.processorId)} successfully ${asString3(objectData.action)}.`;
152250
+ }
152093
152251
  return JSON.stringify(data, null, 2);
152094
152252
  }
152095
152253
  function normalizeVersionSelector(value) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentio/cli",
3
- "version": "3.4.1",
3
+ "version": "3.4.2-rc.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
package/src/api.ts CHANGED
@@ -420,6 +420,37 @@ export async function postApiJson<T>(
420
420
  return (await response.json()) as T
421
421
  }
422
422
 
423
+ export async function putApiJson<T>(
424
+ apiPath: string,
425
+ context: ApiContext,
426
+ body?: unknown,
427
+ query?: Record<string, string | number | boolean | undefined>
428
+ ): Promise<T> {
429
+ const url = getApiUrl(apiPath, context.host)
430
+ if (query) {
431
+ for (const [key, value] of Object.entries(query)) {
432
+ if (value !== undefined) {
433
+ url.searchParams.set(key, String(value))
434
+ }
435
+ }
436
+ }
437
+ const response = await fetch(url.href, {
438
+ method: 'PUT',
439
+ headers: {
440
+ ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
441
+ ...context.headers
442
+ },
443
+ body: body !== undefined ? JSON.stringify(body) : undefined
444
+ })
445
+ if (!response.ok) {
446
+ const text = await response.text()
447
+ throw new CliError(
448
+ `Sentio API request failed: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`
449
+ )
450
+ }
451
+ return (await response.json()) as T
452
+ }
453
+
423
454
  function parseStructuredInput(content: string, source: string, filename?: string) {
424
455
  if (!content.trim()) {
425
456
  throw new CliError(`Expected JSON or YAML in ${source}, but it was empty.`)
@@ -2,7 +2,16 @@ import { ProcessorExtService, ProcessorService } from '@sentio/api'
2
2
  import { Command, InvalidArgumentError } from '@commander-js/extra-typings'
3
3
  import process from 'process'
4
4
  import yaml from 'yaml'
5
- import { CliError, createApiContext, handleCommandError, resolveProjectRef, unwrapApiResult } from '../api.js'
5
+ import {
6
+ CliError,
7
+ createApiContext,
8
+ handleCommandError,
9
+ resolveProjectRef,
10
+ unwrapApiResult,
11
+ postApiJson,
12
+ putApiJson
13
+ } from '../api.js'
14
+ import { confirm } from './upload.js'
6
15
 
7
16
  interface ProcessorOptions {
8
17
  host?: string
@@ -30,6 +39,9 @@ export function createProcessorCommand() {
30
39
  processorCommand.addCommand(createProcessorStatusCommand())
31
40
  processorCommand.addCommand(createProcessorSourceCommand())
32
41
  processorCommand.addCommand(createProcessorActivatePendingCommand())
42
+ processorCommand.addCommand(createProcessorPauseCommand())
43
+ processorCommand.addCommand(createProcessorResumeCommand())
44
+ processorCommand.addCommand(createProcessorStopCommand())
33
45
  return processorCommand
34
46
  }
35
47
 
@@ -71,6 +83,7 @@ function createProcessorActivatePendingCommand() {
71
83
  )
72
84
  )
73
85
  .showHelpAfterError()
86
+ .option('-y, --yes', 'Bypass confirmation')
74
87
  .action(async (options, command) => {
75
88
  try {
76
89
  await runActivatePending(options)
@@ -80,6 +93,55 @@ function createProcessorActivatePendingCommand() {
80
93
  })
81
94
  }
82
95
 
96
+ function createProcessorPauseCommand() {
97
+ return withOutputOptions(
98
+ withSharedProjectOptions(withAuthOptions(new Command('pause').description('Pause a processor')))
99
+ )
100
+ .showHelpAfterError()
101
+ .argument('[processorId]', 'ID of the processor')
102
+ .option('--reason <reason>', 'Reason for pausing')
103
+ .option('-y, --yes', 'Bypass confirmation')
104
+ .action(async (processorId, options, command) => {
105
+ try {
106
+ await runProcessorPause(processorId, options)
107
+ } catch (error) {
108
+ handleProcessorCommandError(error, command)
109
+ }
110
+ })
111
+ }
112
+
113
+ function createProcessorResumeCommand() {
114
+ return withOutputOptions(
115
+ withSharedProjectOptions(withAuthOptions(new Command('resume').description('Resume a processor')))
116
+ )
117
+ .showHelpAfterError()
118
+ .argument('[processorId]', 'ID of the processor')
119
+ .option('-y, --yes', 'Bypass confirmation')
120
+ .action(async (processorId, options, command) => {
121
+ try {
122
+ await runProcessorResume(processorId, options)
123
+ } catch (error) {
124
+ handleProcessorCommandError(error, command)
125
+ }
126
+ })
127
+ }
128
+
129
+ function createProcessorStopCommand() {
130
+ return withOutputOptions(
131
+ withSharedProjectOptions(withAuthOptions(new Command('stop').description('Stop a processor')))
132
+ )
133
+ .showHelpAfterError()
134
+ .argument('[processorId]', 'ID of the processor')
135
+ .option('-y, --yes', 'Bypass confirmation')
136
+ .action(async (processorId, options, command) => {
137
+ try {
138
+ await runProcessorStop(processorId, options)
139
+ } catch (error) {
140
+ handleProcessorCommandError(error, command)
141
+ }
142
+ })
143
+ }
144
+
83
145
  async function runProcessorStatus(options: ProcessorStatusOptions) {
84
146
  const context = createApiContext(options)
85
147
  const project = await resolveProjectRef(options, context, { ownerSlug: true })
@@ -127,9 +189,41 @@ async function runProcessorSource(options: ProcessorSourceOptions) {
127
189
  printOutput(options, data)
128
190
  }
129
191
 
130
- async function runActivatePending(options: ProcessorOptions) {
192
+ async function runActivatePending(options: ProcessorOptions & { yes?: boolean }) {
131
193
  const context = createApiContext(options)
132
194
  const project = await resolveProjectRef(options, context, { ownerSlug: true })
195
+
196
+ const statusResponse = await ProcessorService.getProcessorStatusV2({
197
+ path: {
198
+ owner: project.owner,
199
+ slug: project.slug
200
+ },
201
+ query: { version: 'ALL' },
202
+ headers: context.headers
203
+ })
204
+ const data = unwrapApiResult(statusResponse)
205
+ const processors = Array.isArray(data.processors) ? data.processors : []
206
+
207
+ const activeProcessor = processors.find((p) => asString(p.versionState) === 'ACTIVE')
208
+ const pendingProcessor = processors.find((p) => asString(p.versionState) === 'PENDING')
209
+
210
+ if (!pendingProcessor) {
211
+ throw new CliError(`No pending version found for project ${project.owner}/${project.slug}.`)
212
+ }
213
+
214
+ if (!options.yes) {
215
+ let message = `Activate the pending version ${asNumber(pendingProcessor.version)}. Are you sure you want to proceed?`
216
+ if (activeProcessor) {
217
+ message = `Activate the pending version ${asNumber(pendingProcessor.version)} may obsolete the active version ${asNumber(activeProcessor.version)}. Are you sure you want to proceed?`
218
+ }
219
+
220
+ const isConfirmed = await confirm(message)
221
+ if (!isConfirmed) {
222
+ console.log('Activation cancelled.')
223
+ return
224
+ }
225
+ }
226
+
133
227
  const response = await ProcessorService.activatePendingVersion({
134
228
  path: {
135
229
  owner: project.owner,
@@ -143,6 +237,88 @@ async function runActivatePending(options: ProcessorOptions) {
143
237
  })
144
238
  }
145
239
 
240
+ async function resolveAndConfirmProcessor(
241
+ actionName: string,
242
+ processorId: string | undefined,
243
+ options: ProcessorOptions & { yes?: boolean }
244
+ ): Promise<string | undefined> {
245
+ const context = createApiContext(options)
246
+ let resolvedProcessorId = processorId
247
+ let versionToConfirm = ''
248
+
249
+ if (!resolvedProcessorId) {
250
+ const project = await resolveProjectRef(options, context, { ownerSlug: true })
251
+ const statusResponse = await ProcessorService.getProcessorStatusV2({
252
+ path: {
253
+ owner: project.owner,
254
+ slug: project.slug
255
+ },
256
+ query: { version: 'ACTIVE' },
257
+ headers: context.headers
258
+ })
259
+ const data = unwrapApiResult(statusResponse)
260
+ const processors = Array.isArray(data.processors) ? data.processors : []
261
+ const activeProcessor = processors.find((p) => asString(p.versionState) === 'ACTIVE')
262
+
263
+ if (!activeProcessor || !activeProcessor.processorId) {
264
+ throw new CliError(
265
+ `No active processor found for project ${project.owner}/${project.slug}. Please specify a processorId.`
266
+ )
267
+ }
268
+ resolvedProcessorId = asString(activeProcessor.processorId)!
269
+ versionToConfirm = `version ${asNumber(activeProcessor.version)} of project ${project.owner}/${project.slug}`
270
+ } else {
271
+ versionToConfirm = `processor ${resolvedProcessorId}`
272
+ }
273
+
274
+ if (!options.yes) {
275
+ const isConfirmed = await confirm(`Are you sure you want to ${actionName} ${versionToConfirm}?`)
276
+ if (!isConfirmed) {
277
+ console.log(`${actionName.charAt(0).toUpperCase() + actionName.slice(1)} cancelled.`)
278
+ return undefined
279
+ }
280
+ }
281
+
282
+ return resolvedProcessorId
283
+ }
284
+
285
+ async function runProcessorPause(
286
+ processorId: string | undefined,
287
+ options: ProcessorOptions & { reason?: string; yes?: boolean }
288
+ ) {
289
+ const resolvedProcessorId = await resolveAndConfirmProcessor('pause', processorId, options)
290
+ if (!resolvedProcessorId) return
291
+ const context = createApiContext(options)
292
+ const response = await putApiJson(`/api/v1/processors/${resolvedProcessorId}/pause`, context, {
293
+ reason: options.reason
294
+ })
295
+ printOutput(options, { processorId: resolvedProcessorId, action: 'paused', ...(response as Record<string, unknown>) })
296
+ }
297
+
298
+ async function runProcessorResume(processorId: string | undefined, options: ProcessorOptions & { yes?: boolean }) {
299
+ const resolvedProcessorId = await resolveAndConfirmProcessor('resume', processorId, options)
300
+ if (!resolvedProcessorId) return
301
+ const context = createApiContext(options)
302
+ const response = await putApiJson(`/api/v1/processors/${resolvedProcessorId}/resume`, context)
303
+ printOutput(options, {
304
+ processorId: resolvedProcessorId,
305
+ action: 'resumed',
306
+ ...(response as Record<string, unknown>)
307
+ })
308
+ }
309
+
310
+ async function runProcessorStop(processorId: string | undefined, options: ProcessorOptions & { yes?: boolean }) {
311
+ const resolvedProcessorId = await resolveAndConfirmProcessor('stop', processorId, options)
312
+ if (!resolvedProcessorId) return
313
+ const context = createApiContext(options)
314
+ const response = await postApiJson(`/api/v1/processors/stop`, context, { processorId: resolvedProcessorId })
315
+ printOutput(options, {
316
+ processorId: resolvedProcessorId,
317
+ action: 'stopped',
318
+ ...(response as Record<string, unknown>)
319
+ })
320
+ }
321
+
146
322
  function withAuthOptions<T extends Command<any, any, any>>(command: T) {
147
323
  return command
148
324
  .option('--host <host>', 'Override Sentio host')
@@ -246,6 +422,16 @@ function formatOutput(data: unknown) {
246
422
  return `Pending processor version activated for ${asString(objectData.project) ?? '<project>'}.`
247
423
  }
248
424
 
425
+ if (
426
+ data &&
427
+ typeof data === 'object' &&
428
+ 'action' in (data as Record<string, unknown>) &&
429
+ 'processorId' in (data as Record<string, unknown>)
430
+ ) {
431
+ const objectData = data as Record<string, unknown>
432
+ return `Processor ${asString(objectData.processorId)} successfully ${asString(objectData.action)}.`
433
+ }
434
+
249
435
  return JSON.stringify(data, null, 2)
250
436
  }
251
437