@pikku/kysely 0.13.29 → 0.13.31

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,33 @@
1
+ ## 0.13.31
2
+
3
+ ### Patch Changes
4
+
5
+ - 01c0209: `@pikku/kysely` re-exports `Kysely`, `PostgresDialect` and `CamelCasePlugin` from its own copy of kysely. The local-services codegen writes these imports into a project, so it now opens and types the database with the same kysely copy the generated services were built against, instead of a second copy the project may resolve on its own.
6
+ - 5bce779: Webhook trigger sources are off until someone turns them on, and addons declare their own.
7
+
8
+ An addon calls `wireTriggerWebhookSource` in its own package, and an app that wires the addon gets the source (its route included) without declaring it: named and routed after the addon's namespace, so two instances get one each. A source the app declares under the same name wins.
9
+
10
+ Every source now has an `enabled` switch in the `triggerSourceStore`, off by default. `reconcileTriggerSources` registers only enabled sources and records each one's `baseUrl` and `labelPrefix`; a disabled source's route answers 404 without running `receive`. New in core: `enableTriggerSource` registers a source with its provider and `disableTriggerSource` stops it receiving, then tears it down, both at the recorded address unless one is given. The admin addon exposes them as `triggerSourceEnable` and `triggerSourceDisable`. The `pikkuTriggerSource` table gains `enabled`, `baseUrl` and `labelPrefix`: run `pikku db generate` for the migration.
11
+
12
+ - Updated dependencies [dfcd351]
13
+ - Updated dependencies [cf40182]
14
+ - Updated dependencies [5bce779]
15
+ - Updated dependencies [5bce779]
16
+ - @pikku/core@0.12.130
17
+
18
+ ## 0.13.30
19
+
20
+ ### Patch Changes
21
+
22
+ - 658f047: A declared webhook source is a registered one. `reconcileTriggerSources` sets up every declared source with its provider (check, then setup where missing or drifted) and `teardownTriggerSources` removes named ones, recording what was registered in a `TriggerSourceStore` (in-memory, or `KyselyTriggerSourceStore` on `pikku_trigger_source`). The admin addon exposes list, reconcile, teardown and forget under the new `admin:triggers` scopes.
23
+ - Updated dependencies [658f047]
24
+ - Updated dependencies [de63ab2]
25
+ - Updated dependencies [658f047]
26
+ - Updated dependencies [658f047]
27
+ - Updated dependencies [658f047]
28
+ - Updated dependencies [658f047]
29
+ - @pikku/core@0.12.128
30
+
1
31
  ## 0.13.29
2
32
 
3
33
  ### Patch Changes
@@ -14,12 +14,14 @@ export { KyselyScopeService } from './kysely-scope-service.js';
14
14
  export { KyselyFeatureFlagStore } from './kysely-feature-flag-store.js';
15
15
  export type { KyselyFeatureFlagStoreOptions } from './kysely-feature-flag-store.js';
16
16
  export { KyselyWebhookService } from './kysely-webhook-service.js';
17
+ export { KyselyTriggerSourceStore } from './kysely-trigger-source-store.js';
17
18
  export { KyselyIncomingWebhookService } from './kysely-incoming-webhook-service.js';
18
19
  export { createAuditedKysely, type CreateAuditedKyselyOptions, } from './create-audited-kysely.js';
19
20
  export { KyselyAuditService } from './kysely-audit-service.js';
20
21
  export { KyselyAnalyticsService } from './kysely-analytics-service.js';
21
22
  export { KyselyVirtualUserRunStore } from './kysely-virtual-user-run-store.js';
22
23
  export { KyselyVirtualUserScheduleStore } from './kysely-virtual-user-schedule-store.js';
24
+ export { CamelCasePlugin, Kysely, PostgresDialect } from 'kysely';
23
25
  export { SerializePlugin, BaseSerializePlugin, type Serializer, type Deserializer, } from './serialize-plugin.js';
24
26
  export { createCoercionPlugin, type ColumnKind, type CoercionMap, type CreateCoercionPluginOptions, } from './coercion-plugin.js';
25
27
  export { createClassificationPlugin, type CreateClassificationPluginOptions, } from './classification-plugin.js';
package/dist/src/index.js CHANGED
@@ -13,12 +13,17 @@ export { KyselySessionStore } from './kysely-session-store.js';
13
13
  export { KyselyScopeService } from './kysely-scope-service.js';
14
14
  export { KyselyFeatureFlagStore } from './kysely-feature-flag-store.js';
15
15
  export { KyselyWebhookService } from './kysely-webhook-service.js';
16
+ export { KyselyTriggerSourceStore } from './kysely-trigger-source-store.js';
16
17
  export { KyselyIncomingWebhookService } from './kysely-incoming-webhook-service.js';
17
18
  export { createAuditedKysely, } from './create-audited-kysely.js';
18
19
  export { KyselyAuditService } from './kysely-audit-service.js';
19
20
  export { KyselyAnalyticsService } from './kysely-analytics-service.js';
20
21
  export { KyselyVirtualUserRunStore } from './kysely-virtual-user-run-store.js';
21
22
  export { KyselyVirtualUserScheduleStore } from './kysely-virtual-user-schedule-store.js';
23
+ // Re-exported so a generated file that constructs the services above opens and
24
+ // types its database with the same copy of kysely those services were built
25
+ // against, rather than a second copy the project may resolve on its own.
26
+ export { CamelCasePlugin, Kysely, PostgresDialect } from 'kysely';
22
27
  export { SerializePlugin, BaseSerializePlugin, } from './serialize-plugin.js';
23
28
  export { createCoercionPlugin, } from './coercion-plugin.js';
24
29
  export { createClassificationPlugin, } from './classification-plugin.js';
@@ -236,6 +236,20 @@ export interface PikkuFeatureFlagsTable {
236
236
  note: string | null;
237
237
  updatedAt: Generated<Date>;
238
238
  }
239
+ /** What a declared trigger source registered with its provider. */
240
+ export interface PikkuTriggerSourceTable {
241
+ name: string;
242
+ kind: string;
243
+ baseUrl: string | null;
244
+ labelPrefix: string | null;
245
+ declared: Generated<boolean>;
246
+ enabled: Generated<boolean>;
247
+ status: string | null;
248
+ /** The last setup's provider identifiers as JSON; never a secret. */
249
+ state: string | null;
250
+ detail: string | null;
251
+ updatedAt: Generated<Date>;
252
+ }
239
253
  /** One subject's short-circuit, in either direction, over a flag's rollout. */
240
254
  export interface PikkuFeatureFlagOverridesTable {
241
255
  flag: string;
@@ -421,6 +435,7 @@ export interface KyselyPikkuDB {
421
435
  pikkuUserScope: PikkuUserScopeTable;
422
436
  pikkuFeatureFlags: PikkuFeatureFlagsTable;
423
437
  pikkuFeatureFlagOverrides: PikkuFeatureFlagOverridesTable;
438
+ pikkuTriggerSource: PikkuTriggerSourceTable;
424
439
  channels: ChannelsTable;
425
440
  channelSubscriptions: ChannelSubscriptionsTable;
426
441
  workflowRuns: WorkflowRunsTable;
@@ -0,0 +1,15 @@
1
+ import type { DeclaredTriggerSource, TriggerSourceResult, TriggerSourceRow, TriggerSourceStore } from '@pikku/core/services';
2
+ import type { Kysely } from 'kysely';
3
+ import type { KyselyPikkuDB } from './kysely-tables.js';
4
+ export declare class KyselyTriggerSourceStore implements TriggerSourceStore {
5
+ private db;
6
+ private initialized;
7
+ constructor(db: Kysely<KyselyPikkuDB>);
8
+ init(): Promise<void>;
9
+ syncTriggerSources(sources: DeclaredTriggerSource[]): Promise<void>;
10
+ listTriggerSources(): Promise<TriggerSourceRow[]>;
11
+ getTriggerSource(name: string): Promise<TriggerSourceRow | null>;
12
+ recordTriggerSource(name: string, result: TriggerSourceResult): Promise<void>;
13
+ setTriggerSourceEnabled(name: string, enabled: boolean): Promise<void>;
14
+ deleteTriggerSource(name: string): Promise<void>;
15
+ }
@@ -0,0 +1,109 @@
1
+ import { requirePikkuSchema } from './schema/index.js';
2
+ import { triggerSourceSchema } from './schema/trigger-source.schema.js';
3
+ const parseState = (value) => {
4
+ if (!value)
5
+ return null;
6
+ if (typeof value !== 'string')
7
+ return value;
8
+ try {
9
+ return JSON.parse(value);
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ };
15
+ const toRow = (row) => ({
16
+ name: row.name,
17
+ kind: row.kind,
18
+ baseUrl: row.baseUrl,
19
+ labelPrefix: row.labelPrefix,
20
+ declared: !!row.declared,
21
+ enabled: !!row.enabled,
22
+ status: row.status,
23
+ state: parseState(row.state),
24
+ detail: row.detail,
25
+ updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null,
26
+ });
27
+ export class KyselyTriggerSourceStore {
28
+ db;
29
+ initialized = false;
30
+ constructor(db) {
31
+ this.db = db;
32
+ }
33
+ async init() {
34
+ if (this.initialized)
35
+ return;
36
+ await requirePikkuSchema(this.db, triggerSourceSchema);
37
+ this.initialized = true;
38
+ }
39
+ async syncTriggerSources(sources) {
40
+ await this.db.transaction().execute(async (trx) => {
41
+ for (const { name, kind, baseUrl, labelPrefix } of sources) {
42
+ const address = {
43
+ ...(baseUrl !== undefined ? { baseUrl } : {}),
44
+ ...(labelPrefix !== undefined ? { labelPrefix } : {}),
45
+ };
46
+ await trx
47
+ .insertInto('pikkuTriggerSource')
48
+ .values({ name, kind, declared: true, ...address })
49
+ .onConflict((oc) => oc.column('name').doUpdateSet({ kind, declared: true, ...address }))
50
+ .execute();
51
+ }
52
+ const markStale = trx
53
+ .updateTable('pikkuTriggerSource')
54
+ .set({ declared: false });
55
+ await (sources.length > 0
56
+ ? markStale.where('name', 'not in', sources.map((s) => s.name))
57
+ : markStale).execute();
58
+ });
59
+ }
60
+ async listTriggerSources() {
61
+ const rows = await this.db
62
+ .selectFrom('pikkuTriggerSource')
63
+ .selectAll()
64
+ .orderBy('name')
65
+ .execute();
66
+ return rows.map(toRow);
67
+ }
68
+ async getTriggerSource(name) {
69
+ const row = await this.db
70
+ .selectFrom('pikkuTriggerSource')
71
+ .selectAll()
72
+ .where('name', '=', name)
73
+ .executeTakeFirst();
74
+ return row ? toRow(row) : null;
75
+ }
76
+ async recordTriggerSource(name, result) {
77
+ const { numUpdatedRows } = await this.db
78
+ .updateTable('pikkuTriggerSource')
79
+ .set({
80
+ status: result.status,
81
+ ...(result.state !== undefined
82
+ ? { state: result.state ? JSON.stringify(result.state) : null }
83
+ : {}),
84
+ detail: result.detail ?? null,
85
+ updatedAt: new Date(),
86
+ })
87
+ .where('name', '=', name)
88
+ .executeTakeFirst();
89
+ if (!numUpdatedRows) {
90
+ throw new Error(`Unknown trigger source: ${name}`);
91
+ }
92
+ }
93
+ async setTriggerSourceEnabled(name, enabled) {
94
+ const { numUpdatedRows } = await this.db
95
+ .updateTable('pikkuTriggerSource')
96
+ .set({ enabled })
97
+ .where('name', '=', name)
98
+ .executeTakeFirst();
99
+ if (!numUpdatedRows) {
100
+ throw new Error(`Unknown trigger source: ${name}`);
101
+ }
102
+ }
103
+ async deleteTriggerSource(name) {
104
+ await this.db
105
+ .deleteFrom('pikkuTriggerSource')
106
+ .where('name', '=', name)
107
+ .execute();
108
+ }
109
+ }
@@ -24,6 +24,7 @@ export { channelSchema } from './channel.schema.js';
24
24
  export { credentialSchema } from './credential.schema.js';
25
25
  export { deploymentSchema } from './deployment.schema.js';
26
26
  export { flagSchema } from './flag.schema.js';
27
+ export { triggerSourceSchema } from './trigger-source.schema.js';
27
28
  export { incomingWebhookSchema } from './incoming-webhook.schema.js';
28
29
  export { scopeSchema } from './scope.schema.js';
29
30
  export { secretSchema } from './secret.schema.js';
@@ -8,6 +8,7 @@ import { credentialSchema } from './credential.schema.js';
8
8
  import { deploymentSchema } from './deployment.schema.js';
9
9
  import { scopeSchema } from './scope.schema.js';
10
10
  import { flagSchema } from './flag.schema.js';
11
+ import { triggerSourceSchema } from './trigger-source.schema.js';
11
12
  import { incomingWebhookSchema } from './incoming-webhook.schema.js';
12
13
  import { secretSchema } from './secret.schema.js';
13
14
  import { sessionSchema } from './session.schema.js';
@@ -42,6 +43,7 @@ export const pikkuSchemas = [
42
43
  agentSchema,
43
44
  scopeSchema,
44
45
  flagSchema,
46
+ triggerSourceSchema,
45
47
  auditSchema,
46
48
  analyticsSchema,
47
49
  virtualUserSchema,
@@ -54,6 +56,7 @@ export { channelSchema } from './channel.schema.js';
54
56
  export { credentialSchema } from './credential.schema.js';
55
57
  export { deploymentSchema } from './deployment.schema.js';
56
58
  export { flagSchema } from './flag.schema.js';
59
+ export { triggerSourceSchema } from './trigger-source.schema.js';
57
60
  export { incomingWebhookSchema } from './incoming-webhook.schema.js';
58
61
  export { scopeSchema } from './scope.schema.js';
59
62
  export { secretSchema } from './secret.schema.js';
@@ -0,0 +1,6 @@
1
+ import type { PikkuSchema } from './pikku-schema.types.js';
2
+ /**
3
+ * What each declared trigger source registered with its provider. `state` holds provider identifiers only: a signing secret a
4
+ * provider issues goes to the credential service.
5
+ */
6
+ export declare const triggerSourceSchema: PikkuSchema;
@@ -0,0 +1,23 @@
1
+ import { sql } from 'kysely';
2
+ /**
3
+ * What each declared trigger source registered with its provider. `state` holds provider identifiers only: a signing secret a
4
+ * provider issues goes to the credential service.
5
+ */
6
+ export const triggerSourceSchema = {
7
+ name: 'trigger-source',
8
+ ownedBy: ['triggerSourceStore'],
9
+ statements: [
10
+ (db) => db.schema
11
+ .createTable('pikkuTriggerSource')
12
+ .addColumn('name', 'text', (col) => col.primaryKey())
13
+ .addColumn('kind', 'text', (col) => col.notNull())
14
+ .addColumn('baseUrl', 'text')
15
+ .addColumn('labelPrefix', 'text')
16
+ .addColumn('declared', 'boolean', (col) => col.defaultTo(true).notNull())
17
+ .addColumn('enabled', 'boolean', (col) => col.defaultTo(false).notNull())
18
+ .addColumn('status', 'text')
19
+ .addColumn('state', 'text')
20
+ .addColumn('detail', 'text')
21
+ .addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
22
+ ],
23
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/kysely",
3
- "version": "0.13.29",
3
+ "version": "0.13.31",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/pikkujs/pikku.git",
@@ -26,7 +26,7 @@
26
26
  "prepublishOnly": "bun run build"
27
27
  },
28
28
  "peerDependencies": {
29
- "@pikku/core": "^0.12.125"
29
+ "@pikku/core": "^0.12.130"
30
30
  },
31
31
  "dependencies": {
32
32
  "kysely": "^0.29.5"