@harborclient/sdk 0.7.0 → 1.0.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.
Files changed (81) hide show
  1. package/dist/build/index.d.ts +59 -0
  2. package/dist/build/index.d.ts.map +1 -0
  3. package/dist/build/index.js +116 -0
  4. package/dist/client.d.ts +2 -2
  5. package/dist/components/index.d.ts +1 -0
  6. package/dist/components/index.d.ts.map +1 -1
  7. package/dist/components/index.js +1 -0
  8. package/dist/components/portalToBody.d.ts +11 -0
  9. package/dist/components/portalToBody.d.ts.map +1 -0
  10. package/dist/components/portalToBody.js +15 -0
  11. package/dist/eslint/index.d.ts +9 -0
  12. package/dist/eslint/index.d.ts.map +1 -0
  13. package/dist/eslint/index.js +18 -0
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/main.d.ts +1 -1
  17. package/dist/main.d.ts.map +1 -1
  18. package/dist/runtime/index.d.ts +1 -1
  19. package/dist/runtime/jsx-dev-runtime.d.ts +1 -1
  20. package/dist/runtime/jsx-runtime-host.d.ts +44 -0
  21. package/dist/runtime/jsx-runtime-host.js +42 -0
  22. package/dist/runtime/react-dom.d.ts +1 -0
  23. package/dist/runtime/react-dom.js +16 -0
  24. package/dist/runtime/react.d.ts +6 -0
  25. package/dist/runtime/react.js +70 -2
  26. package/dist/runtime/reactHost.js +52 -0
  27. package/dist/runtime/store.d.ts +106 -0
  28. package/dist/runtime/store.d.ts.map +1 -1
  29. package/dist/runtime/store.js +100 -0
  30. package/dist/runtime/store.ts +211 -0
  31. package/dist/runtime/viewHost.js +2 -1
  32. package/dist/runtime-utils.d.ts +59 -0
  33. package/dist/runtime-utils.d.ts.map +1 -1
  34. package/dist/runtime-utils.js +66 -0
  35. package/dist/storage/index.d.ts +1 -0
  36. package/dist/storage/index.d.ts.map +1 -1
  37. package/dist/storage/index.js +1 -0
  38. package/dist/storage/validate.d.ts +71 -0
  39. package/dist/storage/validate.d.ts.map +1 -0
  40. package/dist/storage/validate.js +111 -0
  41. package/dist/types.d.ts +14 -0
  42. package/dist/types.d.ts.map +1 -1
  43. package/package.json +37 -8
  44. package/tsconfig.base.json +15 -0
  45. package/dist/components/enhanceControl.test.d.ts +0 -2
  46. package/dist/components/enhanceControl.test.d.ts.map +0 -1
  47. package/dist/components/enhanceControl.test.js +0 -83
  48. package/dist/components/utils.test.d.ts +0 -2
  49. package/dist/components/utils.test.d.ts.map +0 -1
  50. package/dist/components/utils.test.js +0 -44
  51. package/dist/http/resolveRequest.test.d.ts +0 -2
  52. package/dist/http/resolveRequest.test.d.ts.map +0 -1
  53. package/dist/http/resolveRequest.test.js +0 -40
  54. package/dist/http/substitute.test.d.ts +0 -2
  55. package/dist/http/substitute.test.d.ts.map +0 -1
  56. package/dist/http/substitute.test.js +0 -93
  57. package/dist/pluginDatabaseApi.test.d.ts +0 -2
  58. package/dist/pluginDatabaseApi.test.d.ts.map +0 -1
  59. package/dist/pluginDatabaseApi.test.js +0 -65
  60. package/dist/runtime/index.test.d.ts +0 -2
  61. package/dist/runtime/index.test.d.ts.map +0 -1
  62. package/dist/runtime/index.test.js +0 -41
  63. package/dist/runtime/index.test.ts +0 -53
  64. package/dist/runtime-utils.test.d.ts +0 -2
  65. package/dist/runtime-utils.test.d.ts.map +0 -1
  66. package/dist/runtime-utils.test.js +0 -104
  67. package/dist/signing/signing.test.d.ts +0 -2
  68. package/dist/signing/signing.test.d.ts.map +0 -1
  69. package/dist/signing/signing.test.js +0 -100
  70. package/dist/storage/cappedList.test.d.ts +0 -2
  71. package/dist/storage/cappedList.test.d.ts.map +0 -1
  72. package/dist/storage/cappedList.test.js +0 -11
  73. package/dist/utilities.test.d.ts +0 -2
  74. package/dist/utilities.test.d.ts.map +0 -1
  75. package/dist/utilities.test.js +0 -16
  76. package/dist/variables/dynamic.test.d.ts +0 -2
  77. package/dist/variables/dynamic.test.d.ts.map +0 -1
  78. package/dist/variables/dynamic.test.js +0 -60
  79. package/dist/variables/tokens.test.d.ts +0 -2
  80. package/dist/variables/tokens.test.d.ts.map +0 -1
  81. package/dist/variables/tokens.test.js +0 -160
@@ -1,93 +0,0 @@
1
- import { describe, expect, it } from '@jest/globals';
2
- import { resolveAuthVariables, substituteKeyValueRows, substituteVariables } from './substitute.js';
3
- describe('substituteVariables', () => {
4
- it('replaces known placeholders', () => {
5
- expect(substituteVariables('{{host}}/api', { host: 'https://example.com' })).toBe('https://example.com/api');
6
- });
7
- it('allows whitespace inside braces', () => {
8
- expect(substituteVariables('{{ host }}/api', { host: 'https://example.com' })).toBe('https://example.com/api');
9
- });
10
- it('supports dotted and hyphenated keys', () => {
11
- expect(substituteVariables('{{api.base}}-{{api-key}}', {
12
- 'api.base': 'https://example.com',
13
- 'api-key': 'secret'
14
- })).toBe('https://example.com-secret');
15
- });
16
- it('replaces multiple placeholders in one string', () => {
17
- expect(substituteVariables('{{scheme}}://{{host}}/{{path}}', {
18
- scheme: 'https',
19
- host: 'example.com',
20
- path: 'users'
21
- })).toBe('https://example.com/users');
22
- });
23
- it('leaves unknown placeholders unchanged', () => {
24
- expect(substituteVariables('{{missing}}/api', { host: 'https://example.com' })).toBe('{{missing}}/api');
25
- });
26
- it('replaces with empty string when variable is defined as empty', () => {
27
- expect(substituteVariables('prefix{{token}}suffix', { token: '' })).toBe('prefixsuffix');
28
- });
29
- it('returns text unchanged when there are no placeholders', () => {
30
- expect(substituteVariables('plain text', { host: 'https://example.com' })).toBe('plain text');
31
- });
32
- it('resolves dynamic variables when not in the runtime map', () => {
33
- const result = substituteVariables('prefix{{$timestamp}}suffix', {});
34
- expect(result).not.toContain('{{');
35
- expect(result).toMatch(/^prefix\d+suffix$/);
36
- });
37
- it('prefers runtime variables over dynamic variables', () => {
38
- expect(substituteVariables('{{$timestamp}}', { $timestamp: 'fixed' })).toBe('fixed');
39
- });
40
- });
41
- describe('resolveAuthVariables', () => {
42
- const auth = {
43
- type: 'basic',
44
- basic: {
45
- username: '{{user}}',
46
- password: '{{pass}}'
47
- },
48
- bearer: {
49
- token: '{{token}}'
50
- }
51
- };
52
- it('substitutes basic and bearer credential fields', () => {
53
- const substitute = (text) => text.replace('{{user}}', 'alice').replace('{{pass}}', 'secret').replace('{{token}}', 'tok');
54
- expect(resolveAuthVariables(auth, substitute)).toEqual({
55
- type: 'basic',
56
- basic: {
57
- username: 'alice',
58
- password: 'secret'
59
- },
60
- bearer: {
61
- token: 'tok'
62
- }
63
- });
64
- });
65
- it('preserves auth type and structure', () => {
66
- const substitute = (text) => text;
67
- const resolved = resolveAuthVariables(auth, substitute);
68
- expect(resolved.type).toBe('basic');
69
- expect(resolved.basic).toEqual(auth.basic);
70
- expect(resolved.bearer).toEqual(auth.bearer);
71
- });
72
- });
73
- describe('substituteKeyValueRows', () => {
74
- it('substitutes values while preserving row metadata', () => {
75
- const rows = [
76
- { key: 'Accept', value: '{{accept}}', enabled: true },
77
- { key: 'X-Api-Key', value: 'static', enabled: false }
78
- ];
79
- expect(substituteKeyValueRows(rows, { accept: 'application/json' })).toEqual([
80
- { key: 'Accept', value: 'application/json', enabled: true },
81
- { key: 'X-Api-Key', value: 'static', enabled: false }
82
- ]);
83
- });
84
- it('leaves unknown placeholders in row values', () => {
85
- const rows = [{ key: 'Host', value: '{{host}}', enabled: true }];
86
- expect(substituteKeyValueRows(rows, {})).toEqual([
87
- { key: 'Host', value: '{{host}}', enabled: true }
88
- ]);
89
- });
90
- it('returns an empty array for no rows', () => {
91
- expect(substituteKeyValueRows([], { host: 'example.com' })).toEqual([]);
92
- });
93
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=pluginDatabaseApi.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pluginDatabaseApi.test.d.ts","sourceRoot":"","sources":["../src/pluginDatabaseApi.test.ts"],"names":[],"mappings":""}
@@ -1,65 +0,0 @@
1
- import { describe, expect, it, jest } from '@jest/globals';
2
- import { createPluginDatabaseApi } from './runtime/pluginDatabaseApi.js';
3
- /**
4
- * Builds a mock database backend for unit tests.
5
- */
6
- function createMockBackend() {
7
- return {
8
- query: jest.fn(async () => undefined),
9
- exec: jest.fn(async () => undefined),
10
- beginTransaction: jest.fn(async () => 'txn-1'),
11
- endTransaction: jest.fn(async () => undefined)
12
- };
13
- }
14
- describe('createPluginDatabaseApi', () => {
15
- it('forwards get, all, and run with the correct query modes', async () => {
16
- const backend = createMockBackend();
17
- backend.query
18
- .mockResolvedValueOnce({ id: 1 })
19
- .mockResolvedValueOnce([{ id: 1 }, { id: 2 }])
20
- .mockResolvedValueOnce({ changes: 1, lastInsertRowid: 42 });
21
- const db = createPluginDatabaseApi(backend);
22
- await expect(db.get('SELECT 1', [1])).resolves.toEqual({ id: 1 });
23
- await expect(db.all('SELECT *', [2])).resolves.toEqual([{ id: 1 }, { id: 2 }]);
24
- await expect(db.run('INSERT INTO t VALUES (?)', [3])).resolves.toEqual({
25
- changes: 1,
26
- lastInsertRowid: 42
27
- });
28
- expect(backend.query).toHaveBeenNthCalledWith(1, 'get', 'SELECT 1', [1], undefined);
29
- expect(backend.query).toHaveBeenNthCalledWith(2, 'all', 'SELECT *', [2], undefined);
30
- expect(backend.query).toHaveBeenNthCalledWith(3, 'run', 'INSERT INTO t VALUES (?)', [3], undefined);
31
- });
32
- it('forwards exec unchanged', async () => {
33
- const backend = createMockBackend();
34
- const db = createPluginDatabaseApi(backend);
35
- await db.exec('CREATE TABLE t (id INTEGER)');
36
- expect(backend.exec).toHaveBeenCalledWith('CREATE TABLE t (id INTEGER)');
37
- });
38
- it('commits successful transactions and passes txnId to tx helpers', async () => {
39
- const backend = createMockBackend();
40
- backend.query.mockResolvedValue({ changes: 1, lastInsertRowid: 1 });
41
- const db = createPluginDatabaseApi(backend);
42
- const result = await db.transaction(async (tx) => {
43
- await tx.run('INSERT INTO t VALUES (?)', [1]);
44
- await tx.all('SELECT * FROM t');
45
- return 'done';
46
- });
47
- expect(result).toBe('done');
48
- expect(backend.beginTransaction).toHaveBeenCalledTimes(1);
49
- expect(backend.endTransaction).toHaveBeenCalledWith('txn-1', 'commit');
50
- expect(backend.query).toHaveBeenCalledWith('run', 'INSERT INTO t VALUES (?)', [1], 'txn-1');
51
- expect(backend.query).toHaveBeenCalledWith('all', 'SELECT * FROM t', undefined, 'txn-1');
52
- });
53
- it('rolls back failed transactions', async () => {
54
- const backend = createMockBackend();
55
- const db = createPluginDatabaseApi(backend);
56
- const boom = new Error('boom');
57
- await expect(db.transaction(async (tx) => {
58
- await tx.run('INSERT INTO t VALUES (?)', [1]);
59
- throw boom;
60
- })).rejects.toThrow(boom);
61
- expect(backend.beginTransaction).toHaveBeenCalledTimes(1);
62
- expect(backend.endTransaction).toHaveBeenCalledWith('txn-1', 'rollback');
63
- expect(backend.endTransaction).not.toHaveBeenCalledWith('txn-1', 'commit');
64
- });
65
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=index.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/runtime/index.test.ts"],"names":[],"mappings":""}
@@ -1,41 +0,0 @@
1
- import { describe, expect, it, jest } from '@jest/globals';
2
- import { defineTheme, registerTheme } from './index.js';
3
- /**
4
- * Builds a minimal plugin context mock for registerTheme tests.
5
- */
6
- function createMockPluginContext() {
7
- const disposable = { dispose: jest.fn() };
8
- const registerMock = jest.fn(() => disposable);
9
- const subscriptions = [];
10
- return {
11
- subscriptions,
12
- themes: { register: registerMock },
13
- registerMock
14
- };
15
- }
16
- describe('registerTheme', () => {
17
- it('registers the theme, pushes the disposable onto subscriptions, and returns it', () => {
18
- const hc = createMockPluginContext();
19
- const theme = {
20
- id: 'solarized',
21
- title: 'Solarized Dark',
22
- type: 'dark',
23
- colors: { surface: '#002b36' }
24
- };
25
- const disposable = registerTheme(hc, theme);
26
- expect(hc.registerMock).toHaveBeenCalledWith(theme);
27
- expect(hc.subscriptions).toHaveLength(1);
28
- expect(hc.subscriptions[0]).toBe(disposable);
29
- });
30
- });
31
- describe('defineTheme', () => {
32
- it('returns the theme argument unchanged', () => {
33
- const theme = {
34
- id: 'nord',
35
- title: 'Nord',
36
- type: 'dark',
37
- stylesheet: 'dist/theme.css'
38
- };
39
- expect(defineTheme(theme)).toBe(theme);
40
- });
41
- });
@@ -1,53 +0,0 @@
1
- import { describe, expect, it, jest } from '@jest/globals';
2
- import type { PluginContext, ThemeContribution } from '../types';
3
- import { defineTheme, registerTheme } from './index.js';
4
-
5
- /**
6
- * Builds a minimal plugin context mock for registerTheme tests.
7
- */
8
- function createMockPluginContext(): PluginContext & {
9
- registerMock: jest.MockedFunction<PluginContext['themes']['register']>;
10
- } {
11
- const disposable = { dispose: jest.fn() };
12
- const registerMock = jest.fn(() => disposable);
13
- const subscriptions: PluginContext['subscriptions'] = [];
14
-
15
- return {
16
- subscriptions,
17
- themes: { register: registerMock },
18
- registerMock
19
- } as unknown as PluginContext & {
20
- registerMock: jest.MockedFunction<PluginContext['themes']['register']>;
21
- };
22
- }
23
-
24
- describe('registerTheme', () => {
25
- it('registers the theme, pushes the disposable onto subscriptions, and returns it', () => {
26
- const hc = createMockPluginContext();
27
- const theme: ThemeContribution = {
28
- id: 'solarized',
29
- title: 'Solarized Dark',
30
- type: 'dark',
31
- colors: { surface: '#002b36' }
32
- };
33
-
34
- const disposable = registerTheme(hc, theme);
35
-
36
- expect(hc.registerMock).toHaveBeenCalledWith(theme);
37
- expect(hc.subscriptions).toHaveLength(1);
38
- expect(hc.subscriptions[0]).toBe(disposable);
39
- });
40
- });
41
-
42
- describe('defineTheme', () => {
43
- it('returns the theme argument unchanged', () => {
44
- const theme: ThemeContribution = {
45
- id: 'nord',
46
- title: 'Nord',
47
- type: 'dark',
48
- stylesheet: 'dist/theme.css'
49
- };
50
-
51
- expect(defineTheme(theme)).toBe(theme);
52
- });
53
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=runtime-utils.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"runtime-utils.test.d.ts","sourceRoot":"","sources":["../src/runtime-utils.test.ts"],"names":[],"mappings":""}
@@ -1,104 +0,0 @@
1
- import { afterEach, describe, expect, it, jest } from '@jest/globals';
2
- import { byteLength, randomId, truncateBody, truncateToBytes } from './runtime-utils.js';
3
- const originalTextEncoder = globalThis.TextEncoder;
4
- const originalCrypto = globalThis.crypto;
5
- afterEach(() => {
6
- globalThis.TextEncoder = originalTextEncoder;
7
- globalThis.crypto = originalCrypto;
8
- jest.restoreAllMocks();
9
- });
10
- function withoutTextEncoder(run) {
11
- // @ts-expect-error — exercise manual UTF-8 fallback used in SES main runtime
12
- globalThis.TextEncoder = undefined;
13
- return run();
14
- }
15
- describe('randomId', () => {
16
- it('returns a UUID when crypto.randomUUID is available', () => {
17
- const spy = jest
18
- .spyOn(globalThis.crypto, 'randomUUID')
19
- .mockReturnValue('00000000-0000-4000-8000-000000000000');
20
- expect(randomId()).toBe('00000000-0000-4000-8000-000000000000');
21
- spy.mockRestore();
22
- });
23
- it('falls back to a prefixed id when randomUUID is unavailable', () => {
24
- // @ts-expect-error — exercise SES main-runtime fallback
25
- globalThis.crypto = undefined;
26
- expect(randomId('req')).toMatch(/^req-\d+-[a-z0-9]+$/);
27
- });
28
- it('uses the default prefix in the fallback path', () => {
29
- // @ts-expect-error — exercise SES main-runtime fallback
30
- globalThis.crypto = undefined;
31
- expect(randomId()).toMatch(/^id-\d+-[a-z0-9]+$/);
32
- });
33
- });
34
- describe('byteLength', () => {
35
- it('counts ASCII as one byte per character', () => {
36
- expect(byteLength('abc')).toBe(3);
37
- expect(byteLength('')).toBe(0);
38
- });
39
- it('counts two-byte UTF-8 characters', () => {
40
- expect(byteLength('é')).toBe(2);
41
- });
42
- it('counts three-byte UTF-8 characters', () => {
43
- expect(byteLength('中')).toBe(3);
44
- });
45
- it('counts surrogate pairs as four bytes', () => {
46
- expect(byteLength('😀')).toBe(4);
47
- });
48
- it('matches TextEncoder when the manual fallback is used', () => {
49
- const samples = ['plain', 'é', '中', '😀', 'mix é 中 😀'];
50
- for (const sample of samples) {
51
- const encodedLength = new originalTextEncoder().encode(sample).length;
52
- withoutTextEncoder(() => {
53
- expect(byteLength(sample)).toBe(encodedLength);
54
- });
55
- }
56
- });
57
- });
58
- describe('truncateToBytes', () => {
59
- it('returns the original string when it fits', () => {
60
- expect(truncateToBytes('hello', 10)).toBe('hello');
61
- expect(truncateToBytes('é', 2)).toBe('é');
62
- });
63
- it('truncates multibyte text without splitting code units', () => {
64
- expect(truncateToBytes('éé', 2)).toBe('é');
65
- expect(truncateToBytes('abc', 2)).toBe('ab');
66
- });
67
- it('returns an empty string when maxBytes is zero', () => {
68
- expect(truncateToBytes('hello', 0)).toBe('');
69
- });
70
- it('excludes an incomplete surrogate pair in the manual fallback', () => {
71
- withoutTextEncoder(() => {
72
- expect(truncateToBytes('a😀b', 2)).toBe('a');
73
- });
74
- });
75
- it('does not split multibyte characters in the manual fallback', () => {
76
- withoutTextEncoder(() => {
77
- expect(truncateToBytes('mix é end', 5)).toBe('mix ');
78
- expect(truncateToBytes('中文字', 3)).toBe('中');
79
- });
80
- });
81
- });
82
- describe('truncateBody', () => {
83
- it('returns the body unchanged when within the byte limit', () => {
84
- expect(truncateBody('{"ok":true}', 100)).toEqual({
85
- body: '{"ok":true}',
86
- truncated: false
87
- });
88
- });
89
- it('truncates and appends the default suffix when over the limit', () => {
90
- const body = 'x'.repeat(20);
91
- const maxBytes = 10;
92
- const result = truncateBody(body, maxBytes);
93
- expect(result.truncated).toBe(true);
94
- expect(result.body.endsWith(`[truncated — body exceeded ${maxBytes} bytes]`)).toBe(true);
95
- expect(byteLength(result.body.replace(/\n\n\[truncated — body exceeded \d+ bytes\]$/, ''))).toBeLessThanOrEqual(maxBytes);
96
- });
97
- it('uses a custom suffix when provided', () => {
98
- const result = truncateBody('0123456789', 5, '…');
99
- expect(result).toEqual({
100
- body: '01234…',
101
- truncated: true
102
- });
103
- });
104
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=signing.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"signing.test.d.ts","sourceRoot":"","sources":["../../src/signing/signing.test.ts"],"names":[],"mappings":""}
@@ -1,100 +0,0 @@
1
- import { describe, expect, it } from '@jest/globals';
2
- import { writeFileSync } from 'node:fs';
3
- import { join } from 'node:path';
4
- import { signPlugin } from './sign.js';
5
- import { createTestPluginDir, createTestSigningKeys } from './testFixtures.js';
6
- import { verifyPlugin } from './verify.js';
7
- describe('signPlugin', () => {
8
- it('writes signature.json for a valid plugin directory', async () => {
9
- const keys = createTestSigningKeys();
10
- const fixture = createTestPluginDir();
11
- try {
12
- const result = await signPlugin({
13
- pluginDir: fixture.pluginDir,
14
- privateKeyPem: keys.privateKeyPem,
15
- keyId: 'test-key'
16
- });
17
- expect(result.signature.pluginId).toBe('com.example.test-plugin');
18
- expect(result.signature.pluginVersion).toBe('1.0.0');
19
- expect(result.signature.keyId).toBe('test-key');
20
- expect(result.signature.files.map((file) => file.path)).toEqual([
21
- 'dist/renderer.js',
22
- 'manifest.json'
23
- ]);
24
- const verification = await verifyPlugin({
25
- pluginDir: fixture.pluginDir,
26
- trustedPublicKeysPem: [keys.publicKeyPem]
27
- });
28
- expect(verification.status).toBe('valid');
29
- }
30
- finally {
31
- fixture.cleanup();
32
- }
33
- });
34
- it('rejects invalid private keys', async () => {
35
- const fixture = createTestPluginDir();
36
- try {
37
- await expect(signPlugin({
38
- pluginDir: fixture.pluginDir,
39
- privateKeyPem: 'not-a-key'
40
- })).rejects.toThrow(/invalid ed25519 private key/i);
41
- }
42
- finally {
43
- fixture.cleanup();
44
- }
45
- });
46
- });
47
- describe('verifyPlugin', () => {
48
- it('returns unsigned when signature.json is absent', async () => {
49
- const fixture = createTestPluginDir();
50
- try {
51
- const result = await verifyPlugin({
52
- pluginDir: fixture.pluginDir,
53
- trustedPublicKeysPem: [createTestSigningKeys().publicKeyPem]
54
- });
55
- expect(result.status).toBe('unsigned');
56
- }
57
- finally {
58
- fixture.cleanup();
59
- }
60
- });
61
- it('returns invalid when a signed file is tampered with', async () => {
62
- const keys = createTestSigningKeys();
63
- const fixture = createTestPluginDir();
64
- try {
65
- await signPlugin({
66
- pluginDir: fixture.pluginDir,
67
- privateKeyPem: keys.privateKeyPem
68
- });
69
- writeFileSync(join(fixture.pluginDir, 'dist', 'renderer.js'), 'export function activate() { return 1; }');
70
- const result = await verifyPlugin({
71
- pluginDir: fixture.pluginDir,
72
- trustedPublicKeysPem: [keys.publicKeyPem]
73
- });
74
- expect(result.status).toBe('invalid');
75
- expect(result.error).toMatch(/signed inventory/i);
76
- }
77
- finally {
78
- fixture.cleanup();
79
- }
80
- });
81
- it('returns invalid when verified with the wrong public key', async () => {
82
- const keys = createTestSigningKeys();
83
- const otherKeys = createTestSigningKeys();
84
- const fixture = createTestPluginDir();
85
- try {
86
- await signPlugin({
87
- pluginDir: fixture.pluginDir,
88
- privateKeyPem: keys.privateKeyPem
89
- });
90
- const result = await verifyPlugin({
91
- pluginDir: fixture.pluginDir,
92
- trustedPublicKeysPem: [otherKeys.publicKeyPem]
93
- });
94
- expect(result.status).toBe('invalid');
95
- }
96
- finally {
97
- fixture.cleanup();
98
- }
99
- });
100
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=cappedList.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cappedList.test.d.ts","sourceRoot":"","sources":["../../src/storage/cappedList.test.ts"],"names":[],"mappings":""}
@@ -1,11 +0,0 @@
1
- import { describe, expect, it } from '@jest/globals';
2
- import { mergeById } from './cappedList.js';
3
- describe('mergeById', () => {
4
- it('dedupes and caps newest-first', () => {
5
- const merged = mergeById([{ id: 'b' }, { id: 'a' }], [{ id: 'a' }, { id: 'c' }], {
6
- cap: 3,
7
- idOf: (entry) => entry.id
8
- });
9
- expect(merged.map((entry) => entry.id)).toEqual(['b', 'a', 'c']);
10
- });
11
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=utilities.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utilities.test.d.ts","sourceRoot":"","sources":["../src/utilities.test.ts"],"names":[],"mappings":""}
@@ -1,16 +0,0 @@
1
- import { describe, expect, it } from '@jest/globals';
2
- import { methodColorClass, statusColorClass } from './ui/tokens.js';
3
- import { formatRelativeTime, formatHeaders } from './ui/format.js';
4
- describe('method and status color helpers', () => {
5
- it('return host classes', () => {
6
- expect(methodColorClass('GET')).toBe('text-method-get');
7
- expect(statusColorClass(200)).toBe('bg-success');
8
- expect(statusColorClass(404)).toBe('bg-danger');
9
- });
10
- });
11
- describe('format helpers', () => {
12
- it('produce readable output', () => {
13
- expect(formatHeaders({ Accept: 'application/json' })).toBe('Accept: application/json');
14
- expect(formatRelativeTime(Date.now() - 10_000)).toMatch(/ago|just now/);
15
- });
16
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=dynamic.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dynamic.test.d.ts","sourceRoot":"","sources":["../../src/variables/dynamic.test.ts"],"names":[],"mappings":""}
@@ -1,60 +0,0 @@
1
- import { describe, expect, it } from '@jest/globals';
2
- import { DYNAMIC_VARIABLE_CATEGORIES, DYNAMIC_VARIABLE_NAMES, DYNAMIC_VARIABLES, getDynamicVariableDescription, isDynamicVariable, resolveDynamicVariable } from './dynamic.js';
3
- describe('dynamicVariables', () => {
4
- it('registers all Postman-style dynamic variable names with $ prefix', () => {
5
- expect(DYNAMIC_VARIABLE_NAMES.length).toBeGreaterThan(100);
6
- for (const name of DYNAMIC_VARIABLE_NAMES) {
7
- expect(name.startsWith('$')).toBe(true);
8
- }
9
- });
10
- it('generates a non-empty value for every registered dynamic variable', () => {
11
- for (const name of DYNAMIC_VARIABLE_NAMES) {
12
- const value = resolveDynamicVariable(name);
13
- expect(value).toBeDefined();
14
- expect(value.length).toBeGreaterThan(0);
15
- }
16
- });
17
- it('isDynamicVariable and getDynamicVariableDescription reflect the registry', () => {
18
- expect(isDynamicVariable('$guid')).toBe(true);
19
- expect(isDynamicVariable('$randomFirstName')).toBe(true);
20
- expect(isDynamicVariable('host')).toBe(false);
21
- expect(isDynamicVariable('$unknownDynamic')).toBe(false);
22
- expect(getDynamicVariableDescription('$guid')).toBe(DYNAMIC_VARIABLES.$guid.description);
23
- expect(getDynamicVariableDescription('host')).toBeUndefined();
24
- });
25
- it('resolveDynamicVariable returns undefined for unknown keys', () => {
26
- expect(resolveDynamicVariable('$notARealVariable')).toBeUndefined();
27
- });
28
- it('$guid and $randomUUID produce uuid-v4 shaped values', () => {
29
- const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
30
- expect(resolveDynamicVariable('$guid')).toMatch(uuidPattern);
31
- expect(resolveDynamicVariable('$randomUUID')).toMatch(uuidPattern);
32
- });
33
- it('$timestamp returns a numeric unix seconds string', () => {
34
- const value = resolveDynamicVariable('$timestamp');
35
- expect(value).toMatch(/^\d+$/);
36
- const seconds = Number(value);
37
- expect(seconds).toBeGreaterThan(1_500_000_000);
38
- expect(seconds).toBeLessThanOrEqual(Math.floor(Date.now() / 1000));
39
- });
40
- it('$isoTimestamp returns an ISO-8601 UTC string', () => {
41
- const value = resolveDynamicVariable('$isoTimestamp');
42
- expect(value).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/);
43
- expect(() => new Date(value).toISOString()).not.toThrow();
44
- });
45
- it('generates fresh values on each resolve call for random variables', () => {
46
- const first = resolveDynamicVariable('$randomInt');
47
- const second = resolveDynamicVariable('$randomInt');
48
- expect(first).toMatch(/^\d+$/);
49
- expect(second).toMatch(/^\d+$/);
50
- });
51
- it('lists every dynamic variable exactly once across documentation categories', () => {
52
- const categorized = DYNAMIC_VARIABLE_CATEGORIES.flatMap((category) => category.keys);
53
- const unique = new Set(categorized);
54
- expect(categorized.length).toBe(DYNAMIC_VARIABLE_NAMES.length);
55
- expect(unique.size).toBe(DYNAMIC_VARIABLE_NAMES.length);
56
- for (const name of DYNAMIC_VARIABLE_NAMES) {
57
- expect(unique.has(name)).toBe(true);
58
- }
59
- });
60
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=tokens.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tokens.test.d.ts","sourceRoot":"","sources":["../../src/variables/tokens.test.ts"],"names":[],"mappings":""}