@pikku/kysely 0.12.13 → 0.12.15

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,25 @@
1
+ ## 0.12.15
2
+
3
+ ### Patch Changes
4
+
5
+ - ea48df2: Include runningAt, succeededAt, and failedAt timestamps in getRunSteps results
6
+ - Updated dependencies [2cf67be]
7
+ - @pikku/core@0.12.28
8
+
9
+ ## 0.12.14
10
+
11
+ ### Patch Changes
12
+
13
+ - 4b5c75b: feat(auth-js): wire OIDC config (issuer/tenantId) as variables, expand provider registry
14
+ - 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()`.
15
+ - 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.
16
+ - `serialize-auth-gen` emits `wireVariable({...})` declarations and `services.variables.get()` calls in the generated factory for OIDC providers.
17
+ - 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.
18
+
19
+ - Updated dependencies [4b5c75b]
20
+ - Updated dependencies [4b5c75b]
21
+ - @pikku/core@0.12.27
22
+
1
23
  ## 0.12.13
2
24
 
3
25
  ### Patch Changes
@@ -24,5 +24,6 @@ export declare class KyselySecretService implements SecretService {
24
24
  hasSecret(key: string): Promise<boolean>;
25
25
  setSecret(key: string, value: unknown): Promise<void>;
26
26
  deleteSecret(key: string): Promise<void>;
27
+ getSecrets(keys: string[]): Promise<Record<string, unknown>>;
27
28
  rotateKEK(): Promise<number>;
28
29
  }
@@ -110,6 +110,24 @@ export class KyselySecretService {
110
110
  await this.db.deleteFrom('secrets').where('key', '=', key).execute();
111
111
  await this.logAudit(key, 'delete');
112
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
+ }
113
131
  async rotateKEK() {
114
132
  if (!this.previousKey) {
115
133
  throw new Error('No previousKey configured — nothing to rotate from');
@@ -1,3 +1,4 @@
1
+ import { sql } from 'kysely';
1
2
  import { parseJson } from './kysely-json.js';
2
3
  export class KyselyWorkflowRunService {
3
4
  db;
@@ -82,6 +83,9 @@ export class KyselyWorkflowRunService {
82
83
  .select(eb.fn.countAll().as('cnt'))
83
84
  .whereRef('workflowStepHistory.workflowStepId', '=', 's.workflowStepId')
84
85
  .as('attemptCount'))
86
+ .select(sql `(SELECT MAX(h.running_at) FROM workflow_step_history h WHERE h.workflow_step_id = s.workflow_step_id)`.as('runningAt'))
87
+ .select(sql `(SELECT MAX(h.succeeded_at) FROM workflow_step_history h WHERE h.workflow_step_id = s.workflow_step_id)`.as('succeededAt'))
88
+ .select(sql `(SELECT MAX(h.failed_at) FROM workflow_step_history h WHERE h.workflow_step_id = s.workflow_step_id)`.as('failedAt'))
85
89
  .where('s.workflowRunId', '=', runId)
86
90
  .orderBy('s.createdAt', 'asc')
87
91
  .execute();
@@ -99,6 +103,15 @@ export class KyselyWorkflowRunService {
99
103
  retryDelay: row.retryDelay ?? undefined,
100
104
  createdAt: new Date(row.createdAt),
101
105
  updatedAt: new Date(row.updatedAt),
106
+ runningAt: row.runningAt
107
+ ? new Date(row.runningAt)
108
+ : undefined,
109
+ succeededAt: row.succeededAt
110
+ ? new Date(row.succeededAt)
111
+ : undefined,
112
+ failedAt: row.failedAt
113
+ ? new Date(row.failedAt)
114
+ : undefined,
102
115
  }));
103
116
  }
104
117
  async getRunHistory(runId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/kysely",
3
- "version": "0.12.13",
3
+ "version": "0.12.15",
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.26"
23
+ "@pikku/core": "^0.12.28"
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
  }
@@ -149,6 +149,29 @@ export class KyselySecretService implements SecretService {
149
149
  await this.logAudit(key, 'delete')
150
150
  }
151
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
+
152
175
  async rotateKEK(): Promise<number> {
153
176
  if (!this.previousKey) {
154
177
  throw new Error('No previousKey configured — nothing to rotate from')
@@ -5,6 +5,7 @@ import type {
5
5
  WorkflowRunService,
6
6
  } from '@pikku/core/workflow'
7
7
  import type { Kysely } from 'kysely'
8
+ import { sql } from 'kysely'
8
9
  import type { KyselyPikkuDB } from './kysely-tables.js'
9
10
  import { parseJson } from './kysely-json.js'
10
11
 
@@ -111,6 +112,15 @@ export class KyselyWorkflowRunService implements WorkflowRunService {
111
112
  )
112
113
  .as('attemptCount')
113
114
  )
115
+ .select(
116
+ sql<string | null>`(SELECT MAX(h.running_at) FROM workflow_step_history h WHERE h.workflow_step_id = s.workflow_step_id)`.as('runningAt')
117
+ )
118
+ .select(
119
+ sql<string | null>`(SELECT MAX(h.succeeded_at) FROM workflow_step_history h WHERE h.workflow_step_id = s.workflow_step_id)`.as('succeededAt')
120
+ )
121
+ .select(
122
+ sql<string | null>`(SELECT MAX(h.failed_at) FROM workflow_step_history h WHERE h.workflow_step_id = s.workflow_step_id)`.as('failedAt')
123
+ )
114
124
  .where('s.workflowRunId', '=', runId)
115
125
  .orderBy('s.createdAt', 'asc')
116
126
  .execute()
@@ -129,6 +139,15 @@ export class KyselyWorkflowRunService implements WorkflowRunService {
129
139
  retryDelay: row.retryDelay ?? undefined,
130
140
  createdAt: new Date(row.createdAt as unknown as string),
131
141
  updatedAt: new Date(row.updatedAt as unknown as string),
142
+ runningAt: row.runningAt
143
+ ? new Date(row.runningAt as unknown as string)
144
+ : undefined,
145
+ succeededAt: row.succeededAt
146
+ ? new Date(row.succeededAt as unknown as string)
147
+ : undefined,
148
+ failedAt: row.failedAt
149
+ ? new Date(row.failedAt as unknown as string)
150
+ : undefined,
132
151
  }))
133
152
  }
134
153