@getstrata/core 0.7.5 → 1.0.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/CHANGELOG.md +52 -33
- package/README.md +36 -43
- package/dist/core/database/baseRepository.d.ts +2 -1
- package/dist/core/database/dialect.d.ts +5 -1
- package/dist/core/database/errors.d.ts +4 -0
- package/dist/core/database/mysqlConnection.d.ts +3 -1
- package/dist/core/errors/http.d.ts +4 -1
- package/dist/core/http/clientIp.d.ts +6 -3
- package/dist/core/http/webErrorResponse.d.ts +3 -1
- package/dist/core/runtime/appEnv.d.ts +4 -0
- package/dist/core/tenant/tenancyConfig.d.ts +1 -0
- package/dist/entries/audit/exportAuditLogs.js +7 -5
- package/dist/entries/auth/scimAuthMiddleware.js +9 -7
- package/dist/entries/auth/sessionCookie.js +2 -2
- package/dist/entries/auth/sessionGuard.js +2 -2
- package/dist/entries/contracts/authUserDirectory.js +1 -0
- package/dist/entries/database/errors.js +45 -6
- package/dist/entries/database/model.js +4 -4
- package/dist/entries/database/mysqlConnection.js +18 -2
- package/dist/entries/database/query.js +2 -2
- package/dist/entries/database/repositoryQuery.js +20 -20
- package/dist/entries/database/schema.js +2 -2
- package/dist/entries/database/sqliteConnection.js +5 -0
- package/dist/entries/http/clientIp.js +24 -6
- package/dist/entries/http/corsMiddleware.js +14 -3
- package/dist/entries/http/loginThrottleMiddleware.js +25 -8
- package/dist/entries/http/memoryThrottleMiddleware.js +25 -8
- package/dist/entries/http/response.js +66 -7
- package/dist/entries/http/scimThrottleMiddleware.js +23 -6
- package/dist/entries/http/throttleMiddleware.js +25 -8
- package/dist/entries/http/webErrorResponse.js +66 -7
- package/dist/entries/jobs/exportAuditLogsJob.js +7 -5
- package/dist/entries/logging/requestLoggingMiddleware.js +29 -10
- package/dist/entries/openapi/generator.js +5 -5
- package/dist/entries/runtime/appEnv.js +8 -0
- package/dist/entries/tenant/databaseTenantContext.js +7 -5
- package/dist/entries/tenant/tenancyConfig.js +7 -5
- package/dist/entries/tenant/tenantDatabaseScope.js +9 -7
- package/dist/framework/public-api.d.ts +3 -3
- package/dist/index.js +212 -90
- package/package.json +16 -3
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// ../../src/core/http/webErrorResponse.ts
|
|
3
3
|
import { toHttpError as toHttpError2, ValidationError } from "@getstrata/core/errors/http";
|
|
4
|
+
import { appLogger } from "@getstrata/core/logging/logger";
|
|
4
5
|
|
|
5
6
|
// ../../src/core/database/errors.ts
|
|
6
7
|
import {
|
|
7
8
|
BadRequestError,
|
|
8
9
|
ConflictError,
|
|
10
|
+
InternalServerError,
|
|
9
11
|
toHttpError,
|
|
10
12
|
UnprocessableEntityError
|
|
11
13
|
} from "@getstrata/core/errors/http";
|
|
@@ -24,14 +26,55 @@ function getPostgresSqlState(error) {
|
|
|
24
26
|
}
|
|
25
27
|
return;
|
|
26
28
|
}
|
|
29
|
+
var MYSQL_ERRNO_MESSAGES = {
|
|
30
|
+
1062: () => new ConflictError("A record with these values already exists."),
|
|
31
|
+
1451: () => new UnprocessableEntityError("Record is still referenced by other records."),
|
|
32
|
+
1452: () => new UnprocessableEntityError("Referenced record does not exist."),
|
|
33
|
+
1048: () => new BadRequestError("Required field is missing."),
|
|
34
|
+
3819: () => new BadRequestError("Value violates a database constraint.")
|
|
35
|
+
};
|
|
36
|
+
function mapSqliteError(error) {
|
|
37
|
+
const code = typeof error.code === "string" ? error.code : "";
|
|
38
|
+
if (!code.startsWith("SQLITE_")) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
if (code === "SQLITE_CONSTRAINT_UNIQUE" || code === "SQLITE_CONSTRAINT_PRIMARYKEY") {
|
|
42
|
+
return new ConflictError("A record with these values already exists.");
|
|
43
|
+
}
|
|
44
|
+
if (code === "SQLITE_CONSTRAINT_FOREIGNKEY") {
|
|
45
|
+
return new UnprocessableEntityError("Referenced record does not exist.");
|
|
46
|
+
}
|
|
47
|
+
if (code === "SQLITE_CONSTRAINT_NOTNULL") {
|
|
48
|
+
return new BadRequestError("Required field is missing.");
|
|
49
|
+
}
|
|
50
|
+
if (code.startsWith("SQLITE_CONSTRAINT")) {
|
|
51
|
+
return new BadRequestError("Value violates a database constraint.");
|
|
52
|
+
}
|
|
53
|
+
return new InternalServerError("Database operation failed.");
|
|
54
|
+
}
|
|
55
|
+
function mapMysqlError(error) {
|
|
56
|
+
const code = typeof error.code === "string" ? error.code : "";
|
|
57
|
+
if (!code.startsWith("ER_")) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const factory = typeof error.errno === "number" ? MYSQL_ERRNO_MESSAGES[error.errno] : undefined;
|
|
61
|
+
return factory ? factory() : new InternalServerError("Database operation failed.");
|
|
62
|
+
}
|
|
27
63
|
function mapDatabaseError(error) {
|
|
28
64
|
const httpError = toHttpError(error);
|
|
29
65
|
if (httpError) {
|
|
30
66
|
return httpError;
|
|
31
67
|
}
|
|
32
68
|
if (!isPostgresError(error)) {
|
|
33
|
-
|
|
34
|
-
|
|
69
|
+
return new InternalServerError;
|
|
70
|
+
}
|
|
71
|
+
const sqlite = mapSqliteError(error);
|
|
72
|
+
if (sqlite) {
|
|
73
|
+
return sqlite;
|
|
74
|
+
}
|
|
75
|
+
const mysql = mapMysqlError(error);
|
|
76
|
+
if (mysql) {
|
|
77
|
+
return mysql;
|
|
35
78
|
}
|
|
36
79
|
const sqlState = getPostgresSqlState(error);
|
|
37
80
|
switch (sqlState) {
|
|
@@ -52,10 +95,7 @@ function mapDatabaseError(error) {
|
|
|
52
95
|
constraint: error.constraint
|
|
53
96
|
});
|
|
54
97
|
default:
|
|
55
|
-
return new
|
|
56
|
-
code: error.code,
|
|
57
|
-
sqlState
|
|
58
|
-
});
|
|
98
|
+
return new InternalServerError("Database operation failed.");
|
|
59
99
|
}
|
|
60
100
|
}
|
|
61
101
|
async function withDatabaseErrorHandling(operation) {
|
|
@@ -66,6 +106,11 @@ async function withDatabaseErrorHandling(operation) {
|
|
|
66
106
|
}
|
|
67
107
|
}
|
|
68
108
|
|
|
109
|
+
// ../../src/core/runtime/appEnv.ts
|
|
110
|
+
function isProductionEnv(env = process.env) {
|
|
111
|
+
return env.APP_ENV === "production" || env.NODE_ENV === "production";
|
|
112
|
+
}
|
|
113
|
+
|
|
69
114
|
// ../../src/core/runtime/frontendMode.ts
|
|
70
115
|
var FRONTEND_MODES = ["api", "server-htmx", "spa-react", "hybrid"];
|
|
71
116
|
var DEFAULT_SPA_PREFIX = "/app";
|
|
@@ -316,14 +361,27 @@ function errorPageTitle(status, message) {
|
|
|
316
361
|
return message;
|
|
317
362
|
}
|
|
318
363
|
function publicErrorMessage(status, message) {
|
|
319
|
-
if (status >= 500 &&
|
|
364
|
+
if (status >= 500 && isProductionEnv()) {
|
|
365
|
+
return "Something went wrong.";
|
|
366
|
+
}
|
|
320
367
|
return message;
|
|
321
368
|
}
|
|
369
|
+
function logServerError(error, mappedError) {
|
|
370
|
+
if (mappedError.status < 500) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
appLogger.error("Unhandled request error", {
|
|
374
|
+
status: mappedError.status,
|
|
375
|
+
error: error instanceof Error ? error.message : String(error),
|
|
376
|
+
stack: error instanceof Error ? error.stack : undefined
|
|
377
|
+
});
|
|
378
|
+
}
|
|
322
379
|
async function webErrorResponse(error, request) {
|
|
323
380
|
if (!request || !isViewsEnabled() || requestPrefersJson(request)) {
|
|
324
381
|
return null;
|
|
325
382
|
}
|
|
326
383
|
const mappedError = toHttpError2(error) ?? mapDatabaseError(error);
|
|
384
|
+
logServerError(error, mappedError);
|
|
327
385
|
if (mappedError.status === 401) {
|
|
328
386
|
return Response.redirect(loginRedirectLocation(request), 302);
|
|
329
387
|
}
|
|
@@ -337,6 +395,7 @@ async function webErrorResponse(error, request) {
|
|
|
337
395
|
});
|
|
338
396
|
}
|
|
339
397
|
export {
|
|
398
|
+
logServerError,
|
|
340
399
|
normalizeFieldErrors,
|
|
341
400
|
webErrorResponse
|
|
342
401
|
};
|
|
@@ -191,14 +191,16 @@ async function safeFetch(input, init = {}, options = {}) {
|
|
|
191
191
|
import { repositoryConnection as db } from "@getstrata/core/database/repositoryConnection";
|
|
192
192
|
|
|
193
193
|
// ../../src/core/tenant/tenancyConfig.ts
|
|
194
|
+
var TENANCY_DRIVERS = ["rls", "column", "none"];
|
|
194
195
|
function readTenancyDriver(env = process.env) {
|
|
195
|
-
|
|
196
|
-
|
|
196
|
+
const raw = env.TENANCY_DRIVER?.trim();
|
|
197
|
+
if (raw === undefined || raw === "") {
|
|
198
|
+
return "rls";
|
|
197
199
|
}
|
|
198
|
-
if (
|
|
199
|
-
return
|
|
200
|
+
if (TENANCY_DRIVERS.includes(raw)) {
|
|
201
|
+
return raw;
|
|
200
202
|
}
|
|
201
|
-
|
|
203
|
+
throw new Error(`TENANCY_DRIVER must be one of ${TENANCY_DRIVERS.join(", ")}; received "${raw}".`);
|
|
202
204
|
}
|
|
203
205
|
function isTenancyEnabled(env = process.env) {
|
|
204
206
|
return readTenancyDriver(env) !== "none";
|
|
@@ -1,21 +1,38 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// ../../src/core/logging/requestLoggingMiddleware.ts
|
|
3
|
-
import { currentRequestMeta, runWithRequestMeta } from "@getstrata/core/http/requestMetaContext";
|
|
3
|
+
import { currentRequestMeta as currentRequestMeta2, runWithRequestMeta } from "@getstrata/core/http/requestMetaContext";
|
|
4
4
|
|
|
5
5
|
// ../../src/core/http/clientIp.ts
|
|
6
|
+
import { currentRequestMeta } from "@getstrata/core/http/requestMetaContext";
|
|
6
7
|
function trustForwardedFor(env = process.env) {
|
|
7
8
|
return (env.TRUST_FORWARDED_FOR ?? "false") === "true";
|
|
8
9
|
}
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
function isPrivateAddress(address) {
|
|
11
|
+
const ip = address.replace(/^::ffff:/i, "");
|
|
12
|
+
return ip === "::1" || ip === "localhost" || /^127\./.test(ip) || /^10\./.test(ip) || /^192\.168\./.test(ip) || /^172\.(1[6-9]|2\d|3[01])\./.test(ip) || /^169\.254\./.test(ip) || /^f[cd][0-9a-f]{2}:/i.test(ip) || /^fe80:/i.test(ip);
|
|
13
|
+
}
|
|
14
|
+
function forwardedClientIp(request) {
|
|
15
|
+
const hops = (request.headers.get("x-forwarded-for") ?? "").split(",").map((hop) => hop.trim()).filter(Boolean);
|
|
16
|
+
for (let index = hops.length - 1;index >= 0; index -= 1) {
|
|
17
|
+
const hop = hops[index];
|
|
18
|
+
if (hop && !isPrivateAddress(hop)) {
|
|
19
|
+
return hop;
|
|
20
|
+
}
|
|
12
21
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return forwarded;
|
|
22
|
+
if (hops.length > 0) {
|
|
23
|
+
return hops[hops.length - 1];
|
|
16
24
|
}
|
|
17
25
|
return request.headers.get("x-real-ip")?.trim() || undefined;
|
|
18
26
|
}
|
|
27
|
+
function readClientIp(request, env = process.env) {
|
|
28
|
+
if (trustForwardedFor(env)) {
|
|
29
|
+
const forwarded = forwardedClientIp(request);
|
|
30
|
+
if (forwarded) {
|
|
31
|
+
return forwarded;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return currentRequestMeta().ipAddress ?? undefined;
|
|
35
|
+
}
|
|
19
36
|
|
|
20
37
|
// ../../src/core/logging/logger.ts
|
|
21
38
|
class Logger {
|
|
@@ -56,9 +73,10 @@ var appLogger = new Logger("app");
|
|
|
56
73
|
// ../../src/core/logging/requestLoggingMiddleware.ts
|
|
57
74
|
function createRequestLoggingMiddleware() {
|
|
58
75
|
return async (request, next) => {
|
|
76
|
+
const ipAddress = readClientIp(request) ?? null;
|
|
59
77
|
return await runWithRequestMeta({
|
|
60
|
-
...
|
|
61
|
-
ipAddress
|
|
78
|
+
...currentRequestMeta2(),
|
|
79
|
+
ipAddress,
|
|
62
80
|
userAgent: request.headers.get("user-agent"),
|
|
63
81
|
request
|
|
64
82
|
}, async () => {
|
|
@@ -71,7 +89,8 @@ function createRequestLoggingMiddleware() {
|
|
|
71
89
|
method: request.method,
|
|
72
90
|
path: new URL(request.url).pathname,
|
|
73
91
|
status: response.status,
|
|
74
|
-
durationMs
|
|
92
|
+
durationMs,
|
|
93
|
+
ipAddress
|
|
75
94
|
});
|
|
76
95
|
return response;
|
|
77
96
|
});
|
|
@@ -103,7 +103,7 @@ var PUBLIC_ROUTE_DESCRIPTIONS = {
|
|
|
103
103
|
"GET /health": "Liveness probe",
|
|
104
104
|
"GET /ready": "Readiness probe",
|
|
105
105
|
"GET /metrics": "Prometheus metrics",
|
|
106
|
-
"GET /api/user": "Current authenticated
|
|
106
|
+
"GET /api/user": "Current authenticated user",
|
|
107
107
|
"POST /api/login": "Login with email and password",
|
|
108
108
|
"POST /api/auth/token": "Mint a short-lived JWT with email and password",
|
|
109
109
|
"POST /api/apply/login": "Candidate portal login (opaque token)",
|
|
@@ -254,13 +254,13 @@ function renderOpenApiDocument(spec) {
|
|
|
254
254
|
return `${JSON.stringify(spec, null, 2)}
|
|
255
255
|
`;
|
|
256
256
|
}
|
|
257
|
-
function toMethodName(method, path,
|
|
258
|
-
const relativePath = path.startsWith(
|
|
257
|
+
function toMethodName(method, path, apiPrefix) {
|
|
258
|
+
const relativePath = path.startsWith(apiPrefix) ? path.slice(apiPrefix.length) || "/" : path;
|
|
259
259
|
const segments = relativePath.replace(/\{|\}/g, "").split("/").filter(Boolean).flatMap((segment) => segment.split("-")).map((segment) => segment.replace(/[^a-zA-Z0-9]/g, "")).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1));
|
|
260
260
|
return `${method.toLowerCase()}${segments.join("")}`;
|
|
261
261
|
}
|
|
262
|
-
function toRequestPath(path,
|
|
263
|
-
return path.startsWith(
|
|
262
|
+
function toRequestPath(path, apiPrefix) {
|
|
263
|
+
return path.startsWith(apiPrefix) ? path.slice(apiPrefix.length) || "/" : path;
|
|
264
264
|
}
|
|
265
265
|
function renderTypeScriptSdk(spec, prefix = apiPrefix()) {
|
|
266
266
|
const lines = [
|
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
import { repositoryConnection as db } from "@getstrata/core/database/repositoryConnection";
|
|
4
4
|
|
|
5
5
|
// ../../src/core/tenant/tenancyConfig.ts
|
|
6
|
+
var TENANCY_DRIVERS = ["rls", "column", "none"];
|
|
6
7
|
function readTenancyDriver(env = process.env) {
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
const raw = env.TENANCY_DRIVER?.trim();
|
|
9
|
+
if (raw === undefined || raw === "") {
|
|
10
|
+
return "rls";
|
|
9
11
|
}
|
|
10
|
-
if (
|
|
11
|
-
return
|
|
12
|
+
if (TENANCY_DRIVERS.includes(raw)) {
|
|
13
|
+
return raw;
|
|
12
14
|
}
|
|
13
|
-
|
|
15
|
+
throw new Error(`TENANCY_DRIVER must be one of ${TENANCY_DRIVERS.join(", ")}; received "${raw}".`);
|
|
14
16
|
}
|
|
15
17
|
function isTenancyEnabled(env = process.env) {
|
|
16
18
|
return readTenancyDriver(env) !== "none";
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// ../../src/core/tenant/tenancyConfig.ts
|
|
3
|
+
var TENANCY_DRIVERS = ["rls", "column", "none"];
|
|
3
4
|
function readTenancyDriver(env = process.env) {
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
const raw = env.TENANCY_DRIVER?.trim();
|
|
6
|
+
if (raw === undefined || raw === "") {
|
|
7
|
+
return "rls";
|
|
6
8
|
}
|
|
7
|
-
if (
|
|
8
|
-
return
|
|
9
|
+
if (TENANCY_DRIVERS.includes(raw)) {
|
|
10
|
+
return raw;
|
|
9
11
|
}
|
|
10
|
-
|
|
12
|
+
throw new Error(`TENANCY_DRIVER must be one of ${TENANCY_DRIVERS.join(", ")}; received "${raw}".`);
|
|
11
13
|
}
|
|
12
14
|
function isTenancyEnabled(env = process.env) {
|
|
13
15
|
return readTenancyDriver(env) !== "none";
|
|
@@ -29,14 +29,16 @@ function hasActiveDatabaseConnection() {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// ../../src/core/tenant/tenancyConfig.ts
|
|
32
|
+
var TENANCY_DRIVERS = ["rls", "column", "none"];
|
|
32
33
|
function readTenancyDriver(env = process.env) {
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
const raw = env.TENANCY_DRIVER?.trim();
|
|
35
|
+
if (raw === undefined || raw === "") {
|
|
36
|
+
return "rls";
|
|
35
37
|
}
|
|
36
|
-
if (
|
|
37
|
-
return
|
|
38
|
+
if (TENANCY_DRIVERS.includes(raw)) {
|
|
39
|
+
return raw;
|
|
38
40
|
}
|
|
39
|
-
|
|
41
|
+
throw new Error(`TENANCY_DRIVER must be one of ${TENANCY_DRIVERS.join(", ")}; received "${raw}".`);
|
|
40
42
|
}
|
|
41
43
|
function isTenancyEnabled(env = process.env) {
|
|
42
44
|
return readTenancyDriver(env) !== "none";
|
|
@@ -64,8 +66,8 @@ async function runWithTenantDatabase(tenant, callback) {
|
|
|
64
66
|
return await runWithTenant(tenant, callback);
|
|
65
67
|
}
|
|
66
68
|
if (hasActiveDatabaseConnection()) {
|
|
67
|
-
const
|
|
68
|
-
await applyTenantContextToTransaction(
|
|
69
|
+
const activeConnection = getActiveDatabaseConnection(getDefaultDatabasePool());
|
|
70
|
+
await applyTenantContextToTransaction(activeConnection, tenant.id);
|
|
69
71
|
return await runWithTenant(tenant, callback);
|
|
70
72
|
}
|
|
71
73
|
return await getDefaultDatabasePool().begin(async (transaction) => {
|
|
@@ -35,7 +35,7 @@ export { createDatabaseConnection } from "../core/database/connection.ts";
|
|
|
35
35
|
export { getActiveDatabaseConnection, hasActiveDatabaseConnection, runWithDatabaseConnection, } from "../core/database/connectionContext.ts";
|
|
36
36
|
export { getDefaultDatabasePool, getDefaultDatabaseQuery, registerDefaultDatabasePool, } from "../core/database/defaultConnection.ts";
|
|
37
37
|
export type { SqlDialect } from "../core/database/dialect.ts";
|
|
38
|
-
export { currentSqlDialect, dialectFor, resetSqlDialect, runWithSqlDialect, useSqlDialect, } from "../core/database/dialect.ts";
|
|
38
|
+
export { currentSqlDialect, dialectFor, resetSqlDialect, runWithSqlDialect, sqlTimestamp, useSqlDialect, } from "../core/database/dialect.ts";
|
|
39
39
|
export { Factory } from "../core/database/factory.ts";
|
|
40
40
|
export { foreignKeyFromTable, pivotTableName, singularize } from "../core/database/inflection.ts";
|
|
41
41
|
export { withMigrationLock } from "../core/database/migrations/advisoryLock.ts";
|
|
@@ -43,7 +43,7 @@ export { freshDatabase, getMigrationStatus, loadMigrationsFromDirectory, migrate
|
|
|
43
43
|
export type { Migration, MigrationDatabase, MigrationStatus, } from "../core/database/migrations/types.ts";
|
|
44
44
|
export type { CastType, GlobalScopeFn, ModelConstructor } from "../core/database/model.ts";
|
|
45
45
|
export { applyCasts, BelongsToManyRelationQuery, BelongsToRelationQuery, dehydrateValue, filterMassAssignable, HasManyRelationQuery, HasOneRelationQuery, hydrateValue, Model, ModelQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery, registerModelClass, registerModelRepository, } from "../core/database/model.ts";
|
|
46
|
-
export { createMysqlConnection, createMysqlConnectionFromPool, } from "../core/database/mysqlConnection.ts";
|
|
46
|
+
export { createMysqlConnection, createMysqlConnectionFromPool, createMysqlPool, } from "../core/database/mysqlConnection.ts";
|
|
47
47
|
export { getNamedConnection, hasNamedConnection, registerNamedConnection, resetNamedConnections, runOnNamedConnection, unregisterNamedConnection, } from "../core/database/namedConnections.ts";
|
|
48
48
|
export { createDatabaseQueryProxy } from "../core/database/queryProxy.ts";
|
|
49
49
|
export type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasOneRelation, MorphManyRelation, MorphOneRelation, MorphToRelation, } from "../core/database/relationships.ts";
|
|
@@ -60,7 +60,7 @@ export { runInTransaction } from "../core/database/transaction.ts";
|
|
|
60
60
|
export type { QueryJoin, QueryJoinOn, QueryOptions, QueryOrder, QuerySelectItem, QueryWhere, } from "../core/database/types.ts";
|
|
61
61
|
export type { WhereNode } from "../core/database/whereBuilder.ts";
|
|
62
62
|
export { WhereBuilder } from "../core/database/whereBuilder.ts";
|
|
63
|
-
export { BadRequestError, ConflictError, ForbiddenError, HttpError, isHttpErrorLike, NotFoundError, PayloadTooLargeError, PreconditionFailedError, toHttpError, UnauthorizedError, UnprocessableEntityError, ValidationError, } from "../core/errors/http.ts";
|
|
63
|
+
export { BadRequestError, ConflictError, ForbiddenError, HttpError, InternalServerError, isHttpErrorLike, NotFoundError, PayloadTooLargeError, PreconditionFailedError, toHttpError, UnauthorizedError, UnprocessableEntityError, ValidationError, } from "../core/errors/http.ts";
|
|
64
64
|
export type { EventListener } from "../core/events/eventBus.ts";
|
|
65
65
|
export { EventBus, eventBus } from "../core/events/eventBus.ts";
|
|
66
66
|
export { modelEventName } from "../core/events/index.ts";
|