epicshop 6.65.0 → 6.67.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/cli.js CHANGED
@@ -5,9 +5,11 @@ import { matchSorter } from 'match-sorter';
5
5
  import yargs from 'yargs';
6
6
  import { hideBin } from 'yargs/helpers';
7
7
  import { assertCanPrompt } from "./utils/cli-runtime.js";
8
+ import { initCliSentry } from "./utils/sentry-cli.js";
8
9
  // Check for --help on start command before yargs parses
9
10
  // (yargs exits before command handler when help is requested)
10
11
  const args = hideBin(process.argv);
12
+ const cliSentry = initCliSentry(args);
11
13
  if ((args.includes('--help') || args.includes('-h')) &&
12
14
  (args.length === 0 || args[0] === 'start')) {
13
15
  const { displayHelp } = await import("./commands/start.js");
@@ -34,6 +36,9 @@ const cli = yargs(args)
34
36
  .alias('h', 'help')
35
37
  .version(false)
36
38
  .showHelpOnFail(true)
39
+ .middleware((argv) => {
40
+ cliSentry.setCommandContextFromArgv(argv);
41
+ })
37
42
  .command('start [workshop]', 'Start a workshop (auto-detects if inside a workshop directory)', (yargs) => {
38
43
  return yargs
39
44
  .positional('workshop', {
@@ -663,6 +668,12 @@ const cli = yargs(args)
663
668
  throw error;
664
669
  }
665
670
  }
671
+ if (!argv.subcommand) {
672
+ cliSentry.setCommandContext({
673
+ command: 'auth',
674
+ subcommand,
675
+ });
676
+ }
666
677
  let result;
667
678
  switch (subcommand) {
668
679
  case 'status':
@@ -1172,6 +1183,7 @@ try {
1172
1183
  });
1173
1184
  },
1174
1185
  });
1186
+ cliSentry.setCommandContext({ command: subcommand, interactive: true });
1175
1187
  switch (subcommand) {
1176
1188
  case 'start': {
1177
1189
  const { findWorkshopRoot, startWorkshop } = await import("./commands/workshops.js");
@@ -1421,6 +1433,10 @@ try {
1421
1433
  });
1422
1434
  },
1423
1435
  });
1436
+ cliSentry.setCommandContext({
1437
+ command: 'auth',
1438
+ subcommand: authSubcommand,
1439
+ });
1424
1440
  let authResult;
1425
1441
  switch (authSubcommand) {
1426
1442
  case 'status':
@@ -1532,6 +1548,8 @@ catch (error) {
1532
1548
  if (error.message === 'USER_QUIT') {
1533
1549
  process.exit(0);
1534
1550
  }
1551
+ cliSentry.captureException(error);
1552
+ await cliSentry.flush();
1535
1553
  console.error(chalk.red('❌ Error:'), error);
1536
1554
  process.exit(1);
1537
1555
  }
@@ -0,0 +1,18 @@
1
+ type CliCommandContext = {
2
+ command?: string;
3
+ subcommand?: string;
4
+ flags?: string[];
5
+ interactive?: boolean;
6
+ help?: boolean;
7
+ };
8
+ type CliSentry = {
9
+ enabled: boolean;
10
+ setCommandContext: (update: Partial<CliCommandContext>) => void;
11
+ setCommandContextFromArgv: (argv: {
12
+ _: Array<string | number>;
13
+ }) => void;
14
+ captureException: (error: unknown) => void;
15
+ flush: (timeoutMs?: number) => Promise<boolean>;
16
+ };
17
+ export declare function initCliSentry(args: string[]): CliSentry;
18
+ export {};
@@ -0,0 +1,135 @@
1
+ import * as Sentry from '@sentry/node';
2
+ import { getEnv } from '@epic-web/workshop-utils/init-env';
3
+ const HELP_FLAGS = new Set(['--help', '-h']);
4
+ function extractFlags(args) {
5
+ const flags = new Set();
6
+ for (let i = 0; i < args.length; i += 1) {
7
+ const arg = args[i];
8
+ if (!arg || arg === '-' || !arg.startsWith('-')) {
9
+ continue;
10
+ }
11
+ if (arg === '--') {
12
+ break;
13
+ }
14
+ if (arg.startsWith('--')) {
15
+ const [flag] = arg.split('=');
16
+ if (flag)
17
+ flags.add(flag);
18
+ if (!arg.includes('=') && args[i + 1] && !args[i + 1]?.startsWith('-')) {
19
+ i += 1;
20
+ }
21
+ }
22
+ else {
23
+ flags.add(arg);
24
+ if (arg.length === 2 && args[i + 1] && !args[i + 1]?.startsWith('-')) {
25
+ i += 1;
26
+ }
27
+ }
28
+ }
29
+ return Array.from(flags).sort();
30
+ }
31
+ function deriveCommandContext(args) {
32
+ const interactive = args.length === 0;
33
+ const doubleDashIndex = args.indexOf('--');
34
+ const argsBeforeDoubleDash = doubleDashIndex >= 0 ? args.slice(0, doubleDashIndex) : args;
35
+ const help = argsBeforeDoubleDash.some((arg) => HELP_FLAGS.has(arg));
36
+ const flags = extractFlags(args);
37
+ let command;
38
+ const firstNonFlagIndex = args.findIndex((arg) => !arg.startsWith('-'));
39
+ if (firstNonFlagIndex >= 0) {
40
+ command = args[firstNonFlagIndex];
41
+ }
42
+ if (!command) {
43
+ if (help) {
44
+ command = 'help';
45
+ }
46
+ else if (interactive) {
47
+ command = 'chooser';
48
+ }
49
+ }
50
+ return {
51
+ command,
52
+ flags,
53
+ interactive,
54
+ help: help || command === 'help',
55
+ };
56
+ }
57
+ function deriveCommandContextFromArgv(args, argv) {
58
+ const baseContext = deriveCommandContext(args);
59
+ const segments = argv._?.map(String).filter(Boolean) ?? [];
60
+ const command = segments[0] ?? baseContext.command;
61
+ const hasSubcommand = Object.prototype.hasOwnProperty.call(argv, 'subcommand');
62
+ const subcommand = hasSubcommand && typeof argv.subcommand === 'string'
63
+ ? argv.subcommand
64
+ : baseContext.subcommand;
65
+ const help = Boolean(argv.help ?? argv.h ?? baseContext.help);
66
+ return {
67
+ ...baseContext,
68
+ command,
69
+ subcommand,
70
+ help,
71
+ };
72
+ }
73
+ function applyCommandContext(context) {
74
+ Sentry.setTag('cli.command', context.command ?? 'unknown');
75
+ Sentry.setTag('cli.subcommand', context.subcommand ?? 'none');
76
+ if (context.interactive !== undefined) {
77
+ Sentry.setTag('cli.interactive', context.interactive ? 'true' : 'false');
78
+ }
79
+ if (context.help !== undefined) {
80
+ Sentry.setTag('cli.help', context.help ? 'true' : 'false');
81
+ }
82
+ Sentry.setContext('cli', {
83
+ command: context.command ?? 'unknown',
84
+ subcommand: context.subcommand ?? null,
85
+ flags: context.flags ?? [],
86
+ interactive: context.interactive ?? false,
87
+ help: context.help ?? false,
88
+ stdin_tty: Boolean(process.stdin.isTTY),
89
+ stdout_tty: Boolean(process.stdout.isTTY),
90
+ });
91
+ }
92
+ export function initCliSentry(args) {
93
+ const env = getEnv();
94
+ const enabled = env.EPICSHOP_IS_PUBLISHED && Boolean(env.SENTRY_DSN);
95
+ if (!enabled) {
96
+ return {
97
+ enabled,
98
+ setCommandContext: () => { },
99
+ setCommandContextFromArgv: () => { },
100
+ captureException: () => { },
101
+ flush: async () => true,
102
+ };
103
+ }
104
+ Sentry.init({
105
+ dsn: env.SENTRY_DSN,
106
+ sendDefaultPii: false,
107
+ environment: env.EPICSHOP_IS_PUBLISHED ? 'production' : 'development',
108
+ tracesSampleRate: 1,
109
+ });
110
+ Sentry.setTags({
111
+ epicshop_github_repo: env.EPICSHOP_GITHUB_REPO || 'unknown',
112
+ epicshop_workshop_instance_id: env.EPICSHOP_WORKSHOP_INSTANCE_ID || 'unknown',
113
+ epicshop_app_version: env.EPICSHOP_APP_VERSION || 'unknown',
114
+ epicshop_published: env.EPICSHOP_IS_PUBLISHED ? 'true' : 'false',
115
+ });
116
+ let currentContext = deriveCommandContext(args);
117
+ applyCommandContext(currentContext);
118
+ return {
119
+ enabled,
120
+ setCommandContext(update) {
121
+ currentContext = { ...currentContext, ...update };
122
+ applyCommandContext(currentContext);
123
+ },
124
+ setCommandContextFromArgv(argv) {
125
+ currentContext = deriveCommandContextFromArgv(args, argv);
126
+ applyCommandContext(currentContext);
127
+ },
128
+ captureException(error) {
129
+ Sentry.captureException(error);
130
+ },
131
+ flush(timeoutMs = 2000) {
132
+ return Sentry.flush(timeoutMs);
133
+ },
134
+ };
135
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epicshop",
3
- "version": "6.65.0",
3
+ "version": "6.67.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -93,15 +93,16 @@
93
93
  "build:watch": "nx watch --projects=epicshop -- nx run \\$NX_PROJECT_NAME:build"
94
94
  },
95
95
  "dependencies": {
96
- "@epic-web/workshop-utils": "6.65.0",
96
+ "@epic-web/workshop-utils": "6.67.0",
97
97
  "@inquirer/prompts": "^8.2.0",
98
+ "@sentry/node": "^10.35.0",
98
99
  "chalk": "^5.6.2",
99
100
  "close-with-grace": "^2.4.0",
100
101
  "execa": "^9.6.1",
101
102
  "get-port": "^7.1.0",
102
103
  "match-sorter": "^8.2.0",
103
- "openid-client": "^6.8.1",
104
104
  "open": "^11.0.0",
105
+ "openid-client": "^6.8.1",
105
106
  "ora": "^9.0.0",
106
107
  "yargs": "^18.0.0"
107
108
  },
@@ -109,8 +110,8 @@
109
110
  "@epic-web/config": "^1.21.3",
110
111
  "@types/node": "^25.0.9",
111
112
  "@types/yargs": "^17.0.35",
112
- "zshy": "^0.7.0",
113
- "vitest": "^4.0.17"
113
+ "vitest": "^4.0.17",
114
+ "zshy": "^0.7.0"
114
115
  },
115
116
  "repository": {
116
117
  "type": "git",