@lokeshhh/devblitz-cli 1.0.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 (70) hide show
  1. package/bin/run +3 -0
  2. package/dist/commands/init.d.ts +7 -0
  3. package/dist/commands/init.d.ts.map +1 -0
  4. package/dist/commands/init.js +152 -0
  5. package/dist/commands/init.js.map +1 -0
  6. package/dist/commands/login.d.ts +7 -0
  7. package/dist/commands/login.d.ts.map +1 -0
  8. package/dist/commands/login.js +75 -0
  9. package/dist/commands/login.js.map +1 -0
  10. package/dist/commands/run.d.ts +7 -0
  11. package/dist/commands/run.d.ts.map +1 -0
  12. package/dist/commands/run.js +385 -0
  13. package/dist/commands/run.js.map +1 -0
  14. package/dist/commands/status.d.ts +7 -0
  15. package/dist/commands/status.d.ts.map +1 -0
  16. package/dist/commands/status.js +121 -0
  17. package/dist/commands/status.js.map +1 -0
  18. package/dist/components/Header.d.ts +9 -0
  19. package/dist/components/Header.d.ts.map +1 -0
  20. package/dist/components/Header.js +7 -0
  21. package/dist/components/Header.js.map +1 -0
  22. package/dist/components/HelpView.d.ts +7 -0
  23. package/dist/components/HelpView.d.ts.map +1 -0
  24. package/dist/components/HelpView.js +51 -0
  25. package/dist/components/HelpView.js.map +1 -0
  26. package/dist/components/ProgressBar.d.ts +9 -0
  27. package/dist/components/ProgressBar.d.ts.map +1 -0
  28. package/dist/components/ProgressBar.js +10 -0
  29. package/dist/components/ProgressBar.js.map +1 -0
  30. package/dist/components/Spinner.d.ts +12 -0
  31. package/dist/components/Spinner.d.ts.map +1 -0
  32. package/dist/components/Spinner.js +21 -0
  33. package/dist/components/Spinner.js.map +1 -0
  34. package/dist/components/StatusMessage.d.ts +8 -0
  35. package/dist/components/StatusMessage.d.ts.map +1 -0
  36. package/dist/components/StatusMessage.js +26 -0
  37. package/dist/components/StatusMessage.js.map +1 -0
  38. package/dist/components/Table.d.ts +15 -0
  39. package/dist/components/Table.d.ts.map +1 -0
  40. package/dist/components/Table.js +26 -0
  41. package/dist/components/Table.js.map +1 -0
  42. package/dist/components/TestResultLine.d.ts +9 -0
  43. package/dist/components/TestResultLine.d.ts.map +1 -0
  44. package/dist/components/TestResultLine.js +29 -0
  45. package/dist/components/TestResultLine.js.map +1 -0
  46. package/dist/components/index.d.ts +8 -0
  47. package/dist/components/index.d.ts.map +1 -0
  48. package/dist/components/index.js +8 -0
  49. package/dist/components/index.js.map +1 -0
  50. package/dist/index.d.ts +3 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +59 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/utils/api.d.ts +5 -0
  55. package/dist/utils/api.d.ts.map +1 -0
  56. package/dist/utils/api.js +60 -0
  57. package/dist/utils/api.js.map +1 -0
  58. package/dist/utils/auth.d.ts +24 -0
  59. package/dist/utils/auth.d.ts.map +1 -0
  60. package/dist/utils/auth.js +79 -0
  61. package/dist/utils/auth.js.map +1 -0
  62. package/dist/utils/helpers.d.ts +8 -0
  63. package/dist/utils/helpers.d.ts.map +1 -0
  64. package/dist/utils/helpers.js +36 -0
  65. package/dist/utils/helpers.js.map +1 -0
  66. package/dist/utils/theme.d.ts +27 -0
  67. package/dist/utils/theme.d.ts.map +1 -0
  68. package/dist/utils/theme.js +32 -0
  69. package/dist/utils/theme.js.map +1 -0
  70. package/package.json +57 -0
@@ -0,0 +1,51 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Box, Text } from 'ink';
4
+ import { spacing } from '../utils/theme.js';
5
+ const commands = {
6
+ login: {
7
+ name: 'login',
8
+ description: 'authenticate with devblitz',
9
+ usage: 'devblitz login [options]',
10
+ options: [
11
+ { flag: '-l, --logout', description: 'log out from current session' },
12
+ ],
13
+ examples: [
14
+ 'devblitz login',
15
+ 'devblitz login --logout',
16
+ ],
17
+ },
18
+ init: {
19
+ name: 'init',
20
+ description: 'join contest and setup environment',
21
+ usage: 'devblitz init <contest-id>',
22
+ examples: [
23
+ 'devblitz init abc123',
24
+ ],
25
+ },
26
+ run: {
27
+ name: 'run',
28
+ description: 'run tests for a chapter',
29
+ usage: 'devblitz run <chapter-uuid>',
30
+ examples: [
31
+ 'devblitz run chapter-uuid-here',
32
+ ],
33
+ },
34
+ status: {
35
+ name: 'status',
36
+ description: 'show contest progress',
37
+ usage: 'devblitz status <contest-id>',
38
+ examples: [
39
+ 'devblitz status abc123',
40
+ ],
41
+ },
42
+ };
43
+ export const HelpView = ({ command }) => {
44
+ if (command && commands[command]) {
45
+ const cmd = commands[command];
46
+ return (_jsxs(Box, { flexDirection: "column", paddingTop: 1, children: [_jsxs(Text, { bold: true, children: ["devblitz ", cmd.name] }), _jsx(Text, {}), _jsx(Text, { dimColor: true, children: cmd.description }), _jsx(Text, {}), _jsx(Text, { bold: true, children: "Usage" }), _jsxs(Text, { children: [spacing.indent, "$ ", cmd.usage] }), _jsx(Text, {}), cmd.options && cmd.options.length > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, children: "Options" }), cmd.options.map((opt, i) => (_jsxs(Text, { children: [spacing.indent, opt.flag.padEnd(20), opt.description] }, i))), _jsx(Text, {})] })), cmd.examples && cmd.examples.length > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, children: "Examples" }), cmd.examples.map((ex, i) => (_jsxs(Text, { dimColor: true, children: [spacing.indent, "$ ", ex] }, i)))] }))] }));
47
+ }
48
+ // Show all commands
49
+ return (_jsxs(Box, { flexDirection: "column", paddingTop: 1, children: [_jsx(Text, { bold: true, children: "devblitz" }), _jsx(Text, {}), _jsx(Text, { bold: true, children: "Usage" }), _jsxs(Text, { children: [spacing.indent, "$ devblitz ", '<command>'] }), _jsx(Text, {}), _jsx(Text, { bold: true, children: "Commands" }), _jsxs(Text, { children: [spacing.indent, 'login'.padEnd(22), "authenticate with devblitz"] }), _jsxs(Text, { children: [spacing.indent, 'init <contest-id>'.padEnd(22), "join contest and setup environment"] }), _jsxs(Text, { children: [spacing.indent, 'run <chapter-uuid>'.padEnd(22), "run tests for a chapter"] }), _jsxs(Text, { children: [spacing.indent, 'status <contest-id>'.padEnd(22), "show contest progress"] }), _jsx(Text, {}), _jsx(Text, { bold: true, children: "Options" }), _jsxs(Text, { children: [spacing.indent, '-h, --help'.padEnd(22), "show help"] }), _jsxs(Text, { children: [spacing.indent, '-v, --version'.padEnd(22), "show version"] }), _jsx(Text, {}), _jsxs(Text, { dimColor: true, children: ["Run devblitz help ", '<command>', " for more info"] })] }));
50
+ };
51
+ //# sourceMappingURL=HelpView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HelpView.js","sourceRoot":"","sources":["../../src/components/HelpView.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ interface ProgressBarProps {
3
+ current: number;
4
+ total: number;
5
+ label?: string;
6
+ }
7
+ export declare const ProgressBar: React.FC<ProgressBarProps>;
8
+ export {};
9
+ //# sourceMappingURL=ProgressBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgressBar.d.ts","sourceRoot":"","sources":["../../src/components/ProgressBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAoBlD,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Box, Text } from 'ink';
4
+ import { ProgressBar as InkProgressBar } from '@inkjs/ui';
5
+ import { spacing, colors } from '../utils/theme.js';
6
+ export const ProgressBar = ({ current, total, label }) => {
7
+ const percentage = total > 0 ? current / total : 0;
8
+ return (_jsxs(Box, { flexDirection: "column", children: [label && (_jsxs(Box, { children: [_jsx(Text, { children: spacing.indent }), _jsx(Text, { dimColor: true, children: label })] })), _jsxs(Box, { children: [_jsx(Text, { children: spacing.indent }), _jsx(Box, { width: 30, children: _jsx(InkProgressBar, { value: percentage }) }), _jsxs(Text, { dimColor: true, children: [" ", current, "/", total] })] })] }));
9
+ };
10
+ //# sourceMappingURL=ProgressBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgressBar.js","sourceRoot":"","sources":["../../src/components/ProgressBar.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,WAAW,IAAI,cAAc,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAQpD,MAAM,CAAC,MAAM,WAAW,GAA+B,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IACnF,MAAM,UAAU,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnD,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACxB,KAAK,IAAI,CACR,MAAC,GAAG,eACF,KAAC,IAAI,cAAE,OAAO,CAAC,MAAM,GAAQ,EAC7B,KAAC,IAAI,IAAC,QAAQ,kBAAE,KAAK,GAAQ,IACzB,CACP,EACD,MAAC,GAAG,eACF,KAAC,IAAI,cAAE,OAAO,CAAC,MAAM,GAAQ,EAC7B,KAAC,GAAG,IAAC,KAAK,EAAE,EAAE,YACZ,KAAC,cAAc,IAAC,KAAK,EAAE,UAAU,GAAI,GACjC,EACN,MAAC,IAAI,IAAC,QAAQ,wBAAG,OAAO,OAAG,KAAK,IAAQ,IACpC,IACF,CACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ interface SpinnerProps {
3
+ label?: string;
4
+ }
5
+ /**
6
+ * Simple spinner using only Ink + React. Avoids @inkjs/ui's Spinner to prevent
7
+ * "Invalid hook call" when multiple React copies exist (e.g. React 18 from Ink
8
+ * vs React 19 elsewhere in the monorepo).
9
+ */
10
+ export declare const Spinner: React.FC<SpinnerProps>;
11
+ export {};
12
+ //# sourceMappingURL=Spinner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Spinner.d.ts","sourceRoot":"","sources":["../../src/components/Spinner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAMnD,UAAU,YAAY;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAgB1C,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useState, useEffect } from 'react';
3
+ import { Box, Text } from 'ink';
4
+ import { spacing } from '../utils/theme.js';
5
+ const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
6
+ /**
7
+ * Simple spinner using only Ink + React. Avoids @inkjs/ui's Spinner to prevent
8
+ * "Invalid hook call" when multiple React copies exist (e.g. React 18 from Ink
9
+ * vs React 19 elsewhere in the monorepo).
10
+ */
11
+ export const Spinner = ({ label }) => {
12
+ const [frame, setFrame] = useState(0);
13
+ useEffect(() => {
14
+ const t = setInterval(() => {
15
+ setFrame((f) => (f + 1) % FRAMES.length);
16
+ }, 80);
17
+ return () => clearInterval(t);
18
+ }, []);
19
+ return (_jsxs(Box, { children: [_jsxs(Text, { dimColor: true, children: [spacing.indent, FRAMES[frame]] }), label && _jsxs(Text, { dimColor: true, children: [" ", label] })] }));
20
+ };
21
+ //# sourceMappingURL=Spinner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Spinner.js","sourceRoot":"","sources":["../../src/components/Spinner.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAMlE;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAA2B,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IAC3D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEtC,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,CAAC,GAAG,WAAW,CAAC,GAAG,EAAE;YACzB,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,MAAC,GAAG,eACF,MAAC,IAAI,IAAC,QAAQ,mBAAE,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,IAAQ,EACpD,KAAK,IAAI,MAAC,IAAI,IAAC,QAAQ,wBAAG,KAAK,IAAQ,IACpC,CACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ interface StatusMessageProps {
3
+ variant: 'success' | 'error' | 'warning' | 'info';
4
+ children: React.ReactNode;
5
+ }
6
+ export declare const StatusMessage: React.FC<StatusMessageProps>;
7
+ export {};
8
+ //# sourceMappingURL=StatusMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusMessage.d.ts","sourceRoot":"","sources":["../../src/components/StatusMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,UAAU,kBAAkB;IAC1B,OAAO,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IAClD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAmCtD,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Box, Text } from 'ink';
4
+ import { symbols, spacing, colors } from '../utils/theme.js';
5
+ export const StatusMessage = ({ variant, children }) => {
6
+ const getColor = () => {
7
+ switch (variant) {
8
+ case 'success': return colors.status.success;
9
+ case 'error': return colors.status.error;
10
+ case 'warning': return colors.status.warning;
11
+ case 'info': return colors.status.info;
12
+ }
13
+ };
14
+ const getPrefix = () => {
15
+ switch (variant) {
16
+ case 'success': return symbols.success;
17
+ case 'error': return 'Error:';
18
+ case 'warning': return 'Warning:';
19
+ case 'info': return '';
20
+ }
21
+ };
22
+ const prefix = getPrefix();
23
+ const color = getColor();
24
+ return (_jsxs(Box, { children: [_jsx(Text, { children: spacing.indent }), prefix && (_jsxs(Text, { color: color, dimColor: variant !== 'error', children: [prefix, ' '] })), _jsx(Text, { color: variant === 'error' ? color : undefined, dimColor: variant === 'info', children: children })] }));
25
+ };
26
+ //# sourceMappingURL=StatusMessage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusMessage.js","sourceRoot":"","sources":["../../src/components/StatusMessage.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAO7D,MAAM,CAAC,MAAM,aAAa,GAAiC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;IACnF,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,QAAQ,OAAO,EAAE,CAAC;YAChB,KAAK,SAAS,CAAC,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;YAC7C,KAAK,OAAO,CAAC,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YACzC,KAAK,SAAS,CAAC,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;YAC7C,KAAK,MAAM,CAAC,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;QACzC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,GAAG,EAAE;QACrB,QAAQ,OAAO,EAAE,CAAC;YAChB,KAAK,SAAS,CAAC,CAAC,OAAO,OAAO,CAAC,OAAO,CAAC;YACvC,KAAK,OAAO,CAAC,CAAC,OAAO,QAAQ,CAAC;YAC9B,KAAK,SAAS,CAAC,CAAC,OAAO,UAAU,CAAC;YAClC,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC;QACzB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IAEzB,OAAO,CACL,MAAC,GAAG,eACF,KAAC,IAAI,cAAE,OAAO,CAAC,MAAM,GAAQ,EAC5B,MAAM,IAAI,CACT,MAAC,IAAI,IAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,aAC9C,MAAM,EAAE,GAAG,IACP,CACR,EACD,KAAC,IAAI,IAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,KAAK,MAAM,YAC/E,QAAQ,GACJ,IACH,CACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ interface Column {
3
+ key: string;
4
+ header: string;
5
+ width?: number;
6
+ align?: 'left' | 'right';
7
+ }
8
+ interface TableProps {
9
+ columns: Column[];
10
+ data: Record<string, string | number>[];
11
+ showHeader?: boolean;
12
+ }
13
+ export declare const Table: React.FC<TableProps>;
14
+ export {};
15
+ //# sourceMappingURL=Table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Table.d.ts","sourceRoot":"","sources":["../../src/components/Table.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,UAAU,MAAM;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,UAAU,UAAU;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CA4CtC,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Box, Text } from 'ink';
4
+ import { spacing } from '../utils/theme.js';
5
+ export const Table = ({ columns, data, showHeader = true }) => {
6
+ // Calculate column widths based on content if not specified
7
+ const getColumnWidth = (col) => {
8
+ if (col.width)
9
+ return col.width;
10
+ const headerLen = col.header.length;
11
+ const maxDataLen = data.reduce((max, row) => {
12
+ const val = String(row[col.key] ?? '');
13
+ return Math.max(max, val.length);
14
+ }, 0);
15
+ return Math.max(headerLen, maxDataLen) + 2;
16
+ };
17
+ const formatCell = (value, width, align = 'left') => {
18
+ const str = String(value ?? '');
19
+ if (align === 'right') {
20
+ return str.padStart(width);
21
+ }
22
+ return str.padEnd(width);
23
+ };
24
+ return (_jsxs(Box, { flexDirection: "column", children: [showHeader && (_jsxs(Box, { children: [_jsx(Text, { children: spacing.indent }), columns.map((col, i) => (_jsx(Text, { dimColor: true, children: formatCell(col.header, getColumnWidth(col), col.align) }, col.key)))] })), data.map((row, rowIndex) => (_jsxs(Box, { children: [_jsx(Text, { children: spacing.indent }), columns.map((col, i) => (_jsx(Text, { children: formatCell(row[col.key], getColumnWidth(col), col.align) }, col.key)))] }, rowIndex)))] }));
25
+ };
26
+ //# sourceMappingURL=Table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Table.js","sourceRoot":"","sources":["../../src/components/Table.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAe5C,MAAM,CAAC,MAAM,KAAK,GAAyB,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,EAAE,EAAE;IAClF,4DAA4D;IAC5D,MAAM,cAAc,GAAG,CAAC,GAAW,EAAU,EAAE;QAC7C,IAAI,GAAG,CAAC,KAAK;YAAE,OAAO,GAAG,CAAC,KAAK,CAAC;QAChC,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;QACpC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC1C,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACvC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC,EAAE,CAAC,CAAC,CAAC;QACN,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,CAAC,KAAkC,EAAE,KAAa,EAAE,QAA0B,MAAM,EAAU,EAAE;QACjH,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QAChC,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;YACtB,OAAO,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACxB,UAAU,IAAI,CACb,MAAC,GAAG,eACF,KAAC,IAAI,cAAE,OAAO,CAAC,MAAM,GAAQ,EAC5B,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CACvB,KAAC,IAAI,IAAe,QAAQ,kBACzB,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,IAD9C,GAAG,CAAC,GAAG,CAEX,CACR,CAAC,IACE,CACP,EACA,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,CAC3B,MAAC,GAAG,eACF,KAAC,IAAI,cAAE,OAAO,CAAC,MAAM,GAAQ,EAC5B,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CACvB,KAAC,IAAI,cACF,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,IADhD,GAAG,CAAC,GAAG,CAEX,CACR,CAAC,KANM,QAAQ,CAOZ,CACP,CAAC,IACE,CACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ interface TestResultLineProps {
3
+ name: string;
4
+ status: 'passed' | 'failed' | 'running' | 'pending';
5
+ duration?: number;
6
+ }
7
+ export declare const TestResultLine: React.FC<TestResultLineProps>;
8
+ export {};
9
+ //# sourceMappingURL=TestResultLine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestResultLine.d.ts","sourceRoot":"","sources":["../../src/components/TestResultLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAyCxD,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Box, Text } from 'ink';
4
+ import { symbols, spacing, colors } from '../utils/theme.js';
5
+ export const TestResultLine = ({ name, status, duration }) => {
6
+ const getSymbol = () => {
7
+ switch (status) {
8
+ case 'passed': return symbols.success;
9
+ case 'failed': return symbols.error;
10
+ case 'running': return ' ';
11
+ case 'pending': return ' ';
12
+ }
13
+ };
14
+ const getColor = () => {
15
+ switch (status) {
16
+ case 'passed': return colors.status.success;
17
+ case 'failed': return colors.status.error;
18
+ case 'running': return colors.text.muted;
19
+ case 'pending': return colors.text.muted;
20
+ }
21
+ };
22
+ const symbol = getSymbol();
23
+ const color = getColor();
24
+ const durationStr = duration !== undefined ? `${duration}ms` : '';
25
+ // Pad name to 50 chars for alignment
26
+ const paddedName = name.length > 48 ? name.slice(0, 45) + '...' : name;
27
+ return (_jsxs(Box, { children: [_jsx(Text, { children: spacing.indent }), _jsx(Text, { color: color, dimColor: status !== 'failed', children: symbol }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: status === 'running' || status === 'pending', children: status === 'running' ? 'running...' : paddedName }), durationStr && (_jsxs(Text, { dimColor: true, children: [" ", durationStr.padStart(8)] }))] }));
28
+ };
29
+ //# sourceMappingURL=TestResultLine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestResultLine.js","sourceRoot":"","sources":["../../src/components/TestResultLine.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAQ7D,MAAM,CAAC,MAAM,cAAc,GAAkC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC1F,MAAM,SAAS,GAAG,GAAG,EAAE;QACrB,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,QAAQ,CAAC,CAAC,OAAO,OAAO,CAAC,OAAO,CAAC;YACtC,KAAK,QAAQ,CAAC,CAAC,OAAO,OAAO,CAAC,KAAK,CAAC;YACpC,KAAK,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC;YAC3B,KAAK,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,QAAQ,CAAC,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;YAC5C,KAAK,QAAQ,CAAC,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YAC1C,KAAK,SAAS,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;YACzC,KAAK,SAAS,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;QAC3C,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,WAAW,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAElE,qCAAqC;IACrC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAEvE,OAAO,CACL,MAAC,GAAG,eACF,KAAC,IAAI,cAAE,OAAO,CAAC,MAAM,GAAQ,EAC7B,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,QAAQ,YAC9C,MAAM,GACF,EACP,KAAC,IAAI,oBAAS,EACd,KAAC,IAAI,IAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,YACzD,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,GAC5C,EACN,WAAW,IAAI,CACd,MAAC,IAAI,IAAC,QAAQ,wBAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAQ,CACjD,IACG,CACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { Spinner } from './Spinner.js';
2
+ export { StatusMessage } from './StatusMessage.js';
3
+ export { TestResultLine } from './TestResultLine.js';
4
+ export { ProgressBar } from './ProgressBar.js';
5
+ export { Table } from './Table.js';
6
+ export { Header } from './Header.js';
7
+ export { HelpView } from './HelpView.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { Spinner } from './Spinner.js';
2
+ export { StatusMessage } from './StatusMessage.js';
3
+ export { TestResultLine } from './TestResultLine.js';
4
+ export { ProgressBar } from './ProgressBar.js';
5
+ export { Table } from './Table.js';
6
+ export { Header } from './Header.js';
7
+ export { HelpView } from './HelpView.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+ import React from 'react';
3
+ import { render } from 'ink';
4
+ import { program } from 'commander';
5
+ import { Login } from './commands/login.js';
6
+ import { Init } from './commands/init.js';
7
+ import { Run } from './commands/run.js';
8
+ import { Status } from './commands/status.js';
9
+ import { HelpView } from './components/HelpView.js';
10
+ // Pre-process arguments to handle help flags
11
+ const args = process.argv.slice(2);
12
+ // If no arguments or just --help/-h, show our custom help
13
+ if (args.length === 0 || (args.length === 1 && (args[0] === '--help' || args[0] === '-h'))) {
14
+ render(React.createElement(HelpView, {}));
15
+ process.exit(0);
16
+ }
17
+ // Handle help <command>
18
+ if (args[0] === 'help') {
19
+ render(React.createElement(HelpView, { command: args[1] }));
20
+ process.exit(0);
21
+ }
22
+ program
23
+ .name('devblitz')
24
+ .description('CLI for DevBlitz coding contests')
25
+ .version('1.0.0')
26
+ .allowUnknownOption(false);
27
+ program
28
+ .command('login')
29
+ .description('Authenticate with DevBlitz')
30
+ .option('-l, --logout', 'Log out from DevBlitz')
31
+ .action((options) => {
32
+ render(React.createElement(Login, { logoutFlag: options.logout }));
33
+ });
34
+ program
35
+ .command('init <contestId>')
36
+ .description('Join a contest and setup environment')
37
+ .action((contestId) => {
38
+ render(React.createElement(Init, { contestId }));
39
+ });
40
+ program
41
+ .command('run <chapterUuid>')
42
+ .description('Run tests for a chapter')
43
+ .action((chapterUuid) => {
44
+ render(React.createElement(Run, { chapterUuid }));
45
+ });
46
+ program
47
+ .command('status <contestId>')
48
+ .description('Show your contest progress')
49
+ .action((contestId) => {
50
+ render(React.createElement(Status, { contestId }));
51
+ });
52
+ // Handle unknown commands
53
+ program.on('command:*', () => {
54
+ render(React.createElement(HelpView, {}));
55
+ process.exit(1);
56
+ });
57
+ // Parse arguments
58
+ program.parse();
59
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { type AxiosInstance } from "axios";
2
+ export declare function getApiClient(): AxiosInstance;
3
+ export declare function apiRequest<T>(method: "get" | "post" | "put" | "delete", url: string, data?: any): Promise<T>;
4
+ export declare function getBaseUrl(): string;
5
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/utils/api.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,aAAa,EAAc,MAAM,OAAO,CAAC;AAQ9D,wBAAgB,YAAY,IAAI,aAAa,CAwC5C;AAED,wBAAsB,UAAU,CAAC,CAAC,EAC9B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,EACzC,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,GAAG,GACX,OAAO,CAAC,CAAC,CAAC,CAqBZ;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC"}
@@ -0,0 +1,60 @@
1
+ import axios, { AxiosError } from "axios";
2
+ import { getAuthToken, getSessionCookie } from "./auth.js";
3
+ const DEFAULT_BASE_URL = process.env.DEVBLITZ_API_URL || "http://localhost:8000";
4
+ let apiClient = null;
5
+ export function getApiClient() {
6
+ if (!apiClient) {
7
+ apiClient = axios.create({
8
+ baseURL: DEFAULT_BASE_URL,
9
+ withCredentials: true,
10
+ headers: {
11
+ "Content-Type": "application/json",
12
+ },
13
+ });
14
+ apiClient.interceptors.request.use((config) => {
15
+ const token = getAuthToken();
16
+ const cookie = getSessionCookie();
17
+ // If we have a token, use Bearer auth
18
+ if (token) {
19
+ config.headers.Authorization = `Bearer ${token}`;
20
+ }
21
+ if (cookie && !token) {
22
+ config.headers.Cookie = cookie;
23
+ }
24
+ return config;
25
+ });
26
+ apiClient.interceptors.response.use((response) => response, (error) => {
27
+ if (error.response?.status === 401) {
28
+ console.error("\n Error: Authentication required. Please run: devblitz login");
29
+ }
30
+ return Promise.reject(error);
31
+ });
32
+ }
33
+ return apiClient;
34
+ }
35
+ export async function apiRequest(method, url, data) {
36
+ const client = getApiClient();
37
+ try {
38
+ const response = await client.request({
39
+ method,
40
+ url,
41
+ data,
42
+ });
43
+ return response.data;
44
+ }
45
+ catch (error) {
46
+ if (error.response) {
47
+ const message = error.response.data?.message ||
48
+ error.response.data?.error ||
49
+ error.response.data?.success === false
50
+ ? error.response.data?.message || "API request failed"
51
+ : "API request failed";
52
+ throw new Error(message);
53
+ }
54
+ throw error;
55
+ }
56
+ }
57
+ export function getBaseUrl() {
58
+ return DEFAULT_BASE_URL;
59
+ }
60
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/utils/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAsB,UAAU,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE3D,MAAM,gBAAgB,GAClB,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,uBAAuB,CAAC;AAE5D,IAAI,SAAS,GAAyB,IAAI,CAAC;AAE3C,MAAM,UAAU,YAAY;IACxB,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC;YACrB,OAAO,EAAE,gBAAgB;YACzB,eAAe,EAAE,IAAI;YACrB,OAAO,EAAE;gBACL,cAAc,EAAE,kBAAkB;aACrC;SACJ,CAAC,CAAC;QAEH,SAAS,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1C,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;YAElC,sCAAsC;YACtC,IAAI,KAAK,EAAE,CAAC;gBACR,MAAM,CAAC,OAAO,CAAC,aAAa,GAAG,UAAU,KAAK,EAAE,CAAC;YACrD,CAAC;YAED,IAAI,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;gBACnB,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;YACnC,CAAC;YAED,OAAO,MAAM,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAC/B,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,EACtB,CAAC,KAAiB,EAAE,EAAE;YAClB,IAAI,KAAK,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;gBACjC,OAAO,CAAC,KAAK,CACT,gEAAgE,CACnE,CAAC;YACN,CAAC;YACD,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC,CACJ,CAAC;IACN,CAAC;IAED,OAAO,SAAS,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC5B,MAAyC,EACzC,GAAW,EACX,IAAU;IAEV,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAI;YACrC,MAAM;YACN,GAAG;YACH,IAAI;SACP,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,IAAS,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACjB,MAAM,OAAO,GACT,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO;gBAC5B,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK;gBAC1B,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,KAAK,KAAK;gBAClC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,IAAI,oBAAoB;gBACtD,CAAC,CAAC,oBAAoB,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;QACD,MAAM,KAAK,CAAC;IAChB,CAAC;AACL,CAAC;AAED,MAAM,UAAU,UAAU;IACtB,OAAO,gBAAgB,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,24 @@
1
+ export interface AuthCredentials {
2
+ email: string;
3
+ password: string;
4
+ }
5
+ export interface AuthResponse {
6
+ user: {
7
+ id: string;
8
+ email: string;
9
+ name: string;
10
+ role: string;
11
+ };
12
+ session: {
13
+ token: string;
14
+ };
15
+ }
16
+ export declare function login(credentials: AuthCredentials): Promise<AuthResponse>;
17
+ export declare function logout(): void;
18
+ export declare function getAuthToken(): string | null;
19
+ export declare function getSessionCookie(): string | null;
20
+ export declare function getCurrentUser(): any;
21
+ export declare function isAuthenticated(): boolean;
22
+ export declare function setApiUrl(url: string): void;
23
+ export declare function getApiUrl(): string;
24
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/utils/auth.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE;QACF,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,OAAO,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;KACjB,CAAC;CACL;AAED,wBAAsB,KAAK,CACvB,WAAW,EAAE,eAAe,GAC7B,OAAO,CAAC,YAAY,CAAC,CA4DvB;AAED,wBAAgB,MAAM,IAAI,IAAI,CAI7B;AAED,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEhD;AAED,wBAAgB,cAAc,IAAI,GAAG,CAEpC;AAED,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC"}
@@ -0,0 +1,79 @@
1
+ import ConfigStore from "configstore";
2
+ import axios from "axios";
3
+ const config = new ConfigStore("devblitz", {
4
+ token: null,
5
+ sessionCookie: null,
6
+ user: null,
7
+ apiUrl: process.env.DEVBLITZ_API_URL || "http://localhost:8000",
8
+ });
9
+ export async function login(credentials) {
10
+ const apiUrl = config.get("apiUrl");
11
+ try {
12
+ const response = await axios.post(`${apiUrl}/api/auth/sign-in/email`, {
13
+ email: credentials.email,
14
+ password: credentials.password,
15
+ }, {
16
+ withCredentials: true,
17
+ headers: {
18
+ "Content-Type": "application/json",
19
+ },
20
+ });
21
+ const cookies = response.headers["set-cookie"] || [];
22
+ const sessionCookie = cookies.find((c) => c.startsWith("better-auth.session_token") ||
23
+ c.includes("better-auth.session_token"));
24
+ if (sessionCookie) {
25
+ const cookieValue = sessionCookie.split(";")[0];
26
+ config.set("sessionCookie", cookieValue);
27
+ }
28
+ if (response.data?.user) {
29
+ config.set("user", response.data.user);
30
+ }
31
+ if (response.data?.session?.token) {
32
+ config.set("token", response.data.session.token);
33
+ }
34
+ return {
35
+ user: response.data.user || {
36
+ id: "",
37
+ email: credentials.email,
38
+ name: "",
39
+ role: "PARTICIPANT",
40
+ },
41
+ session: {
42
+ token: response.data?.session?.token || "",
43
+ },
44
+ };
45
+ }
46
+ catch (error) {
47
+ if (error.response?.status === 401) {
48
+ throw new Error("Invalid email or password");
49
+ }
50
+ if (error.response?.status === 400) {
51
+ throw new Error(error.response.data?.message || "Invalid request");
52
+ }
53
+ throw new Error(error.response?.data?.message || error.message || "Login failed");
54
+ }
55
+ }
56
+ export function logout() {
57
+ config.delete("token");
58
+ config.delete("sessionCookie");
59
+ config.delete("user");
60
+ }
61
+ export function getAuthToken() {
62
+ return config.get("token") || null;
63
+ }
64
+ export function getSessionCookie() {
65
+ return config.get("sessionCookie") || null;
66
+ }
67
+ export function getCurrentUser() {
68
+ return config.get("user") || null;
69
+ }
70
+ export function isAuthenticated() {
71
+ return !!(getAuthToken() || getSessionCookie());
72
+ }
73
+ export function setApiUrl(url) {
74
+ config.set("apiUrl", url);
75
+ }
76
+ export function getApiUrl() {
77
+ return config.get("apiUrl");
78
+ }
79
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/utils/auth.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,UAAU,EAAE;IACvC,KAAK,EAAE,IAAI;IACX,aAAa,EAAE,IAAI;IACnB,IAAI,EAAE,IAAI;IACV,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,uBAAuB;CAClE,CAAC,CAAC;AAmBH,MAAM,CAAC,KAAK,UAAU,KAAK,CACvB,WAA4B;IAE5B,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEpC,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAC7B,GAAG,MAAM,yBAAyB,EAClC;YACI,KAAK,EAAE,WAAW,CAAC,KAAK;YACxB,QAAQ,EAAE,WAAW,CAAC,QAAQ;SACjC,EACD;YACI,eAAe,EAAE,IAAI;YACrB,OAAO,EAAE;gBACL,cAAc,EAAE,kBAAkB;aACrC;SACJ,CACJ,CAAC;QAEF,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;QACrD,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAC9B,CAAC,CAAS,EAAE,EAAE,CACV,CAAC,CAAC,UAAU,CAAC,2BAA2B,CAAC;YACzC,CAAC,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAC9C,CAAC;QAEF,IAAI,aAAa,EAAE,CAAC;YAChB,MAAM,WAAW,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAChD,MAAM,CAAC,GAAG,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;QAC7C,CAAC;QAED,IAAI,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,CAAC;QAED,IAAI,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YAChC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACrD,CAAC;QAED,OAAO;YACH,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI;gBACxB,EAAE,EAAE,EAAE;gBACN,KAAK,EAAE,WAAW,CAAC,KAAK;gBACxB,IAAI,EAAE,EAAE;gBACR,IAAI,EAAE,aAAa;aACtB;YACD,OAAO,EAAE;gBACL,KAAK,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE;aAC7C;SACJ,CAAC;IACN,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,IAAI,KAAK,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QACjD,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,IAAI,iBAAiB,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,IAAI,KAAK,CACX,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,cAAc,CACnE,CAAC;IACN,CAAC;AACL,CAAC;AAED,MAAM,UAAU,MAAM;IAClB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACvB,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAC/B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,YAAY;IACxB,OAAO,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC5B,OAAO,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,IAAI,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,cAAc;IAC1B,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,eAAe;IAC3B,OAAO,CAAC,CAAC,CAAC,YAAY,EAAE,IAAI,gBAAgB,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAW;IACjC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,SAAS;IACrB,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import ora from "ora";
2
+ export declare function createSpinner(text: string): ora.Ora;
3
+ export declare function success(message: string): void;
4
+ export declare function error(message: string): void;
5
+ export declare function info(message: string): void;
6
+ export declare function warn(message: string): void;
7
+ export declare function formatTimeRemaining(ms: number): string;
8
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AAGtB,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,WAKzC;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,QAEtC;AAED,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,QAEpC;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,QAEnC;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,QAEnC;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAYtD"}