@getstrata/core 0.5.49 → 0.5.50
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 +4 -2
- package/dist/core/auth/membershipContextMiddleware.d.ts +1 -1
- package/dist/core/auth/scimAuthMiddleware.d.ts +1 -1
- package/dist/core/database/errors.d.ts +1 -1
- package/dist/core/facades/index.d.ts +1 -1
- package/dist/core/http/authMiddleware.d.ts +2 -2
- package/dist/core/http/authorizeMiddleware.d.ts +2 -2
- package/dist/core/http/index.d.ts +1 -1
- package/dist/core/http/requireAuthMiddleware.d.ts +1 -1
- package/dist/core/http/requireWebAuthMiddleware.d.ts +1 -1
- package/dist/core/http/securedRouteModelBinding.d.ts +1 -1
- package/dist/core/logging/requestLoggingMiddleware.d.ts +1 -1
- package/dist/core/queue/failedJobRepository.d.ts +1 -1
- package/dist/core/queue/failedJobTable.d.ts +1 -1
- package/dist/core/runtime/applicationRegistry.d.ts +3 -3
- package/dist/core/tracing/tracingMiddleware.d.ts +1 -1
- package/dist/entries/audit/exportAuditLogs.js +9 -175
- package/dist/entries/auth/membershipMiddleware.js +2 -74
- package/dist/entries/auth/scimAuthMiddleware.js +10 -93
- package/dist/entries/auth/sessionGuard.js +0 -6
- package/dist/entries/database/errors.js +6 -66
- package/dist/entries/database/model.js +2 -65
- package/dist/entries/http/authMiddleware.js +1 -23
- package/dist/entries/http/authorizeMiddleware.js +2 -89
- package/dist/entries/http/bodySizeLimitMiddleware.js +1 -66
- package/dist/entries/http/conditionalResponse.js +3 -66
- package/dist/entries/http/csrfMiddleware.js +2 -65
- package/dist/entries/http/etag.js +3 -66
- package/dist/entries/http/formRequest.js +5 -107
- package/dist/entries/http/pagination.js +8 -110
- package/dist/entries/http/parseFormBody.js +1 -66
- package/dist/entries/http/parseMultipartUpload.js +3 -66
- package/dist/entries/http/requireAbilityMiddleware.js +2 -89
- package/dist/entries/http/requireAuthMiddleware.js +1 -66
- package/dist/entries/http/requireGlobalAdminMiddleware.js +4 -128
- package/dist/entries/http/requireWebAuthMiddleware.js +2 -65
- package/dist/entries/http/routeModelBinding.js +3 -108
- package/dist/entries/http/securedRouteModelBinding.js +15 -203
- package/dist/entries/http/throttleMiddleware.js +2 -44
- package/dist/entries/http/webErrorResponse.js +25 -93
- package/dist/entries/http/webFormRequest.js +8 -109
- package/dist/entries/jobs/dispatchWebhookJob.js +5 -174
- package/dist/entries/logging/requestLoggingMiddleware.js +2 -25
- package/dist/entries/queue/createAppQueue.js +4 -2324
- package/dist/entries/queue/failedJobRepository.js +4 -2324
- package/dist/entries/queue/publicQueue.js +4 -2324
- package/dist/entries/queue/queueMetrics.js +4 -2324
- package/dist/entries/security/safeFetch.js +1 -68
- package/dist/entries/security/safeUrl.js +1 -68
- package/dist/entries/security/stripeWebhook.js +1 -68
- package/dist/entries/tenant/databaseTenantContext.js +3 -105
- package/dist/entries/tenant/tenantDatabaseScope.js +3 -58
- package/dist/entries/validation/rules.js +1 -66
- package/dist/entries/view.js +5 -16
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -59,8 +59,10 @@ Some subpaths **re-export the main bundle** so singleton state stays shared (dat
|
|
|
59
59
|
|
|
60
60
|
When adding a subpath that owns process-wide state or base classes used with `instanceof`, append it to
|
|
61
61
|
`CORE_SHARED_SUBPATHS`, run `bun scripts/sync-package-subpaths.ts`, and rebuild. Non-shared subpath
|
|
62
|
-
bundles are built with `--external @getstrata/core
|
|
63
|
-
|
|
62
|
+
bundles are built with generated `--external @getstrata/core/*` flags so framework source can import
|
|
63
|
+
shared modules via package self-imports (`scripts/codemod-core-self-imports.ts`).
|
|
64
|
+
`scripts/verify-bundled-subpaths.ts` ensures entries like `http/webFormRequest` do not inline
|
|
65
|
+
`ValidationError`.
|
|
64
66
|
|
|
65
67
|
```typescript
|
|
66
68
|
import { createAuthMiddleware } from "@getstrata/core/http/authMiddleware";
|
|
@@ -2,7 +2,7 @@ declare function cache(): import("../../types/services").CacheLike;
|
|
|
2
2
|
declare function auth(): import("../auth/guard").AuthManager;
|
|
3
3
|
declare function policyGate(): import("../auth/policy").PolicyGate;
|
|
4
4
|
declare function queue(): import("../queue").Queue;
|
|
5
|
-
declare function events(): import("
|
|
5
|
+
declare function events(): import("@getstrata/core/events").EventBus;
|
|
6
6
|
declare function config<T>(key: string): T | undefined;
|
|
7
7
|
declare function log(): import("../logging/logger").Logger;
|
|
8
8
|
declare function mail(): import("../mail/mailer").Mailer;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type AuthUser, authContext } from "
|
|
2
|
-
import type { AuthManager } from "
|
|
1
|
+
import { type AuthUser, authContext } from "@getstrata/core/auth/authContext";
|
|
2
|
+
import type { AuthManager } from "@getstrata/core/auth/guard";
|
|
3
3
|
declare function createAuthMiddleware(auth: AuthManager): (request: Request, next: () => Promise<Response>) => Promise<Response>;
|
|
4
4
|
export type { AuthUser };
|
|
5
5
|
export { authContext, createAuthMiddleware };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AuthManager } from "
|
|
2
|
-
import type { Policy, PolicyGate } from "
|
|
1
|
+
import type { AuthManager } from "@getstrata/core/auth/guard";
|
|
2
|
+
import type { Policy, PolicyGate } from "@getstrata/core/auth/policy";
|
|
3
3
|
import type { Middleware } from "./middleware";
|
|
4
4
|
declare function createAuthorizeMiddleware(gate: PolicyGate, auth: AuthManager, resource: string, action: keyof Policy): Middleware;
|
|
5
5
|
export { createAuthorizeMiddleware };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { BadRequestError, ConflictError, ForbiddenError, HttpError, NotFoundError, PayloadTooLargeError, PreconditionFailedError, UnauthorizedError, UnprocessableEntityError, ValidationError, } from "
|
|
1
|
+
export { BadRequestError, ConflictError, ForbiddenError, HttpError, NotFoundError, PayloadTooLargeError, PreconditionFailedError, UnauthorizedError, UnprocessableEntityError, ValidationError, } from "@getstrata/core/errors/http";
|
|
2
2
|
export type { PaginatedResult, PaginationMeta } from "../pagination";
|
|
3
3
|
export { createAuthMiddleware } from "./authMiddleware";
|
|
4
4
|
export { createAuthorizeMiddleware } from "./authorizeMiddleware";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AuthManager } from "
|
|
1
|
+
import type { AuthManager } from "@getstrata/core/auth/guard";
|
|
2
2
|
import type { Middleware } from "./middleware";
|
|
3
3
|
declare function createRequireAuthMiddleware(auth: AuthManager): Middleware;
|
|
4
4
|
export { createRequireAuthMiddleware };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AuthManager } from "
|
|
1
|
+
import type { AuthManager } from "@getstrata/core/auth/guard";
|
|
2
2
|
import type { Middleware } from "./middleware";
|
|
3
3
|
declare function createRequireWebAuthMiddleware(auth: AuthManager): Middleware;
|
|
4
4
|
export { createRequireWebAuthMiddleware };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { FailedJobRecord } from "./types";
|
|
2
|
-
declare const failedJobTable: import("
|
|
2
|
+
declare const failedJobTable: import("@getstrata/core/database").TableDefinition<FailedJobRecord, "id">;
|
|
3
3
|
export { failedJobTable };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import type { AuthManager } from "@getstrata/core/auth/guard";
|
|
2
|
+
import type { PolicyGate } from "@getstrata/core/auth/policy";
|
|
3
|
+
import type { EventBus } from "@getstrata/core/events";
|
|
1
4
|
import type { CacheLike } from "../../types/services";
|
|
2
|
-
import type { AuthManager } from "../auth/guard";
|
|
3
|
-
import type { PolicyGate } from "../auth/policy";
|
|
4
5
|
import type { AppContext } from "../contracts/di";
|
|
5
|
-
import type { EventBus } from "../events";
|
|
6
6
|
import { type Logger } from "../logging/logger";
|
|
7
7
|
import type { Queue } from "../queue";
|
|
8
8
|
declare function setActiveApplicationContext(context: AppContext): void;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
// ../../src/core/audit/exportAuditLogs.ts
|
|
3
|
+
import { repositoryConnection as db2 } from "@getstrata/core/database/repositoryConnection";
|
|
4
|
+
|
|
2
5
|
// ../../src/config/app.ts
|
|
3
6
|
var appConfig = {
|
|
4
7
|
name: "WorkHub",
|
|
@@ -8,179 +11,9 @@ var appConfig = {
|
|
|
8
11
|
apiPrefix: process.env.API_PREFIX ?? "/api/v1"
|
|
9
12
|
};
|
|
10
13
|
|
|
11
|
-
// ../../src/core/database/boundConnection.ts
|
|
12
|
-
var boundConnectionHolder = {
|
|
13
|
-
connection: null
|
|
14
|
-
};
|
|
15
|
-
function bindDatabaseConnection(connection) {
|
|
16
|
-
boundConnectionHolder.connection = connection;
|
|
17
|
-
}
|
|
18
|
-
function getBoundDatabaseConnection() {
|
|
19
|
-
return boundConnectionHolder.connection;
|
|
20
|
-
}
|
|
21
|
-
function resetBoundDatabaseConnection() {
|
|
22
|
-
boundConnectionHolder.connection = null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// ../../src/core/runtime/asyncContextStore.ts
|
|
26
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
27
|
-
function createAsyncContextStore(key) {
|
|
28
|
-
const symbol = Symbol.for(key);
|
|
29
|
-
const globalRecord = globalThis;
|
|
30
|
-
const existing = globalRecord[symbol];
|
|
31
|
-
if (existing) {
|
|
32
|
-
return existing;
|
|
33
|
-
}
|
|
34
|
-
const store = new AsyncLocalStorage;
|
|
35
|
-
globalRecord[symbol] = store;
|
|
36
|
-
return store;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// ../../src/core/database/connectionContext.ts
|
|
40
|
-
var activeConnection = createAsyncContextStore("@getstrata/databaseConnectionContext");
|
|
41
|
-
function runWithDatabaseConnection(connection, callback) {
|
|
42
|
-
return activeConnection.run(connection, callback);
|
|
43
|
-
}
|
|
44
|
-
function getActiveDatabaseConnection(fallback) {
|
|
45
|
-
return activeConnection.getStore() ?? fallback;
|
|
46
|
-
}
|
|
47
|
-
function hasActiveDatabaseConnection() {
|
|
48
|
-
return activeConnection.getStore() !== undefined;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// ../../src/core/database/queryProxy.ts
|
|
52
|
-
var POOL_CONNECTION_METHODS = new Set(["begin", "close", "connect"]);
|
|
53
|
-
function createDatabaseQueryProxy(pool) {
|
|
54
|
-
function resolveDatabase() {
|
|
55
|
-
return getActiveDatabaseConnection(pool);
|
|
56
|
-
}
|
|
57
|
-
function resolveDatabaseForProperty(property) {
|
|
58
|
-
if (typeof property === "string" && POOL_CONNECTION_METHODS.has(property)) {
|
|
59
|
-
return pool;
|
|
60
|
-
}
|
|
61
|
-
return resolveDatabase();
|
|
62
|
-
}
|
|
63
|
-
return new Proxy(function database() {}, {
|
|
64
|
-
apply(_target, _thisArg, args) {
|
|
65
|
-
return resolveDatabase()(...args);
|
|
66
|
-
},
|
|
67
|
-
get(_target, property) {
|
|
68
|
-
const connection = resolveDatabaseForProperty(property);
|
|
69
|
-
const value = connection[property];
|
|
70
|
-
return typeof value === "function" ? value.bind(connection) : value;
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// ../../src/core/database/defaultConnection.ts
|
|
76
|
-
var defaultPool = {
|
|
77
|
-
connection: null
|
|
78
|
-
};
|
|
79
|
-
var defaultQuery = {
|
|
80
|
-
connection: null
|
|
81
|
-
};
|
|
82
|
-
function registerDefaultDatabasePool(connection) {
|
|
83
|
-
defaultPool.connection = connection;
|
|
84
|
-
defaultQuery.connection = createDatabaseQueryProxy(connection);
|
|
85
|
-
}
|
|
86
|
-
function getDefaultDatabasePool() {
|
|
87
|
-
if (!defaultPool.connection) {
|
|
88
|
-
throw new Error("Default database pool is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
|
|
89
|
-
}
|
|
90
|
-
return defaultPool.connection;
|
|
91
|
-
}
|
|
92
|
-
function getDefaultDatabaseQuery() {
|
|
93
|
-
if (!defaultQuery.connection) {
|
|
94
|
-
throw new Error("Default database query handle is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
|
|
95
|
-
}
|
|
96
|
-
return defaultQuery.connection;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// ../../src/core/database/repositoryConnection.ts
|
|
100
|
-
function resolveRepositoryConnection() {
|
|
101
|
-
return getBoundDatabaseConnection() ?? getDefaultDatabaseQuery();
|
|
102
|
-
}
|
|
103
|
-
var repositoryConnection = new Proxy(function repositoryConnection2() {}, {
|
|
104
|
-
apply(_target, _thisArg, args) {
|
|
105
|
-
return resolveRepositoryConnection()(...args);
|
|
106
|
-
},
|
|
107
|
-
get(_target, property) {
|
|
108
|
-
const connection = resolveRepositoryConnection();
|
|
109
|
-
const value = connection[property];
|
|
110
|
-
return typeof value === "function" ? value.bind(connection) : value;
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
|
|
114
14
|
// ../../src/core/security/safeUrl.ts
|
|
115
15
|
import { lookup as dnsLookupImpl } from "dns/promises";
|
|
116
|
-
|
|
117
|
-
// ../../src/core/errors/http.ts
|
|
118
|
-
class HttpError extends Error {
|
|
119
|
-
status;
|
|
120
|
-
details;
|
|
121
|
-
constructor(status, message, details) {
|
|
122
|
-
super(message);
|
|
123
|
-
this.name = new.target.name;
|
|
124
|
-
this.status = status;
|
|
125
|
-
this.details = details;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
class BadRequestError extends HttpError {
|
|
130
|
-
constructor(message = "Bad Request", details) {
|
|
131
|
-
super(400, message, details);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
class NotFoundError extends HttpError {
|
|
136
|
-
constructor(message = "Not Found", details) {
|
|
137
|
-
super(404, message, details);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
class ConflictError extends HttpError {
|
|
142
|
-
constructor(message = "Conflict", details) {
|
|
143
|
-
super(409, message, details);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
class UnprocessableEntityError extends HttpError {
|
|
148
|
-
constructor(message = "Unprocessable Entity", details) {
|
|
149
|
-
super(422, message, details);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
class ValidationError extends HttpError {
|
|
154
|
-
constructor(message = "Validation failed", details) {
|
|
155
|
-
super(422, message, details);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
class ForbiddenError extends HttpError {
|
|
160
|
-
constructor(message = "Forbidden", details) {
|
|
161
|
-
super(403, message, details);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
class UnauthorizedError extends HttpError {
|
|
166
|
-
constructor(message = "Unauthorized", details) {
|
|
167
|
-
super(401, message, details);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
class PayloadTooLargeError extends HttpError {
|
|
172
|
-
constructor(message = "Payload Too Large", details) {
|
|
173
|
-
super(413, message, details);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
class PreconditionFailedError extends HttpError {
|
|
178
|
-
constructor(message = "Precondition Failed", details) {
|
|
179
|
-
super(412, message, details);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// ../../src/core/security/safeUrl.ts
|
|
16
|
+
import { BadRequestError } from "@getstrata/core/errors/http";
|
|
184
17
|
var dnsLookup = dnsLookupImpl;
|
|
185
18
|
var BLOCKED_HOSTNAMES = new Set([
|
|
186
19
|
"localhost",
|
|
@@ -310,12 +143,13 @@ async function safeFetch(input, init = {}, options = {}) {
|
|
|
310
143
|
}
|
|
311
144
|
|
|
312
145
|
// ../../src/core/tenant/databaseTenantContext.ts
|
|
146
|
+
import { repositoryConnection as db } from "@getstrata/core/database/repositoryConnection";
|
|
313
147
|
async function runWithMigrationBypass(callback) {
|
|
314
|
-
await
|
|
148
|
+
await db`SELECT set_config('app.bypass_rls', 'true', false)`;
|
|
315
149
|
try {
|
|
316
150
|
return await callback();
|
|
317
151
|
} finally {
|
|
318
|
-
await
|
|
152
|
+
await db`SELECT set_config('app.bypass_rls', 'false', false)`;
|
|
319
153
|
}
|
|
320
154
|
}
|
|
321
155
|
|
|
@@ -372,7 +206,7 @@ async function exportPendingAuditLogs() {
|
|
|
372
206
|
return 0;
|
|
373
207
|
}
|
|
374
208
|
return await runWithMigrationBypass(async () => {
|
|
375
|
-
const rows = await
|
|
209
|
+
const rows = await db2`
|
|
376
210
|
SELECT
|
|
377
211
|
id,
|
|
378
212
|
user_id,
|
|
@@ -422,7 +256,7 @@ async function exportPendingAuditLogs() {
|
|
|
422
256
|
}
|
|
423
257
|
const ids = rows.map((row) => row.id);
|
|
424
258
|
for (const id of ids) {
|
|
425
|
-
await
|
|
259
|
+
await db2`UPDATE audit_log SET exported_at = NOW() WHERE id = ${id}`;
|
|
426
260
|
}
|
|
427
261
|
return rows.length;
|
|
428
262
|
});
|
|
@@ -73,12 +73,6 @@ function registerDefaultDatabasePool(connection) {
|
|
|
73
73
|
defaultPool.connection = connection;
|
|
74
74
|
defaultQuery.connection = createDatabaseQueryProxy(connection);
|
|
75
75
|
}
|
|
76
|
-
function getDefaultDatabasePool() {
|
|
77
|
-
if (!defaultPool.connection) {
|
|
78
|
-
throw new Error("Default database pool is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
|
|
79
|
-
}
|
|
80
|
-
return defaultPool.connection;
|
|
81
|
-
}
|
|
82
76
|
function getDefaultDatabaseQuery() {
|
|
83
77
|
if (!defaultQuery.connection) {
|
|
84
78
|
throw new Error("Default database query handle is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
|
|
@@ -179,77 +173,11 @@ class OrganizationMemberRepository {
|
|
|
179
173
|
}
|
|
180
174
|
var memberRepository_default = OrganizationMemberRepository;
|
|
181
175
|
|
|
182
|
-
// ../../src/core/
|
|
183
|
-
|
|
184
|
-
status;
|
|
185
|
-
details;
|
|
186
|
-
constructor(status, message, details) {
|
|
187
|
-
super(message);
|
|
188
|
-
this.name = new.target.name;
|
|
189
|
-
this.status = status;
|
|
190
|
-
this.details = details;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
class BadRequestError extends HttpError {
|
|
195
|
-
constructor(message = "Bad Request", details) {
|
|
196
|
-
super(400, message, details);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
class NotFoundError extends HttpError {
|
|
201
|
-
constructor(message = "Not Found", details) {
|
|
202
|
-
super(404, message, details);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
class ConflictError extends HttpError {
|
|
207
|
-
constructor(message = "Conflict", details) {
|
|
208
|
-
super(409, message, details);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
class UnprocessableEntityError extends HttpError {
|
|
213
|
-
constructor(message = "Unprocessable Entity", details) {
|
|
214
|
-
super(422, message, details);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
class ValidationError extends HttpError {
|
|
219
|
-
constructor(message = "Validation failed", details) {
|
|
220
|
-
super(422, message, details);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
class ForbiddenError extends HttpError {
|
|
225
|
-
constructor(message = "Forbidden", details) {
|
|
226
|
-
super(403, message, details);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
class UnauthorizedError extends HttpError {
|
|
231
|
-
constructor(message = "Unauthorized", details) {
|
|
232
|
-
super(401, message, details);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
class PayloadTooLargeError extends HttpError {
|
|
237
|
-
constructor(message = "Payload Too Large", details) {
|
|
238
|
-
super(413, message, details);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
class PreconditionFailedError extends HttpError {
|
|
243
|
-
constructor(message = "Precondition Failed", details) {
|
|
244
|
-
super(412, message, details);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
176
|
+
// ../../src/core/auth/accessControl.ts
|
|
177
|
+
import { ForbiddenError } from "@getstrata/core/errors/http";
|
|
247
178
|
|
|
248
179
|
// ../../src/core/auth/authContext.ts
|
|
249
180
|
var authContext = createAsyncContextStore("@getstrata/authContext");
|
|
250
|
-
function runWithAuthUser(user, callback) {
|
|
251
|
-
return authContext.run(user, callback);
|
|
252
|
-
}
|
|
253
181
|
function currentAuthUser() {
|
|
254
182
|
return authContext.getStore() ?? null;
|
|
255
183
|
}
|
|
@@ -1,22 +1,8 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// ../../src/core/
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
};
|
|
6
|
-
function bindDatabaseConnection(connection) {
|
|
7
|
-
boundConnectionHolder.connection = connection;
|
|
8
|
-
}
|
|
9
|
-
function getBoundDatabaseConnection() {
|
|
10
|
-
return boundConnectionHolder.connection;
|
|
11
|
-
}
|
|
12
|
-
function resetBoundDatabaseConnection() {
|
|
13
|
-
boundConnectionHolder.connection = null;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// ../../src/core/database/bindConnection.ts
|
|
17
|
-
function bindDatabaseConnection2(connection) {
|
|
18
|
-
bindDatabaseConnection(connection);
|
|
19
|
-
}
|
|
2
|
+
// ../../src/core/auth/scimAuthMiddleware.ts
|
|
3
|
+
import { bindDatabaseConnection } from "@getstrata/core/database/bindConnection";
|
|
4
|
+
import { resetBoundDatabaseConnection } from "@getstrata/core/database/boundConnection";
|
|
5
|
+
import { getDefaultDatabasePool as getDefaultDatabasePool2 } from "@getstrata/core/database/defaultConnection";
|
|
20
6
|
|
|
21
7
|
// ../../src/core/runtime/asyncContextStore.ts
|
|
22
8
|
import { AsyncLocalStorage } from "async_hooks";
|
|
@@ -44,54 +30,6 @@ function hasActiveDatabaseConnection() {
|
|
|
44
30
|
return activeConnection.getStore() !== undefined;
|
|
45
31
|
}
|
|
46
32
|
|
|
47
|
-
// ../../src/core/database/queryProxy.ts
|
|
48
|
-
var POOL_CONNECTION_METHODS = new Set(["begin", "close", "connect"]);
|
|
49
|
-
function createDatabaseQueryProxy(pool) {
|
|
50
|
-
function resolveDatabase() {
|
|
51
|
-
return getActiveDatabaseConnection(pool);
|
|
52
|
-
}
|
|
53
|
-
function resolveDatabaseForProperty(property) {
|
|
54
|
-
if (typeof property === "string" && POOL_CONNECTION_METHODS.has(property)) {
|
|
55
|
-
return pool;
|
|
56
|
-
}
|
|
57
|
-
return resolveDatabase();
|
|
58
|
-
}
|
|
59
|
-
return new Proxy(function database() {}, {
|
|
60
|
-
apply(_target, _thisArg, args) {
|
|
61
|
-
return resolveDatabase()(...args);
|
|
62
|
-
},
|
|
63
|
-
get(_target, property) {
|
|
64
|
-
const connection = resolveDatabaseForProperty(property);
|
|
65
|
-
const value = connection[property];
|
|
66
|
-
return typeof value === "function" ? value.bind(connection) : value;
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ../../src/core/database/defaultConnection.ts
|
|
72
|
-
var defaultPool = {
|
|
73
|
-
connection: null
|
|
74
|
-
};
|
|
75
|
-
var defaultQuery = {
|
|
76
|
-
connection: null
|
|
77
|
-
};
|
|
78
|
-
function registerDefaultDatabasePool(connection) {
|
|
79
|
-
defaultPool.connection = connection;
|
|
80
|
-
defaultQuery.connection = createDatabaseQueryProxy(connection);
|
|
81
|
-
}
|
|
82
|
-
function getDefaultDatabasePool() {
|
|
83
|
-
if (!defaultPool.connection) {
|
|
84
|
-
throw new Error("Default database pool is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
|
|
85
|
-
}
|
|
86
|
-
return defaultPool.connection;
|
|
87
|
-
}
|
|
88
|
-
function getDefaultDatabaseQuery() {
|
|
89
|
-
if (!defaultQuery.connection) {
|
|
90
|
-
throw new Error("Default database query handle is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
|
|
91
|
-
}
|
|
92
|
-
return defaultQuery.connection;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
33
|
// ../../src/domain/scim.ts
|
|
96
34
|
var TEST_SCIM_BEARER_TOKEN = "workhub-scim-test-token";
|
|
97
35
|
|
|
@@ -139,24 +77,10 @@ function resolveScimTenantFromToken(token) {
|
|
|
139
77
|
return null;
|
|
140
78
|
}
|
|
141
79
|
|
|
142
|
-
// ../../src/core/database/repositoryConnection.ts
|
|
143
|
-
function resolveRepositoryConnection() {
|
|
144
|
-
return getBoundDatabaseConnection() ?? getDefaultDatabaseQuery();
|
|
145
|
-
}
|
|
146
|
-
var repositoryConnection = new Proxy(function repositoryConnection2() {}, {
|
|
147
|
-
apply(_target, _thisArg, args) {
|
|
148
|
-
return resolveRepositoryConnection()(...args);
|
|
149
|
-
},
|
|
150
|
-
get(_target, property) {
|
|
151
|
-
const connection = resolveRepositoryConnection();
|
|
152
|
-
const value = connection[property];
|
|
153
|
-
return typeof value === "function" ? value.bind(connection) : value;
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
|
|
157
80
|
// ../../src/core/tenant/resolveTenant.ts
|
|
81
|
+
import { repositoryConnection as db } from "@getstrata/core/database/repositoryConnection";
|
|
158
82
|
async function resolveTenant(tenantId) {
|
|
159
|
-
const rows = await
|
|
83
|
+
const rows = await db`
|
|
160
84
|
SELECT id, slug, plan, region
|
|
161
85
|
FROM tenant
|
|
162
86
|
WHERE id = ${tenantId}
|
|
@@ -166,6 +90,9 @@ async function resolveTenant(tenantId) {
|
|
|
166
90
|
return row ? { id: row.id, slug: row.slug, plan: row.plan, region: row.region ?? "eu" } : null;
|
|
167
91
|
}
|
|
168
92
|
|
|
93
|
+
// ../../src/core/tenant/tenantDatabaseScope.ts
|
|
94
|
+
import { getDefaultDatabasePool } from "@getstrata/core/database/defaultConnection";
|
|
95
|
+
|
|
169
96
|
// ../../src/core/tenant/tenantContext.ts
|
|
170
97
|
var tenantContext = createAsyncContextStore("@getstrata/tenantContext");
|
|
171
98
|
function runWithTenant(tenant, callback) {
|
|
@@ -174,16 +101,6 @@ function runWithTenant(tenant, callback) {
|
|
|
174
101
|
function currentTenant() {
|
|
175
102
|
return tenantContext.getStore() ?? null;
|
|
176
103
|
}
|
|
177
|
-
function rateLimitMultiplierForPlan(plan) {
|
|
178
|
-
switch (plan) {
|
|
179
|
-
case "enterprise":
|
|
180
|
-
return 4;
|
|
181
|
-
case "pro":
|
|
182
|
-
return 2;
|
|
183
|
-
default:
|
|
184
|
-
return 1;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
104
|
|
|
188
105
|
// ../../src/core/tenant/tenantDatabaseScope.ts
|
|
189
106
|
async function applyTenantContextToTransaction(transaction, tenantId) {
|
|
@@ -224,7 +141,7 @@ function createScimAuthMiddleware() {
|
|
|
224
141
|
return jsonScimError("SCIM tenant not found.", 401);
|
|
225
142
|
}
|
|
226
143
|
return await runWithTenantDatabase(tenant, async () => {
|
|
227
|
-
|
|
144
|
+
bindDatabaseConnection(getActiveDatabaseConnection(getDefaultDatabasePool2()));
|
|
228
145
|
try {
|
|
229
146
|
return await next();
|
|
230
147
|
} finally {
|
|
@@ -152,12 +152,6 @@ function registerDefaultDatabasePool(connection) {
|
|
|
152
152
|
defaultPool.connection = connection;
|
|
153
153
|
defaultQuery.connection = createDatabaseQueryProxy(connection);
|
|
154
154
|
}
|
|
155
|
-
function getDefaultDatabasePool() {
|
|
156
|
-
if (!defaultPool.connection) {
|
|
157
|
-
throw new Error("Default database pool is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
|
|
158
|
-
}
|
|
159
|
-
return defaultPool.connection;
|
|
160
|
-
}
|
|
161
155
|
function getDefaultDatabaseQuery() {
|
|
162
156
|
if (!defaultQuery.connection) {
|
|
163
157
|
throw new Error("Default database query handle is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
|
|
@@ -1,71 +1,11 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// ../../src/core/errors/http.ts
|
|
3
|
-
class HttpError extends Error {
|
|
4
|
-
status;
|
|
5
|
-
details;
|
|
6
|
-
constructor(status, message, details) {
|
|
7
|
-
super(message);
|
|
8
|
-
this.name = new.target.name;
|
|
9
|
-
this.status = status;
|
|
10
|
-
this.details = details;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
class BadRequestError extends HttpError {
|
|
15
|
-
constructor(message = "Bad Request", details) {
|
|
16
|
-
super(400, message, details);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
class NotFoundError extends HttpError {
|
|
21
|
-
constructor(message = "Not Found", details) {
|
|
22
|
-
super(404, message, details);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
class ConflictError extends HttpError {
|
|
27
|
-
constructor(message = "Conflict", details) {
|
|
28
|
-
super(409, message, details);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
class UnprocessableEntityError extends HttpError {
|
|
33
|
-
constructor(message = "Unprocessable Entity", details) {
|
|
34
|
-
super(422, message, details);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
class ValidationError extends HttpError {
|
|
39
|
-
constructor(message = "Validation failed", details) {
|
|
40
|
-
super(422, message, details);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
class ForbiddenError extends HttpError {
|
|
45
|
-
constructor(message = "Forbidden", details) {
|
|
46
|
-
super(403, message, details);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
class UnauthorizedError extends HttpError {
|
|
51
|
-
constructor(message = "Unauthorized", details) {
|
|
52
|
-
super(401, message, details);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
class PayloadTooLargeError extends HttpError {
|
|
57
|
-
constructor(message = "Payload Too Large", details) {
|
|
58
|
-
super(413, message, details);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
class PreconditionFailedError extends HttpError {
|
|
63
|
-
constructor(message = "Precondition Failed", details) {
|
|
64
|
-
super(412, message, details);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
2
|
// ../../src/core/database/errors.ts
|
|
3
|
+
import {
|
|
4
|
+
BadRequestError,
|
|
5
|
+
ConflictError,
|
|
6
|
+
HttpError,
|
|
7
|
+
UnprocessableEntityError
|
|
8
|
+
} from "@getstrata/core/errors/http";
|
|
69
9
|
function isPostgresError(error) {
|
|
70
10
|
return typeof error === "object" && error !== null && (("errno" in error) || ("code" in error));
|
|
71
11
|
}
|