@develit-io/backend-sdk 9.0.3 → 9.1.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/index.d.mts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/middlewares.mjs +112 -73
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -474,6 +474,22 @@ type InferResultType<Tables extends Record<string, unknown>, TableName extends k
|
|
|
474
474
|
with: With;
|
|
475
475
|
}>;
|
|
476
476
|
|
|
477
|
+
interface RequestLog {
|
|
478
|
+
method: string;
|
|
479
|
+
path: string;
|
|
480
|
+
query: Record<string, string>;
|
|
481
|
+
headers: Record<string, string>;
|
|
482
|
+
body: Record<string, unknown> | null;
|
|
483
|
+
}
|
|
484
|
+
interface ResponseLog {
|
|
485
|
+
method: string;
|
|
486
|
+
path: string;
|
|
487
|
+
status: number;
|
|
488
|
+
statusText: string;
|
|
489
|
+
headers: Record<string, string>;
|
|
490
|
+
body: unknown;
|
|
491
|
+
}
|
|
492
|
+
|
|
477
493
|
declare const paginationQuerySchema: z.$ZodObject<Readonly<Readonly<{
|
|
478
494
|
[k: string]: z.$ZodType<unknown, unknown, z.$ZodTypeInternals<unknown, unknown>>;
|
|
479
495
|
}>>, z.$ZodObjectConfig>;
|
|
@@ -844,4 +860,4 @@ type AsyncMethod<TArgs extends unknown[] = unknown[], TResult = unknown> = (...a
|
|
|
844
860
|
declare function cloudflareQueue<TArgs extends unknown[] = unknown[], TResult = unknown>(options: WithRetryCounterOptions): (target: unknown, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<AsyncMethod<TArgs, TResult>>) => void;
|
|
845
861
|
|
|
846
862
|
export { DatabaseTransaction, ENVIRONMENT, RPCResponse, USER_ROLES, action, asNonEmpty, bankAccount, bankAccountMetadataSchema, base, bicSchema, buildMultiFilterConditions, buildRangeFilterConditions, buildSearchConditions, calculateExponentialBackoff, cloudflareQueue, composeWranglerBase, createAuditLogWriter, createInternalError, createSignatureKeyPair, defineCommand, derivePortFromId, develitWorker, durableObjectNamespaceIdFromName, first, firstOrError, getD1Credentials, getD1DatabaseIdFromWrangler, getDrizzleD1Config, getSecret, handleAction, ibanSchema, isInternalError, nullToOptional, optionalToNull, paginationQuerySchema, paginationSchema, resolveColumn, service, signPayload, useFetch, useResult, useResultSync, uuidv4, verifyPayloadSignature, workflowInstanceStatusSchema };
|
|
847
|
-
export type { ActionExecution, ActionHandlerOptions, AuditLogWriter, BankAccountMetadata, BaseEvent, BuildSearchOptions, Command, CommandLogPayload, DevelitWorkerMethods, Environment, GatewayResponse, IRPCResponse, IdempotencyContextVariables, IncludeRelation, InferResultType, InternalError, InternalErrorResponseStatus, Project, UserContextVariables, UserRole, ValidatedInput, WorkflowInstanceStatus };
|
|
863
|
+
export type { ActionExecution, ActionHandlerOptions, AuditLogWriter, BankAccountMetadata, BaseEvent, BuildSearchOptions, Command, CommandLogPayload, DevelitWorkerMethods, Environment, GatewayResponse, IRPCResponse, IdempotencyContextVariables, IncludeRelation, InferResultType, InternalError, InternalErrorResponseStatus, Project, RequestLog, ResponseLog, UserContextVariables, UserRole, ValidatedInput, WorkflowInstanceStatus };
|
package/dist/index.d.ts
CHANGED
|
@@ -474,6 +474,22 @@ type InferResultType<Tables extends Record<string, unknown>, TableName extends k
|
|
|
474
474
|
with: With;
|
|
475
475
|
}>;
|
|
476
476
|
|
|
477
|
+
interface RequestLog {
|
|
478
|
+
method: string;
|
|
479
|
+
path: string;
|
|
480
|
+
query: Record<string, string>;
|
|
481
|
+
headers: Record<string, string>;
|
|
482
|
+
body: Record<string, unknown> | null;
|
|
483
|
+
}
|
|
484
|
+
interface ResponseLog {
|
|
485
|
+
method: string;
|
|
486
|
+
path: string;
|
|
487
|
+
status: number;
|
|
488
|
+
statusText: string;
|
|
489
|
+
headers: Record<string, string>;
|
|
490
|
+
body: unknown;
|
|
491
|
+
}
|
|
492
|
+
|
|
477
493
|
declare const paginationQuerySchema: z.$ZodObject<Readonly<Readonly<{
|
|
478
494
|
[k: string]: z.$ZodType<unknown, unknown, z.$ZodTypeInternals<unknown, unknown>>;
|
|
479
495
|
}>>, z.$ZodObjectConfig>;
|
|
@@ -844,4 +860,4 @@ type AsyncMethod<TArgs extends unknown[] = unknown[], TResult = unknown> = (...a
|
|
|
844
860
|
declare function cloudflareQueue<TArgs extends unknown[] = unknown[], TResult = unknown>(options: WithRetryCounterOptions): (target: unknown, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<AsyncMethod<TArgs, TResult>>) => void;
|
|
845
861
|
|
|
846
862
|
export { DatabaseTransaction, ENVIRONMENT, RPCResponse, USER_ROLES, action, asNonEmpty, bankAccount, bankAccountMetadataSchema, base, bicSchema, buildMultiFilterConditions, buildRangeFilterConditions, buildSearchConditions, calculateExponentialBackoff, cloudflareQueue, composeWranglerBase, createAuditLogWriter, createInternalError, createSignatureKeyPair, defineCommand, derivePortFromId, develitWorker, durableObjectNamespaceIdFromName, first, firstOrError, getD1Credentials, getD1DatabaseIdFromWrangler, getDrizzleD1Config, getSecret, handleAction, ibanSchema, isInternalError, nullToOptional, optionalToNull, paginationQuerySchema, paginationSchema, resolveColumn, service, signPayload, useFetch, useResult, useResultSync, uuidv4, verifyPayloadSignature, workflowInstanceStatusSchema };
|
|
847
|
-
export type { ActionExecution, ActionHandlerOptions, AuditLogWriter, BankAccountMetadata, BaseEvent, BuildSearchOptions, Command, CommandLogPayload, DevelitWorkerMethods, Environment, GatewayResponse, IRPCResponse, IdempotencyContextVariables, IncludeRelation, InferResultType, InternalError, InternalErrorResponseStatus, Project, UserContextVariables, UserRole, ValidatedInput, WorkflowInstanceStatus };
|
|
863
|
+
export type { ActionExecution, ActionHandlerOptions, AuditLogWriter, BankAccountMetadata, BaseEvent, BuildSearchOptions, Command, CommandLogPayload, DevelitWorkerMethods, Environment, GatewayResponse, IRPCResponse, IdempotencyContextVariables, IncludeRelation, InferResultType, InternalError, InternalErrorResponseStatus, Project, RequestLog, ResponseLog, UserContextVariables, UserRole, ValidatedInput, WorkflowInstanceStatus };
|
package/dist/middlewares.mjs
CHANGED
|
@@ -25,89 +25,94 @@ const logRequest = (log) => {
|
|
|
25
25
|
const logResponse = (log) => {
|
|
26
26
|
console.log(`RESPONSE | An outgoing response has been recorded.`, log);
|
|
27
27
|
};
|
|
28
|
+
const getRequestIpAddress = (request) => {
|
|
29
|
+
return request.header("cf-connecting-ip") || request.header("x-real-ip") || request.header("x-forwarded-for") || "UNKNOWN";
|
|
30
|
+
};
|
|
31
|
+
const getRequestUserAgent = (request) => {
|
|
32
|
+
return request.header("user-agent") || "UNKNOWN";
|
|
33
|
+
};
|
|
28
34
|
|
|
29
35
|
const idempotency = () => {
|
|
30
36
|
return createMiddleware(async (context, next) => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
if (!context.env.MIDDLEWARE_IDEMPOTENCY_DISABLED) {
|
|
38
|
+
const idempotencyKeyHeader = context.req.header("x-idempotency-key");
|
|
39
|
+
if (!idempotencyKeyHeader) {
|
|
40
|
+
throw new HTTPException(401, {
|
|
41
|
+
message: `The 'x-idempotency-key' header must exist and must have a value.`
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const existingIdempotencyRecord = await context.env.IDEMPOTENCY_KV.get(idempotencyKeyHeader);
|
|
45
|
+
if (existingIdempotencyRecord) {
|
|
46
|
+
throw new HTTPException(409, {
|
|
47
|
+
message: "The identical request has already been processed. The idempotency key is not unique."
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
await context.env.IDEMPOTENCY_KV.put(
|
|
51
|
+
idempotencyKeyHeader,
|
|
52
|
+
idempotencyKeyHeader,
|
|
53
|
+
{
|
|
54
|
+
expirationTtl: 60 * 60 * 24 * 3
|
|
55
|
+
// 3 days
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
context.set("idempotency", {
|
|
59
|
+
key: idempotencyKeyHeader
|
|
41
60
|
});
|
|
42
61
|
}
|
|
43
|
-
await context.env.IDEMPOTENCY_KV.put(
|
|
44
|
-
idempotencyKeyHeader,
|
|
45
|
-
idempotencyKeyHeader,
|
|
46
|
-
{
|
|
47
|
-
expirationTtl: 60 * 60 * 24 * 3
|
|
48
|
-
// 3 days
|
|
49
|
-
}
|
|
50
|
-
);
|
|
51
|
-
context.set("idempotency", {
|
|
52
|
-
key: idempotencyKeyHeader
|
|
53
|
-
});
|
|
54
62
|
await next();
|
|
55
63
|
});
|
|
56
64
|
};
|
|
57
65
|
|
|
58
66
|
const jwt = () => {
|
|
59
67
|
return createMiddleware(async (context, next) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (!data || error) {
|
|
81
|
-
throw new HTTPException(401, {
|
|
82
|
-
message: "The JWT must contain valid user information."
|
|
68
|
+
if (!context.env.MIDDLEWARE_JWT_DISABLED) {
|
|
69
|
+
const authorizationHeader = context.req.header("authorization");
|
|
70
|
+
if (!authorizationHeader) {
|
|
71
|
+
throw new HTTPException(401, {
|
|
72
|
+
message: `The 'authorization' header must exist and must have a value.`
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
if (!validateBearerScheme(authorizationHeader)) {
|
|
76
|
+
throw new HTTPException(401, {
|
|
77
|
+
message: `The 'authorization' header value must use the Bearer scheme.`
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const bearerToken = extractBearerToken(authorizationHeader);
|
|
81
|
+
if (!validateBearerToken(bearerToken)) {
|
|
82
|
+
throw new HTTPException(401, {
|
|
83
|
+
message: `The Bearer token in the 'authorization' header value must be a JWT.`
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const { data, error } = await context.env.AUTH_SERVICE.verifyAccessToken({
|
|
87
|
+
accessToken: bearerToken
|
|
83
88
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
if (!data || error) {
|
|
90
|
+
throw new HTTPException(401, {
|
|
91
|
+
message: "The JWT must contain valid user information."
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const rawUserMetaDataString = data.payload.user.rawUserMetaData;
|
|
95
|
+
const rawUserMetaData = rawUserMetaDataString ? JSON.parse(rawUserMetaDataString) : null;
|
|
96
|
+
const organizationId = rawUserMetaData?.organizationId ?? null;
|
|
97
|
+
if (!organizationId) {
|
|
98
|
+
throw new HTTPException(422, {
|
|
99
|
+
message: "User data integrity check failed."
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
context.set("user", {
|
|
103
|
+
email: data.payload.user.email,
|
|
104
|
+
role: data.payload.user.role,
|
|
105
|
+
organizationId
|
|
91
106
|
});
|
|
92
107
|
}
|
|
93
|
-
context.set("user", {
|
|
94
|
-
email: data.payload.user.email,
|
|
95
|
-
role: data.payload.user.role,
|
|
96
|
-
organizationId
|
|
97
|
-
});
|
|
98
108
|
await next();
|
|
99
109
|
});
|
|
100
110
|
};
|
|
101
111
|
|
|
102
112
|
const ip = () => {
|
|
103
113
|
return createMiddleware(async (context, next) => {
|
|
104
|
-
if (!
|
|
105
|
-
const requestIp =
|
|
106
|
-
if (!requestIp) {
|
|
107
|
-
throw new HTTPException(401, {
|
|
108
|
-
message: "Failed to retrieve request IP address."
|
|
109
|
-
});
|
|
110
|
-
}
|
|
114
|
+
if (!context.env.MIDDLEWARE_IP_DISABLED) {
|
|
115
|
+
const requestIp = getRequestIpAddress(context.req);
|
|
111
116
|
const user = context.get("user");
|
|
112
117
|
if (!user.organizationId) {
|
|
113
118
|
throw new HTTPException(401, {
|
|
@@ -156,22 +161,56 @@ const composeResponseLog = async (response, method, path) => {
|
|
|
156
161
|
|
|
157
162
|
const logger = () => {
|
|
158
163
|
return createMiddleware(async (context, next) => {
|
|
159
|
-
|
|
160
|
-
|
|
164
|
+
if (!context.env.MIDDLEWARE_LOGGER_DISABLED) {
|
|
165
|
+
const requestLog = await composeRequestLog(context.req);
|
|
166
|
+
logRequest(requestLog);
|
|
167
|
+
if (!context.env.MIDDLEWARE_LOGGER_AUDITLOG_DISABLED) {
|
|
168
|
+
const user = context.get("user") || {};
|
|
169
|
+
await context.env.AUDITLOG_SERVICE.processLog({
|
|
170
|
+
type: "REQUEST",
|
|
171
|
+
actor: {
|
|
172
|
+
email: user.email || "UNKNOWN",
|
|
173
|
+
organizationId: user.organizationId || "UNKNOWN"
|
|
174
|
+
},
|
|
175
|
+
metadata: {
|
|
176
|
+
ip: getRequestIpAddress(context.req),
|
|
177
|
+
userAgent: getRequestUserAgent(context.req)
|
|
178
|
+
},
|
|
179
|
+
log: requestLog
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
161
183
|
await next();
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
184
|
+
if (!context.env.MIDDLEWARE_LOGGER_DISABLED) {
|
|
185
|
+
const response = context.res.clone();
|
|
186
|
+
const responseLog = await composeResponseLog(
|
|
187
|
+
response,
|
|
188
|
+
context.req.method,
|
|
189
|
+
context.req.url
|
|
190
|
+
);
|
|
191
|
+
logResponse(responseLog);
|
|
192
|
+
if (!context.env.MIDDLEWARE_LOGGER_AUDITLOG_DISABLED) {
|
|
193
|
+
const user = context.get("user") || {};
|
|
194
|
+
await context.env.AUDITLOG_SERVICE.processLog({
|
|
195
|
+
type: "RESPONSE",
|
|
196
|
+
actor: {
|
|
197
|
+
email: user.email || "UNKNOWN",
|
|
198
|
+
organizationId: user.organizationId || "UNKNOWN"
|
|
199
|
+
},
|
|
200
|
+
metadata: {
|
|
201
|
+
ip: getRequestIpAddress(context.req),
|
|
202
|
+
userAgent: getRequestUserAgent(context.req)
|
|
203
|
+
},
|
|
204
|
+
log: responseLog
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
169
208
|
});
|
|
170
209
|
};
|
|
171
210
|
|
|
172
211
|
const signature = () => {
|
|
173
212
|
return createMiddleware(async (context, next) => {
|
|
174
|
-
if (!
|
|
213
|
+
if (!context.env.MIDDLEWARE_SIGNATURE_DISABLED) {
|
|
175
214
|
const signatureHeader = context.req.header("x-signature");
|
|
176
215
|
if (!signatureHeader) {
|
|
177
216
|
throw new HTTPException(401, {
|