@pikku/kysely 0.12.12 → 0.12.14

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/CHANGELOG.md CHANGED
@@ -1,3 +1,28 @@
1
+ ## 0.12.14
2
+
3
+ ### Patch Changes
4
+
5
+ - 4b5c75b: feat(auth-js): wire OIDC config (issuer/tenantId) as variables, expand provider registry
6
+ - Move `issuer` and `tenantId` out of the secret blob for OIDC providers (auth0, okta, azure-ad, keycloak, cognito, microsoft-entra-id) — they are public config URLs, not secrets. Now registered via `wireVariable` and loaded at runtime via `services.variables.get()`.
7
+ - Expand provider registry from 13 to 31 providers: reddit, notion, instagram, zoom, figma, tiktok, threads, patreon, dropbox, bitbucket, hubspot, salesforce, atlassian, strava, keycloak, cognito, microsoft-entra-id added.
8
+ - `serialize-auth-gen` emits `wireVariable({...})` declarations and `services.variables.get()` calls in the generated factory for OIDC providers.
9
+ - Integration verifier exercises real `/auth/providers` endpoint with `LocalSecretService` + `LocalVariablesService`, including a spy test proving `services.variables.get('AUTH0_ISSUER')` is called at request time.
10
+
11
+ - Updated dependencies [4b5c75b]
12
+ - Updated dependencies [4b5c75b]
13
+ - @pikku/core@0.12.27
14
+
15
+ ## 0.12.13
16
+
17
+ ### Patch Changes
18
+
19
+ - 909eb25: Add audit logging support for function invocations and database queries.
20
+
21
+ Introduces `AuditService` and `createAuditedKysely` — configurable audit capture with best-effort and transactional durability modes. Audit logs capture session metadata (user, org), RPC call details, and Kysely query operations (type, tables, changes). Audit context is scoped per-invocation so nested RPC calls are correctly attributed.
22
+
23
+ - Updated dependencies [909eb25]
24
+ - @pikku/core@0.12.26
25
+
1
26
  ## 0.12.12
2
27
 
3
28
  ### Patch Changes
@@ -20,10 +20,10 @@ export declare class KyselySecretService implements SecretService {
20
20
  init(): Promise<void>;
21
21
  private logAudit;
22
22
  private getKEK;
23
- getSecret(key: string): Promise<string>;
24
- getSecretJSON<R = {}>(key: string): Promise<R>;
23
+ getSecret<T = string>(key: string): Promise<T>;
25
24
  hasSecret(key: string): Promise<boolean>;
26
- setSecretJSON(key: string, value: unknown): Promise<void>;
25
+ setSecret(key: string, value: unknown): Promise<void>;
27
26
  deleteSecret(key: string): Promise<void>;
27
+ getSecrets(keys: string[]): Promise<Record<string, unknown>>;
28
28
  rotateKEK(): Promise<number>;
29
29
  }
@@ -76,10 +76,6 @@ export class KyselySecretService {
76
76
  await this.logAudit(key, 'read');
77
77
  return result;
78
78
  }
79
- async getSecretJSON(key) {
80
- const raw = await this.getSecret(key);
81
- return JSON.parse(raw);
82
- }
83
79
  async hasSecret(key) {
84
80
  const row = await this.db
85
81
  .selectFrom('secrets')
@@ -88,9 +84,8 @@ export class KyselySecretService {
88
84
  .executeTakeFirst();
89
85
  return !!row;
90
86
  }
91
- async setSecretJSON(key, value) {
92
- const plaintext = JSON.stringify(value);
93
- const { ciphertext, wrappedDEK } = await envelopeEncrypt(this.key, plaintext);
87
+ async setSecret(key, value) {
88
+ const { ciphertext, wrappedDEK } = await envelopeEncrypt(this.key, value);
94
89
  const now = new Date().toISOString();
95
90
  await this.db
96
91
  .insertInto('secrets')
@@ -115,6 +110,24 @@ export class KyselySecretService {
115
110
  await this.db.deleteFrom('secrets').where('key', '=', key).execute();
116
111
  await this.logAudit(key, 'delete');
117
112
  }
113
+ async getSecrets(keys) {
114
+ const rows = await this.db
115
+ .selectFrom('secrets')
116
+ .select(['key', 'ciphertext', 'wrappedDek', 'keyVersion'])
117
+ .where('key', 'in', keys)
118
+ .execute();
119
+ const out = {};
120
+ for (const row of rows) {
121
+ try {
122
+ const kek = this.getKEK(row.keyVersion);
123
+ out[row.key] = await envelopeDecrypt(kek, row.ciphertext, row.wrappedDek);
124
+ }
125
+ catch {
126
+ // skip secrets that fail to decrypt
127
+ }
128
+ }
129
+ return out;
130
+ }
118
131
  async rotateKEK() {
119
132
  if (!this.previousKey) {
120
133
  throw new Error('No previousKey configured — nothing to rotate from');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/kysely",
3
- "version": "0.12.12",
3
+ "version": "0.12.14",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "module": "dist/src/index.js",
@@ -20,7 +20,7 @@
20
20
  "prepublishOnly": "yarn build"
21
21
  },
22
22
  "peerDependencies": {
23
- "@pikku/core": "^0.12.24"
23
+ "@pikku/core": "^0.12.27"
24
24
  },
25
25
  "dependencies": {
26
26
  "kysely": "^0.28.12"
@@ -33,5 +33,8 @@
33
33
  "kysely-postgres-js": "^3.0.0",
34
34
  "postgres": "^3.4.8",
35
35
  "typescript": "^5.9"
36
+ },
37
+ "exports": {
38
+ ".": "./dist/src/index.js"
36
39
  }
37
40
  }
@@ -93,7 +93,7 @@ export class KyselySecretService implements SecretService {
93
93
  throw new Error(`No KEK available for key_version ${version}`)
94
94
  }
95
95
 
96
- async getSecret(key: string): Promise<string> {
96
+ async getSecret<T = string>(key: string): Promise<T> {
97
97
  const row = await this.db
98
98
  .selectFrom('secrets')
99
99
  .select(['ciphertext', 'wrappedDek', 'keyVersion'])
@@ -103,20 +103,11 @@ export class KyselySecretService implements SecretService {
103
103
  if (!row) throw new Error('Requested secret not found')
104
104
 
105
105
  const kek = this.getKEK(row.keyVersion)
106
- const result = await envelopeDecrypt<string>(
107
- kek,
108
- row.ciphertext,
109
- row.wrappedDek
110
- )
106
+ const result = await envelopeDecrypt<T>(kek, row.ciphertext, row.wrappedDek)
111
107
  await this.logAudit(key, 'read')
112
108
  return result
113
109
  }
114
110
 
115
- async getSecretJSON<R = {}>(key: string): Promise<R> {
116
- const raw = await this.getSecret(key)
117
- return JSON.parse(raw) as R
118
- }
119
-
120
111
  async hasSecret(key: string): Promise<boolean> {
121
112
  const row = await this.db
122
113
  .selectFrom('secrets')
@@ -126,12 +117,8 @@ export class KyselySecretService implements SecretService {
126
117
  return !!row
127
118
  }
128
119
 
129
- async setSecretJSON(key: string, value: unknown): Promise<void> {
130
- const plaintext = JSON.stringify(value)
131
- const { ciphertext, wrappedDEK } = await envelopeEncrypt(
132
- this.key,
133
- plaintext
134
- )
120
+ async setSecret(key: string, value: unknown): Promise<void> {
121
+ const { ciphertext, wrappedDEK } = await envelopeEncrypt(this.key, value)
135
122
  const now = new Date().toISOString()
136
123
 
137
124
  await this.db
@@ -162,6 +149,29 @@ export class KyselySecretService implements SecretService {
162
149
  await this.logAudit(key, 'delete')
163
150
  }
164
151
 
152
+ async getSecrets(keys: string[]): Promise<Record<string, unknown>> {
153
+ const rows = await this.db
154
+ .selectFrom('secrets')
155
+ .select(['key', 'ciphertext', 'wrappedDek', 'keyVersion'])
156
+ .where('key', 'in', keys)
157
+ .execute()
158
+
159
+ const out: Record<string, unknown> = {}
160
+ for (const row of rows) {
161
+ try {
162
+ const kek = this.getKEK(row.keyVersion)
163
+ out[row.key] = await envelopeDecrypt(
164
+ kek,
165
+ row.ciphertext,
166
+ row.wrappedDek
167
+ )
168
+ } catch {
169
+ // skip secrets that fail to decrypt
170
+ }
171
+ }
172
+ return out
173
+ }
174
+
165
175
  async rotateKEK(): Promise<number> {
166
176
  if (!this.previousKey) {
167
177
  throw new Error('No previousKey configured — nothing to rotate from')
@@ -128,7 +128,7 @@ function registerTests(
128
128
  auditReads: true,
129
129
  })
130
130
  await service.init()
131
- await service.setSecretJSON('audit-test', 'value')
131
+ await service.setSecret('audit-test', 'value')
132
132
  await service.getSecret('audit-test')
133
133
  await service.deleteSecret('audit-test')
134
134
 
@@ -152,7 +152,7 @@ function registerTests(
152
152
  auditReads: false,
153
153
  })
154
154
  await service.init()
155
- await service.setSecretJSON('no-read-audit', 'value')
155
+ await service.setSecret('no-read-audit', 'value')
156
156
  await service.getSecret('no-read-audit')
157
157
 
158
158
  const logs = await getDb()