@pg-prime/events 0.0.0-stage → 0.2.0
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/LICENSE +373 -0
- package/README.md +43 -2
- package/dist/channel.d.ts +19 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +51 -0
- package/dist/channel.js.map +1 -0
- package/dist/define.d.ts +49 -0
- package/dist/define.d.ts.map +1 -0
- package/dist/define.js +39 -0
- package/dist/define.js.map +1 -0
- package/dist/errors.d.ts +19 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +30 -0
- package/dist/errors.js.map +1 -0
- package/dist/events.d.ts +57 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +99 -0
- package/dist/events.js.map +1 -0
- package/dist/hooks.d.ts +40 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +27 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/log/cursor.d.ts +37 -0
- package/dist/log/cursor.d.ts.map +1 -0
- package/dist/log/cursor.js +58 -0
- package/dist/log/cursor.js.map +1 -0
- package/dist/log/migrations.d.ts +3 -0
- package/dist/log/migrations.d.ts.map +1 -0
- package/dist/log/migrations.js +55 -0
- package/dist/log/migrations.js.map +1 -0
- package/dist/log/sql.d.ts +68 -0
- package/dist/log/sql.d.ts.map +1 -0
- package/dist/log/sql.js +251 -0
- package/dist/log/sql.js.map +1 -0
- package/dist/log/subscription.d.ts +53 -0
- package/dist/log/subscription.d.ts.map +1 -0
- package/dist/log/subscription.js +272 -0
- package/dist/log/subscription.js.map +1 -0
- package/dist/log/topic.d.ts +48 -0
- package/dist/log/topic.d.ts.map +1 -0
- package/dist/log/topic.js +111 -0
- package/dist/log/topic.js.map +1 -0
- package/dist/payload.d.ts +40 -0
- package/dist/payload.d.ts.map +1 -0
- package/dist/payload.js +53 -0
- package/dist/payload.js.map +1 -0
- package/dist/unsupported-typescript.d.ts +70 -0
- package/dist/util.d.ts +11 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +31 -0
- package/dist/util.js.map +1 -0
- package/dist/waker.d.ts +22 -0
- package/dist/waker.d.ts.map +1 -0
- package/dist/waker.js +86 -0
- package/dist/waker.js.map +1 -0
- package/package.json +53 -3
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { AsyncDisposable_, Db } from 'pg-prime';
|
|
2
|
+
import type { ChannelHandle } from './channel.js';
|
|
3
|
+
import type { ChannelDef, EventsDefinitions, PayloadOf, SubscriptionDef, TopicDef } from './define.js';
|
|
4
|
+
import type { EventsHooks, Hooks } from './hooks.js';
|
|
5
|
+
import type { Statements } from './log/sql.js';
|
|
6
|
+
import type { SubscriptionHandle } from './log/subscription.js';
|
|
7
|
+
import type { TopicHandle } from './log/topic.js';
|
|
8
|
+
export interface EventsConfig<D extends EventsDefinitions> {
|
|
9
|
+
db: Db;
|
|
10
|
+
/** Default `'pgprime_events'`. */
|
|
11
|
+
schema?: string;
|
|
12
|
+
/** Default true; false only checks the version and throws `SchemaVersionError` when behind. */
|
|
13
|
+
autoMigrate?: boolean;
|
|
14
|
+
define?: D;
|
|
15
|
+
hooks?: EventsHooks;
|
|
16
|
+
}
|
|
17
|
+
export interface Events<D extends EventsDefinitions> extends AsyncDisposable_ {
|
|
18
|
+
readonly channels: {
|
|
19
|
+
readonly [K in keyof D['channels']]: ChannelHandle<PayloadOf<D['channels'][K]>>;
|
|
20
|
+
};
|
|
21
|
+
readonly topics: {
|
|
22
|
+
readonly [K in keyof D['topics']]: TopicHandle<PayloadOf<D['topics'][K]>>;
|
|
23
|
+
};
|
|
24
|
+
readonly subscriptions: {
|
|
25
|
+
readonly [K in keyof D['subscriptions']]: SubscriptionHandle<PayloadOf<D['subscriptions'][K]>>;
|
|
26
|
+
};
|
|
27
|
+
channel<T>(def: ChannelDef<T>): ChannelHandle<T>;
|
|
28
|
+
topic<T>(def: TopicDef<T>): TopicHandle<T>;
|
|
29
|
+
subscription<T>(def: SubscriptionDef<T>): SubscriptionHandle<T>;
|
|
30
|
+
/** Migrates and upserts the declared topics and subscriptions; required before any `{ tx }` call. */
|
|
31
|
+
start(): Promise<void>;
|
|
32
|
+
/** Applies missing schema versions, whatever `autoMigrate` says. */
|
|
33
|
+
migrate(): Promise<{
|
|
34
|
+
from: number;
|
|
35
|
+
to: number;
|
|
36
|
+
}>;
|
|
37
|
+
observe(hooks: EventsHooks): () => void;
|
|
38
|
+
/** Stops every reader and tail this instance started; `db` stays open. */
|
|
39
|
+
close(): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
/** What the handles share. */
|
|
42
|
+
export interface Core {
|
|
43
|
+
readonly db: Db;
|
|
44
|
+
readonly sql: Statements;
|
|
45
|
+
readonly hooks: Hooks;
|
|
46
|
+
/** Readers and tails, closed by `events.close()`. */
|
|
47
|
+
readonly running: Set<{
|
|
48
|
+
close(): Promise<void>;
|
|
49
|
+
}>;
|
|
50
|
+
topicChannel(topic: string): string;
|
|
51
|
+
/** Ensures the schema, then upserts the topic, or the subscription with its cursor seeded once. */
|
|
52
|
+
ready(def: TopicDef<any> | SubscriptionDef<any>): Promise<void>;
|
|
53
|
+
forget(def: SubscriptionDef<any>): void;
|
|
54
|
+
assertStarted(what: string): void;
|
|
55
|
+
}
|
|
56
|
+
export declare function pgEvents<const D extends EventsDefinitions = {}>(config: EventsConfig<D>): Events<D>;
|
|
57
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
|
package/dist/events.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ConfigError, migrateOwnedSchema, quoteIdentPart } from 'pg-prime';
|
|
2
|
+
import { channelHandle, engineChannel } from './channel.js';
|
|
3
|
+
import { NotStartedError, SchemaVersionError } from './errors.js';
|
|
4
|
+
import { createHooks } from './hooks.js';
|
|
5
|
+
import { BEGINNING, seed } from './log/cursor.js';
|
|
6
|
+
import { MIGRATIONS } from './log/migrations.js';
|
|
7
|
+
import { statements } from './log/sql.js';
|
|
8
|
+
import { subscriptionHandle } from './log/subscription.js';
|
|
9
|
+
import { topicHandle } from './log/topic.js';
|
|
10
|
+
import { ASYNC_DISPOSE } from './util.js';
|
|
11
|
+
export function pgEvents(config) {
|
|
12
|
+
const { db, define = {} } = config;
|
|
13
|
+
const schema = config.schema ?? 'pgprime_events';
|
|
14
|
+
quoteIdentPart(schema);
|
|
15
|
+
const sql = statements(schema);
|
|
16
|
+
const hooks = createHooks(config.hooks);
|
|
17
|
+
let ensuring;
|
|
18
|
+
let ensured = false;
|
|
19
|
+
const memo = new Map();
|
|
20
|
+
const key = (def) => def.kind === 'topic' ? `t/${def.name}` : `s/${def.topic.name}/${def.name}`;
|
|
21
|
+
const migrate = async (apply) => {
|
|
22
|
+
try {
|
|
23
|
+
const r = await migrateOwnedSchema(db, { schema, migrations: MIGRATIONS, apply });
|
|
24
|
+
if (r.to < MIGRATIONS.length) {
|
|
25
|
+
throw new SchemaVersionError(`@pg-prime/events: schema ${schema} is at version ${r.to} and this client needs ` +
|
|
26
|
+
`${MIGRATIONS.length}. Run events.migrate().`);
|
|
27
|
+
}
|
|
28
|
+
ensured = true;
|
|
29
|
+
return r;
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
throw e instanceof ConfigError ? new SchemaVersionError(e.message, e) : e;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const ensure = () => (ensuring ??= migrate(config.autoMigrate !== false).catch((e) => {
|
|
36
|
+
ensuring = undefined;
|
|
37
|
+
throw e;
|
|
38
|
+
}));
|
|
39
|
+
const core = {
|
|
40
|
+
db,
|
|
41
|
+
sql,
|
|
42
|
+
hooks,
|
|
43
|
+
running: new Set(),
|
|
44
|
+
topicChannel: (topic) => engineChannel(schema, 't', topic),
|
|
45
|
+
ready(def) {
|
|
46
|
+
const k = key(def);
|
|
47
|
+
let p = memo.get(k);
|
|
48
|
+
if (p === undefined) {
|
|
49
|
+
p = (async () => {
|
|
50
|
+
await ensure();
|
|
51
|
+
if (def.kind === 'topic') {
|
|
52
|
+
return sql.upsertTopic(db, def.name, def.keepMs, def.keepUntilConsumed);
|
|
53
|
+
}
|
|
54
|
+
await core.ready(def.topic);
|
|
55
|
+
const c = def.from === 'beginning'
|
|
56
|
+
? BEGINNING
|
|
57
|
+
: await sql.seedNow(db).then((x) => seed(x.xmax, x.xip));
|
|
58
|
+
await sql.upsertSubscription(db, def.topic.name, def.name, def.types, c);
|
|
59
|
+
})();
|
|
60
|
+
p.catch(() => memo.delete(k));
|
|
61
|
+
memo.set(k, p);
|
|
62
|
+
}
|
|
63
|
+
return p;
|
|
64
|
+
},
|
|
65
|
+
forget: (def) => void memo.delete(key(def)),
|
|
66
|
+
assertStarted(what) {
|
|
67
|
+
if (!ensured)
|
|
68
|
+
throw new NotStartedError(what);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
const handles = (defs, f) => Object.freeze(Object.fromEntries(Object.entries(defs ?? {}).map(([k, d]) => [k, f(d)])));
|
|
72
|
+
const close = async () => {
|
|
73
|
+
await Promise.all([...core.running].map((r) => r.close()));
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
channels: handles(define.channels, (d) => channelHandle(db, d)),
|
|
77
|
+
topics: handles(define.topics, (d) => topicHandle(core, d)),
|
|
78
|
+
subscriptions: handles(define.subscriptions, (d) => subscriptionHandle(core, d)),
|
|
79
|
+
channel: (def) => channelHandle(db, def),
|
|
80
|
+
topic: (def) => topicHandle(core, def),
|
|
81
|
+
subscription: (def) => subscriptionHandle(core, def),
|
|
82
|
+
async start() {
|
|
83
|
+
await ensure();
|
|
84
|
+
for (const d of Object.values(define.topics ?? {}))
|
|
85
|
+
await core.ready(d);
|
|
86
|
+
for (const d of Object.values(define.subscriptions ?? {}))
|
|
87
|
+
await core.ready(d);
|
|
88
|
+
},
|
|
89
|
+
migrate: async () => {
|
|
90
|
+
const r = await migrate(true);
|
|
91
|
+
ensuring = Promise.resolve(r);
|
|
92
|
+
return r;
|
|
93
|
+
},
|
|
94
|
+
observe: (h) => hooks.observe(h),
|
|
95
|
+
close,
|
|
96
|
+
[ASYNC_DISPOSE]: close,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type InternalKind = 'listen-unavailable' | 'heartbeat-failed' | 'subscription-behind-retention' | 'reader-failed' | 'hook-failed';
|
|
2
|
+
export interface EventsHooks {
|
|
3
|
+
onPublish?(e: {
|
|
4
|
+
topic: string;
|
|
5
|
+
count: number;
|
|
6
|
+
inTx: boolean;
|
|
7
|
+
}): void;
|
|
8
|
+
onDeliver?(e: {
|
|
9
|
+
topic: string;
|
|
10
|
+
subscription: string;
|
|
11
|
+
count: number;
|
|
12
|
+
durationMs: number;
|
|
13
|
+
}): void;
|
|
14
|
+
onRetry?(e: {
|
|
15
|
+
topic: string;
|
|
16
|
+
subscription: string;
|
|
17
|
+
entry: bigint;
|
|
18
|
+
attempt: number;
|
|
19
|
+
error: unknown;
|
|
20
|
+
}): void;
|
|
21
|
+
onPark?(e: {
|
|
22
|
+
topic: string;
|
|
23
|
+
subscription: string;
|
|
24
|
+
entry: bigint;
|
|
25
|
+
error: unknown;
|
|
26
|
+
}): void;
|
|
27
|
+
onInternal?(e: {
|
|
28
|
+
kind: InternalKind;
|
|
29
|
+
message: string;
|
|
30
|
+
cause?: unknown;
|
|
31
|
+
}): void;
|
|
32
|
+
}
|
|
33
|
+
/** Fan-out to every observer; a throwing hook is reported as `hook-failed`, never rethrown. */
|
|
34
|
+
export interface Hooks {
|
|
35
|
+
emit<K extends keyof EventsHooks>(name: K, e: Parameters<NonNullable<EventsHooks[K]>>[0]): void;
|
|
36
|
+
internal(kind: InternalKind, message: string, cause?: unknown): void;
|
|
37
|
+
observe(h: EventsHooks): () => void;
|
|
38
|
+
}
|
|
39
|
+
export declare function createHooks(initial?: EventsHooks): Hooks;
|
|
40
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GACpB,oBAAoB,GACpB,kBAAkB,GAClB,+BAA+B,GAC/B,eAAe,GACf,aAAa,CAAA;AAEjB,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,CAAC,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;IACpE,SAAS,CAAC,CAAC,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC/F,OAAO,CAAC,CAAC,CAAC,EAAE;QACV,KAAK,EAAE,MAAM,CAAA;QACb,YAAY,EAAE,MAAM,CAAA;QACpB,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;QACf,KAAK,EAAE,OAAO,CAAA;KACf,GAAG,IAAI,CAAA;IACR,MAAM,CAAC,CAAC,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;IACxF,UAAU,CAAC,CAAC,CAAC,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;CAC/E;AAED,+FAA+F;AAC/F,MAAM,WAAW,KAAK;IACpB,IAAI,CAAC,CAAC,SAAS,MAAM,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;IAC/F,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IACpE,OAAO,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,IAAI,CAAA;CACpC;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,KAAK,CAsBxD"}
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function createHooks(initial) {
|
|
2
|
+
const all = new Set(initial === undefined ? [] : [initial]);
|
|
3
|
+
const hooks = {
|
|
4
|
+
emit(name, e) {
|
|
5
|
+
for (const h of all) {
|
|
6
|
+
try {
|
|
7
|
+
;
|
|
8
|
+
h[name]?.call(h, e);
|
|
9
|
+
}
|
|
10
|
+
catch (cause) {
|
|
11
|
+
if (name === 'onInternal')
|
|
12
|
+
continue;
|
|
13
|
+
hooks.internal('hook-failed', `@pg-prime/events: the ${name} hook threw.`, cause);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
internal(kind, message, cause) {
|
|
18
|
+
hooks.emit('onInternal', cause === undefined ? { kind, message } : { kind, message, cause });
|
|
19
|
+
},
|
|
20
|
+
observe(h) {
|
|
21
|
+
all.add(h);
|
|
22
|
+
return () => void all.delete(h);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
return hooks;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AA4BA,MAAM,UAAU,WAAW,CAAC,OAAqB;IAC/C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAc,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;IACxE,MAAM,KAAK,GAAU;QACnB,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;gBACpB,IAAI,CAAC;oBACH,CAAC;oBAAC,CAAC,CAAC,IAAI,CAAwC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;gBAC9D,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,IAAI,KAAK,YAAY;wBAAE,SAAQ;oBACnC,KAAK,CAAC,QAAQ,CAAC,aAAa,EAAE,yBAAyB,IAAI,cAAc,EAAE,KAAK,CAAC,CAAA;gBACnF,CAAC;YACH,CAAC;QACH,CAAC;QACD,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK;YAC3B,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAA;QAC9F,CAAC;QACD,OAAO,CAAC,CAAC;YACP,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;YACV,OAAO,GAAG,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QACjC,CAAC;KACF,CAAA;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { defineChannel, defineSubscription, defineTopic } from './define.js';
|
|
2
|
+
export type { ChannelDef, EventsDefinitions, PayloadOf, RetryOptions, SubscriptionDef, TopicDef, } from './define.js';
|
|
3
|
+
export type { PayloadOptions, StandardSchemaV1 } from './payload.js';
|
|
4
|
+
export { pgEvents } from './events.js';
|
|
5
|
+
export type { Events, EventsConfig } from './events.js';
|
|
6
|
+
export { engineChannel, engineChannelSql } from './channel.js';
|
|
7
|
+
export type { ChannelHandle } from './channel.js';
|
|
8
|
+
export { waker } from './waker.js';
|
|
9
|
+
export type { WakeReason, Waker, WakerOptions } from './waker.js';
|
|
10
|
+
export type { Entry, PublishOptions, TopicHandle } from './log/topic.js';
|
|
11
|
+
export type { BatchHandler, EntryHandler, ReadContext, Reader, RunOptions, SubscriptionHandle, } from './log/subscription.js';
|
|
12
|
+
export type { EventsHooks, InternalKind } from './hooks.js';
|
|
13
|
+
export { EventsLeaseLostError, NotStartedError, PayloadError, SchemaVersionError, } from './errors.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC5E,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,eAAe,EACf,QAAQ,GACT,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC9D,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACjE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACxE,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,MAAM,EACN,UAAU,EACV,kBAAkB,GACnB,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC3D,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,YAAY,EACZ,kBAAkB,GACnB,MAAM,aAAa,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { defineChannel, defineSubscription, defineTopic } from './define.js';
|
|
2
|
+
export { pgEvents } from './events.js';
|
|
3
|
+
export { engineChannel, engineChannelSql } from './channel.js';
|
|
4
|
+
export { waker } from './waker.js';
|
|
5
|
+
export { EventsLeaseLostError, NotStartedError, PayloadError, SchemaVersionError, } from './errors.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAU5E,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE9D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAYlC,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,YAAY,EACZ,kBAAkB,GACnB,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Position `(xid, id)` plus `pending`: transactions below the position that were still running
|
|
3
|
+
* when a read stepped over them, each mapped to the last id delivered from it (0: none).
|
|
4
|
+
*/
|
|
5
|
+
export interface Cursor {
|
|
6
|
+
readonly xid: bigint;
|
|
7
|
+
readonly id: bigint;
|
|
8
|
+
readonly pending: ReadonlyMap<bigint, bigint>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* What a read saw: the last unfiltered `next` row, the last unfiltered `late` row when `late`
|
|
12
|
+
* filled the read limit (more may follow), and the snapshot's running xids.
|
|
13
|
+
*/
|
|
14
|
+
export interface ReadView {
|
|
15
|
+
readonly pos: {
|
|
16
|
+
readonly xid: bigint;
|
|
17
|
+
readonly id: bigint;
|
|
18
|
+
} | null;
|
|
19
|
+
readonly late: {
|
|
20
|
+
readonly xid: bigint;
|
|
21
|
+
readonly id: bigint;
|
|
22
|
+
} | null;
|
|
23
|
+
readonly running: readonly bigint[];
|
|
24
|
+
}
|
|
25
|
+
export declare const BEGINNING: Cursor;
|
|
26
|
+
/** `from: 'now'`: everything that commits after the snapshot `(xmax, xip)`. */
|
|
27
|
+
export declare function seed(xmax: bigint, xip: readonly bigint[]): Cursor;
|
|
28
|
+
/** The cursor right after acknowledging `e`, one entry of `read`. */
|
|
29
|
+
export declare function advance(c: Cursor, read: ReadView, e: {
|
|
30
|
+
xid: bigint;
|
|
31
|
+
id: bigint;
|
|
32
|
+
}): Cursor;
|
|
33
|
+
/** The cursor once everything `read` delivered is acknowledged, even when it delivered nothing. */
|
|
34
|
+
export declare function advanceTo(c: Cursor, read: ReadView): Cursor;
|
|
35
|
+
export declare function encodeCursor(c: Cursor): string;
|
|
36
|
+
export declare function decodeCursor(s: string): Cursor;
|
|
37
|
+
//# sourceMappingURL=cursor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/log/cursor.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC9C;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,GAAG,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAClE,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACnE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC;AAED,eAAO,MAAM,SAAS,EAAE,MAAgD,CAAA;AAExE,+EAA+E;AAC/E,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEjE;AAED,qEAAqE;AACrE,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAQzF;AAED,mGAAmG;AACnG,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAa3D;AAMD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG9C;AAID,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAW9C"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { UsageError } from 'pg-prime';
|
|
2
|
+
export const BEGINNING = { xid: 0n, id: 0n, pending: new Map() };
|
|
3
|
+
/** `from: 'now'`: everything that commits after the snapshot `(xmax, xip)`. */
|
|
4
|
+
export function seed(xmax, xip) {
|
|
5
|
+
return { xid: xmax, id: 0n, pending: new Map(xip.map((x) => [x, 0n])) };
|
|
6
|
+
}
|
|
7
|
+
/** The cursor right after acknowledging `e`, one entry of `read`. */
|
|
8
|
+
export function advance(c, read, e) {
|
|
9
|
+
const pending = new Map(c.pending);
|
|
10
|
+
if (pending.has(e.xid)) {
|
|
11
|
+
pending.set(e.xid, e.id);
|
|
12
|
+
return { xid: c.xid, id: c.id, pending };
|
|
13
|
+
}
|
|
14
|
+
addRunning(pending, read.running, e.xid);
|
|
15
|
+
return { xid: e.xid, id: e.id, pending };
|
|
16
|
+
}
|
|
17
|
+
/** The cursor once everything `read` delivered is acknowledged, even when it delivered nothing. */
|
|
18
|
+
export function advanceTo(c, read) {
|
|
19
|
+
const pending = new Map(c.pending);
|
|
20
|
+
if (read.pos !== null)
|
|
21
|
+
addRunning(pending, read.running, read.pos.xid);
|
|
22
|
+
const running = new Set(read.running);
|
|
23
|
+
// A finished transaction's entries are all visible, and `late` reads them in (xid, id) order.
|
|
24
|
+
for (const x of pending.keys()) {
|
|
25
|
+
if (running.has(x) || (read.late !== null && x > read.late.xid))
|
|
26
|
+
continue;
|
|
27
|
+
if (x === read.late?.xid)
|
|
28
|
+
pending.set(x, read.late.id);
|
|
29
|
+
else
|
|
30
|
+
pending.delete(x);
|
|
31
|
+
}
|
|
32
|
+
return read.pos === null
|
|
33
|
+
? { xid: c.xid, id: c.id, pending }
|
|
34
|
+
: { xid: read.pos.xid, id: read.pos.id, pending };
|
|
35
|
+
}
|
|
36
|
+
function addRunning(pending, running, below) {
|
|
37
|
+
for (const x of running)
|
|
38
|
+
if (x < below && !pending.has(x))
|
|
39
|
+
pending.set(x, 0n);
|
|
40
|
+
}
|
|
41
|
+
export function encodeCursor(c) {
|
|
42
|
+
const p = [...c.pending].sort((a, b) => (a[0] < b[0] ? -1 : 1)).map(([x, a]) => `${x}:${a}`);
|
|
43
|
+
return `${c.xid}.${c.id}${p.length === 0 ? '' : `.${p.join(',')}`}`;
|
|
44
|
+
}
|
|
45
|
+
const CURSOR = /^(\d+)\.(\d+)(?:\.(\d+:\d+(?:,\d+:\d+)*))?$/;
|
|
46
|
+
export function decodeCursor(s) {
|
|
47
|
+
const m = CURSOR.exec(s);
|
|
48
|
+
if (m === null) {
|
|
49
|
+
throw new UsageError(`@pg-prime/events: ${JSON.stringify(s)} is not an Entry.cursor.`);
|
|
50
|
+
}
|
|
51
|
+
const pending = new Map();
|
|
52
|
+
for (const pair of m[3]?.split(',') ?? []) {
|
|
53
|
+
const [x, a] = pair.split(':');
|
|
54
|
+
pending.set(BigInt(x), BigInt(a));
|
|
55
|
+
}
|
|
56
|
+
return { xid: BigInt(m[1]), id: BigInt(m[2]), pending };
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/log/cursor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../src/log/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE9C,eAAO,MAAM,UAAU,EAAE,SAAS,cAAc,EAqD/C,CAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export const MIGRATIONS = [
|
|
2
|
+
{
|
|
3
|
+
version: 1,
|
|
4
|
+
name: 'events log',
|
|
5
|
+
up: (s) => [
|
|
6
|
+
`create table ${s}.topics (
|
|
7
|
+
name text primary key,
|
|
8
|
+
keep_ms bigint,
|
|
9
|
+
keep_until_consumed boolean not null default false,
|
|
10
|
+
maint_at timestamptz not null default '-infinity',
|
|
11
|
+
created_at timestamptz not null default now()
|
|
12
|
+
)`,
|
|
13
|
+
`create table ${s}.entries (
|
|
14
|
+
id bigint generated always as identity primary key,
|
|
15
|
+
xid xid8 not null default pg_current_xact_id(),
|
|
16
|
+
topic text not null,
|
|
17
|
+
type text,
|
|
18
|
+
key text,
|
|
19
|
+
payload jsonb not null,
|
|
20
|
+
headers jsonb,
|
|
21
|
+
at timestamptz not null default clock_timestamp()
|
|
22
|
+
)`,
|
|
23
|
+
`create index entries_cursor on ${s}.entries (topic, xid, id)`,
|
|
24
|
+
`create index entries_age on ${s}.entries (topic, at)`,
|
|
25
|
+
`create table ${s}.subscriptions (
|
|
26
|
+
topic text not null references ${s}.topics (name) on delete cascade,
|
|
27
|
+
name text not null,
|
|
28
|
+
types text[],
|
|
29
|
+
last_xid xid8 not null,
|
|
30
|
+
last_id bigint not null,
|
|
31
|
+
pending xid8[] not null default '{}',
|
|
32
|
+
pending_after bigint[] not null default '{}',
|
|
33
|
+
token text,
|
|
34
|
+
lease_until timestamptz,
|
|
35
|
+
head_id bigint,
|
|
36
|
+
head_size int not null default 0,
|
|
37
|
+
head_attempts int not null default 0,
|
|
38
|
+
head_retry_at timestamptz,
|
|
39
|
+
updated_at timestamptz not null default now(),
|
|
40
|
+
primary key (topic, name)
|
|
41
|
+
) with (fillfactor = 50)`,
|
|
42
|
+
`create table ${s}.parked (
|
|
43
|
+
topic text not null,
|
|
44
|
+
subscription text not null,
|
|
45
|
+
entry bigint not null,
|
|
46
|
+
attempts int not null,
|
|
47
|
+
error text,
|
|
48
|
+
parked_at timestamptz not null default clock_timestamp(),
|
|
49
|
+
primary key (topic, subscription, entry),
|
|
50
|
+
foreign key (topic, subscription) references ${s}.subscriptions (topic, name) on delete cascade
|
|
51
|
+
)`,
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
//# sourceMappingURL=migrations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/log/migrations.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,UAAU,GAA8B;IACnD;QACE,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,YAAY;QAClB,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;YACT,gBAAgB,CAAC;;;;;;QAMf;YACF,gBAAgB,CAAC;;;;;;;;;QASf;YACF,kCAAkC,CAAC,2BAA2B;YAC9D,+BAA+B,CAAC,sBAAsB;YACtD,gBAAgB,CAAC;yCACkB,CAAC;;;;;;;;;;;;;;;+BAeX;YACzB,gBAAgB,CAAC;;;;;;;;uDAQgC,CAAC;QAChD;SACH;KACF;CACF,CAAA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Queryable } from 'pg-prime';
|
|
2
|
+
import type { Cursor, ReadView } from './cursor.js';
|
|
3
|
+
type Q = Queryable<any>;
|
|
4
|
+
export interface EntryRow {
|
|
5
|
+
readonly id: bigint;
|
|
6
|
+
readonly xid: bigint;
|
|
7
|
+
readonly type: string | null;
|
|
8
|
+
readonly key: string | null;
|
|
9
|
+
readonly payload: unknown;
|
|
10
|
+
readonly headers: Record<string, string> | null;
|
|
11
|
+
readonly at: Date;
|
|
12
|
+
}
|
|
13
|
+
export interface LeaseRow {
|
|
14
|
+
readonly token: string;
|
|
15
|
+
readonly cursor: Cursor;
|
|
16
|
+
readonly types: readonly string[] | null;
|
|
17
|
+
readonly headId: bigint | null;
|
|
18
|
+
readonly headSize: number;
|
|
19
|
+
readonly retryInMs: number;
|
|
20
|
+
}
|
|
21
|
+
export interface NewEntry {
|
|
22
|
+
readonly type: string | null;
|
|
23
|
+
readonly key: string | null;
|
|
24
|
+
readonly headers: Record<string, string> | null;
|
|
25
|
+
/** Serialized JSON. */
|
|
26
|
+
readonly payload: string;
|
|
27
|
+
}
|
|
28
|
+
export interface Statements {
|
|
29
|
+
publish(q: Q, topic: string, channel: string, rows: readonly NewEntry[]): Promise<bigint[]>;
|
|
30
|
+
seedNow(q: Q): Promise<{
|
|
31
|
+
xmax: bigint;
|
|
32
|
+
xip: bigint[];
|
|
33
|
+
}>;
|
|
34
|
+
upsertTopic(q: Q, name: string, keepMs: number | null, untilConsumed: boolean): Promise<void>;
|
|
35
|
+
upsertSubscription(q: Q, t: string, s: string, types: readonly string[] | null, c: Cursor): Promise<void>;
|
|
36
|
+
lease(q: Q, t: string, s: string, leaseMs: number): Promise<LeaseRow | undefined>;
|
|
37
|
+
heartbeat(q: Q, t: string, s: string, token: string, leaseMs: number): Promise<boolean>;
|
|
38
|
+
release(q: Q, t: string, s: string, token: string): Promise<void>;
|
|
39
|
+
read(q: Q, t: string, c: Cursor, n: number, types: readonly string[] | null): Promise<{
|
|
40
|
+
view: ReadView;
|
|
41
|
+
rows: EntryRow[];
|
|
42
|
+
}>;
|
|
43
|
+
mark(q: Q, t: string, s: string, token: string, first: bigint, size: number): Promise<number | undefined>;
|
|
44
|
+
commit(q: Q, t: string, s: string, token: string, c: Cursor): Promise<boolean>;
|
|
45
|
+
/** The stored cursor, once any transaction updating it has ended. */
|
|
46
|
+
stored(q: Q, t: string, s: string, token: string): Promise<Cursor | undefined>;
|
|
47
|
+
nack(q: Q, t: string, s: string, token: string, delayMs: number): Promise<boolean>;
|
|
48
|
+
park(q: Q, t: string, s: string, token: string, c: Cursor, entry: bigint, attempts: number, error: string | null): Promise<boolean>;
|
|
49
|
+
maintain(q: Q, t: string, everyMs: number): Promise<{
|
|
50
|
+
deleted: number;
|
|
51
|
+
behind: boolean;
|
|
52
|
+
}>;
|
|
53
|
+
reset(q: Q, t: string, s: string, c: Cursor): Promise<boolean>;
|
|
54
|
+
lag(q: Q, t: string, s: string): Promise<{
|
|
55
|
+
entries: number;
|
|
56
|
+
oldestAt: Date | null;
|
|
57
|
+
}>;
|
|
58
|
+
parked(q: Q, t: string, s: string, limit: number): Promise<(EntryRow & {
|
|
59
|
+
attempts: number;
|
|
60
|
+
error: string | null;
|
|
61
|
+
})[]>;
|
|
62
|
+
discard(q: Q, t: string, s: string, ids: readonly bigint[]): Promise<number>;
|
|
63
|
+
remove(q: Q, t: string, s: string): Promise<void>;
|
|
64
|
+
browse(q: Q, t: string, afterId: bigint, limit: number): Promise<EntryRow[]>;
|
|
65
|
+
}
|
|
66
|
+
export declare function statements(schema: string): Statements;
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=sql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../src/log/sql.ts"],"names":[],"mappings":"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"}
|