@getstrata/core 0.5.14 → 0.5.15

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.
Files changed (41) hide show
  1. package/dist/bootstrap/contracts.d.ts +2 -0
  2. package/dist/core/auth/membershipService.d.ts +5 -1
  3. package/dist/core/database/baseRepository.d.ts +6 -1
  4. package/dist/core/database/connectionContext.d.ts +2 -1
  5. package/dist/core/database/defaultConnection.d.ts +6 -0
  6. package/dist/core/database/queryProxy.d.ts +3 -0
  7. package/dist/core/database/repositoryConnection.d.ts +3 -3
  8. package/dist/core/jobs/dispatchWebhookJob.d.ts +0 -1
  9. package/dist/core/security/safeFetch.d.ts +2 -0
  10. package/dist/core/security/safeUrl.d.ts +16 -1
  11. package/dist/core/tenant/tenantDatabaseScope.d.ts +2 -1
  12. package/dist/db/connection/index.d.ts +1 -1
  13. package/dist/entries/auth/accessControl.js +1 -113
  14. package/dist/entries/auth/authContext.js +1 -15
  15. package/dist/entries/auth/guard.js +1 -3044
  16. package/dist/entries/auth/membershipContext.js +1 -276
  17. package/dist/entries/auth/membershipScope.js +1 -390
  18. package/dist/entries/auth/membershipService.js +1 -480
  19. package/dist/entries/auth/policy.js +1 -134
  20. package/dist/entries/database.js +1 -2398
  21. package/dist/entries/http/csrfToken.js +0 -6
  22. package/dist/entries/http/middleware.js +1 -68
  23. package/dist/entries/http/requestMetaContext.js +1 -18
  24. package/dist/entries/http/webErrorResponse.js +94 -563
  25. package/dist/entries/http/webFormRequest.js +0 -131
  26. package/dist/entries/http.js +1 -4091
  27. package/dist/entries/jobs/dispatchWebhookJob.js +109 -102
  28. package/dist/entries/queue/createAppQueue.js +111 -631
  29. package/dist/entries/queue/jobRunner.js +0 -3
  30. package/dist/entries/queue/publicQueue.js +45 -546
  31. package/dist/entries/queue/queueMetrics.js +111 -631
  32. package/dist/entries/security/safeUrl.js +29 -0
  33. package/dist/entries/security/securityEvents.js +1 -41
  34. package/dist/entries/tenant/tenantContext.js +1 -30
  35. package/dist/entries/tenant/tenantMiddleware.js +1 -312
  36. package/dist/entries/tracing/traceContext.js +1 -15
  37. package/dist/entries/view.js +94 -563
  38. package/dist/framework/public-api.d.ts +29 -6
  39. package/dist/index.js +2125 -2000
  40. package/dist/modules/user/repository.d.ts +1 -0
  41. package/package.json +6 -5
@@ -1,3 +1,4 @@
1
+ import type { StorageManager } from "../core/storage/storage";
1
2
  import type { CacheLike } from "../types/services";
2
3
  type CachedJson = <T>(cacheKey: string, loader: () => Promise<T>, tags?: string[], request?: Request) => Promise<Response>;
3
4
  type AppRouteMap = Record<string, any>;
@@ -23,6 +24,7 @@ declare class ConfigStore {
23
24
  interface AppDependencies {
24
25
  container: ServiceContainer;
25
26
  cache: CacheLike;
27
+ storage: StorageManager;
26
28
  }
27
29
  type MutableAppDependencies = Partial<Omit<AppDependencies, "container">> & Pick<AppDependencies, "container">;
28
30
  interface ProviderContext {
@@ -1,7 +1,10 @@
1
1
  import type { OrganizationMemberRole } from "../../modules/organization/memberTypes";
2
2
  import { type AuthUser } from "./authContext";
3
+ import { membershipRepository as defaultMembershipRepository } from "./membershipContext";
4
+ type MembershipRepositoryLike = Pick<typeof defaultMembershipRepository, "listForUser" | "findMembership" | "listForOrganization" | "addMember" | "removeMember">;
3
5
  declare class MembershipService {
4
- constructor();
6
+ private readonly members;
7
+ constructor(members?: MembershipRepositoryLike);
5
8
  listOrganizationIdsForUser(userId: number): Promise<number[]>;
6
9
  getOrgRole(userId: number, organizationId: number): Promise<OrganizationMemberRole | null>;
7
10
  requireOrgAccess(organizationId: number, minimumRole?: OrganizationMemberRole, user?: AuthUser | null): Promise<OrganizationMemberRole>;
@@ -16,5 +19,6 @@ declare class MembershipService {
16
19
  removeMember(organizationId: number, userId: number): Promise<boolean>;
17
20
  }
18
21
  declare function resolveMembershipService(): MembershipService;
22
+ export type { MembershipRepositoryLike };
19
23
  export default MembershipService;
20
24
  export { resolveMembershipService };
@@ -9,6 +9,11 @@ type ExtendedQueryOptions<TEntity extends object> = QueryOptions<TEntity> & {
9
9
  };
10
10
  interface DatabaseConnection {
11
11
  unsafe<T>(query: string, params?: readonly unknown[]): Promise<T[]>;
12
+ begin?<T>(callback: (transaction: DatabaseConnection) => Promise<T>): Promise<T>;
13
+ close?(): Promise<void>;
14
+ }
15
+ interface SqlDatabaseConnection extends DatabaseConnection {
16
+ (strings: TemplateStringsArray, ...values: unknown[]): Promise<unknown[]>;
12
17
  }
13
18
  type ErrorFactory<TValue> = (value: TValue) => Error;
14
19
  declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TEntity & string> {
@@ -59,4 +64,4 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
59
64
  loadMorphToForChildren<TChild extends object, TParent extends object, MorphTypeKey extends keyof TChild & string, MorphIdKey extends keyof TChild & string, OwnerKey extends keyof TParent & string>(children: readonly TChild[], relation: MorphToRelation<TChild, MorphTypeKey, MorphIdKey>, repositoriesByType: ReadonlyMap<string, BaseRepository<TParent, OwnerKey>>, options?: Omit<QueryOptions<TParent>, "where">): Promise<Map<TChild[MorphIdKey], TParent>>;
60
65
  }
61
66
  export default BaseRepository;
62
- export type { DatabaseConnection };
67
+ export type { DatabaseConnection, SqlDatabaseConnection };
@@ -3,5 +3,6 @@ type ActiveDatabaseHandle = {
3
3
  };
4
4
  declare function runWithDatabaseConnection<T>(connection: ActiveDatabaseHandle, callback: () => T | Promise<T>): T | Promise<T>;
5
5
  declare function getActiveDatabaseConnection<T extends ActiveDatabaseHandle>(fallback: T): T;
6
+ declare function hasActiveDatabaseConnection(): boolean;
6
7
  export type { ActiveDatabaseHandle };
7
- export { getActiveDatabaseConnection, runWithDatabaseConnection };
8
+ export { getActiveDatabaseConnection, hasActiveDatabaseConnection, runWithDatabaseConnection };
@@ -0,0 +1,6 @@
1
+ import type { SqlDatabaseConnection } from "./baseRepository";
2
+ declare function registerDefaultDatabasePool(connection: SqlDatabaseConnection): void;
3
+ declare function getDefaultDatabasePool(): SqlDatabaseConnection;
4
+ declare function getDefaultDatabaseQuery(): SqlDatabaseConnection;
5
+ declare function resetDefaultDatabasePoolForTests(): void;
6
+ export { getDefaultDatabasePool, getDefaultDatabaseQuery, registerDefaultDatabasePool, resetDefaultDatabasePoolForTests, };
@@ -0,0 +1,3 @@
1
+ import type { SqlDatabaseConnection } from "./baseRepository";
2
+ declare function createDatabaseQueryProxy(pool: SqlDatabaseConnection): SqlDatabaseConnection;
3
+ export { createDatabaseQueryProxy };
@@ -1,4 +1,4 @@
1
- import type { DatabaseConnection } from "./baseRepository";
2
- declare function resolveRepositoryConnection(): DatabaseConnection;
3
- declare const repositoryConnection: DatabaseConnection;
1
+ import type { SqlDatabaseConnection } from "./baseRepository";
2
+ declare function resolveRepositoryConnection(): SqlDatabaseConnection;
3
+ declare const repositoryConnection: SqlDatabaseConnection;
4
4
  export { repositoryConnection, resolveRepositoryConnection };
@@ -5,7 +5,6 @@ interface DispatchWebhookPayload {
5
5
  payload: Record<string, unknown>;
6
6
  }
7
7
  declare class DispatchWebhookJob extends Job<DispatchWebhookPayload> {
8
- constructor();
9
8
  readonly maxAttempts = 3;
10
9
  readonly backoffMs = 2000;
11
10
  handle(payload: DispatchWebhookPayload): Promise<void>;
@@ -2,6 +2,8 @@ declare const DEFAULT_FETCH_TIMEOUT_MS = 10000;
2
2
  interface SafeFetchOptions {
3
3
  timeoutMs?: number;
4
4
  maxRedirects?: number;
5
+ allowHttp?: boolean;
6
+ resolveDns?: boolean;
5
7
  }
6
8
  declare function safeFetch(input: string, init?: RequestInit, options?: SafeFetchOptions): Promise<Response>;
7
9
  export type { SafeFetchOptions };
@@ -1,5 +1,20 @@
1
+ type DnsLookupResult = {
2
+ address: string;
3
+ family: number;
4
+ };
5
+ type DnsLookup = (hostname: string, options: {
6
+ all: true;
7
+ verbatim: true;
8
+ }) => Promise<DnsLookupResult[]>;
1
9
  declare function isBlockedHostname(hostname: string): boolean;
2
10
  declare function assertSafeOutboundUrl(rawUrl: string, options?: {
3
11
  allowHttp?: boolean;
4
12
  }): URL;
5
- export { assertSafeOutboundUrl, isBlockedHostname };
13
+ declare function isBlockedIpAddress(address: string): boolean;
14
+ declare function assertSafeOutboundUrlResolved(rawUrl: string, options?: {
15
+ allowHttp?: boolean;
16
+ resolveDns?: boolean;
17
+ }): Promise<URL>;
18
+ declare function setDnsLookupForTests(lookupFn: DnsLookup): void;
19
+ declare function resetDnsLookupForTests(): void;
20
+ export { assertSafeOutboundUrl, assertSafeOutboundUrlResolved, isBlockedHostname, isBlockedIpAddress, resetDnsLookupForTests, setDnsLookupForTests, };
@@ -4,4 +4,5 @@ type TransactionHandle = {
4
4
  };
5
5
  declare function applyTenantContextToTransaction(transaction: TransactionHandle, tenantId: number): Promise<void>;
6
6
  declare function runWithTenantDatabase<T>(tenant: TenantContext, callback: () => T | Promise<T>): Promise<T>;
7
- export { applyTenantContextToTransaction, runWithTenantDatabase };
7
+ declare function isInsideTenantDatabaseScope(tenantId?: number | undefined): boolean;
8
+ export { applyTenantContextToTransaction, isInsideTenantDatabaseScope, runWithTenantDatabase };
@@ -1,4 +1,4 @@
1
- import { type DatabaseConnection } from "./createConnection";
1
+ import type { DatabaseConnection } from "./createConnection";
2
2
  declare function getDatabase(): DatabaseConnection;
3
3
  declare function pingDatabase(connection?: DatabaseConnection): Promise<boolean>;
4
4
  declare function ensureDatabaseConnection(): Promise<DatabaseConnection>;
@@ -1,113 +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
- // ../../src/core/auth/authContext.ts
69
- import { AsyncLocalStorage } from "async_hooks";
70
- var authContext = new AsyncLocalStorage;
71
- function runWithAuthUser(user, callback) {
72
- return authContext.run(user, callback);
73
- }
74
- function currentAuthUser() {
75
- return authContext.getStore() ?? null;
76
- }
77
-
78
- // ../../src/core/auth/accessControl.ts
79
- var ROLE_RANK = {
80
- member: 1,
81
- admin: 2,
82
- owner: 3
83
- };
84
- function isGlobalAdmin(user) {
85
- return user?.role === "admin";
86
- }
87
- function hasMinimumOrgRole(role, minimum) {
88
- if (!role) {
89
- return false;
90
- }
91
- return ROLE_RANK[role] >= ROLE_RANK[minimum];
92
- }
93
- function requireAuthenticatedUser() {
94
- const user = currentAuthUser();
95
- if (!user) {
96
- throw new ForbiddenError("Authentication required.");
97
- }
98
- return user;
99
- }
100
- function resolveUserId(user) {
101
- const userId = typeof user.id === "number" ? user.id : Number(user.id);
102
- if (!Number.isInteger(userId) || userId <= 0) {
103
- throw new ForbiddenError("Invalid authenticated user.");
104
- }
105
- return userId;
106
- }
107
- export {
108
- resolveUserId,
109
- requireAuthenticatedUser,
110
- isGlobalAdmin,
111
- hasMinimumOrgRole,
112
- ROLE_RANK
113
- };
1
+ export * from "../../index.js";
@@ -1,15 +1 @@
1
- // @bun
2
- // ../../src/core/auth/authContext.ts
3
- import { AsyncLocalStorage } from "async_hooks";
4
- var authContext = new AsyncLocalStorage;
5
- function runWithAuthUser(user, callback) {
6
- return authContext.run(user, callback);
7
- }
8
- function currentAuthUser() {
9
- return authContext.getStore() ?? null;
10
- }
11
- export {
12
- runWithAuthUser,
13
- currentAuthUser,
14
- authContext
15
- };
1
+ export * from "../../index.js";