@x12i/memorix-client-api 0.18.0 → 0.20.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.
Files changed (112) hide show
  1. package/HANDOVER.md +13 -2
  2. package/dist/agent-directory.d.ts +25 -0
  3. package/dist/agent-directory.d.ts.map +1 -0
  4. package/dist/agent-directory.js +75 -0
  5. package/dist/agent-directory.js.map +1 -0
  6. package/dist/app.d.ts +31 -6
  7. package/dist/app.d.ts.map +1 -1
  8. package/dist/app.js +285 -61
  9. package/dist/app.js.map +1 -1
  10. package/dist/authix.d.ts +28 -2
  11. package/dist/authix.d.ts.map +1 -1
  12. package/dist/authix.js +55 -4
  13. package/dist/authix.js.map +1 -1
  14. package/dist/catalog.d.ts +33 -1
  15. package/dist/catalog.d.ts.map +1 -1
  16. package/dist/catalog.js +83 -4
  17. package/dist/catalog.js.map +1 -1
  18. package/dist/cli.js +11 -1
  19. package/dist/cli.js.map +1 -1
  20. package/dist/config.d.ts +9 -0
  21. package/dist/config.d.ts.map +1 -1
  22. package/dist/config.js +31 -0
  23. package/dist/config.js.map +1 -1
  24. package/dist/errors.d.ts +16 -2
  25. package/dist/errors.d.ts.map +1 -1
  26. package/dist/errors.js +16 -2
  27. package/dist/errors.js.map +1 -1
  28. package/dist/fetch.d.ts.map +1 -1
  29. package/dist/fetch.js +27 -3
  30. package/dist/fetch.js.map +1 -1
  31. package/dist/peers.d.ts +2 -2
  32. package/dist/peers.d.ts.map +1 -1
  33. package/dist/peers.js +4 -4
  34. package/dist/peers.js.map +1 -1
  35. package/dist/refs.d.ts +7 -1
  36. package/dist/refs.d.ts.map +1 -1
  37. package/dist/refs.js +36 -26
  38. package/dist/refs.js.map +1 -1
  39. package/dist/scope.d.ts +25 -2
  40. package/dist/scope.d.ts.map +1 -1
  41. package/dist/scope.js +71 -4
  42. package/dist/scope.js.map +1 -1
  43. package/dist/scoper-embedded.d.ts +29 -0
  44. package/dist/scoper-embedded.d.ts.map +1 -0
  45. package/dist/scoper-embedded.js +239 -0
  46. package/dist/scoper-embedded.js.map +1 -0
  47. package/dist/scoper.d.ts +19 -27
  48. package/dist/scoper.d.ts.map +1 -1
  49. package/dist/scoper.js +51 -254
  50. package/dist/scoper.js.map +1 -1
  51. package/dist/upstream.d.ts +6 -1
  52. package/dist/upstream.d.ts.map +1 -1
  53. package/dist/upstream.js +22 -4
  54. package/dist/upstream.js.map +1 -1
  55. package/dist/v1/census.d.ts +63 -0
  56. package/dist/v1/census.d.ts.map +1 -0
  57. package/dist/v1/census.js +154 -0
  58. package/dist/v1/census.js.map +1 -0
  59. package/dist/v1/content.d.ts +48 -0
  60. package/dist/v1/content.d.ts.map +1 -0
  61. package/dist/v1/content.js +323 -0
  62. package/dist/v1/content.js.map +1 -0
  63. package/dist/v1/context.d.ts +50 -0
  64. package/dist/v1/context.d.ts.map +1 -0
  65. package/dist/v1/context.js +4 -0
  66. package/dist/v1/context.js.map +1 -0
  67. package/dist/v1/directory.d.ts +26 -0
  68. package/dist/v1/directory.d.ts.map +1 -0
  69. package/dist/v1/directory.js +89 -0
  70. package/dist/v1/directory.js.map +1 -0
  71. package/dist/v1/discovery.d.ts +24 -0
  72. package/dist/v1/discovery.d.ts.map +1 -0
  73. package/dist/v1/discovery.js +166 -0
  74. package/dist/v1/discovery.js.map +1 -0
  75. package/dist/v1/gaps.d.ts +18 -0
  76. package/dist/v1/gaps.d.ts.map +1 -0
  77. package/dist/v1/gaps.js +2 -0
  78. package/dist/v1/gaps.js.map +1 -0
  79. package/dist/v1/http.d.ts +18 -0
  80. package/dist/v1/http.d.ts.map +1 -0
  81. package/dist/v1/http.js +105 -0
  82. package/dist/v1/http.js.map +1 -0
  83. package/dist/v1/mapping.d.ts +161 -0
  84. package/dist/v1/mapping.d.ts.map +1 -0
  85. package/dist/v1/mapping.js +402 -0
  86. package/dist/v1/mapping.js.map +1 -0
  87. package/dist/v1/planning-store.d.ts +74 -0
  88. package/dist/v1/planning-store.d.ts.map +1 -0
  89. package/dist/v1/planning-store.js +192 -0
  90. package/dist/v1/planning-store.js.map +1 -0
  91. package/dist/v1/planning.d.ts +5 -0
  92. package/dist/v1/planning.d.ts.map +1 -0
  93. package/dist/v1/planning.js +297 -0
  94. package/dist/v1/planning.js.map +1 -0
  95. package/dist/v1/records.d.ts +18 -0
  96. package/dist/v1/records.d.ts.map +1 -0
  97. package/dist/v1/records.js +42 -0
  98. package/dist/v1/records.js.map +1 -0
  99. package/dist/v1/relationships.d.ts +72 -0
  100. package/dist/v1/relationships.d.ts.map +1 -0
  101. package/dist/v1/relationships.js +436 -0
  102. package/dist/v1/relationships.js.map +1 -0
  103. package/dist/v1/routes.d.ts +5 -0
  104. package/dist/v1/routes.d.ts.map +1 -0
  105. package/dist/v1/routes.js +16 -0
  106. package/dist/v1/routes.js.map +1 -0
  107. package/dist/v1/sources.d.ts +62 -0
  108. package/dist/v1/sources.d.ts.map +1 -0
  109. package/dist/v1/sources.js +218 -0
  110. package/dist/v1/sources.js.map +1 -0
  111. package/openapi/openapi.json +3616 -480
  112. package/package.json +74 -74
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/v1/context.ts"],"names":[],"mappings":"AAgBA,MAAM,UAAU,OAAO,CAAC,GAAmB;IACzC,OAAO,GAA8B,CAAC;AACxC,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { ClientScope } from "../scope.js";
2
+ import { type Upstream } from "../upstream.js";
3
+ export type DirectorySubject = {
4
+ recordId: string;
5
+ objectType: string;
6
+ dataCategory: string | null;
7
+ contentTypes: string[];
8
+ };
9
+ export type DirectoryPage = {
10
+ subjects: DirectorySubject[];
11
+ nextCursor: string | null;
12
+ };
13
+ /**
14
+ * One page of the record directory (`GET /api/data/subjects`, service 3.20.0).
15
+ * `null` when this Memorix does not serve the route.
16
+ */
17
+ export declare function pageDirectory(upstream: Upstream, scope: ClientScope, objectType: string, page: {
18
+ limit: number;
19
+ cursor?: string;
20
+ withoutContent?: boolean;
21
+ }): Promise<DirectoryPage | null>;
22
+ /** Composed contents of each listed record, at most eight reads at a time. */
23
+ export declare function composeSubjects(upstream: Upstream, scope: ClientScope, subjects: DirectorySubject[], wanted: string[], markdown: boolean): Promise<Map<string, Record<string, unknown>>>;
24
+ /** True when Memorix pages the record directory. Reused for five minutes. */
25
+ export declare function directoryPagingServed(upstream: Upstream, scope: ClientScope): Promise<boolean>;
26
+ //# sourceMappingURL=directory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../../src/v1/directory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAA0B,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAEvE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAKxF;;;GAGG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAAE,GACjE,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAiC/B;AAED,8EAA8E;AAC9E,wBAAsB,eAAe,CACnC,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,gBAAgB,EAAE,EAC5B,MAAM,EAAE,MAAM,EAAE,EAChB,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAqB/C;AAID,6EAA6E;AAC7E,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAa9F"}
@@ -0,0 +1,89 @@
1
+ import { ApiError, UpstreamError } from "../errors.js";
2
+ import { asRecord, upstreamCode } from "../upstream.js";
3
+ const COMPOSE_CONCURRENCY = 8;
4
+ const PROBE_TTL_MS = 5 * 60_000;
5
+ /**
6
+ * One page of the record directory (`GET /api/data/subjects`, service 3.20.0).
7
+ * `null` when this Memorix does not serve the route.
8
+ */
9
+ export async function pageDirectory(upstream, scope, objectType, page) {
10
+ const params = new URLSearchParams({ objectType, limit: String(page.limit) });
11
+ if (page.cursor)
12
+ params.set("cursor", page.cursor);
13
+ if (page.withoutContent)
14
+ params.set("withoutContent", "true");
15
+ let body;
16
+ try {
17
+ body = asRecord(await upstream.get(`/api/data/subjects?${params.toString()}`, scope));
18
+ }
19
+ catch (err) {
20
+ if (err instanceof UpstreamError) {
21
+ const code = upstreamCode(err);
22
+ if (code === "ROUTE_UNKNOWN_OBJECT_TYPE") {
23
+ throw new ApiError(404, "READ_NOT_FOUND", `Unknown object type ${objectType}`);
24
+ }
25
+ if (err.statusCode === 404 || err.statusCode === 501)
26
+ return null;
27
+ }
28
+ throw err;
29
+ }
30
+ if (!body || !Array.isArray(body.subjects))
31
+ return null;
32
+ const subjects = [];
33
+ for (const raw of body.subjects) {
34
+ const item = asRecord(raw);
35
+ if (!item || typeof item.recordId !== "string")
36
+ continue;
37
+ subjects.push({
38
+ recordId: item.recordId,
39
+ objectType: typeof item.objectType === "string" ? item.objectType : objectType,
40
+ dataCategory: typeof item.dataCategory === "string" ? item.dataCategory : null,
41
+ contentTypes: Array.isArray(item.contentTypes)
42
+ ? item.contentTypes.filter((ct) => typeof ct === "string")
43
+ : [],
44
+ });
45
+ }
46
+ const next = asRecord(body.pageInfo)?.nextCursor;
47
+ return { subjects, nextCursor: typeof next === "string" && next ? next : null };
48
+ }
49
+ /** Composed contents of each listed record, at most eight reads at a time. */
50
+ export async function composeSubjects(upstream, scope, subjects, wanted, markdown) {
51
+ const out = new Map();
52
+ const queue = subjects
53
+ .map((subject) => ({ subject, contentTypes: subject.contentTypes.filter((ct) => wanted.includes(ct)) }))
54
+ .filter((item) => item.contentTypes.length > 0);
55
+ async function worker() {
56
+ for (let item = queue.shift(); item; item = queue.shift()) {
57
+ const composed = asRecord(await upstream.post("/api/data/compose", scope, {
58
+ explicit: true,
59
+ recordId: item.subject.recordId,
60
+ contentTypes: item.contentTypes,
61
+ ...(markdown ? { include: { markdown: true } } : {}),
62
+ }));
63
+ const contents = asRecord(asRecord(composed?.composition)?.contents);
64
+ if (contents)
65
+ out.set(item.subject.recordId, contents);
66
+ }
67
+ }
68
+ await Promise.all(Array.from({ length: Math.min(COMPOSE_CONCURRENCY, queue.length) }, () => worker()));
69
+ return out;
70
+ }
71
+ const probes = new WeakMap();
72
+ /** True when Memorix pages the record directory. Reused for five minutes. */
73
+ export function directoryPagingServed(upstream, scope) {
74
+ const probe = probes.get(upstream);
75
+ if (probe && Date.now() - probe.at < PROBE_TTL_MS)
76
+ return probe.value;
77
+ const value = (async () => {
78
+ try {
79
+ await upstream.get("/api/data/subjects?objectType=__capability_probe__&limit=1", scope);
80
+ return true;
81
+ }
82
+ catch (err) {
83
+ return err instanceof UpstreamError && upstreamCode(err) === "ROUTE_UNKNOWN_OBJECT_TYPE";
84
+ }
85
+ })();
86
+ probes.set(upstream, { at: Date.now(), value });
87
+ return value;
88
+ }
89
+ //# sourceMappingURL=directory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory.js","sourceRoot":"","sources":["../../src/v1/directory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { FastifyInstance } from "fastify";
2
+ import type { V1Deps } from "./context.js";
3
+ export declare const CONTRACT = "visualizer";
4
+ export declare const CONTRACT_REVISION = "2026-10-24";
5
+ export declare const SERVICE = "@x12i/memorix-client-api";
6
+ export type Features = {
7
+ mapping: boolean;
8
+ census: boolean;
9
+ orgAgents: boolean;
10
+ relationshipPairs: boolean;
11
+ relationshipPairCounts: boolean;
12
+ sourceContentTypes: boolean;
13
+ partialListing: boolean;
14
+ conflictBodies: boolean;
15
+ directoryOnlyRecords: boolean;
16
+ conflictCensus: boolean;
17
+ directoryPaging: boolean;
18
+ planning: boolean;
19
+ packRevisions: boolean;
20
+ conditionalRefresh: boolean;
21
+ };
22
+ export declare function featuresFor(deps: V1Deps, orgId: string, caller: string): Promise<Features>;
23
+ export declare function registerDiscoveryRoutes(app: FastifyInstance, deps: V1Deps): void;
24
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/v1/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAM/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAI3C,eAAO,MAAM,QAAQ,eAAe,CAAC;AACrC,eAAO,MAAM,iBAAiB,eAAe,CAAC;AAC9C,eAAO,MAAM,OAAO,6BAA6B,CAAC;AAElD,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,sBAAsB,EAAE,OAAO,CAAC;IAChC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;IACxB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,OAAO,CAAC;CAC7B,CAAC;AAyBF,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4BhG;AAOD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAoHhF"}
@@ -0,0 +1,166 @@
1
+ import { ApiError } from "../errors.js";
2
+ import { orgFromToken } from "../scope.js";
3
+ import { asRecord } from "../upstream.js";
4
+ import { directoryPagingServed } from "./directory.js";
5
+ import { queryOf, text } from "./http.js";
6
+ export const CONTRACT = "visualizer";
7
+ export const CONTRACT_REVISION = "2026-10-24";
8
+ export const SERVICE = "@x12i/memorix-client-api";
9
+ const AGENT_INFO_TTL_MS = 5 * 60_000;
10
+ function headerValue(req, name) {
11
+ const raw = req.headers[name];
12
+ return (Array.isArray(raw) ? raw[0] : raw)?.trim() ?? "";
13
+ }
14
+ /** Org used for a call that does not select one: the header, else the token's only org. */
15
+ function orgForProbe(req, claims) {
16
+ const requested = headerValue(req, "x-memorix-org-id");
17
+ if (claims) {
18
+ if (requested)
19
+ return orgFromToken(claims.organizationIds, requested);
20
+ return claims.organizationIds[0] ?? "";
21
+ }
22
+ return requested;
23
+ }
24
+ export async function featuresFor(deps, orgId, caller) {
25
+ let orgAgents = false;
26
+ let directoryPaging = false;
27
+ if (orgId) {
28
+ try {
29
+ orgAgents = (await deps.directory.deployed(orgId, caller)) !== null;
30
+ }
31
+ catch {
32
+ orgAgents = false;
33
+ }
34
+ directoryPaging = await directoryPagingServed(deps.upstream, { orgId, agentIds: ["*"], caller });
35
+ }
36
+ // Every composed read pairs with memorix-service 3.19.1, which also serves the org agent record (3.18.0).
37
+ return {
38
+ mapping: orgAgents,
39
+ census: orgAgents,
40
+ orgAgents,
41
+ relationshipPairs: orgAgents,
42
+ relationshipPairCounts: orgAgents,
43
+ sourceContentTypes: orgAgents,
44
+ partialListing: orgAgents,
45
+ conflictBodies: orgAgents,
46
+ directoryOnlyRecords: orgAgents,
47
+ conflictCensus: orgAgents,
48
+ directoryPaging,
49
+ planning: deps.planning !== null,
50
+ packRevisions: false,
51
+ conditionalRefresh: true,
52
+ };
53
+ }
54
+ function organizationEntry(id, claims) {
55
+ const name = claims?.organizationNames?.[id];
56
+ return name ? { id, name, nameStatus: "declared" } : { id, nameStatus: "unspecified" };
57
+ }
58
+ export function registerDiscoveryRoutes(app, deps) {
59
+ const agentInfo = new Map();
60
+ function infoOf(agentId, scope) {
61
+ const hit = agentInfo.get(agentId);
62
+ if (hit && Date.now() - hit.at < AGENT_INFO_TTL_MS)
63
+ return hit.value;
64
+ const value = (async () => {
65
+ const body = asRecord(await deps.upstream.get(`/api/metadata/raw?agentId=${encodeURIComponent(agentId)}`, {
66
+ orgId: scope.orgId,
67
+ agentIds: [agentId],
68
+ caller: scope.caller,
69
+ }));
70
+ const agent = asRecord(asRecord(body?.raw)?.agent);
71
+ const lineage = asRecord(body?.lineage);
72
+ return {
73
+ ...(typeof agent?.name === "string" && agent.name ? { name: agent.name } : {}),
74
+ ...(typeof agent?.description === "string" && agent.description ? { description: agent.description } : {}),
75
+ ...(typeof lineage?.checksum === "string"
76
+ ? {
77
+ pack: {
78
+ checksum: lineage.checksum,
79
+ ...(typeof lineage.installedAt === "string" ? { installedAt: lineage.installedAt } : {}),
80
+ ...(typeof lineage.source === "string" ? { source: lineage.source } : {}),
81
+ },
82
+ }
83
+ : {}),
84
+ };
85
+ })();
86
+ agentInfo.set(agentId, { at: Date.now(), value });
87
+ value.catch(() => agentInfo.delete(agentId));
88
+ return value;
89
+ }
90
+ app.get("/ready", async (_req, reply) => {
91
+ const memorix = await deps.probeMemorix();
92
+ if (!memorix)
93
+ return reply.status(503).send({ ok: false, service: SERVICE, memorix: "down" });
94
+ return { ok: true, service: SERVICE, auth: deps.authMode, memorix: "up" };
95
+ });
96
+ app.get("/api/v1/capabilities", async (req) => {
97
+ const { claims, caller } = await deps.authenticate(req);
98
+ const orgId = orgForProbe(req, claims);
99
+ return {
100
+ service: SERVICE,
101
+ api: "v1",
102
+ contract: CONTRACT,
103
+ contractRevision: CONTRACT_REVISION,
104
+ features: await featuresFor(deps, orgId, caller),
105
+ limits: {
106
+ pageLimitDefault: 50,
107
+ pageLimitMax: 200,
108
+ refBatchMax: 200,
109
+ upstreamTimeoutMs: 30_000,
110
+ },
111
+ rateLimit: null,
112
+ };
113
+ });
114
+ app.get("/api/v1/organizations", async (req) => {
115
+ const { claims } = await deps.authenticate(req);
116
+ const ids = claims ? claims.organizationIds : [headerValue(req, "x-memorix-org-id")].filter(Boolean);
117
+ return { organizations: ids.map((id) => organizationEntry(id, claims)) };
118
+ });
119
+ app.get("/api/v1/organization", async (req) => {
120
+ const scope = await deps.scopeFor(req, { agents: "none" });
121
+ const features = await featuresFor(deps, scope.orgId, scope.caller);
122
+ return {
123
+ organization: organizationEntry(scope.orgId, (await deps.authenticate(req)).claims),
124
+ capabilities: { census: features.census, sources: features.sourceContentTypes, planning: features.planning },
125
+ };
126
+ });
127
+ app.get("/api/v1/agents", async (req) => {
128
+ const scope = await deps.scopeFor(req, { agents: "none" });
129
+ const deployment = text(queryOf(req).deployment) ?? "org";
130
+ if (deployment !== "org" && deployment !== "platform") {
131
+ throw new ApiError(400, "VALIDATION", "deployment must be org or platform");
132
+ }
133
+ const deployed = await deps.directory.deployed(scope.orgId, scope.caller);
134
+ if (deployed === null && deployment === "org") {
135
+ throw new ApiError(501, "CAPABILITY_UNAVAILABLE", "Memorix keeps no org agent record", { feature: "orgAgents" });
136
+ }
137
+ const deployedIds = new Set((deployed ?? []).map((agent) => agent.id));
138
+ const listed = deployment === "org" ? (deployed ?? []) : await deps.directory.installed(scope.orgId, scope.caller);
139
+ const agents = await Promise.all(listed.map(async (agent) => {
140
+ let info = {};
141
+ try {
142
+ info = await infoOf(agent.id, scope);
143
+ }
144
+ catch {
145
+ info = {};
146
+ }
147
+ const deploymentState = deployment === "org" ? (agent.ok ? "deployed" : "missing") : deployedIds.has(agent.id) ? "deployed" : "installed";
148
+ return {
149
+ id: agent.id,
150
+ ...(info.name ? { name: info.name } : {}),
151
+ ...(info.description ? { description: info.description } : {}),
152
+ versionStatus: "unspecified",
153
+ ...(info.pack ? { pack: info.pack } : {}),
154
+ deploymentState,
155
+ resolution: { ok: agent.ok, error: agent.ok ? null : agent.error },
156
+ objectTypes: agent.ok ? agent.objectTypes : [],
157
+ };
158
+ }));
159
+ return {
160
+ scope: { orgId: scope.orgId, caller: scope.caller },
161
+ deployment,
162
+ agents,
163
+ };
164
+ });
165
+ }
166
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/v1/discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export type GapCategory = "empty" | "directory-only" | "not-measured" | "estimated" | "inaccessible" | "resolution-failure" | "unavailable" | "stale";
2
+ export type Gap = {
3
+ code: string;
4
+ category: GapCategory;
5
+ orgId: string;
6
+ agentIds: string[];
7
+ /** Mapping section that was not returned: `counts`, `relationships`, `functions`, or `sources`. */
8
+ section?: "counts" | "relationships" | "functions" | "sources" | "objectTypes";
9
+ objectType?: string;
10
+ contentType?: string;
11
+ definitionId?: string;
12
+ sourceId?: string;
13
+ message?: string;
14
+ observedAt?: string;
15
+ retryable: boolean;
16
+ evidence?: Record<string, unknown>;
17
+ };
18
+ //# sourceMappingURL=gaps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gaps.d.ts","sourceRoot":"","sources":["../../src/v1/gaps.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GACnB,OAAO,GACP,gBAAgB,GAChB,cAAc,GACd,WAAW,GACX,cAAc,GACd,oBAAoB,GACpB,aAAa,GACb,OAAO,CAAC;AAEZ,MAAM,MAAM,GAAG,GAAG;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,mGAAmG;IACnG,OAAO,CAAC,EAAE,QAAQ,GAAG,eAAe,GAAG,WAAW,GAAG,SAAS,GAAG,aAAa,CAAC;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=gaps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gaps.js","sourceRoot":"","sources":["../../src/v1/gaps.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ import type { FastifyReply, FastifyRequest } from "fastify";
2
+ export declare function queryOf(req: FastifyRequest): Record<string, unknown>;
3
+ export declare function text(raw: unknown): string | undefined;
4
+ export declare function csv(raw: unknown): string[] | undefined;
5
+ export declare function jsonQuery(raw: unknown, name: string): unknown;
6
+ export declare function limitOf(raw: unknown, fallback?: number): number;
7
+ export declare function boolQuery(raw: unknown, name: string, fallback?: boolean): boolean;
8
+ export declare function wildcardParam(req: FastifyRequest): string;
9
+ /** Path after `prefix` exactly as sent, before percent-decoding, so `%2F` stays inside one segment. */
10
+ export declare function rawPathAfter(req: FastifyRequest, prefix: string): string | null;
11
+ export declare function decodeSegments(raw: string): string;
12
+ export declare function requestIdFrom(headerValue: string | string[] | undefined): string;
13
+ export declare function etagOf(parts: unknown): string;
14
+ /** Sends `body` with an `ETag`, or `304` with no body when `If-None-Match` matches. */
15
+ export declare function sendWithEtag(req: FastifyRequest, reply: FastifyReply, body: unknown, tagParts: unknown): FastifyReply<import("fastify").RouteGenericInterface, import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, unknown, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown>;
16
+ /** Short stable id for a Memorix fingerprint string. */
17
+ export declare function fingerprintId(raw: unknown): string | null;
18
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/v1/http.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG5D,wBAAgB,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEpE;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAIrD;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAItD;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAQ7D;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,SAAK,GAAG,MAAM,CAK3D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAK/E;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAGzD;AAED,uGAAuG;AACvG,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK/E;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWlD;AAID,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,CAGhF;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE7C;AAYD,uFAAuF;AACvF,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,6RAKtG;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAGzD"}
@@ -0,0 +1,105 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { ApiError } from "../errors.js";
3
+ export function queryOf(req) {
4
+ return (req.query ?? {});
5
+ }
6
+ export function text(raw) {
7
+ if (typeof raw !== "string")
8
+ return undefined;
9
+ const value = raw.trim();
10
+ return value ? value : undefined;
11
+ }
12
+ export function csv(raw) {
13
+ if (typeof raw !== "string" || !raw.trim())
14
+ return undefined;
15
+ const items = raw.split(",").map((item) => item.trim()).filter(Boolean);
16
+ return items.length > 0 ? items : undefined;
17
+ }
18
+ export function jsonQuery(raw, name) {
19
+ if (raw === undefined || raw === "")
20
+ return undefined;
21
+ if (typeof raw !== "string")
22
+ return raw;
23
+ try {
24
+ return JSON.parse(raw);
25
+ }
26
+ catch {
27
+ throw new ApiError(400, "VALIDATION", `${name} must be JSON`);
28
+ }
29
+ }
30
+ export function limitOf(raw, fallback = 50) {
31
+ if (raw === undefined || raw === "")
32
+ return fallback;
33
+ const limit = Number(raw);
34
+ if (!Number.isFinite(limit))
35
+ throw new ApiError(400, "VALIDATION", "limit must be a number");
36
+ return Math.min(Math.max(Math.trunc(limit), 1), 200);
37
+ }
38
+ export function boolQuery(raw, name, fallback = false) {
39
+ if (raw === undefined || raw === "")
40
+ return fallback;
41
+ if (raw === true || raw === "true")
42
+ return true;
43
+ if (raw === false || raw === "false")
44
+ return false;
45
+ throw new ApiError(400, "VALIDATION", `${name} must be true or false`);
46
+ }
47
+ export function wildcardParam(req) {
48
+ const params = req.params;
49
+ return params["*"] ?? "";
50
+ }
51
+ /** Path after `prefix` exactly as sent, before percent-decoding, so `%2F` stays inside one segment. */
52
+ export function rawPathAfter(req, prefix) {
53
+ const url = req.raw.url ?? req.url;
54
+ const path = url.split("?")[0] ?? "";
55
+ if (!path.startsWith(prefix))
56
+ return null;
57
+ return path.slice(prefix.length);
58
+ }
59
+ export function decodeSegments(raw) {
60
+ return raw
61
+ .split("/")
62
+ .map((segment) => {
63
+ try {
64
+ return decodeURIComponent(segment);
65
+ }
66
+ catch {
67
+ throw new ApiError(400, "VALIDATION", "path segment is not valid percent-encoding");
68
+ }
69
+ })
70
+ .join("/");
71
+ }
72
+ const REQUEST_ID = /^[\w.:\-/+=]{1,128}$/;
73
+ export function requestIdFrom(headerValue) {
74
+ const raw = (Array.isArray(headerValue) ? headerValue[0] : headerValue)?.trim();
75
+ return raw && REQUEST_ID.test(raw) ? raw : randomUUID();
76
+ }
77
+ export function etagOf(parts) {
78
+ return `"${createHash("sha256").update(JSON.stringify(parts)).digest("base64url").slice(0, 27)}"`;
79
+ }
80
+ function etagMatches(header, etag) {
81
+ const raw = Array.isArray(header) ? header.join(",") : header;
82
+ if (!raw)
83
+ return false;
84
+ if (raw.trim() === "*")
85
+ return true;
86
+ return raw
87
+ .split(",")
88
+ .map((item) => item.trim().replace(/^W\//, ""))
89
+ .includes(etag);
90
+ }
91
+ /** Sends `body` with an `ETag`, or `304` with no body when `If-None-Match` matches. */
92
+ export function sendWithEtag(req, reply, body, tagParts) {
93
+ const etag = etagOf(tagParts);
94
+ reply.header("etag", etag);
95
+ if (etagMatches(req.headers["if-none-match"], etag))
96
+ return reply.code(304).send();
97
+ return reply.send(body);
98
+ }
99
+ /** Short stable id for a Memorix fingerprint string. */
100
+ export function fingerprintId(raw) {
101
+ if (typeof raw !== "string" || !raw)
102
+ return null;
103
+ return createHash("sha256").update(raw).digest("hex").slice(0, 16);
104
+ }
105
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/v1/http.ts"],"names":[],"mappings":"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"}