@harborclient/sdk 1.0.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.
- package/dist/build/index.d.ts.map +1 -1
- package/dist/build/index.js +10 -1
- package/dist/client.d.ts +2 -2
- package/dist/components/portalToBody.d.ts +2 -1
- package/dist/components/portalToBody.d.ts.map +1 -1
- package/dist/components/portalToBody.js +5 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/main.d.ts +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/jsx-dev-runtime.d.ts +1 -1
- package/dist/runtime/store.d.ts +6 -1
- package/dist/runtime/store.d.ts.map +1 -1
- package/dist/runtime/store.js +8 -2
- package/dist/runtime/store.ts +11 -3
- package/package.json +3 -2
- package/dist/components/enhanceControl.test.d.ts +0 -2
- package/dist/components/enhanceControl.test.d.ts.map +0 -1
- package/dist/components/enhanceControl.test.js +0 -83
- package/dist/components/utils.test.d.ts +0 -2
- package/dist/components/utils.test.d.ts.map +0 -1
- package/dist/components/utils.test.js +0 -44
- package/dist/http/resolveRequest.test.d.ts +0 -2
- package/dist/http/resolveRequest.test.d.ts.map +0 -1
- package/dist/http/resolveRequest.test.js +0 -41
- package/dist/http/substitute.test.d.ts +0 -2
- package/dist/http/substitute.test.d.ts.map +0 -1
- package/dist/http/substitute.test.js +0 -93
- package/dist/pluginDatabaseApi.test.d.ts +0 -2
- package/dist/pluginDatabaseApi.test.d.ts.map +0 -1
- package/dist/pluginDatabaseApi.test.js +0 -65
- package/dist/runtime/index.test.d.ts +0 -2
- package/dist/runtime/index.test.d.ts.map +0 -1
- package/dist/runtime/index.test.js +0 -41
- package/dist/runtime/index.test.ts +0 -53
- package/dist/runtime-utils.test.d.ts +0 -2
- package/dist/runtime-utils.test.d.ts.map +0 -1
- package/dist/runtime-utils.test.js +0 -177
- package/dist/signing/signing.test.d.ts +0 -2
- package/dist/signing/signing.test.d.ts.map +0 -1
- package/dist/signing/signing.test.js +0 -100
- package/dist/storage/cappedList.test.d.ts +0 -2
- package/dist/storage/cappedList.test.d.ts.map +0 -1
- package/dist/storage/cappedList.test.js +0 -11
- package/dist/storage/validate.test.d.ts +0 -2
- package/dist/storage/validate.test.d.ts.map +0 -1
- package/dist/storage/validate.test.js +0 -78
- package/dist/store.test.d.ts +0 -2
- package/dist/store.test.d.ts.map +0 -1
- package/dist/store.test.js +0 -248
- package/dist/utilities.test.d.ts +0 -2
- package/dist/utilities.test.d.ts.map +0 -1
- package/dist/utilities.test.js +0 -16
- package/dist/variables/dynamic.test.d.ts +0 -2
- package/dist/variables/dynamic.test.d.ts.map +0 -1
- package/dist/variables/dynamic.test.js +0 -60
- package/dist/variables/tokens.test.d.ts +0 -2
- package/dist/variables/tokens.test.d.ts.map +0 -1
- package/dist/variables/tokens.test.js +0 -160
|
@@ -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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-utils.test.d.ts","sourceRoot":"","sources":["../src/runtime-utils.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, jest } from '@jest/globals';
|
|
2
|
-
import { byteLength, createLogger, 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
|
-
});
|
|
105
|
-
describe('createLogger', () => {
|
|
106
|
-
it('prefixes messages with [pluginId]', () => {
|
|
107
|
-
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
108
|
-
const logger = createLogger('my-plugin');
|
|
109
|
-
logger.info('hello');
|
|
110
|
-
expect(logSpy).toHaveBeenCalledWith('[my-plugin]', 'hello');
|
|
111
|
-
logSpy.mockRestore();
|
|
112
|
-
});
|
|
113
|
-
it('filters messages below the active level', () => {
|
|
114
|
-
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
115
|
-
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => { });
|
|
116
|
-
const logger = createLogger('my-plugin', { level: 'warn' });
|
|
117
|
-
logger.debug('hidden');
|
|
118
|
-
logger.info('hidden');
|
|
119
|
-
logger.warn('visible');
|
|
120
|
-
expect(logSpy).not.toHaveBeenCalled();
|
|
121
|
-
expect(warnSpy).toHaveBeenCalledTimes(1);
|
|
122
|
-
expect(warnSpy).toHaveBeenCalledWith('[my-plugin]', 'visible');
|
|
123
|
-
logSpy.mockRestore();
|
|
124
|
-
warnSpy.mockRestore();
|
|
125
|
-
});
|
|
126
|
-
it('updates the active level via setLevel', () => {
|
|
127
|
-
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
128
|
-
const logger = createLogger('my-plugin');
|
|
129
|
-
logger.info('before');
|
|
130
|
-
logger.setLevel('silent');
|
|
131
|
-
logger.info('after');
|
|
132
|
-
expect(logSpy).toHaveBeenCalledTimes(1);
|
|
133
|
-
expect(logSpy).toHaveBeenCalledWith('[my-plugin]', 'before');
|
|
134
|
-
logSpy.mockRestore();
|
|
135
|
-
});
|
|
136
|
-
it('suppresses all output at silent level', () => {
|
|
137
|
-
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
138
|
-
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
139
|
-
const logger = createLogger('my-plugin', { level: 'silent' });
|
|
140
|
-
logger.debug('a');
|
|
141
|
-
logger.info('b');
|
|
142
|
-
logger.warn('c');
|
|
143
|
-
logger.error('d');
|
|
144
|
-
expect(logSpy).not.toHaveBeenCalled();
|
|
145
|
-
expect(errorSpy).not.toHaveBeenCalled();
|
|
146
|
-
logSpy.mockRestore();
|
|
147
|
-
errorSpy.mockRestore();
|
|
148
|
-
});
|
|
149
|
-
it('routes warn and error through console.warn and console.error when available', () => {
|
|
150
|
-
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => { });
|
|
151
|
-
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
152
|
-
const logger = createLogger('my-plugin', { level: 'debug' });
|
|
153
|
-
logger.warn('warned');
|
|
154
|
-
logger.error('failed');
|
|
155
|
-
expect(warnSpy).toHaveBeenCalledWith('[my-plugin]', 'warned');
|
|
156
|
-
expect(errorSpy).toHaveBeenCalledWith('[my-plugin]', 'failed');
|
|
157
|
-
warnSpy.mockRestore();
|
|
158
|
-
errorSpy.mockRestore();
|
|
159
|
-
});
|
|
160
|
-
it('falls back to console.log when console.warn and console.error are unavailable', () => {
|
|
161
|
-
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
162
|
-
const originalWarn = console.warn;
|
|
163
|
-
const originalError = console.error;
|
|
164
|
-
// @ts-expect-error — exercise SES main-runtime fallback
|
|
165
|
-
console.warn = undefined;
|
|
166
|
-
// @ts-expect-error — exercise SES main-runtime fallback
|
|
167
|
-
console.error = undefined;
|
|
168
|
-
const logger = createLogger('my-plugin', { level: 'debug' });
|
|
169
|
-
logger.warn('warned');
|
|
170
|
-
logger.error('failed');
|
|
171
|
-
expect(logSpy).toHaveBeenCalledWith('[my-plugin]', 'warned');
|
|
172
|
-
expect(logSpy).toHaveBeenCalledWith('[my-plugin]', 'failed');
|
|
173
|
-
console.warn = originalWarn;
|
|
174
|
-
console.error = originalError;
|
|
175
|
-
logSpy.mockRestore();
|
|
176
|
-
});
|
|
177
|
-
});
|
|
@@ -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 +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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validate.test.d.ts","sourceRoot":"","sources":["../../src/storage/validate.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from '@jest/globals';
|
|
2
|
-
import { arrayOf, asRecord, bool, isRecord, num, numArray, oneOf, recordOf, str, strArray } from './validate.js';
|
|
3
|
-
describe('isRecord', () => {
|
|
4
|
-
it('accepts plain objects and rejects arrays and primitives', () => {
|
|
5
|
-
expect(isRecord({ a: 1 })).toBe(true);
|
|
6
|
-
expect(isRecord([])).toBe(false);
|
|
7
|
-
expect(isRecord(null)).toBe(false);
|
|
8
|
-
expect(isRecord('x')).toBe(false);
|
|
9
|
-
});
|
|
10
|
-
});
|
|
11
|
-
describe('asRecord', () => {
|
|
12
|
-
it('returns the record or null', () => {
|
|
13
|
-
const value = { key: 'v' };
|
|
14
|
-
expect(asRecord(value)).toBe(value);
|
|
15
|
-
expect(asRecord(null)).toBeNull();
|
|
16
|
-
expect(asRecord([1])).toBeNull();
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
describe('str', () => {
|
|
20
|
-
it('returns strings and falls back otherwise', () => {
|
|
21
|
-
expect(str('hello', '')).toBe('hello');
|
|
22
|
-
expect(str(42, 'fallback')).toBe('fallback');
|
|
23
|
-
expect(str(undefined, null)).toBeNull();
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
describe('num', () => {
|
|
27
|
-
it('returns finite numbers and falls back otherwise', () => {
|
|
28
|
-
expect(num(3, 0)).toBe(3);
|
|
29
|
-
expect(num(NaN, 0)).toBe(0);
|
|
30
|
-
expect(num(Infinity, 0)).toBe(0);
|
|
31
|
-
expect(num('3', null)).toBeNull();
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
describe('bool', () => {
|
|
35
|
-
it('returns booleans and falls back otherwise', () => {
|
|
36
|
-
expect(bool(true, false)).toBe(true);
|
|
37
|
-
expect(bool(false, true)).toBe(false);
|
|
38
|
-
expect(bool('true', true)).toBe(true);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
describe('oneOf', () => {
|
|
42
|
-
it('accepts allowed literals and falls back otherwise', () => {
|
|
43
|
-
expect(oneOf('delay', ['interval', 'delay'], 'interval')).toBe('delay');
|
|
44
|
-
expect(oneOf('other', ['interval', 'delay'], 'interval')).toBe('interval');
|
|
45
|
-
expect(oneOf(1, ['interval', 'delay'], 'interval')).toBe('interval');
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
describe('numArray', () => {
|
|
49
|
-
it('filters to finite numbers', () => {
|
|
50
|
-
expect(numArray([1, NaN, 2, 'x', Infinity])).toEqual([1, 2]);
|
|
51
|
-
expect(numArray(null)).toEqual([]);
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
describe('strArray', () => {
|
|
55
|
-
it('filters to strings', () => {
|
|
56
|
-
expect(strArray(['a', 1, 'b'])).toEqual(['a', 'b']);
|
|
57
|
-
expect(strArray(undefined)).toEqual([]);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
describe('arrayOf', () => {
|
|
61
|
-
it('filters through a guard', () => {
|
|
62
|
-
const isNum = (entry) => typeof entry === 'number' && Number.isFinite(entry);
|
|
63
|
-
expect(arrayOf([1, 'x', 2], isNum)).toEqual([1, 2]);
|
|
64
|
-
expect(arrayOf('nope', isNum)).toEqual([]);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
describe('recordOf', () => {
|
|
68
|
-
it('keeps entries that pass the guard', () => {
|
|
69
|
-
const isNum = (entry) => typeof entry === 'number' && Number.isFinite(entry);
|
|
70
|
-
expect(recordOf({
|
|
71
|
-
a: 1,
|
|
72
|
-
b: 'x',
|
|
73
|
-
c: 2
|
|
74
|
-
}, isNum)).toEqual({ a: 1, c: 2 });
|
|
75
|
-
expect(recordOf([], isNum)).toEqual({});
|
|
76
|
-
expect(recordOf(null, isNum)).toEqual({});
|
|
77
|
-
});
|
|
78
|
-
});
|
package/dist/store.test.d.ts
DELETED
package/dist/store.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store.test.d.ts","sourceRoot":"","sources":["../src/store.test.ts"],"names":[],"mappings":""}
|