@pikku/kysely 0.13.28 → 0.13.30
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 +25 -0
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +3 -1
- package/dist/src/kysely-incoming-webhook-service.d.ts +29 -0
- package/dist/src/kysely-incoming-webhook-service.js +94 -0
- package/dist/src/kysely-tables.d.ts +24 -0
- package/dist/src/kysely-trigger-source-store.d.ts +14 -0
- package/dist/src/kysely-trigger-source-store.js +92 -0
- package/dist/src/schema/incoming-webhook.schema.d.ts +3 -0
- package/dist/src/schema/incoming-webhook.schema.js +28 -0
- package/dist/src/schema/index.d.ts +2 -0
- package/dist/src/schema/index.js +6 -0
- package/dist/src/schema/trigger-source.schema.d.ts +6 -0
- package/dist/src/schema/trigger-source.schema.js +20 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
## 0.13.30
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- 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.
|
|
6
|
+
- Updated dependencies [658f047]
|
|
7
|
+
- Updated dependencies [de63ab2]
|
|
8
|
+
- Updated dependencies [658f047]
|
|
9
|
+
- Updated dependencies [658f047]
|
|
10
|
+
- Updated dependencies [658f047]
|
|
11
|
+
- Updated dependencies [658f047]
|
|
12
|
+
- @pikku/core@0.12.128
|
|
13
|
+
|
|
14
|
+
## 0.13.29
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- 5e93f30: Add `wireTriggerWebhookSource({ name, method?, route?, secret?, events, receive?, check?, setup?, teardown? })` in `#pikku/trigger`. Each source becomes a `POST /webhooks/<name>` route whose events are validated against their schemas and queued on `pikku-incoming-webhooks` through `IncomingWebhookService`; a generated worker runs the matching `wireTrigger({ name: '<source>:<event>' })` and the queue retries it on failure. `pikku webhooks status | setup | teardown --url --labelPrefix [--previous]` registers the routes with the provider and prints one JSON line per source.
|
|
19
|
+
|
|
20
|
+
`KyselyIncomingWebhookService` (with the `incoming-webhook` schema) records a receipt per event, drops a provider's redelivery of an event it already accepted, and keeps each dispatch's attempts and last error. `pikku dev` and `pikku serve` use it when a Kysely database is configured.
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [5e93f30]
|
|
23
|
+
- Updated dependencies [5e93f30]
|
|
24
|
+
- @pikku/core@0.12.125
|
|
25
|
+
|
|
1
26
|
## 0.13.28
|
|
2
27
|
|
|
3
28
|
### Patch Changes
|
package/dist/src/index.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ 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';
|
|
18
|
+
export { KyselyIncomingWebhookService } from './kysely-incoming-webhook-service.js';
|
|
17
19
|
export { createAuditedKysely, type CreateAuditedKyselyOptions, } from './create-audited-kysely.js';
|
|
18
20
|
export { KyselyAuditService } from './kysely-audit-service.js';
|
|
19
21
|
export { KyselyAnalyticsService } from './kysely-analytics-service.js';
|
|
@@ -23,7 +25,7 @@ export { SerializePlugin, BaseSerializePlugin, type Serializer, type Deserialize
|
|
|
23
25
|
export { createCoercionPlugin, type ColumnKind, type CoercionMap, type CreateCoercionPluginOptions, } from './coercion-plugin.js';
|
|
24
26
|
export { createClassificationPlugin, type CreateClassificationPluginOptions, } from './classification-plugin.js';
|
|
25
27
|
export { ClassificationCrypto, DEFAULT_KEY_ID, isColumnEnvelope, parseColumnEnvelope, type ClassificationCryptoOptions, type ColumnEnvelope, type KEKResolver, type ResolvedKEK, } from './classification-crypto.js';
|
|
26
|
-
export { agentSchema, analyticsSchema, auditSchema, channelSchema, credentialSchema, deploymentSchema, flagSchema, scopeSchema, secretSchema, sessionSchema, virtualUserSchema, webhookSchema, workflowSchema, pikkuSchemas, requiredPikkuSchemas, applyPikkuSchemas, compilePikkuSchemas, requirePikkuSchema, resolveRequirements, type PikkuSchema, type RequiredTypes, type UnmetRequirement, type SchemaStatementFactory, } from './schema/index.js';
|
|
28
|
+
export { agentSchema, analyticsSchema, auditSchema, channelSchema, credentialSchema, deploymentSchema, flagSchema, incomingWebhookSchema, scopeSchema, secretSchema, sessionSchema, virtualUserSchema, webhookSchema, workflowSchema, pikkuSchemas, requiredPikkuSchemas, applyPikkuSchemas, compilePikkuSchemas, requirePikkuSchema, resolveRequirements, type PikkuSchema, type RequiredTypes, type UnmetRequirement, type SchemaStatementFactory, } from './schema/index.js';
|
|
27
29
|
export type { KyselyPikkuDB } from './kysely-tables.js';
|
|
28
30
|
export type { WorkflowRunService } from '@pikku/core/workflow';
|
|
29
31
|
export type { AgentRunService, AgentRunRow } from '@pikku/core/agent';
|
package/dist/src/index.js
CHANGED
|
@@ -13,6 +13,8 @@ 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';
|
|
17
|
+
export { KyselyIncomingWebhookService } from './kysely-incoming-webhook-service.js';
|
|
16
18
|
export { createAuditedKysely, } from './create-audited-kysely.js';
|
|
17
19
|
export { KyselyAuditService } from './kysely-audit-service.js';
|
|
18
20
|
export { KyselyAnalyticsService } from './kysely-analytics-service.js';
|
|
@@ -22,4 +24,4 @@ export { SerializePlugin, BaseSerializePlugin, } from './serialize-plugin.js';
|
|
|
22
24
|
export { createCoercionPlugin, } from './coercion-plugin.js';
|
|
23
25
|
export { createClassificationPlugin, } from './classification-plugin.js';
|
|
24
26
|
export { ClassificationCrypto, DEFAULT_KEY_ID, isColumnEnvelope, parseColumnEnvelope, } from './classification-crypto.js';
|
|
25
|
-
export { agentSchema, analyticsSchema, auditSchema, channelSchema, credentialSchema, deploymentSchema, flagSchema, scopeSchema, secretSchema, sessionSchema, virtualUserSchema, webhookSchema, workflowSchema, pikkuSchemas, requiredPikkuSchemas, applyPikkuSchemas, compilePikkuSchemas, requirePikkuSchema, resolveRequirements, } from './schema/index.js';
|
|
27
|
+
export { agentSchema, analyticsSchema, auditSchema, channelSchema, credentialSchema, deploymentSchema, flagSchema, incomingWebhookSchema, scopeSchema, secretSchema, sessionSchema, virtualUserSchema, webhookSchema, workflowSchema, pikkuSchemas, requiredPikkuSchemas, applyPikkuSchemas, compilePikkuSchemas, requirePikkuSchema, resolveRequirements, } from './schema/index.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { IncomingWebhookService, type IncomingWebhookAttempt, type IncomingWebhookReceiptRecord } from '@pikku/core/services';
|
|
2
|
+
import type { QueueService } from '@pikku/core/queue';
|
|
3
|
+
import type { TriggerEvent, WebhookRequest } from '@pikku/core/trigger';
|
|
4
|
+
import type { Kysely } from 'kysely';
|
|
5
|
+
import type { KyselyPikkuDB } from './kysely-tables.js';
|
|
6
|
+
/**
|
|
7
|
+
* Durable {@link IncomingWebhookService}: records a `webhook_receipt` row per
|
|
8
|
+
* accepted event before queueing it, so a provider's redelivery of an event id
|
|
9
|
+
* it has already sent is dropped, and each trigger attempt rolls the receipt's
|
|
10
|
+
* status forward.
|
|
11
|
+
*/
|
|
12
|
+
export declare class KyselyIncomingWebhookService extends IncomingWebhookService {
|
|
13
|
+
private db;
|
|
14
|
+
private initialized;
|
|
15
|
+
constructor(queueService: QueueService, db: Kysely<KyselyPikkuDB>, retries?: number);
|
|
16
|
+
init(): Promise<void>;
|
|
17
|
+
accept({ source, events, }: {
|
|
18
|
+
source: string;
|
|
19
|
+
request: WebhookRequest;
|
|
20
|
+
events: TriggerEvent[];
|
|
21
|
+
}): Promise<number>;
|
|
22
|
+
/** The new receipt's id, or undefined when this provider event id was already received. */
|
|
23
|
+
private record;
|
|
24
|
+
recordAttempt(receiptId: string, { error }: IncomingWebhookAttempt): Promise<void>;
|
|
25
|
+
listReceipts(opts?: {
|
|
26
|
+
source?: string;
|
|
27
|
+
limit?: number;
|
|
28
|
+
}): Promise<IncomingWebhookReceiptRecord[]>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { IncomingWebhookService, } from '@pikku/core/services';
|
|
2
|
+
import { requirePikkuSchema } from './schema/index.js';
|
|
3
|
+
import { incomingWebhookSchema } from './schema/incoming-webhook.schema.js';
|
|
4
|
+
/**
|
|
5
|
+
* Durable {@link IncomingWebhookService}: records a `webhook_receipt` row per
|
|
6
|
+
* accepted event before queueing it, so a provider's redelivery of an event id
|
|
7
|
+
* it has already sent is dropped, and each trigger attempt rolls the receipt's
|
|
8
|
+
* status forward.
|
|
9
|
+
*/
|
|
10
|
+
export class KyselyIncomingWebhookService extends IncomingWebhookService {
|
|
11
|
+
db;
|
|
12
|
+
initialized = false;
|
|
13
|
+
constructor(queueService, db, retries) {
|
|
14
|
+
super(queueService, retries);
|
|
15
|
+
this.db = db;
|
|
16
|
+
}
|
|
17
|
+
async init() {
|
|
18
|
+
if (this.initialized)
|
|
19
|
+
return;
|
|
20
|
+
await requirePikkuSchema(this.db, incomingWebhookSchema);
|
|
21
|
+
this.initialized = true;
|
|
22
|
+
}
|
|
23
|
+
async accept({ source, events, }) {
|
|
24
|
+
let accepted = 0;
|
|
25
|
+
for (const event of events) {
|
|
26
|
+
const receiptId = await this.record(source, event);
|
|
27
|
+
if (!receiptId)
|
|
28
|
+
continue;
|
|
29
|
+
try {
|
|
30
|
+
await this.enqueue({ source, event, receiptId });
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
// Without the receipt the provider's retry is accepted again rather
|
|
34
|
+
// than dropped as a duplicate of an event that was never queued.
|
|
35
|
+
await this.db
|
|
36
|
+
.deleteFrom('webhookReceipt')
|
|
37
|
+
.where('receiptId', '=', receiptId)
|
|
38
|
+
.execute();
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
accepted++;
|
|
42
|
+
}
|
|
43
|
+
return accepted;
|
|
44
|
+
}
|
|
45
|
+
/** The new receipt's id, or undefined when this provider event id was already received. */
|
|
46
|
+
async record(source, event) {
|
|
47
|
+
const receiptId = globalThis.crypto.randomUUID();
|
|
48
|
+
const providerEventId = event.id ?? null;
|
|
49
|
+
try {
|
|
50
|
+
await this.db
|
|
51
|
+
.insertInto('webhookReceipt')
|
|
52
|
+
.values({ receiptId, source, event: event.name, providerEventId })
|
|
53
|
+
.execute();
|
|
54
|
+
return receiptId;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (providerEventId === null)
|
|
58
|
+
throw error;
|
|
59
|
+
const existing = await this.db
|
|
60
|
+
.selectFrom('webhookReceipt')
|
|
61
|
+
.select('receiptId')
|
|
62
|
+
.where('source', '=', source)
|
|
63
|
+
.where('event', '=', event.name)
|
|
64
|
+
.where('providerEventId', '=', providerEventId)
|
|
65
|
+
.executeTakeFirst();
|
|
66
|
+
if (existing)
|
|
67
|
+
return undefined;
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async recordAttempt(receiptId, { error }) {
|
|
72
|
+
await this.db
|
|
73
|
+
.updateTable('webhookReceipt')
|
|
74
|
+
.set((eb) => ({
|
|
75
|
+
attempts: eb('attempts', '+', 1),
|
|
76
|
+
status: error ? 'failed' : 'delivered',
|
|
77
|
+
lastError: error ?? null,
|
|
78
|
+
...(error ? {} : { deliveredAt: new Date() }),
|
|
79
|
+
}))
|
|
80
|
+
.where('receiptId', '=', receiptId)
|
|
81
|
+
.execute();
|
|
82
|
+
}
|
|
83
|
+
async listReceipts(opts) {
|
|
84
|
+
let query = this.db
|
|
85
|
+
.selectFrom('webhookReceipt')
|
|
86
|
+
.selectAll()
|
|
87
|
+
.orderBy('createdAt', 'desc')
|
|
88
|
+
.limit(opts?.limit ?? 100);
|
|
89
|
+
if (opts?.source) {
|
|
90
|
+
query = query.where('source', '=', opts.source);
|
|
91
|
+
}
|
|
92
|
+
return query.execute();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -236,6 +236,17 @@ 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
|
+
declared: Generated<boolean>;
|
|
244
|
+
status: string | null;
|
|
245
|
+
/** The last setup's provider identifiers as JSON; never a secret. */
|
|
246
|
+
state: string | null;
|
|
247
|
+
detail: string | null;
|
|
248
|
+
updatedAt: Generated<Date>;
|
|
249
|
+
}
|
|
239
250
|
/** One subject's short-circuit, in either direction, over a flag's rollout. */
|
|
240
251
|
export interface PikkuFeatureFlagOverridesTable {
|
|
241
252
|
flag: string;
|
|
@@ -282,6 +293,17 @@ export interface WebhookDeliveryAttemptTable {
|
|
|
282
293
|
error: string | null;
|
|
283
294
|
createdAt: Generated<Date>;
|
|
284
295
|
}
|
|
296
|
+
export interface WebhookReceiptTable {
|
|
297
|
+
receiptId: string;
|
|
298
|
+
source: string;
|
|
299
|
+
event: string;
|
|
300
|
+
providerEventId: string | null;
|
|
301
|
+
status: Generated<'pending' | 'delivered' | 'failed'>;
|
|
302
|
+
attempts: Generated<number>;
|
|
303
|
+
lastError: string | null;
|
|
304
|
+
createdAt: Generated<Date>;
|
|
305
|
+
deliveredAt: Date | null;
|
|
306
|
+
}
|
|
285
307
|
/**
|
|
286
308
|
* One virtual-user run. The JSON columns (`goals`, `memory`, `findings`,
|
|
287
309
|
* `tally`) are text the store serialises itself, so the row is byte-identical
|
|
@@ -410,6 +432,7 @@ export interface KyselyPikkuDB {
|
|
|
410
432
|
pikkuUserScope: PikkuUserScopeTable;
|
|
411
433
|
pikkuFeatureFlags: PikkuFeatureFlagsTable;
|
|
412
434
|
pikkuFeatureFlagOverrides: PikkuFeatureFlagOverridesTable;
|
|
435
|
+
pikkuTriggerSource: PikkuTriggerSourceTable;
|
|
413
436
|
channels: ChannelsTable;
|
|
414
437
|
channelSubscriptions: ChannelSubscriptionsTable;
|
|
415
438
|
workflowRuns: WorkflowRunsTable;
|
|
@@ -433,6 +456,7 @@ export interface KyselyPikkuDB {
|
|
|
433
456
|
pikkuUserSessions: UserSessionsTable;
|
|
434
457
|
webhookDelivery: WebhookDeliveryTable;
|
|
435
458
|
webhookDeliveryAttempt: WebhookDeliveryAttemptTable;
|
|
459
|
+
webhookReceipt: WebhookReceiptTable;
|
|
436
460
|
virtualUserRun: VirtualUserRunTable;
|
|
437
461
|
virtualUserRunStep: VirtualUserRunStepTable;
|
|
438
462
|
virtualUserSchedule: VirtualUserScheduleTable;
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
deleteTriggerSource(name: string): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
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
|
+
declared: !!row.declared,
|
|
19
|
+
status: row.status,
|
|
20
|
+
state: parseState(row.state),
|
|
21
|
+
detail: row.detail,
|
|
22
|
+
updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null,
|
|
23
|
+
});
|
|
24
|
+
export class KyselyTriggerSourceStore {
|
|
25
|
+
db;
|
|
26
|
+
initialized = false;
|
|
27
|
+
constructor(db) {
|
|
28
|
+
this.db = db;
|
|
29
|
+
}
|
|
30
|
+
async init() {
|
|
31
|
+
if (this.initialized)
|
|
32
|
+
return;
|
|
33
|
+
await requirePikkuSchema(this.db, triggerSourceSchema);
|
|
34
|
+
this.initialized = true;
|
|
35
|
+
}
|
|
36
|
+
async syncTriggerSources(sources) {
|
|
37
|
+
await this.db.transaction().execute(async (trx) => {
|
|
38
|
+
for (const { name, kind } of sources) {
|
|
39
|
+
await trx
|
|
40
|
+
.insertInto('pikkuTriggerSource')
|
|
41
|
+
.values({ name, kind, declared: true })
|
|
42
|
+
.onConflict((oc) => oc.column('name').doUpdateSet({ kind, declared: true }))
|
|
43
|
+
.execute();
|
|
44
|
+
}
|
|
45
|
+
const markStale = trx
|
|
46
|
+
.updateTable('pikkuTriggerSource')
|
|
47
|
+
.set({ declared: false });
|
|
48
|
+
await (sources.length > 0
|
|
49
|
+
? markStale.where('name', 'not in', sources.map((s) => s.name))
|
|
50
|
+
: markStale).execute();
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async listTriggerSources() {
|
|
54
|
+
const rows = await this.db
|
|
55
|
+
.selectFrom('pikkuTriggerSource')
|
|
56
|
+
.selectAll()
|
|
57
|
+
.orderBy('name')
|
|
58
|
+
.execute();
|
|
59
|
+
return rows.map(toRow);
|
|
60
|
+
}
|
|
61
|
+
async getTriggerSource(name) {
|
|
62
|
+
const row = await this.db
|
|
63
|
+
.selectFrom('pikkuTriggerSource')
|
|
64
|
+
.selectAll()
|
|
65
|
+
.where('name', '=', name)
|
|
66
|
+
.executeTakeFirst();
|
|
67
|
+
return row ? toRow(row) : null;
|
|
68
|
+
}
|
|
69
|
+
async recordTriggerSource(name, result) {
|
|
70
|
+
const { numUpdatedRows } = await this.db
|
|
71
|
+
.updateTable('pikkuTriggerSource')
|
|
72
|
+
.set({
|
|
73
|
+
status: result.status,
|
|
74
|
+
...(result.state !== undefined
|
|
75
|
+
? { state: result.state ? JSON.stringify(result.state) : null }
|
|
76
|
+
: {}),
|
|
77
|
+
detail: result.detail ?? null,
|
|
78
|
+
updatedAt: new Date(),
|
|
79
|
+
})
|
|
80
|
+
.where('name', '=', name)
|
|
81
|
+
.executeTakeFirst();
|
|
82
|
+
if (!numUpdatedRows) {
|
|
83
|
+
throw new Error(`Unknown trigger source: ${name}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async deleteTriggerSource(name) {
|
|
87
|
+
await this.db
|
|
88
|
+
.deleteFrom('pikkuTriggerSource')
|
|
89
|
+
.where('name', '=', name)
|
|
90
|
+
.execute();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { sql } from 'kysely';
|
|
2
|
+
/** One row per event a webhook source accepted, keyed for provider de-duplication. */
|
|
3
|
+
export const incomingWebhookSchema = {
|
|
4
|
+
name: 'incoming-webhook',
|
|
5
|
+
ownedBy: ['incomingWebhookService'],
|
|
6
|
+
statements: [
|
|
7
|
+
(db) => db.schema
|
|
8
|
+
.createTable('webhookReceipt')
|
|
9
|
+
.addColumn('receiptId', 'text', (col) => col.primaryKey())
|
|
10
|
+
.addColumn('source', 'text', (col) => col.notNull())
|
|
11
|
+
.addColumn('event', 'text', (col) => col.notNull())
|
|
12
|
+
.addColumn('providerEventId', 'text')
|
|
13
|
+
.addColumn('status', 'text', (col) => col.defaultTo('pending').notNull())
|
|
14
|
+
.addColumn('attempts', 'integer', (col) => col.defaultTo(0).notNull())
|
|
15
|
+
.addColumn('lastError', 'text')
|
|
16
|
+
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
17
|
+
.addColumn('deliveredAt', 'timestamp'),
|
|
18
|
+
(db) => db.schema
|
|
19
|
+
.createIndex('idx_webhook_receipt_provider_event')
|
|
20
|
+
.unique()
|
|
21
|
+
.on('webhookReceipt')
|
|
22
|
+
.columns(['source', 'event', 'providerEventId']),
|
|
23
|
+
(db) => db.schema
|
|
24
|
+
.createIndex('idx_webhook_receipt_source_created')
|
|
25
|
+
.on('webhookReceipt')
|
|
26
|
+
.columns(['source', 'createdAt']),
|
|
27
|
+
],
|
|
28
|
+
};
|
|
@@ -24,6 +24,8 @@ 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';
|
|
28
|
+
export { incomingWebhookSchema } from './incoming-webhook.schema.js';
|
|
27
29
|
export { scopeSchema } from './scope.schema.js';
|
|
28
30
|
export { secretSchema } from './secret.schema.js';
|
|
29
31
|
export { sessionSchema } from './session.schema.js';
|
package/dist/src/schema/index.js
CHANGED
|
@@ -8,6 +8,8 @@ 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';
|
|
12
|
+
import { incomingWebhookSchema } from './incoming-webhook.schema.js';
|
|
11
13
|
import { secretSchema } from './secret.schema.js';
|
|
12
14
|
import { sessionSchema } from './session.schema.js';
|
|
13
15
|
import { webhookSchema } from './webhook.schema.js';
|
|
@@ -36,10 +38,12 @@ export const pikkuSchemas = [
|
|
|
36
38
|
credentialSchema,
|
|
37
39
|
deploymentSchema,
|
|
38
40
|
webhookSchema,
|
|
41
|
+
incomingWebhookSchema,
|
|
39
42
|
workflowSchema,
|
|
40
43
|
agentSchema,
|
|
41
44
|
scopeSchema,
|
|
42
45
|
flagSchema,
|
|
46
|
+
triggerSourceSchema,
|
|
43
47
|
auditSchema,
|
|
44
48
|
analyticsSchema,
|
|
45
49
|
virtualUserSchema,
|
|
@@ -52,6 +56,8 @@ export { channelSchema } from './channel.schema.js';
|
|
|
52
56
|
export { credentialSchema } from './credential.schema.js';
|
|
53
57
|
export { deploymentSchema } from './deployment.schema.js';
|
|
54
58
|
export { flagSchema } from './flag.schema.js';
|
|
59
|
+
export { triggerSourceSchema } from './trigger-source.schema.js';
|
|
60
|
+
export { incomingWebhookSchema } from './incoming-webhook.schema.js';
|
|
55
61
|
export { scopeSchema } from './scope.schema.js';
|
|
56
62
|
export { secretSchema } from './secret.schema.js';
|
|
57
63
|
export { sessionSchema } from './session.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,20 @@
|
|
|
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('declared', 'boolean', (col) => col.defaultTo(true).notNull())
|
|
15
|
+
.addColumn('status', 'text')
|
|
16
|
+
.addColumn('state', 'text')
|
|
17
|
+
.addColumn('detail', 'text')
|
|
18
|
+
.addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
19
|
+
],
|
|
20
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/kysely",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.30",
|
|
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.
|
|
29
|
+
"@pikku/core": "^0.12.128"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"kysely": "^0.29.5"
|