@axiom-lattice/gateway 4.2.0 → 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{A2AAuthService-DK5X6VIL.mjs → A2AAuthService-7UGQ7GMW.mjs} +3 -2
- package/dist/{WechatChannelAdapter-WSDKR4OA.mjs → WechatChannelAdapter-7WHE5UGY.mjs} +2 -1
- package/dist/{WechatChannelAdapter-WSDKR4OA.mjs.map → WechatChannelAdapter-7WHE5UGY.mjs.map} +1 -1
- package/dist/{a2a-7N3WDAOP.mjs → a2a-FGYX2HH3.mjs} +71 -32
- package/dist/a2a-FGYX2HH3.mjs.map +1 -0
- package/dist/{a2a-standard-WC2BSOFV.mjs → a2a-standard-VEQBXBMM.mjs} +93 -115
- package/dist/a2a-standard-VEQBXBMM.mjs.map +1 -0
- package/dist/agentProvider-X4FVQPKW.mjs +88 -0
- package/dist/agentProvider-X4FVQPKW.mjs.map +1 -0
- package/dist/chunk-2POW27EI.mjs +27 -0
- package/dist/chunk-2POW27EI.mjs.map +1 -0
- package/dist/chunk-52SUWMOX.mjs +121 -0
- package/dist/chunk-52SUWMOX.mjs.map +1 -0
- package/dist/chunk-GF4GGTWJ.mjs +164 -0
- package/dist/chunk-GF4GGTWJ.mjs.map +1 -0
- package/dist/{chunk-2HOCF46L.mjs → chunk-GPHOYR3X.mjs} +33 -11
- package/dist/chunk-GPHOYR3X.mjs.map +1 -0
- package/dist/chunk-NFEGQTCC.mjs +27 -0
- package/dist/chunk-PWHUWFXL.mjs +173 -0
- package/dist/chunk-PWHUWFXL.mjs.map +1 -0
- package/dist/chunk-QUT2DS4R.mjs +50 -0
- package/dist/chunk-QUT2DS4R.mjs.map +1 -0
- package/dist/chunk-TJAUXMYJ.mjs +109 -0
- package/dist/chunk-TJAUXMYJ.mjs.map +1 -0
- package/dist/chunk-WKNZ7GBC.mjs +56 -0
- package/dist/chunk-WKNZ7GBC.mjs.map +1 -0
- package/dist/collection_service-RTRJEQFL.mjs +8 -0
- package/dist/embed/agent-chat-loader.js +1 -1
- package/dist/embed/{embed-page-AgentDetailSideApp-6CVXM3P3.js → embed-page-AgentDetailSideApp-KGYKTMZR.js} +1 -1
- package/dist/embed/{embed-page-AgentDetailSideApp-DRGKJ6C5.css → embed-page-AgentDetailSideApp-O6G4NJ7I.css} +1 -1
- package/dist/embed/{embed-page-AgentGovernanceWorkbench-4B3NJPCY.js → embed-page-AgentGovernanceWorkbench-F42AJH77.js} +1 -1
- package/dist/embed/embed-page-AgentGovernanceWorkbench-SFZNVMUH.css +1 -0
- package/dist/embed/embed-page-MessageGraph-ACHQORG7.js +6 -0
- package/dist/embed/{embed-page-ReactChart-OG5Z43H7.js → embed-page-ReactChart-FGUHXBED.js} +1 -1
- package/dist/embed/{embed-page-SkillFlow-GS4OUCJJ.js → embed-page-SkillFlow-SFZ5HLMK.js} +1 -1
- package/dist/embed/{embed-page-TasksSideApp-I6Z7BOT2.js → embed-page-TasksSideApp-4GY5YBTN.js} +1 -1
- package/dist/embed/{embed-page-TeamWorkspace-LSCUIJDA.js → embed-page-TeamWorkspace-YWE6ZTLB.js} +4 -4
- package/dist/embed/{embed-page-TopologyRuntimeView-RY7NOUB7.js → embed-page-TopologyRuntimeView-MKFPCHT3.js} +1 -1
- package/dist/embed/{embed-page-WorkflowAutomationView-RNKIKDUX.js → embed-page-WorkflowAutomationView-WT6VH5HD.js} +1 -1
- package/dist/embed/{embed-page-chunk-7CFGO35V.js → embed-page-chunk-3PY2YGBU.js} +1 -1
- package/dist/embed/embed-page-chunk-3WXEO6CG.js +245 -0
- package/dist/embed/embed-page-chunk-42S7N5Y5.js +4084 -0
- package/dist/embed/{embed-page-chunk-SU5GXLKX.js → embed-page-chunk-67U2KZFL.js} +4 -4
- package/dist/embed/{embed-page-chunk-4X5XHAMX.js → embed-page-chunk-74BPRLSV.js} +4 -4
- package/dist/embed/{embed-page-chunk-DVHOG6AY.js → embed-page-chunk-AC6X2XRH.js} +1 -1
- package/dist/embed/{embed-page-chunk-4BIOW547.js → embed-page-chunk-FDID7LZP.js} +1 -1
- package/dist/embed/{embed-page-chunk-JLWIJ4BP.js → embed-page-chunk-FU2KMTSK.js} +1 -1
- package/dist/embed/{embed-page-chunk-EPEKIAZP.js → embed-page-chunk-HS5VQFWH.js} +1 -1
- package/dist/embed/{embed-page-chunk-Q32Y7CP2.js → embed-page-chunk-IV5C4DYL.js} +1 -1
- package/dist/embed/{embed-page-chunk-KGX7G7XQ.js → embed-page-chunk-KEL6XU6R.js} +1 -1
- package/dist/embed/{embed-page-chunk-AYOVLRHX.js → embed-page-chunk-MGZK7ELC.js} +94 -69
- package/dist/embed/{embed-page-chunk-BZI3YCE7.js → embed-page-chunk-N46WJ2FS.js} +1 -1
- package/dist/embed/{embed-page-chunk-KG5A66WX.js → embed-page-chunk-O4QK5LWZ.js} +83 -83
- package/dist/embed/{embed-page-chunk-ESLOGPBN.js → embed-page-chunk-Z7USDLHI.js} +1 -1
- package/dist/embed/{embed-page-code-highlighter-TBT4ICNZ.js → embed-page-code-highlighter-Y6CQA4CN.js} +1 -1
- package/dist/embed/{embed-page-mermaid-TBO3M7GX.js → embed-page-mermaid-CW4QCAH3.js} +1 -1
- package/dist/embed/embed-page.css +1 -1
- package/dist/embed/embed-page.js +1 -1
- package/dist/index.js +2074 -619
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +345 -346
- package/dist/index.mjs.map +1 -1
- package/dist/kbProvider-2D6DZ34N.mjs +50 -0
- package/dist/kbProvider-2D6DZ34N.mjs.map +1 -0
- package/dist/{mcp-configs-IIKQM5GM.mjs → mcp-configs-WCY5EXCW.mjs} +2 -1
- package/dist/mcp-configs-WCY5EXCW.mjs.map +1 -0
- package/dist/{mcpTransportRegistry-XMJ5Y2RG.mjs → mcpTransportRegistry-VXUVJKBC.mjs} +2 -1
- package/dist/mcpTransportRegistry-VXUVJKBC.mjs.map +1 -0
- package/dist/open-HH7RKGML.mjs +260 -0
- package/dist/open-HH7RKGML.mjs.map +1 -0
- package/dist/open-audit-UJ3NXCGW.mjs +32 -0
- package/dist/open-audit-UJ3NXCGW.mjs.map +1 -0
- package/dist/open-catalog-WYS2AENM.mjs +59 -0
- package/dist/open-catalog-WYS2AENM.mjs.map +1 -0
- package/dist/open-exposure-FK4G6O6L.mjs +67 -0
- package/dist/open-exposure-FK4G6O6L.mjs.map +1 -0
- package/dist/open-files-GVRMK5PL.mjs +146 -0
- package/dist/open-files-GVRMK5PL.mjs.map +1 -0
- package/dist/open-session-3VN65PRR.mjs +53 -0
- package/dist/open-session-3VN65PRR.mjs.map +1 -0
- package/dist/openLattice-GAAGQJST.mjs +16 -0
- package/dist/openLattice-GAAGQJST.mjs.map +1 -0
- package/dist/registerExposedPlugins-63EUF4VS.mjs +99 -0
- package/dist/registerExposedPlugins-63EUF4VS.mjs.map +1 -0
- package/dist/{resources-VA7LSDKN.mjs → resources-SRQRKW5G.mjs} +47 -4
- package/dist/resources-SRQRKW5G.mjs.map +1 -0
- package/dist/sandboxProvider-I3P66VXT.mjs +10 -0
- package/dist/sandboxProvider-I3P66VXT.mjs.map +1 -0
- package/dist/{sender-PX32VSHB.mjs → sender-PLDU5EZ3.mjs} +3 -1
- package/dist/{sender-PX32VSHB.mjs.map → sender-PLDU5EZ3.mjs.map} +1 -1
- package/package.json +7 -7
- package/dist/a2a-7N3WDAOP.mjs.map +0 -1
- package/dist/a2a-standard-WC2BSOFV.mjs.map +0 -1
- package/dist/chunk-2HOCF46L.mjs.map +0 -1
- package/dist/embed/embed-page-chunk-A2LQIHX4.js +0 -261
- package/dist/embed/embed-page-chunk-OWGBADV6.js +0 -3880
- package/dist/open-DCAOL5CG.mjs +0 -176
- package/dist/open-DCAOL5CG.mjs.map +0 -1
- package/dist/resources-VA7LSDKN.mjs.map +0 -1
- /package/dist/{A2AAuthService-DK5X6VIL.mjs.map → A2AAuthService-7UGQ7GMW.mjs.map} +0 -0
- /package/dist/{mcp-configs-IIKQM5GM.mjs.map → chunk-NFEGQTCC.mjs.map} +0 -0
- /package/dist/{mcpTransportRegistry-XMJ5Y2RG.mjs.map → collection_service-RTRJEQFL.mjs.map} +0 -0
- /package/dist/embed/{embed-page-AgentGovernanceWorkbench-SDS3GBCC.css → embed-page-MessageGraph-TYOOATYV.css} +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OpenAuditService,
|
|
3
|
+
OpenCredentialService
|
|
4
|
+
} from "./chunk-52SUWMOX.mjs";
|
|
5
|
+
import {
|
|
6
|
+
openLattice
|
|
7
|
+
} from "./chunk-GF4GGTWJ.mjs";
|
|
8
|
+
import {
|
|
9
|
+
resolveContextSandbox
|
|
10
|
+
} from "./chunk-TJAUXMYJ.mjs";
|
|
11
|
+
import "./chunk-WKNZ7GBC.mjs";
|
|
12
|
+
import "./chunk-NFEGQTCC.mjs";
|
|
13
|
+
|
|
14
|
+
// src/routes/open-files.ts
|
|
15
|
+
import { getStoreLattice } from "@axiom-lattice/core";
|
|
16
|
+
function extractBearer(request) {
|
|
17
|
+
const header = request.headers.authorization;
|
|
18
|
+
if (!header?.startsWith("Bearer ")) return void 0;
|
|
19
|
+
return header.slice("Bearer ".length).trim() || void 0;
|
|
20
|
+
}
|
|
21
|
+
function safePath(raw) {
|
|
22
|
+
if (typeof raw !== "string" || raw.length === 0) return null;
|
|
23
|
+
if (raw.includes("..")) return null;
|
|
24
|
+
return raw.startsWith("/") ? raw : `/${raw}`;
|
|
25
|
+
}
|
|
26
|
+
function registerOpenFilesRoutes(app, deps = {}) {
|
|
27
|
+
const openAuth = deps.openAuth ?? new OpenCredentialService(
|
|
28
|
+
getStoreLattice("default", "a2aApiKey").store,
|
|
29
|
+
getStoreLattice("default", "project").store
|
|
30
|
+
);
|
|
31
|
+
const audit = deps.audit ?? (() => {
|
|
32
|
+
try {
|
|
33
|
+
const store = getStoreLattice("default", "openAudit").store;
|
|
34
|
+
return new OpenAuditService(store);
|
|
35
|
+
} catch {
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
})();
|
|
39
|
+
app.addContentTypeParser(
|
|
40
|
+
"application/octet-stream",
|
|
41
|
+
{ parseAs: "buffer" },
|
|
42
|
+
(_req, body, done) => done(null, body)
|
|
43
|
+
);
|
|
44
|
+
app.get("/open/sandbox/files/download", async (request, reply) => {
|
|
45
|
+
const context = await openAuth.resolve(extractBearer(request));
|
|
46
|
+
if (!context) return reply.status(401).send({ error: "AUTH_FAILED" });
|
|
47
|
+
const path = safePath(request.query.path);
|
|
48
|
+
if (!path) return reply.status(400).send({ error: "PATH_REQUIRED" });
|
|
49
|
+
if (!openLattice.isAllowed(context.grants, "sandbox_files_read")) {
|
|
50
|
+
return reply.status(403).send({ error: "GRANT_DENIED" });
|
|
51
|
+
}
|
|
52
|
+
const startedAt = Date.now();
|
|
53
|
+
try {
|
|
54
|
+
const sandbox = await resolveContextSandbox({
|
|
55
|
+
tenantId: context.tenantId,
|
|
56
|
+
projectId: context.projectId,
|
|
57
|
+
workspaceId: context.workspaceId,
|
|
58
|
+
runConfig: {}
|
|
59
|
+
});
|
|
60
|
+
const data = await sandbox.file.downloadFile({ file: path });
|
|
61
|
+
await audit?.record({
|
|
62
|
+
tenantId: context.tenantId,
|
|
63
|
+
credentialId: context.credentialId,
|
|
64
|
+
credentialKind: context.kind,
|
|
65
|
+
projectId: context.projectId,
|
|
66
|
+
domain: "sandbox",
|
|
67
|
+
action: "files_read",
|
|
68
|
+
args: { path },
|
|
69
|
+
status: "ok",
|
|
70
|
+
durationMs: Date.now() - startedAt
|
|
71
|
+
});
|
|
72
|
+
return reply.status(200).type("application/octet-stream").header("Content-Disposition", "attachment").send(data);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
await audit?.record({
|
|
75
|
+
tenantId: context.tenantId,
|
|
76
|
+
credentialId: context.credentialId,
|
|
77
|
+
credentialKind: context.kind,
|
|
78
|
+
projectId: context.projectId,
|
|
79
|
+
domain: "sandbox",
|
|
80
|
+
action: "files_read",
|
|
81
|
+
args: { path },
|
|
82
|
+
status: "error",
|
|
83
|
+
errorCode: "EXECUTION_ERROR",
|
|
84
|
+
durationMs: Date.now() - startedAt
|
|
85
|
+
});
|
|
86
|
+
return reply.status(502).send({
|
|
87
|
+
error: err instanceof Error ? err.message : "SANDBOX_ERROR"
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
app.post("/open/sandbox/files/upload", async (request, reply) => {
|
|
92
|
+
const context = await openAuth.resolve(extractBearer(request));
|
|
93
|
+
if (!context) return reply.status(401).send({ error: "AUTH_FAILED" });
|
|
94
|
+
const path = safePath(request.query.path);
|
|
95
|
+
if (!path) return reply.status(400).send({ error: "PATH_REQUIRED" });
|
|
96
|
+
if (!openLattice.isAllowed(context.grants, "sandbox_files_write")) {
|
|
97
|
+
return reply.status(403).send({ error: "GRANT_DENIED" });
|
|
98
|
+
}
|
|
99
|
+
const body = request.body;
|
|
100
|
+
if (!Buffer.isBuffer(body)) {
|
|
101
|
+
return reply.status(400).send({ error: "BINARY_BODY_REQUIRED" });
|
|
102
|
+
}
|
|
103
|
+
const startedAt = Date.now();
|
|
104
|
+
try {
|
|
105
|
+
const sandbox = await resolveContextSandbox({
|
|
106
|
+
tenantId: context.tenantId,
|
|
107
|
+
projectId: context.projectId,
|
|
108
|
+
workspaceId: context.workspaceId,
|
|
109
|
+
runConfig: {}
|
|
110
|
+
});
|
|
111
|
+
await sandbox.file.uploadFile({ file: path, data: body });
|
|
112
|
+
await audit?.record({
|
|
113
|
+
tenantId: context.tenantId,
|
|
114
|
+
credentialId: context.credentialId,
|
|
115
|
+
credentialKind: context.kind,
|
|
116
|
+
projectId: context.projectId,
|
|
117
|
+
domain: "sandbox",
|
|
118
|
+
action: "files_write",
|
|
119
|
+
args: { path, bytes: body.length },
|
|
120
|
+
status: "ok",
|
|
121
|
+
durationMs: Date.now() - startedAt
|
|
122
|
+
});
|
|
123
|
+
return reply.status(200).send({ success: true, path });
|
|
124
|
+
} catch (err) {
|
|
125
|
+
await audit?.record({
|
|
126
|
+
tenantId: context.tenantId,
|
|
127
|
+
credentialId: context.credentialId,
|
|
128
|
+
credentialKind: context.kind,
|
|
129
|
+
projectId: context.projectId,
|
|
130
|
+
domain: "sandbox",
|
|
131
|
+
action: "files_write",
|
|
132
|
+
args: { path, bytes: body.length },
|
|
133
|
+
status: "error",
|
|
134
|
+
errorCode: "EXECUTION_ERROR",
|
|
135
|
+
durationMs: Date.now() - startedAt
|
|
136
|
+
});
|
|
137
|
+
return reply.status(502).send({
|
|
138
|
+
error: err instanceof Error ? err.message : "SANDBOX_ERROR"
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
export {
|
|
144
|
+
registerOpenFilesRoutes
|
|
145
|
+
};
|
|
146
|
+
//# sourceMappingURL=open-files-GVRMK5PL.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/routes/open-files.ts"],"sourcesContent":["/**\n * Open sandbox file transfer (binary sugar): download/upload raw bytes.\n *\n * MCP is awkward for binary transfer, so these REST sugar endpoints exist\n * alongside /open/mcp. They share the same credential pipeline and\n * authorization kernel — only the transport differs.\n */\n\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\nimport { getStoreLattice } from \"@axiom-lattice/core\";\nimport type { A2AApiKeyStore, OpenAuditStore, ProjectStore } from \"@axiom-lattice/protocols\";\nimport { OpenCredentialService } from \"../services/open/openCredentialService\";\nimport { openLattice } from \"../services/open/openLattice\";\nimport { resolveContextSandbox } from \"../services/open/providers/sandboxProvider\";\nimport { OpenAuditService } from \"../services/open/openAuditService\";\n\nexport interface OpenFilesRouteDeps {\n openAuth?: OpenCredentialService;\n audit?: OpenAuditService;\n}\n\nfunction extractBearer(request: FastifyRequest): string | undefined {\n const header = request.headers.authorization;\n if (!header?.startsWith(\"Bearer \")) return undefined;\n return header.slice(\"Bearer \".length).trim() || undefined;\n}\n\nfunction safePath(raw: unknown): string | null {\n if (typeof raw !== \"string\" || raw.length === 0) return null;\n if (raw.includes(\"..\")) return null;\n return raw.startsWith(\"/\") ? raw : `/${raw}`;\n}\n\nexport function registerOpenFilesRoutes(\n app: FastifyInstance,\n deps: OpenFilesRouteDeps = {},\n): void {\n const openAuth =\n deps.openAuth ??\n new OpenCredentialService(\n getStoreLattice(\"default\", \"a2aApiKey\").store as A2AApiKeyStore,\n getStoreLattice(\"default\", \"project\").store as ProjectStore,\n );\n\n const audit =\n deps.audit ??\n (() => {\n try {\n const store = getStoreLattice(\"default\", \"openAudit\").store as OpenAuditStore;\n return new OpenAuditService(store);\n } catch {\n return undefined;\n }\n })();\n\n // Buffer raw octet-stream bodies so upload can accept arbitrary bytes.\n app.addContentTypeParser(\n \"application/octet-stream\",\n { parseAs: \"buffer\" },\n (_req, body, done) => done(null, body),\n );\n\n app.get(\"/open/sandbox/files/download\", async (request: FastifyRequest, reply: FastifyReply) => {\n const context = await openAuth.resolve(extractBearer(request));\n if (!context) return reply.status(401).send({ error: \"AUTH_FAILED\" });\n const path = safePath((request.query as { path?: string }).path);\n if (!path) return reply.status(400).send({ error: \"PATH_REQUIRED\" });\n if (!openLattice.isAllowed(context.grants, \"sandbox_files_read\")) {\n return reply.status(403).send({ error: \"GRANT_DENIED\" });\n }\n const startedAt = Date.now();\n try {\n const sandbox = await resolveContextSandbox({\n tenantId: context.tenantId,\n projectId: context.projectId,\n workspaceId: context.workspaceId,\n runConfig: {},\n });\n const data = await sandbox.file.downloadFile({ file: path });\n await audit?.record({\n tenantId: context.tenantId,\n credentialId: context.credentialId,\n credentialKind: context.kind,\n projectId: context.projectId,\n domain: \"sandbox\",\n action: \"files_read\",\n args: { path },\n status: \"ok\",\n durationMs: Date.now() - startedAt,\n });\n return reply\n .status(200)\n .type(\"application/octet-stream\")\n .header(\"Content-Disposition\", \"attachment\")\n .send(data);\n } catch (err) {\n await audit?.record({\n tenantId: context.tenantId,\n credentialId: context.credentialId,\n credentialKind: context.kind,\n projectId: context.projectId,\n domain: \"sandbox\",\n action: \"files_read\",\n args: { path },\n status: \"error\",\n errorCode: \"EXECUTION_ERROR\",\n durationMs: Date.now() - startedAt,\n });\n return reply.status(502).send({\n error: err instanceof Error ? err.message : \"SANDBOX_ERROR\",\n });\n }\n });\n\n app.post(\"/open/sandbox/files/upload\", async (request: FastifyRequest, reply: FastifyReply) => {\n const context = await openAuth.resolve(extractBearer(request));\n if (!context) return reply.status(401).send({ error: \"AUTH_FAILED\" });\n const path = safePath((request.query as { path?: string }).path);\n if (!path) return reply.status(400).send({ error: \"PATH_REQUIRED\" });\n if (!openLattice.isAllowed(context.grants, \"sandbox_files_write\")) {\n return reply.status(403).send({ error: \"GRANT_DENIED\" });\n }\n const body = request.body;\n if (!Buffer.isBuffer(body)) {\n return reply.status(400).send({ error: \"BINARY_BODY_REQUIRED\" });\n }\n const startedAt = Date.now();\n try {\n const sandbox = await resolveContextSandbox({\n tenantId: context.tenantId,\n projectId: context.projectId,\n workspaceId: context.workspaceId,\n runConfig: {},\n });\n await sandbox.file.uploadFile({ file: path, data: body });\n await audit?.record({\n tenantId: context.tenantId,\n credentialId: context.credentialId,\n credentialKind: context.kind,\n projectId: context.projectId,\n domain: \"sandbox\",\n action: \"files_write\",\n args: { path, bytes: body.length },\n status: \"ok\",\n durationMs: Date.now() - startedAt,\n });\n return reply.status(200).send({ success: true, path });\n } catch (err) {\n await audit?.record({\n tenantId: context.tenantId,\n credentialId: context.credentialId,\n credentialKind: context.kind,\n projectId: context.projectId,\n domain: \"sandbox\",\n action: \"files_write\",\n args: { path, bytes: body.length },\n status: \"error\",\n errorCode: \"EXECUTION_ERROR\",\n durationMs: Date.now() - startedAt,\n });\n return reply.status(502).send({\n error: err instanceof Error ? err.message : \"SANDBOX_ERROR\",\n });\n }\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
openLattice
|
|
3
|
+
} from "./chunk-GF4GGTWJ.mjs";
|
|
4
|
+
import {
|
|
5
|
+
BROWSER_GRANTS
|
|
6
|
+
} from "./chunk-2POW27EI.mjs";
|
|
7
|
+
import {
|
|
8
|
+
init_openToken,
|
|
9
|
+
signOpenToken
|
|
10
|
+
} from "./chunk-WKNZ7GBC.mjs";
|
|
11
|
+
import "./chunk-NFEGQTCC.mjs";
|
|
12
|
+
|
|
13
|
+
// src/routes/open-session.ts
|
|
14
|
+
init_openToken();
|
|
15
|
+
import { getStoreLattice } from "@axiom-lattice/core";
|
|
16
|
+
function registerOpenSessionRoutes(app) {
|
|
17
|
+
app.post(
|
|
18
|
+
"/open/session",
|
|
19
|
+
async (request, reply) => {
|
|
20
|
+
const body = request.body ?? {};
|
|
21
|
+
const shareToken = body.shareToken;
|
|
22
|
+
if (typeof shareToken !== "string" || shareToken.length === 0) {
|
|
23
|
+
return reply.status(400).send({ error: "SHARE_TOKEN_REQUIRED" });
|
|
24
|
+
}
|
|
25
|
+
const store = getStoreLattice("default", "sharedResource").store;
|
|
26
|
+
const record = await store.findByToken(shareToken);
|
|
27
|
+
if (!record || record.revoked) {
|
|
28
|
+
return reply.status(404).send({ error: "SHARE_NOT_FOUND" });
|
|
29
|
+
}
|
|
30
|
+
if (record.expiresAt && new Date(record.expiresAt) < /* @__PURE__ */ new Date()) {
|
|
31
|
+
return reply.status(410).send({ error: "SHARE_EXPIRED" });
|
|
32
|
+
}
|
|
33
|
+
const grants = BROWSER_GRANTS;
|
|
34
|
+
const browserToken = signOpenToken({
|
|
35
|
+
kind: "browser_token",
|
|
36
|
+
tenantId: record.tenantId,
|
|
37
|
+
projectId: record.projectId,
|
|
38
|
+
shareId: record.token,
|
|
39
|
+
grants
|
|
40
|
+
});
|
|
41
|
+
const actions = await openLattice.catalogFor(grants, { tenantId: record.tenantId });
|
|
42
|
+
return reply.status(200).send({
|
|
43
|
+
browserToken,
|
|
44
|
+
expiresAt: Date.now() + 15 * 60 * 1e3,
|
|
45
|
+
actions: actions.map((a) => a.toolName)
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
export {
|
|
51
|
+
registerOpenSessionRoutes
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=open-session-3VN65PRR.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/routes/open-session.ts"],"sourcesContent":["/**\n * Open session exchange: downgrades a share token into a short-lived browser\n * token scoped to the platform browser whitelist. The share link is the key;\n * grants come from the whitelist (V1: kb read-only), not the caller.\n */\n\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\nimport { getStoreLattice } from \"@axiom-lattice/core\";\nimport type { SharedResourceStore } from \"@axiom-lattice/protocols\";\nimport { signOpenToken } from \"../services/open/openToken\";\nimport { BROWSER_GRANTS } from \"../services/open/previewToken\";\nimport type { OpenToolDescriptor } from \"../services/open/openLattice\";\nimport { openLattice } from \"../services/open/openLattice\";\n\nexport function registerOpenSessionRoutes(app: FastifyInstance): void {\n app.post(\n \"/open/session\",\n async (request: FastifyRequest, reply: FastifyReply) => {\n const body = (request.body ?? {}) as { shareToken?: string };\n const shareToken = body.shareToken;\n if (typeof shareToken !== \"string\" || shareToken.length === 0) {\n return reply.status(400).send({ error: \"SHARE_TOKEN_REQUIRED\" });\n }\n\n const store = getStoreLattice(\"default\", \"sharedResource\")\n .store as SharedResourceStore;\n const record = await store.findByToken(shareToken);\n if (!record || record.revoked) {\n return reply.status(404).send({ error: \"SHARE_NOT_FOUND\" });\n }\n if (record.expiresAt && new Date(record.expiresAt) < new Date()) {\n return reply.status(410).send({ error: \"SHARE_EXPIRED\" });\n }\n\n const grants = BROWSER_GRANTS;\n const browserToken = signOpenToken({\n kind: \"browser_token\",\n tenantId: record.tenantId,\n projectId: record.projectId,\n shareId: record.token,\n grants,\n });\n\n const actions: OpenToolDescriptor[] = await openLattice.catalogFor(grants, { tenantId: record.tenantId });\n\n return reply.status(200).send({\n browserToken,\n expiresAt: Date.now() + 15 * 60 * 1000,\n actions: actions.map((a) => a.toolName),\n });\n },\n );\n}\n"],"mappings":";;;;;;;;;;;;;AASA;AAFA,SAAS,uBAAuB;AAOzB,SAAS,0BAA0B,KAA4B;AACpE,MAAI;AAAA,IACF;AAAA,IACA,OAAO,SAAyB,UAAwB;AACtD,YAAM,OAAQ,QAAQ,QAAQ,CAAC;AAC/B,YAAM,aAAa,KAAK;AACxB,UAAI,OAAO,eAAe,YAAY,WAAW,WAAW,GAAG;AAC7D,eAAO,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,uBAAuB,CAAC;AAAA,MACjE;AAEA,YAAM,QAAQ,gBAAgB,WAAW,gBAAgB,EACtD;AACH,YAAM,SAAS,MAAM,MAAM,YAAY,UAAU;AACjD,UAAI,CAAC,UAAU,OAAO,SAAS;AAC7B,eAAO,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MAC5D;AACA,UAAI,OAAO,aAAa,IAAI,KAAK,OAAO,SAAS,IAAI,oBAAI,KAAK,GAAG;AAC/D,eAAO,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,gBAAgB,CAAC;AAAA,MAC1D;AAEA,YAAM,SAAS;AACf,YAAM,eAAe,cAAc;AAAA,QACjC,MAAM;AAAA,QACN,UAAU,OAAO;AAAA,QACjB,WAAW,OAAO;AAAA,QAClB,SAAS,OAAO;AAAA,QAChB;AAAA,MACF,CAAC;AAED,YAAM,UAAgC,MAAM,YAAY,WAAW,QAAQ,EAAE,UAAU,OAAO,SAAS,CAAC;AAExG,aAAO,MAAM,OAAO,GAAG,EAAE,KAAK;AAAA,QAC5B;AAAA,QACA,WAAW,KAAK,IAAI,IAAI,KAAK,KAAK;AAAA,QAClC,SAAS,QAAQ,IAAI,CAAC,MAAM,EAAE,QAAQ;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ActionNotFoundError,
|
|
3
|
+
GrantDeniedError,
|
|
4
|
+
OpenLattice,
|
|
5
|
+
ValidationError,
|
|
6
|
+
openLattice
|
|
7
|
+
} from "./chunk-GF4GGTWJ.mjs";
|
|
8
|
+
import "./chunk-NFEGQTCC.mjs";
|
|
9
|
+
export {
|
|
10
|
+
ActionNotFoundError,
|
|
11
|
+
GrantDeniedError,
|
|
12
|
+
OpenLattice,
|
|
13
|
+
ValidationError,
|
|
14
|
+
openLattice
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=openLattice-GAAGQJST.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
openLattice
|
|
3
|
+
} from "./chunk-GF4GGTWJ.mjs";
|
|
4
|
+
import "./chunk-NFEGQTCC.mjs";
|
|
5
|
+
|
|
6
|
+
// src/services/open/registerExposedPlugins.ts
|
|
7
|
+
import { PluginRegistry } from "@axiom-lattice/core";
|
|
8
|
+
|
|
9
|
+
// src/services/open/pluginExposeAdapter.ts
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
function schemaOf(tool) {
|
|
12
|
+
return tool.lc_kwargs?.schema ?? tool.schema ?? z.object({}).passthrough();
|
|
13
|
+
}
|
|
14
|
+
function createPluginProvider(domain, tools, options = {}) {
|
|
15
|
+
function toAction(info) {
|
|
16
|
+
return {
|
|
17
|
+
name: info.name,
|
|
18
|
+
description: info.description || info.tool.description || `Plugin tool ${info.name}`,
|
|
19
|
+
schema: schemaOf(info.tool),
|
|
20
|
+
annotations: {
|
|
21
|
+
readOnlyHint: info.readOnly ?? false,
|
|
22
|
+
destructiveHint: info.destructive ?? false
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const actions = tools.map(toAction);
|
|
27
|
+
return {
|
|
28
|
+
domain,
|
|
29
|
+
label: options.label ?? domain,
|
|
30
|
+
source: "plugin",
|
|
31
|
+
scopeKind: "tenant",
|
|
32
|
+
actions,
|
|
33
|
+
execute: async (action, args, ctx) => {
|
|
34
|
+
const info = tools.find((t) => t.name === action);
|
|
35
|
+
if (!info) {
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: "text", text: `Unknown action: ${action}` }],
|
|
38
|
+
isError: true
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const exeConfig = {
|
|
42
|
+
configurable: {
|
|
43
|
+
runConfig: {
|
|
44
|
+
tenantId: ctx.tenantId,
|
|
45
|
+
_resolvedConnections: ctx.runConfig._resolvedConnections ?? []
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const output = await info.tool.invoke(args, exeConfig);
|
|
50
|
+
return { content: [{ type: "text", text: output }] };
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/services/open/registerExposedPlugins.ts
|
|
56
|
+
async function registerExposedPluginTools() {
|
|
57
|
+
for (const key of PluginRegistry.list()) {
|
|
58
|
+
const plugin = PluginRegistry.get(key);
|
|
59
|
+
if (!plugin?.middleware) continue;
|
|
60
|
+
const openExpose = plugin.meta.openExpose;
|
|
61
|
+
const exposed = openExpose ? openExpose.map(
|
|
62
|
+
(entry) => typeof entry === "string" ? { name: entry, description: "", expose: true } : {
|
|
63
|
+
name: entry.name,
|
|
64
|
+
description: "",
|
|
65
|
+
expose: true,
|
|
66
|
+
readOnly: entry.readOnly,
|
|
67
|
+
destructive: entry.destructive
|
|
68
|
+
}
|
|
69
|
+
) : plugin.meta.tools?.filter((t) => t.expose) ?? [];
|
|
70
|
+
if (exposed.length === 0) continue;
|
|
71
|
+
try {
|
|
72
|
+
const middleware = await plugin.middleware({
|
|
73
|
+
...plugin.meta.defaultConfig ?? {},
|
|
74
|
+
connectAll: true
|
|
75
|
+
});
|
|
76
|
+
const toolObjects = middleware.tools ?? [];
|
|
77
|
+
const matched = exposed.map((tm) => {
|
|
78
|
+
const tool = toolObjects.find((t) => t.name === tm.name);
|
|
79
|
+
if (!tool) return null;
|
|
80
|
+
const annotations = tm;
|
|
81
|
+
return {
|
|
82
|
+
name: tm.name,
|
|
83
|
+
description: tm.description,
|
|
84
|
+
tool,
|
|
85
|
+
readOnly: annotations.readOnly,
|
|
86
|
+
destructive: annotations.destructive
|
|
87
|
+
};
|
|
88
|
+
}).filter(Boolean);
|
|
89
|
+
if (matched.length === 0) continue;
|
|
90
|
+
const provider = createPluginProvider(key, matched, { label: plugin.meta.name });
|
|
91
|
+
openLattice.register(provider);
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export {
|
|
97
|
+
registerExposedPluginTools
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=registerExposedPlugins-63EUF4VS.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/services/open/registerExposedPlugins.ts","../src/services/open/pluginExposeAdapter.ts"],"sourcesContent":["import { PluginRegistry } from \"@axiom-lattice/core\";\nimport { openLattice } from \"./openLattice\";\nimport { createPluginProvider } from \"./pluginExposeAdapter\";\n\n/** Walk PluginRegistry and register every exposed tool as an Open provider. */\nexport async function registerExposedPluginTools(): Promise<void> {\n for (const key of PluginRegistry.list()) {\n const plugin = PluginRegistry.get(key);\n if (!plugin?.middleware) continue;\n // Declaration source: meta.openExpose (preferred, standalone) or\n // meta.tools[].expose (per-tool flags).\n const openExpose = plugin.meta.openExpose;\n const exposed = openExpose\n ? openExpose.map((entry) =>\n typeof entry === \"string\"\n ? { name: entry, description: \"\", expose: true }\n : {\n name: entry.name,\n description: \"\",\n expose: true,\n readOnly: entry.readOnly,\n destructive: entry.destructive,\n },\n )\n : (plugin.meta.tools?.filter((t) => t.expose) ?? []);\n if (exposed.length === 0) continue;\n try {\n // Open-door semantics: resolve the tenant's connections at call time\n // (credential → tenant → tenant's own Connection Store entries).\n const middleware = await plugin.middleware({\n ...(plugin.meta.defaultConfig ?? {}),\n connectAll: true,\n });\n const toolObjects = (middleware as { tools?: Array<{ name: string; description: string; invoke: (input: unknown, config?: unknown) => Promise<string> }> }).tools ?? [];\n const matched = exposed\n .map((tm) => {\n const tool = toolObjects.find((t: { name: string }) => t.name === tm.name);\n if (!tool) return null;\n const annotations = tm as { readOnly?: boolean; destructive?: boolean };\n return {\n name: tm.name,\n description: tm.description,\n tool,\n readOnly: annotations.readOnly,\n destructive: annotations.destructive,\n };\n })\n .filter(Boolean) as Array<{\n name: string;\n description?: string;\n tool: { name: string; description: string; invoke: (input: unknown, config?: unknown) => Promise<string> };\n readOnly?: boolean;\n destructive?: boolean;\n }>;\n if (matched.length === 0) continue;\n const provider = createPluginProvider(key, matched, { label: plugin.meta.name });\n openLattice.register(provider);\n } catch {\n // skip plugins whose middleware fails to instantiate\n }\n }\n}","/**\n * Plugin expose adapter: converts a plugin's middleware-emitted tools into an\n * OpenProvider, so `expose: true` tools surface on the Open API catalog.\n *\n * The LangChain tool emits schema via .lc_kwargs.schema (ZodType) and runs via\n * .invoke(input, exeConfig). We synthesize the exeConfig the way the Agent\n * path would — injecting tenantId + _resolvedConnections into runConfig.\n */\n\nimport { z } from \"zod\";\nimport type { OpenExecutionContext, OpenGrant } from \"@axiom-lattice/protocols\";\nimport type { OpenProviderDeclaration, OpenActionDeclaration } from \"./openLattice\";\n\nexport interface PluginToolLike {\n name: string;\n description: string;\n invoke: (input: unknown, exeConfig?: unknown) => Promise<string>;\n lc_kwargs?: { schema?: z.ZodTypeAny };\n schema?: z.ZodTypeAny;\n}\n\nfunction schemaOf(tool: PluginToolLike): z.ZodTypeAny {\n return tool.lc_kwargs?.schema ?? tool.schema ?? z.object({}).passthrough();\n}\n\n/** Build an Open provider exposing the given plugin tools under a domain. */\nexport interface PluginExposedTool {\n name: string;\n description?: string;\n tool: PluginToolLike;\n /** MCP readOnlyHint (default false — conservative). */\n readOnly?: boolean;\n /** MCP destructiveHint (default false). */\n destructive?: boolean;\n}\n\nexport function createPluginProvider(\n domain: string,\n tools: PluginExposedTool[],\n options: { label?: string } = {},\n): OpenProviderDeclaration {\n function toAction(info: PluginExposedTool): OpenActionDeclaration {\n return {\n name: info.name,\n description:\n info.description || info.tool.description || `Plugin tool ${info.name}`,\n schema: schemaOf(info.tool),\n annotations: {\n readOnlyHint: info.readOnly ?? false,\n destructiveHint: info.destructive ?? false,\n },\n };\n }\n\n const actions = tools.map(toAction);\n return {\n domain,\n label: options.label ?? domain,\n source: \"plugin\",\n scopeKind: \"tenant\",\n actions,\n execute: async (action: string, args: unknown, ctx: OpenExecutionContext) => {\n const info = tools.find((t) => t.name === action);\n if (!info) {\n return {\n content: [{ type: \"text\", text: `Unknown action: ${action}` }],\n isError: true,\n };\n }\n const exeConfig = {\n configurable: {\n runConfig: {\n tenantId: ctx.tenantId,\n _resolvedConnections: ctx.runConfig._resolvedConnections ?? [],\n },\n },\n };\n const output = await info.tool.invoke(args, exeConfig);\n return { content: [{ type: \"text\", text: output }] };\n },\n };\n}"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getContentTypeFromFilename
|
|
3
3
|
} from "./chunk-LHQY46YB.mjs";
|
|
4
|
+
import {
|
|
5
|
+
init_openToken,
|
|
6
|
+
openToken_exports
|
|
7
|
+
} from "./chunk-WKNZ7GBC.mjs";
|
|
8
|
+
import {
|
|
9
|
+
__toCommonJS
|
|
10
|
+
} from "./chunk-NFEGQTCC.mjs";
|
|
4
11
|
|
|
5
12
|
// src/controllers/resources.ts
|
|
6
13
|
import bcrypt from "bcryptjs";
|
|
@@ -9,6 +16,23 @@ import {
|
|
|
9
16
|
createSharePayload,
|
|
10
17
|
buildNamedVolumeName
|
|
11
18
|
} from "@axiom-lattice/core";
|
|
19
|
+
|
|
20
|
+
// src/services/open/sandboxGrants.ts
|
|
21
|
+
var ALLOWED = {
|
|
22
|
+
kb: ["search", "entries_read"]
|
|
23
|
+
};
|
|
24
|
+
function sanitizeShareOpenGrants(grants) {
|
|
25
|
+
const out = [];
|
|
26
|
+
for (const grant of grants ?? []) {
|
|
27
|
+
const allowed = ALLOWED[grant.domain];
|
|
28
|
+
if (!allowed) continue;
|
|
29
|
+
const items = grant.items && grant.items.length > 0 ? grant.items.filter((item) => allowed.includes(item)) : allowed;
|
|
30
|
+
if (items.length > 0) out.push({ domain: grant.domain, items });
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/controllers/resources.ts
|
|
12
36
|
var ResourceController = class {
|
|
13
37
|
constructor(deps) {
|
|
14
38
|
this.deps = deps;
|
|
@@ -293,7 +317,8 @@ var ResourceController = class {
|
|
|
293
317
|
workspaceId: record.workspaceId,
|
|
294
318
|
projectId: record.projectId,
|
|
295
319
|
assistantId: record.assistantId,
|
|
296
|
-
resourcePath: basePath + apiSubPath
|
|
320
|
+
resourcePath: basePath + apiSubPath,
|
|
321
|
+
openGrants: record.openGrants
|
|
297
322
|
}, apiSubPath, ext, request, reply);
|
|
298
323
|
}
|
|
299
324
|
async _execApiCore(config, apiSubPath, ext, request, reply) {
|
|
@@ -324,9 +349,10 @@ var ResourceController = class {
|
|
|
324
349
|
`export API_QUERY='${JSON.stringify(queryObj).replace(/'/g, "'\\''")}'`,
|
|
325
350
|
`export API_BODY='${bodyStr.replace(/'/g, "'\\''")}'`,
|
|
326
351
|
`export API_METHOD='${request.method}'`,
|
|
327
|
-
`export API_GATEWAY_URL='${request.protocol}://${request.hostname}'`,
|
|
352
|
+
`export API_GATEWAY_URL='${request.protocol}://${request.headers["x-forwarded-host"] ?? request.headers.host ?? request.hostname}'`,
|
|
328
353
|
`export API_TENANT_ID='${config.tenantId}'`,
|
|
329
|
-
`export API_ASSISTANT_ID='${config.assistantId || ""}'
|
|
354
|
+
`export API_ASSISTANT_ID='${config.assistantId || ""}'`,
|
|
355
|
+
`export OPEN_API_TOKEN='${this._mintSandboxToken(sandbox.name, config)}'`
|
|
330
356
|
].join(" && ");
|
|
331
357
|
const fullCmd = `${envVars} && ${cmd}`;
|
|
332
358
|
this.deps.logger.info("[api] exec", { scriptPath, cmd: cmd.substring(0, 80) });
|
|
@@ -354,8 +380,25 @@ var ResourceController = class {
|
|
|
354
380
|
_passwordPage(token) {
|
|
355
381
|
return `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Password Protected</title><style>body{font-family:-apple-system,BlinkMacSystemFont,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#f5f5f5}.card{background:#fff;padding:32px;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,.1);width:100%;max-width:360px;text-align:center}h2{margin:0 0 8px;font-size:20px}p{margin:0 0 20px;color:#666;font-size:14px}input{width:100%;padding:10px 12px;border:1px solid #d9d9d9;border-radius:8px;font-size:14px;box-sizing:border-box;margin-bottom:12px}button{width:100%;padding:10px;background:#6366f1;color:#fff;border:none;border-radius:8px;font-size:14px;cursor:pointer}.error{color:#ef4444;font-size:13px;margin-top:8px;display:none}</style></head><body><div class="card"><h2>Password Protected</h2><p>This share requires a password to access.</p><form id="f"><input type="password" id="p" placeholder="Enter password" required><button type="submit">Unlock</button><div class="error" id="e">Incorrect password</div></form></div><script>document.getElementById('f').onsubmit=async(e)=>{e.preventDefault();const r=await fetch('/s/${token}/unlock',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:document.getElementById('p').value})});if(r.ok)location.reload();else document.getElementById('e').style.display='block'}</script></body></html>`;
|
|
356
382
|
}
|
|
383
|
+
_mintSandboxToken(sandboxName, config) {
|
|
384
|
+
const { signOpenToken } = (init_openToken(), __toCommonJS(openToken_exports));
|
|
385
|
+
return signOpenToken({
|
|
386
|
+
kind: "sandbox_token",
|
|
387
|
+
tenantId: config.tenantId,
|
|
388
|
+
workspaceId: config.workspaceId,
|
|
389
|
+
projectId: config.projectId,
|
|
390
|
+
sandboxName,
|
|
391
|
+
grants: [
|
|
392
|
+
{
|
|
393
|
+
domain: "sandbox",
|
|
394
|
+
items: ["files_read", "files_list", "files_write", "shell_exec"]
|
|
395
|
+
},
|
|
396
|
+
...sanitizeShareOpenGrants(config.openGrants)
|
|
397
|
+
]
|
|
398
|
+
});
|
|
399
|
+
}
|
|
357
400
|
};
|
|
358
401
|
export {
|
|
359
402
|
ResourceController
|
|
360
403
|
};
|
|
361
|
-
//# sourceMappingURL=resources-
|
|
404
|
+
//# sourceMappingURL=resources-SRQRKW5G.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/controllers/resources.ts","../src/services/open/sandboxGrants.ts"],"sourcesContent":["import { FastifyRequest, FastifyReply } from \"fastify\";\nimport type { ResourceAddress, ShareRecord, SharedResourceStore } from \"@axiom-lattice/protocols\";\nimport bcrypt from \"bcryptjs\";\nimport {\n generateToken,\n createSharePayload,\n TokenCache,\n SandboxLatticeManager,\n buildNamedVolumeName,\n} from \"@axiom-lattice/core\";\nimport { getContentTypeFromFilename } from \"../utils/mime\";\nimport { sanitizeShareOpenGrants } from \"../services/open/sandboxGrants\";\n\ninterface ResourceControllerDeps {\n store: SharedResourceStore;\n sandboxManager: SandboxLatticeManager;\n cache: TokenCache;\n logger: { info: (msg: string, obj?: object) => void; warn: (msg: string, obj?: object) => void; error: (msg: string, obj?: object) => void };\n}\n\nexport class ResourceController {\n constructor(private deps: ResourceControllerDeps) {}\n\n async createShare(request: FastifyRequest, reply: FastifyReply) {\n const userId = (request as any).user\n ? (request as any).user.id ?? \"unknown\"\n : \"unknown\";\n const tenantId = (request.headers[\"x-tenant-id\"] as string) || \"default\";\n const workspaceId = request.headers[\"x-workspace-id\"] as string;\n const projectId = request.headers[\"x-project-id\"] as string;\n const body = request.body as any;\n\n if (!workspaceId || !projectId) {\n return reply.status(400).send({ error: \"x-workspace-id and x-project-id headers required\" });\n }\n\n const payload = createSharePayload(\n tenantId,\n workspaceId,\n projectId,\n userId as string,\n body,\n );\n const token = generateToken();\n\n try {\n await this.deps.store.create({ ...payload, token });\n this.deps.logger.info(\n \"[share] created\",\n { token, originalPath: body.resourcePath, normalizedPath: payload.address.resourcePath, volume: payload.address.volume, userId },\n );\n } catch {\n return reply.status(500).send({ error: \"Failed to create share\" });\n }\n\n return reply.status(201).send({ token, url: `/s/${token}` });\n }\n\n async listShares(request: FastifyRequest, reply: FastifyReply) {\n const userId = (request as any).user\n ? (request as any).user.id ?? \"unknown\"\n : \"unknown\";\n const tenantId = (request.headers[\"x-tenant-id\"] as string) || \"default\";\n const shares = await this.deps.store.listByUser(tenantId, userId as string);\n return reply.send(shares.filter((r: any) => (r as any).visibility !== \"internal\"));\n }\n\n async updateShare(request: FastifyRequest, reply: FastifyReply) {\n const { token } = request.params as unknown as { token: string };\n const userId = (request as any).user\n ? (request as any).user.id ?? \"unknown\"\n : \"unknown\";\n const patch = request.body as any;\n\n const record = await this.deps.store.findByToken(token);\n if (!record || record.createdBy !== userId) {\n return reply.status(404).send({ error: \"Share not found\" });\n }\n\n await this.deps.store.update(token, patch);\n\n if (patch.revoked) {\n this.deps.cache.invalidate(token);\n }\n\n return reply.send({ ok: true });\n }\n\n async revokeShare(request: FastifyRequest, reply: FastifyReply) {\n const { token } = request.params as unknown as { token: string };\n const userId = (request as any).user\n ? (request as any).user.id ?? \"unknown\"\n : \"unknown\";\n\n const record = await this.deps.store.findByToken(token);\n if (!record || record.createdBy !== userId) {\n return reply.status(404).send({ error: \"Share not found\" });\n }\n\n await this.deps.store.update(token, { revoked: true });\n this.deps.cache.invalidate(token);\n\n return reply.send({ ok: true });\n }\n\n async resolveResource(request: FastifyRequest, reply: FastifyReply) {\n const params = request.params as unknown as { token: string; \"*\"?: string };\n const { token } = params;\n const subPath = params[\"*\"] ?? \"\";\n\n this.deps.logger.info(\"[share] resolve start\", { token, subPath });\n\n const isApi = subPath && /(^|\\/)api\\//.test(subPath) && (subPath.endsWith(\".js\") || subPath.endsWith(\".py\"));\n\n // Only API paths accept non-GET methods\n if (request.method !== \"GET\" && !isApi) {\n return reply.status(405).send({ error: \"Method not allowed\" });\n }\n\n // API runtime — proxy to sandbox. Detected by /api/ anywhere in subPath.\n if (isApi) {\n const record = await this.deps.store.findByToken(token);\n if (!record || record.revoked) return reply.status(404).send(\"Not found\");\n if (record.expiresAt && new Date(record.expiresAt) < new Date()) {\n return reply.status(410).send(\"Expired\");\n }\n // Auth check for API calls (same as file access)\n if (!this._isInternalRequest(request)) {\n if (record.visibility === \"internal\") {\n return reply.status(401).send({ error: \"Internal access only\" });\n }\n if (record.visibility === \"password\") {\n if (!this._isUnlocked(request, token)) {\n return reply.status(401).send({ error: \"Password required\" });\n }\n }\n }\n const ext = subPath.endsWith(\".py\") ? \"py\" : \"js\";\n return this._execApi(record, subPath, ext, request, reply);\n }\n\n // 1. Check cache\n const cached = this.deps.cache.get(token);\n if (cached && !cached.requiresUnlock) {\n this.deps.logger.info(\"[share] cache hit\", { token, volume: cached.address.volume, resourcePath: cached.address.resourcePath });\n return this._serveFile(cached.address, token, subPath, cached.sandboxConfig ?? { tenantId: \"default\", workspaceId: \"\", projectId: \"\", assistantId: null }, reply);\n }\n this.deps.logger.info(\"[share] cache miss, querying DB\", { token });\n\n // 2. Single DB lookup\n const record = await this.deps.store.findByToken(token);\n if (!record || record.revoked) {\n this.deps.logger.warn(\"[share] token not found or revoked\", { token, found: !!record, revoked: record?.revoked });\n return reply.status(404).send(\"Not found\");\n }\n if (record.expiresAt && new Date(record.expiresAt) < new Date()) {\n this.deps.logger.info(\"[share] token expired\", { token, expiresAt: record.expiresAt });\n return reply.status(410).send(\"Expired\");\n }\n\n this.deps.logger.info(\"[share] record found\", {\n token,\n volume: record.address.volume,\n resourcePath: record.address.resourcePath,\n visibility: record.visibility,\n workspaceId: record.workspaceId,\n projectId: record.projectId,\n });\n\n // 3. Auth\n const isInternal = this._isInternalRequest(request);\n if (!isInternal) {\n // Internal shares: must be logged in\n if (record.visibility === \"internal\") {\n return reply.status(401).send({ error: \"Internal access only\" });\n }\n if (record.visibility === \"password\") {\n const unlocked = this._isUnlocked(request, token);\n if (!unlocked) {\n this.deps.logger.info(\"[share] password protected, returning password page\", { token });\n this.deps.cache.set(token, {\n address: record.address,\n requiresUnlock: true,\n sandboxConfig: { tenantId: record.tenantId, workspaceId: record.workspaceId, projectId: record.projectId, assistantId: record.assistantId },\n });\n return reply.type(\"text/html\").send(this._passwordPage(token));\n }\n this.deps.logger.info(\"[share] password unlocked\", { token });\n }\n }\n\n // 4. Access count\n if (record.maxAccess !== null) {\n const ok = await this.deps.store.atomicIncrementAccess(token);\n if (!ok) return reply.status(410).send(\"Access limit reached\");\n } else {\n this.deps.store.incrementAccess(token).catch(() => {});\n }\n\n // 5. Cache\n const sandboxConfig = { tenantId: record.tenantId, workspaceId: record.workspaceId, projectId: record.projectId, assistantId: record.assistantId };\n this.deps.cache.set(token, {\n address: record.address,\n requiresUnlock: record.visibility === \"password\" && !isInternal,\n sandboxConfig,\n });\n\n return this._serveFile(record.address, token, subPath, sandboxConfig, reply);\n }\n\n /**\n * Thin redirect: /f/{uuidHex3}/{path} → /s/{internal-token}/{path}\n * Decodes 3 UUIDs (no dashes, 96 hex chars), ensures internal share, 302 redirects.\n */\n async resolveDirectFile(request: FastifyRequest, reply: FastifyReply) {\n const params = request.params as unknown as { tid: string; wid: string; pid: string; \"*\"?: string };\n const tenantId = params.tid;\n const workspaceId = params.wid;\n const projectId = params.pid;\n const subPath = (params[\"*\"] ?? \"\");\n\n const isApi = subPath && /(^|\\/)api\\//.test(subPath) && (subPath.endsWith(\".js\") || subPath.endsWith(\".py\"));\n\n // Only API paths accept non-GET methods\n if (request.method !== \"GET\" && !isApi) {\n return reply.status(405).send({ error: \"Method not allowed\" });\n }\n\n // API runtime\n if (isApi) {\n const ext = subPath.endsWith(\".py\") ? \"py\" : \"js\";\n return this._execApiCore({\n tenantId, workspaceId, projectId, assistantId: \"\",\n resourcePath: subPath,\n }, subPath, ext, request, reply);\n }\n\n const volume = buildNamedVolumeName(\"p\", \"project\", tenantId, workspaceId, projectId);\n return this._resolveAndServe(volume, subPath, reply, `/f/${tenantId}/${workspaceId}/${projectId}`,\n { tenantId, workspaceId, projectId, assistantId: null },\n );\n }\n\n async unlockShare(request: FastifyRequest, reply: FastifyReply) {\n const { token } = request.params as unknown as { token: string };\n const { password } = request.body as unknown as { password: string };\n\n const record = await this.deps.store.findByToken(token);\n if (!record || !record.passwordHash) {\n return reply.status(404).send({ error: \"Invalid request\" });\n }\n\n const valid = await bcrypt.compare(password, record.passwordHash!);\n if (!valid) {\n return reply.status(401).send({ error: \"Incorrect password\" });\n }\n\n const cookieOpts = [\n `share_unlock_${token}=1`,\n \"Max-Age=86400\",\n `Path=/s/${token}`,\n \"SameSite=Lax\",\n \"HttpOnly\",\n ];\n if (request.protocol === \"https\") {\n cookieOpts.push(\"Secure\");\n }\n reply.header(\"Set-Cookie\", cookieOpts.join(\"; \"));\n return reply.send({ ok: true });\n }\n\n private _isInternalRequest(request: FastifyRequest): boolean {\n const user = (request as any).user;\n if (user && user.id) return true;\n // Fallback: same-origin browser request (iframe/img embed — no Auth header)\n const origin = request.headers.origin || request.headers.referer;\n if (origin) {\n try {\n const { hostname } = new URL(origin);\n if (hostname === request.hostname) return true;\n } catch { /* malformed */ }\n }\n return false;\n }\n\n private _isUnlocked(request: FastifyRequest, token: string): boolean {\n const cookie = request.headers.cookie ?? \"\";\n return cookie.includes(`share_unlock_${token}=1`);\n }\n\n /** Returns true if the path has a file extension indicating it's a file, not a directory */\n private _isFilePath(path: string): boolean {\n return /\\.[a-zA-Z0-9]+$/.test(path);\n }\n\n /**\n * Shared file resolution: directory → index.html, volume FS → sandbox, base tag, response.\n */\n private async _resolveAndServe(\n volume: string,\n resourcePath: string,\n reply: FastifyReply,\n baseTagPrefix: string,\n sandboxConfig?: { tenantId: string; workspaceId: string; projectId: string; assistantId: string | null },\n ) {\n const cleanPath = resourcePath.replace(/\\/+$/, \"\");\n const entryPath = !cleanPath\n ? \"index.html\"\n : this._isFilePath(cleanPath)\n ? cleanPath\n : `${cleanPath}/index.html`;\n\n const address: ResourceAddress = { volume, resourcePath: \"\" };\n\n let buf: Buffer;\n try {\n // Volume FS first\n const provider = this.deps.sandboxManager.getDefaultProvider();\n buf = await provider.getResourceResolver().resolve({ ...address, resourcePath: entryPath });\n } catch {\n // Sandbox fallback\n if (!sandboxConfig) return reply.status(404).send(\"File not found\");\n try {\n const sandbox = await this.deps.sandboxManager.getSandboxFromConfig({\n assistant_id: sandboxConfig.assistantId ?? \"\",\n thread_id: \"\",\n tenantId: sandboxConfig.tenantId,\n workspaceId: sandboxConfig.workspaceId,\n projectId: sandboxConfig.projectId,\n });\n buf = await sandbox.file.downloadFile({ file: `/project/${entryPath}` });\n } catch {\n return reply.status(404).send(\"File not found\");\n }\n }\n\n const filename = entryPath.split(\"/\").pop() || \"download\";\n const contentType = getContentTypeFromFilename(filename);\n\n // Inject base tag for HTML\n if (/\\.(html|htm)$/i.test(filename)) {\n const baseDir = cleanPath\n ? (this._isFilePath(cleanPath) ? cleanPath.replace(/[^/]+$/, \"\") : cleanPath)\n : \"\";\n const html = buf.toString(\"utf-8\");\n if (!/<base\\b/i.test(html)) {\n const baseTag = `<base href=\"${baseTagPrefix}${baseDir ? \"/\" + baseDir : \"\"}/\">`;\n buf = Buffer.from(\n html.includes(\"<head>\") ? html.replace(\"<head>\", `<head>${baseTag}`) : baseTag + html,\n \"utf-8\"\n );\n }\n }\n\n return reply\n .status(200)\n .type(contentType)\n .header(\"Content-Disposition\", `inline; filename*=UTF-8''${encodeURIComponent(filename)}`)\n .header(\"Access-Control-Allow-Origin\", \"*\")\n .send(buf);\n }\n\n private async _serveFile(\n address: ResourceAddress,\n token: string,\n subPath: string,\n sandboxConfig: { tenantId: string; workspaceId: string; projectId: string; assistantId: string | null },\n reply: FastifyReply,\n ) {\n const resourcePath = subPath\n ? this._resolveSafeSubPath(address.resourcePath, subPath)\n : address.resourcePath;\n return this._resolveAndServe(\n address.volume,\n resourcePath,\n reply,\n `/s/${token}`,\n sandboxConfig,\n );\n }\n\n private async _execApi(\n record: ShareRecord,\n apiSubPath: string,\n ext: \"js\" | \"py\",\n request: FastifyRequest,\n reply: FastifyReply,\n ) {\n const basePath = this._isFilePath(record.address.resourcePath)\n ? \"\"\n : `${record.address.resourcePath}/`;\n return this._execApiCore({\n tenantId: record.tenantId,\n workspaceId: record.workspaceId,\n projectId: record.projectId,\n assistantId: record.assistantId,\n resourcePath: basePath + apiSubPath,\n openGrants: record.openGrants,\n }, apiSubPath, ext, request, reply);\n }\n\n private async _execApiCore(\n config: {\n tenantId: string;\n workspaceId: string;\n projectId: string;\n assistantId?: string | null;\n resourcePath: string;\n openGrants?: import(\"@axiom-lattice/protocols\").OpenGrant[];\n },\n apiSubPath: string,\n ext: \"js\" | \"py\",\n request: FastifyRequest,\n reply: FastifyReply,\n ) {\n let sandbox: any;\n try {\n sandbox = await this.deps.sandboxManager.getSandboxFromConfig({\n assistant_id: config.assistantId ?? \"\",\n thread_id: \"\",\n tenantId: config.tenantId,\n workspaceId: config.workspaceId,\n projectId: config.projectId,\n });\n } catch (err) {\n this.deps.logger.error(\"[share] sandbox start failed for API\", { error: (err as Error).message });\n return reply.status(502).send({ error: \"Sandbox unavailable\" });\n }\n\n const scriptPath = `/project/${config.resourcePath}`;\n const cmd = ext === \"py\" ? `python3 ${scriptPath}` : `node ${scriptPath}`;\n\n // Pass query params and body via environment\n const queryStr = request.url.includes(\"?\") ? (request.url as string).split(\"?\")[1] : \"\";\n const queryObj: Record<string, string> = {};\n if (queryStr) {\n for (const [k, v] of new URLSearchParams(queryStr)) {\n queryObj[k] = v;\n }\n }\n\n const bodyStr = (request.body as string) ?? \"\";\n\n const envVars = [\n `export API_QUERY='${JSON.stringify(queryObj).replace(/'/g, \"'\\\\''\")}'`,\n `export API_BODY='${bodyStr.replace(/'/g, \"'\\\\''\")}'`,\n `export API_METHOD='${request.method}'`,\n `export API_GATEWAY_URL='${request.protocol}://${request.headers[\"x-forwarded-host\"] ?? request.headers.host ?? request.hostname}'`,\n `export API_TENANT_ID='${config.tenantId}'`,\n `export API_ASSISTANT_ID='${config.assistantId || \"\"}'`,\n `export OPEN_API_TOKEN='${this._mintSandboxToken(sandbox.name, config)}'`,\n ].join(\" && \");\n\n const fullCmd = `${envVars} && ${cmd}`;\n\n this.deps.logger.info(\"[api] exec\", { scriptPath, cmd: cmd.substring(0, 80) });\n\n try {\n const result = await sandbox.shell.execCommand({ command: fullCmd });\n // Parse stdout as JSON\n let data: unknown;\n try {\n data = JSON.parse(result.output?.trim() || \"{}\");\n } catch {\n data = { output: result.output?.trim() || \"\" };\n }\n return reply.status(200).type(\"application/json\").send(data);\n } catch (err) {\n this.deps.logger.warn(\"[api] exec failed\", { scriptPath, error: (err as Error).message });\n return reply.status(500).send({ error: (err as Error).message });\n }\n }\n\n private _resolveSafeSubPath(entryFile: string, subPath: string): string {\n if (!subPath) return entryFile;\n if (subPath.includes(\"..\")) throw new Error(\"Path traversal denied\");\n if (subPath.startsWith(entryFile + \"/\") || subPath === entryFile) return subPath;\n const entryDir = this._isFilePath(entryFile)\n ? entryFile.replace(/[^/]+$/, \"\")\n : entryFile + \"/\";\n return (entryDir + subPath).replace(/\\/+/g, \"/\");\n }\n\n private _passwordPage(token: string): string {\n return `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>Password Protected</title><style>body{font-family:-apple-system,BlinkMacSystemFont,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#f5f5f5}.card{background:#fff;padding:32px;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,.1);width:100%;max-width:360px;text-align:center}h2{margin:0 0 8px;font-size:20px}p{margin:0 0 20px;color:#666;font-size:14px}input{width:100%;padding:10px 12px;border:1px solid #d9d9d9;border-radius:8px;font-size:14px;box-sizing:border-box;margin-bottom:12px}button{width:100%;padding:10px;background:#6366f1;color:#fff;border:none;border-radius:8px;font-size:14px;cursor:pointer}.error{color:#ef4444;font-size:13px;margin-top:8px;display:none}</style></head><body><div class=\"card\"><h2>Password Protected</h2><p>This share requires a password to access.</p><form id=\"f\"><input type=\"password\" id=\"p\" placeholder=\"Enter password\" required><button type=\"submit\">Unlock</button><div class=\"error\" id=\"e\">Incorrect password</div></form></div><script>document.getElementById('f').onsubmit=async(e)=>{e.preventDefault();const r=await fetch('/s/${token}/unlock',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:document.getElementById('p').value})});if(r.ok)location.reload();else document.getElementById('e').style.display='block'}</script></body></html>`;\n }\n\n private _mintSandboxToken(\n sandboxName: string,\n config: {\n tenantId: string;\n workspaceId: string;\n projectId: string;\n openGrants?: import(\"@axiom-lattice/protocols\").OpenGrant[];\n },\n ): string {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const { signOpenToken } = require(\"../services/open/openToken\") as {\n signOpenToken: (p: unknown) => string;\n };\n return signOpenToken({\n kind: \"sandbox_token\",\n tenantId: config.tenantId,\n workspaceId: config.workspaceId,\n projectId: config.projectId,\n sandboxName,\n grants: [\n {\n domain: \"sandbox\",\n items: [\"files_read\", \"files_list\", \"files_write\", \"shell_exec\"],\n },\n ...sanitizeShareOpenGrants(config.openGrants),\n ],\n });\n }\n}\n","/**\n * Sandbox-token grant sanitation.\n *\n * Sandbox tokens always carry the self-binding sandbox grant (resolved from\n * the credential's tenant/workspace/project). Shares may append extra\n * Open-door grants, but only within the V1 whitelist: read-only kb access.\n * Anything else is dropped server-side (the share creator cannot widen scope).\n */\n\nimport type { OpenGrant } from \"@axiom-lattice/protocols\";\n\n/** V1 allowlist: domain → permitted (read-only) actions. */\nconst ALLOWED: Record<string, string[]> = {\n kb: [\"search\", \"entries_read\"],\n};\n\nexport function sanitizeShareOpenGrants(grants: OpenGrant[] | undefined): OpenGrant[] {\n const out: OpenGrant[] = [];\n for (const grant of grants ?? []) {\n const allowed = ALLOWED[grant.domain];\n if (!allowed) continue;\n const items =\n grant.items && grant.items.length > 0\n ? grant.items.filter((item) => allowed.includes(item))\n : allowed;\n if (items.length > 0) out.push({ domain: grant.domain, items });\n }\n return out;\n}\n"],"mappings":"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","names":["record"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import "./chunk-NFEGQTCC.mjs";
|
|
2
|
+
|
|
1
3
|
// src/channels/lark/sender.ts
|
|
2
4
|
async function createLarkSender(config, client) {
|
|
3
5
|
const resolved = client ?? await createDefaultLarkClient(config);
|
|
@@ -29,4 +31,4 @@ async function createDefaultLarkClient(config) {
|
|
|
29
31
|
export {
|
|
30
32
|
createLarkSender
|
|
31
33
|
};
|
|
32
|
-
//# sourceMappingURL=sender-
|
|
34
|
+
//# sourceMappingURL=sender-PLDU5EZ3.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/channels/lark/sender.ts"],"sourcesContent":["interface LarkSenderConfig {\n appId: string;\n appSecret: string;\n}\n\ninterface LarkSdkMessageClient {\n im: {\n v1: {\n message: {\n create(input: {\n params: {\n receive_id_type: \"chat_id\";\n };\n data: {\n receive_id: string;\n msg_type: \"text\";\n content: string;\n };\n }): Promise<{ code?: number }>;\n };\n };\n };\n}\n\nexport async function createLarkSender(\n config: LarkSenderConfig,\n client?: LarkSdkMessageClient,\n) {\n const resolved = client ?? (await createDefaultLarkClient(config));\n\n return {\n async sendTextReply(input: { chatId: string; text: string }): Promise<void> {\n const response = await resolved.im.v1.message.create({\n params: {\n receive_id_type: \"chat_id\",\n },\n data: {\n receive_id: input.chatId,\n msg_type: \"text\",\n content: JSON.stringify({ text: input.text }),\n },\n });\n\n if (response.code && response.code !== 0) {\n throw new Error(\"Failed to send Lark reply\");\n }\n },\n };\n}\n\nasync function createDefaultLarkClient(config: LarkSenderConfig): Promise<LarkSdkMessageClient> {\n const Lark = await import(\"@larksuiteoapi/node-sdk\");\n\n return new Lark.Client({\n appId: config.appId,\n appSecret: config.appSecret,\n }) as LarkSdkMessageClient;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/channels/lark/sender.ts"],"sourcesContent":["interface LarkSenderConfig {\n appId: string;\n appSecret: string;\n}\n\ninterface LarkSdkMessageClient {\n im: {\n v1: {\n message: {\n create(input: {\n params: {\n receive_id_type: \"chat_id\";\n };\n data: {\n receive_id: string;\n msg_type: \"text\";\n content: string;\n };\n }): Promise<{ code?: number }>;\n };\n };\n };\n}\n\nexport async function createLarkSender(\n config: LarkSenderConfig,\n client?: LarkSdkMessageClient,\n) {\n const resolved = client ?? (await createDefaultLarkClient(config));\n\n return {\n async sendTextReply(input: { chatId: string; text: string }): Promise<void> {\n const response = await resolved.im.v1.message.create({\n params: {\n receive_id_type: \"chat_id\",\n },\n data: {\n receive_id: input.chatId,\n msg_type: \"text\",\n content: JSON.stringify({ text: input.text }),\n },\n });\n\n if (response.code && response.code !== 0) {\n throw new Error(\"Failed to send Lark reply\");\n }\n },\n };\n}\n\nasync function createDefaultLarkClient(config: LarkSenderConfig): Promise<LarkSdkMessageClient> {\n const Lark = await import(\"@larksuiteoapi/node-sdk\");\n\n return new Lark.Client({\n appId: config.appId,\n appSecret: config.appSecret,\n }) as LarkSdkMessageClient;\n}\n"],"mappings":";;;AAwBA,eAAsB,iBACpB,QACA,QACA;AACA,QAAM,WAAW,UAAW,MAAM,wBAAwB,MAAM;AAEhE,SAAO;AAAA,IACL,MAAM,cAAc,OAAwD;AAC1E,YAAM,WAAW,MAAM,SAAS,GAAG,GAAG,QAAQ,OAAO;AAAA,QACnD,QAAQ;AAAA,UACN,iBAAiB;AAAA,QACnB;AAAA,QACA,MAAM;AAAA,UACJ,YAAY,MAAM;AAAA,UAClB,UAAU;AAAA,UACV,SAAS,KAAK,UAAU,EAAE,MAAM,MAAM,KAAK,CAAC;AAAA,QAC9C;AAAA,MACF,CAAC;AAED,UAAI,SAAS,QAAQ,SAAS,SAAS,GAAG;AACxC,cAAM,IAAI,MAAM,2BAA2B;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,wBAAwB,QAAyD;AAC9F,QAAM,OAAO,MAAM,OAAO,yBAAyB;AAEnD,SAAO,IAAI,KAAK,OAAO;AAAA,IACrB,OAAO,OAAO;AAAA,IACd,WAAW,OAAO;AAAA,EACpB,CAAC;AACH;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axiom-lattice/gateway",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -47,11 +47,11 @@
|
|
|
47
47
|
"tar": "^7.5.22",
|
|
48
48
|
"uuid": "^9.0.1",
|
|
49
49
|
"zod": "3.25.76",
|
|
50
|
-
"@axiom-lattice/cli-a2a": "0.2.
|
|
51
|
-
"@axiom-lattice/core": "4.2.
|
|
52
|
-
"@axiom-lattice/pg-stores": "3.1.
|
|
53
|
-
"@axiom-lattice/protocols": "4.2.
|
|
54
|
-
"@axiom-lattice/queue-redis": "1.1.
|
|
50
|
+
"@axiom-lattice/cli-a2a": "0.2.7",
|
|
51
|
+
"@axiom-lattice/core": "4.2.9",
|
|
52
|
+
"@axiom-lattice/pg-stores": "3.1.9",
|
|
53
|
+
"@axiom-lattice/protocols": "4.2.1",
|
|
54
|
+
"@axiom-lattice/queue-redis": "1.1.7"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/bcrypt": "^6.0.0",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"tsconfig-paths": "^4.2.0",
|
|
73
73
|
"tsup": "^8.5.0",
|
|
74
74
|
"typescript": "^5.8.2",
|
|
75
|
-
"@axiom-lattice/react-sdk": "4.
|
|
75
|
+
"@axiom-lattice/react-sdk": "4.1.0"
|
|
76
76
|
},
|
|
77
77
|
"scripts": {
|
|
78
78
|
"build": "tsup src/index.ts --format cjs,esm --dts --clean --sourcemap && pnpm copy:embed-assets",
|