@x12i/memorix-service 0.0.0-bootstrap.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 (84) hide show
  1. package/README.md +37 -0
  2. package/dist/app.d.ts +21 -0
  3. package/dist/app.d.ts.map +1 -0
  4. package/dist/app.js +67 -0
  5. package/dist/app.js.map +1 -0
  6. package/dist/catalog-bridge.d.ts +7 -0
  7. package/dist/catalog-bridge.d.ts.map +1 -0
  8. package/dist/catalog-bridge.js +155 -0
  9. package/dist/catalog-bridge.js.map +1 -0
  10. package/dist/cli.d.ts +3 -0
  11. package/dist/cli.d.ts.map +1 -0
  12. package/dist/cli.js +36 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/errors.d.ts +25 -0
  15. package/dist/errors.d.ts.map +1 -0
  16. package/dist/errors.js +79 -0
  17. package/dist/errors.js.map +1 -0
  18. package/dist/index.d.ts +7 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +7 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/isolation.d.ts +63 -0
  23. package/dist/isolation.d.ts.map +1 -0
  24. package/dist/isolation.js +175 -0
  25. package/dist/isolation.js.map +1 -0
  26. package/dist/known-packs.d.ts +5 -0
  27. package/dist/known-packs.d.ts.map +1 -0
  28. package/dist/known-packs.js +26 -0
  29. package/dist/known-packs.js.map +1 -0
  30. package/dist/mongo-metadata-store.d.ts +17 -0
  31. package/dist/mongo-metadata-store.d.ts.map +1 -0
  32. package/dist/mongo-metadata-store.js +81 -0
  33. package/dist/mongo-metadata-store.js.map +1 -0
  34. package/dist/openapi/openapi.json +6431 -0
  35. package/dist/platform.d.ts +52 -0
  36. package/dist/platform.d.ts.map +1 -0
  37. package/dist/platform.js +246 -0
  38. package/dist/platform.js.map +1 -0
  39. package/dist/relationships/operator-links.d.ts +23 -0
  40. package/dist/relationships/operator-links.d.ts.map +1 -0
  41. package/dist/relationships/operator-links.js +41 -0
  42. package/dist/relationships/operator-links.js.map +1 -0
  43. package/dist/request-scope.d.ts +7 -0
  44. package/dist/request-scope.d.ts.map +1 -0
  45. package/dist/request-scope.js +24 -0
  46. package/dist/request-scope.js.map +1 -0
  47. package/dist/routes/data.d.ts +4 -0
  48. package/dist/routes/data.d.ts.map +1 -0
  49. package/dist/routes/data.js +237 -0
  50. package/dist/routes/data.js.map +1 -0
  51. package/dist/routes/intelligence.d.ts +5 -0
  52. package/dist/routes/intelligence.d.ts.map +1 -0
  53. package/dist/routes/intelligence.js +94 -0
  54. package/dist/routes/intelligence.js.map +1 -0
  55. package/dist/routes/memory.d.ts +4 -0
  56. package/dist/routes/memory.d.ts.map +1 -0
  57. package/dist/routes/memory.js +80 -0
  58. package/dist/routes/memory.js.map +1 -0
  59. package/dist/routes/metadata.d.ts +4 -0
  60. package/dist/routes/metadata.d.ts.map +1 -0
  61. package/dist/routes/metadata.js +104 -0
  62. package/dist/routes/metadata.js.map +1 -0
  63. package/dist/routes/operations.d.ts +4 -0
  64. package/dist/routes/operations.d.ts.map +1 -0
  65. package/dist/routes/operations.js +66 -0
  66. package/dist/routes/operations.js.map +1 -0
  67. package/dist/routes/pipelines.d.ts +4 -0
  68. package/dist/routes/pipelines.d.ts.map +1 -0
  69. package/dist/routes/pipelines.js +128 -0
  70. package/dist/routes/pipelines.js.map +1 -0
  71. package/dist/routes/relationships.d.ts +4 -0
  72. package/dist/routes/relationships.d.ts.map +1 -0
  73. package/dist/routes/relationships.js +138 -0
  74. package/dist/routes/relationships.js.map +1 -0
  75. package/dist/routes/workflow.d.ts +4 -0
  76. package/dist/routes/workflow.d.ts.map +1 -0
  77. package/dist/routes/workflow.js +104 -0
  78. package/dist/routes/workflow.js.map +1 -0
  79. package/dist/scope.d.ts +19 -0
  80. package/dist/scope.d.ts.map +1 -0
  81. package/dist/scope.js +53 -0
  82. package/dist/scope.js.map +1 -0
  83. package/openapi/openapi.json +6431 -0
  84. package/package.json +65 -0
@@ -0,0 +1,66 @@
1
+ import { resolveScope } from "../request-scope.js";
2
+ export async function registerOperationsRoutes(app, platform) {
3
+ app.get("/api/operations/runs", async (req) => {
4
+ const scope = resolveScope(req);
5
+ const ports = platform.client ? platform.portsFor(scope) : null;
6
+ const pipelineRuns = ports
7
+ ? await ports.pipeline.listRuns?.() ?? []
8
+ : [];
9
+ return {
10
+ scope,
11
+ pipelineRuns,
12
+ memoryRuns: [],
13
+ relationshipRuns: [],
14
+ intelligenceArtifacts: platform.client
15
+ ? await platform.intelligenceArtifactsFor(scope.orgId).listProposalIds()
16
+ : [],
17
+ };
18
+ });
19
+ app.get("/api/operations/schedules", async (req) => {
20
+ const scope = resolveScope(req);
21
+ const effective = platform.metadata.resolveEffective(scope.agentIds);
22
+ const schedules = (effective.effective ?? [])
23
+ .filter((e) => e.kind === "schedules")
24
+ .map((e) => e.definition);
25
+ return { scope, schedules };
26
+ });
27
+ app.get("/api/operations/artifacts", async (req) => {
28
+ const scope = resolveScope(req);
29
+ const ports = platform.client ? platform.portsFor(scope) : null;
30
+ const runs = ports ? ((await ports.pipeline.listRuns?.()) ?? []) : [];
31
+ const artifacts = [];
32
+ for (const run of runs) {
33
+ const runId = String(run.runId ?? "");
34
+ const refs = [
35
+ run.capturedContextRef,
36
+ ...(Array.isArray(run.artifacts) ? run.artifacts : []),
37
+ ].filter(Boolean);
38
+ for (const ref of refs) {
39
+ if (ref && typeof ref === "object") {
40
+ artifacts.push({
41
+ ...ref,
42
+ runId,
43
+ pipelineId: run.pipelineId ?? null,
44
+ runStatus: run.status ?? null,
45
+ });
46
+ }
47
+ }
48
+ // Also surface run identity as operational context when DataRef missing but run exists
49
+ if (refs.length === 0 && runId) {
50
+ artifacts.push({
51
+ kind: "pipeline-run",
52
+ runId,
53
+ pipelineId: run.pipelineId ?? null,
54
+ status: run.status ?? null,
55
+ note: "run ledger entry (no capturedContextRef on this run)",
56
+ });
57
+ }
58
+ }
59
+ return {
60
+ scope,
61
+ artifacts,
62
+ note: "DataRef / G8 artifact references from pipeline runs; no inline secrets",
63
+ };
64
+ });
65
+ }
66
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.js","sourceRoot":"","sources":["../../src/routes/operations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { FastifyInstance } from "fastify";
2
+ import type { MemorixPlatform } from "../platform.js";
3
+ export declare function registerPipelineRoutes(app: FastifyInstance, platform: MemorixPlatform): Promise<void>;
4
+ //# sourceMappingURL=pipelines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipelines.d.ts","sourceRoot":"","sources":["../../src/routes/pipelines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,IAAI,CAAC,CA0Jf"}
@@ -0,0 +1,128 @@
1
+ import { validatePipelineDefinition } from "@x12i/memorix-pipeline/v2";
2
+ import { resolveScope } from "../request-scope.js";
3
+ import { ServiceError } from "../errors.js";
4
+ export async function registerPipelineRoutes(app, platform) {
5
+ app.get("/api/pipelines/definitions", async (req) => {
6
+ const scope = resolveScope(req);
7
+ const effective = platform.metadata.resolveEffective(scope.agentIds);
8
+ const definitions = (effective.effective ?? [])
9
+ .filter((e) => e.kind === "pipelines")
10
+ .map((e) => e.definition);
11
+ return { scope, definitions };
12
+ });
13
+ app.post("/api/pipelines/validate", async (req) => {
14
+ const scope = resolveScope(req);
15
+ const body = req.body;
16
+ let definition = body.definition;
17
+ if (!definition && body.pipelineId) {
18
+ const def = platform.metadata.getDefinition(scope.agentIds, "pipelines", body.pipelineId);
19
+ definition = def?.definition;
20
+ }
21
+ if (!definition) {
22
+ throw new ServiceError("VALIDATION", "definition or pipelineId required", 400);
23
+ }
24
+ try {
25
+ validatePipelineDefinition(definition);
26
+ return { scope, valid: true, compiled: true, issues: [] };
27
+ }
28
+ catch (err) {
29
+ return {
30
+ scope,
31
+ valid: false,
32
+ compiled: false,
33
+ issues: [err instanceof Error ? err.message : String(err)],
34
+ };
35
+ }
36
+ });
37
+ app.post("/api/pipelines/start", async (req) => {
38
+ const scope = resolveScope(req);
39
+ const body = req.body;
40
+ if (!body?.pipelineId && !body?.definition) {
41
+ throw new ServiceError("VALIDATION", "pipelineId or definition required", 400);
42
+ }
43
+ const ports = platform.portsFor(scope);
44
+ let definition;
45
+ if (body.definition) {
46
+ definition = structuredClone(body.definition);
47
+ }
48
+ else {
49
+ const def = platform.metadata.getDefinition(scope.agentIds, "pipelines", body.pipelineId);
50
+ if (!def?.definition) {
51
+ throw new ServiceError("NOT_FOUND", `pipeline ${body.pipelineId} not found`, 404);
52
+ }
53
+ definition = structuredClone(def.definition);
54
+ }
55
+ if (body.forceFailStepId) {
56
+ const steps = definition.steps ?? [];
57
+ const step = steps.find((s) => s.id === body.forceFailStepId || s.stepId === body.forceFailStepId);
58
+ if (!step) {
59
+ throw new ServiceError("VALIDATION", `forceFailStepId ${body.forceFailStepId} not found on pipeline`, 400);
60
+ }
61
+ step.portConfig = { ...(step.portConfig ?? {}), forceFail: true };
62
+ }
63
+ const run = await ports.pipeline.start(definition, body.input, {
64
+ trigger: body.trigger ?? "on-demand",
65
+ });
66
+ return {
67
+ scope,
68
+ runId: run.runId,
69
+ pipelineId: body.pipelineId ?? definition.pipelineId ?? null,
70
+ trigger: body.trigger ?? "on-demand",
71
+ status: run.status,
72
+ forceFailStepId: body.forceFailStepId ?? null,
73
+ run,
74
+ };
75
+ });
76
+ app.get("/api/pipelines/runs/:runId", async (req) => {
77
+ const scope = resolveScope(req);
78
+ const { runId } = req.params;
79
+ const ports = platform.portsFor(scope);
80
+ const run = await ports.pipeline.getRun(runId);
81
+ const steps = run
82
+ ? await ports.pipeline.getStepAttempts(runId)
83
+ : [];
84
+ const captured = run?.capturedContextRef ?? null;
85
+ return {
86
+ scope,
87
+ runId,
88
+ status: run?.status ?? "unknown",
89
+ pipelineId: run?.pipelineId ?? null,
90
+ steps,
91
+ artifacts: captured ? [captured] : [],
92
+ capturedContextRef: captured,
93
+ run,
94
+ };
95
+ });
96
+ app.post("/api/pipelines/runs/:runId/retry-step", async (req) => {
97
+ const scope = resolveScope(req);
98
+ const { runId } = req.params;
99
+ const body = req.body;
100
+ if (!body?.confirm) {
101
+ throw new ServiceError("CONFIRMATION_REQUIRED", "confirm:true required", 400);
102
+ }
103
+ if (!body.stepId)
104
+ throw new ServiceError("VALIDATION", "stepId required", 400);
105
+ const ports = platform.portsFor(scope);
106
+ const result = await ports.pipeline.retryFailedStep(runId, body.stepId);
107
+ const run = await ports.pipeline.getRun(runId);
108
+ const steps = await ports.pipeline.getStepAttempts(runId);
109
+ return {
110
+ scope,
111
+ runId,
112
+ stepId: body.stepId,
113
+ status: run?.status ?? "unknown",
114
+ stepAttempt: result,
115
+ steps,
116
+ run,
117
+ note: "retry envelope; status is the refreshed pipeline run status",
118
+ };
119
+ });
120
+ app.post("/api/pipelines/runs/:runId/resume", async (req) => {
121
+ const scope = resolveScope(req);
122
+ const { runId } = req.params;
123
+ const ports = platform.portsFor(scope);
124
+ const result = await ports.pipeline.resume(runId);
125
+ return { scope, runId, status: "resume-accepted", result };
126
+ });
127
+ }
128
+ //# sourceMappingURL=pipelines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipelines.js","sourceRoot":"","sources":["../../src/routes/pipelines.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { FastifyInstance } from "fastify";
2
+ import type { MemorixPlatform } from "../platform.js";
3
+ export declare function registerRelationshipRoutes(app: FastifyInstance, platform: MemorixPlatform): Promise<void>;
4
+ //# sourceMappingURL=relationships.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../../src/routes/relationships.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAKtD,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,IAAI,CAAC,CA6Kf"}
@@ -0,0 +1,138 @@
1
+ import { resolveScope } from "../request-scope.js";
2
+ import { ServiceError } from "../errors.js";
3
+ import { normalizeOperatorRelationshipLink } from "../relationships/operator-links.js";
4
+ export async function registerRelationshipRoutes(app, platform) {
5
+ app.get("/api/relationships/definitions", async (req) => {
6
+ const scope = resolveScope(req);
7
+ const ports = platform.portsFor(scope);
8
+ const definitions = platform.metadata
9
+ .resolveEffective(scope.agentIds)
10
+ .effective?.filter((e) => e.kind === "relationship-definitions")
11
+ .map((e) => e.definition) ?? [];
12
+ const compiledPlans = [];
13
+ for (const d of definitions) {
14
+ const id = String(d.id ?? "");
15
+ if (!id)
16
+ continue;
17
+ try {
18
+ compiledPlans.push(ports.relationships.compile(id, scope.agentIds));
19
+ }
20
+ catch {
21
+ /* skip */
22
+ }
23
+ }
24
+ return { scope, definitions, compiledPlans };
25
+ });
26
+ app.get("/api/relationships/query", async (req) => {
27
+ const scope = resolveScope(req);
28
+ const q = req.query;
29
+ if (!q.recordId) {
30
+ throw new ServiceError("VALIDATION", "recordId required", 400);
31
+ }
32
+ const ports = platform.portsFor(scope);
33
+ const traversal = q.direction === "inverse" ? "inverse" : "forward";
34
+ const section = await ports.reader.getRelationships(scope, q.recordId, {
35
+ include: true,
36
+ definitionIds: q.definitionId ? [q.definitionId] : undefined,
37
+ traversal,
38
+ // Prefer snapshots for expansion proof; fall back to raw when snapshots absent.
39
+ expandContentTypes: q.expand === "true" ? ["snapshots", "raw"] : undefined,
40
+ });
41
+ const links = section.items.map((item) => normalizeOperatorRelationshipLink(q.recordId, item, traversal));
42
+ const unresolvedTargets = links.filter((i) => i.targetStatus === "unresolved");
43
+ return {
44
+ scope,
45
+ direction: q.direction ?? "forward",
46
+ definitionId: q.definitionId ?? null,
47
+ links,
48
+ unresolvedTargets,
49
+ pageInfo: section.pageInfo,
50
+ };
51
+ });
52
+ app.post("/api/relationships/discover", async (req) => {
53
+ const scope = resolveScope(req);
54
+ const body = req.body;
55
+ if (!body?.definitionId) {
56
+ throw new ServiceError("VALIDATION", "definitionId required", 400);
57
+ }
58
+ const ports = platform.portsFor(scope);
59
+ const result = await ports.relationships.discoverAndMaterialize(scope, body.definitionId);
60
+ return {
61
+ scope,
62
+ runId: `rel-discover-${Date.now()}`,
63
+ definitionId: body.definitionId,
64
+ status: "completed",
65
+ result,
66
+ };
67
+ });
68
+ app.post("/api/relationships/verify", async (req) => {
69
+ const scope = resolveScope(req);
70
+ const body = req.body;
71
+ if (!body?.definitionId) {
72
+ throw new ServiceError("VALIDATION", "definitionId required", 400);
73
+ }
74
+ const ports = platform.portsFor(scope);
75
+ const verify = await ports.relationships.verifyDefinition(scope, body.definitionId);
76
+ return { scope, definitionId: body.definitionId, verify };
77
+ });
78
+ app.post("/api/relationships/rebuild", async (req) => {
79
+ const scope = resolveScope(req);
80
+ const body = req.body;
81
+ if (!body?.confirm) {
82
+ throw new ServiceError("CONFIRMATION_REQUIRED", "confirm:true required", 400);
83
+ }
84
+ if (!body.definitionId) {
85
+ throw new ServiceError("VALIDATION", "definitionId required", 400);
86
+ }
87
+ const ports = platform.portsFor(scope);
88
+ const rebuild = await ports.relationships.rebuildDefinition(scope, body.definitionId);
89
+ return { scope, definitionId: body.definitionId, rebuild };
90
+ });
91
+ app.post("/api/relationships/cleanup", async (req) => {
92
+ const scope = resolveScope(req);
93
+ const body = req.body;
94
+ if (!body?.confirm) {
95
+ throw new ServiceError("CONFIRMATION_REQUIRED", "confirm:true required", 400);
96
+ }
97
+ if (!body.definitionId) {
98
+ throw new ServiceError("VALIDATION", "definitionId required", 400);
99
+ }
100
+ const ports = platform.portsFor(scope);
101
+ const engine = ports.relationships;
102
+ const cleanup = engine.removeDefinitionLinks
103
+ ? await engine.removeDefinitionLinks(scope, body.definitionId)
104
+ : { status: "noop" };
105
+ return { scope, definitionId: body.definitionId, cleanup };
106
+ });
107
+ app.get("/api/relationships/related-property", async (req) => {
108
+ const scope = resolveScope(req);
109
+ const q = req.query;
110
+ if (!q.definitionId || !q.subjectRecordId || !q.relatedObjectType) {
111
+ throw new ServiceError("VALIDATION", "definitionId, subjectRecordId, relatedObjectType required", 400);
112
+ }
113
+ const ports = platform.portsFor(scope);
114
+ const results = await ports.reader.queryRelationshipsByRelatedProperties(scope, {
115
+ definitionId: q.definitionId,
116
+ subjectRecordId: q.subjectRecordId,
117
+ traversal: "forward",
118
+ relatedObjectType: q.relatedObjectType,
119
+ relatedContentType: q.relatedContentType ?? "snapshots",
120
+ relatedFilters: q.property
121
+ ? [{ field: q.property, op: "exists", value: true }]
122
+ : undefined,
123
+ relatedScanLimit: Math.min(Number(q.limit ?? 50), 200),
124
+ limit: Math.min(Number(q.limit ?? 50), 200),
125
+ });
126
+ return {
127
+ scope,
128
+ definitionId: q.definitionId,
129
+ property: q.property ?? null,
130
+ limit: Math.min(Number(q.limit ?? 50), 200),
131
+ results,
132
+ };
133
+ });
134
+ app.all("/api/relationships/links", async () => {
135
+ throw new ServiceError("FORBIDDEN_ROUTE", "ad-hoc/manual link mutation is not exposed", 405);
136
+ });
137
+ }
138
+ //# sourceMappingURL=relationships.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationships.js","sourceRoot":"","sources":["../../src/routes/relationships.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { FastifyInstance } from "fastify";
2
+ import type { MemorixPlatform } from "../platform.js";
3
+ export declare function registerWorkflowRoutes(app: FastifyInstance, platform: MemorixPlatform): Promise<void>;
4
+ //# sourceMappingURL=workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../src/routes/workflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,IAAI,CAAC,CAqHf"}
@@ -0,0 +1,104 @@
1
+ import { resolveScope } from "../request-scope.js";
2
+ import { ServiceError } from "../errors.js";
3
+ export async function registerWorkflowRoutes(app, platform) {
4
+ app.get("/api/workflow", async (req) => {
5
+ const scope = resolveScope(req);
6
+ const q = req.query;
7
+ if (!q.id) {
8
+ return {
9
+ scope,
10
+ id: null,
11
+ contentType: "workflow",
12
+ record: null,
13
+ currentRevision: null,
14
+ };
15
+ }
16
+ const ports = platform.portsFor(scope);
17
+ const objectType = q.objectType ?? "work-items";
18
+ const record = await ports.reader.getContent(scope, {
19
+ objectType,
20
+ contentType: "workflow",
21
+ recordId: q.id,
22
+ });
23
+ return {
24
+ scope,
25
+ id: q.id,
26
+ objectType,
27
+ contentType: "workflow",
28
+ record,
29
+ currentRevision: record.revision,
30
+ };
31
+ });
32
+ app.put("/api/workflow", async (req) => {
33
+ const scope = resolveScope(req);
34
+ const body = req.body;
35
+ if (!body?.id || !body.record) {
36
+ throw new ServiceError("VALIDATION", "id and record required", 400);
37
+ }
38
+ if (body.expectedRevision === undefined) {
39
+ throw new ServiceError("VALIDATION", "exact revision precondition required (expectedRevision)", 400);
40
+ }
41
+ if (body.currentRevision !== undefined &&
42
+ body.currentRevision !== body.expectedRevision) {
43
+ throw new ServiceError("REVISION_CONFLICT", "stale expectedRevision — reload and retry", 409, {
44
+ id: body.id,
45
+ expectedRevision: body.expectedRevision,
46
+ currentRevision: body.currentRevision,
47
+ });
48
+ }
49
+ const ports = platform.portsFor(scope);
50
+ const objectType = body.objectType ?? "work-items";
51
+ try {
52
+ const record = {
53
+ ...body.record,
54
+ recordId: body.id,
55
+ objectType,
56
+ contentType: "workflow",
57
+ dataCategory: "entity",
58
+ };
59
+ let existing = null;
60
+ try {
61
+ existing = await ports.reader.getContent(scope, {
62
+ objectType,
63
+ contentType: "workflow",
64
+ recordId: body.id,
65
+ });
66
+ }
67
+ catch {
68
+ existing = null;
69
+ }
70
+ let result;
71
+ if (!existing && Number(body.expectedRevision) === 0) {
72
+ result = await ports.writer.add({
73
+ scope,
74
+ precondition: { kind: "absent" },
75
+ record,
76
+ });
77
+ }
78
+ else {
79
+ result = await ports.writer.upsert({
80
+ scope,
81
+ precondition: { kind: "revision", revision: Number(body.expectedRevision) },
82
+ record,
83
+ });
84
+ }
85
+ return {
86
+ scope,
87
+ id: body.id,
88
+ expectedRevision: body.expectedRevision,
89
+ currentRevision: result.record.revision,
90
+ status: "accepted",
91
+ conflict: false,
92
+ result,
93
+ };
94
+ }
95
+ catch (err) {
96
+ const msg = err instanceof Error ? err.message : String(err);
97
+ if (/stale|revision|WRITE_STALE/i.test(msg)) {
98
+ throw new ServiceError("REVISION_CONFLICT", msg, 409);
99
+ }
100
+ throw err;
101
+ }
102
+ });
103
+ }
104
+ //# sourceMappingURL=workflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow.js","sourceRoot":"","sources":["../../src/routes/workflow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Canonical request scope: exactly one orgId + one or more unique agentIds.
3
+ * orgId = data universe; agentIds = effective metadata only.
4
+ */
5
+ export type MemorixScope = {
6
+ orgId: string;
7
+ agentIds: string[];
8
+ };
9
+ export declare class ScopeValidationError extends Error {
10
+ readonly code = "SCOPE_INVALID";
11
+ constructor(message: string);
12
+ }
13
+ export declare function canonicalizeScope(input: {
14
+ orgId?: unknown;
15
+ agentIds?: unknown;
16
+ agentId?: unknown;
17
+ }): MemorixScope;
18
+ export declare function scopeFromHeaders(headers: Record<string, string | string[] | undefined>): MemorixScope;
19
+ //# sourceMappingURL=scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,mBAAmB;gBACpB,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,YAAY,CAkCf;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,YAAY,CAarG"}
package/dist/scope.js ADDED
@@ -0,0 +1,53 @@
1
+ export class ScopeValidationError extends Error {
2
+ code = "SCOPE_INVALID";
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "ScopeValidationError";
6
+ }
7
+ }
8
+ export function canonicalizeScope(input) {
9
+ const orgId = typeof input.orgId === "string" ? input.orgId.trim() : "";
10
+ if (!orgId) {
11
+ throw new ScopeValidationError("orgId is required and must be a non-empty string");
12
+ }
13
+ // Reject singular agentId-only scope on new routes
14
+ if (input.agentId !== undefined && input.agentIds === undefined) {
15
+ throw new ScopeValidationError("singular agentId is rejected; provide agentIds[] (one or more)");
16
+ }
17
+ let raw = [];
18
+ if (Array.isArray(input.agentIds)) {
19
+ raw = input.agentIds;
20
+ }
21
+ else if (typeof input.agentIds === "string") {
22
+ raw = input.agentIds.split(",").map((s) => s.trim());
23
+ }
24
+ const agentIds = [
25
+ ...new Set(raw
26
+ .filter((a) => typeof a === "string")
27
+ .map((a) => a.trim())
28
+ .filter(Boolean)),
29
+ ].sort((a, b) => a.localeCompare(b));
30
+ if (agentIds.length === 0) {
31
+ throw new ScopeValidationError("agentIds[] must contain at least one non-empty agent id");
32
+ }
33
+ return { orgId, agentIds };
34
+ }
35
+ export function scopeFromHeaders(headers) {
36
+ const org = header(headers, "x-memorix-org-id") ??
37
+ header(headers, "x-org-id");
38
+ const agents = header(headers, "x-memorix-agent-ids") ??
39
+ header(headers, "x-agent-ids");
40
+ const singular = header(headers, "x-memorix-agent-id") ?? header(headers, "x-agent-id");
41
+ return canonicalizeScope({
42
+ orgId: org,
43
+ agentIds: agents,
44
+ agentId: singular !== undefined && agents === undefined ? singular : undefined,
45
+ });
46
+ }
47
+ function header(headers, name) {
48
+ const v = headers[name] ?? headers[name.toLowerCase()];
49
+ if (Array.isArray(v))
50
+ return v[0];
51
+ return typeof v === "string" ? v : undefined;
52
+ }
53
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"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"}