@pikku/core 0.12.24 → 0.12.25

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 (44) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/data-classification.d.ts +16 -0
  3. package/dist/data-classification.js +1 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/services/gopass-secrets.d.ts +2 -35
  6. package/dist/services/gopass-secrets.js +10 -40
  7. package/dist/services/local-secrets.d.ts +2 -36
  8. package/dist/services/local-secrets.js +3 -52
  9. package/dist/services/local-variables.d.ts +3 -5
  10. package/dist/services/local-variables.js +10 -10
  11. package/dist/services/scoped-secret-service.d.ts +2 -3
  12. package/dist/services/scoped-secret-service.js +2 -6
  13. package/dist/services/secret-service.d.ts +5 -12
  14. package/dist/services/typed-secret-service.d.ts +3 -4
  15. package/dist/services/typed-secret-service.js +2 -5
  16. package/dist/services/typed-variables-service.d.ts +3 -6
  17. package/dist/services/typed-variables-service.js +0 -6
  18. package/dist/services/variables-service.d.ts +2 -4
  19. package/dist/testing/service-tests.js +13 -13
  20. package/dist/wirings/ai-agent/ai-agent-prepare.js +4 -1
  21. package/dist/wirings/ai-agent/ai-agent.types.d.ts +4 -0
  22. package/dist/wirings/oauth2/oauth2-client.js +3 -3
  23. package/package.json +1 -1
  24. package/src/data-classification.ts +15 -0
  25. package/src/index.ts +9 -0
  26. package/src/services/gopass-secrets.ts +10 -42
  27. package/src/services/local-secrets.test.ts +10 -10
  28. package/src/services/local-secrets.ts +11 -59
  29. package/src/services/local-variables.test.ts +4 -4
  30. package/src/services/local-variables.ts +12 -17
  31. package/src/services/scoped-secret-service.test.ts +10 -11
  32. package/src/services/scoped-secret-service.ts +4 -9
  33. package/src/services/secret-service.ts +5 -12
  34. package/src/services/typed-secret-service.test.ts +16 -17
  35. package/src/services/typed-secret-service.ts +5 -9
  36. package/src/services/typed-variables-service.test.ts +5 -5
  37. package/src/services/typed-variables-service.ts +5 -17
  38. package/src/services/variables-service.ts +2 -4
  39. package/src/testing/service-tests.ts +13 -13
  40. package/src/wirings/ai-agent/ai-agent-prepare.ts +7 -2
  41. package/src/wirings/ai-agent/ai-agent.types.ts +4 -0
  42. package/src/wirings/oauth2/oauth2-client.test.ts +2 -3
  43. package/src/wirings/oauth2/oauth2-client.ts +3 -3
  44. package/tsconfig.tsbuildinfo +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/core",
3
- "version": "0.12.24",
3
+ "version": "0.12.25",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "module": "dist/index.js",
@@ -0,0 +1,15 @@
1
+ export type Private<T> = T & { readonly __pii__: 'private' }
2
+ export type Secret<T> = T & { readonly __pii__: 'secret' }
3
+
4
+ export type Classification = 'public' | 'private' | 'secret'
5
+ export type AnonymizeStrategy = 'fake:email' | 'fake:name' | 'hash' | 'keep' | null
6
+
7
+ export interface ColumnClassification {
8
+ classification: Classification
9
+ anonymize_strategy: AnonymizeStrategy
10
+ }
11
+
12
+ export type ClassificationManifest = {
13
+ version: 1
14
+ tables: Record<string, Record<string, ColumnClassification>>
15
+ }
package/src/index.ts CHANGED
@@ -177,3 +177,12 @@ export {
177
177
  type ScheduledTaskSummary,
178
178
  } from './services/scheduler-service.js'
179
179
  export { SchedulerService } from './services/scheduler-service.js'
180
+
181
+ export type {
182
+ Private,
183
+ Secret,
184
+ Classification,
185
+ AnonymizeStrategy,
186
+ ColumnClassification,
187
+ ClassificationManifest,
188
+ } from './data-classification.js'
@@ -6,10 +6,6 @@ import type { SecretService } from './secret-service.js'
6
6
  * Requires gopass to be installed and configured on the system.
7
7
  */
8
8
  export class GopassSecretService implements SecretService {
9
- /**
10
- * Creates an instance of GopassSecretService.
11
- * @param prefix - Optional prefix for all secret keys (e.g., 'pikku/' will look up 'pikku/mykey' for key 'mykey')
12
- */
13
9
  constructor(private prefix: string = '') {}
14
10
 
15
11
  private getFullKey(key: string): string {
@@ -19,39 +15,22 @@ export class GopassSecretService implements SecretService {
19
15
  return this.prefix ? `${this.prefix}${key}` : key
20
16
  }
21
17
 
22
- /**
23
- * Retrieves a secret by key and parses it as JSON.
24
- * @param key - The key of the secret to retrieve.
25
- * @returns A promise that resolves to the parsed secret value.
26
- * @throws {Error} If the secret is not found or gopass fails.
27
- */
28
- public async getSecretJSON<R>(key: string): Promise<R> {
29
- const value = await this.getSecret(key)
30
- return JSON.parse(value)
31
- }
32
-
33
- /**
34
- * Retrieves a secret by key as a string.
35
- * @param key - The key of the secret to retrieve.
36
- * @returns A promise that resolves to the secret value.
37
- * @throws {Error} If the secret is not found or gopass fails.
38
- */
39
- public async getSecret(key: string): Promise<string> {
18
+ public async getSecret<T = string>(key: string): Promise<T> {
40
19
  const fullKey = this.getFullKey(key)
41
20
  try {
42
- return execFileSync('gopass', ['show', '-o', fullKey], {
21
+ const raw = execFileSync('gopass', ['show', '-o', fullKey], {
43
22
  encoding: 'utf8',
44
23
  }).trim()
24
+ try {
25
+ return JSON.parse(raw) as T
26
+ } catch {
27
+ return raw as unknown as T
28
+ }
45
29
  } catch (error: any) {
46
30
  throw new Error(`Secret Not Found: ${key}`, { cause: error })
47
31
  }
48
32
  }
49
33
 
50
- /**
51
- * Checks if a secret exists without throwing.
52
- * @param key - The key of the secret to check.
53
- * @returns A promise that resolves to true if the secret exists.
54
- */
55
34
  public async hasSecret(key: string): Promise<boolean> {
56
35
  const fullKey = this.getFullKey(key)
57
36
  try {
@@ -62,19 +41,13 @@ export class GopassSecretService implements SecretService {
62
41
  }
63
42
  }
64
43
 
65
- /**
66
- * Stores a JSON value as a secret in gopass.
67
- * @param key - The key to store the secret under.
68
- * @param value - The JSON value to store.
69
- * @returns A promise that resolves when the secret is stored.
70
- */
71
- public async setSecretJSON(key: string, value: unknown): Promise<void> {
44
+ public async setSecret(key: string, value: unknown): Promise<void> {
72
45
  const fullKey = this.getFullKey(key)
73
- const jsonValue = JSON.stringify(value)
46
+ const encoded = typeof value === 'string' ? value : JSON.stringify(value)
74
47
  try {
75
48
  execFileSync('gopass', ['insert', '-f', fullKey], {
76
49
  encoding: 'utf8',
77
- input: jsonValue,
50
+ input: encoded,
78
51
  stdio: ['pipe', 'pipe', 'pipe'],
79
52
  })
80
53
  } catch (error: any) {
@@ -82,11 +55,6 @@ export class GopassSecretService implements SecretService {
82
55
  }
83
56
  }
84
57
 
85
- /**
86
- * Deletes a secret from gopass.
87
- * @param key - The key of the secret to delete.
88
- * @returns A promise that resolves when the secret is deleted.
89
- */
90
58
  public async deleteSecret(key: string): Promise<void> {
91
59
  const fullKey = this.getFullKey(key)
92
60
  try {
@@ -6,9 +6,9 @@ import { LocalVariablesService } from './local-variables.js'
6
6
  describe('LocalSecretService', () => {
7
7
  test('should get secret from local storage', async () => {
8
8
  const service = new LocalSecretService()
9
- await service.setSecretJSON('MY_KEY', { token: 'abc' })
9
+ await service.setSecret('MY_KEY', { token: 'abc' })
10
10
  const result = await service.getSecret('MY_KEY')
11
- assert.strictEqual(result, '{"token":"abc"}')
11
+ assert.deepStrictEqual(result, { token: 'abc' })
12
12
  })
13
13
 
14
14
  test('should get secret from environment variables', async () => {
@@ -28,22 +28,22 @@ describe('LocalSecretService', () => {
28
28
 
29
29
  test('should get JSON secret from local storage', async () => {
30
30
  const service = new LocalSecretService()
31
- await service.setSecretJSON('JSON_KEY', { data: 42 })
32
- const result = await service.getSecretJSON('JSON_KEY')
31
+ await service.setSecret('JSON_KEY', { data: 42 })
32
+ const result = await service.getSecret('JSON_KEY')
33
33
  assert.deepStrictEqual(result, { data: 42 })
34
34
  })
35
35
 
36
36
  test('should get JSON secret from environment variables', async () => {
37
37
  const vars = new LocalVariablesService({ CONFIG: '{"port":3000}' })
38
38
  const service = new LocalSecretService(vars)
39
- const result = await service.getSecretJSON('CONFIG')
39
+ const result = await service.getSecret('CONFIG')
40
40
  assert.deepStrictEqual(result, { port: 3000 })
41
41
  })
42
42
 
43
43
  test('should throw when JSON secret not found', async () => {
44
44
  const vars = new LocalVariablesService({})
45
45
  const service = new LocalSecretService(vars)
46
- await assert.rejects(() => service.getSecretJSON('MISSING'), {
46
+ await assert.rejects(() => service.getSecret('MISSING'), {
47
47
  message: 'Requested secret not found',
48
48
  })
49
49
  })
@@ -51,15 +51,15 @@ describe('LocalSecretService', () => {
51
51
  test('should prefer local storage over env variables', async () => {
52
52
  const vars = new LocalVariablesService({ KEY: 'env-value' })
53
53
  const service = new LocalSecretService(vars)
54
- await service.setSecretJSON('KEY', 'local-value')
54
+ await service.setSecret('KEY', 'local-value')
55
55
  const result = await service.getSecret('KEY')
56
- assert.strictEqual(result, '"local-value"')
56
+ assert.strictEqual(result, 'local-value')
57
57
  })
58
58
 
59
59
  test('should check hasSecret in local storage', async () => {
60
60
  const vars = new LocalVariablesService({})
61
61
  const service = new LocalSecretService(vars)
62
- await service.setSecretJSON('EXISTS', 'yes')
62
+ await service.setSecret('EXISTS', 'yes')
63
63
  assert.strictEqual(await service.hasSecret('EXISTS'), true)
64
64
  assert.strictEqual(await service.hasSecret('NOPE'), false)
65
65
  })
@@ -72,7 +72,7 @@ describe('LocalSecretService', () => {
72
72
 
73
73
  test('should delete secret from local storage', async () => {
74
74
  const service = new LocalSecretService()
75
- await service.setSecretJSON('DEL_KEY', 'value')
75
+ await service.setSecret('DEL_KEY', 'value')
76
76
  assert.strictEqual(await service.hasSecret('DEL_KEY'), true)
77
77
  await service.deleteSecret('DEL_KEY')
78
78
  assert.strictEqual(await service.hasSecret('DEL_KEY'), false)
@@ -9,81 +9,38 @@ import type { VariablesService } from './variables-service.js'
9
9
  export class LocalSecretService implements SecretService {
10
10
  private localSecrets: Map<string, string> = new Map()
11
11
 
12
- // TODO: Drop this fallback once secrets and variables expose aligned typed/raw access paths again.
13
- private parseSecret<R>(raw: string): R {
12
+ private parseSecret<T>(raw: string): T {
14
13
  try {
15
- return JSON.parse(raw) as R
14
+ return JSON.parse(raw) as T
16
15
  } catch {
17
- return raw as unknown as R
16
+ return raw as unknown as T
18
17
  }
19
18
  }
20
19
 
21
- /**
22
- * Creates an instance of LocalSecretService.
23
- */
24
20
  constructor(
25
21
  private variables: VariablesService = new LocalVariablesService()
26
22
  ) {}
27
23
 
28
- /**
29
- * Retrieves a secret by key.
30
- * Checks local storage first, then falls back to environment variables.
31
- * @param key - The key of the secret to retrieve.
32
- * @returns A promise that resolves to the secret value.
33
- * @throws {Error} If the secret is not found.
34
- */
35
- public async getSecretJSON<R>(key: string): Promise<R> {
36
- // Check local storage first
24
+ public async getSecret<T = string>(key: string): Promise<T> {
37
25
  const localValue = this.localSecrets.get(key)
38
26
  if (localValue) {
39
- return this.parseSecret(localValue)
27
+ return this.parseSecret<T>(localValue)
40
28
  }
41
29
 
42
- // Fall back to environment variables
43
30
  const value = await this.variables.get(key)
44
31
  if (value) {
45
- return this.parseSecret(value)
32
+ return this.parseSecret<T>(value)
46
33
  }
47
34
  throw new Error('Requested secret not found')
48
35
  }
49
36
 
50
- /**
51
- * Retrieves a secret by key.
52
- * Checks local storage first, then falls back to environment variables.
53
- * @param key - The key of the secret to retrieve.
54
- * @returns A promise that resolves to the secret value.
55
- * @throws {Error} If the secret is not found.
56
- */
57
- public async getSecret(key: string): Promise<string> {
58
- // Check local storage first
59
- const localValue = this.localSecrets.get(key)
60
- if (localValue) {
61
- return localValue
62
- }
63
-
64
- // Fall back to environment variables
65
- const value = await this.variables.get(key)
66
- if (value) {
67
- return value
68
- }
69
- throw new Error('Requested secret not found')
70
- }
71
-
72
- /**
73
- * Stores a JSON value as a secret in local storage.
74
- * @param key - The key to store the secret under.
75
- * @param value - The JSON value to store.
76
- * @returns A promise that resolves when the secret is stored.
77
- */
78
- public async setSecretJSON(key: string, value: unknown): Promise<void> {
79
- this.localSecrets.set(key, JSON.stringify(value))
37
+ public async setSecret(key: string, value: unknown): Promise<void> {
38
+ this.localSecrets.set(
39
+ key,
40
+ typeof value === 'string' ? value : JSON.stringify(value)
41
+ )
80
42
  }
81
43
 
82
- /**
83
- * Checks if a secret exists without throwing.
84
- * @param key - The key of the secret to check.
85
- * @returns A promise that resolves to true if the secret exists.
86
- */
87
44
  public async hasSecret(key: string): Promise<boolean> {
88
45
  if (this.localSecrets.has(key)) {
89
46
  return true
@@ -92,11 +49,6 @@ export class LocalSecretService implements SecretService {
92
49
  return value !== undefined && value !== null && value !== ''
93
50
  }
94
51
 
95
- /**
96
- * Deletes a secret from local storage.
97
- * @param key - The key of the secret to delete.
98
- * @returns A promise that resolves when the secret is deleted.
99
- */
100
52
  public async deleteSecret(key: string): Promise<void> {
101
53
  this.localSecrets.delete(key)
102
54
  }
@@ -39,19 +39,19 @@ describe('LocalVariablesService', () => {
39
39
 
40
40
  test('should get JSON variable', () => {
41
41
  const service = new LocalVariablesService({ DATA: '{"key":"val"}' })
42
- const result = service.getJSON('DATA')
42
+ const result = service.get('DATA')
43
43
  assert.deepStrictEqual(result, { key: 'val' })
44
44
  })
45
45
 
46
46
  test('should return undefined for missing JSON variable', () => {
47
47
  const service = new LocalVariablesService({})
48
- assert.strictEqual(service.getJSON('MISSING'), undefined)
48
+ assert.strictEqual(service.get('MISSING'), undefined)
49
49
  })
50
50
 
51
51
  test('should set JSON variable', () => {
52
52
  const service = new LocalVariablesService({})
53
- service.setJSON('DATA', { key: 'val' })
54
- assert.strictEqual(service.get('DATA'), '{"key":"val"}')
53
+ service.set('DATA', { key: 'val' })
54
+ assert.deepStrictEqual(service.get('DATA'), { key: 'val' })
55
55
  })
56
56
 
57
57
  test('should handle has with undefined value', () => {
@@ -5,28 +5,23 @@ export class LocalVariablesService implements VariablesService {
5
5
  private variables: Record<string, string | undefined> = process.env
6
6
  ) {}
7
7
 
8
- public getAll():
9
- | Promise<Record<string, string | undefined>>
10
- | Record<string, string | undefined> {
8
+ public getAll(): Record<string, string | undefined> {
11
9
  return this.variables || {}
12
10
  }
13
11
 
14
- public get(name: string): Promise<string | undefined> | string | undefined {
15
- return this.variables[name]
12
+ public get<T = string>(name: string): T | undefined {
13
+ const raw = this.variables[name]
14
+ if (raw === undefined) return undefined
15
+ try {
16
+ return JSON.parse(raw) as T
17
+ } catch {
18
+ return raw as unknown as T
19
+ }
16
20
  }
17
21
 
18
- public getJSON<T = unknown>(name: string): T | undefined {
19
- const value = this.variables[name]
20
- if (value === undefined) return undefined
21
- return JSON.parse(value)
22
- }
23
-
24
- public set(name: string, value: string): void {
25
- this.variables[name] = value
26
- }
27
-
28
- public setJSON(name: string, value: unknown): void {
29
- this.variables[name] = JSON.stringify(value)
22
+ public set(name: string, value: unknown): void {
23
+ this.variables[name] =
24
+ typeof value === 'string' ? value : JSON.stringify(value)
30
25
  }
31
26
 
32
27
  public has(name: string): boolean {
@@ -3,10 +3,9 @@ import assert from 'node:assert'
3
3
  import { ScopedSecretService } from './scoped-secret-service.js'
4
4
 
5
5
  const createMockSecrets = () => ({
6
- getSecret: async (key: string) => `value-of-${key}`,
7
- getSecretJSON: async (key: string) => ({ key }),
6
+ getSecret: async <T>(key: string) => ({ key }) as T,
8
7
  hasSecret: async () => true,
9
- setSecretJSON: async () => {},
8
+ setSecret: async () => {},
10
9
  deleteSecret: async () => {},
11
10
  })
12
11
 
@@ -15,7 +14,7 @@ describe('ScopedSecretService', () => {
15
14
  const mock = createMockSecrets()
16
15
  const scoped = new ScopedSecretService(mock, new Set(['KEY1', 'KEY2']))
17
16
  const result = await scoped.getSecret('KEY1')
18
- assert.strictEqual(result, 'value-of-KEY1')
17
+ assert.deepStrictEqual(result, { key: 'KEY1' })
19
18
  })
20
19
 
21
20
  test('should deny access to non-allowed keys', async () => {
@@ -26,17 +25,17 @@ describe('ScopedSecretService', () => {
26
25
  })
27
26
  })
28
27
 
29
- test('should allow getSecretJSON for allowed keys', async () => {
28
+ test('should allow getSecret for allowed keys', async () => {
30
29
  const mock = createMockSecrets()
31
30
  const scoped = new ScopedSecretService(mock, new Set(['KEY1']))
32
- const result = await scoped.getSecretJSON('KEY1')
31
+ const result = await scoped.getSecret('KEY1')
33
32
  assert.deepStrictEqual(result, { key: 'KEY1' })
34
33
  })
35
34
 
36
- test('should deny getSecretJSON for non-allowed keys', async () => {
35
+ test('should deny getSecret for non-allowed keys', async () => {
37
36
  const mock = createMockSecrets()
38
37
  const scoped = new ScopedSecretService(mock, new Set(['KEY1']))
39
- await assert.rejects(() => scoped.getSecretJSON('FORBIDDEN'), {
38
+ await assert.rejects(() => scoped.getSecret('FORBIDDEN'), {
40
39
  message: 'Access denied to secret key: FORBIDDEN',
41
40
  })
42
41
  })
@@ -56,11 +55,11 @@ describe('ScopedSecretService', () => {
56
55
  })
57
56
  })
58
57
 
59
- test('should always throw on setSecretJSON', async () => {
58
+ test('should always throw on setSecret', async () => {
60
59
  const mock = createMockSecrets()
61
60
  const scoped = new ScopedSecretService(mock, new Set(['KEY1']))
62
- await assert.rejects(() => scoped.setSecretJSON('KEY1', 'val'), {
63
- message: 'setSecretJSON is not allowed in scoped secret service',
61
+ await assert.rejects(() => scoped.setSecret('KEY1', 'val'), {
62
+ message: 'setSecret is not allowed in scoped secret service',
64
63
  })
65
64
  })
66
65
 
@@ -16,14 +16,9 @@ export class ScopedSecretService implements SecretService {
16
16
  }
17
17
  }
18
18
 
19
- async getSecret(key: string): Promise<string> {
19
+ async getSecret<T = string>(key: string): Promise<T> {
20
20
  this.assertAllowed(key)
21
- return this.secrets.getSecret(key)
22
- }
23
-
24
- async getSecretJSON<T = {}>(key: string): Promise<T> {
25
- this.assertAllowed(key)
26
- return this.secrets.getSecretJSON<T>(key)
21
+ return this.secrets.getSecret<T>(key)
27
22
  }
28
23
 
29
24
  async hasSecret(key: string): Promise<boolean> {
@@ -31,8 +26,8 @@ export class ScopedSecretService implements SecretService {
31
26
  return this.secrets.hasSecret(key)
32
27
  }
33
28
 
34
- async setSecretJSON(_key: string, _value: unknown): Promise<void> {
35
- throw new Error('setSecretJSON is not allowed in scoped secret service')
29
+ async setSecret(_key: string, _value: unknown): Promise<void> {
30
+ throw new Error('setSecret is not allowed in scoped secret service')
36
31
  }
37
32
 
38
33
  async deleteSecret(_key: string): Promise<void> {
@@ -3,19 +3,12 @@
3
3
  */
4
4
  export interface SecretService {
5
5
  /**
6
- * Retrieves a secret by key and parses it as JSON.
7
- * @param key - The key of the secret to retrieve.
8
- * @returns A promise that resolves to the parsed secret value.
9
- * @throws If the secret is not found.
10
- */
11
- getSecretJSON<Return = {}>(key: string): Promise<Return>
12
- /**
13
- * Retrieves a secret by key as a string.
6
+ * Retrieves a secret by key, typed as T (defaults to string).
14
7
  * @param key - The key of the secret to retrieve.
15
8
  * @returns A promise that resolves to the secret value.
16
9
  * @throws If the secret is not found.
17
10
  */
18
- getSecret(key: string): Promise<string>
11
+ getSecret<T = string>(key: string): Promise<T>
19
12
  /**
20
13
  * Checks if a secret exists without throwing.
21
14
  * @param key - The key of the secret to check.
@@ -23,12 +16,12 @@ export interface SecretService {
23
16
  */
24
17
  hasSecret(key: string): Promise<boolean>
25
18
  /**
26
- * Stores a JSON value as a secret.
19
+ * Stores a secret value.
27
20
  * @param key - The key to store the secret under.
28
- * @param value - The JSON value to store.
21
+ * @param value - The value to store.
29
22
  * @returns A promise that resolves when the secret is stored.
30
23
  */
31
- setSecretJSON(key: string, value: unknown): Promise<void>
24
+ setSecret(key: string, value: unknown): Promise<void>
32
25
  /**
33
26
  * Deletes a secret by key.
34
27
  * @param key - The key of the secret to delete.
@@ -3,18 +3,17 @@ import assert from 'node:assert'
3
3
  import { TypedSecretService } from './typed-secret-service.js'
4
4
 
5
5
  const createMockSecrets = (store: Map<string, string> = new Map()) => ({
6
- getSecret: async (key: string) => {
6
+ getSecret: async <T = string>(key: string): Promise<T> => {
7
7
  const val = store.get(key)
8
8
  if (!val) throw new Error(`Not found: ${key}`)
9
- return val
10
- },
11
- getSecretJSON: async (key: string) => {
12
- const val = store.get(key)
13
- if (!val) throw new Error(`Not found: ${key}`)
14
- return JSON.parse(val)
9
+ try {
10
+ return JSON.parse(val) as T
11
+ } catch {
12
+ return val as unknown as T
13
+ }
15
14
  },
16
15
  hasSecret: async (key: string) => store.has(key),
17
- setSecretJSON: async (key: string, value: unknown) => {
16
+ setSecret: async (key: string, value: unknown) => {
18
17
  store.set(key, JSON.stringify(value))
19
18
  },
20
19
  deleteSecret: async (key: string) => {
@@ -24,42 +23,42 @@ const createMockSecrets = (store: Map<string, string> = new Map()) => ({
24
23
 
25
24
  describe('TypedSecretService', () => {
26
25
  test('should delegate getSecret to underlying service', async () => {
27
- const store = new Map([['API_KEY', 'sk-123']])
26
+ const store = new Map([['API_KEY', '"sk-123"']])
28
27
  const service = new TypedSecretService(createMockSecrets(store), {})
29
28
  const result = await service.getSecret('API_KEY')
30
29
  assert.strictEqual(result, 'sk-123')
31
30
  })
32
31
 
33
- test('should delegate getSecretJSON to underlying service', async () => {
32
+ test('should delegate getSecret with type to underlying service', async () => {
34
33
  const store = new Map([['CONFIG', '{"port":3000}']])
35
34
  const service = new TypedSecretService(createMockSecrets(store), {})
36
- const result = await service.getSecretJSON('CONFIG')
35
+ const result = await service.getSecret<{ port: number }>('CONFIG')
37
36
  assert.deepStrictEqual(result, { port: 3000 })
38
37
  })
39
38
 
40
39
  test('should delegate hasSecret to underlying service', async () => {
41
- const store = new Map([['EXISTS', 'val']])
40
+ const store = new Map([['EXISTS', '"val"']])
42
41
  const service = new TypedSecretService(createMockSecrets(store), {})
43
42
  assert.strictEqual(await service.hasSecret('EXISTS'), true)
44
43
  assert.strictEqual(await service.hasSecret('MISSING'), false)
45
44
  })
46
45
 
47
- test('should delegate setSecretJSON to underlying service', async () => {
46
+ test('should delegate setSecret to underlying service', async () => {
48
47
  const store = new Map<string, string>()
49
48
  const service = new TypedSecretService(createMockSecrets(store), {})
50
- await service.setSecretJSON('NEW_KEY', { data: 'val' })
49
+ await service.setSecret('NEW_KEY', { data: 'val' })
51
50
  assert.strictEqual(store.get('NEW_KEY'), '{"data":"val"}')
52
51
  })
53
52
 
54
53
  test('should delegate deleteSecret to underlying service', async () => {
55
- const store = new Map([['KEY', 'val']])
54
+ const store = new Map([['KEY', '"val"']])
56
55
  const service = new TypedSecretService(createMockSecrets(store), {})
57
56
  await service.deleteSecret('KEY')
58
57
  assert.strictEqual(store.has('KEY'), false)
59
58
  })
60
59
 
61
60
  test('should get all status for credentials', async () => {
62
- const store = new Map([['STRIPE_KEY', 'sk-123']])
61
+ const store = new Map([['STRIPE_KEY', '"sk-123"']])
63
62
  const meta = {
64
63
  STRIPE_KEY: { name: 'stripe', displayName: 'Stripe' },
65
64
  GITHUB_TOKEN: {
@@ -80,7 +79,7 @@ describe('TypedSecretService', () => {
80
79
  })
81
80
 
82
81
  test('should get missing credentials', async () => {
83
- const store = new Map([['STRIPE_KEY', 'sk-123']])
82
+ const store = new Map([['STRIPE_KEY', '"sk-123"']])
84
83
  const meta = {
85
84
  STRIPE_KEY: { name: 'stripe', displayName: 'Stripe' },
86
85
  GITHUB_TOKEN: { name: 'github', displayName: 'GitHub' },
@@ -22,13 +22,9 @@ export class TypedSecretService<
22
22
  private credentialsMeta: Record<string, CredentialMeta>
23
23
  ) {}
24
24
 
25
- async getSecretJSON<K extends keyof TMap & string>(key: K): Promise<TMap[K]>
26
- async getSecretJSON<T = unknown>(key: string): Promise<T>
27
- async getSecretJSON(key: string): Promise<unknown> {
28
- return this.secrets.getSecretJSON(key)
29
- }
30
-
31
- async getSecret(key: string): Promise<string> {
25
+ async getSecret<K extends keyof TMap & string>(key: K): Promise<TMap[K]>
26
+ async getSecret<T = string>(key: string): Promise<T>
27
+ async getSecret(key: string): Promise<unknown> {
32
28
  return this.secrets.getSecret(key)
33
29
  }
34
30
 
@@ -36,11 +32,11 @@ export class TypedSecretService<
36
32
  return this.secrets.hasSecret(key)
37
33
  }
38
34
 
39
- async setSecretJSON<K extends string>(
35
+ async setSecret<K extends string>(
40
36
  key: K,
41
37
  value: K extends keyof TMap ? TMap[K] : unknown
42
38
  ): Promise<void> {
43
- return this.secrets.setSecretJSON(key, value)
39
+ return this.secrets.setSecret(key, value)
44
40
  }
45
41
 
46
42
  async deleteSecret(key: string): Promise<void> {
@@ -36,15 +36,15 @@ describe('TypedVariablesService', () => {
36
36
  assert.strictEqual(service.has('DB_URL'), false)
37
37
  })
38
38
 
39
- test('should delegate getJSON to underlying service', () => {
39
+ test('should delegate get to underlying service', () => {
40
40
  const service = createService({ DATA: '{"key":"val"}' })
41
- assert.deepStrictEqual(service.getJSON('DATA'), { key: 'val' })
41
+ assert.deepStrictEqual(service.get('DATA'), { key: 'val' })
42
42
  })
43
43
 
44
- test('should delegate setJSON to underlying service', () => {
44
+ test('should delegate set to underlying service', () => {
45
45
  const service = createService()
46
- service.setJSON('DATA', { key: 'val' })
47
- assert.strictEqual(service.get('DATA'), '{"key":"val"}')
46
+ service.set('DATA', { key: 'val' })
47
+ assert.deepStrictEqual(service.get('DATA'), { key: 'val' })
48
48
  })
49
49
 
50
50
  test('should get all status for configured variables', async () => {