@hiyve/cli 1.0.11 → 1.0.13

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/README.md CHANGED
@@ -67,7 +67,7 @@ Templates: `basic`, `ai`, `full`
67
67
 
68
68
  ## Getting Your API Key
69
69
 
70
- 1. Log in to the [Hiyve Developer Console](https://console.hiyve.dev)
70
+ 1. Log in to the [Hiyve Developer Console](https://api.hiyve.dev)
71
71
  2. Navigate to **API Keys** in the sidebar
72
72
  3. Copy your secret key (starts with `sk_test_` or `sk_live_`)
73
73
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hiyve/cli",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "Hiyve SDK CLI - Configure npm for private @hiyve packages",
5
5
  "type": "module",
6
6
  "bin": {
@@ -217,7 +217,7 @@ export default defineConfig({
217
217
  }
218
218
 
219
219
  function generateEnvExample(template) {
220
- let env = `# Hiyve API Key (from console.hiyve.dev)
220
+ let env = `# Hiyve API Key (from api.hiyve.dev)
221
221
  HIYVE_API_KEY=pk_live_your_api_key_here
222
222
 
223
223
  # Room configuration
@@ -6,7 +6,7 @@
6
6
 
7
7
  import chalk from 'chalk';
8
8
  import ora from 'ora';
9
- import { getApiUrl } from '../config.js';
9
+ import { getApiUrl, isDevMode } from '../config.js';
10
10
  import { getCurrentConfig } from '../utils/npmrc.js';
11
11
 
12
12
  /**
@@ -16,6 +16,9 @@ export async function list() {
16
16
  console.log('');
17
17
  console.log(chalk.cyan('Available @hiyve Packages'));
18
18
  console.log(chalk.gray('─'.repeat(40)));
19
+ if (isDevMode()) {
20
+ console.log(chalk.yellow(' Mode: development (--dev)'));
21
+ }
19
22
  console.log('');
20
23
 
21
24
  // Get current config for auth token
@@ -41,6 +44,14 @@ export async function list() {
41
44
  const error = await response.json().catch(() => ({ error: 'Unknown error' }));
42
45
  console.log('');
43
46
  console.log(chalk.red(` ${error.error || 'Failed to fetch packages'}`));
47
+ if (isDevMode()) {
48
+ console.log(chalk.gray(' You are using --dev mode (development registry).'));
49
+ console.log(chalk.gray(' If you meant to use production, run without --dev:'));
50
+ console.log(chalk.cyan(' npx @hiyve/cli list'));
51
+ } else {
52
+ console.log(chalk.gray(' If you meant to use the development registry, use --dev:'));
53
+ console.log(chalk.cyan(' npx @hiyve/cli --dev list'));
54
+ }
44
55
  process.exit(1);
45
56
  }
46
57
 
@@ -74,7 +85,15 @@ export async function list() {
74
85
  spinner.fail('Connection failed');
75
86
  console.log('');
76
87
  console.log(chalk.red(` ${err.message}`));
77
- console.log(chalk.gray(' Please check your internet connection'));
88
+ console.log(chalk.gray(' Please check your internet connection.'));
89
+ if (isDevMode()) {
90
+ console.log(chalk.gray(' You are using --dev mode (development registry).'));
91
+ console.log(chalk.gray(' If you meant to use production, run without --dev:'));
92
+ console.log(chalk.cyan(' npx @hiyve/cli list'));
93
+ } else {
94
+ console.log(chalk.gray(' If you meant to use the development registry, use --dev:'));
95
+ console.log(chalk.cyan(' npx @hiyve/cli --dev list'));
96
+ }
78
97
  process.exit(1);
79
98
  }
80
99
  }
@@ -8,7 +8,7 @@ import prompts from 'prompts';
8
8
  import chalk from 'chalk';
9
9
  import ora from 'ora';
10
10
  import { configureNpmrc } from '../utils/npmrc.js';
11
- import { getApiUrl, getRegistryUrl } from '../config.js';
11
+ import { getApiUrl, getRegistryUrl, isDevMode } from '../config.js';
12
12
 
13
13
  /**
14
14
  * Login to Hiyve and configure npm
@@ -21,6 +21,9 @@ export async function login(options) {
21
21
  console.log('');
22
22
  console.log(chalk.cyan('Hiyve SDK Authentication'));
23
23
  console.log(chalk.gray('─'.repeat(40)));
24
+ if (isDevMode()) {
25
+ console.log(chalk.yellow(' Mode: development (--dev)'));
26
+ }
24
27
  console.log('');
25
28
 
26
29
  // Prompt for API key if not provided
@@ -28,11 +31,14 @@ export async function login(options) {
28
31
  const response = await prompts({
29
32
  type: 'password',
30
33
  name: 'apiKey',
31
- message: 'Enter your Hiyve API key:',
34
+ message: 'Enter your Hiyve API key (pk_*):',
32
35
  validate: (value) => {
33
36
  if (!value) return 'API key is required';
34
- if (!value.startsWith('sk_') && !value.startsWith('mk_')) {
35
- return 'API key should start with sk_test_, sk_live_, or mk_';
37
+ if (!value.startsWith('pk_')) {
38
+ if (value.startsWith('sk_')) {
39
+ return 'Secret keys (sk_*) are no longer needed for registry login. Use your API key (pk_*) from console.hiyve.dev';
40
+ }
41
+ return 'Expected an API key starting with pk_test_ or pk_live_ (from console.hiyve.dev)';
36
42
  }
37
43
  if (value.length < 35) return 'API key appears to be too short';
38
44
  return true;
@@ -48,17 +54,26 @@ export async function login(options) {
48
54
  apiKey = response.apiKey;
49
55
  }
50
56
 
51
- // Validate API key format (sk_test_*, sk_live_*, or legacy mk_*)
57
+ // Validate API key format
58
+ const isPublicKey = apiKey.match(/^pk_(test|live)_[a-fA-F0-9]+$/);
59
+
60
+ // Accept legacy sk_ and mk_ keys for backward compatibility (existing users)
52
61
  const isSecretKey = apiKey.match(/^sk_(test|live)_[a-fA-F0-9]+$/);
53
62
  const isManagementKey = apiKey.match(/^mk_[a-fA-F0-9]{32}$/);
54
63
 
55
- if (!isSecretKey && !isManagementKey) {
64
+ if (!isPublicKey && !isSecretKey && !isManagementKey) {
56
65
  console.log('');
57
66
  console.log(chalk.red('✗ Invalid API key format'));
58
- console.log(chalk.gray(' Expected: sk_test_* or sk_live_* (from console.hiyve.dev)'));
67
+ console.log(chalk.gray(' Expected: pk_test_* or pk_live_* (from console.hiyve.dev)'));
59
68
  process.exit(1);
60
69
  }
61
70
 
71
+ if (isSecretKey) {
72
+ console.log(chalk.yellow(' Note: Secret keys (sk_*) still work but are no longer required.'));
73
+ console.log(chalk.yellow(' You can use your API key (pk_*) instead for registry access.'));
74
+ console.log('');
75
+ }
76
+
62
77
  // Verify API key with registry
63
78
  const spinner = ora('Verifying API key...').start();
64
79
 
@@ -74,6 +89,14 @@ export async function login(options) {
74
89
  spinner.fail('API key verification failed');
75
90
  console.log('');
76
91
  console.log(chalk.red(` ${error.error || 'Invalid API key'}`));
92
+ if (isDevMode()) {
93
+ console.log(chalk.gray(' You are using --dev mode (development registry).'));
94
+ console.log(chalk.gray(' If you meant to use production, run without --dev:'));
95
+ console.log(chalk.cyan(' npx @hiyve/cli login'));
96
+ } else {
97
+ console.log(chalk.gray(' If you are using a test key (pk_test_*), use --dev mode:'));
98
+ console.log(chalk.cyan(' npx @hiyve/cli --dev login'));
99
+ }
77
100
  process.exit(1);
78
101
  }
79
102
 
@@ -87,7 +110,15 @@ export async function login(options) {
87
110
  spinner.fail('Connection failed');
88
111
  console.log('');
89
112
  console.log(chalk.red(` ${err.message}`));
90
- console.log(chalk.gray(' Please check your internet connection'));
113
+ console.log(chalk.gray(' Please check your internet connection.'));
114
+ if (isDevMode()) {
115
+ console.log(chalk.gray(' You are using --dev mode (development registry).'));
116
+ console.log(chalk.gray(' If you meant to use production, run without --dev:'));
117
+ console.log(chalk.cyan(' npx @hiyve/cli login'));
118
+ } else {
119
+ console.log(chalk.gray(' If you meant to use the development registry, use --dev:'));
120
+ console.log(chalk.cyan(' npx @hiyve/cli --dev login'));
121
+ }
91
122
  process.exit(1);
92
123
  }
93
124
 
package/src/config.js CHANGED
@@ -34,6 +34,13 @@ export function getRegistryUrl() {
34
34
  return _devMode ? DEV_API_URL : PROD_API_URL;
35
35
  }
36
36
 
37
+ /**
38
+ * Check if dev mode is currently active.
39
+ */
40
+ export function isDevMode() {
41
+ return _devMode;
42
+ }
43
+
37
44
  // Backwards-compatible named export
38
45
  export const REGISTRY_URL = PROD_API_URL;
39
46
 
@@ -42,4 +49,5 @@ export default {
42
49
  getApiUrl,
43
50
  getRegistryUrl,
44
51
  setDevMode,
52
+ isDevMode,
45
53
  };
@@ -32,7 +32,8 @@ export async function configureNpmrc(registryUrl, apiKey) {
32
32
  !trimmed.includes('//api.hiyve.dev/') &&
33
33
  !trimmed.includes('//api.muziemedia.com/') &&
34
34
  !trimmed.includes(':_authToken=mk_') &&
35
- !trimmed.includes(':_authToken=sk_')
35
+ !trimmed.includes(':_authToken=sk_') &&
36
+ !trimmed.includes(':_authToken=pk_')
36
37
  );
37
38
  });
38
39
 
@@ -68,7 +69,8 @@ export async function removeNpmrc() {
68
69
  !trimmed.includes('//api.hiyve.dev/') &&
69
70
  !trimmed.includes('//api.muziemedia.com/') &&
70
71
  !trimmed.includes(':_authToken=mk_') &&
71
- !trimmed.includes(':_authToken=sk_')
72
+ !trimmed.includes(':_authToken=sk_') &&
73
+ !trimmed.includes(':_authToken=pk_')
72
74
  );
73
75
  });
74
76
 
@@ -92,18 +94,18 @@ export function getCurrentConfig() {
92
94
  // Find registry line
93
95
  const registryLine = lines.find((line) => line.trim().startsWith('@hiyve:registry'));
94
96
 
95
- // Find token line (sk_* or legacy mk_*)
97
+ // Find token line (pk_*, sk_*, or legacy mk_*)
96
98
  const tokenLine = lines.find((line) => {
97
99
  const trimmed = line.trim();
98
- return trimmed.includes(':_authToken=sk_') || trimmed.includes(':_authToken=mk_');
100
+ return trimmed.includes(':_authToken=pk_') || trimmed.includes(':_authToken=sk_') || trimmed.includes(':_authToken=mk_');
99
101
  });
100
102
 
101
103
  if (!registryLine || !tokenLine) {
102
104
  return null;
103
105
  }
104
106
 
105
- // Extract API key (sk_* or legacy mk_*)
106
- const tokenMatch = tokenLine.match(/:_authToken=((?:sk_|mk_)[a-zA-Z0-9_]+)/);
107
+ // Extract API key (pk_*, sk_*, or legacy mk_*)
108
+ const tokenMatch = tokenLine.match(/:_authToken=((?:pk_|sk_|mk_)[a-zA-Z0-9_]+)/);
107
109
  const apiKey = tokenMatch ? tokenMatch[1] : null;
108
110
 
109
111
  // Mask API key for display
@@ -32,6 +32,19 @@ describe('configureNpmrc', () => {
32
32
  expect(content).toContain(':_authToken=sk_live_abc123def456');
33
33
  });
34
34
 
35
+ it('creates .npmrc with pk_ key', async () => {
36
+ fs.existsSync.mockReturnValue(false);
37
+ fs.writeFileSync.mockImplementation(() => {});
38
+
39
+ await configureNpmrc('https://api.hiyve.dev/registry/', 'pk_live_abc123def456');
40
+
41
+ expect(fs.writeFileSync).toHaveBeenCalledOnce();
42
+ const [writePath, content] = fs.writeFileSync.mock.calls[0];
43
+ expect(writePath).toBe(NPMRC_PATH);
44
+ expect(content).toContain('@hiyve:registry=https://api.hiyve.dev/registry/');
45
+ expect(content).toContain(':_authToken=pk_live_abc123def456');
46
+ });
47
+
35
48
  it('replaces existing @hiyve lines when .npmrc already has them', async () => {
36
49
  const existingContent = [
37
50
  '@hiyve:registry=https://old-registry.example.com/',
@@ -54,6 +67,42 @@ describe('configureNpmrc', () => {
54
67
  expect(content).toContain(':_authToken=sk_live_newkey5678');
55
68
  });
56
69
 
70
+ it('replaces existing sk_ token with pk_ key', async () => {
71
+ const existingContent = [
72
+ '@hiyve:registry=https://api.hiyve.dev/registry/',
73
+ '//api.hiyve.dev/registry/:_authToken=sk_live_oldkey1234',
74
+ 'other-config=value',
75
+ ].join('\n');
76
+
77
+ fs.existsSync.mockReturnValue(true);
78
+ fs.readFileSync.mockReturnValue(existingContent);
79
+ fs.writeFileSync.mockImplementation(() => {});
80
+
81
+ await configureNpmrc('https://api.hiyve.dev/registry/', 'pk_live_newkey5678');
82
+
83
+ const [, content] = fs.writeFileSync.mock.calls[0];
84
+ expect(content).not.toContain('sk_live_oldkey1234');
85
+ expect(content).toContain(':_authToken=pk_live_newkey5678');
86
+ });
87
+
88
+ it('replaces existing pk_ token with new pk_ key', async () => {
89
+ const existingContent = [
90
+ '@hiyve:registry=https://api.hiyve.dev/registry/',
91
+ '//api.hiyve.dev/registry/:_authToken=pk_test_oldkey1234',
92
+ 'other-config=value',
93
+ ].join('\n');
94
+
95
+ fs.existsSync.mockReturnValue(true);
96
+ fs.readFileSync.mockReturnValue(existingContent);
97
+ fs.writeFileSync.mockImplementation(() => {});
98
+
99
+ await configureNpmrc('https://api.hiyve.dev/registry/', 'pk_live_newkey5678');
100
+
101
+ const [, content] = fs.writeFileSync.mock.calls[0];
102
+ expect(content).not.toContain('pk_test_oldkey1234');
103
+ expect(content).toContain(':_authToken=pk_live_newkey5678');
104
+ });
105
+
57
106
  it('replaces legacy mk_ tokens', async () => {
58
107
  const existingContent = [
59
108
  '@hiyve:registry=https://console.hiyve.dev/api/registry/',
@@ -172,6 +221,47 @@ describe('removeNpmrc', () => {
172
221
  expect(content).not.toContain('sk_live_abc123def456');
173
222
  });
174
223
 
224
+ it('removes @hiyve lines with pk_ tokens', async () => {
225
+ const existingContent = [
226
+ 'registry=https://registry.npmjs.org/',
227
+ '@hiyve:registry=https://api.hiyve.dev/registry/',
228
+ '//api.hiyve.dev/registry/:_authToken=pk_live_abc123def456',
229
+ 'other-config=true',
230
+ ].join('\n');
231
+
232
+ fs.existsSync.mockReturnValue(true);
233
+ fs.readFileSync.mockReturnValue(existingContent);
234
+ fs.writeFileSync.mockImplementation(() => {});
235
+
236
+ await removeNpmrc();
237
+
238
+ const [, content] = fs.writeFileSync.mock.calls[0];
239
+ expect(content).not.toContain('@hiyve:registry');
240
+ expect(content).not.toContain('api.hiyve.dev');
241
+ expect(content).not.toContain('pk_live_abc123def456');
242
+ expect(content).toContain('other-config=true');
243
+ });
244
+
245
+ it('removes @hiyve lines with pk_ tokens (old registry)', async () => {
246
+ const existingContent = [
247
+ 'registry=https://registry.npmjs.org/',
248
+ '@hiyve:registry=https://console.hiyve.dev/api/registry/',
249
+ '//console.hiyve.dev/api/registry/:_authToken=pk_test_abc123def456',
250
+ 'other-config=true',
251
+ ].join('\n');
252
+
253
+ fs.existsSync.mockReturnValue(true);
254
+ fs.readFileSync.mockReturnValue(existingContent);
255
+ fs.writeFileSync.mockImplementation(() => {});
256
+
257
+ await removeNpmrc();
258
+
259
+ const [, content] = fs.writeFileSync.mock.calls[0];
260
+ expect(content).not.toContain('@hiyve:registry');
261
+ expect(content).not.toContain('console.hiyve.dev');
262
+ expect(content).not.toContain('pk_test_abc123def456');
263
+ });
264
+
175
265
  it('removes @hiyve lines with legacy mk_ tokens', async () => {
176
266
  const existingContent = [
177
267
  'registry=https://registry.npmjs.org/',
@@ -243,6 +333,40 @@ describe('getCurrentConfig', () => {
243
333
  expect(getCurrentConfig()).toBeNull();
244
334
  });
245
335
 
336
+ it('returns config for pk_ keys (new registry)', () => {
337
+ const content = [
338
+ '@hiyve:registry=https://api.hiyve.dev/registry/',
339
+ '//api.hiyve.dev/registry/:_authToken=pk_live_1a2b3c4d5e6f7890abcd',
340
+ ].join('\n');
341
+
342
+ fs.existsSync.mockReturnValue(true);
343
+ fs.readFileSync.mockReturnValue(content);
344
+
345
+ const result = getCurrentConfig();
346
+ expect(result).toEqual({
347
+ apiKey: 'pk_live_1a2b3c4d5e6f7890abcd',
348
+ maskedApiKey: 'pk_live_...abcd',
349
+ registryUrl: 'https://api.hiyve.dev/registry/',
350
+ });
351
+ });
352
+
353
+ it('returns config for pk_ keys (old registry — backward compat)', () => {
354
+ const content = [
355
+ '@hiyve:registry=https://console.hiyve.dev/api/registry/',
356
+ '//console.hiyve.dev/api/registry/:_authToken=pk_test_1a2b3c4d5e6f7890abcd',
357
+ ].join('\n');
358
+
359
+ fs.existsSync.mockReturnValue(true);
360
+ fs.readFileSync.mockReturnValue(content);
361
+
362
+ const result = getCurrentConfig();
363
+ expect(result).toEqual({
364
+ apiKey: 'pk_test_1a2b3c4d5e6f7890abcd',
365
+ maskedApiKey: 'pk_test_...abcd',
366
+ registryUrl: 'https://console.hiyve.dev/api/registry/',
367
+ });
368
+ });
369
+
246
370
  it('returns config for sk_ keys (new registry)', () => {
247
371
  const content = [
248
372
  '@hiyve:registry=https://api.hiyve.dev/registry/',
@@ -294,7 +418,7 @@ describe('getCurrentConfig', () => {
294
418
  });
295
419
  });
296
420
 
297
- it('maskedApiKey shows first 8 and last 4 chars', () => {
421
+ it('maskedApiKey shows first 8 and last 4 chars for sk_ keys', () => {
298
422
  const apiKey = 'sk_test_aabbccdd11223344eeff';
299
423
  const content = [
300
424
  '@hiyve:registry=https://api.hiyve.dev/registry/',
@@ -309,6 +433,21 @@ describe('getCurrentConfig', () => {
309
433
  expect(result.maskedApiKey).toBe('sk_test_...eeff');
310
434
  });
311
435
 
436
+ it('maskedApiKey shows first 8 and last 4 chars for pk_ keys', () => {
437
+ const apiKey = 'pk_live_aabbccdd11223344eeff';
438
+ const content = [
439
+ '@hiyve:registry=https://api.hiyve.dev/registry/',
440
+ `//api.hiyve.dev/registry/:_authToken=${apiKey}`,
441
+ ].join('\n');
442
+
443
+ fs.existsSync.mockReturnValue(true);
444
+ fs.readFileSync.mockReturnValue(content);
445
+
446
+ const result = getCurrentConfig();
447
+ expect(result.apiKey).toBe(apiKey);
448
+ expect(result.maskedApiKey).toBe('pk_live_...eeff');
449
+ });
450
+
312
451
  it('returns null when only registry line is present but no token', () => {
313
452
  const content = '@hiyve:registry=https://api.hiyve.dev/registry/\n';
314
453