@axiom-lattice/gateway 8.3.0 → 9.0.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/{A2AAuthService-7UGQ7GMW.mjs → A2AAuthService-UKN53ZGP.mjs} +2 -2
- package/dist/{a2a-BHBLACJV.mjs → a2a-YLKZE5JG.mjs} +7 -5
- package/dist/{a2a-standard-VL5I7B4W.mjs → a2a-standard-MD7WNDTP.mjs} +79 -127
- package/dist/a2a-standard-MD7WNDTP.mjs.map +1 -0
- package/dist/chunk-A7YNAU5L.mjs +377 -0
- package/dist/chunk-A7YNAU5L.mjs.map +1 -0
- package/dist/{chunk-3XIIQ6EK.mjs → chunk-BOPNXTMO.mjs} +66 -5
- package/dist/chunk-BOPNXTMO.mjs.map +1 -0
- package/dist/{chunk-L6MBEEII.mjs → chunk-JGQURU44.mjs} +24 -6
- package/dist/chunk-JGQURU44.mjs.map +1 -0
- package/dist/{chunk-GPHOYR3X.mjs → chunk-LCM4OQTI.mjs} +30 -1
- package/dist/chunk-LCM4OQTI.mjs.map +1 -0
- package/dist/{chunk-HVIKCUOF.mjs → chunk-MFWTGNQR.mjs} +74 -5
- package/dist/chunk-MFWTGNQR.mjs.map +1 -0
- package/dist/chunk-NYYSBNDG.mjs +575 -0
- package/dist/chunk-NYYSBNDG.mjs.map +1 -0
- package/dist/{chunk-W3YH4S6G.mjs → chunk-SIMEG2JT.mjs} +19 -2
- package/dist/chunk-SIMEG2JT.mjs.map +1 -0
- package/dist/chunk-T2HIWZGP.mjs +580 -0
- package/dist/chunk-T2HIWZGP.mjs.map +1 -0
- package/dist/chunk-Y7OVVPVU.mjs +13 -0
- package/dist/chunk-Y7OVVPVU.mjs.map +1 -0
- package/dist/{chunk-GL7RV5L3.mjs → chunk-YR32MWEJ.mjs} +36 -73
- package/dist/chunk-YR32MWEJ.mjs.map +1 -0
- package/dist/embed/{embed-page-AgentDetailSideApp-7YTMN643.js → embed-page-AgentDetailSideApp-6RYNHS5F.js} +1 -1
- package/dist/embed/{embed-page-AgentDetailSideApp-O6G4NJ7I.css → embed-page-AgentDetailSideApp-JMJOOC4V.css} +1 -1
- package/dist/embed/{embed-page-AgentGovernanceWorkbench-SFZNVMUH.css → embed-page-AgentGovernanceWorkbench-3T3ZFJI5.css} +1 -1
- package/dist/embed/embed-page-AgentGovernanceWorkbench-UAPXF3SZ.js +1 -0
- package/dist/embed/{embed-page-LangfuseDashboard-BEOJDMWF.js → embed-page-LangfuseDashboard-ZYGZNW7P.js} +1 -1
- package/dist/embed/{embed-page-MessageGraph-N2DXVMEK.js → embed-page-MessageGraph-S2P3WACC.js} +1 -1
- package/dist/embed/{embed-page-TopologyRuntimeView-CWOXLVFW.css → embed-page-MessageGraph-UDC6GQA5.css} +1 -1
- package/dist/embed/{embed-page-ReactChart-3QDZX2WG.js → embed-page-ReactChart-I3UZVE4Z.js} +1 -1
- package/dist/embed/{embed-page-ReactChart-MXGF35OQ.css → embed-page-ReactChart-URBKYQYE.css} +1 -1
- package/dist/embed/{embed-page-SkillFlow-3X24ILKU.js → embed-page-SkillFlow-JMIJ46FX.js} +1 -1
- package/dist/embed/{embed-page-TasksSideApp-MYIRJWFM.js → embed-page-TasksSideApp-IVFEFLSH.js} +1 -1
- package/dist/embed/{embed-page-TasksSideApp-HV6DKQ26.css → embed-page-TasksSideApp-TTCP4ENP.css} +1 -1
- package/dist/embed/{embed-page-ThreadMaintenancePanel-V327PV5R.js → embed-page-ThreadMaintenancePanel-KQPPAEWJ.js} +1 -1
- package/dist/embed/{embed-page-WorkflowAutomationView-YQFB3CTV.css → embed-page-TopologyRuntimeView-S4AMB4RI.css} +1 -1
- package/dist/embed/{embed-page-TopologyRuntimeView-3O6VJUZR.js → embed-page-TopologyRuntimeView-XCFQ23HF.js} +1 -1
- package/dist/embed/{embed-page-MessageGraph-UT2TCPSO.css → embed-page-WorkflowAutomationView-FWVCQ3YM.css} +1 -1
- package/dist/embed/embed-page-WorkflowAutomationView-UTKCKP75.js +3 -0
- package/dist/embed/embed-page-chunk-5X4MNQAW.js +242 -0
- package/dist/embed/{embed-page-chunk-PMOGSY6W.js → embed-page-chunk-77CQOFKU.js} +1 -1
- package/dist/embed/{embed-page-chunk-PROZXFWS.js → embed-page-chunk-7VDAOX3D.js} +1 -1
- package/dist/embed/{embed-page-chunk-BSRASK7V.js → embed-page-chunk-MD4U4DHC.js} +5 -5
- package/dist/embed/embed-page-chunk-RANB2CUO.js +3 -0
- package/dist/embed/{embed-page-chunk-IELKCYQX.js → embed-page-chunk-RVIS6CKE.js} +1 -1
- package/dist/embed/embed-page-chunk-SEOTZ4Q7.js +6829 -0
- package/dist/embed/{embed-page-chunk-ASEIOK7X.js → embed-page-chunk-TCVPYXPL.js} +2 -2
- package/dist/embed/embed-page-chunk-WHGU76CU.js +211 -0
- package/dist/embed/{embed-page-chunk-WGEXK773.js → embed-page-chunk-ZZFTCBM6.js} +1 -1
- package/dist/embed/embed-page-en-4HSTKY4Q.js +1 -0
- package/dist/embed/{embed-page-en-XJYWUJEL.js → embed-page-en-DNDGCPMA.js} +1 -1
- package/dist/embed/embed-page-en-H5NOZEKE.js +1 -0
- package/dist/embed/embed-page-en-MIVBTEEL.js +1 -0
- package/dist/embed/{embed-page-en-HDSVQ4O6.js → embed-page-en-QJRX2NQE.js} +1 -1
- package/dist/embed/{embed-page-zh-6EBUEFKP.js → embed-page-zh-2H4EB3F3.js} +1 -1
- package/dist/embed/embed-page-zh-4C2K3RH2.js +1 -0
- package/dist/embed/embed-page-zh-7PJNJJZY.js +1 -0
- package/dist/embed/{embed-page-zh-IR652A6J.js → embed-page-zh-HTEHFCSL.js} +1 -1
- package/dist/embed/embed-page-zh-UZ4GPIU7.js +1 -0
- package/dist/embed/embed-page.css +1 -1
- package/dist/embed/embed-page.js +1 -1
- package/dist/embed/mcp-app-page.js +61 -0
- package/dist/index.d.mts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +3574 -2349
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +327 -1049
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-app-shares-SHPBJQXS.mjs +300 -0
- package/dist/mcp-app-shares-SHPBJQXS.mjs.map +1 -0
- package/dist/mcp-apps-QVUK6UBA.mjs +26 -0
- package/dist/{open-7ED27I5B.mjs → open-27ZPLBIW.mjs} +101 -18
- package/dist/open-27ZPLBIW.mjs.map +1 -0
- package/dist/{open-catalog-SZQ435AY.mjs → open-catalog-NVGP6SQP.mjs} +38 -7
- package/dist/open-catalog-NVGP6SQP.mjs.map +1 -0
- package/dist/{open-exposure-I3DN2X4E.mjs → open-exposure-HGYT5VFC.mjs} +8 -9
- package/dist/open-exposure-HGYT5VFC.mjs.map +1 -0
- package/dist/{open-files-V3R2BFTV.mjs → open-files-JPB2NBL6.mjs} +4 -4
- package/dist/{open-session-2Y7XJJW2.mjs → open-session-CLZT3HVG.mjs} +5 -5
- package/dist/open-session-CLZT3HVG.mjs.map +1 -0
- package/dist/openLattice-D5YTSZBY.mjs +28 -0
- package/dist/{registerExposedPlugins-6GCOE64C.mjs → registerExposedPlugins-2JGXSMAL.mjs} +4 -3
- package/dist/{resources-DAU5ZIPB.mjs → resources-YD5DOPGD.mjs} +83 -3
- package/dist/resources-YD5DOPGD.mjs.map +1 -0
- package/dist/{sandboxOpenCredentialProvider-AT227D4N.mjs → sandboxOpenCredentialProvider-RTYOYRCT.mjs} +19 -14
- package/dist/sandboxOpenCredentialProvider-RTYOYRCT.mjs.map +1 -0
- package/package.json +10 -8
- package/dist/a2a-standard-VL5I7B4W.mjs.map +0 -1
- package/dist/chunk-3XIIQ6EK.mjs.map +0 -1
- package/dist/chunk-GL7RV5L3.mjs.map +0 -1
- package/dist/chunk-GPHOYR3X.mjs.map +0 -1
- package/dist/chunk-GXZFO3VU.mjs +0 -42
- package/dist/chunk-GXZFO3VU.mjs.map +0 -1
- package/dist/chunk-HVIKCUOF.mjs.map +0 -1
- package/dist/chunk-HYYLYIMH.mjs +0 -230
- package/dist/chunk-HYYLYIMH.mjs.map +0 -1
- package/dist/chunk-L6MBEEII.mjs.map +0 -1
- package/dist/chunk-W3YH4S6G.mjs.map +0 -1
- package/dist/embed/embed-page-AgentGovernanceWorkbench-YWJ4ZLEV.js +0 -1
- package/dist/embed/embed-page-WorkflowAutomationView-YHOS4WQR.js +0 -3
- package/dist/embed/embed-page-chunk-4XKCMM5C.js +0 -211
- package/dist/embed/embed-page-chunk-IBRMWDHE.js +0 -6835
- package/dist/embed/embed-page-chunk-JTL73EBV.js +0 -3
- package/dist/embed/embed-page-chunk-YMVKQQXJ.js +0 -242
- package/dist/embed/embed-page-en-E35GE7TA.js +0 -1
- package/dist/embed/embed-page-en-GLT2HEZZ.js +0 -1
- package/dist/embed/embed-page-en-JOTELYAL.js +0 -1
- package/dist/embed/embed-page-zh-BPO6ZSJM.js +0 -1
- package/dist/embed/embed-page-zh-XMEJPDMF.js +0 -1
- package/dist/embed/embed-page-zh-ZLK3GLM3.js +0 -1
- package/dist/open-7ED27I5B.mjs.map +0 -1
- package/dist/open-catalog-SZQ435AY.mjs.map +0 -1
- package/dist/open-exposure-I3DN2X4E.mjs.map +0 -1
- package/dist/open-session-2Y7XJJW2.mjs.map +0 -1
- package/dist/openLattice-Q6M5S6CY.mjs +0 -18
- package/dist/openRateLimiter-XEOL3A5G.mjs +0 -8
- package/dist/resources-DAU5ZIPB.mjs.map +0 -1
- package/dist/sandboxOpenCredentialProvider-AT227D4N.mjs.map +0 -1
- /package/dist/{A2AAuthService-7UGQ7GMW.mjs.map → A2AAuthService-UKN53ZGP.mjs.map} +0 -0
- /package/dist/{a2a-BHBLACJV.mjs.map → a2a-YLKZE5JG.mjs.map} +0 -0
- /package/dist/{openLattice-Q6M5S6CY.mjs.map → mcp-apps-QVUK6UBA.mjs.map} +0 -0
- /package/dist/{open-files-V3R2BFTV.mjs.map → open-files-JPB2NBL6.mjs.map} +0 -0
- /package/dist/{openRateLimiter-XEOL3A5G.mjs.map → openLattice-D5YTSZBY.mjs.map} +0 -0
- /package/dist/{registerExposedPlugins-6GCOE64C.mjs.map → registerExposedPlugins-2JGXSMAL.mjs.map} +0 -0
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
|
-
invalidateAgentReflectionCache
|
|
3
|
-
|
|
4
|
-
} from "./chunk-GL7RV5L3.mjs";
|
|
2
|
+
invalidateAgentReflectionCache
|
|
3
|
+
} from "./chunk-YR32MWEJ.mjs";
|
|
5
4
|
import {
|
|
6
5
|
getContentTypeFromFilename,
|
|
7
6
|
getFilenameFromPath,
|
|
8
7
|
sendBufferWithRange
|
|
9
8
|
} from "./chunk-EMYRCJOI.mjs";
|
|
9
|
+
import {
|
|
10
|
+
createRecoveryCallerDeps
|
|
11
|
+
} from "./chunk-NOXGKYUV.mjs";
|
|
12
|
+
import {
|
|
13
|
+
Logger,
|
|
14
|
+
getQrCode,
|
|
15
|
+
getQrCodeStatus
|
|
16
|
+
} from "./chunk-6CUQGDJI.mjs";
|
|
10
17
|
import {
|
|
11
18
|
PathOutsideRootError,
|
|
12
19
|
ProjectFileValidationError,
|
|
@@ -28,9 +35,12 @@ import {
|
|
|
28
35
|
wakeRunTaskQueue
|
|
29
36
|
} from "./chunk-2SR4F3ZD.mjs";
|
|
30
37
|
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
claimDedupKey,
|
|
39
|
+
createRateLimitService,
|
|
40
|
+
getRateLimitService,
|
|
41
|
+
incrementRateCounter,
|
|
42
|
+
setRateLimitService
|
|
43
|
+
} from "./chunk-A7YNAU5L.mjs";
|
|
34
44
|
import {
|
|
35
45
|
buildPreviewTokenScript
|
|
36
46
|
} from "./chunk-7CG57LEF.mjs";
|
|
@@ -40,14 +50,25 @@ import {
|
|
|
40
50
|
} from "./chunk-PWHUWFXL.mjs";
|
|
41
51
|
import {
|
|
42
52
|
A2A_KEY_CHANGED_TOPIC,
|
|
53
|
+
ProjectAccessService,
|
|
54
|
+
ProjectCollaborationError,
|
|
43
55
|
handleA2AKeyChanged,
|
|
44
56
|
publishA2AKeyChanged,
|
|
45
|
-
refreshStoreKeyMap
|
|
46
|
-
|
|
57
|
+
refreshStoreKeyMap,
|
|
58
|
+
setA2AProjectAccess
|
|
59
|
+
} from "./chunk-NYYSBNDG.mjs";
|
|
47
60
|
import {
|
|
48
61
|
A2AAuthService,
|
|
49
62
|
parseEnvKeys
|
|
50
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-LCM4OQTI.mjs";
|
|
64
|
+
import {
|
|
65
|
+
getMcpUiResourceResolver,
|
|
66
|
+
listTenantPlugins,
|
|
67
|
+
registerMcpAppRoutes,
|
|
68
|
+
resolveTenantPluginByType
|
|
69
|
+
} from "./chunk-T2HIWZGP.mjs";
|
|
70
|
+
import "./chunk-XUWD4VKY.mjs";
|
|
71
|
+
import "./chunk-MFWTGNQR.mjs";
|
|
51
72
|
import {
|
|
52
73
|
createOrphanRecoveryRuntime,
|
|
53
74
|
createTaskRunLiveness,
|
|
@@ -59,14 +80,6 @@ import {
|
|
|
59
80
|
resolveTopCaller,
|
|
60
81
|
runOrphanRecovery
|
|
61
82
|
} from "./chunk-NZXKECNN.mjs";
|
|
62
|
-
import {
|
|
63
|
-
createRecoveryCallerDeps
|
|
64
|
-
} from "./chunk-NOXGKYUV.mjs";
|
|
65
|
-
import {
|
|
66
|
-
Logger,
|
|
67
|
-
getQrCode,
|
|
68
|
-
getQrCodeStatus
|
|
69
|
-
} from "./chunk-6CUQGDJI.mjs";
|
|
70
83
|
import "./chunk-NFEGQTCC.mjs";
|
|
71
84
|
|
|
72
85
|
// src/index.ts
|
|
@@ -80,7 +93,7 @@ import staticPlugin from "@fastify/static";
|
|
|
80
93
|
import path4 from "path";
|
|
81
94
|
|
|
82
95
|
// src/routes/index.ts
|
|
83
|
-
import { randomUUID as
|
|
96
|
+
import { randomUUID as randomUUID31 } from "crypto";
|
|
84
97
|
import {
|
|
85
98
|
descriptorDataValue as descriptorDataValue3,
|
|
86
99
|
snapshotExactRecord as snapshotExactRecord14,
|
|
@@ -10003,14 +10016,6 @@ async function importApply(request, reply) {
|
|
|
10003
10016
|
|
|
10004
10017
|
// src/controllers/middleware-types.ts
|
|
10005
10018
|
import { serializePluginMeta } from "@axiom-lattice/core";
|
|
10006
|
-
|
|
10007
|
-
// src/services/plugins/tenantPluginResolver.ts
|
|
10008
|
-
import { listTenantPlugins } from "@axiom-lattice/core";
|
|
10009
|
-
async function resolveTenantPluginByType(tenantId, type) {
|
|
10010
|
-
return (await listTenantPlugins(tenantId)).find((p) => p.meta.type === type);
|
|
10011
|
-
}
|
|
10012
|
-
|
|
10013
|
-
// src/controllers/middleware-types.ts
|
|
10014
10019
|
async function collectMiddlewareMetas(tenantId) {
|
|
10015
10020
|
return (await listTenantPlugins(tenantId)).map(serializePluginMeta);
|
|
10016
10021
|
}
|
|
@@ -10998,8 +11003,9 @@ function createProjectCollaborationInitializer(deps) {
|
|
|
10998
11003
|
};
|
|
10999
11004
|
}
|
|
11000
11005
|
var WorkspaceController = class {
|
|
11001
|
-
constructor(projectCollaboration) {
|
|
11006
|
+
constructor(projectCollaboration, projectAccess) {
|
|
11002
11007
|
this.projectCollaboration = projectCollaboration;
|
|
11008
|
+
this.projectAccess = projectAccess;
|
|
11003
11009
|
this.workspaceStore = getStoreLattice16("default", "workspace").store;
|
|
11004
11010
|
this.projectStore = getStoreLattice16("default", "project").store;
|
|
11005
11011
|
const roomStore = getStoreLattice16("default", "projectRoom").store;
|
|
@@ -11041,6 +11047,48 @@ var WorkspaceController = class {
|
|
|
11041
11047
|
}
|
|
11042
11048
|
return request.headers["x-tenant-id"] || "default";
|
|
11043
11049
|
}
|
|
11050
|
+
requireActor(request, reply) {
|
|
11051
|
+
const user = request.user;
|
|
11052
|
+
if (!user?.id || !user.tenantId) {
|
|
11053
|
+
void reply.status(401).send({
|
|
11054
|
+
success: false,
|
|
11055
|
+
code: "UNAUTHORIZED",
|
|
11056
|
+
error: "Unauthorized"
|
|
11057
|
+
});
|
|
11058
|
+
return null;
|
|
11059
|
+
}
|
|
11060
|
+
return { tenantId: user.tenantId, userId: user.id };
|
|
11061
|
+
}
|
|
11062
|
+
accessService() {
|
|
11063
|
+
if (!this.projectAccess) {
|
|
11064
|
+
throw new Error("Project access service is not configured");
|
|
11065
|
+
}
|
|
11066
|
+
return this.projectAccess;
|
|
11067
|
+
}
|
|
11068
|
+
async requireReadableProject(actor3, workspaceId, projectId, capability2) {
|
|
11069
|
+
try {
|
|
11070
|
+
const result = await this.accessService().requireExistingProjectAccess({
|
|
11071
|
+
tenantId: actor3.tenantId,
|
|
11072
|
+
userId: actor3.userId,
|
|
11073
|
+
projectId,
|
|
11074
|
+
capability: capability2
|
|
11075
|
+
});
|
|
11076
|
+
if (result.project.workspaceId !== workspaceId) return null;
|
|
11077
|
+
return result.project;
|
|
11078
|
+
} catch (error) {
|
|
11079
|
+
if (error instanceof ProjectCollaborationError && (error.code === "PROJECT_ACCESS_DENIED" || error.code === "PROJECT_NOT_FOUND")) {
|
|
11080
|
+
return null;
|
|
11081
|
+
}
|
|
11082
|
+
throw error;
|
|
11083
|
+
}
|
|
11084
|
+
}
|
|
11085
|
+
projectNotFound(reply) {
|
|
11086
|
+
return reply.status(404).send({
|
|
11087
|
+
success: false,
|
|
11088
|
+
code: "PROJECT_NOT_FOUND",
|
|
11089
|
+
error: "Project not found"
|
|
11090
|
+
});
|
|
11091
|
+
}
|
|
11044
11092
|
// ==================== Workspace CRUD ====================
|
|
11045
11093
|
async listWorkspaces(request, reply) {
|
|
11046
11094
|
const tenantId = this.getTenantId(request);
|
|
@@ -11098,14 +11146,18 @@ var WorkspaceController = class {
|
|
|
11098
11146
|
}
|
|
11099
11147
|
// ==================== Project CRUD ====================
|
|
11100
11148
|
async listProjects(request, reply) {
|
|
11101
|
-
const
|
|
11149
|
+
const actor3 = this.requireActor(request, reply);
|
|
11150
|
+
if (!actor3) return;
|
|
11102
11151
|
const { workspaceId } = request.params;
|
|
11103
11152
|
const kindFilter = request.query.kind;
|
|
11104
|
-
await this.ensureTrainingProject(tenantId, workspaceId);
|
|
11105
|
-
await this.publicRoom.ensure(tenantId, workspaceId);
|
|
11106
|
-
const projects =
|
|
11153
|
+
await this.ensureTrainingProject(actor3.tenantId, workspaceId);
|
|
11154
|
+
await this.publicRoom.ensure(actor3.tenantId, workspaceId);
|
|
11155
|
+
const projects = await this.accessService().listReadableProjects({
|
|
11156
|
+
tenantId: actor3.tenantId,
|
|
11157
|
+
userId: actor3.userId,
|
|
11158
|
+
workspaceId,
|
|
11107
11159
|
kind: kindFilter
|
|
11108
|
-
})
|
|
11160
|
+
});
|
|
11109
11161
|
return { success: true, data: projects };
|
|
11110
11162
|
}
|
|
11111
11163
|
/**
|
|
@@ -11130,13 +11182,9 @@ var WorkspaceController = class {
|
|
|
11130
11182
|
});
|
|
11131
11183
|
}
|
|
11132
11184
|
async createProject(request, reply) {
|
|
11133
|
-
const
|
|
11134
|
-
|
|
11135
|
-
const
|
|
11136
|
-
if (user?.tenantId && selectedTenantId && user.tenantId !== selectedTenantId) {
|
|
11137
|
-
return reply.status(403).send({ success: false, code: "TENANT_ACCESS_DENIED", error: "Tenant access denied" });
|
|
11138
|
-
}
|
|
11139
|
-
const tenantId = user?.tenantId ?? selectedTenantId ?? "default";
|
|
11185
|
+
const actor3 = this.requireActor(request, reply);
|
|
11186
|
+
if (!actor3) return;
|
|
11187
|
+
const tenantId = actor3.tenantId;
|
|
11140
11188
|
const { workspaceId } = request.params;
|
|
11141
11189
|
const data = request.body;
|
|
11142
11190
|
if (writesCapabilityBundleIds(data.config)) {
|
|
@@ -11146,9 +11194,9 @@ var WorkspaceController = class {
|
|
|
11146
11194
|
message: CAPABILITY_BUNDLE_CONFIG_MESSAGE
|
|
11147
11195
|
});
|
|
11148
11196
|
}
|
|
11149
|
-
if (
|
|
11197
|
+
if (this.projectCollaboration) {
|
|
11150
11198
|
try {
|
|
11151
|
-
const authorized = await this.projectCollaboration.authorizeCreator({ tenantId, userId:
|
|
11199
|
+
const authorized = await this.projectCollaboration.authorizeCreator({ tenantId, userId: actor3.userId });
|
|
11152
11200
|
if (!authorized) {
|
|
11153
11201
|
return reply.status(403).send({ success: false, code: "TENANT_ACCESS_DENIED", error: "Tenant access denied" });
|
|
11154
11202
|
}
|
|
@@ -11159,7 +11207,7 @@ var WorkspaceController = class {
|
|
|
11159
11207
|
console.error({
|
|
11160
11208
|
event: "project:collaboration-preflight-failed",
|
|
11161
11209
|
tenantId,
|
|
11162
|
-
userId:
|
|
11210
|
+
userId: actor3.userId,
|
|
11163
11211
|
errorName: error instanceof Error ? error.name : "UnknownError"
|
|
11164
11212
|
});
|
|
11165
11213
|
return reply.status(500).send({
|
|
@@ -11177,42 +11225,72 @@ var WorkspaceController = class {
|
|
|
11177
11225
|
id3,
|
|
11178
11226
|
data
|
|
11179
11227
|
);
|
|
11180
|
-
if (
|
|
11228
|
+
if (this.projectCollaboration) {
|
|
11181
11229
|
try {
|
|
11182
|
-
await this.projectCollaboration.initialize({ tenantId, userId:
|
|
11230
|
+
await this.projectCollaboration.initialize({ tenantId, userId: actor3.userId, project });
|
|
11183
11231
|
} catch (error) {
|
|
11184
|
-
const phase = error instanceof ProjectCollaborationInitializationError ? error.phase :
|
|
11232
|
+
const phase = error instanceof ProjectCollaborationInitializationError ? error.phase : void 0;
|
|
11233
|
+
let rolledBack = false;
|
|
11234
|
+
if (phase === "owner") {
|
|
11235
|
+
try {
|
|
11236
|
+
rolledBack = await this.projectStore.deleteProject(tenantId, project.id);
|
|
11237
|
+
if (!rolledBack) {
|
|
11238
|
+
console.error({
|
|
11239
|
+
event: "project:owner-initialization-rollback-missed",
|
|
11240
|
+
tenantId,
|
|
11241
|
+
projectId: project.id
|
|
11242
|
+
});
|
|
11243
|
+
}
|
|
11244
|
+
} catch (cleanupError) {
|
|
11245
|
+
console.error({
|
|
11246
|
+
event: "project:owner-initialization-rollback-failed",
|
|
11247
|
+
tenantId,
|
|
11248
|
+
projectId: project.id,
|
|
11249
|
+
errorName: cleanupError instanceof Error ? cleanupError.name : "UnknownError"
|
|
11250
|
+
});
|
|
11251
|
+
}
|
|
11252
|
+
}
|
|
11185
11253
|
console.error({
|
|
11186
11254
|
event: "project:collaboration-initialization-failed",
|
|
11187
11255
|
phase,
|
|
11188
11256
|
tenantId,
|
|
11189
11257
|
projectId: project.id,
|
|
11190
|
-
userId:
|
|
11258
|
+
userId: actor3.userId,
|
|
11191
11259
|
errorName: error instanceof Error ? error.name : "UnknownError"
|
|
11192
11260
|
});
|
|
11193
11261
|
return reply.status(500).send({
|
|
11194
11262
|
success: false,
|
|
11195
11263
|
error: "Internal server error",
|
|
11196
|
-
code: phase === "owner" ? "PROJECT_OWNER_INITIALIZATION_FAILED" : "PROJECT_ROOM_INITIALIZATION_FAILED",
|
|
11264
|
+
code: phase === "owner" ? "PROJECT_OWNER_INITIALIZATION_FAILED" : phase === "room" ? "PROJECT_ROOM_INITIALIZATION_FAILED" : "PROJECT_COLLABORATION_INITIALIZATION_FAILED",
|
|
11197
11265
|
projectId: project.id,
|
|
11198
|
-
retryable: phase === "room"
|
|
11266
|
+
retryable: phase === "room" || rolledBack
|
|
11199
11267
|
});
|
|
11200
11268
|
}
|
|
11201
11269
|
}
|
|
11202
11270
|
return reply.status(201).send({ success: true, data: project });
|
|
11203
11271
|
}
|
|
11204
11272
|
async getProject(request, reply) {
|
|
11205
|
-
const
|
|
11206
|
-
|
|
11207
|
-
const project = await this.
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11273
|
+
const actor3 = this.requireActor(request, reply);
|
|
11274
|
+
if (!actor3) return;
|
|
11275
|
+
const project = await this.requireReadableProject(
|
|
11276
|
+
actor3,
|
|
11277
|
+
request.params.workspaceId,
|
|
11278
|
+
request.params.projectId,
|
|
11279
|
+
"read"
|
|
11280
|
+
);
|
|
11281
|
+
if (!project) return this.projectNotFound(reply);
|
|
11211
11282
|
return { success: true, data: project };
|
|
11212
11283
|
}
|
|
11213
11284
|
async updateProject(request, reply) {
|
|
11214
|
-
const
|
|
11215
|
-
|
|
11285
|
+
const actor3 = this.requireActor(request, reply);
|
|
11286
|
+
if (!actor3) return;
|
|
11287
|
+
const project = await this.requireReadableProject(
|
|
11288
|
+
actor3,
|
|
11289
|
+
request.params.workspaceId,
|
|
11290
|
+
request.params.projectId,
|
|
11291
|
+
"manage"
|
|
11292
|
+
);
|
|
11293
|
+
if (!project) return this.projectNotFound(reply);
|
|
11216
11294
|
const updates = request.body;
|
|
11217
11295
|
if (writesCapabilityBundleIds(updates.config)) {
|
|
11218
11296
|
return reply.status(400).send({
|
|
@@ -11221,36 +11299,35 @@ var WorkspaceController = class {
|
|
|
11221
11299
|
message: CAPABILITY_BUNDLE_CONFIG_MESSAGE
|
|
11222
11300
|
});
|
|
11223
11301
|
}
|
|
11224
|
-
if (updates.kind !== void 0) {
|
|
11225
|
-
|
|
11226
|
-
|
|
11227
|
-
|
|
11228
|
-
|
|
11229
|
-
error: "The workspace public room classification cannot be changed"
|
|
11230
|
-
});
|
|
11231
|
-
}
|
|
11302
|
+
if (project.id === workspacePublicRoomProjectId(actor3.tenantId, project.workspaceId) && (updates.kind !== void 0 || updates.name !== void 0)) {
|
|
11303
|
+
return reply.status(409).send({
|
|
11304
|
+
success: false,
|
|
11305
|
+
error: "The workspace public room cannot be renamed or reclassified"
|
|
11306
|
+
});
|
|
11232
11307
|
}
|
|
11233
|
-
const
|
|
11234
|
-
tenantId,
|
|
11235
|
-
|
|
11308
|
+
const updated = await this.projectStore.updateProject(
|
|
11309
|
+
actor3.tenantId,
|
|
11310
|
+
project.id,
|
|
11236
11311
|
updates
|
|
11237
11312
|
);
|
|
11238
|
-
if (!
|
|
11239
|
-
|
|
11240
|
-
}
|
|
11241
|
-
return { success: true, data: project };
|
|
11313
|
+
if (!updated) return this.projectNotFound(reply);
|
|
11314
|
+
return { success: true, data: updated };
|
|
11242
11315
|
}
|
|
11243
11316
|
async deleteProject(request, reply) {
|
|
11244
|
-
const
|
|
11245
|
-
|
|
11246
|
-
const project = await this.
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11317
|
+
const actor3 = this.requireActor(request, reply);
|
|
11318
|
+
if (!actor3) return;
|
|
11319
|
+
const project = await this.requireReadableProject(
|
|
11320
|
+
actor3,
|
|
11321
|
+
request.params.workspaceId,
|
|
11322
|
+
request.params.projectId,
|
|
11323
|
+
"manage"
|
|
11324
|
+
);
|
|
11325
|
+
if (!project) return this.projectNotFound(reply);
|
|
11326
|
+
const { workspaceId } = request.params;
|
|
11250
11327
|
if (project.kind === "training") {
|
|
11251
11328
|
const training = await this.projectStore.getProjectsByWorkspace(
|
|
11252
|
-
tenantId,
|
|
11253
|
-
workspaceId,
|
|
11329
|
+
actor3.tenantId,
|
|
11330
|
+
project.workspaceId,
|
|
11254
11331
|
{ kind: "training" }
|
|
11255
11332
|
);
|
|
11256
11333
|
if (training.length <= 1) {
|
|
@@ -11260,16 +11337,14 @@ var WorkspaceController = class {
|
|
|
11260
11337
|
});
|
|
11261
11338
|
}
|
|
11262
11339
|
}
|
|
11263
|
-
if (project.id === workspacePublicRoomProjectId(tenantId, project.workspaceId ?? workspaceId)) {
|
|
11340
|
+
if (project.id === workspacePublicRoomProjectId(actor3.tenantId, project.workspaceId ?? workspaceId)) {
|
|
11264
11341
|
return reply.status(409).send({
|
|
11265
11342
|
success: false,
|
|
11266
11343
|
error: "The workspace public room cannot be deleted"
|
|
11267
11344
|
});
|
|
11268
11345
|
}
|
|
11269
|
-
const deleted = await this.projectStore.deleteProject(tenantId,
|
|
11270
|
-
if (!deleted)
|
|
11271
|
-
return reply.status(404).send({ success: false, error: "Project not found" });
|
|
11272
|
-
}
|
|
11346
|
+
const deleted = await this.projectStore.deleteProject(actor3.tenantId, project.id);
|
|
11347
|
+
if (!deleted) return this.projectNotFound(reply);
|
|
11273
11348
|
return { success: true };
|
|
11274
11349
|
}
|
|
11275
11350
|
// ==================== File Operations ====================
|
|
@@ -11907,8 +11982,8 @@ var WorkspaceController = class {
|
|
|
11907
11982
|
}
|
|
11908
11983
|
}
|
|
11909
11984
|
};
|
|
11910
|
-
function registerWorkspaceRoutes(app2, projectCollaboration) {
|
|
11911
|
-
const controller = new WorkspaceController(projectCollaboration);
|
|
11985
|
+
function registerWorkspaceRoutes(app2, projectCollaboration, projectAccess) {
|
|
11986
|
+
const controller = new WorkspaceController(projectCollaboration, projectAccess);
|
|
11912
11987
|
app2.get("/api/workspaces", controller.listWorkspaces.bind(controller));
|
|
11913
11988
|
app2.post("/api/workspaces", controller.createWorkspace.bind(controller));
|
|
11914
11989
|
app2.get(
|
|
@@ -11975,250 +12050,12 @@ function registerWorkspaceRoutes(app2, projectCollaboration) {
|
|
|
11975
12050
|
return controller;
|
|
11976
12051
|
}
|
|
11977
12052
|
|
|
11978
|
-
// src/services/collaboration/ProjectAccessService.ts
|
|
11979
|
-
import { randomUUID as randomUUID14 } from "crypto";
|
|
11980
|
-
var ProjectCollaborationError = class extends Error {
|
|
11981
|
-
/** Creates a project collaboration error. */
|
|
11982
|
-
constructor(code, statusCode, message) {
|
|
11983
|
-
super(message);
|
|
11984
|
-
this.code = code;
|
|
11985
|
-
this.statusCode = statusCode;
|
|
11986
|
-
this.name = "ProjectCollaborationError";
|
|
11987
|
-
}
|
|
11988
|
-
};
|
|
11989
|
-
var allowedRoles = {
|
|
11990
|
-
read: /* @__PURE__ */ new Set(["owner", "admin", "member", "viewer"]),
|
|
11991
|
-
send: /* @__PURE__ */ new Set(["owner", "admin", "member"]),
|
|
11992
|
-
manage: /* @__PURE__ */ new Set(["owner", "admin"])
|
|
11993
|
-
};
|
|
11994
|
-
var membershipConflictNames = /* @__PURE__ */ new Set([
|
|
11995
|
-
"DuplicateProjectMembershipError",
|
|
11996
|
-
"ProjectMembershipIdConflictError"
|
|
11997
|
-
]);
|
|
11998
|
-
function isProjectMembershipConflict(error) {
|
|
11999
|
-
return error instanceof Error && membershipConflictNames.has(error.name);
|
|
12000
|
-
}
|
|
12001
|
-
var ProjectAccessService = class {
|
|
12002
|
-
/** Creates a project access service from explicitly injected stores. */
|
|
12003
|
-
constructor(deps) {
|
|
12004
|
-
this.deps = deps;
|
|
12005
|
-
this.idFactory = deps.idFactory ?? randomUUID14;
|
|
12006
|
-
}
|
|
12007
|
-
/** Returns the project and active membership when the user has the requested capability. */
|
|
12008
|
-
async requireProjectAccess(input) {
|
|
12009
|
-
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
12010
|
-
if (!project) {
|
|
12011
|
-
throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
12012
|
-
}
|
|
12013
|
-
if (project.kind === "public") {
|
|
12014
|
-
return this.requirePublicProjectAccess(project, input);
|
|
12015
|
-
}
|
|
12016
|
-
const membership = await this.deps.membershipStore.findByUser(
|
|
12017
|
-
input.tenantId,
|
|
12018
|
-
input.projectId,
|
|
12019
|
-
input.userId
|
|
12020
|
-
);
|
|
12021
|
-
if (project.kind === "personal") {
|
|
12022
|
-
if (!this.isActiveMembership(membership, input)) this.accessDenied();
|
|
12023
|
-
this.requireCapability(membership, input.capability);
|
|
12024
|
-
return { project, membership };
|
|
12025
|
-
}
|
|
12026
|
-
if (this.isActiveMembership(membership, input) && this.hasCapability(membership, input.capability)) {
|
|
12027
|
-
return { project, membership };
|
|
12028
|
-
}
|
|
12029
|
-
const tenantAdmin = await this.tenantAdminMembership(project, input);
|
|
12030
|
-
if (this.isActiveMembership(membership, input)) {
|
|
12031
|
-
if (tenantAdmin) return { project, membership: tenantAdmin };
|
|
12032
|
-
this.requireCapability(membership, input.capability);
|
|
12033
|
-
}
|
|
12034
|
-
const memberships = await this.deps.membershipStore.list(input.tenantId, input.projectId);
|
|
12035
|
-
if (memberships.length !== 0) {
|
|
12036
|
-
if (tenantAdmin) return { project, membership: tenantAdmin };
|
|
12037
|
-
this.accessDenied();
|
|
12038
|
-
}
|
|
12039
|
-
if (!tenantAdmin) this.accessDenied();
|
|
12040
|
-
let claim;
|
|
12041
|
-
try {
|
|
12042
|
-
claim = await this.deps.membershipStore.createInitialOwner({
|
|
12043
|
-
id: this.idFactory(),
|
|
12044
|
-
tenantId: input.tenantId,
|
|
12045
|
-
projectId: input.projectId,
|
|
12046
|
-
userId: input.userId
|
|
12047
|
-
});
|
|
12048
|
-
} catch (error) {
|
|
12049
|
-
if (isProjectMembershipConflict(error)) {
|
|
12050
|
-
throw new ProjectCollaborationError(
|
|
12051
|
-
"PROJECT_MEMBERSHIP_CONFLICT",
|
|
12052
|
-
409,
|
|
12053
|
-
"Project membership could not be initialized"
|
|
12054
|
-
);
|
|
12055
|
-
}
|
|
12056
|
-
throw error;
|
|
12057
|
-
}
|
|
12058
|
-
if (claim.kind === "created" || claim.kind === "existing") {
|
|
12059
|
-
return { project, membership: claim.membership };
|
|
12060
|
-
}
|
|
12061
|
-
const racedMembership = await this.deps.membershipStore.findByUser(
|
|
12062
|
-
input.tenantId,
|
|
12063
|
-
input.projectId,
|
|
12064
|
-
input.userId
|
|
12065
|
-
);
|
|
12066
|
-
if (racedMembership?.status !== "active") this.accessDenied();
|
|
12067
|
-
this.requireCapability(racedMembership, input.capability);
|
|
12068
|
-
return { project, membership: racedMembership };
|
|
12069
|
-
}
|
|
12070
|
-
/** Authorizes an already-existing membership, or any tenant member for public rooms; never mutates persistence. */
|
|
12071
|
-
async requireExistingProjectAccess(input) {
|
|
12072
|
-
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
12073
|
-
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
12074
|
-
if (project.kind === "public") {
|
|
12075
|
-
return this.requireExistingPublicProjectAccess(project, input);
|
|
12076
|
-
}
|
|
12077
|
-
const membership = await this.deps.membershipStore.findByUser(
|
|
12078
|
-
input.tenantId,
|
|
12079
|
-
input.projectId,
|
|
12080
|
-
input.userId
|
|
12081
|
-
);
|
|
12082
|
-
const activeMembership = this.isActiveMembership(membership, input) ? membership : void 0;
|
|
12083
|
-
if (project.kind === "personal") {
|
|
12084
|
-
if (!activeMembership) this.accessDenied();
|
|
12085
|
-
this.requireCapability(activeMembership, input.capability);
|
|
12086
|
-
return { project, membership: activeMembership };
|
|
12087
|
-
}
|
|
12088
|
-
if (activeMembership && this.hasCapability(activeMembership, input.capability)) {
|
|
12089
|
-
return { project, membership: activeMembership };
|
|
12090
|
-
}
|
|
12091
|
-
const tenantAdmin = await this.tenantAdminMembership(project, input);
|
|
12092
|
-
if (tenantAdmin) return { project, membership: tenantAdmin };
|
|
12093
|
-
if (activeMembership) this.requireCapability(activeMembership, input.capability);
|
|
12094
|
-
this.accessDenied();
|
|
12095
|
-
}
|
|
12096
|
-
/**
|
|
12097
|
-
* Authorizes roster visibility for any active participant (owner/admin/member/viewer).
|
|
12098
|
-
* Mutating the roster requires `manage` separately; reading it never does, because every
|
|
12099
|
-
* room participant needs the member list to render the room and derive their own capabilities.
|
|
12100
|
-
*/
|
|
12101
|
-
async requireRosterAccess(input) {
|
|
12102
|
-
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
12103
|
-
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
12104
|
-
return this.requireProjectAccess({
|
|
12105
|
-
...input,
|
|
12106
|
-
capability: "read"
|
|
12107
|
-
});
|
|
12108
|
-
}
|
|
12109
|
-
async requirePublicProjectAccess(project, input) {
|
|
12110
|
-
const membership = await this.deps.membershipStore.findByUser(
|
|
12111
|
-
input.tenantId,
|
|
12112
|
-
input.projectId,
|
|
12113
|
-
input.userId
|
|
12114
|
-
);
|
|
12115
|
-
if (membership?.status === "active") {
|
|
12116
|
-
if (this.hasCapability(membership, input.capability)) return { project, membership };
|
|
12117
|
-
const tenantAdmin = await this.tenantAdminMembership(project, input);
|
|
12118
|
-
if (tenantAdmin) return { project, membership: tenantAdmin };
|
|
12119
|
-
this.requireCapability(membership, input.capability);
|
|
12120
|
-
return { project, membership };
|
|
12121
|
-
}
|
|
12122
|
-
const materialized = await this.materializePublicMembership(input);
|
|
12123
|
-
this.requireCapability(materialized, input.capability);
|
|
12124
|
-
return { project, membership: materialized };
|
|
12125
|
-
}
|
|
12126
|
-
async requireExistingPublicProjectAccess(project, input) {
|
|
12127
|
-
const membership = await this.deps.membershipStore.findByUser(
|
|
12128
|
-
input.tenantId,
|
|
12129
|
-
input.projectId,
|
|
12130
|
-
input.userId
|
|
12131
|
-
);
|
|
12132
|
-
if (membership?.status === "active") {
|
|
12133
|
-
if (this.hasCapability(membership, input.capability)) return { project, membership };
|
|
12134
|
-
const tenantAdmin = await this.tenantAdminMembership(project, input);
|
|
12135
|
-
if (tenantAdmin) return { project, membership: tenantAdmin };
|
|
12136
|
-
this.requireCapability(membership, input.capability);
|
|
12137
|
-
return { project, membership };
|
|
12138
|
-
}
|
|
12139
|
-
if (membership) this.accessDenied();
|
|
12140
|
-
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
12141
|
-
if (!tenantLink) this.accessDenied();
|
|
12142
|
-
const role = tenantLink.role === "owner" || tenantLink.role === "admin" ? "admin" : "member";
|
|
12143
|
-
const synthetic = {
|
|
12144
|
-
id: `public:${input.userId}`,
|
|
12145
|
-
tenantId: input.tenantId,
|
|
12146
|
-
projectId: input.projectId,
|
|
12147
|
-
userId: input.userId,
|
|
12148
|
-
role,
|
|
12149
|
-
status: "active",
|
|
12150
|
-
joinedAt: project.createdAt,
|
|
12151
|
-
updatedAt: project.updatedAt
|
|
12152
|
-
};
|
|
12153
|
-
this.requireCapability(synthetic, input.capability);
|
|
12154
|
-
return { project, membership: synthetic };
|
|
12155
|
-
}
|
|
12156
|
-
async materializePublicMembership(input) {
|
|
12157
|
-
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
12158
|
-
if (!tenantLink) this.accessDenied();
|
|
12159
|
-
const existing = await this.deps.membershipStore.findByUser(
|
|
12160
|
-
input.tenantId,
|
|
12161
|
-
input.projectId,
|
|
12162
|
-
input.userId
|
|
12163
|
-
);
|
|
12164
|
-
if (existing) this.accessDenied();
|
|
12165
|
-
const role = tenantLink.role === "owner" || tenantLink.role === "admin" ? "admin" : "member";
|
|
12166
|
-
try {
|
|
12167
|
-
return await this.deps.membershipStore.create({
|
|
12168
|
-
id: this.idFactory(),
|
|
12169
|
-
tenantId: input.tenantId,
|
|
12170
|
-
projectId: input.projectId,
|
|
12171
|
-
userId: input.userId,
|
|
12172
|
-
role,
|
|
12173
|
-
status: "active"
|
|
12174
|
-
});
|
|
12175
|
-
} catch (error) {
|
|
12176
|
-
if (isProjectMembershipConflict(error)) {
|
|
12177
|
-
const raced = await this.deps.membershipStore.findByUser(
|
|
12178
|
-
input.tenantId,
|
|
12179
|
-
input.projectId,
|
|
12180
|
-
input.userId
|
|
12181
|
-
);
|
|
12182
|
-
if (raced?.status === "active") return raced;
|
|
12183
|
-
}
|
|
12184
|
-
throw error;
|
|
12185
|
-
}
|
|
12186
|
-
}
|
|
12187
|
-
hasCapability(membership, capability2) {
|
|
12188
|
-
return allowedRoles[capability2].has(membership.role);
|
|
12189
|
-
}
|
|
12190
|
-
requireCapability(membership, capability2) {
|
|
12191
|
-
if (!this.hasCapability(membership, capability2)) this.accessDenied();
|
|
12192
|
-
}
|
|
12193
|
-
async tenantAdminMembership(project, input) {
|
|
12194
|
-
if (project.kind === "personal") return void 0;
|
|
12195
|
-
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
12196
|
-
if (tenantLink?.role !== "owner" && tenantLink?.role !== "admin") return void 0;
|
|
12197
|
-
return {
|
|
12198
|
-
id: `tenant-admin:${input.userId}`,
|
|
12199
|
-
tenantId: input.tenantId,
|
|
12200
|
-
projectId: project.id,
|
|
12201
|
-
userId: input.userId,
|
|
12202
|
-
role: "admin",
|
|
12203
|
-
status: "active",
|
|
12204
|
-
joinedAt: project.createdAt,
|
|
12205
|
-
updatedAt: project.updatedAt
|
|
12206
|
-
};
|
|
12207
|
-
}
|
|
12208
|
-
isActiveMembership(membership, input) {
|
|
12209
|
-
return membership != null && membership.tenantId === input.tenantId && membership.projectId === input.projectId && membership.userId === input.userId && membership.status === "active";
|
|
12210
|
-
}
|
|
12211
|
-
accessDenied() {
|
|
12212
|
-
throw new ProjectCollaborationError("PROJECT_ACCESS_DENIED", 403, "Project access denied");
|
|
12213
|
-
}
|
|
12214
|
-
};
|
|
12215
|
-
|
|
12216
12053
|
// src/controllers/database-configs.ts
|
|
12217
12054
|
import {
|
|
12218
12055
|
getStoreLattice as getStoreLattice17,
|
|
12219
12056
|
sqlDatabaseManager
|
|
12220
12057
|
} from "@axiom-lattice/core";
|
|
12221
|
-
import { randomUUID as
|
|
12058
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
12222
12059
|
function getTenantId16(request) {
|
|
12223
12060
|
const userTenantId = request.user?.tenantId;
|
|
12224
12061
|
if (userTenantId) {
|
|
@@ -12296,7 +12133,7 @@ async function createDatabaseConfig(request, reply) {
|
|
|
12296
12133
|
message: "Database configuration with this key already exists"
|
|
12297
12134
|
};
|
|
12298
12135
|
}
|
|
12299
|
-
const id3 = body.id ||
|
|
12136
|
+
const id3 = body.id || randomUUID14();
|
|
12300
12137
|
const config = await store2.createConfig(tenantId, id3, body);
|
|
12301
12138
|
try {
|
|
12302
12139
|
sqlDatabaseManager.registerDatabase(tenantId, config.key, config.config);
|
|
@@ -12501,7 +12338,7 @@ import {
|
|
|
12501
12338
|
metricsServerManager as metricsServerManager2,
|
|
12502
12339
|
SemanticMetricsClient as SemanticMetricsClient2
|
|
12503
12340
|
} from "@axiom-lattice/core";
|
|
12504
|
-
import { randomUUID as
|
|
12341
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
12505
12342
|
function getTenantId17(request) {
|
|
12506
12343
|
const userTenantId = request.user?.tenantId;
|
|
12507
12344
|
if (userTenantId) {
|
|
@@ -12582,7 +12419,7 @@ async function createMetricsServerConfig(request, reply) {
|
|
|
12582
12419
|
message: "selectedDataSources is required for semantic metrics servers"
|
|
12583
12420
|
};
|
|
12584
12421
|
}
|
|
12585
|
-
const id3 = body.id ||
|
|
12422
|
+
const id3 = body.id || randomUUID15();
|
|
12586
12423
|
const configData = {
|
|
12587
12424
|
key: body.key,
|
|
12588
12425
|
name: body.name,
|
|
@@ -13245,7 +13082,7 @@ import {
|
|
|
13245
13082
|
McpLatticeManager,
|
|
13246
13083
|
convertToConnection
|
|
13247
13084
|
} from "@axiom-lattice/core";
|
|
13248
|
-
import { randomUUID as
|
|
13085
|
+
import { randomUUID as randomUUID16 } from "crypto";
|
|
13249
13086
|
|
|
13250
13087
|
// src/services/mcpConfigSync.ts
|
|
13251
13088
|
var MCP_CONFIG_CHANGED_TOPIC = "mcp-config-changed";
|
|
@@ -13364,7 +13201,7 @@ async function createMcpServerConfig(request, reply) {
|
|
|
13364
13201
|
message: "MCP server configuration with this key already exists"
|
|
13365
13202
|
};
|
|
13366
13203
|
}
|
|
13367
|
-
const id3 = body.id ||
|
|
13204
|
+
const id3 = body.id || randomUUID16();
|
|
13368
13205
|
const config = await store2.createConfig(tenantId, id3, body);
|
|
13369
13206
|
try {
|
|
13370
13207
|
await connectAndRegisterTools(config);
|
|
@@ -13726,562 +13563,6 @@ function registerMcpServerConfigRoutes(app2) {
|
|
|
13726
13563
|
app2.post("/api/mcp-servers/test-tools", testMcpServerTools);
|
|
13727
13564
|
}
|
|
13728
13565
|
|
|
13729
|
-
// src/routes/mcp-apps.ts
|
|
13730
|
-
import {
|
|
13731
|
-
parseMcpUiRef
|
|
13732
|
-
} from "@axiom-lattice/protocols";
|
|
13733
|
-
import {
|
|
13734
|
-
getSandboxPluginCatalog as getSandboxPluginCatalog2,
|
|
13735
|
-
mcpManager as mcpManager2,
|
|
13736
|
-
resolvePluginConnections,
|
|
13737
|
-
verifyMcpUiScope
|
|
13738
|
-
} from "@axiom-lattice/core";
|
|
13739
|
-
|
|
13740
|
-
// src/services/mcp-ui/UiResourceResolver.ts
|
|
13741
|
-
import { createHash as createHash3 } from "crypto";
|
|
13742
|
-
var DEFAULT_TTL_MS = 5 * 60 * 1e3;
|
|
13743
|
-
function publicFieldsOf(payload) {
|
|
13744
|
-
return {
|
|
13745
|
-
mimeType: payload.mimeType,
|
|
13746
|
-
html: payload.html,
|
|
13747
|
-
...payload.csp !== void 0 ? { csp: payload.csp } : {},
|
|
13748
|
-
...payload.permissions !== void 0 ? { permissions: payload.permissions } : {},
|
|
13749
|
-
...payload.prefersBorder !== void 0 ? { prefersBorder: payload.prefersBorder } : {}
|
|
13750
|
-
};
|
|
13751
|
-
}
|
|
13752
|
-
var UiResourceResolver = class {
|
|
13753
|
-
constructor(deps) {
|
|
13754
|
-
this.deps = deps;
|
|
13755
|
-
this.inFlight = /* @__PURE__ */ new Map();
|
|
13756
|
-
}
|
|
13757
|
-
keyOf(ref) {
|
|
13758
|
-
return ref.kind === "mcp" ? `mcp\0${ref.serverKey}\0${ref.resourceUri}` : `plugin\0${ref.pluginType}\0${ref.resource}`;
|
|
13759
|
-
}
|
|
13760
|
-
fullKey(tenantId, ref) {
|
|
13761
|
-
return `${tenantId}\0${this.keyOf(ref)}`;
|
|
13762
|
-
}
|
|
13763
|
-
/**
|
|
13764
|
-
* Resolve a UI resource for a tenant.
|
|
13765
|
-
*
|
|
13766
|
-
* @param tenantId Tenant scope.
|
|
13767
|
-
* @param ref The fence ref.
|
|
13768
|
-
* @returns Public UI resource payload (no cache metadata).
|
|
13769
|
-
*/
|
|
13770
|
-
async resolve(tenantId, ref) {
|
|
13771
|
-
const key = this.fullKey(tenantId, ref);
|
|
13772
|
-
const ttl = this.deps.ttlMs ?? DEFAULT_TTL_MS;
|
|
13773
|
-
const cached = await this.deps.store.get(key);
|
|
13774
|
-
if (cached && Date.now() - cached.fetchedAt < ttl) return publicFieldsOf(cached);
|
|
13775
|
-
const existing = this.inFlight.get(key);
|
|
13776
|
-
if (existing) return existing;
|
|
13777
|
-
const promise = this.fetchAndCache(tenantId, ref, key, cached);
|
|
13778
|
-
this.inFlight.set(key, promise);
|
|
13779
|
-
try {
|
|
13780
|
-
return await promise;
|
|
13781
|
-
} finally {
|
|
13782
|
-
this.inFlight.delete(key);
|
|
13783
|
-
}
|
|
13784
|
-
}
|
|
13785
|
-
/**
|
|
13786
|
-
* Evict the cached entry for a tenant/ref.
|
|
13787
|
-
*
|
|
13788
|
-
* @param tenantId Tenant scope.
|
|
13789
|
-
* @param ref The fence ref.
|
|
13790
|
-
*/
|
|
13791
|
-
async invalidate(tenantId, ref) {
|
|
13792
|
-
await this.deps.store.delete(this.fullKey(tenantId, ref));
|
|
13793
|
-
}
|
|
13794
|
-
/**
|
|
13795
|
-
* Evict every cached plugin UI resource for a tenant.
|
|
13796
|
-
*
|
|
13797
|
-
* @param tenantId Tenant whose plugin UI resources to drop.
|
|
13798
|
-
* @remarks Called when a tenant's plugin catalog changes so an edited
|
|
13799
|
-
* `ui/*.html` is re-fetched instead of being served from the TTL cache
|
|
13800
|
-
* (which is keyed by ref identity, not content).
|
|
13801
|
-
*/
|
|
13802
|
-
async invalidateTenantPlugins(tenantId) {
|
|
13803
|
-
await this.deps.store.deleteByPrefix(`${tenantId}\0plugin\0`);
|
|
13804
|
-
}
|
|
13805
|
-
async fetchAndCache(tenantId, ref, key, cached) {
|
|
13806
|
-
try {
|
|
13807
|
-
const fresh = ref.kind === "mcp" ? await this.deps.fetchMcp(tenantId, ref.serverKey, ref.resourceUri) : await this.deps.fetchPlugin(tenantId, ref.pluginType, ref.resource);
|
|
13808
|
-
const entry = {
|
|
13809
|
-
...publicFieldsOf(fresh),
|
|
13810
|
-
hash: createHash3("sha256").update(fresh.html).digest("hex"),
|
|
13811
|
-
fetchedAt: Date.now()
|
|
13812
|
-
};
|
|
13813
|
-
await this.deps.store.set(key, entry);
|
|
13814
|
-
return publicFieldsOf(fresh);
|
|
13815
|
-
} catch (error) {
|
|
13816
|
-
if (cached) return { ...publicFieldsOf(cached), stale: true };
|
|
13817
|
-
throw error;
|
|
13818
|
-
}
|
|
13819
|
-
}
|
|
13820
|
-
};
|
|
13821
|
-
|
|
13822
|
-
// src/services/mcp-ui/McpUiResourceCacheStore.ts
|
|
13823
|
-
var InMemoryMcpUiResourceCacheStore = class {
|
|
13824
|
-
constructor() {
|
|
13825
|
-
this.map = /* @__PURE__ */ new Map();
|
|
13826
|
-
}
|
|
13827
|
-
async get(key) {
|
|
13828
|
-
return this.map.get(key);
|
|
13829
|
-
}
|
|
13830
|
-
async set(key, entry) {
|
|
13831
|
-
this.map.set(key, entry);
|
|
13832
|
-
}
|
|
13833
|
-
async delete(key) {
|
|
13834
|
-
this.map.delete(key);
|
|
13835
|
-
}
|
|
13836
|
-
async deleteByPrefix(prefix) {
|
|
13837
|
-
for (const key of this.map.keys()) {
|
|
13838
|
-
if (key.startsWith(prefix)) this.map.delete(key);
|
|
13839
|
-
}
|
|
13840
|
-
}
|
|
13841
|
-
};
|
|
13842
|
-
|
|
13843
|
-
// src/services/mcp-ui/buildCsp.ts
|
|
13844
|
-
var DEFAULT_CSP = [
|
|
13845
|
-
"default-src 'none'",
|
|
13846
|
-
"script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval'",
|
|
13847
|
-
"style-src 'self' 'unsafe-inline'",
|
|
13848
|
-
"img-src 'self' data:",
|
|
13849
|
-
"media-src 'self' data:",
|
|
13850
|
-
// Fonts are restricted to the document origin; declared `resourceDomains`
|
|
13851
|
-
// are the only origins ever added (no `data:` — a base64-embedded font must
|
|
13852
|
-
// be served from a declared origin).
|
|
13853
|
-
"font-src 'self'",
|
|
13854
|
-
"object-src 'none'",
|
|
13855
|
-
"connect-src 'none'",
|
|
13856
|
-
"frame-src 'none'",
|
|
13857
|
-
"base-uri 'self'"
|
|
13858
|
-
].join("; ");
|
|
13859
|
-
var ORIGIN_PATTERN = /^(https?|wss?):\/\/(\*\.)?[^\s;,'"*]+$/;
|
|
13860
|
-
function declaredOrigins(domains) {
|
|
13861
|
-
if (!Array.isArray(domains)) return [];
|
|
13862
|
-
return domains.filter((domain) => typeof domain === "string" && ORIGIN_PATTERN.test(domain));
|
|
13863
|
-
}
|
|
13864
|
-
function buildCsp(csp) {
|
|
13865
|
-
if (!csp) return DEFAULT_CSP;
|
|
13866
|
-
const resourceOrigins = declaredOrigins(csp.resourceDomains);
|
|
13867
|
-
const resource = resourceOrigins.join(" ");
|
|
13868
|
-
const withResourceOrigins = (base) => resource ? `${base} ${resource}` : base;
|
|
13869
|
-
const img = ["'self'", "data:", ...resourceOrigins].join(" ");
|
|
13870
|
-
const connect = declaredOrigins(csp.connectDomains);
|
|
13871
|
-
const frame = declaredOrigins(csp.frameDomains);
|
|
13872
|
-
const baseUri = declaredOrigins(csp.baseUriDomains);
|
|
13873
|
-
const parts = [
|
|
13874
|
-
"default-src 'none'",
|
|
13875
|
-
withResourceOrigins("script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval'"),
|
|
13876
|
-
withResourceOrigins("style-src 'self' 'unsafe-inline'"),
|
|
13877
|
-
`img-src ${img}`,
|
|
13878
|
-
`media-src ${["'self'", "data:", ...resourceOrigins].join(" ")}`,
|
|
13879
|
-
withResourceOrigins("font-src 'self'"),
|
|
13880
|
-
"object-src 'none'",
|
|
13881
|
-
`connect-src ${connect.length ? connect.join(" ") : "'none'"}`,
|
|
13882
|
-
`frame-src ${frame.length ? frame.join(" ") : "'none'"}`,
|
|
13883
|
-
`base-uri ${baseUri.length ? baseUri.join(" ") : "'self'"}`
|
|
13884
|
-
];
|
|
13885
|
-
return parts.join("; ");
|
|
13886
|
-
}
|
|
13887
|
-
|
|
13888
|
-
// src/services/mcp-ui/sandboxPage.ts
|
|
13889
|
-
var DEFAULT_CSP_LITERAL = JSON.stringify(buildCsp(void 0));
|
|
13890
|
-
var SANDBOX_HTML = `<!doctype html>
|
|
13891
|
-
<html lang="en">
|
|
13892
|
-
<head>
|
|
13893
|
-
<meta charset="utf-8" />
|
|
13894
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13895
|
-
<title>MCP App Sandbox</title>
|
|
13896
|
-
<style>html, body { margin: 0; height: 100%; }</style>
|
|
13897
|
-
</head>
|
|
13898
|
-
<body>
|
|
13899
|
-
<script>
|
|
13900
|
-
(function () {
|
|
13901
|
-
var HOST_READY = "ui/notifications/sandbox-proxy-ready";
|
|
13902
|
-
var RESOURCE_READY = "ui/notifications/sandbox-resource-ready";
|
|
13903
|
-
var CONTROL_PREFIX = "ui/notifications/sandbox-";
|
|
13904
|
-
var DEFAULT_CSP = ${DEFAULT_CSP_LITERAL};
|
|
13905
|
-
|
|
13906
|
-
function withCsp(html, csp) {
|
|
13907
|
-
var policy = typeof csp === "string" && csp.length > 0 ? csp : DEFAULT_CSP;
|
|
13908
|
-
var escaped = policy.replace(/&/g, "&").replace(/"/g, """);
|
|
13909
|
-
var meta = '<meta http-equiv="Content-Security-Policy" content="' + escaped + '">';
|
|
13910
|
-
// Insert at the very start (after an optional doctype) so the parser
|
|
13911
|
-
// places the meta in the implicit head. Never search for a literal
|
|
13912
|
-
// <head>: a resource could hide a decoy inside a comment/string and
|
|
13913
|
-
// slip its real head past the splice.
|
|
13914
|
-
var doctype = /^\\s*<!doctype[^>]*>/i.exec(html);
|
|
13915
|
-
if (doctype) {
|
|
13916
|
-
return html.slice(0, doctype[0].length) + meta + html.slice(doctype[0].length);
|
|
13917
|
-
}
|
|
13918
|
-
return meta + html;
|
|
13919
|
-
}
|
|
13920
|
-
|
|
13921
|
-
// Size reporter injected into every View document. The host renders the
|
|
13922
|
-
// View inside an opaque-origin iframe it cannot measure, so auto-height
|
|
13923
|
-
// only happens when the View posts ui/notifications/size-changed. Most
|
|
13924
|
-
// hand-written plugin apps never do; this script makes every app report
|
|
13925
|
-
// its own content size. It only measures and postMessages \u2014 it never
|
|
13926
|
-
// mutates the app's DOM.
|
|
13927
|
-
var SIZE_REPORTER = [
|
|
13928
|
-
"(function(){",
|
|
13929
|
-
"function send(){",
|
|
13930
|
-
"try{",
|
|
13931
|
-
"var d=document.documentElement,b=document.body;",
|
|
13932
|
-
"var w=Math.ceil(Math.max(d?d.scrollWidth:0,b?b.scrollWidth:0));",
|
|
13933
|
-
"var h=Math.ceil(Math.max(d?d.scrollHeight:0,b?b.scrollHeight:0));",
|
|
13934
|
-
"window.parent.postMessage({jsonrpc:'2.0',method:'ui/notifications/size-changed',params:{width:w,height:h}},'*');",
|
|
13935
|
-
"}catch(e){}",
|
|
13936
|
-
"}",
|
|
13937
|
-
"send();",
|
|
13938
|
-
"window.addEventListener('load',send);",
|
|
13939
|
-
"if(typeof ResizeObserver!=='undefined'){",
|
|
13940
|
-
"var ro=new ResizeObserver(send);",
|
|
13941
|
-
"ro.observe(document.documentElement);",
|
|
13942
|
-
"if(document.body)ro.observe(document.body);",
|
|
13943
|
-
"}else{window.addEventListener('resize',send);}",
|
|
13944
|
-
"})();"
|
|
13945
|
-
].join("");
|
|
13946
|
-
|
|
13947
|
-
function withSizeReporter(html) {
|
|
13948
|
-
// Split the closing tag so this template literal never contains a
|
|
13949
|
-
// literal script terminator that would end the sandbox page's own
|
|
13950
|
-
// script block during HTML parsing.
|
|
13951
|
-
var tag = "<scr" + "ipt>" + SIZE_REPORTER + "<" + "/scr" + "ipt>";
|
|
13952
|
-
var lower = html.toLowerCase();
|
|
13953
|
-
var bodyEnd = lower.lastIndexOf("</body>");
|
|
13954
|
-
if (bodyEnd >= 0) return html.slice(0, bodyEnd) + tag + html.slice(bodyEnd);
|
|
13955
|
-
return html + tag;
|
|
13956
|
-
}
|
|
13957
|
-
|
|
13958
|
-
var inner = null;
|
|
13959
|
-
|
|
13960
|
-
window.parent.postMessage({ jsonrpc: "2.0", method: HOST_READY, params: {} }, "*");
|
|
13961
|
-
|
|
13962
|
-
window.addEventListener("message", function (event) {
|
|
13963
|
-
if (event.source !== window.parent) return;
|
|
13964
|
-
var data = event.data;
|
|
13965
|
-
if (!data || typeof data !== "object") return;
|
|
13966
|
-
|
|
13967
|
-
if (data.method === RESOURCE_READY) {
|
|
13968
|
-
var params = data.params || {};
|
|
13969
|
-
if (inner && inner.parentNode) inner.parentNode.removeChild(inner);
|
|
13970
|
-
inner = document.createElement("iframe");
|
|
13971
|
-
inner.setAttribute("sandbox", params.sandbox || "allow-scripts");
|
|
13972
|
-
inner.setAttribute("srcdoc", withCsp(withSizeReporter(String(params.html || "")), params.csp));
|
|
13973
|
-
inner.style.cssText = "width:100%;height:100%;border:0;display:block";
|
|
13974
|
-
document.body.appendChild(inner);
|
|
13975
|
-
return;
|
|
13976
|
-
}
|
|
13977
|
-
|
|
13978
|
-
if (typeof data.method === "string" && data.method.indexOf(CONTROL_PREFIX) === 0) return;
|
|
13979
|
-
if (inner && inner.contentWindow) inner.contentWindow.postMessage(data, "*");
|
|
13980
|
-
});
|
|
13981
|
-
|
|
13982
|
-
window.addEventListener("message", function (event) {
|
|
13983
|
-
if (inner && event.source === inner.contentWindow) {
|
|
13984
|
-
var data = event.data;
|
|
13985
|
-
if (data && typeof data === "object" && typeof data.method === "string"
|
|
13986
|
-
&& data.method.indexOf(CONTROL_PREFIX) === 0) return;
|
|
13987
|
-
window.parent.postMessage(event.data, "*");
|
|
13988
|
-
}
|
|
13989
|
-
});
|
|
13990
|
-
})();
|
|
13991
|
-
</script>
|
|
13992
|
-
</body>
|
|
13993
|
-
</html>
|
|
13994
|
-
`;
|
|
13995
|
-
|
|
13996
|
-
// src/routes/mcp-apps.ts
|
|
13997
|
-
var SANDBOX_HTML_CONTENT_TYPE = "text/html; charset=utf-8";
|
|
13998
|
-
var PluginMethodNotSupportedError = class extends Error {
|
|
13999
|
-
/**
|
|
14000
|
-
* @param method - Unsupported JSON-RPC method.
|
|
14001
|
-
*/
|
|
14002
|
-
constructor(method) {
|
|
14003
|
-
super(`plugin backend does not support ${method}`);
|
|
14004
|
-
this.name = "PluginMethodNotSupportedError";
|
|
14005
|
-
}
|
|
14006
|
-
};
|
|
14007
|
-
var McpAppScopeError = class extends Error {
|
|
14008
|
-
/**
|
|
14009
|
-
* @param status - HTTP status to return.
|
|
14010
|
-
* @param code - Stable machine-readable denial code.
|
|
14011
|
-
*/
|
|
14012
|
-
constructor(status, code) {
|
|
14013
|
-
super(code);
|
|
14014
|
-
this.status = status;
|
|
14015
|
-
this.code = code;
|
|
14016
|
-
this.name = "McpAppScopeError";
|
|
14017
|
-
}
|
|
14018
|
-
};
|
|
14019
|
-
function denyScope(status, code, detail) {
|
|
14020
|
-
console.warn(JSON.stringify({ event: "mcp-apps:scope-denied", ...detail, code }));
|
|
14021
|
-
return new McpAppScopeError(status, code);
|
|
14022
|
-
}
|
|
14023
|
-
var ALLOWED_METHODS = /* @__PURE__ */ new Set(["tools/call", "tools/list", "resources/read"]);
|
|
14024
|
-
function asRecord(value) {
|
|
14025
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
14026
|
-
}
|
|
14027
|
-
function makeMcpAppHandlers(deps) {
|
|
14028
|
-
return {
|
|
14029
|
-
/**
|
|
14030
|
-
* Resolve the `mcp_app` UI resource for a parsed ref.
|
|
14031
|
-
*
|
|
14032
|
-
* @param tenantId Tenant scope.
|
|
14033
|
-
* @param rawRef Untrusted ref payload.
|
|
14034
|
-
* @returns The resource payload plus a ready-to-use `cspPolicy` string
|
|
14035
|
-
* ({@link buildCsp}, always non-empty), or a 400/502 error envelope.
|
|
14036
|
-
*/
|
|
14037
|
-
async resource(tenantId, rawRef) {
|
|
14038
|
-
const ref = parseMcpUiRef(rawRef);
|
|
14039
|
-
if (!ref) return { status: 400, body: { error: "INVALID_REF" } };
|
|
14040
|
-
if (ref.kind === "plugin" && ref.pluginType === "") {
|
|
14041
|
-
return { status: 400, body: { error: "INVALID_REF" } };
|
|
14042
|
-
}
|
|
14043
|
-
try {
|
|
14044
|
-
const payload = await deps.resolveUiResource(tenantId, ref);
|
|
14045
|
-
return { status: 200, body: { ...payload, cspPolicy: buildCsp(payload.csp) } };
|
|
14046
|
-
} catch (error) {
|
|
14047
|
-
console.warn(JSON.stringify({
|
|
14048
|
-
event: "mcp-apps:resource-failed",
|
|
14049
|
-
tenantId,
|
|
14050
|
-
kind: ref.kind,
|
|
14051
|
-
error: error instanceof Error ? error.message : String(error)
|
|
14052
|
-
}));
|
|
14053
|
-
return { status: 502, body: { error: "RESOURCE_UNAVAILABLE" } };
|
|
14054
|
-
}
|
|
14055
|
-
},
|
|
14056
|
-
/**
|
|
14057
|
-
* Proxy an allow-listed JSON-RPC method for a parsed ref.
|
|
14058
|
-
*
|
|
14059
|
-
* @param tenantId Tenant scope.
|
|
14060
|
-
* @param rawRef Untrusted ref payload.
|
|
14061
|
-
* @param method JSON-RPC method name.
|
|
14062
|
-
* @param params JSON-RPC params.
|
|
14063
|
-
* @param context Request-scoped run context forwarded to `tools/call`.
|
|
14064
|
-
* @returns The backend result, or a 400/403/502 error envelope.
|
|
14065
|
-
*/
|
|
14066
|
-
async rpc(tenantId, rawRef, method, params, context) {
|
|
14067
|
-
const ref = parseMcpUiRef(rawRef);
|
|
14068
|
-
if (!ref) return { status: 400, body: { error: "INVALID_REF" } };
|
|
14069
|
-
if (!ALLOWED_METHODS.has(method)) return { status: 403, body: { error: "METHOD_NOT_ALLOWED" } };
|
|
14070
|
-
try {
|
|
14071
|
-
if (method === "tools/call") {
|
|
14072
|
-
const name = typeof params.name === "string" ? params.name : "";
|
|
14073
|
-
if (name === "") return { status: 400, body: { error: "INVALID_PARAMS" } };
|
|
14074
|
-
if ("pluginType" in ref && ref.pluginType === "") {
|
|
14075
|
-
return { status: 400, body: { error: "INVALID_REF" } };
|
|
14076
|
-
}
|
|
14077
|
-
return {
|
|
14078
|
-
status: 200,
|
|
14079
|
-
body: await deps.callTool(tenantId, ref, name, asRecord(params.arguments) ?? {}, context)
|
|
14080
|
-
};
|
|
14081
|
-
}
|
|
14082
|
-
if (method === "resources/read") {
|
|
14083
|
-
const uri = typeof params.uri === "string" ? params.uri : "";
|
|
14084
|
-
if (uri === "") return { status: 400, body: { error: "INVALID_PARAMS" } };
|
|
14085
|
-
return { status: 200, body: await deps.readResource(tenantId, ref, uri) };
|
|
14086
|
-
}
|
|
14087
|
-
return { status: 200, body: { tools: await deps.listTools(tenantId, ref) } };
|
|
14088
|
-
} catch (error) {
|
|
14089
|
-
if (error instanceof McpAppScopeError) {
|
|
14090
|
-
return { status: error.status, body: { error: error.code } };
|
|
14091
|
-
}
|
|
14092
|
-
if (error instanceof PluginToolScopeError) {
|
|
14093
|
-
return { status: 403, body: { error: "PLUGIN_TOOL_SCOPE" } };
|
|
14094
|
-
}
|
|
14095
|
-
if (error instanceof PluginMethodNotSupportedError) {
|
|
14096
|
-
return { status: 403, body: { error: "PLUGIN_METHOD_UNSUPPORTED" } };
|
|
14097
|
-
}
|
|
14098
|
-
const context2 = { tenantId, kind: ref.kind, method };
|
|
14099
|
-
if (method === "resources/read") context2.uri = typeof params.uri === "string" ? params.uri : "";
|
|
14100
|
-
if (method === "tools/call") context2.name = typeof params.name === "string" ? params.name : "";
|
|
14101
|
-
console.warn(JSON.stringify({
|
|
14102
|
-
event: "mcp-apps:rpc-failed",
|
|
14103
|
-
...context2,
|
|
14104
|
-
error: error instanceof Error ? error.message : String(error)
|
|
14105
|
-
}));
|
|
14106
|
-
return { status: 502, body: { error: "RPC_FAILED" } };
|
|
14107
|
-
}
|
|
14108
|
-
}
|
|
14109
|
-
};
|
|
14110
|
-
}
|
|
14111
|
-
async function fetchPluginUiResource(backend, tenantId, pluginType, resource) {
|
|
14112
|
-
const plugin = await backend.resolvePlugin(tenantId, pluginType);
|
|
14113
|
-
if (!plugin) throw new Error(`plugin "${pluginType}" not found`);
|
|
14114
|
-
const tool = (plugin.meta.tools ?? []).find((t2) => t2.ui?.resource === resource);
|
|
14115
|
-
if (!tool?.ui) throw new Error(`plugin "${pluginType}" has no tool declaring ui resource "${resource}"`);
|
|
14116
|
-
const inline = plugin.meta.uiResources?.[resource];
|
|
14117
|
-
if (inline) {
|
|
14118
|
-
return {
|
|
14119
|
-
mimeType: inline.mimeType ?? "text/html;profile=mcp-app",
|
|
14120
|
-
html: inline.html,
|
|
14121
|
-
csp: inline.csp ?? tool.ui.csp,
|
|
14122
|
-
permissions: tool.ui.permissions,
|
|
14123
|
-
prefersBorder: tool.ui.prefersBorder
|
|
14124
|
-
};
|
|
14125
|
-
}
|
|
14126
|
-
const html = await backend.catalog.readPluginFile(tenantId, pluginType, resource);
|
|
14127
|
-
return {
|
|
14128
|
-
mimeType: "text/html",
|
|
14129
|
-
html,
|
|
14130
|
-
csp: tool.ui.csp,
|
|
14131
|
-
permissions: tool.ui.permissions,
|
|
14132
|
-
prefersBorder: tool.ui.prefersBorder
|
|
14133
|
-
};
|
|
14134
|
-
}
|
|
14135
|
-
async function callPluginTool(backend, tenantId, ref, name, args, context, deps) {
|
|
14136
|
-
const scope = ref.scope ? (deps?.verifyScope ?? verifyMcpUiScope)(ref.scope) : null;
|
|
14137
|
-
if (ref.scope && !scope) {
|
|
14138
|
-
throw denyScope(403, "SCOPE_INVALID", {
|
|
14139
|
-
tenantId,
|
|
14140
|
-
pluginType: ref.pluginType,
|
|
14141
|
-
tool: name
|
|
14142
|
-
});
|
|
14143
|
-
}
|
|
14144
|
-
if (scope) {
|
|
14145
|
-
const mismatched = scope.tid !== tenantId || scope.plugin !== ref.pluginType || scope.resource !== ref.resource;
|
|
14146
|
-
if (mismatched) {
|
|
14147
|
-
throw denyScope(403, "SCOPE_MISMATCH", {
|
|
14148
|
-
tenantId,
|
|
14149
|
-
pluginType: ref.pluginType,
|
|
14150
|
-
tool: name,
|
|
14151
|
-
jti: scope.jti,
|
|
14152
|
-
threadId: scope.thid
|
|
14153
|
-
});
|
|
14154
|
-
}
|
|
14155
|
-
}
|
|
14156
|
-
const manifest = await backend.catalog.getValidatedManifest(tenantId, ref.pluginType);
|
|
14157
|
-
const rawConnectionKey = args.connectionKey;
|
|
14158
|
-
const explicit = typeof rawConnectionKey === "string" ? rawConnectionKey : void 0;
|
|
14159
|
-
const scoped = scope?.ck;
|
|
14160
|
-
const connectionRelevant = Boolean(manifest?.connection) || scoped !== void 0;
|
|
14161
|
-
if (connectionRelevant && (explicit !== void 0 ? explicit !== scoped : rawConnectionKey !== void 0)) {
|
|
14162
|
-
throw denyScope(403, "CONNECTION_NOT_ALLOWED", {
|
|
14163
|
-
tenantId,
|
|
14164
|
-
pluginType: ref.pluginType,
|
|
14165
|
-
tool: name,
|
|
14166
|
-
jti: scope?.jti,
|
|
14167
|
-
threadId: scope?.thid
|
|
14168
|
-
});
|
|
14169
|
-
}
|
|
14170
|
-
let connection;
|
|
14171
|
-
let connectionKey;
|
|
14172
|
-
if (scoped !== void 0) {
|
|
14173
|
-
const resolveConnections = deps?.resolveConnections ?? resolvePluginConnections;
|
|
14174
|
-
const resolved = await resolveConnections(
|
|
14175
|
-
ref.pluginType,
|
|
14176
|
-
{ connections: [scoped] },
|
|
14177
|
-
{ tenantId }
|
|
14178
|
-
);
|
|
14179
|
-
if (resolved.length === 0) {
|
|
14180
|
-
throw denyScope(403, "CONNECTION_NOT_ALLOWED", {
|
|
14181
|
-
tenantId,
|
|
14182
|
-
pluginType: ref.pluginType,
|
|
14183
|
-
tool: name,
|
|
14184
|
-
jti: scope?.jti,
|
|
14185
|
-
threadId: scope?.thid
|
|
14186
|
-
});
|
|
14187
|
-
}
|
|
14188
|
-
connection = resolved[0].config;
|
|
14189
|
-
connectionKey = resolved[0].key;
|
|
14190
|
-
}
|
|
14191
|
-
if (manifest?.connection && !connectionKey) {
|
|
14192
|
-
throw denyScope(409, "CONNECTION_REQUIRED", {
|
|
14193
|
-
tenantId,
|
|
14194
|
-
pluginType: ref.pluginType,
|
|
14195
|
-
tool: name,
|
|
14196
|
-
jti: scope?.jti,
|
|
14197
|
-
threadId: scope?.thid
|
|
14198
|
-
});
|
|
14199
|
-
}
|
|
14200
|
-
const identity = scope ? {
|
|
14201
|
-
workspaceId: scope.wid,
|
|
14202
|
-
projectId: scope.pid,
|
|
14203
|
-
threadId: scope.thid,
|
|
14204
|
-
assistantId: scope.aid
|
|
14205
|
-
} : {
|
|
14206
|
-
workspaceId: context?.workspaceId,
|
|
14207
|
-
projectId: context?.projectId
|
|
14208
|
-
};
|
|
14209
|
-
return invokePluginTool(backend, tenantId, ref.pluginType, name, args, {
|
|
14210
|
-
...identity,
|
|
14211
|
-
...connection === void 0 ? {} : { connection }
|
|
14212
|
-
});
|
|
14213
|
-
}
|
|
14214
|
-
function createDefaultPluginBackend() {
|
|
14215
|
-
return {
|
|
14216
|
-
resolvePlugin: (tenantId, type) => resolveTenantPluginByType(tenantId, type),
|
|
14217
|
-
catalog: {
|
|
14218
|
-
readPluginFile: (tenantId, pluginType, relPath) => getSandboxPluginCatalog2().readPluginFile(tenantId, pluginType, relPath),
|
|
14219
|
-
getValidatedManifest: (tenantId, pluginType) => getSandboxPluginCatalog2().getValidatedManifest(tenantId, pluginType),
|
|
14220
|
-
getExecutor: () => getSandboxPluginCatalog2().getExecutor()
|
|
14221
|
-
}
|
|
14222
|
-
};
|
|
14223
|
-
}
|
|
14224
|
-
var uiResourceResolverSingleton;
|
|
14225
|
-
function getMcpUiResourceResolver() {
|
|
14226
|
-
return uiResourceResolverSingleton;
|
|
14227
|
-
}
|
|
14228
|
-
function resolveMcpAppDeps(pluginBackend = createDefaultPluginBackend()) {
|
|
14229
|
-
const uiResourceResolver = new UiResourceResolver({
|
|
14230
|
-
store: new InMemoryMcpUiResourceCacheStore(),
|
|
14231
|
-
fetchMcp: (tenantId, serverKey, resourceUri) => mcpManager2.readUiResource(tenantId, serverKey, resourceUri),
|
|
14232
|
-
fetchPlugin: (tenantId, pluginType, resource) => fetchPluginUiResource(pluginBackend, tenantId, pluginType, resource)
|
|
14233
|
-
});
|
|
14234
|
-
uiResourceResolverSingleton = uiResourceResolver;
|
|
14235
|
-
return {
|
|
14236
|
-
resolveUiResource: (tenantId, ref) => uiResourceResolver.resolve(tenantId, ref),
|
|
14237
|
-
callTool: (tenantId, ref, name, args, context) => ref.kind === "mcp" ? mcpManager2.callServerTool(tenantId, ref.serverKey, name, args) : callPluginTool(pluginBackend, tenantId, ref, name, args, context),
|
|
14238
|
-
// Plugin refs reach these only after `tools/call`; the handler treats the
|
|
14239
|
-
// rejection as an unsupported method (403). The branches are live because
|
|
14240
|
-
// the pure handler deliberately delegates method policy to the deps.
|
|
14241
|
-
readResource: (tenantId, ref, uri) => ref.kind === "mcp" ? mcpManager2.readServerResource(tenantId, ref.serverKey, uri) : Promise.reject(new PluginMethodNotSupportedError("resources/read")),
|
|
14242
|
-
listTools: (tenantId, ref) => ref.kind === "mcp" ? mcpManager2.getAvailableTools(tenantId, ref.serverKey) : Promise.reject(new PluginMethodNotSupportedError("tools/list"))
|
|
14243
|
-
};
|
|
14244
|
-
}
|
|
14245
|
-
function firstHeader(request, name) {
|
|
14246
|
-
const header2 = request.headers[name];
|
|
14247
|
-
return Array.isArray(header2) ? header2[0] : header2;
|
|
14248
|
-
}
|
|
14249
|
-
function tenantOf(request) {
|
|
14250
|
-
const user = request.user;
|
|
14251
|
-
return user?.tenantId ?? firstHeader(request, "x-tenant-id") ?? "default";
|
|
14252
|
-
}
|
|
14253
|
-
function runContextOf(request) {
|
|
14254
|
-
return {
|
|
14255
|
-
tenantId: tenantOf(request),
|
|
14256
|
-
workspaceId: firstHeader(request, "x-workspace-id"),
|
|
14257
|
-
projectId: firstHeader(request, "x-project-id")
|
|
14258
|
-
};
|
|
14259
|
-
}
|
|
14260
|
-
function registerMcpAppRoutes(fastify2, deps = resolveMcpAppDeps()) {
|
|
14261
|
-
const handlers = makeMcpAppHandlers(deps);
|
|
14262
|
-
fastify2.get("/mcp-apps/sandbox.html", async (_request, reply) => {
|
|
14263
|
-
return reply.header("content-type", SANDBOX_HTML_CONTENT_TYPE).header("x-content-type-options", "nosniff").header("cache-control", "no-store").send(SANDBOX_HTML);
|
|
14264
|
-
});
|
|
14265
|
-
fastify2.post("/api/mcp-apps/resource", async (request, reply) => {
|
|
14266
|
-
const body = asRecord(request.body) ?? {};
|
|
14267
|
-
const result = await handlers.resource(tenantOf(request), body.ref);
|
|
14268
|
-
return reply.code(result.status).send(result.body);
|
|
14269
|
-
});
|
|
14270
|
-
fastify2.post("/api/mcp-apps/rpc", async (request, reply) => {
|
|
14271
|
-
const body = asRecord(request.body) ?? {};
|
|
14272
|
-
const params = asRecord(body.params) ?? {};
|
|
14273
|
-
const context = runContextOf(request);
|
|
14274
|
-
const result = await handlers.rpc(
|
|
14275
|
-
context.tenantId,
|
|
14276
|
-
body.ref,
|
|
14277
|
-
String(body.method ?? ""),
|
|
14278
|
-
params,
|
|
14279
|
-
context
|
|
14280
|
-
);
|
|
14281
|
-
return reply.code(result.status).send(result.body);
|
|
14282
|
-
});
|
|
14283
|
-
}
|
|
14284
|
-
|
|
14285
13566
|
// src/controllers/eval.ts
|
|
14286
13567
|
import { getStoreLattice as getStoreLattice21, hasModelLatticeForTenant as hasModelLatticeForTenant2, modelLatticeManager as modelLatticeManager2 } from "@axiom-lattice/core";
|
|
14287
13568
|
import { v4 as uuidv43 } from "uuid";
|
|
@@ -15431,6 +14712,16 @@ var AuthController = class {
|
|
|
15431
14712
|
}
|
|
15432
14713
|
async login(request, reply) {
|
|
15433
14714
|
const { email, password } = request.body;
|
|
14715
|
+
const rateLimit = await getRateLimitService().consume("auth.login", {
|
|
14716
|
+
ip: request.ip
|
|
14717
|
+
});
|
|
14718
|
+
if (!rateLimit.allowed) {
|
|
14719
|
+
return reply.header("Retry-After", String(rateLimit.retryAfterSeconds)).status(429).send({
|
|
14720
|
+
success: false,
|
|
14721
|
+
error: "RATE_LIMITED",
|
|
14722
|
+
retryAfterSeconds: rateLimit.retryAfterSeconds
|
|
14723
|
+
});
|
|
14724
|
+
}
|
|
15434
14725
|
try {
|
|
15435
14726
|
const user = await this.userStore.getUserByEmail(email);
|
|
15436
14727
|
if (!user) {
|
|
@@ -15799,7 +15090,7 @@ function isStaleConsoleSessionCredential(authHeader) {
|
|
|
15799
15090
|
function bypassesConsoleAuth(request) {
|
|
15800
15091
|
const path5 = request.url.split("?")[0];
|
|
15801
15092
|
const method = request.method;
|
|
15802
|
-
if (method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/bootstrap$/.test(path5) || (method === "GET" || method === "POST") && /^\/api\/web-apps\/[^/]+\/runtime\/threads$/.test(path5) || (method === "PATCH" || method === "DELETE") && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/messages$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/files\/(viewfile|downloadfile)$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/api\/assistants\/[^/]+\/threads\/[^/]+\/sandbox\/(viewfile|downloadfile)$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/(messages\/stream|abort|attachments)$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/interrupts\/[^/]+\/resume$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs\/[^/]+$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs\/[^/]+\/join$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs\/[^/]+\/cancel$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/chat$/.test(path5) || method === "GET" && /^\/embed\/[^/]+$/.test(path5) || method === "GET" && path5 === "/mcp-apps/sandbox.html" || (method === "POST" || method === "DELETE") && path5 === "/open/mcp" || (method === "POST" || method === "GET") && (path5 === "/mcp" || path5 === "/mcp/") || method === "POST" && path5 === "/open/session" || (method === "GET" || method === "POST") && path5.startsWith("/open/sandbox/files/")) return true;
|
|
15093
|
+
if (method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/bootstrap$/.test(path5) || (method === "GET" || method === "POST") && /^\/api\/web-apps\/[^/]+\/runtime\/threads$/.test(path5) || (method === "PATCH" || method === "DELETE") && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/messages$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/files\/(viewfile|downloadfile)$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime\/api\/assistants\/[^/]+\/threads\/[^/]+\/sandbox\/(viewfile|downloadfile)$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/(messages\/stream|abort|attachments)$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime\/threads\/[^/]+\/interrupts\/[^/]+\/resume$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs\/[^/]+$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs\/[^/]+\/join$/.test(path5) || method === "POST" && /^\/api\/web-apps\/[^/]+\/runtime(?:\/api)?\/assistants\/[^/]+\/threads\/[^/]+\/runs\/[^/]+\/cancel$/.test(path5) || method === "GET" && /^\/api\/web-apps\/[^/]+\/chat$/.test(path5) || method === "GET" && /^\/embed\/[^/]+$/.test(path5) || method === "GET" && path5 === "/mcp-apps/sandbox.html" || method === "GET" && /^\/api\/mcp-app-shares\/[^/]+\/bootstrap$/.test(path5) || method === "POST" && /^\/api\/mcp-app-shares\/[^/]+\/(resource|rpc|unlock)$/.test(path5) || (method === "POST" || method === "DELETE") && path5 === "/open/mcp" || (method === "POST" || method === "GET") && (path5 === "/mcp" || path5 === "/mcp/") || method === "POST" && path5 === "/open/session" || (method === "GET" || method === "POST") && path5.startsWith("/open/sandbox/files/")) return true;
|
|
15803
15094
|
if (request.method === "GET" && (/^\/api\/a2a\/agents\/[^/]+\/\.well-known\/agent-card\.json$/.test(path5) || /^\/a2a\/(?:v1\/)?[^/]+\/\.well-known\/agent-card\.json$/.test(path5))) {
|
|
15804
15095
|
return true;
|
|
15805
15096
|
}
|
|
@@ -16221,7 +15512,7 @@ function registerChannelRoutes(app2, dependencies) {
|
|
|
16221
15512
|
}
|
|
16222
15513
|
|
|
16223
15514
|
// src/controllers/channel-installations.ts
|
|
16224
|
-
import { randomUUID as
|
|
15515
|
+
import { randomUUID as randomUUID17 } from "crypto";
|
|
16225
15516
|
import {
|
|
16226
15517
|
descriptorDataValue
|
|
16227
15518
|
} from "@axiom-lattice/protocols";
|
|
@@ -16442,7 +15733,7 @@ async function createChannelInstallation(request, reply) {
|
|
|
16442
15733
|
};
|
|
16443
15734
|
}
|
|
16444
15735
|
const store2 = await getInstallationStore();
|
|
16445
|
-
const installationId =
|
|
15736
|
+
const installationId = randomUUID17();
|
|
16446
15737
|
const createInput = {
|
|
16447
15738
|
channel: body.channel,
|
|
16448
15739
|
name: body.name,
|
|
@@ -17434,7 +16725,7 @@ async function getLocalA2ATemplates(_request, reply) {
|
|
|
17434
16725
|
}
|
|
17435
16726
|
|
|
17436
16727
|
// src/routes/a2a-test-connection.ts
|
|
17437
|
-
import { randomUUID as
|
|
16728
|
+
import { randomUUID as randomUUID18 } from "crypto";
|
|
17438
16729
|
function describeTestConnectionError(error, agentCardUrl) {
|
|
17439
16730
|
if (!(error instanceof Error)) {
|
|
17440
16731
|
return `Failed to fetch agent card from ${agentCardUrl}: ${String(error)}`;
|
|
@@ -17474,7 +16765,7 @@ async function ensureLocalRuntimeForConnectionTest(localRuntime, agentCardUrl) {
|
|
|
17474
16765
|
return { error: portValidation.error };
|
|
17475
16766
|
}
|
|
17476
16767
|
const state = await localA2AService.startProvider(
|
|
17477
|
-
`test-${
|
|
16768
|
+
`test-${randomUUID18()}`,
|
|
17478
16769
|
testRuntime
|
|
17479
16770
|
);
|
|
17480
16771
|
if (state.status === "running") return { runtimeId: state.runtimeId };
|
|
@@ -17565,6 +16856,7 @@ import {
|
|
|
17565
16856
|
ProjectTaskOwnerPolicyError as ProjectTaskOwnerPolicyError2,
|
|
17566
16857
|
projectMutationMutex as projectMutationMutex2,
|
|
17567
16858
|
projectTaskAdmissionNotifier,
|
|
16859
|
+
projectRoomMessageNotifier,
|
|
17568
16860
|
taskLifecycleNotifier as taskLifecycleNotifier2
|
|
17569
16861
|
} from "@axiom-lattice/core";
|
|
17570
16862
|
|
|
@@ -17903,16 +17195,16 @@ function snapshotEnsureInput(input) {
|
|
|
17903
17195
|
}
|
|
17904
17196
|
|
|
17905
17197
|
// src/services/tasks/TaskCommandService.ts
|
|
17906
|
-
import { createHash as
|
|
17198
|
+
import { createHash as createHash3 } from "crypto";
|
|
17907
17199
|
|
|
17908
17200
|
// src/services/collaboration/ProjectTaskRunService.ts
|
|
17909
|
-
import { randomUUID as
|
|
17201
|
+
import { randomUUID as randomUUID20 } from "crypto";
|
|
17910
17202
|
import {
|
|
17911
17203
|
createTaskRunBridge
|
|
17912
17204
|
} from "@axiom-lattice/core";
|
|
17913
17205
|
|
|
17914
17206
|
// src/services/collaboration/ProjectTaskRunPlanner.ts
|
|
17915
|
-
import { randomUUID as
|
|
17207
|
+
import { randomUUID as randomUUID19 } from "crypto";
|
|
17916
17208
|
|
|
17917
17209
|
// src/services/collaboration/ProjectTaskRunProtocol.ts
|
|
17918
17210
|
import {
|
|
@@ -18228,7 +17520,7 @@ var ProjectTaskRunPlanner = class {
|
|
|
18228
17520
|
} catch (error) {
|
|
18229
17521
|
throw asPlanError(error);
|
|
18230
17522
|
}
|
|
18231
|
-
const inputId = (this.deps.idFactory ??
|
|
17523
|
+
const inputId = (this.deps.idFactory ?? randomUUID19)();
|
|
18232
17524
|
const actor3 = input.actor ?? SYSTEM_ACTOR;
|
|
18233
17525
|
const userId = actor3.startsWith("user:") && actor3.length > "user:".length ? actor3.slice("user:".length) : void 0;
|
|
18234
17526
|
const trustedContext = {
|
|
@@ -18371,7 +17663,7 @@ var ProjectTaskRunService = class {
|
|
|
18371
17663
|
...deps.idFactory === void 0 ? {} : { idFactory: deps.idFactory }
|
|
18372
17664
|
});
|
|
18373
17665
|
this.runBridge = createTaskRunBridge({ lifecycle: deps.lifecycle });
|
|
18374
|
-
this.idFactory = deps.idFactory ??
|
|
17666
|
+
this.idFactory = deps.idFactory ?? randomUUID20;
|
|
18375
17667
|
this.log = deps.log ?? { warn: () => void 0 };
|
|
18376
17668
|
}
|
|
18377
17669
|
/**
|
|
@@ -19040,7 +18332,7 @@ var _TaskCommandService = class _TaskCommandService {
|
|
|
19040
18332
|
threadId,
|
|
19041
18333
|
summary: "User comment",
|
|
19042
18334
|
detail: { markdown: text, type: "user_comment" },
|
|
19043
|
-
fallbackEventKey: `task-comment:${task.id}:${
|
|
18335
|
+
fallbackEventKey: `task-comment:${task.id}:${createHash3("sha256").update(text).digest("hex")}`
|
|
19044
18336
|
});
|
|
19045
18337
|
const agent = this.deps.agents.getAgent(this.agentScope(task, threadId));
|
|
19046
18338
|
await agent.addMessage({ input: { message: text } });
|
|
@@ -19728,7 +19020,7 @@ var AgentWebAppService = class {
|
|
|
19728
19020
|
}
|
|
19729
19021
|
async create(context, input) {
|
|
19730
19022
|
await this.validateAssistant(context, input.assistantId);
|
|
19731
|
-
const normalized = await this.validateConfig(context
|
|
19023
|
+
const normalized = await this.validateConfig(context, input);
|
|
19732
19024
|
return this.deps.webAppStore.create(context.tenantId, normalized);
|
|
19733
19025
|
}
|
|
19734
19026
|
async list(context, assistantId) {
|
|
@@ -19755,7 +19047,7 @@ var AgentWebAppService = class {
|
|
|
19755
19047
|
identity: patch.identity ?? current3.identity
|
|
19756
19048
|
};
|
|
19757
19049
|
await this.validateAssistant(context, current3.assistantId);
|
|
19758
|
-
const validated = await this.validateConfig(context
|
|
19050
|
+
const validated = await this.validateConfig(context, effective, current3);
|
|
19759
19051
|
const update = {
|
|
19760
19052
|
...patch.name !== void 0 ? { name: validated.name } : {},
|
|
19761
19053
|
...Object.prototype.hasOwnProperty.call(patch, "description") ? { description: validated.description } : {},
|
|
@@ -19768,7 +19060,7 @@ var AgentWebAppService = class {
|
|
|
19768
19060
|
}
|
|
19769
19061
|
async enable(context, webAppId) {
|
|
19770
19062
|
const current3 = await this.requireAuthorizedWebApp(context, webAppId);
|
|
19771
|
-
await this.validateConfig(context
|
|
19063
|
+
await this.validateConfig(context, current3, current3);
|
|
19772
19064
|
return this.writeSnapshot(context, current3, { status: "active" });
|
|
19773
19065
|
}
|
|
19774
19066
|
async disable(context, webAppId) {
|
|
@@ -19790,7 +19082,7 @@ var AgentWebAppService = class {
|
|
|
19790
19082
|
if (await this.deps.configuredAgentResolver.exists(context.tenantId, assistantId)) return;
|
|
19791
19083
|
throw new AgentWebAppError("ASSISTANT_NOT_FOUND", 404, "Assistant not found");
|
|
19792
19084
|
}
|
|
19793
|
-
async validateConfig(
|
|
19085
|
+
async validateConfig(context, input, existing) {
|
|
19794
19086
|
const allowedProjectIds = [...new Set(input.scope.allowedProjectIds)];
|
|
19795
19087
|
if (!allowedProjectIds.length || !allowedProjectIds.includes(input.scope.defaultProjectId)) {
|
|
19796
19088
|
throw new AgentWebAppError("PROJECT_SCOPE_INVALID", 400, "Default project must be in the project allowlist");
|
|
@@ -19798,13 +19090,28 @@ var AgentWebAppService = class {
|
|
|
19798
19090
|
if (!input.features.projectSelector && allowedProjectIds.length !== 1) {
|
|
19799
19091
|
throw new AgentWebAppError("PROJECT_SCOPE_INVALID", 400, "Disabled project selection requires exactly one project");
|
|
19800
19092
|
}
|
|
19093
|
+
const existingIds = new Set(existing?.scope.allowedProjectIds ?? []);
|
|
19801
19094
|
for (const projectId of allowedProjectIds) {
|
|
19802
|
-
if (!await this.deps.projectStore.getProjectById(tenantId, projectId)) {
|
|
19095
|
+
if (!await this.deps.projectStore.getProjectById(context.tenantId, projectId)) {
|
|
19803
19096
|
throw new AgentWebAppError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
19804
19097
|
}
|
|
19098
|
+
if (existingIds.has(projectId)) continue;
|
|
19099
|
+
try {
|
|
19100
|
+
await this.deps.projectAccess.requireExistingProjectAccess({
|
|
19101
|
+
tenantId: context.tenantId,
|
|
19102
|
+
userId: context.userId,
|
|
19103
|
+
projectId,
|
|
19104
|
+
capability: "read"
|
|
19105
|
+
});
|
|
19106
|
+
} catch (error) {
|
|
19107
|
+
if (error instanceof ProjectCollaborationError) {
|
|
19108
|
+
throw new AgentWebAppError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
19109
|
+
}
|
|
19110
|
+
throw error;
|
|
19111
|
+
}
|
|
19805
19112
|
}
|
|
19806
19113
|
const scope = await this.validateModels(
|
|
19807
|
-
tenantId,
|
|
19114
|
+
context.tenantId,
|
|
19808
19115
|
input.scope,
|
|
19809
19116
|
input.features.modelSelector
|
|
19810
19117
|
);
|
|
@@ -20013,7 +19320,7 @@ import { createHmac as createHmac3 } from "crypto";
|
|
|
20013
19320
|
import { z as z5, ZodError as ZodError2 } from "zod";
|
|
20014
19321
|
|
|
20015
19322
|
// src/services/agent-web-app/AgentWebAppRuntimeService.ts
|
|
20016
|
-
import { createHash as
|
|
19323
|
+
import { createHash as createHash4, randomUUID as randomUUID21 } from "crypto";
|
|
20017
19324
|
import { MessageChunkTypes as MessageChunkTypes3, parseAgentWebAppGenUIBlock, buildAffinityMissChunk as buildAffinityMissChunk2 } from "@axiom-lattice/protocols";
|
|
20018
19325
|
import { getReplicaId as getReplicaId7, getThreadRunOwner as getThreadRunOwner2, normalizeAgentInterrupts as normalizeAgentInterrupts2 } from "@axiom-lattice/core";
|
|
20019
19326
|
function isRecord9(value) {
|
|
@@ -20308,10 +19615,10 @@ ${formatFileRefsSection(refs)}` : input.content;
|
|
|
20308
19615
|
const runtime = await this.resolveOwnedRuntime(webAppId, userId, threadId, selection);
|
|
20309
19616
|
this.requireNamedFeature(runtime.webApp.features.attachments, "Attachments are disabled");
|
|
20310
19617
|
if (!this.deps.saveProjectFile || !this.deps.attachmentRefs) this.fail("INTERNAL_ERROR", 500, "Attachment service is unavailable");
|
|
20311
|
-
const userDigest =
|
|
20312
|
-
const contentDigest =
|
|
19618
|
+
const userDigest = createHash4("sha256").update(userId, "utf8").digest("hex");
|
|
19619
|
+
const contentDigest = createHash4("sha256").update(file.bytes).digest("hex");
|
|
20313
19620
|
const displayName = file.name;
|
|
20314
|
-
const physicalName = `${
|
|
19621
|
+
const physicalName = `${randomUUID21()}-${sanitizePhysicalFilename(file.name)}`;
|
|
20315
19622
|
const saved = await this.deps.saveProjectFile({
|
|
20316
19623
|
tenantId: runtime.webApp.tenantId,
|
|
20317
19624
|
workspaceId: runtime.project.workspaceId,
|
|
@@ -20472,7 +19779,7 @@ ${formatFileRefsSection(refs)}` : input.content;
|
|
|
20472
19779
|
const thread = await this.deps.threadStore.createThread(
|
|
20473
19780
|
runtime.webApp.tenantId,
|
|
20474
19781
|
runtime.webApp.assistantId,
|
|
20475
|
-
|
|
19782
|
+
randomUUID21(),
|
|
20476
19783
|
{ metadata: this.metadata(runtime, userId, normalizeLabel(rawLabel)) }
|
|
20477
19784
|
);
|
|
20478
19785
|
return toRuntimeThread(thread);
|
|
@@ -20517,7 +19824,7 @@ function implicitThreadId(runtime, userId) {
|
|
|
20517
19824
|
userId,
|
|
20518
19825
|
runtime.project.id
|
|
20519
19826
|
]);
|
|
20520
|
-
const bytes =
|
|
19827
|
+
const bytes = createHash4("sha256").update(canonicalTuple, "utf8").digest().subarray(0, 16);
|
|
20521
19828
|
bytes[6] = bytes[6] & 15 | 128;
|
|
20522
19829
|
bytes[8] = bytes[8] & 63 | 128;
|
|
20523
19830
|
const hex = bytes.toString("hex");
|
|
@@ -21331,17 +20638,19 @@ var CSS_CONTENT_TYPE = "text/css; charset=utf-8";
|
|
|
21331
20638
|
var EXACT_ASSETS = {
|
|
21332
20639
|
"agent-chat-loader.js": { contentType: JS_CONTENT_TYPE },
|
|
21333
20640
|
"embed-page.js": { contentType: JS_CONTENT_TYPE },
|
|
21334
|
-
"embed-page.css": { contentType: CSS_CONTENT_TYPE }
|
|
20641
|
+
"embed-page.css": { contentType: CSS_CONTENT_TYPE },
|
|
20642
|
+
"mcp-app-page.js": { contentType: JS_CONTENT_TYPE },
|
|
20643
|
+
"mcp-app-page.css": { contentType: CSS_CONTENT_TYPE }
|
|
21335
20644
|
};
|
|
21336
|
-
var HASHED_CHUNK_PATTERN = /^embed-page-[A-Za-z0-9._-]+\.(js|css)$/;
|
|
21337
|
-
var CHUNK_CSS_PATTERN = /^embed-page-[A-Za-z0-9._-]+\.css$/;
|
|
20645
|
+
var HASHED_CHUNK_PATTERN = /^(embed-page|mcp-app-page)-[A-Za-z0-9._-]+\.(js|css)$/;
|
|
20646
|
+
var CHUNK_CSS_PATTERN = /^(embed-page|mcp-app-page)-[A-Za-z0-9._-]+\.css$/;
|
|
21338
20647
|
function resolveAsset(asset) {
|
|
21339
20648
|
if (asset.includes("..")) return null;
|
|
21340
20649
|
const exact2 = EXACT_ASSETS[asset];
|
|
21341
20650
|
if (exact2 !== void 0) return { contentType: exact2.contentType, immutable: false };
|
|
21342
20651
|
const hashed = HASHED_CHUNK_PATTERN.exec(asset);
|
|
21343
20652
|
if (hashed) {
|
|
21344
|
-
return { contentType: hashed[
|
|
20653
|
+
return { contentType: hashed[2] === "css" ? CSS_CONTENT_TYPE : JS_CONTENT_TYPE, immutable: true };
|
|
21345
20654
|
}
|
|
21346
20655
|
return null;
|
|
21347
20656
|
}
|
|
@@ -21446,7 +20755,7 @@ function registerAgentWebAppEmbedRoutes(app2, deps = {}) {
|
|
|
21446
20755
|
}
|
|
21447
20756
|
|
|
21448
20757
|
// src/services/agent-web-app/AgentWebAppAttachmentRef.ts
|
|
21449
|
-
import { createCipheriv, createDecipheriv, createHash as
|
|
20758
|
+
import { createCipheriv, createDecipheriv, createHash as createHash5, randomBytes as randomBytes2 } from "crypto";
|
|
21450
20759
|
var TTL_MS = 15 * 6e4;
|
|
21451
20760
|
function resolveAgentWebAppAttachmentSecret(consoleSecret) {
|
|
21452
20761
|
return process.env.WEB_APP_ATTACHMENT_SECRET || process.env.AUTH_TOKEN_SECRET || process.env.JWT_SECRET || consoleSecret;
|
|
@@ -21455,7 +20764,7 @@ var AgentWebAppAttachmentRefService = class {
|
|
|
21455
20764
|
constructor(secret, now = Date.now) {
|
|
21456
20765
|
this.now = now;
|
|
21457
20766
|
if (!secret) throw new Error("Attachment signing secret is required");
|
|
21458
|
-
this.key =
|
|
20767
|
+
this.key = createHash5("sha256").update(secret, "utf8").digest();
|
|
21459
20768
|
}
|
|
21460
20769
|
sign(input) {
|
|
21461
20770
|
const payload = {
|
|
@@ -21517,7 +20826,7 @@ function decodeCanonical(value, expectedBytes) {
|
|
|
21517
20826
|
return decoded;
|
|
21518
20827
|
}
|
|
21519
20828
|
function digestUser(userId) {
|
|
21520
|
-
return
|
|
20829
|
+
return createHash5("sha256").update(userId, "utf8").digest("hex");
|
|
21521
20830
|
}
|
|
21522
20831
|
function isAttachmentPayload(value) {
|
|
21523
20832
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
@@ -21880,7 +21189,7 @@ function registerCapabilityBundleRoutes(app2, controller) {
|
|
|
21880
21189
|
import { ZodError as ZodError3 } from "zod";
|
|
21881
21190
|
|
|
21882
21191
|
// src/services/model-provider/ModelProviderService.ts
|
|
21883
|
-
import { randomUUID as
|
|
21192
|
+
import { randomUUID as randomUUID22 } from "crypto";
|
|
21884
21193
|
import { toModelKey } from "@axiom-lattice/protocols";
|
|
21885
21194
|
import {
|
|
21886
21195
|
assertSafeUpstreamUrl,
|
|
@@ -22219,7 +21528,7 @@ var unsafeReasonToErrorCode = {
|
|
|
22219
21528
|
var ModelProviderService = class {
|
|
22220
21529
|
constructor(deps) {
|
|
22221
21530
|
this.deps = deps;
|
|
22222
|
-
this.idFactory = deps.idFactory ?? (() =>
|
|
21531
|
+
this.idFactory = deps.idFactory ?? (() => randomUUID22());
|
|
22223
21532
|
}
|
|
22224
21533
|
/**
|
|
22225
21534
|
* List the tenant's provider configurations.
|
|
@@ -23410,12 +22719,12 @@ async function handleModelProviderChanged(payload, reconcile) {
|
|
|
23410
22719
|
}
|
|
23411
22720
|
|
|
23412
22721
|
// src/services/collaboration/ProjectRoomService.ts
|
|
23413
|
-
import { randomUUID as
|
|
22722
|
+
import { randomUUID as randomUUID23 } from "crypto";
|
|
23414
22723
|
var ProjectRoomService = class {
|
|
23415
22724
|
/** Creates a project room service from explicitly injected collaborators. */
|
|
23416
22725
|
constructor(deps) {
|
|
23417
22726
|
this.deps = deps;
|
|
23418
|
-
this.idFactory = deps.idFactory ??
|
|
22727
|
+
this.idFactory = deps.idFactory ?? randomUUID23;
|
|
23419
22728
|
}
|
|
23420
22729
|
/**
|
|
23421
22730
|
* Authorizes read access and ensures the project's main room.
|
|
@@ -23475,7 +22784,7 @@ var ProjectRoomService = class {
|
|
|
23475
22784
|
};
|
|
23476
22785
|
|
|
23477
22786
|
// src/services/collaboration/ProjectMembershipService.ts
|
|
23478
|
-
import { randomUUID as
|
|
22787
|
+
import { randomUUID as randomUUID24 } from "crypto";
|
|
23479
22788
|
var ProjectMembershipServiceError = class extends Error {
|
|
23480
22789
|
constructor(code, statusCode, message) {
|
|
23481
22790
|
super(message);
|
|
@@ -23484,14 +22793,14 @@ var ProjectMembershipServiceError = class extends Error {
|
|
|
23484
22793
|
this.name = "ProjectMembershipServiceError";
|
|
23485
22794
|
}
|
|
23486
22795
|
};
|
|
23487
|
-
var
|
|
22796
|
+
var membershipConflictNames = /* @__PURE__ */ new Set(["DuplicateProjectMembershipError", "ProjectMembershipIdConflictError"]);
|
|
23488
22797
|
function isMembershipConflict(error) {
|
|
23489
|
-
return error instanceof Error &&
|
|
22798
|
+
return error instanceof Error && membershipConflictNames.has(error.name);
|
|
23490
22799
|
}
|
|
23491
22800
|
var ProjectMembershipService = class {
|
|
23492
22801
|
constructor(deps) {
|
|
23493
22802
|
this.deps = deps;
|
|
23494
|
-
this.idFactory = deps.idFactory ??
|
|
22803
|
+
this.idFactory = deps.idFactory ?? randomUUID24;
|
|
23495
22804
|
this.mutationMutex = deps.projectMutationMutex ?? projectMutationMutex;
|
|
23496
22805
|
}
|
|
23497
22806
|
async list(actor3) {
|
|
@@ -23621,7 +22930,7 @@ var ProjectMembershipService = class {
|
|
|
23621
22930
|
};
|
|
23622
22931
|
|
|
23623
22932
|
// src/services/collaboration/ProjectRosterService.ts
|
|
23624
|
-
import { randomUUID as
|
|
22933
|
+
import { randomUUID as randomUUID25 } from "crypto";
|
|
23625
22934
|
var ProjectRosterServiceError = class extends Error {
|
|
23626
22935
|
/** Creates a stable roster service error. */
|
|
23627
22936
|
constructor(code, statusCode, message) {
|
|
@@ -23640,7 +22949,7 @@ var ProjectRosterService = class {
|
|
|
23640
22949
|
/** Creates a roster service from explicitly injected collaborators. */
|
|
23641
22950
|
constructor(deps) {
|
|
23642
22951
|
this.deps = deps;
|
|
23643
|
-
this.idFactory = deps.idFactory ??
|
|
22952
|
+
this.idFactory = deps.idFactory ?? randomUUID25;
|
|
23644
22953
|
this.mutationMutex = deps.projectMutationMutex ?? projectMutationMutex;
|
|
23645
22954
|
}
|
|
23646
22955
|
/**
|
|
@@ -23747,7 +23056,7 @@ var ProjectRosterService = class {
|
|
|
23747
23056
|
const agent = (await this.deps.agents.list(actor3.tenantId, actor3.userId)).find((item) => item.assistantId === assistantId);
|
|
23748
23057
|
if (!agent || agent.ownerUserId !== void 0) throw new ProjectRosterServiceError("ASSISTANT_NOT_FOUND", 404, "Agent not found");
|
|
23749
23058
|
const room = await this.deps.roomStore.ensureMainRoom({
|
|
23750
|
-
id:
|
|
23059
|
+
id: randomUUID25(),
|
|
23751
23060
|
tenantId: actor3.tenantId,
|
|
23752
23061
|
workspaceId: project.workspaceId,
|
|
23753
23062
|
projectId: actor3.projectId,
|
|
@@ -24091,7 +23400,7 @@ function virtualPublicProjectBot(project, room, agent, mentionName, now) {
|
|
|
24091
23400
|
}
|
|
24092
23401
|
|
|
24093
23402
|
// src/services/collaboration/RoomMessageService.ts
|
|
24094
|
-
import { createHash as
|
|
23403
|
+
import { createHash as createHash6, randomUUID as randomUUID26 } from "crypto";
|
|
24095
23404
|
|
|
24096
23405
|
// src/services/collaboration/ProjectBotMembershipSnapshot.ts
|
|
24097
23406
|
import { snapshotExactRecord as snapshotExactRecord5 } from "@axiom-lattice/protocols";
|
|
@@ -24180,7 +23489,7 @@ var RoomMessageService = class {
|
|
|
24180
23489
|
constructor(deps, options = {}) {
|
|
24181
23490
|
this.deps = deps;
|
|
24182
23491
|
this.idempotentOutcomes = /* @__PURE__ */ new Map();
|
|
24183
|
-
this.idFactory = deps.idFactory ??
|
|
23492
|
+
this.idFactory = deps.idFactory ?? randomUUID26;
|
|
24184
23493
|
const limit = options.idempotentOutcomeLimit ?? 1e3;
|
|
24185
23494
|
if (!Number.isSafeInteger(limit) || limit < 1) throw new RangeError("idempotentOutcomeLimit must be a positive safe integer");
|
|
24186
23495
|
this.idempotentOutcomeLimit = limit;
|
|
@@ -24394,7 +23703,7 @@ var RoomMessageService = class {
|
|
|
24394
23703
|
let idempotencyKey;
|
|
24395
23704
|
if (value.requestIdempotencyKey !== void 0) {
|
|
24396
23705
|
if (typeof value.requestIdempotencyKey !== "string" || !/^[\x21-\x7e]{1,200}$/.test(value.requestIdempotencyKey.trim())) throw new RoomMessageServiceError("INVALID_MESSAGE", 400, "Invalid idempotency key");
|
|
24397
|
-
idempotencyKey = `room-human:${actor3.userId}:${
|
|
23706
|
+
idempotencyKey = `room-human:${actor3.userId}:${createHash6("sha256").update(value.requestIdempotencyKey.trim(), "utf8").digest("hex")}`;
|
|
24398
23707
|
}
|
|
24399
23708
|
return { text, mentions, botIds, ...value.replyToMessageId === void 0 ? {} : { replyToMessageId: value.replyToMessageId }, ...idempotencyKey === void 0 ? {} : { idempotencyKey } };
|
|
24400
23709
|
}
|
|
@@ -24451,7 +23760,7 @@ function cloneRoomMessage(message) {
|
|
|
24451
23760
|
};
|
|
24452
23761
|
}
|
|
24453
23762
|
function fingerprintRequest(input) {
|
|
24454
|
-
return
|
|
23763
|
+
return createHash6("sha256").update(JSON.stringify({
|
|
24455
23764
|
text: input.text,
|
|
24456
23765
|
mentions: input.mentions,
|
|
24457
23766
|
replyToMessageId: input.replyToMessageId ?? null
|
|
@@ -24466,7 +23775,7 @@ import { ZodError as ZodError4 } from "zod";
|
|
|
24466
23775
|
import { toProjectRoomPublicMessage } from "@axiom-lattice/protocols";
|
|
24467
23776
|
|
|
24468
23777
|
// src/services/collaboration/RoomInterruptService.ts
|
|
24469
|
-
import { randomUUID as
|
|
23778
|
+
import { randomUUID as randomUUID27 } from "crypto";
|
|
24470
23779
|
var RESUMABLE_TASK_INTERRUPT_CODES = /* @__PURE__ */ new Set([
|
|
24471
23780
|
"PROJECT_TASK_NOT_RESUMABLE",
|
|
24472
23781
|
"PROJECT_TASK_NOT_READY",
|
|
@@ -24504,7 +23813,7 @@ var RoomInterruptService = class {
|
|
|
24504
23813
|
/** Creates the service from explicitly injected stores and dispatcher. */
|
|
24505
23814
|
constructor(deps) {
|
|
24506
23815
|
this.deps = deps;
|
|
24507
|
-
this.idFactory = deps.idFactory ??
|
|
23816
|
+
this.idFactory = deps.idFactory ?? randomUUID27;
|
|
24508
23817
|
}
|
|
24509
23818
|
/** Resolves a pending clarify interrupt with no answers. */
|
|
24510
23819
|
async skip(input) {
|
|
@@ -24867,7 +24176,7 @@ async function execute(reply, operation) {
|
|
|
24867
24176
|
}
|
|
24868
24177
|
|
|
24869
24178
|
// src/routes/cospace.ts
|
|
24870
|
-
import { randomUUID as
|
|
24179
|
+
import { randomUUID as randomUUID28 } from "crypto";
|
|
24871
24180
|
import { ZodError as ZodError6 } from "zod";
|
|
24872
24181
|
import {
|
|
24873
24182
|
generateDirectHumanProjectId,
|
|
@@ -24901,7 +24210,7 @@ async function computeUnread(deps, tenantId, userId, roomId, lastMessage) {
|
|
|
24901
24210
|
});
|
|
24902
24211
|
}
|
|
24903
24212
|
function registerCoSpaceRoutes(app2, deps) {
|
|
24904
|
-
const idFactory = deps.idFactory ?? (() =>
|
|
24213
|
+
const idFactory = deps.idFactory ?? (() => randomUUID28());
|
|
24905
24214
|
app2.get(
|
|
24906
24215
|
"/api/workspaces/:workspaceId/rooms",
|
|
24907
24216
|
async (request, reply) => {
|
|
@@ -25868,7 +25177,7 @@ function exactValues(value, required, optional = []) {
|
|
|
25868
25177
|
}
|
|
25869
25178
|
|
|
25870
25179
|
// src/services/collaboration/CoordinatorWakeNotifier.ts
|
|
25871
|
-
import { randomUUID as
|
|
25180
|
+
import { randomUUID as randomUUID29 } from "crypto";
|
|
25872
25181
|
import {
|
|
25873
25182
|
snapshotExactRecord as snapshotExactRecord7
|
|
25874
25183
|
} from "@axiom-lattice/protocols";
|
|
@@ -25884,7 +25193,7 @@ var CoordinatorWakeNotifier = class {
|
|
|
25884
25193
|
this.accepted = /* @__PURE__ */ new Set();
|
|
25885
25194
|
this.maxPending = deps.maxPending ?? 1024;
|
|
25886
25195
|
if (!Number.isSafeInteger(this.maxPending) || this.maxPending < 1) throw new RangeError("maxPending must be a positive safe integer");
|
|
25887
|
-
this.idFactory = deps.idFactory ??
|
|
25196
|
+
this.idFactory = deps.idFactory ?? randomUUID29;
|
|
25888
25197
|
}
|
|
25889
25198
|
/** Admits one notification without awaiting any store or dispatch operation. */
|
|
25890
25199
|
handle(value, anchorMessageId) {
|
|
@@ -26515,7 +25824,7 @@ var TaskInterruptCardProjector = class {
|
|
|
26515
25824
|
};
|
|
26516
25825
|
|
|
26517
25826
|
// src/services/collaboration/ProjectTaskObserver.ts
|
|
26518
|
-
import { createHash as
|
|
25827
|
+
import { createHash as createHash7 } from "crypto";
|
|
26519
25828
|
import {
|
|
26520
25829
|
createTaskRunBridge as createTaskRunBridge3,
|
|
26521
25830
|
probeThreadRunOwner as defaultProbeThreadRunOwner
|
|
@@ -27086,7 +26395,7 @@ var ProjectTaskObserver = class {
|
|
|
27086
26395
|
action: "activity",
|
|
27087
26396
|
summary: "Project task recovery warning",
|
|
27088
26397
|
detail: { type: "project_task_recovery_warning", phase, message },
|
|
27089
|
-
eventKey: `project-task-recovery-warning:${task.id}:${phase}:${
|
|
26398
|
+
eventKey: `project-task-recovery-warning:${task.id}:${phase}:${createHash7("sha256").update(message).digest("hex")}`
|
|
27090
26399
|
});
|
|
27091
26400
|
}
|
|
27092
26401
|
async safeWarning(task, phase, error) {
|
|
@@ -27329,7 +26638,7 @@ var ProjectTaskObserver = class {
|
|
|
27329
26638
|
}
|
|
27330
26639
|
}
|
|
27331
26640
|
async persistOverflowWarning(event) {
|
|
27332
|
-
const scopeDigest =
|
|
26641
|
+
const scopeDigest = createHash7("sha256").update(JSON.stringify([event.tenantId, event.workspaceId, event.projectId])).digest("hex");
|
|
27333
26642
|
try {
|
|
27334
26643
|
await this.deps.workItems.createIfAbsentByEventKey({
|
|
27335
26644
|
tenantId: event.tenantId,
|
|
@@ -27434,7 +26743,7 @@ function combineSignals(left, right) {
|
|
|
27434
26743
|
}
|
|
27435
26744
|
|
|
27436
26745
|
// src/services/collaboration/RoomProjectionService.ts
|
|
27437
|
-
import { createHash as
|
|
26746
|
+
import { createHash as createHash8 } from "crypto";
|
|
27438
26747
|
import {
|
|
27439
26748
|
PROJECT_ROOM_TASK_DELEGATED_LABEL,
|
|
27440
26749
|
PROJECT_ROOM_TASK_DELEGATED_SEPARATOR,
|
|
@@ -27655,7 +26964,7 @@ function safeRepairIdentity(value, scope) {
|
|
|
27655
26964
|
return taskId && eventKey && tenantId === scope.tenantId && workspaceId === scope.workspaceId && projectId === scope.projectId ? { taskId, eventKey } : void 0;
|
|
27656
26965
|
}
|
|
27657
26966
|
function tupleKey(prefix, values) {
|
|
27658
|
-
const digest =
|
|
26967
|
+
const digest = createHash8("sha256").update(JSON.stringify(values)).digest("hex");
|
|
27659
26968
|
return `${prefix}:${digest}`;
|
|
27660
26969
|
}
|
|
27661
26970
|
function parseProjectionInput(taskValue, itemValue) {
|
|
@@ -27815,7 +27124,7 @@ function isRecord10(value) {
|
|
|
27815
27124
|
import { taskLifecycleNotifier } from "@axiom-lattice/core";
|
|
27816
27125
|
|
|
27817
27126
|
// src/services/collaboration/ProjectRoomEventBroker.ts
|
|
27818
|
-
import { randomUUID as
|
|
27127
|
+
import { randomUUID as randomUUID30 } from "crypto";
|
|
27819
27128
|
import {
|
|
27820
27129
|
parseProjectRoomEventId,
|
|
27821
27130
|
ProjectRoomBrokerCapacityError,
|
|
@@ -27846,7 +27155,7 @@ var ProjectRoomEventBroker = class {
|
|
|
27846
27155
|
this.subscriberCount = 0;
|
|
27847
27156
|
this.usageClock = 0;
|
|
27848
27157
|
this.closed = false;
|
|
27849
|
-
this.epoch = options.epoch ??
|
|
27158
|
+
this.epoch = options.epoch ?? randomUUID30();
|
|
27850
27159
|
if (!UUID_PATTERN.test(this.epoch)) {
|
|
27851
27160
|
throw new TypeError("Project Room event epoch must be a lowercase canonical UUID");
|
|
27852
27161
|
}
|
|
@@ -28234,7 +27543,7 @@ function snapshotJson(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
|
28234
27543
|
}
|
|
28235
27544
|
|
|
28236
27545
|
// src/services/collaboration/ProjectRoomRealtimePublisher.ts
|
|
28237
|
-
import { createHash as
|
|
27546
|
+
import { createHash as createHash9 } from "crypto";
|
|
28238
27547
|
import {
|
|
28239
27548
|
projectRoomUserEventScope,
|
|
28240
27549
|
snapshotExactRecord as snapshotExactRecord11,
|
|
@@ -28356,7 +27665,7 @@ var BrokerProjectRoomRealtimePublisher = class {
|
|
|
28356
27665
|
try {
|
|
28357
27666
|
event = build();
|
|
28358
27667
|
if (!event) throw new Error("Invalid Project Room realtime projection");
|
|
28359
|
-
const dedupeKey =
|
|
27668
|
+
const dedupeKey = createHash9("sha256").update(JSON.stringify([type, event.scope.tenantId, event.scope.projectId, event.scope.roomId, event.sourceKey])).digest("hex");
|
|
28360
27669
|
if (this.sourceKeys.has(dedupeKey)) return;
|
|
28361
27670
|
this.deps.broker.publish(event.scope, event.draft, event.sourceKey);
|
|
28362
27671
|
this.sourceKeys.set(dedupeKey, true);
|
|
@@ -28601,12 +27910,21 @@ function createProjectRoomRealtimeRuntime(deps) {
|
|
|
28601
27910
|
shutdownTimeoutMs: deps.shutdownTimeoutMs
|
|
28602
27911
|
});
|
|
28603
27912
|
}
|
|
27913
|
+
var PUSH_DEDUPE_LIMIT = 2e3;
|
|
28604
27914
|
function withPushNotifier(target, notifier) {
|
|
27915
|
+
const pushedMessageIds = /* @__PURE__ */ new Set();
|
|
28605
27916
|
return new Proxy(target, {
|
|
28606
27917
|
get(inner, prop, receiver) {
|
|
28607
27918
|
if (prop === "messageCreated") {
|
|
28608
27919
|
return (message) => {
|
|
28609
27920
|
inner.messageCreated(message);
|
|
27921
|
+
if (pushedMessageIds.has(message.id)) return;
|
|
27922
|
+
pushedMessageIds.add(message.id);
|
|
27923
|
+
while (pushedMessageIds.size > PUSH_DEDUPE_LIMIT) {
|
|
27924
|
+
const oldest = pushedMessageIds.values().next().value;
|
|
27925
|
+
if (oldest === void 0) break;
|
|
27926
|
+
pushedMessageIds.delete(oldest);
|
|
27927
|
+
}
|
|
28610
27928
|
void notifier.notifyMessage(message).catch(() => void 0);
|
|
28611
27929
|
};
|
|
28612
27930
|
}
|
|
@@ -29491,6 +28809,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
29491
28809
|
const taskWorkItemStore = getStoreLattice28("default", "taskWorkItem").store;
|
|
29492
28810
|
const projectTaskEnabled = options.projectTaskEnabled ?? process.env.AXIOM_PROJECT_TASK_EXECUTION_ENABLED !== "false";
|
|
29493
28811
|
const accessService = new ProjectAccessService({ projectStore, membershipStore: projectMembershipStore, userTenantLinkStore });
|
|
28812
|
+
setA2AProjectAccess(accessService);
|
|
29494
28813
|
const realtimeMode = resolveProjectRoomRealtimeMode();
|
|
29495
28814
|
const realtimeLog = options.projectTaskLog ?? { warn: () => void 0 };
|
|
29496
28815
|
const roomMessageRetention = createRoomMessageRetentionJob({
|
|
@@ -29521,7 +28840,14 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
29521
28840
|
log: realtimeLog
|
|
29522
28841
|
}) : void 0;
|
|
29523
28842
|
if (projectRoomRealtimeRuntime) {
|
|
29524
|
-
|
|
28843
|
+
const runtime = projectRoomRealtimeRuntime;
|
|
28844
|
+
const unsubscribeProjectRoomMessages = projectRoomMessageNotifier.subscribe((message) => {
|
|
28845
|
+
runtime.publisher.messageCreated(message);
|
|
28846
|
+
});
|
|
28847
|
+
app2.addHook("onClose", async () => {
|
|
28848
|
+
unsubscribeProjectRoomMessages();
|
|
28849
|
+
await runtime.close();
|
|
28850
|
+
});
|
|
29525
28851
|
const workspaceRoomEventsService = new WorkspaceRoomEventsService({
|
|
29526
28852
|
broker: projectRoomRealtimeRuntime.broker,
|
|
29527
28853
|
listMemberRooms: createWorkspaceMemberRoomLister({
|
|
@@ -29664,7 +28990,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
29664
28990
|
});
|
|
29665
28991
|
}
|
|
29666
28992
|
if (projectTaskComposition) app2.addHook("onClose", async () => projectTaskComposition.lease.release());
|
|
29667
|
-
const taskThreadService = projectTaskComposition?.lease.runtime.threads ?? new ProjectTaskThreadService({ threads: threadStore, idFactory:
|
|
28993
|
+
const taskThreadService = projectTaskComposition?.lease.runtime.threads ?? new ProjectTaskThreadService({ threads: threadStore, idFactory: randomUUID31 });
|
|
29668
28994
|
const taskLifecycle = projectTaskComposition?.lease.runtime.lifecycle ?? createTaskLifecycleService({ taskStore, workItemStore: taskWorkItemStore });
|
|
29669
28995
|
const reassignmentAuthorizer = createProjectTaskReassignmentAuthorizer(
|
|
29670
28996
|
new ProjectTaskOwnerPolicy(projectBotMembershipStore),
|
|
@@ -29845,7 +29171,8 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
29845
29171
|
configuredAgentResolver: createConfiguredAgentResolver({
|
|
29846
29172
|
hydrate: (tenantId) => agentLatticeManager5.initializeStoredAssistantsForTenant(tenantId),
|
|
29847
29173
|
has: (tenantId, assistantId) => agentLatticeManager5.hasAgentLatticeWithTenant(tenantId, assistantId)
|
|
29848
|
-
})
|
|
29174
|
+
}),
|
|
29175
|
+
projectAccess: accessService
|
|
29849
29176
|
})
|
|
29850
29177
|
});
|
|
29851
29178
|
registerAgentWebAppRuntimeRoutes(app2, {
|
|
@@ -29855,7 +29182,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
29855
29182
|
userTenantLinkStore,
|
|
29856
29183
|
ensureCoordinator: (scope) => coordinatorEnsurer.ensure(scope),
|
|
29857
29184
|
log: realtimeLog
|
|
29858
|
-
})),
|
|
29185
|
+
}), accessService),
|
|
29859
29186
|
taskController: createTaskController({
|
|
29860
29187
|
access: {
|
|
29861
29188
|
requireProjectAccess: async (input) => {
|
|
@@ -30151,7 +29478,7 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
30151
29478
|
userTenantLinkStore,
|
|
30152
29479
|
ensureCoordinator: (scope) => coordinatorEnsurer.ensure(scope),
|
|
30153
29480
|
log: realtimeLog
|
|
30154
|
-
}));
|
|
29481
|
+
}), accessService);
|
|
30155
29482
|
registerDatabaseConfigRoutes(app2);
|
|
30156
29483
|
registerMetricsServerConfigRoutes(app2);
|
|
30157
29484
|
connectionRoutes(app2);
|
|
@@ -30349,7 +29676,7 @@ function tryCreateProjectTaskRuntime(input) {
|
|
|
30349
29676
|
function createRuntime(input, stores, log2) {
|
|
30350
29677
|
const controller = new AbortController();
|
|
30351
29678
|
const mutex = new ProjectTaskExecutionMutex();
|
|
30352
|
-
const threads = new ProjectTaskThreadService({ threads: input.threadStore, idFactory:
|
|
29679
|
+
const threads = new ProjectTaskThreadService({ threads: input.threadStore, idFactory: randomUUID31 });
|
|
30353
29680
|
const lifecycle = createTaskLifecycleService({ taskStore: input.taskStore, workItemStore: input.taskWorkItemStore });
|
|
30354
29681
|
const projection = new RoomProjectionService({
|
|
30355
29682
|
messages: input.projectRoomMessageStore,
|
|
@@ -30358,7 +29685,7 @@ function createRuntime(input, stores, log2) {
|
|
|
30358
29685
|
warnings: input.taskWorkItemStore,
|
|
30359
29686
|
log: log2,
|
|
30360
29687
|
realtime: input.realtime,
|
|
30361
|
-
idFactory:
|
|
29688
|
+
idFactory: randomUUID31
|
|
30362
29689
|
});
|
|
30363
29690
|
const runService = new ProjectTaskRunService({
|
|
30364
29691
|
tasks: input.taskStore,
|
|
@@ -31182,7 +30509,7 @@ var collectionRegistration = {
|
|
|
31182
30509
|
|
|
31183
30510
|
// src/export_registrations/channel-installation.registration.ts
|
|
31184
30511
|
import { getStoreLattice as getStoreLattice35 } from "@axiom-lattice/core";
|
|
31185
|
-
import { randomUUID as
|
|
30512
|
+
import { randomUUID as randomUUID32 } from "crypto";
|
|
31186
30513
|
var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
31187
30514
|
var PUBLIC_CHANNELS = /* @__PURE__ */ new Set(["lark", "email", "slack", "wechat", "wecom"]);
|
|
31188
30515
|
function isPublicChannel(channel) {
|
|
@@ -31344,7 +30671,7 @@ var channelInstallationRegistration = {
|
|
|
31344
30671
|
}
|
|
31345
30672
|
id3 = sourceId;
|
|
31346
30673
|
} else {
|
|
31347
|
-
id3 =
|
|
30674
|
+
id3 = randomUUID32();
|
|
31348
30675
|
}
|
|
31349
30676
|
await store2.createInstallation(tenantId, id3, createInput);
|
|
31350
30677
|
return { newId: id3 };
|
|
@@ -31792,50 +31119,6 @@ var ChannelAdapterRegistry = class {
|
|
|
31792
31119
|
}
|
|
31793
31120
|
};
|
|
31794
31121
|
|
|
31795
|
-
// src/router/middlewares/channelSharedState.ts
|
|
31796
|
-
import { createClient as createClient2 } from "redis";
|
|
31797
|
-
var clientPromise;
|
|
31798
|
-
async function redis() {
|
|
31799
|
-
const url = process.env.REDIS_URL?.trim();
|
|
31800
|
-
if (!url) return void 0;
|
|
31801
|
-
if (!clientPromise) {
|
|
31802
|
-
clientPromise = (async () => {
|
|
31803
|
-
const client = createClient2({ url });
|
|
31804
|
-
client.on("error", () => void 0);
|
|
31805
|
-
await client.connect();
|
|
31806
|
-
return client;
|
|
31807
|
-
})();
|
|
31808
|
-
}
|
|
31809
|
-
try {
|
|
31810
|
-
const client = await clientPromise;
|
|
31811
|
-
return client.isOpen ? client : void 0;
|
|
31812
|
-
} catch {
|
|
31813
|
-
clientPromise = void 0;
|
|
31814
|
-
return void 0;
|
|
31815
|
-
}
|
|
31816
|
-
}
|
|
31817
|
-
async function claimDedupKey(key, ttlMs) {
|
|
31818
|
-
try {
|
|
31819
|
-
const client = await redis();
|
|
31820
|
-
if (!client) return void 0;
|
|
31821
|
-
const result = await client.set(key, "1", { NX: true, PX: ttlMs });
|
|
31822
|
-
return result === "OK";
|
|
31823
|
-
} catch {
|
|
31824
|
-
return void 0;
|
|
31825
|
-
}
|
|
31826
|
-
}
|
|
31827
|
-
async function incrementRateCounter(key, windowMs) {
|
|
31828
|
-
try {
|
|
31829
|
-
const client = await redis();
|
|
31830
|
-
if (!client) return void 0;
|
|
31831
|
-
const count = await client.incr(key);
|
|
31832
|
-
if (count === 1) await client.pExpire(key, windowMs);
|
|
31833
|
-
return count;
|
|
31834
|
-
} catch {
|
|
31835
|
-
return void 0;
|
|
31836
|
-
}
|
|
31837
|
-
}
|
|
31838
|
-
|
|
31839
31122
|
// src/router/middlewares/deduplication.ts
|
|
31840
31123
|
var processedMessages = /* @__PURE__ */ new Map();
|
|
31841
31124
|
function createDeduplicationMiddleware(ttlMs = 5 * 60 * 1e3) {
|
|
@@ -31948,7 +31231,7 @@ function createAuditLoggerMiddleware() {
|
|
|
31948
31231
|
import { setBindingRegistry, setMenuRegistry, setEvalRunService } from "@axiom-lattice/core";
|
|
31949
31232
|
|
|
31950
31233
|
// src/channels/wecom/WecomChannelAdapter.ts
|
|
31951
|
-
import { randomUUID as
|
|
31234
|
+
import { randomUUID as randomUUID33 } from "crypto";
|
|
31952
31235
|
import { z as z13 } from "zod";
|
|
31953
31236
|
import * as WecomAiBot from "@wecom/aibot-node-sdk";
|
|
31954
31237
|
|
|
@@ -32312,7 +31595,7 @@ function streamIdFor(replyTarget) {
|
|
|
32312
31595
|
const key = replyKeyForTarget(replyTarget);
|
|
32313
31596
|
let streamId = streamIdsByReqId.get(key);
|
|
32314
31597
|
if (!streamId) {
|
|
32315
|
-
streamId =
|
|
31598
|
+
streamId = randomUUID33();
|
|
32316
31599
|
streamIdsByReqId.set(key, streamId);
|
|
32317
31600
|
if (streamIdsByReqId.size > MAX_TRACKED_STREAMS) {
|
|
32318
31601
|
const oldest = streamIdsByReqId.keys().next().value;
|
|
@@ -32904,7 +32187,7 @@ import {
|
|
|
32904
32187
|
agentInstanceManager as agentInstanceManager13,
|
|
32905
32188
|
createSandboxProvider,
|
|
32906
32189
|
TokenCache,
|
|
32907
|
-
mcpManager as
|
|
32190
|
+
mcpManager as mcpManager2,
|
|
32908
32191
|
convertToConnection as convertToConnection2,
|
|
32909
32192
|
createTrustedAgentMessageDispatcher as createTrustedAgentMessageDispatcher2,
|
|
32910
32193
|
ChannelConnectionLeader,
|
|
@@ -32924,7 +32207,7 @@ import {
|
|
|
32924
32207
|
COLLECTION_CHANGED_TOPIC,
|
|
32925
32208
|
vectorStoreLatticeManager as vectorStoreLatticeManager2,
|
|
32926
32209
|
observabilityLatticeManager,
|
|
32927
|
-
getSandboxPluginCatalog as
|
|
32210
|
+
getSandboxPluginCatalog as getSandboxPluginCatalog2,
|
|
32928
32211
|
getSandBoxManager as getSandBoxManager4,
|
|
32929
32212
|
installPluginHost,
|
|
32930
32213
|
ThreadExecutionSupervisor,
|
|
@@ -32935,7 +32218,7 @@ import {
|
|
|
32935
32218
|
} from "@axiom-lattice/core";
|
|
32936
32219
|
|
|
32937
32220
|
// src/services/chunk/redisAppendLog.ts
|
|
32938
|
-
import { createClient as
|
|
32221
|
+
import { createClient as createClient2 } from "redis";
|
|
32939
32222
|
var VALUE_FIELD = "v";
|
|
32940
32223
|
var START_ID = "0-0";
|
|
32941
32224
|
var ChunkLogCorruptionError = class extends Error {
|
|
@@ -32952,7 +32235,7 @@ var ChunkLogCorruptionError = class extends Error {
|
|
|
32952
32235
|
}
|
|
32953
32236
|
};
|
|
32954
32237
|
async function createRedisAppendLog(url, options = {}) {
|
|
32955
|
-
const client =
|
|
32238
|
+
const client = createClient2({
|
|
32956
32239
|
url,
|
|
32957
32240
|
disableOfflineQueue: true,
|
|
32958
32241
|
socket: {
|
|
@@ -33142,7 +32425,7 @@ function readField(fields, name) {
|
|
|
33142
32425
|
}
|
|
33143
32426
|
|
|
33144
32427
|
// src/services/run-cancel/RedisRunCancelNotifier.ts
|
|
33145
|
-
import { createClient as
|
|
32428
|
+
import { createClient as createClient3 } from "redis";
|
|
33146
32429
|
import {
|
|
33147
32430
|
runCancelSignalSchema as runCancelSignalSchema2
|
|
33148
32431
|
} from "@axiom-lattice/protocols";
|
|
@@ -33543,7 +32826,7 @@ function createRedisRunCancelNotifier(options) {
|
|
|
33543
32826
|
});
|
|
33544
32827
|
}
|
|
33545
32828
|
function createNodeRedisClient2(url) {
|
|
33546
|
-
const client =
|
|
32829
|
+
const client = createClient3({
|
|
33547
32830
|
url,
|
|
33548
32831
|
disableOfflineQueue: true,
|
|
33549
32832
|
socket: {
|
|
@@ -33607,7 +32890,7 @@ import {
|
|
|
33607
32890
|
snapshotExactRecord as snapshotExactRecord15,
|
|
33608
32891
|
MessageChunkTypes as MessageChunkTypes4
|
|
33609
32892
|
} from "@axiom-lattice/protocols";
|
|
33610
|
-
import { randomUUID as
|
|
32893
|
+
import { randomUUID as randomUUID34 } from "crypto";
|
|
33611
32894
|
|
|
33612
32895
|
// src/services/channel-reply/channelReplyRuntimeRegistry.ts
|
|
33613
32896
|
var active;
|
|
@@ -33962,7 +33245,7 @@ var _MessageRouter = class _MessageRouter {
|
|
|
33962
33245
|
}
|
|
33963
33246
|
if (!threadId) {
|
|
33964
33247
|
const threadStore = getStoreLattice39("default", "thread").store;
|
|
33965
|
-
const newThreadId =
|
|
33248
|
+
const newThreadId = randomUUID34();
|
|
33966
33249
|
console.log({
|
|
33967
33250
|
event: "dispatch:thread:create",
|
|
33968
33251
|
agentId,
|
|
@@ -34001,7 +33284,7 @@ var _MessageRouter = class _MessageRouter {
|
|
|
34001
33284
|
senderId: message.sender.id,
|
|
34002
33285
|
contentLength: message.content.text.length
|
|
34003
33286
|
}, "Dispatching to agent");
|
|
34004
|
-
const inputMessageId =
|
|
33287
|
+
const inputMessageId = randomUUID34();
|
|
34005
33288
|
const replyTarget = internalRoom ? correlatedRoomReplyTarget(message.replyTarget, inputMessageId) : message.replyTarget;
|
|
34006
33289
|
const replyAdapter = replyTarget ? this.adapterRegistry.get(replyTarget.adapterChannel) : void 0;
|
|
34007
33290
|
if (options.trustedMessageOptions && (!this.trustedDispatcher || !replyTarget || !replyAdapter)) {
|
|
@@ -34198,7 +33481,7 @@ var _MessageRouter = class _MessageRouter {
|
|
|
34198
33481
|
};
|
|
34199
33482
|
const runLedger = getStoreLattice39("default", "agentRun").store;
|
|
34200
33483
|
const jobStore = getStoreLattice39("default", "channelReplyJob").store;
|
|
34201
|
-
const runId =
|
|
33484
|
+
const runId = randomUUID34();
|
|
34202
33485
|
await jobStore.create({
|
|
34203
33486
|
runId,
|
|
34204
33487
|
tenantId,
|
|
@@ -34850,14 +34133,14 @@ async function prepareProjectTaskRuntime(runtime, log2) {
|
|
|
34850
34133
|
import { setPluginDeploymentService } from "@axiom-lattice/core";
|
|
34851
34134
|
|
|
34852
34135
|
// src/services/plugins/PluginDeploymentService.ts
|
|
34853
|
-
import { randomUUID as
|
|
34136
|
+
import { randomUUID as randomUUID35 } from "crypto";
|
|
34854
34137
|
import {
|
|
34855
34138
|
PLUGIN_HOST_DIR,
|
|
34856
34139
|
PluginDeploymentRuntimeRegistry
|
|
34857
34140
|
} from "@axiom-lattice/core";
|
|
34858
34141
|
|
|
34859
34142
|
// src/services/plugins/pluginDeploymentNaming.ts
|
|
34860
|
-
import { createHash as
|
|
34143
|
+
import { createHash as createHash10 } from "crypto";
|
|
34861
34144
|
var PLUGIN_GUEST_PORT = 8080;
|
|
34862
34145
|
var SANDBOX_NAME_HASH_LENGTH = 16;
|
|
34863
34146
|
function pluginSandboxName(tenantId, pluginType) {
|
|
@@ -34867,7 +34150,7 @@ function pluginSandboxName(tenantId, pluginType) {
|
|
|
34867
34150
|
if (!pluginType || typeof pluginType !== "string") {
|
|
34868
34151
|
throw new Error("pluginSandboxName: pluginType must be a non-empty string");
|
|
34869
34152
|
}
|
|
34870
|
-
const hash =
|
|
34153
|
+
const hash = createHash10("sha256").update(`${tenantId}\0${pluginType}`).digest("hex").slice(0, SANDBOX_NAME_HASH_LENGTH);
|
|
34871
34154
|
return `plugin-${hash}`;
|
|
34872
34155
|
}
|
|
34873
34156
|
|
|
@@ -34994,7 +34277,7 @@ var PluginDeploymentService = class {
|
|
|
34994
34277
|
const failedAt = this.nowIso();
|
|
34995
34278
|
await this.store.upsert(
|
|
34996
34279
|
this.buildRecord({
|
|
34997
|
-
id: existing?.id ??
|
|
34280
|
+
id: existing?.id ?? randomUUID35(),
|
|
34998
34281
|
tenantId,
|
|
34999
34282
|
pluginType,
|
|
35000
34283
|
pluginVersion: manifest.version,
|
|
@@ -35016,7 +34299,7 @@ var PluginDeploymentService = class {
|
|
|
35016
34299
|
);
|
|
35017
34300
|
}
|
|
35018
34301
|
const record = this.buildRecord({
|
|
35019
|
-
id: existing?.id ??
|
|
34302
|
+
id: existing?.id ?? randomUUID35(),
|
|
35020
34303
|
tenantId,
|
|
35021
34304
|
pluginType,
|
|
35022
34305
|
pluginVersion: manifest.version,
|
|
@@ -37444,7 +36727,7 @@ function createAgentRunRetentionJob(input) {
|
|
|
37444
36727
|
}
|
|
37445
36728
|
|
|
37446
36729
|
// src/services/run-task/RedisRunTaskWake.ts
|
|
37447
|
-
import { createClient as
|
|
36730
|
+
import { createClient as createClient4 } from "redis";
|
|
37448
36731
|
var RUN_TASK_WAKE_CHANNEL = "run-task:wake";
|
|
37449
36732
|
var DEFAULT_OPERATION_TIMEOUT_MS = 2e3;
|
|
37450
36733
|
var DEFAULT_RETRY_DELAYS_MS = [500, 2e3, 5e3, 1e4];
|
|
@@ -37837,7 +37120,7 @@ function createConfiguredRedisRunTaskWake(options) {
|
|
|
37837
37120
|
return createRedisRunTaskWake({ ...options, url });
|
|
37838
37121
|
}
|
|
37839
37122
|
function createNodeRedisClient3(url) {
|
|
37840
|
-
const client =
|
|
37123
|
+
const client = createClient4({
|
|
37841
37124
|
url,
|
|
37842
37125
|
disableOfflineQueue: true,
|
|
37843
37126
|
socket: {
|
|
@@ -38928,7 +38211,7 @@ async function restoreMcpConnections() {
|
|
|
38928
38211
|
logger8.info(`Restoring ${configs.length} MCP server connections...`);
|
|
38929
38212
|
const deps = {
|
|
38930
38213
|
store: store2,
|
|
38931
|
-
manager:
|
|
38214
|
+
manager: mcpManager2,
|
|
38932
38215
|
convertToConnection: convertToConnection2
|
|
38933
38216
|
};
|
|
38934
38217
|
const results = await Promise.allSettled(
|
|
@@ -38966,6 +38249,8 @@ var start = async (config) => {
|
|
|
38966
38249
|
logger8 = loggerLattice.client;
|
|
38967
38250
|
}
|
|
38968
38251
|
app.decorate("loggerLattice", loggerLattice);
|
|
38252
|
+
const rateLimitService = createRateLimitService(config?.rateLimits);
|
|
38253
|
+
setRateLimitService(rateLimitService);
|
|
38969
38254
|
const observabilityProvider = observabilityLatticeManager.getDefault();
|
|
38970
38255
|
if (observabilityProvider) {
|
|
38971
38256
|
try {
|
|
@@ -39205,9 +38490,9 @@ var start = async (config) => {
|
|
|
39205
38490
|
projectRoomRealtimeRuntime
|
|
39206
38491
|
});
|
|
39207
38492
|
try {
|
|
39208
|
-
const { A2AAuthService: A2AAuthService2, parseEnvKeys: parseEnvKeys2 } = await import("./A2AAuthService-
|
|
39209
|
-
const { registerA2AStandardRoutes } = await import("./a2a-standard-
|
|
39210
|
-
const a2a = await import("./a2a-
|
|
38493
|
+
const { A2AAuthService: A2AAuthService2, parseEnvKeys: parseEnvKeys2 } = await import("./A2AAuthService-UKN53ZGP.mjs");
|
|
38494
|
+
const { registerA2AStandardRoutes } = await import("./a2a-standard-MD7WNDTP.mjs");
|
|
38495
|
+
const a2a = await import("./a2a-YLKZE5JG.mjs");
|
|
39211
38496
|
const a2aKeyStore = getStoreLattice42("default", "a2aApiKey").store;
|
|
39212
38497
|
const assistantStore = getStoreLattice42("default", "assistant").store;
|
|
39213
38498
|
const projectStore = getStoreLattice42("default", "project").store;
|
|
@@ -39236,18 +38521,17 @@ var start = async (config) => {
|
|
|
39236
38521
|
});
|
|
39237
38522
|
}
|
|
39238
38523
|
try {
|
|
39239
|
-
const { registerOpenRoutes } = await import("./open-
|
|
39240
|
-
const { registerOpenSessionRoutes } = await import("./open-session-
|
|
39241
|
-
const { registerOpenCatalogRoutes } = await import("./open-catalog-
|
|
39242
|
-
const { registerOpenFilesRoutes } = await import("./open-files-
|
|
38524
|
+
const { registerOpenRoutes } = await import("./open-27ZPLBIW.mjs");
|
|
38525
|
+
const { registerOpenSessionRoutes } = await import("./open-session-CLZT3HVG.mjs");
|
|
38526
|
+
const { registerOpenCatalogRoutes } = await import("./open-catalog-NVGP6SQP.mjs");
|
|
38527
|
+
const { registerOpenFilesRoutes } = await import("./open-files-JPB2NBL6.mjs");
|
|
39243
38528
|
const { registerOpenAuditRoutes } = await import("./open-audit-UJ3NXCGW.mjs");
|
|
39244
|
-
const { registerOpenExposureRoutes } = await import("./open-exposure-
|
|
39245
|
-
const { openLattice } = await import("./openLattice-
|
|
39246
|
-
const { OpenRateLimiter } = await import("./openRateLimiter-XEOL3A5G.mjs");
|
|
38529
|
+
const { registerOpenExposureRoutes } = await import("./open-exposure-HGYT5VFC.mjs");
|
|
38530
|
+
const { openLattice } = await import("./openLattice-D5YTSZBY.mjs");
|
|
39247
38531
|
const { createKbProvider } = await import("./kbProvider-2D6DZ34N.mjs");
|
|
39248
38532
|
const { createOpenSandboxProvider } = await import("./sandboxProvider-FILMFVIM.mjs");
|
|
39249
38533
|
const { createAgentProvider } = await import("./agentProvider-X4FVQPKW.mjs");
|
|
39250
|
-
const { registerExposedPluginTools } = await import("./registerExposedPlugins-
|
|
38534
|
+
const { registerExposedPluginTools } = await import("./registerExposedPlugins-2JGXSMAL.mjs");
|
|
39251
38535
|
const { CollectionService: CollectionService2 } = await import("./collection_service-RTRJEQFL.mjs");
|
|
39252
38536
|
openLattice.register(createKbProvider(new CollectionService2()));
|
|
39253
38537
|
openLattice.register(createOpenSandboxProvider());
|
|
@@ -39263,18 +38547,7 @@ var start = async (config) => {
|
|
|
39263
38547
|
})
|
|
39264
38548
|
);
|
|
39265
38549
|
await registerExposedPluginTools();
|
|
39266
|
-
|
|
39267
|
-
process.env.OPEN_RATE_LIMIT_PER_MINUTE
|
|
39268
|
-
);
|
|
39269
|
-
const openAgentRateLimitPerMinute = Number(
|
|
39270
|
-
process.env.OPEN_AGENT_RATE_LIMIT_PER_MINUTE
|
|
39271
|
-
);
|
|
39272
|
-
registerOpenRoutes(app, {
|
|
39273
|
-
rateLimiter: new OpenRateLimiter({
|
|
39274
|
-
...Number.isFinite(openRateLimitPerMinute) && openRateLimitPerMinute > 0 ? { defaultPerMinute: openRateLimitPerMinute } : {},
|
|
39275
|
-
...Number.isFinite(openAgentRateLimitPerMinute) && openAgentRateLimitPerMinute > 0 ? { agentPerMinute: openAgentRateLimitPerMinute } : {}
|
|
39276
|
-
})
|
|
39277
|
-
});
|
|
38550
|
+
registerOpenRoutes(app, { rateLimits: rateLimitService });
|
|
39278
38551
|
registerOpenSessionRoutes(app);
|
|
39279
38552
|
registerOpenCatalogRoutes(app);
|
|
39280
38553
|
registerOpenFilesRoutes(app);
|
|
@@ -39287,7 +38560,7 @@ var start = async (config) => {
|
|
|
39287
38560
|
});
|
|
39288
38561
|
}
|
|
39289
38562
|
try {
|
|
39290
|
-
const { registerGatewaySandboxOpenCredentialProvider } = await import("./sandboxOpenCredentialProvider-
|
|
38563
|
+
const { registerGatewaySandboxOpenCredentialProvider } = await import("./sandboxOpenCredentialProvider-RTYOYRCT.mjs");
|
|
39291
38564
|
registerGatewaySandboxOpenCredentialProvider((error) => {
|
|
39292
38565
|
logger8.warn("sandbox open-credential provider failed", { error });
|
|
39293
38566
|
});
|
|
@@ -39319,7 +38592,7 @@ var start = async (config) => {
|
|
|
39319
38592
|
wiring: {
|
|
39320
38593
|
store: pluginDeploymentStore,
|
|
39321
38594
|
sandboxManager: getSandBoxManager4(),
|
|
39322
|
-
catalog:
|
|
38595
|
+
catalog: getSandboxPluginCatalog2(),
|
|
39323
38596
|
installPluginHost,
|
|
39324
38597
|
limits: readPluginDeploymentLimits(),
|
|
39325
38598
|
serviceKey: process.env.MICROSANDBOX_API_KEY,
|
|
@@ -39346,7 +38619,7 @@ var start = async (config) => {
|
|
|
39346
38619
|
}
|
|
39347
38620
|
}
|
|
39348
38621
|
try {
|
|
39349
|
-
const { ResourceController } = await import("./resources-
|
|
38622
|
+
const { ResourceController } = await import("./resources-YD5DOPGD.mjs");
|
|
39350
38623
|
const sharedResourceStore = getStoreLattice42("default", "sharedResource").store;
|
|
39351
38624
|
const cache = new TokenCache();
|
|
39352
38625
|
const resourceController = new ResourceController({
|
|
@@ -39356,6 +38629,13 @@ var start = async (config) => {
|
|
|
39356
38629
|
logger: logger8
|
|
39357
38630
|
});
|
|
39358
38631
|
registerResourceRoutes(app, resourceController);
|
|
38632
|
+
const { registerMcpAppShareRoutes } = await import("./mcp-app-shares-SHPBJQXS.mjs");
|
|
38633
|
+
const { makeMcpAppHandlers, resolveMcpAppDeps } = await import("./mcp-apps-QVUK6UBA.mjs");
|
|
38634
|
+
registerMcpAppShareRoutes(app, {
|
|
38635
|
+
store: sharedResourceStore,
|
|
38636
|
+
handlers: makeMcpAppHandlers(resolveMcpAppDeps()),
|
|
38637
|
+
rateLimits: rateLimitService
|
|
38638
|
+
});
|
|
39359
38639
|
logger8.info("Resource share routes registered");
|
|
39360
38640
|
} catch (err) {
|
|
39361
38641
|
logger8.warn("Resource share infrastructure unavailable", {
|
|
@@ -39435,7 +38715,6 @@ var start = async (config) => {
|
|
|
39435
38715
|
"assistant-changed": (payload) => handleAssistantChanged(payload, async (tenantId) => {
|
|
39436
38716
|
await agentLatticeManager6.initializeStoredAssistantsForTenant(tenantId);
|
|
39437
38717
|
invalidateAgentReflectionCache(tenantId);
|
|
39438
|
-
invalidatePluginReflectionCache(tenantId);
|
|
39439
38718
|
}),
|
|
39440
38719
|
[AGENT_LIFECYCLE_TOPIC]: async (payload) => {
|
|
39441
38720
|
handleAgentLifecycle(payload);
|
|
@@ -39443,7 +38722,7 @@ var start = async (config) => {
|
|
|
39443
38722
|
[A2A_KEY_CHANGED_TOPIC]: (payload) => handleA2AKeyChanged(payload, () => refreshStoreKeyMap()),
|
|
39444
38723
|
[MCP_CONFIG_CHANGED_TOPIC]: (payload) => reconcileMcpConfigChange(payload, {
|
|
39445
38724
|
store: getStoreLattice42("default", "mcp").store,
|
|
39446
|
-
manager:
|
|
38725
|
+
manager: mcpManager2,
|
|
39447
38726
|
convertToConnection: convertToConnection2
|
|
39448
38727
|
}),
|
|
39449
38728
|
[COLLECTION_CHANGED_TOPIC]: async (payload) => {
|
|
@@ -39455,8 +38734,7 @@ var start = async (config) => {
|
|
|
39455
38734
|
[PLUGIN_CATALOG_CHANGED_TOPIC]: async (payload) => {
|
|
39456
38735
|
const tenantId = payload?.tenantId;
|
|
39457
38736
|
if (typeof tenantId === "string" && tenantId.length > 0) {
|
|
39458
|
-
|
|
39459
|
-
invalidatePluginReflectionCache(tenantId);
|
|
38737
|
+
getSandboxPluginCatalog2().invalidate(tenantId);
|
|
39460
38738
|
invalidateAgentReflectionCache(tenantId);
|
|
39461
38739
|
await getMcpUiResourceResolver()?.invalidateTenantPlugins(tenantId);
|
|
39462
38740
|
}
|