@things-factory/webhook 10.1.37 → 10.1.39
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/dist-server/service/index.d.ts +12 -1
- package/dist-server/service/index.js +22 -1
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/outbox/pump-loop.d.ts +38 -0
- package/dist-server/service/outbox/pump-loop.js +93 -0
- package/dist-server/service/outbox/pump-loop.js.map +1 -0
- package/dist-server/service/outbox/pump-round.d.ts +63 -0
- package/dist-server/service/outbox/pump-round.js +67 -0
- package/dist-server/service/outbox/pump-round.js.map +1 -0
- package/dist-server/service/outbox/pump.d.ts +75 -0
- package/dist-server/service/outbox/pump.js +87 -0
- package/dist-server/service/outbox/pump.js.map +1 -0
- package/dist-server/service/outbox/webhook-append-store.d.ts +5 -0
- package/dist-server/service/outbox/webhook-append-store.js +78 -0
- package/dist-server/service/outbox/webhook-append-store.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/dist-server/service/outbox/pump-gate.d.ts +0 -74
- package/dist-server/service/outbox/pump-gate.js +0 -90
- package/dist-server/service/outbox/pump-gate.js.map +0 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.webhookAppendStore = webhookAppendStore;
|
|
4
|
+
const webhook_outbox_event_js_1 = require("../webhook-outbox-event/webhook-outbox-event.js");
|
|
5
|
+
const webhook_sequence_js_1 = require("../webhook-sequence/webhook-sequence.js");
|
|
6
|
+
/**
|
|
7
|
+
* **The front row over this module's own tables** — the writing half of one stream `(domain, peer, scope)`
|
|
8
|
+
* (ADR-0078 decision 2 ②, decision 6).
|
|
9
|
+
*
|
|
10
|
+
* ═════════════════════════════════════════════════════════════════════════
|
|
11
|
+
* ## It takes the open transaction, not a manager
|
|
12
|
+
*
|
|
13
|
+
* `allocate` raises the counter and `insert` writes the rows. If the two are not one transaction, the raise
|
|
14
|
+
* commits on its own and a failed insert leaves a number that names no row - the receiver stops at that hole
|
|
15
|
+
* for good. `OpenTransaction` can only come from `openTransaction`, so the default manager does not compile
|
|
16
|
+
* here. `test/append-store-db.test.ts` breaks an insert after the raise and reads the counter back.
|
|
17
|
+
*
|
|
18
|
+
* ## Raise, then read
|
|
19
|
+
*
|
|
20
|
+
* `increment` takes the row lock, so two writers on the same stream queue behind each other; reading after
|
|
21
|
+
* raising means the run handed out belongs to this transaction. Reading first and writing `last + n` would
|
|
22
|
+
* hand two writers the same numbers.
|
|
23
|
+
*
|
|
24
|
+
* The first append on a stream creates the counter row. Two first appends racing on a brand-new stream
|
|
25
|
+
* meet at the unique index and one of the two business transactions fails whole - loud, and nothing burned.
|
|
26
|
+
*
|
|
27
|
+
* ## What the product keeps per row
|
|
28
|
+
*
|
|
29
|
+
* `lane` and `provenance` are columns (decision 3); a product passes them in `extra`. Anything else in
|
|
30
|
+
* `extra` is refused: a key with no column would be accepted, dropped, and reported as written.
|
|
31
|
+
* ═════════════════════════════════════════════════════════════════════════
|
|
32
|
+
*/
|
|
33
|
+
const EXTRA_COLUMNS = new Set(['lane', 'provenance']);
|
|
34
|
+
function webhookAppendStore(tx, stream) {
|
|
35
|
+
const { domainId, peer, scope } = stream;
|
|
36
|
+
const where = { domain: { id: domainId }, peer, scope };
|
|
37
|
+
return {
|
|
38
|
+
async allocate(count) {
|
|
39
|
+
const exists = await tx.findOne(webhook_sequence_js_1.WebhookSequence, { where });
|
|
40
|
+
if (!exists) {
|
|
41
|
+
await tx.save(webhook_sequence_js_1.WebhookSequence, tx.create(webhook_sequence_js_1.WebhookSequence, { domain: { id: domainId }, peer, scope, lastSeq: 0 }));
|
|
42
|
+
}
|
|
43
|
+
await tx.increment(webhook_sequence_js_1.WebhookSequence, where, 'lastSeq', count);
|
|
44
|
+
const after = await tx.findOne(webhook_sequence_js_1.WebhookSequence, { where });
|
|
45
|
+
if (!after) {
|
|
46
|
+
throw new Error(`webhookAppendStore: the counter for ${peer}/${scope} disappeared while allocating`);
|
|
47
|
+
}
|
|
48
|
+
/* Some drivers hand an int column back as a string. Count in numbers. */
|
|
49
|
+
const lastSeq = Number(after.lastSeq);
|
|
50
|
+
if (!Number.isFinite(lastSeq)) {
|
|
51
|
+
throw new Error(`webhookAppendStore: the counter for ${peer}/${scope} is not a number: ${String(after.lastSeq)}`);
|
|
52
|
+
}
|
|
53
|
+
return lastSeq - count + 1;
|
|
54
|
+
},
|
|
55
|
+
async insert(rows) {
|
|
56
|
+
const entities = rows.map(row => {
|
|
57
|
+
const unknown = Object.keys(row.extra ?? {}).filter(key => !EXTRA_COLUMNS.has(key));
|
|
58
|
+
if (unknown.length) {
|
|
59
|
+
throw new Error(`webhookAppendStore: no column for ${unknown.join(', ')} - it would be dropped and reported as written`);
|
|
60
|
+
}
|
|
61
|
+
return tx.create(webhook_outbox_event_js_1.WebhookOutboxEvent, {
|
|
62
|
+
domain: { id: domainId },
|
|
63
|
+
peer,
|
|
64
|
+
scope,
|
|
65
|
+
seq: row.seq,
|
|
66
|
+
eventId: row.eventId,
|
|
67
|
+
eventTime: row.eventTime,
|
|
68
|
+
recordTime: row.recordTime,
|
|
69
|
+
payload: row.record,
|
|
70
|
+
status: webhook_outbox_event_js_1.WebhookOutboxStatus.Pending,
|
|
71
|
+
...(row.extra ?? {})
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
return await tx.save(webhook_outbox_event_js_1.WebhookOutboxEvent, entities);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=webhook-append-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-append-store.js","sourceRoot":"","sources":["../../../server/service/outbox/webhook-append-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager } from 'typeorm'\n\nimport { WebhookOutboxEvent, WebhookOutboxStatus } from '../webhook-outbox-event/webhook-outbox-event.js'\nimport { WebhookSequence } from '../webhook-sequence/webhook-sequence.js'\nimport type { NewOutboxRow, OpenTransaction, OutboxAppendStore } from './append.js'\nimport type { WebhookStream } from './webhook-store.js'\n\n/**\n * **The front row over this module's own tables** — the writing half of one stream `(domain, peer, scope)`\n * (ADR-0078 decision 2 ②, decision 6).\n *\n * ═════════════════════════════════════════════════════════════════════════\n * ## It takes the open transaction, not a manager\n *\n * `allocate` raises the counter and `insert` writes the rows. If the two are not one transaction, the raise\n * commits on its own and a failed insert leaves a number that names no row - the receiver stops at that hole\n * for good. `OpenTransaction` can only come from `openTransaction`, so the default manager does not compile\n * here. `test/append-store-db.test.ts` breaks an insert after the raise and reads the counter back.\n *\n * ## Raise, then read\n *\n * `increment` takes the row lock, so two writers on the same stream queue behind each other; reading after\n * raising means the run handed out belongs to this transaction. Reading first and writing `last + n` would\n * hand two writers the same numbers.\n *\n * The first append on a stream creates the counter row. Two first appends racing on a brand-new stream\n * meet at the unique index and one of the two business transactions fails whole - loud, and nothing burned.\n *\n * ## What the product keeps per row\n *\n * `lane` and `provenance` are columns (decision 3); a product passes them in `extra`. Anything else in\n * `extra` is refused: a key with no column would be accepted, dropped, and reported as written.\n * ═════════════════════════════════════════════════════════════════════════\n */\n\nconst EXTRA_COLUMNS = new Set(['lane', 'provenance'])\n\nexport function webhookAppendStore(tx: OpenTransaction<EntityManager>, stream: WebhookStream): OutboxAppendStore<object, WebhookOutboxEvent> {\n const { domainId, peer, scope } = stream\n const where = { domain: { id: domainId }, peer, scope }\n\n return {\n async allocate(count: number): Promise<number> {\n const exists = await tx.findOne(WebhookSequence, { where })\n\n if (!exists) {\n await tx.save(WebhookSequence, tx.create(WebhookSequence, { domain: { id: domainId } as any, peer, scope, lastSeq: 0 }))\n }\n\n await tx.increment(WebhookSequence, where, 'lastSeq', count)\n\n const after = await tx.findOne(WebhookSequence, { where })\n if (!after) {\n throw new Error(`webhookAppendStore: the counter for ${peer}/${scope} disappeared while allocating`)\n }\n\n /* Some drivers hand an int column back as a string. Count in numbers. */\n const lastSeq = Number(after.lastSeq)\n if (!Number.isFinite(lastSeq)) {\n throw new Error(`webhookAppendStore: the counter for ${peer}/${scope} is not a number: ${String(after.lastSeq)}`)\n }\n\n return lastSeq - count + 1\n },\n\n async insert(rows: readonly NewOutboxRow<object>[]): Promise<WebhookOutboxEvent[]> {\n const entities = rows.map(row => {\n const unknown = Object.keys(row.extra ?? {}).filter(key => !EXTRA_COLUMNS.has(key))\n if (unknown.length) {\n throw new Error(`webhookAppendStore: no column for ${unknown.join(', ')} - it would be dropped and reported as written`)\n }\n\n return tx.create(WebhookOutboxEvent, {\n domain: { id: domainId } as any,\n peer,\n scope,\n seq: row.seq,\n eventId: row.eventId,\n eventTime: row.eventTime,\n recordTime: row.recordTime,\n payload: row.record,\n status: WebhookOutboxStatus.Pending,\n ...(row.extra ?? {})\n })\n })\n\n return await tx.save(WebhookOutboxEvent, entities)\n }\n }\n}\n"]}
|