@newpeak/barista-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.
Files changed (82) hide show
  1. package/.eslintrc.json +23 -0
  2. package/.prettierrc +9 -0
  3. package/.sisyphus/notepads/liberica-employees/learnings.md +73 -0
  4. package/AGENTS.md +270 -0
  5. package/CONTRIBUTING.md +291 -0
  6. package/README.md +707 -0
  7. package/bin/barista +6 -0
  8. package/bin/barista.js +3 -0
  9. package/docs/ARCHITECTURE.md +184 -0
  10. package/docs/COMMANDS.md +352 -0
  11. package/docs/COMMAND_DESIGN_SPEC.md +811 -0
  12. package/docs/INTEGRATION_NOTES.md +270 -0
  13. package/docs/commands/REFERENCE.md +297 -0
  14. package/docs/commands/arabica/auth/index.md +296 -0
  15. package/docs/commands/liberica/auth/index.md +133 -0
  16. package/docs/commands/liberica/context/index.md +60 -0
  17. package/docs/commands/liberica/employees/create.md +185 -0
  18. package/docs/commands/liberica/employees/disable.md +138 -0
  19. package/docs/commands/liberica/employees/enable.md +137 -0
  20. package/docs/commands/liberica/employees/get.md +153 -0
  21. package/docs/commands/liberica/employees/list.md +168 -0
  22. package/docs/commands/liberica/employees/update.md +180 -0
  23. package/docs/commands/liberica/orgs/list.md +62 -0
  24. package/docs/commands/liberica/positions/list.md +61 -0
  25. package/docs/commands/liberica/roles/list.md +67 -0
  26. package/docs/commands/liberica/users/create.md +170 -0
  27. package/docs/commands/liberica/users/get.md +151 -0
  28. package/docs/commands/liberica/users/list.md +175 -0
  29. package/package.json +37 -0
  30. package/src/commands/arabica/auth/index.ts +277 -0
  31. package/src/commands/arabica/auth/login.ts +5 -0
  32. package/src/commands/arabica/auth/logout.ts +5 -0
  33. package/src/commands/arabica/auth/register.ts +5 -0
  34. package/src/commands/arabica/auth/status.ts +5 -0
  35. package/src/commands/arabica/index.ts +23 -0
  36. package/src/commands/auth.ts +107 -0
  37. package/src/commands/context.ts +60 -0
  38. package/src/commands/liberica/auth/index.ts +170 -0
  39. package/src/commands/liberica/context/index.ts +43 -0
  40. package/src/commands/liberica/employees/create.ts +275 -0
  41. package/src/commands/liberica/employees/delete.ts +122 -0
  42. package/src/commands/liberica/employees/disable.ts +97 -0
  43. package/src/commands/liberica/employees/enable.ts +97 -0
  44. package/src/commands/liberica/employees/get.ts +115 -0
  45. package/src/commands/liberica/employees/index.ts +23 -0
  46. package/src/commands/liberica/employees/list.ts +131 -0
  47. package/src/commands/liberica/employees/update.ts +157 -0
  48. package/src/commands/liberica/index.ts +36 -0
  49. package/src/commands/liberica/orgs/index.ts +35 -0
  50. package/src/commands/liberica/positions/index.ts +30 -0
  51. package/src/commands/liberica/roles/index.ts +59 -0
  52. package/src/commands/liberica/users/create.ts +132 -0
  53. package/src/commands/liberica/users/delete.ts +49 -0
  54. package/src/commands/liberica/users/disable.ts +41 -0
  55. package/src/commands/liberica/users/enable.ts +30 -0
  56. package/src/commands/liberica/users/get.ts +46 -0
  57. package/src/commands/liberica/users/index.ts +27 -0
  58. package/src/commands/liberica/users/list.ts +68 -0
  59. package/src/commands/liberica/users/me.ts +42 -0
  60. package/src/commands/liberica/users/reset-password.ts +42 -0
  61. package/src/commands/liberica/users/update.ts +48 -0
  62. package/src/core/api/client.ts +825 -0
  63. package/src/core/auth/token-manager.ts +183 -0
  64. package/src/core/config/manager.ts +164 -0
  65. package/src/index.ts +37 -0
  66. package/src/types/employee.ts +102 -0
  67. package/src/types/index.ts +75 -0
  68. package/src/types/org.ts +25 -0
  69. package/src/types/position.ts +24 -0
  70. package/src/types/user.ts +64 -0
  71. package/tests/unit/commands/arabica/auth.test.ts +230 -0
  72. package/tests/unit/commands/liberica/auth.test.ts +175 -0
  73. package/tests/unit/commands/liberica/context.test.ts +98 -0
  74. package/tests/unit/commands/liberica/employees/create.test.ts +463 -0
  75. package/tests/unit/commands/liberica/employees/disable.test.ts +82 -0
  76. package/tests/unit/commands/liberica/employees/enable.test.ts +82 -0
  77. package/tests/unit/commands/liberica/employees/get.test.ts +111 -0
  78. package/tests/unit/commands/liberica/employees/list.test.ts +294 -0
  79. package/tests/unit/commands/liberica/employees/update.test.ts +210 -0
  80. package/tests/unit/config.test.ts +141 -0
  81. package/tests/unit/types.test.ts +195 -0
  82. package/tsconfig.json +20 -0
@@ -0,0 +1,141 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import os from 'os';
5
+
6
+ // Mock dependencies before importing ConfigManager
7
+ vi.mock('fs');
8
+ vi.mock('os');
9
+ vi.mock('yaml');
10
+
11
+ describe('ConfigManager', () => {
12
+ const mockConfig = {
13
+ defaults: {
14
+ env: 'dev',
15
+ tenant: 'test-tenant',
16
+ service: 'liberica',
17
+ },
18
+ environments: {
19
+ dev: {
20
+ liberica: { baseUrl: 'https://{tenant}-dev.newpeaksh.com', timeout: 30000 },
21
+ arabica: { baseUrl: 'https://arabica-dev.newpeaksh.com', timeout: 30000 },
22
+ },
23
+ test: {
24
+ liberica: { baseUrl: 'https://{tenant}-test.newpeaksh.com', timeout: 30000 },
25
+ arabica: { baseUrl: 'https://arabica-test.newpeaksh.com', timeout: 30000 },
26
+ },
27
+ 'prod-cn': {
28
+ liberica: { baseUrl: 'https://{tenant}.newpeaksh.com', timeout: 60000 },
29
+ arabica: { baseUrl: 'https://www.newpeaksh.com', timeout: 60000 },
30
+ },
31
+ 'prod-jp': {
32
+ liberica: { baseUrl: 'https://{tenant}.newpeakjp.com', timeout: 60000 },
33
+ arabica: { baseUrl: 'https://members.newpeakjp.com', timeout: 60000 },
34
+ },
35
+ },
36
+ output: {
37
+ format: 'table',
38
+ color: true,
39
+ timestamp: true,
40
+ },
41
+ };
42
+
43
+ beforeEach(() => {
44
+ vi.clearAllMocks();
45
+ vi.resetModules();
46
+ });
47
+
48
+ describe('getCurrentContext', () => {
49
+ it('should return current context with default values', () => {
50
+ // This test verifies the interface
51
+ const context = {
52
+ environment: 'dev' as const,
53
+ service: 'liberica' as const,
54
+ tenant: 'test-tenant',
55
+ };
56
+
57
+ expect(context.environment).toBe('dev');
58
+ expect(context.service).toBe('liberica');
59
+ expect(context.tenant).toBe('test-tenant');
60
+ });
61
+
62
+ it('should have correct environment values', () => {
63
+ const environments = ['dev', 'test', 'prod-cn', 'prod-jp'] as const;
64
+ environments.forEach((env) => {
65
+ expect(['dev', 'test', 'prod-cn', 'prod-jp']).toContain(env);
66
+ });
67
+ });
68
+ });
69
+
70
+ describe('setEnvironment', () => {
71
+ it('should validate environment values', () => {
72
+ const validEnvironments = ['dev', 'test', 'prod-cn', 'prod-jp'];
73
+ const invalidEnvironment = 'invalid-env';
74
+
75
+ expect(validEnvironments.includes('dev')).toBe(true);
76
+ expect(validEnvironments.includes(invalidEnvironment)).toBe(false);
77
+ });
78
+ });
79
+
80
+ describe('setTenant', () => {
81
+ it('should accept any non-empty string as tenant', () => {
82
+ const validTenant = 'my-tenant';
83
+ const emptyTenant = '';
84
+
85
+ expect(validTenant.length > 0).toBe(true);
86
+ expect(emptyTenant.length > 0).toBe(false);
87
+ });
88
+ });
89
+
90
+ describe('config structure', () => {
91
+ it('should have all required environment configurations', () => {
92
+ const envNames = Object.keys(mockConfig.environments);
93
+ expect(envNames).toContain('dev');
94
+ expect(envNames).toContain('test');
95
+ expect(envNames).toContain('prod-cn');
96
+ expect(envNames).toContain('prod-jp');
97
+ });
98
+
99
+ it('should have correct service URLs for each environment', () => {
100
+ const devConfig = mockConfig.environments.dev;
101
+ expect(devConfig.liberica.baseUrl).toContain('{tenant}-dev.newpeaksh.com');
102
+ expect(devConfig.arabica.baseUrl).toContain('arabica-dev.newpeaksh.com');
103
+ });
104
+
105
+ it('should have output configuration', () => {
106
+ expect(mockConfig.output.format).toBe('table');
107
+ expect(typeof mockConfig.output.color).toBe('boolean');
108
+ expect(typeof mockConfig.output.timestamp).toBe('boolean');
109
+ });
110
+ });
111
+
112
+ describe('getEnvironmentUrl', () => {
113
+ it('should build correct URL with tenant placeholder', () => {
114
+ const urlTemplate = 'https://{tenant}-dev.newpeaksh.com';
115
+ const tenant = 'mytenant';
116
+ const result = urlTemplate.replace('{tenant}', tenant);
117
+
118
+ expect(result).toBe('https://mytenant-dev.newpeaksh.com');
119
+ });
120
+
121
+ it('should return arabica URL without tenant substitution', () => {
122
+ const arabicaUrl = 'https://arabica-dev.newpeaksh.com';
123
+ // Arabica doesn't use tenant in URL
124
+ expect(arabicaUrl).not.toContain('{tenant}');
125
+ });
126
+ });
127
+ });
128
+
129
+ describe('Context interface', () => {
130
+ it('should have required properties', () => {
131
+ const context = {
132
+ environment: 'dev' as const,
133
+ service: 'liberica' as const,
134
+ tenant: 'electionjp',
135
+ };
136
+
137
+ expect(context).toHaveProperty('environment');
138
+ expect(context).toHaveProperty('service');
139
+ expect(context).toHaveProperty('tenant');
140
+ });
141
+ });
@@ -0,0 +1,195 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import type { APIResponse, CommandOptions, Context, Config, TokenContext, Environment, Service } from '../../src/types/index.js';
3
+
4
+ describe('APIResponse interface', () => {
5
+ it('should accept valid success response', () => {
6
+ const response: APIResponse = {
7
+ success: true,
8
+ data: { id: '123', name: 'Test' },
9
+ meta: {
10
+ requestId: 'req-001',
11
+ timestamp: '2024-01-15T10:30:00Z',
12
+ pagination: {
13
+ page: 1,
14
+ size: 20,
15
+ total: 100,
16
+ totalPages: 5,
17
+ },
18
+ },
19
+ };
20
+
21
+ expect(response.success).toBe(true);
22
+ expect(response.data).toBeDefined();
23
+ expect(response.meta?.pagination?.page).toBe(1);
24
+ });
25
+
26
+ it('should accept valid error response', () => {
27
+ const response: APIResponse = {
28
+ success: false,
29
+ error: {
30
+ code: 'NOT_FOUND',
31
+ message: 'Resource not found',
32
+ details: { resourceId: '123' },
33
+ },
34
+ };
35
+
36
+ expect(response.success).toBe(false);
37
+ expect(response.error?.code).toBe('NOT_FOUND');
38
+ expect(response.error?.message).toBe('Resource not found');
39
+ });
40
+
41
+ it('should allow data to be undefined', () => {
42
+ const response: APIResponse = {
43
+ success: true,
44
+ };
45
+
46
+ expect(response.data).toBeUndefined();
47
+ });
48
+
49
+ it('should support generic type parameter', () => {
50
+ interface Order {
51
+ id: string;
52
+ productName: string;
53
+ quantity: number;
54
+ }
55
+
56
+ const response: APIResponse<Order[]> = {
57
+ success: true,
58
+ data: [
59
+ { id: '1', productName: 'Coffee Machine', quantity: 10 },
60
+ { id: '2', productName: 'Grinder', quantity: 5 },
61
+ ],
62
+ };
63
+
64
+ expect(response.data).toHaveLength(2);
65
+ expect(response.data?.[0].productName).toBe('Coffee Machine');
66
+ });
67
+ });
68
+
69
+ describe('CommandOptions interface', () => {
70
+ it('should accept all optional command options', () => {
71
+ const options: CommandOptions = {
72
+ env: 'dev',
73
+ tenant: 'electionjp',
74
+ dryRun: true,
75
+ json: false,
76
+ debug: true,
77
+ };
78
+
79
+ expect(options.env).toBe('dev');
80
+ expect(options.tenant).toBe('electionjp');
81
+ expect(options.dryRun).toBe(true);
82
+ expect(options.json).toBe(false);
83
+ expect(options.debug).toBe(true);
84
+ });
85
+
86
+ it('should allow partial options', () => {
87
+ const options: CommandOptions = {
88
+ env: 'prod-cn',
89
+ };
90
+
91
+ expect(options.env).toBe('prod-cn');
92
+ expect(options.tenant).toBeUndefined();
93
+ expect(options.dryRun).toBeUndefined();
94
+ });
95
+ });
96
+
97
+ describe('Context interface', () => {
98
+ it('should have correct structure', () => {
99
+ const context: Context = {
100
+ environment: 'test',
101
+ service: 'arabica',
102
+ tenant: 'my-tenant',
103
+ };
104
+
105
+ expect(context.environment).toBe('test');
106
+ expect(context.service).toBe('arabica');
107
+ expect(context.tenant).toBe('my-tenant');
108
+ });
109
+ });
110
+
111
+ describe('Environment type', () => {
112
+ it('should accept valid environment values', () => {
113
+ const envs: Environment[] = ['dev', 'test', 'prod-cn', 'prod-jp'];
114
+
115
+ envs.forEach((env) => {
116
+ const context: Context = { environment: env, service: 'liberica', tenant: 't' };
117
+ expect(context.environment).toBe(env);
118
+ });
119
+ });
120
+ });
121
+
122
+ describe('Service type', () => {
123
+ it('should accept valid service values', () => {
124
+ const services: Service[] = ['liberica', 'arabica'];
125
+
126
+ services.forEach((service) => {
127
+ const context: Context = { environment: 'dev', service, tenant: 't' };
128
+ expect(context.service).toBe(service);
129
+ });
130
+ });
131
+ });
132
+
133
+ describe('Config interface', () => {
134
+ it('should have defaults structure', () => {
135
+ const config: Config = {
136
+ defaults: {
137
+ env: 'dev',
138
+ tenant: 'default',
139
+ service: 'liberica',
140
+ },
141
+ environments: {
142
+ dev: {
143
+ liberica: { baseUrl: 'https://dev.example.com', timeout: 30000 },
144
+ arabica: { baseUrl: 'https://arabica-dev.example.com', timeout: 30000 },
145
+ },
146
+ test: {
147
+ liberica: { baseUrl: 'https://test.example.com', timeout: 30000 },
148
+ arabica: { baseUrl: 'https://arabica-test.example.com', timeout: 30000 },
149
+ },
150
+ 'prod-cn': {
151
+ liberica: { baseUrl: 'https://example.com', timeout: 60000 },
152
+ arabica: { baseUrl: 'https://www.example.com', timeout: 60000 },
153
+ },
154
+ 'prod-jp': {
155
+ liberica: { baseUrl: 'https://example.jp', timeout: 60000 },
156
+ arabica: { baseUrl: 'https://members.example.jp', timeout: 60000 },
157
+ },
158
+ },
159
+ output: {
160
+ format: 'table',
161
+ color: true,
162
+ timestamp: true,
163
+ },
164
+ };
165
+
166
+ expect(config.defaults.env).toBe('dev');
167
+ expect(config.defaults.tenant).toBe('default');
168
+ expect(config.environments.dev.liberica.baseUrl).toContain('dev.example.com');
169
+ });
170
+ });
171
+
172
+ describe('TokenContext interface', () => {
173
+ it('should accept valid token context without tenant', () => {
174
+ const context: TokenContext = {
175
+ service: 'arabica',
176
+ environment: 'dev',
177
+ };
178
+
179
+ expect(context.service).toBe('arabica');
180
+ expect(context.environment).toBe('dev');
181
+ expect(context.tenant).toBeUndefined();
182
+ });
183
+
184
+ it('should accept valid token context with tenant', () => {
185
+ const context: TokenContext = {
186
+ service: 'liberica',
187
+ environment: 'prod-cn',
188
+ tenant: 'electionjp',
189
+ };
190
+
191
+ expect(context.service).toBe('liberica');
192
+ expect(context.environment).toBe('prod-cn');
193
+ expect(context.tenant).toBe('electionjp');
194
+ });
195
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ES2022",
5
+ "moduleResolution": "node",
6
+ "lib": ["ES2022"],
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "declaration": true,
10
+ "declarationMap": true,
11
+ "sourceMap": true,
12
+ "strict": true,
13
+ "esModuleInterop": true,
14
+ "skipLibCheck": true,
15
+ "forceConsistentCasingInFileNames": true,
16
+ "resolveJsonModule": true
17
+ },
18
+ "include": ["src/**/*"],
19
+ "exclude": ["node_modules", "dist", "tests"]
20
+ }