@burdenoff/be-sdk 2026.510.79
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/README.md +173 -0
- package/configs/eslint/index.js +492 -0
- package/configs/tsconfig/tsconfig.json +53 -0
- package/dist/EventQueueFactory-6NMSGECR.js +8 -0
- package/dist/EventQueueFactory-6NMSGECR.js.map +1 -0
- package/dist/auth/index.d.ts +66 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/cache/index.d.ts +2 -0
- package/dist/cache/index.js +6 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/captcha/index.d.ts +1 -0
- package/dist/captcha/index.js +4 -0
- package/dist/captcha/index.js.map +1 -0
- package/dist/chunk-2HANKZZM.js +245 -0
- package/dist/chunk-2HANKZZM.js.map +1 -0
- package/dist/chunk-2SD5L2F2.js +816 -0
- package/dist/chunk-2SD5L2F2.js.map +1 -0
- package/dist/chunk-3O2RQOPV.js +1068 -0
- package/dist/chunk-3O2RQOPV.js.map +1 -0
- package/dist/chunk-4B43DZIS.js +560 -0
- package/dist/chunk-4B43DZIS.js.map +1 -0
- package/dist/chunk-4XAEES25.js +2444 -0
- package/dist/chunk-4XAEES25.js.map +1 -0
- package/dist/chunk-4XGGWW36.js +1405 -0
- package/dist/chunk-4XGGWW36.js.map +1 -0
- package/dist/chunk-5LXDPGDH.js +245 -0
- package/dist/chunk-5LXDPGDH.js.map +1 -0
- package/dist/chunk-AI7L22ZJ.js +472 -0
- package/dist/chunk-AI7L22ZJ.js.map +1 -0
- package/dist/chunk-CBZNP6RF.js +286 -0
- package/dist/chunk-CBZNP6RF.js.map +1 -0
- package/dist/chunk-ELLX3K54.js +613 -0
- package/dist/chunk-ELLX3K54.js.map +1 -0
- package/dist/chunk-F5XEAGHQ.js +1875 -0
- package/dist/chunk-F5XEAGHQ.js.map +1 -0
- package/dist/chunk-FNZEQOJY.js +628 -0
- package/dist/chunk-FNZEQOJY.js.map +1 -0
- package/dist/chunk-GTEMQXCA.js +516 -0
- package/dist/chunk-GTEMQXCA.js.map +1 -0
- package/dist/chunk-HIWTWIGQ.js +226 -0
- package/dist/chunk-HIWTWIGQ.js.map +1 -0
- package/dist/chunk-IYE2NTRX.js +764 -0
- package/dist/chunk-IYE2NTRX.js.map +1 -0
- package/dist/chunk-J26YGR2U.js +1484 -0
- package/dist/chunk-J26YGR2U.js.map +1 -0
- package/dist/chunk-JG2FTZPI.js +509 -0
- package/dist/chunk-JG2FTZPI.js.map +1 -0
- package/dist/chunk-JVBTNSPG.js +1551 -0
- package/dist/chunk-JVBTNSPG.js.map +1 -0
- package/dist/chunk-L7ZMN2FJ.js +12 -0
- package/dist/chunk-L7ZMN2FJ.js.map +1 -0
- package/dist/chunk-M5IMU3US.js +473 -0
- package/dist/chunk-M5IMU3US.js.map +1 -0
- package/dist/chunk-MLW2HPS5.js +1267 -0
- package/dist/chunk-MLW2HPS5.js.map +1 -0
- package/dist/chunk-MNCGUYLJ.js +269 -0
- package/dist/chunk-MNCGUYLJ.js.map +1 -0
- package/dist/chunk-MOCUBSTW.js +373 -0
- package/dist/chunk-MOCUBSTW.js.map +1 -0
- package/dist/chunk-NGMEI42S.js +103 -0
- package/dist/chunk-NGMEI42S.js.map +1 -0
- package/dist/chunk-NUB5GQTU.js +270 -0
- package/dist/chunk-NUB5GQTU.js.map +1 -0
- package/dist/chunk-OVSYMNCI.js +145 -0
- package/dist/chunk-OVSYMNCI.js.map +1 -0
- package/dist/chunk-QLVKMWFA.js +94 -0
- package/dist/chunk-QLVKMWFA.js.map +1 -0
- package/dist/chunk-SAG6ZYWQ.js +89 -0
- package/dist/chunk-SAG6ZYWQ.js.map +1 -0
- package/dist/chunk-SAK2JCA7.js +198 -0
- package/dist/chunk-SAK2JCA7.js.map +1 -0
- package/dist/chunk-SBS4S2PJ.js +100 -0
- package/dist/chunk-SBS4S2PJ.js.map +1 -0
- package/dist/chunk-SNEOLWXT.js +148 -0
- package/dist/chunk-SNEOLWXT.js.map +1 -0
- package/dist/chunk-TKBD2ONF.js +564 -0
- package/dist/chunk-TKBD2ONF.js.map +1 -0
- package/dist/chunk-UBXFIIAW.js +127 -0
- package/dist/chunk-UBXFIIAW.js.map +1 -0
- package/dist/chunk-VI4VSNTI.js +57 -0
- package/dist/chunk-VI4VSNTI.js.map +1 -0
- package/dist/chunk-VWCN5PMD.js +268 -0
- package/dist/chunk-VWCN5PMD.js.map +1 -0
- package/dist/chunk-XC2YD6CF.js +913 -0
- package/dist/chunk-XC2YD6CF.js.map +1 -0
- package/dist/chunk-XE4OXN2W.js +10 -0
- package/dist/chunk-XE4OXN2W.js.map +1 -0
- package/dist/chunk-YMZEUTD2.js +110 -0
- package/dist/chunk-YMZEUTD2.js.map +1 -0
- package/dist/chunk-Z4IRLBWO.js +758 -0
- package/dist/chunk-Z4IRLBWO.js.map +1 -0
- package/dist/client/internal-client.d.ts +7 -0
- package/dist/client/internal-client.js +5 -0
- package/dist/client/internal-client.js.map +1 -0
- package/dist/client-CSjIrYKS.d.ts +77 -0
- package/dist/config-UKE2E3BW.js +4 -0
- package/dist/config-UKE2E3BW.js.map +1 -0
- package/dist/crypto/index.d.ts +1 -0
- package/dist/crypto/index.js +4 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/database/index.d.ts +117 -0
- package/dist/database/index.js +7 -0
- package/dist/database/index.js.map +1 -0
- package/dist/dataloader/index.d.ts +1 -0
- package/dist/dataloader/index.js +4 -0
- package/dist/dataloader/index.js.map +1 -0
- package/dist/esm-K6H7EIWK.js +1450 -0
- package/dist/esm-K6H7EIWK.js.map +1 -0
- package/dist/event-queue/index.d.ts +6 -0
- package/dist/event-queue/index.js +10 -0
- package/dist/event-queue/index.js.map +1 -0
- package/dist/export/index.d.ts +2 -0
- package/dist/export/index.js +9 -0
- package/dist/export/index.js.map +1 -0
- package/dist/feature-flags/index.d.ts +1 -0
- package/dist/feature-flags/index.js +4 -0
- package/dist/feature-flags/index.js.map +1 -0
- package/dist/gateway/index.d.ts +4 -0
- package/dist/gateway/index.js +8 -0
- package/dist/gateway/index.js.map +1 -0
- package/dist/gateway/security/index.d.ts +2 -0
- package/dist/gateway/security/index.js +5 -0
- package/dist/gateway/security/index.js.map +1 -0
- package/dist/graph/index.d.ts +9 -0
- package/dist/graph/index.js +13 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph-emitter-Bk0FqD53.d.ts +47 -0
- package/dist/graphql/index.d.ts +2 -0
- package/dist/graphql/index.js +7 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/graphql/services/index.d.ts +24 -0
- package/dist/graphql/services/index.js +5 -0
- package/dist/graphql/services/index.js.map +1 -0
- package/dist/graphql-BAVrUgBF.d.ts +22 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +5 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n-DA6IPnYy.d.ts +101 -0
- package/dist/index-4gKQKZ2B.d.ts +71 -0
- package/dist/index-B18rrFru.d.ts +42 -0
- package/dist/index-B70b5mYS.d.ts +33 -0
- package/dist/index-BMq3lFjj.d.ts +247 -0
- package/dist/index-BODgvRtL.d.ts +316 -0
- package/dist/index-BS2idbnr.d.ts +874 -0
- package/dist/index-BV3G48cH.d.ts +124 -0
- package/dist/index-CHbVw5M7.d.ts +73 -0
- package/dist/index-Cq_xNjcv.d.ts +602 -0
- package/dist/index-CrQgidpx.d.ts +77 -0
- package/dist/index-CyVEg86m.d.ts +309 -0
- package/dist/index-DOcBnmMe.d.ts +166 -0
- package/dist/index-DSOpj8DI.d.ts +17 -0
- package/dist/index-DW9q22GH.d.ts +75 -0
- package/dist/index-DlFDFyWD.d.ts +55 -0
- package/dist/index-DoK0bjhH.d.ts +607 -0
- package/dist/index-Dtf6FBaD.d.ts +199 -0
- package/dist/index-KVWGHMbS.d.ts +415 -0
- package/dist/index-PaojfSdd.d.ts +71 -0
- package/dist/index-RU_M5c74.d.ts +163 -0
- package/dist/index-UhkH2eaB.d.ts +192 -0
- package/dist/index-e_18DzAg.d.ts +18 -0
- package/dist/index-jOuh_TKn.d.ts +59 -0
- package/dist/index.d.ts +584 -0
- package/dist/index.js +2626 -0
- package/dist/index.js.map +1 -0
- package/dist/init/index.d.ts +2 -0
- package/dist/init/index.js +12 -0
- package/dist/init/index.js.map +1 -0
- package/dist/instrumentation/index.d.ts +3 -0
- package/dist/instrumentation/index.js +5 -0
- package/dist/instrumentation/index.js.map +1 -0
- package/dist/layer/index.d.ts +2 -0
- package/dist/layer/index.js +6 -0
- package/dist/layer/index.js.map +1 -0
- package/dist/layer-DDip18KY.d.ts +67 -0
- package/dist/logger/index.d.ts +2 -0
- package/dist/logger/index.js +4 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.js +5 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/notifications/index.d.ts +4 -0
- package/dist/notifications/index.js +7 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/observability/index.d.ts +3 -0
- package/dist/observability/index.js +5 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/pino-logger-RYLGXPHZ.js +5 -0
- package/dist/pino-logger-RYLGXPHZ.js.map +1 -0
- package/dist/prisma/generator/index.d.ts +1 -0
- package/dist/prisma/generator/index.js +228 -0
- package/dist/prisma/generator/index.js.map +1 -0
- package/dist/prisma/index.d.ts +5 -0
- package/dist/prisma/index.js +12 -0
- package/dist/prisma/index.js.map +1 -0
- package/dist/prisma-extension-krXnYnrN.d.ts +30 -0
- package/dist/rbac/index.d.ts +116 -0
- package/dist/rbac/index.js +7 -0
- package/dist/rbac/index.js.map +1 -0
- package/dist/sdk-THO3IWEE.js +136 -0
- package/dist/sdk-THO3IWEE.js.map +1 -0
- package/dist/server/index.d.ts +359 -0
- package/dist/server/index.js +884 -0
- package/dist/server/index.js.map +1 -0
- package/dist/telemetry/index.d.ts +83 -0
- package/dist/telemetry/index.js +209 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/temporal/index.d.ts +148 -0
- package/dist/temporal/index.js +6 -0
- package/dist/temporal/index.js.map +1 -0
- package/dist/tracker/index.d.ts +5 -0
- package/dist/tracker/index.js +9 -0
- package/dist/tracker/index.js.map +1 -0
- package/dist/types-Bo2wkjSP.d.ts +35 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/workspace-guard-LHBNK4TG.js +5 -0
- package/dist/workspace-guard-LHBNK4TG.js.map +1 -0
- package/package.json +241 -0
|
@@ -0,0 +1,884 @@
|
|
|
1
|
+
export { createWorkspaceGuardPlugin } from '../chunk-UBXFIIAW.js';
|
|
2
|
+
import { setWorkspaceContext } from '../chunk-GTEMQXCA.js';
|
|
3
|
+
import { I18n } from '../chunk-IYE2NTRX.js';
|
|
4
|
+
import { logger } from '../chunk-CBZNP6RF.js';
|
|
5
|
+
import { __name } from '../chunk-XE4OXN2W.js';
|
|
6
|
+
import crypto from 'crypto';
|
|
7
|
+
|
|
8
|
+
// src/server/auth.ts
|
|
9
|
+
var getDbFn = null;
|
|
10
|
+
async function getDb() {
|
|
11
|
+
if (!getDbFn) {
|
|
12
|
+
const prismaModule = await import('../prisma/index.js');
|
|
13
|
+
getDbFn = prismaModule.getDb;
|
|
14
|
+
}
|
|
15
|
+
return getDbFn();
|
|
16
|
+
}
|
|
17
|
+
__name(getDb, "getDb");
|
|
18
|
+
var joseModule = null;
|
|
19
|
+
var jwtModule = null;
|
|
20
|
+
async function getJose() {
|
|
21
|
+
if (!joseModule) {
|
|
22
|
+
joseModule = await import('jose');
|
|
23
|
+
}
|
|
24
|
+
return joseModule;
|
|
25
|
+
}
|
|
26
|
+
__name(getJose, "getJose");
|
|
27
|
+
async function getJwt() {
|
|
28
|
+
if (!jwtModule) {
|
|
29
|
+
const jwt = await import('jsonwebtoken');
|
|
30
|
+
jwtModule = jwt.default ?? jwt;
|
|
31
|
+
}
|
|
32
|
+
return jwtModule;
|
|
33
|
+
}
|
|
34
|
+
__name(getJwt, "getJwt");
|
|
35
|
+
var authConfig = null;
|
|
36
|
+
function configureAuth(config) {
|
|
37
|
+
authConfig = config;
|
|
38
|
+
logger.debug("[ServerAuth] Auth configured");
|
|
39
|
+
}
|
|
40
|
+
__name(configureAuth, "configureAuth");
|
|
41
|
+
async function fetchWorkspaceSecret(workspaceId) {
|
|
42
|
+
try {
|
|
43
|
+
const db = await getDb();
|
|
44
|
+
const workspace = await db.client.workspace.findUnique({
|
|
45
|
+
where: {
|
|
46
|
+
id: workspaceId
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
if (!workspace?.jwtSecret) {
|
|
50
|
+
logger.debug("[ServerAuth] No JWT secret found for workspace", {
|
|
51
|
+
workspaceId
|
|
52
|
+
});
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
return JSON.parse(JSON.stringify(workspace.jwtSecret));
|
|
56
|
+
} catch (error) {
|
|
57
|
+
logger.warn("[ServerAuth] Error fetching workspace secret", {
|
|
58
|
+
workspaceId,
|
|
59
|
+
error
|
|
60
|
+
});
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
__name(fetchWorkspaceSecret, "fetchWorkspaceSecret");
|
|
65
|
+
function configureDefaultAuth() {
|
|
66
|
+
if (!authConfig) {
|
|
67
|
+
configureAuth({
|
|
68
|
+
fetchWorkspaceSecret
|
|
69
|
+
});
|
|
70
|
+
logger.debug("[ServerAuth] Default auth configured with built-in workspace secret fetcher");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
__name(configureDefaultAuth, "configureDefaultAuth");
|
|
74
|
+
async function generateSymmetricSecret() {
|
|
75
|
+
const joseLib = await getJose();
|
|
76
|
+
const secret = await joseLib.generateSecret("HS256");
|
|
77
|
+
const jwk = await joseLib.exportJWK(secret);
|
|
78
|
+
return jwk;
|
|
79
|
+
}
|
|
80
|
+
__name(generateSymmetricSecret, "generateSymmetricSecret");
|
|
81
|
+
async function verifyJWT(token, secret, options = {}) {
|
|
82
|
+
try {
|
|
83
|
+
const jwt = await getJwt();
|
|
84
|
+
const joseLib = await getJose();
|
|
85
|
+
const decoded = jwt.decode(token, {
|
|
86
|
+
complete: true
|
|
87
|
+
});
|
|
88
|
+
if (!decoded || typeof decoded === "string" || !decoded.payload || typeof decoded.payload !== "object") {
|
|
89
|
+
logger.warn("[ServerAuth] Invalid token format");
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
if (secret) {
|
|
93
|
+
const verifiedJwt2 = jwt.verify(token, secret, options);
|
|
94
|
+
return mapPayloadToActor(verifiedJwt2);
|
|
95
|
+
}
|
|
96
|
+
const decodedJwt = joseLib.decodeJwt(token);
|
|
97
|
+
if (!decodedJwt.workspace_id) {
|
|
98
|
+
logger.warn("[ServerAuth] No workspace_id found in token");
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
if (!authConfig?.fetchWorkspaceSecret) {
|
|
102
|
+
logger.error("[ServerAuth] Auth not configured - call configureAuth() first");
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const workspaceSecret = await authConfig.fetchWorkspaceSecret(decodedJwt.workspace_id);
|
|
106
|
+
if (!workspaceSecret) {
|
|
107
|
+
logger.warn("[ServerAuth] Workspace secret not found");
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const keyLikeSecret = await joseLib.importJWK(workspaceSecret, "HS256");
|
|
111
|
+
const verifiedJwt = await joseLib.jwtVerify(token, keyLikeSecret, options);
|
|
112
|
+
return mapPayloadToActor(verifiedJwt.payload);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
logger.warn("[ServerAuth] Error verifying JWT:", err);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
__name(verifyJWT, "verifyJWT");
|
|
119
|
+
async function decodeJWT(token) {
|
|
120
|
+
try {
|
|
121
|
+
const joseLib = await getJose();
|
|
122
|
+
return joseLib.decodeJwt(token);
|
|
123
|
+
} catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
__name(decodeJWT, "decodeJWT");
|
|
128
|
+
function mapPayloadToActor(payload) {
|
|
129
|
+
return {
|
|
130
|
+
id: payload.sub,
|
|
131
|
+
type: payload.actor_type ?? "user",
|
|
132
|
+
workspace_id: payload.workspace_id,
|
|
133
|
+
tenant_id: payload.tenant_id,
|
|
134
|
+
org_id: payload.org_id,
|
|
135
|
+
isAdmin: payload["isAdmin"]
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
__name(mapPayloadToActor, "mapPayloadToActor");
|
|
139
|
+
function authCheck(actor) {
|
|
140
|
+
if (!actor) {
|
|
141
|
+
throw new Error("Please sign in");
|
|
142
|
+
}
|
|
143
|
+
return actor;
|
|
144
|
+
}
|
|
145
|
+
__name(authCheck, "authCheck");
|
|
146
|
+
function workspaceCheck(context) {
|
|
147
|
+
const actor = authCheck(context.actor);
|
|
148
|
+
if (!context.workspace?.id) {
|
|
149
|
+
throw new Error("Please switch to a workspace");
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
actorId: actor.id,
|
|
153
|
+
workspaceId: context.workspace.id
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
__name(workspaceCheck, "workspaceCheck");
|
|
157
|
+
function requireWorkspace(context) {
|
|
158
|
+
authCheck(context.actor);
|
|
159
|
+
if (!context.workspace?.id) {
|
|
160
|
+
throw new Error("Please switch to a workspace");
|
|
161
|
+
}
|
|
162
|
+
return context;
|
|
163
|
+
}
|
|
164
|
+
__name(requireWorkspace, "requireWorkspace");
|
|
165
|
+
function orgCheck(context) {
|
|
166
|
+
const actor = authCheck(context.actor);
|
|
167
|
+
if (!context.organization?.id) {
|
|
168
|
+
throw new Error("Please switch to an organization");
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
actorId: actor.id,
|
|
172
|
+
orgId: context.organization.id
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
__name(orgCheck, "orgCheck");
|
|
176
|
+
function tenantCheck(context) {
|
|
177
|
+
if (!context.tenant?.id) {
|
|
178
|
+
throw new Error("Tenant context is required");
|
|
179
|
+
}
|
|
180
|
+
return context.tenant.id;
|
|
181
|
+
}
|
|
182
|
+
__name(tenantCheck, "tenantCheck");
|
|
183
|
+
var contextOptions = null;
|
|
184
|
+
function configureContext(options) {
|
|
185
|
+
contextOptions = options;
|
|
186
|
+
logger.debug("[ServerContext] Context builder configured");
|
|
187
|
+
}
|
|
188
|
+
__name(configureContext, "configureContext");
|
|
189
|
+
function getHeader(request, key) {
|
|
190
|
+
return request.headers.get(key.toLowerCase()) ?? void 0;
|
|
191
|
+
}
|
|
192
|
+
__name(getHeader, "getHeader");
|
|
193
|
+
function compareSecret(provided, expected) {
|
|
194
|
+
const providedBuffer = Buffer.from(provided);
|
|
195
|
+
const expectedBuffer = Buffer.from(expected);
|
|
196
|
+
if (providedBuffer.length !== expectedBuffer.length) {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
return crypto.timingSafeEqual(providedBuffer, expectedBuffer);
|
|
200
|
+
}
|
|
201
|
+
__name(compareSecret, "compareSecret");
|
|
202
|
+
function shouldTrustActorHeaders(request, nodeEnv = process.env["NODE_ENV"], expectedGatewayToken = process.env["TRUSTED_GATEWAY_TOKEN"] ?? process.env["INTERNAL_SERVICE_TOKEN"]) {
|
|
203
|
+
if (!getHeader(request, "x-actor-id")) {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
if (nodeEnv === "production") {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
const providedGatewayToken = getHeader(request, "x-internal-service-token") || getHeader(request, "x-gateway-auth-token");
|
|
210
|
+
if (!expectedGatewayToken || !providedGatewayToken) {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
return compareSecret(providedGatewayToken, expectedGatewayToken);
|
|
214
|
+
}
|
|
215
|
+
__name(shouldTrustActorHeaders, "shouldTrustActorHeaders");
|
|
216
|
+
function extractTracking(request) {
|
|
217
|
+
const forwardedFor = getHeader(request, "x-forwarded-for");
|
|
218
|
+
const realIp = getHeader(request, "x-real-ip");
|
|
219
|
+
const ip = forwardedFor?.split(",")[0]?.trim() || realIp || void 0;
|
|
220
|
+
return {
|
|
221
|
+
ip,
|
|
222
|
+
userAgent: getHeader(request, "user-agent")
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
__name(extractTracking, "extractTracking");
|
|
226
|
+
async function extractActor(request) {
|
|
227
|
+
const actorId = getHeader(request, "x-actor-id");
|
|
228
|
+
if (actorId && shouldTrustActorHeaders(request)) {
|
|
229
|
+
logger.debug("[ServerContext] Using gateway-authenticated actor from headers");
|
|
230
|
+
const actorType = getHeader(request, "x-actor-type") || "user";
|
|
231
|
+
const userRole = getHeader(request, "x-user-role");
|
|
232
|
+
return {
|
|
233
|
+
id: actorId,
|
|
234
|
+
type: actorType,
|
|
235
|
+
workspace_id: getHeader(request, "x-workspace-id"),
|
|
236
|
+
tenant_id: getHeader(request, "x-tenant-id"),
|
|
237
|
+
org_id: getHeader(request, "x-org-id") || getHeader(request, "x-organization-id"),
|
|
238
|
+
isAdmin: actorType === "super_admin" || userRole === "TENANT_ADMIN" || userRole === "SUPER_ADMIN" || userRole === "PLATFORM_ADMIN"
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
if (actorId) {
|
|
242
|
+
logger.warn("[ServerContext] Ignoring untrusted actor headers and falling back to JWT verification");
|
|
243
|
+
}
|
|
244
|
+
const authHeader = getHeader(request, "authorization");
|
|
245
|
+
if (!authHeader?.startsWith("Bearer ")) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
const token = authHeader.substring(7);
|
|
249
|
+
try {
|
|
250
|
+
logger.debug("[ServerContext] No gateway headers, verifying JWT directly for actor (dev mode)");
|
|
251
|
+
const payload = await verifyJWT(token);
|
|
252
|
+
if (!payload) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
id: payload.id,
|
|
257
|
+
type: "user",
|
|
258
|
+
workspace_id: payload.workspace_id
|
|
259
|
+
};
|
|
260
|
+
} catch (error) {
|
|
261
|
+
logger.warn("[ServerContext] Invalid JWT token:", error);
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
__name(extractActor, "extractActor");
|
|
266
|
+
function extractTenant(request) {
|
|
267
|
+
const tenantId = getHeader(request, "x-tenant-id");
|
|
268
|
+
const tenantEndpoint = getHeader(request, "x-tenant-endpoint");
|
|
269
|
+
if (tenantId) {
|
|
270
|
+
return {
|
|
271
|
+
id: tenantId,
|
|
272
|
+
endpoint: tenantEndpoint || ""
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
return contextOptions?.defaultTenant || null;
|
|
276
|
+
}
|
|
277
|
+
__name(extractTenant, "extractTenant");
|
|
278
|
+
function extractOrganization(request) {
|
|
279
|
+
const orgId = getHeader(request, "x-org-id") || getHeader(request, "x-organization-id");
|
|
280
|
+
if (orgId) {
|
|
281
|
+
return {
|
|
282
|
+
id: orgId
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
__name(extractOrganization, "extractOrganization");
|
|
288
|
+
function extractWorkspace(request, actor) {
|
|
289
|
+
const workspaceId = getHeader(request, "x-workspace-id");
|
|
290
|
+
if (workspaceId) {
|
|
291
|
+
return {
|
|
292
|
+
id: workspaceId
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
if (actor?.workspace_id) {
|
|
296
|
+
return {
|
|
297
|
+
id: actor.workspace_id
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
__name(extractWorkspace, "extractWorkspace");
|
|
303
|
+
function extractProject(request) {
|
|
304
|
+
const projectId = getHeader(request, "x-project-id");
|
|
305
|
+
if (projectId) {
|
|
306
|
+
return {
|
|
307
|
+
id: projectId
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
__name(extractProject, "extractProject");
|
|
313
|
+
function extractProduct(request) {
|
|
314
|
+
const productId = getHeader(request, "x-product-id");
|
|
315
|
+
if (productId) {
|
|
316
|
+
return {
|
|
317
|
+
id: productId
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
__name(extractProduct, "extractProduct");
|
|
323
|
+
function extractGeography(request) {
|
|
324
|
+
const country = getHeader(request, "x-geo-country");
|
|
325
|
+
const currency = getHeader(request, "x-geo-currency");
|
|
326
|
+
const timezone = getHeader(request, "x-geo-timezone");
|
|
327
|
+
return {
|
|
328
|
+
country: country?.toUpperCase() || void 0,
|
|
329
|
+
currency: currency?.toUpperCase() || void 0,
|
|
330
|
+
timezone: timezone || void 0
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
__name(extractGeography, "extractGeography");
|
|
334
|
+
function extractConsentContext(request) {
|
|
335
|
+
const grantedBy = getHeader(request, "x-consent-granted-by");
|
|
336
|
+
if (!grantedBy) {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
const scopesHeader = getHeader(request, "x-consent-scope");
|
|
340
|
+
const grantedAtHeader = getHeader(request, "x-consent-granted-at");
|
|
341
|
+
const expiresAtHeader = getHeader(request, "x-consent-expires-at");
|
|
342
|
+
return {
|
|
343
|
+
grantedBy,
|
|
344
|
+
scopes: scopesHeader ? scopesHeader.split(",").map((s) => s.trim()) : void 0,
|
|
345
|
+
grantedAt: grantedAtHeader ? new Date(grantedAtHeader) : void 0,
|
|
346
|
+
expiresAt: expiresAtHeader ? new Date(expiresAtHeader) : void 0
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
__name(extractConsentContext, "extractConsentContext");
|
|
350
|
+
async function buildContext(request) {
|
|
351
|
+
if (!contextOptions) {
|
|
352
|
+
throw new Error("[ServerContext] Context not configured - call configureContext() first");
|
|
353
|
+
}
|
|
354
|
+
const actor = await extractActor(request);
|
|
355
|
+
const tenant = extractTenant(request);
|
|
356
|
+
const organization = extractOrganization(request);
|
|
357
|
+
const workspace = extractWorkspace(request, actor);
|
|
358
|
+
const project = extractProject(request);
|
|
359
|
+
const product = extractProduct(request);
|
|
360
|
+
const tracking = extractTracking(request);
|
|
361
|
+
const consentContext = extractConsentContext(request);
|
|
362
|
+
let i18n;
|
|
363
|
+
if (contextOptions.i18n) {
|
|
364
|
+
i18n = contextOptions.i18n.createContextFromRequest(request);
|
|
365
|
+
}
|
|
366
|
+
const geo = extractGeography(request);
|
|
367
|
+
if (geo.country || geo.currency || geo.timezone) {
|
|
368
|
+
if (i18n) {
|
|
369
|
+
if (geo.country) i18n.country = geo.country;
|
|
370
|
+
if (geo.currency) i18n.currency = geo.currency;
|
|
371
|
+
if (geo.timezone) i18n.timezone = geo.timezone;
|
|
372
|
+
} else {
|
|
373
|
+
i18n = {
|
|
374
|
+
locale: "en-US",
|
|
375
|
+
language: "en",
|
|
376
|
+
country: geo.country,
|
|
377
|
+
currency: geo.currency,
|
|
378
|
+
timezone: geo.timezone,
|
|
379
|
+
t: /* @__PURE__ */ __name((key) => key, "t"),
|
|
380
|
+
tp: /* @__PURE__ */ __name((key) => key, "tp"),
|
|
381
|
+
formatNumber: /* @__PURE__ */ __name((value) => String(value), "formatNumber"),
|
|
382
|
+
formatCurrency: /* @__PURE__ */ __name((value, currency) => `${currency} ${value}`, "formatCurrency"),
|
|
383
|
+
formatDate: /* @__PURE__ */ __name((date) => String(date), "formatDate"),
|
|
384
|
+
formatRelativeTime: /* @__PURE__ */ __name((value, unit) => `${value} ${unit}`, "formatRelativeTime")
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
const onBehalfOf = (actor?.type === "app" || actor?.type === "service" || actor?.type === "service_account") && consentContext?.grantedBy ? consentContext.grantedBy : actor?.id;
|
|
389
|
+
const wsCtxPayload = {
|
|
390
|
+
workspaceId: workspace?.id,
|
|
391
|
+
tenantId: tenant?.id,
|
|
392
|
+
actorId: actor?.id,
|
|
393
|
+
actorType: actor?.type,
|
|
394
|
+
organizationId: organization?.id,
|
|
395
|
+
projectId: project?.id,
|
|
396
|
+
onBehalfOf
|
|
397
|
+
};
|
|
398
|
+
logger.debug("[ServerContext] Setting workspace context", {
|
|
399
|
+
workspaceId: wsCtxPayload.workspaceId ?? "NONE",
|
|
400
|
+
actorId: wsCtxPayload.actorId ?? "NONE",
|
|
401
|
+
rawHeader: getHeader(request, "x-workspace-id") ?? "MISSING"
|
|
402
|
+
});
|
|
403
|
+
setWorkspaceContext(wsCtxPayload);
|
|
404
|
+
return {
|
|
405
|
+
request,
|
|
406
|
+
actor,
|
|
407
|
+
tenant,
|
|
408
|
+
organization,
|
|
409
|
+
workspace,
|
|
410
|
+
project,
|
|
411
|
+
product,
|
|
412
|
+
tracking,
|
|
413
|
+
consentContext: consentContext || void 0,
|
|
414
|
+
onBehalfOf: onBehalfOf || actor?.id || "",
|
|
415
|
+
db: contextOptions.getDb(),
|
|
416
|
+
i18n,
|
|
417
|
+
responseHeaders: new Headers()
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
__name(buildContext, "buildContext");
|
|
421
|
+
function getContextOptions() {
|
|
422
|
+
return contextOptions;
|
|
423
|
+
}
|
|
424
|
+
__name(getContextOptions, "getContextOptions");
|
|
425
|
+
|
|
426
|
+
// src/server/security.ts
|
|
427
|
+
var LOCALHOST_ORIGINS = [
|
|
428
|
+
"http://localhost:3000",
|
|
429
|
+
"http://localhost:4000",
|
|
430
|
+
"http://localhost:5173",
|
|
431
|
+
"http://127.0.0.1:3000",
|
|
432
|
+
"http://127.0.0.1:4000",
|
|
433
|
+
"http://127.0.0.1:5173"
|
|
434
|
+
];
|
|
435
|
+
function normalizeCorsOrigins(origins, environment) {
|
|
436
|
+
const normalized = (Array.isArray(origins) ? origins : origins?.split(",") || []).map((origin) => origin.trim()).filter(Boolean);
|
|
437
|
+
if (normalized.length === 0) {
|
|
438
|
+
return environment === "production" ? [] : LOCALHOST_ORIGINS;
|
|
439
|
+
}
|
|
440
|
+
if (normalized.includes("*")) {
|
|
441
|
+
return environment === "production" ? [] : LOCALHOST_ORIGINS;
|
|
442
|
+
}
|
|
443
|
+
return normalized;
|
|
444
|
+
}
|
|
445
|
+
__name(normalizeCorsOrigins, "normalizeCorsOrigins");
|
|
446
|
+
function resolveAllowedCorsOrigin(requestOrigin, allowedOrigins) {
|
|
447
|
+
if (!requestOrigin) {
|
|
448
|
+
return allowedOrigins[0] ?? null;
|
|
449
|
+
}
|
|
450
|
+
return allowedOrigins.includes(requestOrigin) ? requestOrigin : null;
|
|
451
|
+
}
|
|
452
|
+
__name(resolveAllowedCorsOrigin, "resolveAllowedCorsOrigin");
|
|
453
|
+
function canAccessGraphExport(actor) {
|
|
454
|
+
if (!actor) {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
return actor.isAdmin === true || [
|
|
458
|
+
"service",
|
|
459
|
+
"super_admin"
|
|
460
|
+
].includes(actor.type);
|
|
461
|
+
}
|
|
462
|
+
__name(canAccessGraphExport, "canAccessGraphExport");
|
|
463
|
+
|
|
464
|
+
// src/server/server.ts
|
|
465
|
+
var serverStartTime = null;
|
|
466
|
+
async function createServer(definition) {
|
|
467
|
+
const { config, prismaClient, schema, moduleGraph, restEndpoints, yogaPlugins, buildContext: customBuildContext, workspaceExtensionConfig, disableWorkspaceExtension, onShutdown } = definition;
|
|
468
|
+
const { Elysia } = await import('elysia');
|
|
469
|
+
const { BunAdapter } = await import('elysia/adapter/bun');
|
|
470
|
+
const { cors } = await import('@elysiajs/cors');
|
|
471
|
+
const { createYoga } = await import('graphql-yoga');
|
|
472
|
+
const { initializeDatabase, getDb: getDb2, getDatabaseManager } = await import('../prisma/index.js');
|
|
473
|
+
const { createSecurityPlugin } = await import('../middleware/index.js');
|
|
474
|
+
const { createMetricsPlugin } = await import('../observability/index.js');
|
|
475
|
+
const { createWorkspaceGuardPlugin: createWorkspaceGuardPlugin2 } = await import('../workspace-guard-LHBNK4TG.js');
|
|
476
|
+
logger.info(`[Server] Initializing ${config.serviceName}...`);
|
|
477
|
+
const boundary = config.boundary ?? (config.serviceName.startsWith("wspace-") ? "wspace" : config.serviceName.startsWith("global-") ? "global" : "wspace");
|
|
478
|
+
const shouldEnableWorkspaceExtension = disableWorkspaceExtension === true ? false : disableWorkspaceExtension === false ? true : boundary === "wspace";
|
|
479
|
+
logger.info("[Server] Initializing database...", {
|
|
480
|
+
boundary,
|
|
481
|
+
workspaceExtension: shouldEnableWorkspaceExtension
|
|
482
|
+
});
|
|
483
|
+
const { connect } = initializeDatabase(prismaClient, config.serviceName, {
|
|
484
|
+
registerShutdownHandlers: false,
|
|
485
|
+
enableWorkspaceExtension: shouldEnableWorkspaceExtension,
|
|
486
|
+
...workspaceExtensionConfig ? {
|
|
487
|
+
workspaceExtensionConfig
|
|
488
|
+
} : {}
|
|
489
|
+
});
|
|
490
|
+
await connect();
|
|
491
|
+
let i18nInstance;
|
|
492
|
+
if (config.i18n?.enabled && config.i18n.localesPath) {
|
|
493
|
+
logger.info("[Server] Initializing i18n...");
|
|
494
|
+
i18nInstance = new I18n({
|
|
495
|
+
defaultLocale: config.i18n.defaultLocale || "en-US",
|
|
496
|
+
fallbackLocale: config.i18n.fallbackLocale || "en-US",
|
|
497
|
+
localesPath: config.i18n.localesPath,
|
|
498
|
+
supportedLocales: config.i18n.supportedLocales,
|
|
499
|
+
namespace: config.i18n.namespace || config.serviceName,
|
|
500
|
+
lazyLoad: config.i18n.lazyLoad,
|
|
501
|
+
logMissing: config.i18n.logMissing ?? true,
|
|
502
|
+
enableCache: true,
|
|
503
|
+
returnKeyOnMissing: true
|
|
504
|
+
});
|
|
505
|
+
await i18nInstance.initialize();
|
|
506
|
+
logger.info(`[Server] i18n initialized with locales: ${i18nInstance.getSupportedLocales().join(", ")}`);
|
|
507
|
+
}
|
|
508
|
+
configureContext({
|
|
509
|
+
getDb: /* @__PURE__ */ __name(() => getDb2(), "getDb"),
|
|
510
|
+
i18n: i18nInstance
|
|
511
|
+
});
|
|
512
|
+
configureDefaultAuth();
|
|
513
|
+
if (moduleGraph) {
|
|
514
|
+
logger.info("[Server] Initializing module graph...");
|
|
515
|
+
await moduleGraph.initialize();
|
|
516
|
+
}
|
|
517
|
+
const isDev = config.environment !== "production";
|
|
518
|
+
const enablePlayground = config.enablePlayground ?? isDev;
|
|
519
|
+
const workspaceGuardEnabled = config.workspaceGuard?.enabled ?? boundary === "wspace";
|
|
520
|
+
logger.info(`[Server] Boundary: ${boundary}, workspace guard: ${workspaceGuardEnabled ? "enabled" : "disabled"}`);
|
|
521
|
+
const workspaceGuardPlugins = workspaceGuardEnabled ? [
|
|
522
|
+
createWorkspaceGuardPlugin2({
|
|
523
|
+
enabled: true,
|
|
524
|
+
whitelistedOperations: config.workspaceGuard?.whitelistedOperations
|
|
525
|
+
})
|
|
526
|
+
] : [];
|
|
527
|
+
const graphqlEndpoint = config.graphqlEndpoint || "/graphql";
|
|
528
|
+
logger.info("[Server] Setting up GraphQL Yoga with provided schema...");
|
|
529
|
+
const responseHeadersPlugin = {
|
|
530
|
+
onResponse: /* @__PURE__ */ __name(({ response, serverContext }) => {
|
|
531
|
+
const yogaContext = serverContext;
|
|
532
|
+
if (yogaContext?.responseHeaders) {
|
|
533
|
+
yogaContext.responseHeaders.forEach((value, key) => {
|
|
534
|
+
response.headers.append(key, value);
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
}, "onResponse")
|
|
538
|
+
};
|
|
539
|
+
const yoga = createYoga({
|
|
540
|
+
graphqlEndpoint,
|
|
541
|
+
schema,
|
|
542
|
+
graphiql: enablePlayground,
|
|
543
|
+
logging: {
|
|
544
|
+
debug: /* @__PURE__ */ __name((...args) => logger.debug("[GraphQL]", ...args), "debug"),
|
|
545
|
+
info: /* @__PURE__ */ __name((...args) => logger.info("[GraphQL]", ...args), "info"),
|
|
546
|
+
warn: /* @__PURE__ */ __name((...args) => logger.warn("[GraphQL]", ...args), "warn"),
|
|
547
|
+
error: /* @__PURE__ */ __name((...args) => logger.error("[GraphQL]", ...args), "error")
|
|
548
|
+
},
|
|
549
|
+
plugins: [
|
|
550
|
+
...workspaceGuardPlugins,
|
|
551
|
+
responseHeadersPlugin,
|
|
552
|
+
...yogaPlugins || []
|
|
553
|
+
],
|
|
554
|
+
context: /* @__PURE__ */ __name(async ({ request }) => {
|
|
555
|
+
const defaultContext = await buildContext(request);
|
|
556
|
+
if (customBuildContext) {
|
|
557
|
+
return customBuildContext(defaultContext);
|
|
558
|
+
}
|
|
559
|
+
return defaultContext;
|
|
560
|
+
}, "context")
|
|
561
|
+
});
|
|
562
|
+
const app = new Elysia({
|
|
563
|
+
adapter: BunAdapter
|
|
564
|
+
});
|
|
565
|
+
const corsOrigins = normalizeCorsOrigins(config.corsOrigins, config.environment);
|
|
566
|
+
app.use(cors({
|
|
567
|
+
origin: corsOrigins,
|
|
568
|
+
credentials: corsOrigins.length > 0,
|
|
569
|
+
allowedHeaders: [
|
|
570
|
+
"Content-Type",
|
|
571
|
+
"Authorization",
|
|
572
|
+
"X-Tenant-ID",
|
|
573
|
+
"X-Workspace-ID",
|
|
574
|
+
"X-Org-ID",
|
|
575
|
+
"X-Project-ID",
|
|
576
|
+
"X-Product-ID",
|
|
577
|
+
"X-CSRF-Token",
|
|
578
|
+
"X-Service-Name",
|
|
579
|
+
"Accept-Language",
|
|
580
|
+
"X-Locale",
|
|
581
|
+
"X-Language",
|
|
582
|
+
"X-Geo-Country",
|
|
583
|
+
"X-Geo-Currency",
|
|
584
|
+
"X-Geo-Timezone",
|
|
585
|
+
// Actor headers (gateway-injected or dev mode)
|
|
586
|
+
"X-Actor-ID",
|
|
587
|
+
"X-Actor-Type",
|
|
588
|
+
"X-Internal-Service-Token",
|
|
589
|
+
"X-Gateway-Auth-Token"
|
|
590
|
+
],
|
|
591
|
+
methods: [
|
|
592
|
+
"GET",
|
|
593
|
+
"POST",
|
|
594
|
+
"PUT",
|
|
595
|
+
"PATCH",
|
|
596
|
+
"DELETE",
|
|
597
|
+
"OPTIONS"
|
|
598
|
+
]
|
|
599
|
+
}));
|
|
600
|
+
const rawBodyEndpoints = (restEndpoints || []).filter((ep) => ep.rawBody);
|
|
601
|
+
const rawBodyPaths = new Map(rawBodyEndpoints.map((ep) => [
|
|
602
|
+
ep.path,
|
|
603
|
+
ep
|
|
604
|
+
]));
|
|
605
|
+
const rawBodyMatchers = rawBodyEndpoints.map((endpoint) => {
|
|
606
|
+
const regexPattern = endpoint.path.replace(/:[^/]+/g, "[^/]+");
|
|
607
|
+
return {
|
|
608
|
+
endpoint,
|
|
609
|
+
regexPattern,
|
|
610
|
+
regex: new RegExp(`^${regexPattern}$`)
|
|
611
|
+
};
|
|
612
|
+
});
|
|
613
|
+
const matchRawBodyEndpoint = /* @__PURE__ */ __name((pathname) => {
|
|
614
|
+
const exactMatch = rawBodyPaths.get(pathname);
|
|
615
|
+
if (exactMatch) return exactMatch;
|
|
616
|
+
for (const { endpoint, regex, regexPattern } of rawBodyMatchers) {
|
|
617
|
+
const isMatch = regex.test(pathname);
|
|
618
|
+
logger.debug(`[Server] Checking ${pathname} against pattern ${endpoint.path} (regex: ${regexPattern}), match: ${isMatch}`);
|
|
619
|
+
if (isMatch) {
|
|
620
|
+
logger.debug(`[Server] Matched ${pathname} to pattern ${endpoint.path}`);
|
|
621
|
+
return endpoint;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
logger.debug(`[Server] No raw body endpoint match for ${pathname}, rawBodyEndpoints: ${rawBodyEndpoints.length}`);
|
|
625
|
+
return void 0;
|
|
626
|
+
}, "matchRawBodyEndpoint");
|
|
627
|
+
app.onRequest(async ({ request }) => {
|
|
628
|
+
const url = new URL(request.url);
|
|
629
|
+
const pathname = url.pathname;
|
|
630
|
+
logger.debug(`[Server] onRequest: ${request.method} ${pathname}`);
|
|
631
|
+
const isHealthRoute = pathname === "/health" || pathname.startsWith("/health/");
|
|
632
|
+
const buildCorsHeaders = /* @__PURE__ */ __name(() => {
|
|
633
|
+
const origin = request.headers.get("origin") || "*";
|
|
634
|
+
const allowedOrigin = resolveAllowedCorsOrigin(origin === "*" ? null : origin, corsOrigins);
|
|
635
|
+
const headers = {
|
|
636
|
+
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
637
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-Tenant-ID, X-Workspace-ID, X-Org-ID, X-Project-ID, X-Product-ID, X-CSRF-Token, X-Service-Name, Accept-Language, X-Locale, X-Language, X-Geo-Country, X-Geo-Currency, X-Geo-Timezone, X-Actor-ID, X-Actor-Type, X-Internal-Service-Token, X-Gateway-Auth-Token"
|
|
638
|
+
};
|
|
639
|
+
if (allowedOrigin) {
|
|
640
|
+
headers["Access-Control-Allow-Origin"] = allowedOrigin;
|
|
641
|
+
headers["Access-Control-Allow-Credentials"] = "true";
|
|
642
|
+
}
|
|
643
|
+
return headers;
|
|
644
|
+
}, "buildCorsHeaders");
|
|
645
|
+
const rawBodyEndpoint = isHealthRoute ? void 0 : matchRawBodyEndpoint(pathname);
|
|
646
|
+
if (rawBodyEndpoint) {
|
|
647
|
+
logger.debug(`[Server] Matched raw body endpoint: ${pathname} -> ${rawBodyEndpoint.path}`);
|
|
648
|
+
const corsHeaders = buildCorsHeaders();
|
|
649
|
+
if (request.method === "OPTIONS") {
|
|
650
|
+
return new Response(null, {
|
|
651
|
+
status: 204,
|
|
652
|
+
headers: corsHeaders
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
if (request.method !== rawBodyEndpoint.method) {
|
|
656
|
+
return void 0;
|
|
657
|
+
}
|
|
658
|
+
try {
|
|
659
|
+
const rawBody = await request.text();
|
|
660
|
+
const context = await buildContext(request);
|
|
661
|
+
const result = await rawBodyEndpoint.handler(request, context, rawBody);
|
|
662
|
+
if (result instanceof Response) {
|
|
663
|
+
const headers2 = new Headers(result.headers);
|
|
664
|
+
for (const [key, value] of Object.entries(corsHeaders)) {
|
|
665
|
+
headers2.set(key, value);
|
|
666
|
+
}
|
|
667
|
+
return new Response(result.body, {
|
|
668
|
+
status: result.status,
|
|
669
|
+
statusText: result.statusText,
|
|
670
|
+
headers: headers2
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
const headers = new Headers({
|
|
674
|
+
"Content-Type": "application/json",
|
|
675
|
+
...corsHeaders
|
|
676
|
+
});
|
|
677
|
+
return new Response(JSON.stringify(result), {
|
|
678
|
+
status: 200,
|
|
679
|
+
headers
|
|
680
|
+
});
|
|
681
|
+
} catch (error) {
|
|
682
|
+
logger.error(`[Server] Raw body endpoint error (${pathname}):`, error);
|
|
683
|
+
const corsHeaders2 = buildCorsHeaders();
|
|
684
|
+
return new Response(JSON.stringify({
|
|
685
|
+
error: error instanceof Error ? error.message : "Internal server error"
|
|
686
|
+
}), {
|
|
687
|
+
status: 500,
|
|
688
|
+
headers: {
|
|
689
|
+
"Content-Type": "application/json",
|
|
690
|
+
...corsHeaders2
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
const yogaRoutes = [
|
|
696
|
+
graphqlEndpoint,
|
|
697
|
+
`${graphqlEndpoint}/`,
|
|
698
|
+
"/metrics"
|
|
699
|
+
];
|
|
700
|
+
const shouldHandleByYoga = yogaRoutes.includes(pathname);
|
|
701
|
+
if (shouldHandleByYoga) {
|
|
702
|
+
const corsHeaders = buildCorsHeaders();
|
|
703
|
+
if (request.method === "OPTIONS") {
|
|
704
|
+
return new Response(null, {
|
|
705
|
+
status: 204,
|
|
706
|
+
headers: corsHeaders
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
const yogaResponse = await yoga.fetch(request);
|
|
710
|
+
const headers = new Headers(yogaResponse.headers);
|
|
711
|
+
for (const [key, value] of Object.entries(corsHeaders)) {
|
|
712
|
+
headers.set(key, value);
|
|
713
|
+
}
|
|
714
|
+
return new Response(yogaResponse.body, {
|
|
715
|
+
status: yogaResponse.status,
|
|
716
|
+
statusText: yogaResponse.statusText,
|
|
717
|
+
headers
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
return void 0;
|
|
721
|
+
});
|
|
722
|
+
app.use(createMetricsPlugin());
|
|
723
|
+
app.use(createSecurityPlugin({
|
|
724
|
+
csrfSkipRoutes: config.csrfSkipRoutes || [
|
|
725
|
+
"/graphql",
|
|
726
|
+
"/health",
|
|
727
|
+
"/api/graph/"
|
|
728
|
+
],
|
|
729
|
+
loginEndpoints: config.loginEndpoints || [],
|
|
730
|
+
enableCSRF: config.enableCSRF ?? false,
|
|
731
|
+
enableSessionSecurity: config.enableSessionSecurity ?? false
|
|
732
|
+
}));
|
|
733
|
+
const healthResponse = /* @__PURE__ */ __name(() => ({
|
|
734
|
+
status: "healthy",
|
|
735
|
+
service: config.serviceName,
|
|
736
|
+
version: config.serviceVersion || "1.0.0",
|
|
737
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
738
|
+
}), "healthResponse");
|
|
739
|
+
app.get("/health", healthResponse);
|
|
740
|
+
app.get("/health/live", healthResponse);
|
|
741
|
+
app.get("/health/ready", healthResponse);
|
|
742
|
+
app.get("/health/startup", healthResponse);
|
|
743
|
+
if (moduleGraph) {
|
|
744
|
+
app.get("/api/graph/schema", async ({ request, set }) => {
|
|
745
|
+
const context = await buildContext(request);
|
|
746
|
+
if (!canAccessGraphExport(context.actor)) {
|
|
747
|
+
set.status = 403;
|
|
748
|
+
return {
|
|
749
|
+
error: "Forbidden"
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
return moduleGraph.getSchema();
|
|
753
|
+
});
|
|
754
|
+
app.get("/api/graph/export", async ({ query, request, set }) => {
|
|
755
|
+
const context = await buildContext(request);
|
|
756
|
+
if (!canAccessGraphExport(context.actor)) {
|
|
757
|
+
set.status = 403;
|
|
758
|
+
return {
|
|
759
|
+
error: "Forbidden"
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
const { organizationId, workspaceId } = query;
|
|
763
|
+
return moduleGraph.exportAll(organizationId, workspaceId);
|
|
764
|
+
});
|
|
765
|
+
app.get("/api/graph/entities", async ({ query, request, set }) => {
|
|
766
|
+
const context = await buildContext(request);
|
|
767
|
+
if (!canAccessGraphExport(context.actor)) {
|
|
768
|
+
set.status = 403;
|
|
769
|
+
return {
|
|
770
|
+
error: "Forbidden"
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
const { organizationId, workspaceId, types } = query;
|
|
774
|
+
const entityTypes = types?.split(",").map((t) => t.trim());
|
|
775
|
+
return moduleGraph.exportEntities(organizationId, workspaceId, entityTypes);
|
|
776
|
+
});
|
|
777
|
+
app.get("/api/graph/relationships", async ({ query, request, set }) => {
|
|
778
|
+
const context = await buildContext(request);
|
|
779
|
+
if (!canAccessGraphExport(context.actor)) {
|
|
780
|
+
set.status = 403;
|
|
781
|
+
return {
|
|
782
|
+
error: "Forbidden"
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
const { organizationId, workspaceId } = query;
|
|
786
|
+
return moduleGraph.exportRelationships(organizationId, workspaceId);
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
if (restEndpoints && restEndpoints.length > 0) {
|
|
790
|
+
for (const endpoint of restEndpoints) {
|
|
791
|
+
if (endpoint.rawBody) {
|
|
792
|
+
logger.info(`[Server] Raw body endpoint registered: ${endpoint.method} ${endpoint.path}`);
|
|
793
|
+
continue;
|
|
794
|
+
}
|
|
795
|
+
const handler = /* @__PURE__ */ __name(async ({ request }) => {
|
|
796
|
+
const context = await buildContext(request);
|
|
797
|
+
return endpoint.handler(request, context);
|
|
798
|
+
}, "handler");
|
|
799
|
+
switch (endpoint.method) {
|
|
800
|
+
case "GET":
|
|
801
|
+
app.get(endpoint.path, handler);
|
|
802
|
+
break;
|
|
803
|
+
case "POST":
|
|
804
|
+
app.post(endpoint.path, handler);
|
|
805
|
+
break;
|
|
806
|
+
case "PUT":
|
|
807
|
+
app.put(endpoint.path, handler);
|
|
808
|
+
break;
|
|
809
|
+
case "PATCH":
|
|
810
|
+
app.patch(endpoint.path, handler);
|
|
811
|
+
break;
|
|
812
|
+
case "DELETE":
|
|
813
|
+
app.delete(endpoint.path, handler);
|
|
814
|
+
break;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
const host = config.host || "0.0.0.0";
|
|
819
|
+
const port = config.port;
|
|
820
|
+
const serverInstance = {
|
|
821
|
+
app,
|
|
822
|
+
server: null,
|
|
823
|
+
start: /* @__PURE__ */ __name(async () => {
|
|
824
|
+
serverStartTime = /* @__PURE__ */ new Date();
|
|
825
|
+
app.listen({
|
|
826
|
+
port,
|
|
827
|
+
hostname: host
|
|
828
|
+
});
|
|
829
|
+
const elysiaApp = app;
|
|
830
|
+
serverInstance.server = elysiaApp.server;
|
|
831
|
+
logger.info(`\u{1F680} ${config.serviceName} is running at http://${host}:${port}${graphqlEndpoint}`);
|
|
832
|
+
}, "start"),
|
|
833
|
+
stop: /* @__PURE__ */ __name(async () => {
|
|
834
|
+
logger.info(`[Server] Stopping ${config.serviceName}...`);
|
|
835
|
+
if (onShutdown) {
|
|
836
|
+
await onShutdown();
|
|
837
|
+
}
|
|
838
|
+
if (moduleGraph) {
|
|
839
|
+
await moduleGraph.shutdown();
|
|
840
|
+
}
|
|
841
|
+
await getDatabaseManager().disconnect();
|
|
842
|
+
if (serverInstance.server) {
|
|
843
|
+
serverInstance.server.stop();
|
|
844
|
+
}
|
|
845
|
+
logger.info(`[Server] ${config.serviceName} stopped`);
|
|
846
|
+
}, "stop"),
|
|
847
|
+
getInfo: /* @__PURE__ */ __name(() => {
|
|
848
|
+
const uptime = serverStartTime ? Math.floor((Date.now() - serverStartTime.getTime()) / 1e3) : 0;
|
|
849
|
+
return {
|
|
850
|
+
serviceName: config.serviceName,
|
|
851
|
+
serviceVersion: config.serviceVersion || "1.0.0",
|
|
852
|
+
environment: config.environment || "development",
|
|
853
|
+
port,
|
|
854
|
+
host,
|
|
855
|
+
graphqlEndpoint,
|
|
856
|
+
startedAt: serverStartTime?.toISOString() || "",
|
|
857
|
+
uptime
|
|
858
|
+
};
|
|
859
|
+
}, "getInfo")
|
|
860
|
+
};
|
|
861
|
+
const gracefulShutdown = /* @__PURE__ */ __name(async (signal) => {
|
|
862
|
+
logger.info(`[Server] ${signal} received, shutting down gracefully...`);
|
|
863
|
+
await serverInstance.stop();
|
|
864
|
+
process.exit(0);
|
|
865
|
+
}, "gracefulShutdown");
|
|
866
|
+
process.on("SIGTERM", () => {
|
|
867
|
+
void gracefulShutdown("SIGTERM");
|
|
868
|
+
});
|
|
869
|
+
process.on("SIGINT", () => {
|
|
870
|
+
void gracefulShutdown("SIGINT");
|
|
871
|
+
});
|
|
872
|
+
return serverInstance;
|
|
873
|
+
}
|
|
874
|
+
__name(createServer, "createServer");
|
|
875
|
+
function configureServerAuth(fetchWorkspaceSecret2) {
|
|
876
|
+
configureAuth({
|
|
877
|
+
fetchWorkspaceSecret: fetchWorkspaceSecret2
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
__name(configureServerAuth, "configureServerAuth");
|
|
881
|
+
|
|
882
|
+
export { authCheck, buildContext, configureAuth, configureContext, configureDefaultAuth, configureServerAuth, createServer, decodeJWT, fetchWorkspaceSecret, generateSymmetricSecret, getContextOptions, orgCheck, requireWorkspace, tenantCheck, verifyJWT, workspaceCheck };
|
|
883
|
+
//# sourceMappingURL=index.js.map
|
|
884
|
+
//# sourceMappingURL=index.js.map
|