@x12i/memorix-service 3.11.1 → 3.12.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/dist/app.d.ts.map +1 -1
- package/dist/app.js +3 -0
- package/dist/app.js.map +1 -1
- package/dist/hooks/contract.d.ts +9 -0
- package/dist/hooks/contract.d.ts.map +1 -0
- package/dist/hooks/contract.js +87 -0
- package/dist/hooks/contract.js.map +1 -0
- package/dist/hooks/deliver.d.ts +19 -0
- package/dist/hooks/deliver.d.ts.map +1 -0
- package/dist/hooks/deliver.js +57 -0
- package/dist/hooks/deliver.js.map +1 -0
- package/dist/hooks/enqueue.d.ts +4 -0
- package/dist/hooks/enqueue.d.ts.map +1 -0
- package/dist/hooks/enqueue.js +19 -0
- package/dist/hooks/enqueue.js.map +1 -0
- package/dist/hooks/store.d.ts +5 -0
- package/dist/hooks/store.d.ts.map +1 -0
- package/dist/hooks/store.js +229 -0
- package/dist/hooks/store.js.map +1 -0
- package/dist/hooks/types.d.ts +93 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +25 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/hooks/validate.d.ts +19 -0
- package/dist/hooks/validate.d.ts.map +1 -0
- package/dist/hooks/validate.js +173 -0
- package/dist/hooks/validate.js.map +1 -0
- package/dist/hooks/worker.d.ts +13 -0
- package/dist/hooks/worker.d.ts.map +1 -0
- package/dist/hooks/worker.js +80 -0
- package/dist/hooks/worker.js.map +1 -0
- package/dist/openapi/openapi.json +139 -1
- package/dist/platform.d.ts +11 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +129 -0
- package/dist/platform.js.map +1 -1
- package/dist/routes/data.d.ts.map +1 -1
- package/dist/routes/data.js +15 -0
- package/dist/routes/data.js.map +1 -1
- package/dist/routes/hooks.d.ts +4 -0
- package/dist/routes/hooks.d.ts.map +1 -0
- package/dist/routes/hooks.js +104 -0
- package/dist/routes/hooks.js.map +1 -0
- package/openapi/openapi.json +139 -1
- package/package.json +2 -2
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { MemorixScope } from "../scope.js";
|
|
2
|
+
export declare const HOOK_EVENTS: readonly ["created", "updated", "removed"];
|
|
3
|
+
export type HookEventName = (typeof HOOK_EVENTS)[number];
|
|
4
|
+
export declare const DELIVERY_STATUSES: readonly ["pending", "delivered", "rejected", "failed"];
|
|
5
|
+
export type DeliveryStatus = (typeof DELIVERY_STATUSES)[number];
|
|
6
|
+
export type HookHealth = "ok" | "failing";
|
|
7
|
+
export type HookDiscriminator = {
|
|
8
|
+
path: string;
|
|
9
|
+
equals: unknown;
|
|
10
|
+
};
|
|
11
|
+
export type HookMatch = {
|
|
12
|
+
objectType: string;
|
|
13
|
+
contentType: string;
|
|
14
|
+
discriminator?: HookDiscriminator;
|
|
15
|
+
events: HookEventName[];
|
|
16
|
+
ignoreCallers?: string[];
|
|
17
|
+
};
|
|
18
|
+
export type HookSubscription = {
|
|
19
|
+
subscriptionId: string;
|
|
20
|
+
orgId: string;
|
|
21
|
+
agentIds: string[];
|
|
22
|
+
endpoint: string;
|
|
23
|
+
signingSecret: string;
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
match: HookMatch;
|
|
26
|
+
health: HookHealth;
|
|
27
|
+
createdAt: string;
|
|
28
|
+
updatedAt: string;
|
|
29
|
+
};
|
|
30
|
+
export type HookSubscriptionPublic = Omit<HookSubscription, "signingSecret">;
|
|
31
|
+
export type HookAddress = {
|
|
32
|
+
objectType: string;
|
|
33
|
+
contentType: string;
|
|
34
|
+
recordId: string;
|
|
35
|
+
revision?: number;
|
|
36
|
+
};
|
|
37
|
+
export type HookDelivery = {
|
|
38
|
+
deliveryId: string;
|
|
39
|
+
subscriptionId: string;
|
|
40
|
+
endpoint: string;
|
|
41
|
+
address: HookAddress;
|
|
42
|
+
event: HookEventName;
|
|
43
|
+
attempt: number;
|
|
44
|
+
nextAttemptAt: string | null;
|
|
45
|
+
status: DeliveryStatus;
|
|
46
|
+
occurredAt: string;
|
|
47
|
+
scope: MemorixScope;
|
|
48
|
+
change: {
|
|
49
|
+
previousRevision: number | null;
|
|
50
|
+
dataChanged: boolean;
|
|
51
|
+
};
|
|
52
|
+
seq: number;
|
|
53
|
+
createdAt: string;
|
|
54
|
+
leasedUntil: string | null;
|
|
55
|
+
};
|
|
56
|
+
export type HookDeliveryPublic = {
|
|
57
|
+
deliveryId: string;
|
|
58
|
+
subscriptionId: string;
|
|
59
|
+
address: HookAddress;
|
|
60
|
+
event: HookEventName;
|
|
61
|
+
attempt: number;
|
|
62
|
+
nextAttemptAt: string | null;
|
|
63
|
+
status: DeliveryStatus;
|
|
64
|
+
};
|
|
65
|
+
export type DeliverySettle = {
|
|
66
|
+
status: DeliveryStatus;
|
|
67
|
+
nextAttemptAt: string | null;
|
|
68
|
+
leasedUntil: string | null;
|
|
69
|
+
endpoint?: string;
|
|
70
|
+
};
|
|
71
|
+
export type HookStore = {
|
|
72
|
+
saveSubscription(row: HookSubscription): Promise<void>;
|
|
73
|
+
findSubscription(subscriptionId: string): Promise<HookSubscription | null>;
|
|
74
|
+
listSubscriptions(): Promise<HookSubscription[]>;
|
|
75
|
+
deleteSubscription(subscriptionId: string): Promise<boolean>;
|
|
76
|
+
insertDeliveries(rows: HookDelivery[]): Promise<void>;
|
|
77
|
+
listDeliveries(subscriptionId: string, opts: {
|
|
78
|
+
status?: DeliveryStatus;
|
|
79
|
+
limit: number;
|
|
80
|
+
}): Promise<HookDelivery[]>;
|
|
81
|
+
listActionable(nowIso: string): Promise<HookDelivery[]>;
|
|
82
|
+
lease(deliveryId: string, leasedUntil: string, attempt: number, nowIso: string): Promise<HookDelivery | null>;
|
|
83
|
+
settle(deliveryId: string, patch: DeliverySettle): Promise<void>;
|
|
84
|
+
countInFlight(endpoint: string, nowIso: string): Promise<number>;
|
|
85
|
+
hasOlderOpen(endpoint: string, recordId: string, seq: number): Promise<boolean>;
|
|
86
|
+
retargetPending(subscriptionId: string, endpoint: string): Promise<void>;
|
|
87
|
+
deletePending(subscriptionId: string): Promise<void>;
|
|
88
|
+
nextSeq(count: number): Promise<number>;
|
|
89
|
+
};
|
|
90
|
+
export declare function toPublicSubscription(row: HookSubscription): HookSubscriptionPublic;
|
|
91
|
+
export declare function toPublicDelivery(row: HookDelivery): HookDeliveryPublic;
|
|
92
|
+
export declare function sameAgentIds(left: string[], right: string[]): boolean;
|
|
93
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/hooks/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const HOOK_EVENTS = ["created", "updated", "removed"];
|
|
2
|
+
export const DELIVERY_STATUSES = ["pending", "delivered", "rejected", "failed"];
|
|
3
|
+
export function toPublicSubscription(row) {
|
|
4
|
+
const { signingSecret: _secret, ...publicRow } = row;
|
|
5
|
+
return publicRow;
|
|
6
|
+
}
|
|
7
|
+
export function toPublicDelivery(row) {
|
|
8
|
+
return {
|
|
9
|
+
deliveryId: row.deliveryId,
|
|
10
|
+
subscriptionId: row.subscriptionId,
|
|
11
|
+
address: row.address,
|
|
12
|
+
event: row.event,
|
|
13
|
+
attempt: row.attempt,
|
|
14
|
+
nextAttemptAt: row.nextAttemptAt,
|
|
15
|
+
status: row.status,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function sameAgentIds(left, right) {
|
|
19
|
+
if (left.length !== right.length)
|
|
20
|
+
return false;
|
|
21
|
+
const a = [...left].sort((x, y) => x.localeCompare(y));
|
|
22
|
+
const b = [...right].sort((x, y) => x.localeCompare(y));
|
|
23
|
+
return a.every((id, index) => id === b[index]);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/hooks/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAU,CAAC;AAGtE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,CAAU,CAAC;AAsGzF,MAAM,UAAU,oBAAoB,CAAC,GAAqB;IACxD,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,SAAS,EAAE,GAAG,GAAG,CAAC;IACrD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAiB;IAChD,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,MAAM,EAAE,GAAG,CAAC,MAAM;KACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAc,EAAE,KAAe;IAC1D,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC/C,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type DeliveryStatus, type HookMatch } from "./types.js";
|
|
2
|
+
export type SubscriptionBody = {
|
|
3
|
+
endpoint: string;
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
signingSecret?: string;
|
|
6
|
+
match: HookMatch;
|
|
7
|
+
};
|
|
8
|
+
export type SubscriptionPatch = {
|
|
9
|
+
endpoint?: string;
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
match?: HookMatch;
|
|
12
|
+
};
|
|
13
|
+
export declare function assertSubscriptionId(raw: unknown): string;
|
|
14
|
+
export declare function assertEndpoint(raw: unknown): string;
|
|
15
|
+
export declare function parseSubscriptionPut(body: unknown): SubscriptionBody;
|
|
16
|
+
export declare function parseSubscriptionPatch(body: unknown): SubscriptionPatch;
|
|
17
|
+
export declare function parseDeliveryStatus(raw: unknown): DeliveryStatus | undefined;
|
|
18
|
+
export declare function parseDeliveryLimit(raw: unknown): number;
|
|
19
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/hooks/validate.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkC,KAAK,cAAc,EAAsB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAWrH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB,CAAC;AAmBF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAKzD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAanD;AAqED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,CAiBpE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,iBAAiB,CAYvE;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CAM5E;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAOvD"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { CALLER_MAX_LEN, CALLER_PATTERN } from "../caller-identity.js";
|
|
2
|
+
import { ServiceError } from "../errors.js";
|
|
3
|
+
import { DELIVERY_STATUSES, HOOK_EVENTS } from "./types.js";
|
|
4
|
+
const SUBSCRIPTION_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
5
|
+
const TYPE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
6
|
+
const PATH = /^[A-Za-z0-9_]+(?:\.[A-Za-z0-9_]+)*$/;
|
|
7
|
+
const PUT_KEYS = new Set(["endpoint", "enabled", "signingSecret", "match"]);
|
|
8
|
+
const PATCH_KEYS = new Set(["enabled", "endpoint", "match"]);
|
|
9
|
+
const MATCH_KEYS = new Set(["objectType", "contentType", "discriminator", "events", "ignoreCallers"]);
|
|
10
|
+
const DISC_KEYS = new Set(["path", "equals"]);
|
|
11
|
+
function invalid(message) {
|
|
12
|
+
throw new ServiceError("HOOK_SUBSCRIPTION_INVALID", message, 400);
|
|
13
|
+
}
|
|
14
|
+
function isPlainObject(value) {
|
|
15
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
16
|
+
}
|
|
17
|
+
function rejectUnknown(value, allowed) {
|
|
18
|
+
for (const key of Object.keys(value)) {
|
|
19
|
+
if (!allowed.has(key)) {
|
|
20
|
+
const safe = /password|secret|token|api[_-]?key|credential/i.test(key) ? "not allowed" : key;
|
|
21
|
+
invalid(`unknown field ${safe}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function assertSubscriptionId(raw) {
|
|
26
|
+
if (typeof raw !== "string" || !SUBSCRIPTION_ID.test(raw)) {
|
|
27
|
+
invalid("subscriptionId must be 1-128 letters, digits, dots, underscores, or hyphens");
|
|
28
|
+
}
|
|
29
|
+
return raw;
|
|
30
|
+
}
|
|
31
|
+
export function assertEndpoint(raw) {
|
|
32
|
+
if (typeof raw !== "string" || !raw.trim())
|
|
33
|
+
invalid("endpoint is required");
|
|
34
|
+
let url;
|
|
35
|
+
try {
|
|
36
|
+
url = new URL(raw);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
invalid("endpoint must be an absolute http or https URL");
|
|
40
|
+
}
|
|
41
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
42
|
+
invalid("endpoint must be an absolute http or https URL");
|
|
43
|
+
}
|
|
44
|
+
if (!url.hostname)
|
|
45
|
+
invalid("endpoint must be an absolute http or https URL");
|
|
46
|
+
return raw;
|
|
47
|
+
}
|
|
48
|
+
function assertTypeId(raw, field) {
|
|
49
|
+
if (typeof raw !== "string" || !TYPE_ID.test(raw))
|
|
50
|
+
invalid(`${field} is required`);
|
|
51
|
+
return raw;
|
|
52
|
+
}
|
|
53
|
+
function assertEvents(raw) {
|
|
54
|
+
if (!Array.isArray(raw) || raw.length === 0)
|
|
55
|
+
invalid("match.events must list at least one event");
|
|
56
|
+
const events = [];
|
|
57
|
+
for (const item of raw) {
|
|
58
|
+
if (typeof item !== "string" || !HOOK_EVENTS.includes(item)) {
|
|
59
|
+
invalid("match.events must be a subset of created, updated, removed");
|
|
60
|
+
}
|
|
61
|
+
if (events.includes(item))
|
|
62
|
+
invalid("match.events must not repeat an event");
|
|
63
|
+
events.push(item);
|
|
64
|
+
}
|
|
65
|
+
return events;
|
|
66
|
+
}
|
|
67
|
+
function assertIgnoreCallers(raw) {
|
|
68
|
+
if (raw === undefined)
|
|
69
|
+
return undefined;
|
|
70
|
+
if (!Array.isArray(raw))
|
|
71
|
+
invalid("match.ignoreCallers must be an array of caller ids");
|
|
72
|
+
const callers = [];
|
|
73
|
+
for (const item of raw) {
|
|
74
|
+
if (typeof item !== "string" || item.length > CALLER_MAX_LEN || !CALLER_PATTERN.test(item)) {
|
|
75
|
+
invalid("match.ignoreCallers entries must be caller ids");
|
|
76
|
+
}
|
|
77
|
+
callers.push(item);
|
|
78
|
+
}
|
|
79
|
+
return callers;
|
|
80
|
+
}
|
|
81
|
+
function assertMatch(raw) {
|
|
82
|
+
if (!isPlainObject(raw))
|
|
83
|
+
invalid("match is required");
|
|
84
|
+
rejectUnknown(raw, MATCH_KEYS);
|
|
85
|
+
const objectType = assertTypeId(raw.objectType, "match.objectType");
|
|
86
|
+
const contentType = assertTypeId(raw.contentType, "match.contentType");
|
|
87
|
+
const events = assertEvents(raw.events);
|
|
88
|
+
const ignoreCallers = assertIgnoreCallers(raw.ignoreCallers);
|
|
89
|
+
let discriminator;
|
|
90
|
+
if (raw.discriminator !== undefined) {
|
|
91
|
+
if (!isPlainObject(raw.discriminator))
|
|
92
|
+
invalid("match.discriminator must be an object");
|
|
93
|
+
rejectUnknown(raw.discriminator, DISC_KEYS);
|
|
94
|
+
if (typeof raw.discriminator.path !== "string" || !PATH.test(raw.discriminator.path)) {
|
|
95
|
+
invalid("match.discriminator.path must be a dotted path");
|
|
96
|
+
}
|
|
97
|
+
if (!Object.prototype.hasOwnProperty.call(raw.discriminator, "equals")) {
|
|
98
|
+
invalid("match.discriminator.equals is required");
|
|
99
|
+
}
|
|
100
|
+
discriminator = { path: raw.discriminator.path, equals: raw.discriminator.equals };
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
objectType,
|
|
104
|
+
contentType,
|
|
105
|
+
events,
|
|
106
|
+
...(discriminator ? { discriminator } : {}),
|
|
107
|
+
...(ignoreCallers ? { ignoreCallers } : {}),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function assertSecret(raw) {
|
|
111
|
+
if (raw === undefined)
|
|
112
|
+
return undefined;
|
|
113
|
+
if (typeof raw !== "string" || raw.length === 0 || raw.length > 512) {
|
|
114
|
+
invalid("signing key must be a non-empty string");
|
|
115
|
+
}
|
|
116
|
+
return raw;
|
|
117
|
+
}
|
|
118
|
+
export function parseSubscriptionPut(body) {
|
|
119
|
+
if (!isPlainObject(body))
|
|
120
|
+
invalid("body must be an object");
|
|
121
|
+
rejectUnknown(body, PUT_KEYS);
|
|
122
|
+
const endpoint = assertEndpoint(body.endpoint);
|
|
123
|
+
const match = assertMatch(body.match);
|
|
124
|
+
const signingSecret = assertSecret(body.signingSecret);
|
|
125
|
+
let enabled = true;
|
|
126
|
+
if (body.enabled !== undefined) {
|
|
127
|
+
if (typeof body.enabled !== "boolean")
|
|
128
|
+
invalid("enabled must be a boolean");
|
|
129
|
+
enabled = body.enabled;
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
endpoint,
|
|
133
|
+
enabled,
|
|
134
|
+
match,
|
|
135
|
+
...(signingSecret !== undefined ? { signingSecret } : {}),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
export function parseSubscriptionPatch(body) {
|
|
139
|
+
if (!isPlainObject(body))
|
|
140
|
+
invalid("body must be an object");
|
|
141
|
+
rejectUnknown(body, PATCH_KEYS);
|
|
142
|
+
if (Object.keys(body).length === 0)
|
|
143
|
+
invalid("patch body is empty");
|
|
144
|
+
const patch = {};
|
|
145
|
+
if (body.endpoint !== undefined)
|
|
146
|
+
patch.endpoint = assertEndpoint(body.endpoint);
|
|
147
|
+
if (body.enabled !== undefined) {
|
|
148
|
+
if (typeof body.enabled !== "boolean")
|
|
149
|
+
invalid("enabled must be a boolean");
|
|
150
|
+
patch.enabled = body.enabled;
|
|
151
|
+
}
|
|
152
|
+
if (body.match !== undefined)
|
|
153
|
+
patch.match = assertMatch(body.match);
|
|
154
|
+
return patch;
|
|
155
|
+
}
|
|
156
|
+
export function parseDeliveryStatus(raw) {
|
|
157
|
+
if (raw === undefined || raw === "")
|
|
158
|
+
return undefined;
|
|
159
|
+
if (typeof raw !== "string" || !DELIVERY_STATUSES.includes(raw)) {
|
|
160
|
+
invalid("status must be pending, delivered, rejected, or failed");
|
|
161
|
+
}
|
|
162
|
+
return raw;
|
|
163
|
+
}
|
|
164
|
+
export function parseDeliveryLimit(raw) {
|
|
165
|
+
if (raw === undefined || raw === "")
|
|
166
|
+
return 50;
|
|
167
|
+
const limit = typeof raw === "number" ? raw : Number(raw);
|
|
168
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 200) {
|
|
169
|
+
invalid("limit must be an integer from 1 to 200");
|
|
170
|
+
}
|
|
171
|
+
return limit;
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/hooks/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { classifyDeliveryResponse } from "./deliver.js";
|
|
2
|
+
import type { HookStore } from "./types.js";
|
|
3
|
+
export type TickHooksOptions = {
|
|
4
|
+
now?: Date;
|
|
5
|
+
fetchImpl?: typeof fetch;
|
|
6
|
+
timeoutMs?: number;
|
|
7
|
+
backoffMs?: (attempt: number) => number;
|
|
8
|
+
inflightCap?: number;
|
|
9
|
+
maxAttempts?: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function tickHookStore(store: HookStore, opts?: TickHooksOptions): Promise<void>;
|
|
12
|
+
export { classifyDeliveryResponse };
|
|
13
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/hooks/worker.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EAOzB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAsB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2EhG;AAED,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { classifyDeliveryResponse, hookBackoffMs, HOOK_INFLIGHT_CAP, HOOK_LEASE_MS, HOOK_MAX_ATTEMPTS, HOOK_TIMEOUT_MS, postDelivery, } from "./deliver.js";
|
|
2
|
+
export async function tickHookStore(store, opts = {}) {
|
|
3
|
+
const now = opts.now ?? new Date();
|
|
4
|
+
const nowIso = now.toISOString();
|
|
5
|
+
const cap = opts.inflightCap ?? HOOK_INFLIGHT_CAP;
|
|
6
|
+
const maxAttempts = opts.maxAttempts ?? HOOK_MAX_ATTEMPTS;
|
|
7
|
+
const backoff = opts.backoffMs ?? hookBackoffMs;
|
|
8
|
+
const due = await store.listActionable(nowIso);
|
|
9
|
+
const inflight = new Map();
|
|
10
|
+
const tasks = [];
|
|
11
|
+
for (const candidate of due) {
|
|
12
|
+
const subscription = await store.findSubscription(candidate.subscriptionId);
|
|
13
|
+
if (!subscription) {
|
|
14
|
+
await store.settle(candidate.deliveryId, { status: "failed", nextAttemptAt: null, leasedUntil: null });
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (!subscription.enabled)
|
|
18
|
+
continue;
|
|
19
|
+
const endpoint = subscription.endpoint;
|
|
20
|
+
if (await store.hasOlderOpen(endpoint, candidate.address.recordId, candidate.seq))
|
|
21
|
+
continue;
|
|
22
|
+
if (!inflight.has(endpoint))
|
|
23
|
+
inflight.set(endpoint, await store.countInFlight(endpoint, nowIso));
|
|
24
|
+
const used = inflight.get(endpoint) ?? 0;
|
|
25
|
+
if (used >= cap)
|
|
26
|
+
continue;
|
|
27
|
+
const leased = await store.lease(candidate.deliveryId, new Date(now.getTime() + HOOK_LEASE_MS).toISOString(), candidate.attempt + 1, nowIso);
|
|
28
|
+
if (!leased)
|
|
29
|
+
continue;
|
|
30
|
+
inflight.set(endpoint, used + 1);
|
|
31
|
+
if (leased.endpoint !== endpoint) {
|
|
32
|
+
await store.settle(leased.deliveryId, {
|
|
33
|
+
status: "pending",
|
|
34
|
+
nextAttemptAt: leased.nextAttemptAt,
|
|
35
|
+
leasedUntil: leased.leasedUntil,
|
|
36
|
+
endpoint,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const sending = { ...leased, endpoint };
|
|
40
|
+
tasks.push((async () => {
|
|
41
|
+
const outcome = await postDelivery({
|
|
42
|
+
delivery: sending,
|
|
43
|
+
endpoint,
|
|
44
|
+
secret: subscription.signingSecret,
|
|
45
|
+
fetchImpl: opts.fetchImpl,
|
|
46
|
+
timeoutMs: opts.timeoutMs ?? HOOK_TIMEOUT_MS,
|
|
47
|
+
now,
|
|
48
|
+
});
|
|
49
|
+
if (outcome === "delivered") {
|
|
50
|
+
await store.settle(sending.deliveryId, { status: "delivered", nextAttemptAt: null, leasedUntil: null });
|
|
51
|
+
const current = await store.findSubscription(subscription.subscriptionId);
|
|
52
|
+
if (current?.health === "failing") {
|
|
53
|
+
await store.saveSubscription({ ...current, health: "ok", updatedAt: new Date().toISOString() });
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (outcome === "rejected") {
|
|
58
|
+
await store.settle(sending.deliveryId, { status: "rejected", nextAttemptAt: null, leasedUntil: null });
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (outcome === "failing") {
|
|
62
|
+
await store.settle(sending.deliveryId, { status: "failed", nextAttemptAt: null, leasedUntil: null });
|
|
63
|
+
const current = await store.findSubscription(subscription.subscriptionId);
|
|
64
|
+
if (current) {
|
|
65
|
+
await store.saveSubscription({ ...current, health: "failing", updatedAt: new Date().toISOString() });
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (sending.attempt >= maxAttempts) {
|
|
70
|
+
await store.settle(sending.deliveryId, { status: "failed", nextAttemptAt: null, leasedUntil: null });
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const nextAttemptAt = new Date(now.getTime() + backoff(sending.attempt)).toISOString();
|
|
74
|
+
await store.settle(sending.deliveryId, { status: "pending", nextAttemptAt, leasedUntil: null });
|
|
75
|
+
})());
|
|
76
|
+
}
|
|
77
|
+
await Promise.all(tasks);
|
|
78
|
+
}
|
|
79
|
+
export { classifyDeliveryResponse };
|
|
80
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/hooks/worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.0.3",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Memorix Service API",
|
|
5
|
-
"version": "3.
|
|
5
|
+
"version": "3.12.0",
|
|
6
6
|
"description": "One versioned product API over accepted Memorix packages. Scope: orgId + agentIds[]. Headers x-memorix-org-id and x-memorix-agent-ids (comma-separated). MX-CALLER-01: every /api request requires x-memorix-caller (calling app id). Intelligence never auto-installs. Relationships /links is forbidden. IntegrationsRegistry (Stage −1) and RestrictedStore (FG-A3 dual-mode blob)."
|
|
7
7
|
},
|
|
8
8
|
"servers": [
|
|
@@ -46,6 +46,10 @@
|
|
|
46
46
|
"name": "Jobs",
|
|
47
47
|
"description": "Jobs Manager repeated-work API. P3 reads and P4 writes live."
|
|
48
48
|
},
|
|
49
|
+
{
|
|
50
|
+
"name": "Hooks",
|
|
51
|
+
"description": "Content hooks. A subscription is notified after one address is created, updated, or removed. The callback does not run a skill."
|
|
52
|
+
},
|
|
49
53
|
{
|
|
50
54
|
"name": "Connectors",
|
|
51
55
|
"description": "Unified connector catalog (registry + builtins + MGC remote hosts)"
|
|
@@ -2880,6 +2884,10 @@
|
|
|
2880
2884
|
"$ref": "#/components/schemas/PatchOp"
|
|
2881
2885
|
}
|
|
2882
2886
|
},
|
|
2887
|
+
"suppressHooks": {
|
|
2888
|
+
"type": "boolean",
|
|
2889
|
+
"description": "When true, this write does not notify content-hook subscriptions. Not stored on the record. For bulk load and migration."
|
|
2890
|
+
},
|
|
2883
2891
|
"address": {
|
|
2884
2892
|
"$ref": "#/components/schemas/ContentAddress"
|
|
2885
2893
|
},
|
|
@@ -14923,6 +14931,106 @@
|
|
|
14923
14931
|
}
|
|
14924
14932
|
}
|
|
14925
14933
|
}
|
|
14934
|
+
},
|
|
14935
|
+
"/api/hooks/v1/subscriptions": {
|
|
14936
|
+
"get": {
|
|
14937
|
+
"operationId": "hooksListSubscriptions",
|
|
14938
|
+
"tags": ["Hooks"],
|
|
14939
|
+
"summary": "List content-hook subscriptions for this org and agent set",
|
|
14940
|
+
"parameters": [
|
|
14941
|
+
{ "$ref": "#/components/parameters/XMemorixCaller" },
|
|
14942
|
+
{ "$ref": "#/components/parameters/XMemorixOrgId" },
|
|
14943
|
+
{ "$ref": "#/components/parameters/XMemorixAgentIds" }
|
|
14944
|
+
],
|
|
14945
|
+
"responses": {
|
|
14946
|
+
"200": { "description": "Subscriptions. signingSecret is omitted." }
|
|
14947
|
+
}
|
|
14948
|
+
}
|
|
14949
|
+
},
|
|
14950
|
+
"/api/hooks/v1/subscriptions/{subscriptionId}": {
|
|
14951
|
+
"put": {
|
|
14952
|
+
"operationId": "hooksPutSubscription",
|
|
14953
|
+
"tags": ["Hooks"],
|
|
14954
|
+
"summary": "Create or replace a content-hook subscription",
|
|
14955
|
+
"parameters": [
|
|
14956
|
+
{ "$ref": "#/components/parameters/XMemorixCaller" },
|
|
14957
|
+
{ "$ref": "#/components/parameters/XMemorixOrgId" },
|
|
14958
|
+
{ "$ref": "#/components/parameters/XMemorixAgentIds" },
|
|
14959
|
+
{ "name": "subscriptionId", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
14960
|
+
],
|
|
14961
|
+
"requestBody": {
|
|
14962
|
+
"required": true,
|
|
14963
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/HookSubscriptionWrite" } } }
|
|
14964
|
+
},
|
|
14965
|
+
"responses": {
|
|
14966
|
+
"200": { "description": "Stored subscription. signingSecret is omitted." },
|
|
14967
|
+
"400": { "description": "HOOK_SUBSCRIPTION_INVALID" },
|
|
14968
|
+
"409": { "description": "subscriptionId belongs to a different agent scope" }
|
|
14969
|
+
}
|
|
14970
|
+
},
|
|
14971
|
+
"get": {
|
|
14972
|
+
"operationId": "hooksGetSubscription",
|
|
14973
|
+
"tags": ["Hooks"],
|
|
14974
|
+
"summary": "Read one content-hook subscription",
|
|
14975
|
+
"parameters": [
|
|
14976
|
+
{ "$ref": "#/components/parameters/XMemorixCaller" },
|
|
14977
|
+
{ "$ref": "#/components/parameters/XMemorixOrgId" },
|
|
14978
|
+
{ "$ref": "#/components/parameters/XMemorixAgentIds" },
|
|
14979
|
+
{ "name": "subscriptionId", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
14980
|
+
],
|
|
14981
|
+
"responses": {
|
|
14982
|
+
"200": { "description": "Subscription. signingSecret is omitted." },
|
|
14983
|
+
"404": { "description": "HOOK_SUBSCRIPTION_NOT_FOUND" }
|
|
14984
|
+
}
|
|
14985
|
+
},
|
|
14986
|
+
"patch": {
|
|
14987
|
+
"operationId": "hooksPatchSubscription",
|
|
14988
|
+
"tags": ["Hooks"],
|
|
14989
|
+
"summary": "Update enabled, endpoint, or match",
|
|
14990
|
+
"parameters": [
|
|
14991
|
+
{ "$ref": "#/components/parameters/XMemorixCaller" },
|
|
14992
|
+
{ "$ref": "#/components/parameters/XMemorixOrgId" },
|
|
14993
|
+
{ "$ref": "#/components/parameters/XMemorixAgentIds" },
|
|
14994
|
+
{ "name": "subscriptionId", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
14995
|
+
],
|
|
14996
|
+
"responses": {
|
|
14997
|
+
"200": { "description": "Updated subscription. signingSecret is omitted." },
|
|
14998
|
+
"400": { "description": "HOOK_SUBSCRIPTION_INVALID" },
|
|
14999
|
+
"404": { "description": "HOOK_SUBSCRIPTION_NOT_FOUND" }
|
|
15000
|
+
}
|
|
15001
|
+
},
|
|
15002
|
+
"delete": {
|
|
15003
|
+
"operationId": "hooksDeleteSubscription",
|
|
15004
|
+
"tags": ["Hooks"],
|
|
15005
|
+
"summary": "Remove a subscription and stop pending delivery",
|
|
15006
|
+
"parameters": [
|
|
15007
|
+
{ "$ref": "#/components/parameters/XMemorixCaller" },
|
|
15008
|
+
{ "$ref": "#/components/parameters/XMemorixOrgId" },
|
|
15009
|
+
{ "$ref": "#/components/parameters/XMemorixAgentIds" },
|
|
15010
|
+
{ "name": "subscriptionId", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
15011
|
+
],
|
|
15012
|
+
"responses": {
|
|
15013
|
+
"200": { "description": "Removed" },
|
|
15014
|
+
"404": { "description": "HOOK_SUBSCRIPTION_NOT_FOUND" }
|
|
15015
|
+
}
|
|
15016
|
+
}
|
|
15017
|
+
},
|
|
15018
|
+
"/api/hooks/v1/subscriptions/{subscriptionId}/deliveries": {
|
|
15019
|
+
"get": {
|
|
15020
|
+
"operationId": "hooksListDeliveries",
|
|
15021
|
+
"tags": ["Hooks"],
|
|
15022
|
+
"summary": "Recent delivery status, newest first",
|
|
15023
|
+
"parameters": [
|
|
15024
|
+
{ "$ref": "#/components/parameters/XMemorixCaller" },
|
|
15025
|
+
{ "$ref": "#/components/parameters/XMemorixOrgId" },
|
|
15026
|
+
{ "$ref": "#/components/parameters/XMemorixAgentIds" },
|
|
15027
|
+
{ "name": "subscriptionId", "in": "path", "required": true, "schema": { "type": "string" } },
|
|
15028
|
+
{ "name": "status", "in": "query", "schema": { "type": "string", "enum": ["pending", "delivered", "rejected", "failed"] } }
|
|
15029
|
+
],
|
|
15030
|
+
"responses": {
|
|
15031
|
+
"200": { "description": "Delivery rows. Not stored on the subject record." }
|
|
15032
|
+
}
|
|
15033
|
+
}
|
|
14926
15034
|
}
|
|
14927
15035
|
},
|
|
14928
15036
|
"components": {
|
|
@@ -14963,6 +15071,36 @@
|
|
|
14963
15071
|
}
|
|
14964
15072
|
},
|
|
14965
15073
|
"schemas": {
|
|
15074
|
+
"HookSubscriptionWrite": {
|
|
15075
|
+
"type": "object",
|
|
15076
|
+
"required": ["endpoint", "match"],
|
|
15077
|
+
"additionalProperties": false,
|
|
15078
|
+
"properties": {
|
|
15079
|
+
"endpoint": { "type": "string", "format": "uri" },
|
|
15080
|
+
"enabled": { "type": "boolean" },
|
|
15081
|
+
"signingSecret": { "type": "string", "description": "Required on create. Write-only. A later PUT that omits it keeps the stored secret." },
|
|
15082
|
+
"match": {
|
|
15083
|
+
"type": "object",
|
|
15084
|
+
"required": ["objectType", "contentType", "events"],
|
|
15085
|
+
"additionalProperties": false,
|
|
15086
|
+
"properties": {
|
|
15087
|
+
"objectType": { "type": "string" },
|
|
15088
|
+
"contentType": { "type": "string" },
|
|
15089
|
+
"discriminator": {
|
|
15090
|
+
"type": "object",
|
|
15091
|
+
"required": ["path", "equals"],
|
|
15092
|
+
"additionalProperties": false,
|
|
15093
|
+
"properties": {
|
|
15094
|
+
"path": { "type": "string" },
|
|
15095
|
+
"equals": {}
|
|
15096
|
+
}
|
|
15097
|
+
},
|
|
15098
|
+
"events": { "type": "array", "minItems": 1, "items": { "type": "string", "enum": ["created", "updated", "removed"] } },
|
|
15099
|
+
"ignoreCallers": { "type": "array", "items": { "type": "string" } }
|
|
15100
|
+
}
|
|
15101
|
+
}
|
|
15102
|
+
}
|
|
15103
|
+
},
|
|
14966
15104
|
"MemorixScope": {
|
|
14967
15105
|
"type": "object",
|
|
14968
15106
|
"required": [
|
package/dist/platform.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { ServiceError } from "./errors.js";
|
|
|
15
15
|
import { type DeliveryArtifactStore, type RawRecordStore, type TargetItemReceiptStore } from "./mgc-landing-stores.js";
|
|
16
16
|
import { type ServiceCatalog } from "./catalog-bridge.js";
|
|
17
17
|
import { type MemorixScope } from "./scope.js";
|
|
18
|
+
import type { HookStore } from "./hooks/types.js";
|
|
18
19
|
import { type IsolationSession } from "./isolation.js";
|
|
19
20
|
import { type MagitPackService } from "./magit/magit-pack-service.js";
|
|
20
21
|
import { type GenericConnectorsConfig } from "./generic-connectors.js";
|
|
@@ -182,6 +183,16 @@ export type MemorixPlatform = {
|
|
|
182
183
|
ownerId?: string;
|
|
183
184
|
invokePipeline?: Parameters<typeof tickContinuousAcquisition>[0]["invokePipeline"];
|
|
184
185
|
}): () => void;
|
|
186
|
+
/** Content-hook subscriptions and deliveries for one org. */
|
|
187
|
+
hooksFor(orgId: string): HookStore;
|
|
188
|
+
/** Deliver pending content hooks. Works with memory stores when Mongo is absent. */
|
|
189
|
+
startContentHookTicker(opts?: {
|
|
190
|
+
intervalMs?: number;
|
|
191
|
+
}): () => void;
|
|
192
|
+
/** One pass over known orgs. */
|
|
193
|
+
tickContentHooks(): Promise<void>;
|
|
194
|
+
/** Resolves when a kick started by a write has finished its HTTP attempts. */
|
|
195
|
+
whenContentHooksIdle(): Promise<void>;
|
|
185
196
|
/** One-shot tick for tests / Jobs evaluate-now style hosts. */
|
|
186
197
|
tickContinuousAcquisitionForOrg(orgId: string, opts?: {
|
|
187
198
|
ownerId?: string;
|