@x12i/memorix-service 3.11.1 → 3.12.1

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.
Files changed (60) hide show
  1. package/dist/app.d.ts.map +1 -1
  2. package/dist/app.js +6 -1
  3. package/dist/app.js.map +1 -1
  4. package/dist/hooks/contract.d.ts +9 -0
  5. package/dist/hooks/contract.d.ts.map +1 -0
  6. package/dist/hooks/contract.js +87 -0
  7. package/dist/hooks/contract.js.map +1 -0
  8. package/dist/hooks/deliver.d.ts +19 -0
  9. package/dist/hooks/deliver.d.ts.map +1 -0
  10. package/dist/hooks/deliver.js +57 -0
  11. package/dist/hooks/deliver.js.map +1 -0
  12. package/dist/hooks/enqueue.d.ts +4 -0
  13. package/dist/hooks/enqueue.d.ts.map +1 -0
  14. package/dist/hooks/enqueue.js +19 -0
  15. package/dist/hooks/enqueue.js.map +1 -0
  16. package/dist/hooks/store.d.ts +5 -0
  17. package/dist/hooks/store.d.ts.map +1 -0
  18. package/dist/hooks/store.js +285 -0
  19. package/dist/hooks/store.js.map +1 -0
  20. package/dist/hooks/types.d.ts +110 -0
  21. package/dist/hooks/types.d.ts.map +1 -0
  22. package/dist/hooks/types.js +37 -0
  23. package/dist/hooks/types.js.map +1 -0
  24. package/dist/hooks/validate.d.ts +19 -0
  25. package/dist/hooks/validate.d.ts.map +1 -0
  26. package/dist/hooks/validate.js +173 -0
  27. package/dist/hooks/validate.js.map +1 -0
  28. package/dist/hooks/worker.d.ts +12 -0
  29. package/dist/hooks/worker.d.ts.map +1 -0
  30. package/dist/hooks/worker.js +73 -0
  31. package/dist/hooks/worker.js.map +1 -0
  32. package/dist/hooks-live-routes.d.ts +4 -0
  33. package/dist/hooks-live-routes.d.ts.map +1 -0
  34. package/dist/hooks-live-routes.js +13 -0
  35. package/dist/hooks-live-routes.js.map +1 -0
  36. package/dist/hooks-live-ui.d.ts +3 -0
  37. package/dist/hooks-live-ui.d.ts.map +1 -0
  38. package/dist/hooks-live-ui.js +228 -0
  39. package/dist/hooks-live-ui.js.map +1 -0
  40. package/dist/hooks-live.d.ts +38 -0
  41. package/dist/hooks-live.d.ts.map +1 -0
  42. package/dist/hooks-live.js +51 -0
  43. package/dist/hooks-live.js.map +1 -0
  44. package/dist/live-ops-nav.d.ts.map +1 -1
  45. package/dist/live-ops-nav.js +4 -0
  46. package/dist/live-ops-nav.js.map +1 -1
  47. package/dist/openapi/openapi.json +177 -1
  48. package/dist/platform.d.ts +13 -0
  49. package/dist/platform.d.ts.map +1 -1
  50. package/dist/platform.js +133 -0
  51. package/dist/platform.js.map +1 -1
  52. package/dist/routes/data.d.ts.map +1 -1
  53. package/dist/routes/data.js +15 -0
  54. package/dist/routes/data.js.map +1 -1
  55. package/dist/routes/hooks.d.ts +4 -0
  56. package/dist/routes/hooks.d.ts.map +1 -0
  57. package/dist/routes/hooks.js +140 -0
  58. package/dist/routes/hooks.js.map +1 -0
  59. package/openapi/openapi.json +177 -1
  60. package/package.json +2 -2
@@ -0,0 +1,140 @@
1
+ import { resolveScope } from "../request-scope.js";
2
+ import { ServiceError } from "../errors.js";
3
+ import { sameAgentIds, toInboxDelivery, toPublicDelivery, toPublicSubscription, } from "../hooks/types.js";
4
+ import { assertSubscriptionId, parseDeliveryLimit, parseDeliveryStatus, parseSubscriptionPatch, parseSubscriptionPut, } from "../hooks/validate.js";
5
+ function inScope(row, agentIds) {
6
+ return sameAgentIds(row.agentIds, agentIds);
7
+ }
8
+ export async function registerHookRoutes(app, platform) {
9
+ app.put("/api/hooks/v1/subscriptions/:subscriptionId", async (req) => {
10
+ const scope = resolveScope(req);
11
+ const subscriptionId = assertSubscriptionId(req.params.subscriptionId);
12
+ const body = parseSubscriptionPut(req.body);
13
+ const store = platform.hooksFor(scope.orgId);
14
+ const existing = await store.findSubscription(subscriptionId);
15
+ if (existing && !inScope(existing, scope.agentIds)) {
16
+ throw new ServiceError("HOOK_SUBSCRIPTION_INVALID", "subscriptionId is registered to a different agent scope", 409);
17
+ }
18
+ if (!existing && !body.signingSecret) {
19
+ throw new ServiceError("HOOK_SUBSCRIPTION_INVALID", "signing key is required on create", 400);
20
+ }
21
+ const now = new Date().toISOString();
22
+ const endpointChanged = Boolean(existing && existing.endpoint !== body.endpoint);
23
+ const row = {
24
+ subscriptionId,
25
+ orgId: scope.orgId,
26
+ agentIds: [...scope.agentIds],
27
+ endpoint: body.endpoint,
28
+ signingSecret: body.signingSecret ?? existing.signingSecret,
29
+ enabled: body.enabled,
30
+ match: body.match,
31
+ health: endpointChanged ? "ok" : (existing?.health ?? "ok"),
32
+ createdAt: existing?.createdAt ?? now,
33
+ updatedAt: now,
34
+ };
35
+ await store.saveSubscription(row);
36
+ if (endpointChanged)
37
+ await store.retargetPending(subscriptionId, body.endpoint);
38
+ return toPublicSubscription(row);
39
+ });
40
+ app.get("/api/hooks/v1/subscriptions", async (req) => {
41
+ const scope = resolveScope(req);
42
+ const store = platform.hooksFor(scope.orgId);
43
+ const rows = await store.listSubscriptions();
44
+ return { subscriptions: rows.filter((row) => inScope(row, scope.agentIds)).map(toPublicSubscription) };
45
+ });
46
+ app.get("/api/hooks/v1/subscriptions/:subscriptionId", async (req) => {
47
+ const scope = resolveScope(req);
48
+ const subscriptionId = assertSubscriptionId(req.params.subscriptionId);
49
+ const row = await platform.hooksFor(scope.orgId).findSubscription(subscriptionId);
50
+ if (!row || !inScope(row, scope.agentIds)) {
51
+ throw new ServiceError("HOOK_SUBSCRIPTION_NOT_FOUND", "subscription not found", 404);
52
+ }
53
+ return toPublicSubscription(row);
54
+ });
55
+ app.patch("/api/hooks/v1/subscriptions/:subscriptionId", async (req) => {
56
+ const scope = resolveScope(req);
57
+ const subscriptionId = assertSubscriptionId(req.params.subscriptionId);
58
+ const patch = parseSubscriptionPatch(req.body);
59
+ const store = platform.hooksFor(scope.orgId);
60
+ const existing = await store.findSubscription(subscriptionId);
61
+ if (!existing || !inScope(existing, scope.agentIds)) {
62
+ throw new ServiceError("HOOK_SUBSCRIPTION_NOT_FOUND", "subscription not found", 404);
63
+ }
64
+ const endpointChanged = patch.endpoint !== undefined && patch.endpoint !== existing.endpoint;
65
+ const row = {
66
+ ...existing,
67
+ ...(patch.endpoint !== undefined ? { endpoint: patch.endpoint } : {}),
68
+ ...(patch.enabled !== undefined ? { enabled: patch.enabled } : {}),
69
+ ...(patch.match !== undefined ? { match: patch.match } : {}),
70
+ health: endpointChanged ? "ok" : existing.health,
71
+ updatedAt: new Date().toISOString(),
72
+ };
73
+ await store.saveSubscription(row);
74
+ if (endpointChanged && patch.endpoint)
75
+ await store.retargetPending(subscriptionId, patch.endpoint);
76
+ return toPublicSubscription(row);
77
+ });
78
+ app.delete("/api/hooks/v1/subscriptions/:subscriptionId", async (req) => {
79
+ const scope = resolveScope(req);
80
+ const subscriptionId = assertSubscriptionId(req.params.subscriptionId);
81
+ const store = platform.hooksFor(scope.orgId);
82
+ const existing = await store.findSubscription(subscriptionId);
83
+ if (!existing || !inScope(existing, scope.agentIds)) {
84
+ throw new ServiceError("HOOK_SUBSCRIPTION_NOT_FOUND", "subscription not found", 404);
85
+ }
86
+ await store.deletePending(subscriptionId);
87
+ await store.deleteSubscription(subscriptionId);
88
+ return { removed: true };
89
+ });
90
+ app.get("/api/hooks/v1/subscriptions/:subscriptionId/deliveries", async (req) => {
91
+ const scope = resolveScope(req);
92
+ const subscriptionId = assertSubscriptionId(req.params.subscriptionId);
93
+ const store = platform.hooksFor(scope.orgId);
94
+ const existing = await store.findSubscription(subscriptionId);
95
+ if (!existing || !inScope(existing, scope.agentIds)) {
96
+ throw new ServiceError("HOOK_SUBSCRIPTION_NOT_FOUND", "subscription not found", 404);
97
+ }
98
+ const status = parseDeliveryStatus(req.query.status);
99
+ const limit = parseDeliveryLimit(req.query.limit);
100
+ const rows = await store.listDeliveries(subscriptionId, { ...(status ? { status } : {}), limit });
101
+ return { deliveries: rows.map(toPublicDelivery) };
102
+ });
103
+ app.get("/api/hooks/v1/subscriptions/:subscriptionId/inbox", async (req) => {
104
+ const scope = resolveScope(req);
105
+ const subscriptionId = assertSubscriptionId(req.params.subscriptionId);
106
+ const store = platform.hooksFor(scope.orgId);
107
+ const existing = await store.findSubscription(subscriptionId);
108
+ if (!existing || !inScope(existing, scope.agentIds)) {
109
+ throw new ServiceError("HOOK_SUBSCRIPTION_NOT_FOUND", "subscription not found", 404);
110
+ }
111
+ const limit = parseDeliveryLimit(req.query.limit);
112
+ const rows = await store.listInbox(subscriptionId, limit);
113
+ return { deliveries: rows.map(toInboxDelivery) };
114
+ });
115
+ app.post("/api/hooks/v1/subscriptions/:subscriptionId/deliveries/:deliveryId/complete", async (req) => {
116
+ const scope = resolveScope(req);
117
+ const subscriptionId = assertSubscriptionId(req.params.subscriptionId);
118
+ const deliveryId = req.params.deliveryId?.trim() ?? "";
119
+ if (!deliveryId || deliveryId.length > 80) {
120
+ throw new ServiceError("HOOK_DELIVERY_NOT_FOUND", "delivery not found", 404);
121
+ }
122
+ const store = platform.hooksFor(scope.orgId);
123
+ const existing = await store.findSubscription(subscriptionId);
124
+ if (!existing || !inScope(existing, scope.agentIds)) {
125
+ throw new ServiceError("HOOK_SUBSCRIPTION_NOT_FOUND", "subscription not found", 404);
126
+ }
127
+ const delivery = await store.findDelivery(deliveryId);
128
+ if (!delivery || delivery.subscriptionId !== subscriptionId) {
129
+ throw new ServiceError("HOOK_DELIVERY_NOT_FOUND", "delivery not found", 404);
130
+ }
131
+ if (delivery.status === "delivered")
132
+ return { deliveryId, cleared: true };
133
+ if (delivery.status !== "pending") {
134
+ throw new ServiceError("HOOK_DELIVERY_CLOSED", "delivery is already closed", 409);
135
+ }
136
+ await store.settle(deliveryId, { status: "delivered", nextAttemptAt: null, leasedUntil: null });
137
+ return { deliveryId, cleared: true };
138
+ });
139
+ }
140
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/routes/hooks.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.11.1",
5
+ "version": "3.12.1",
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,144 @@
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
+ }
15034
+ },
15035
+ "/api/hooks/v1/subscriptions/{subscriptionId}/inbox": {
15036
+ "get": {
15037
+ "operationId": "hooksInbox",
15038
+ "tags": ["Hooks"],
15039
+ "summary": "Waiting notices, oldest first",
15040
+ "description": "Pending deliveries the subscriber has not accepted. A POST that returns HTTP 200 without { accepted: true }, or times out, or returns 5xx, stays here. Clear one with hooksCompleteDelivery.",
15041
+ "parameters": [
15042
+ { "$ref": "#/components/parameters/XMemorixCaller" },
15043
+ { "$ref": "#/components/parameters/XMemorixOrgId" },
15044
+ { "$ref": "#/components/parameters/XMemorixAgentIds" },
15045
+ { "name": "subscriptionId", "in": "path", "required": true, "schema": { "type": "string" } },
15046
+ { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } }
15047
+ ],
15048
+ "responses": {
15049
+ "200": { "description": "Open deliveries, including address, event, and change." },
15050
+ "404": { "description": "HOOK_SUBSCRIPTION_NOT_FOUND" }
15051
+ }
15052
+ }
15053
+ },
15054
+ "/api/hooks/v1/subscriptions/{subscriptionId}/deliveries/{deliveryId}/complete": {
15055
+ "post": {
15056
+ "operationId": "hooksCompleteDelivery",
15057
+ "tags": ["Hooks"],
15058
+ "summary": "Clear one waiting notice",
15059
+ "parameters": [
15060
+ { "$ref": "#/components/parameters/XMemorixCaller" },
15061
+ { "$ref": "#/components/parameters/XMemorixOrgId" },
15062
+ { "$ref": "#/components/parameters/XMemorixAgentIds" },
15063
+ { "name": "subscriptionId", "in": "path", "required": true, "schema": { "type": "string" } },
15064
+ { "name": "deliveryId", "in": "path", "required": true, "schema": { "type": "string" } }
15065
+ ],
15066
+ "responses": {
15067
+ "200": { "description": "{ deliveryId, cleared: true }. Completing an already delivered row is the same." },
15068
+ "404": { "description": "HOOK_SUBSCRIPTION_NOT_FOUND or HOOK_DELIVERY_NOT_FOUND" },
15069
+ "409": { "description": "HOOK_DELIVERY_CLOSED" }
15070
+ }
15071
+ }
14926
15072
  }
14927
15073
  },
14928
15074
  "components": {
@@ -14963,6 +15109,36 @@
14963
15109
  }
14964
15110
  },
14965
15111
  "schemas": {
15112
+ "HookSubscriptionWrite": {
15113
+ "type": "object",
15114
+ "required": ["endpoint", "match"],
15115
+ "additionalProperties": false,
15116
+ "properties": {
15117
+ "endpoint": { "type": "string", "format": "uri" },
15118
+ "enabled": { "type": "boolean" },
15119
+ "signingSecret": { "type": "string", "description": "Required on create. Write-only. A later PUT that omits it keeps the stored secret." },
15120
+ "match": {
15121
+ "type": "object",
15122
+ "required": ["objectType", "contentType", "events"],
15123
+ "additionalProperties": false,
15124
+ "properties": {
15125
+ "objectType": { "type": "string" },
15126
+ "contentType": { "type": "string" },
15127
+ "discriminator": {
15128
+ "type": "object",
15129
+ "required": ["path", "equals"],
15130
+ "additionalProperties": false,
15131
+ "properties": {
15132
+ "path": { "type": "string" },
15133
+ "equals": {}
15134
+ }
15135
+ },
15136
+ "events": { "type": "array", "minItems": 1, "items": { "type": "string", "enum": ["created", "updated", "removed"] } },
15137
+ "ignoreCallers": { "type": "array", "items": { "type": "string" } }
15138
+ }
15139
+ }
15140
+ }
15141
+ },
14966
15142
  "MemorixScope": {
14967
15143
  "type": "object",
14968
15144
  "required": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x12i/memorix-service",
3
- "version": "3.11.1",
3
+ "version": "3.12.1",
4
4
  "description": "Memorix production service composition root — one versioned API over accepted packages.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -47,7 +47,7 @@
47
47
  "@x12i/funcx": "^4.12.0",
48
48
  "@x12i/magit": "2.14.0",
49
49
  "@x12i/memorix-connector-sdk": "^1.3.0",
50
- "@x12i/memorix-data": "^3.1.0",
50
+ "@x12i/memorix-data": "^3.1.1",
51
51
  "@x12i/memorix-data-journey": "^3.1.0",
52
52
  "@x12i/memorix-format": "^3.0.8",
53
53
  "@x12i/memorix-intelligence": "^3.0.2",