@getstrata/core 0.2.0 → 0.3.0

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 (129) hide show
  1. package/README.md +6 -0
  2. package/dist/bootstrap/applicationRegistry.d.ts +16 -0
  3. package/dist/bootstrap/config.d.ts +19 -0
  4. package/dist/bootstrap/contracts.d.ts +63 -0
  5. package/dist/bootstrap/httpKernel.d.ts +26 -0
  6. package/dist/config/app.d.ts +10 -0
  7. package/dist/config/contentSecurityPolicy.d.ts +5 -0
  8. package/dist/config/cors.d.ts +9 -0
  9. package/dist/config/database.d.ts +10 -0
  10. package/dist/config/features.d.ts +18 -0
  11. package/dist/config/frontend.d.ts +6 -0
  12. package/dist/config/rateLimit.d.ts +9 -0
  13. package/dist/config/uploads.d.ts +5 -0
  14. package/dist/core/auth/accessControl.d.ts +8 -0
  15. package/dist/core/auth/authContext.d.ts +12 -0
  16. package/dist/core/auth/guard.d.ts +36 -0
  17. package/dist/core/auth/membershipContext.d.ts +16 -0
  18. package/dist/core/auth/membershipContextMiddleware.d.ts +3 -0
  19. package/dist/core/auth/membershipMiddleware.d.ts +2 -0
  20. package/dist/core/auth/oauth/oidcProvider.d.ts +18 -0
  21. package/dist/core/auth/oauth/providers.d.ts +22 -0
  22. package/dist/core/auth/oauth/samlProvider.d.ts +9 -0
  23. package/dist/core/auth/oauth/types.d.ts +11 -0
  24. package/dist/core/auth/password.d.ts +3 -0
  25. package/dist/core/auth/policy.d.ts +15 -0
  26. package/dist/core/auth/tokenHash.d.ts +3 -0
  27. package/dist/core/cache/repository.d.ts +17 -0
  28. package/dist/core/cache/store.d.ts +12 -0
  29. package/dist/core/cache/taggedCache.d.ts +9 -0
  30. package/dist/core/cache/tags.d.ts +11 -0
  31. package/dist/core/crypto/fieldEncryption.d.ts +13 -0
  32. package/dist/core/crypto/mfaSecret.d.ts +3 -0
  33. package/dist/core/database/baseRepository.d.ts +44 -0
  34. package/dist/core/database/connection.d.ts +7 -0
  35. package/dist/core/database/connectionContext.d.ts +7 -0
  36. package/dist/core/database/errors.d.ts +12 -0
  37. package/dist/core/database/index.d.ts +11 -0
  38. package/dist/core/database/query.d.ts +51 -0
  39. package/dist/core/database/relationships.d.ts +26 -0
  40. package/dist/core/database/table.d.ts +13 -0
  41. package/dist/core/database/transaction.d.ts +3 -0
  42. package/dist/core/database/types.d.ts +29 -0
  43. package/dist/core/errors/http.d.ts +33 -0
  44. package/dist/core/events/eventBus.d.ts +10 -0
  45. package/dist/core/events/index.d.ts +4 -0
  46. package/dist/core/facades/index.d.ts +10 -0
  47. package/dist/core/http/authMiddleware.d.ts +5 -0
  48. package/dist/core/http/authorizeMiddleware.d.ts +5 -0
  49. package/dist/core/http/bodySizeLimitMiddleware.d.ts +4 -0
  50. package/dist/core/http/conditionalResponse.d.ts +2 -0
  51. package/dist/core/http/contentNegotiation.d.ts +2 -0
  52. package/dist/core/http/corsMiddleware.d.ts +3 -0
  53. package/dist/core/http/csrfMiddleware.d.ts +3 -0
  54. package/dist/core/http/csrfToken.d.ts +14 -0
  55. package/dist/core/http/etag.d.ts +18 -0
  56. package/dist/core/http/flashMiddleware.d.ts +3 -0
  57. package/dist/core/http/flashSession.d.ts +12 -0
  58. package/dist/core/http/formRequest.d.ts +10 -0
  59. package/dist/core/http/index.d.ts +27 -0
  60. package/dist/core/http/loginThrottleMiddleware.d.ts +11 -0
  61. package/dist/core/http/memoryThrottleMiddleware.d.ts +9 -0
  62. package/dist/core/http/metricsMiddleware.d.ts +4 -0
  63. package/dist/core/http/middleware.d.ts +8 -0
  64. package/dist/core/http/pagination.d.ts +11 -0
  65. package/dist/core/http/parseFormBody.d.ts +6 -0
  66. package/dist/core/http/parseMultipartUpload.d.ts +10 -0
  67. package/dist/core/http/requestMetaContext.d.ts +16 -0
  68. package/dist/core/http/requireAbilityMiddleware.d.ts +4 -0
  69. package/dist/core/http/requireAuthMiddleware.d.ts +4 -0
  70. package/dist/core/http/requireGlobalAdminMiddleware.d.ts +3 -0
  71. package/dist/core/http/requireWebAuthMiddleware.d.ts +4 -0
  72. package/dist/core/http/resources.d.ts +7 -0
  73. package/dist/core/http/route.d.ts +6 -0
  74. package/dist/core/http/routeMiddleware.d.ts +3 -0
  75. package/dist/core/http/routeModelBinding.d.ts +3 -0
  76. package/dist/core/http/securedRouteModelBinding.d.ts +10 -0
  77. package/dist/core/http/securityHeadersMiddleware.d.ts +3 -0
  78. package/dist/core/http/throttleMiddleware.d.ts +11 -0
  79. package/dist/core/http/validation.d.ts +23 -0
  80. package/dist/core/http/webErrorResponse.d.ts +5 -0
  81. package/dist/core/http/webFormRequest.d.ts +6 -0
  82. package/dist/core/logging/logger.d.ts +17 -0
  83. package/dist/core/logging/requestLoggingMiddleware.d.ts +3 -0
  84. package/dist/core/mail/mailer.d.ts +36 -0
  85. package/dist/core/metrics/prometheus.d.ts +26 -0
  86. package/dist/core/pagination/index.d.ts +17 -0
  87. package/dist/core/queue/index.d.ts +19 -0
  88. package/dist/core/security/publicReads.d.ts +3 -0
  89. package/dist/core/security/securityEvents.d.ts +6 -0
  90. package/dist/core/security/tokenExpiry.d.ts +2 -0
  91. package/dist/core/security/totp.d.ts +3 -0
  92. package/dist/core/storage/storage.d.ts +41 -0
  93. package/dist/core/tenant/databaseTenantContext.d.ts +2 -0
  94. package/dist/core/tenant/resolveTenant.d.ts +3 -0
  95. package/dist/core/tenant/tenantContext.d.ts +14 -0
  96. package/dist/core/tenant/tenantDatabaseScope.d.ts +7 -0
  97. package/dist/core/tenant/tenantMiddleware.d.ts +6 -0
  98. package/dist/core/tracing/otel.d.ts +26 -0
  99. package/dist/core/tracing/traceContext.d.ts +10 -0
  100. package/dist/core/tracing/tracingMiddleware.d.ts +3 -0
  101. package/dist/core/view/etaViewEngine.d.ts +15 -0
  102. package/dist/core/view/htmlResponse.d.ts +6 -0
  103. package/dist/core/view/index.d.ts +5 -0
  104. package/dist/core/view/viewEngine.d.ts +6 -0
  105. package/dist/core/view/webLayoutData.d.ts +17 -0
  106. package/dist/db/connection/createConnection.d.ts +6 -0
  107. package/dist/db/connection/index.d.ts +11 -0
  108. package/dist/domain/abilities.d.ts +5 -0
  109. package/dist/domain/auth.d.ts +4 -0
  110. package/dist/framework/public-api.d.ts +30 -0
  111. package/dist/index.js +17 -2
  112. package/dist/modules/organization/memberRepository.d.ts +14 -0
  113. package/dist/modules/organization/memberTypes.d.ts +9 -0
  114. package/dist/modules/user/apiTokenRepository.d.ts +8 -0
  115. package/dist/modules/user/apiTokenTable.d.ts +3 -0
  116. package/dist/modules/user/authService.d.ts +23 -0
  117. package/dist/modules/user/notificationRepository.d.ts +6 -0
  118. package/dist/modules/user/notificationService.d.ts +25 -0
  119. package/dist/modules/user/notificationTable.d.ts +3 -0
  120. package/dist/modules/user/notificationTypes.d.ts +12 -0
  121. package/dist/modules/user/oauthIdentityRepository.d.ts +9 -0
  122. package/dist/modules/user/provider.d.ts +11 -0
  123. package/dist/modules/user/repository.d.ts +12 -0
  124. package/dist/modules/user/table.d.ts +3 -0
  125. package/dist/modules/user/tokenService.d.ts +29 -0
  126. package/dist/modules/user/types.d.ts +46 -0
  127. package/dist/types/services.d.ts +16 -0
  128. package/package.json +7 -6
  129. package/index.ts +0 -1
@@ -0,0 +1,2 @@
1
+ declare function resolveDefaultTokenExpiryDays(): number | null;
2
+ export { resolveDefaultTokenExpiryDays };
@@ -0,0 +1,3 @@
1
+ declare function generateTotp(secret: string, counter: number, digits?: number): string;
2
+ declare function verifyTotp(secret: string, token: string, window?: number): boolean;
3
+ export { generateTotp, verifyTotp };
@@ -0,0 +1,41 @@
1
+ import { S3Client } from "bun";
2
+ interface StorageDriver {
3
+ put(path: string, contents: string | Uint8Array): Promise<string>;
4
+ get(path: string): Promise<Uint8Array | null>;
5
+ delete(path: string): Promise<boolean>;
6
+ }
7
+ interface S3StorageConfig {
8
+ accessKeyId: string;
9
+ secretAccessKey: string;
10
+ bucket: string;
11
+ region?: string;
12
+ endpoint?: string;
13
+ }
14
+ declare class LocalStorageDriver implements StorageDriver {
15
+ private readonly rootDirectory;
16
+ constructor(rootDirectory: string);
17
+ private resolvePath;
18
+ put(path: string, contents: string | Uint8Array): Promise<string>;
19
+ get(path: string): Promise<Uint8Array | null>;
20
+ delete(path: string): Promise<boolean>;
21
+ }
22
+ declare class S3StorageDriver implements StorageDriver {
23
+ private readonly client;
24
+ constructor(client: S3Client);
25
+ put(path: string, contents: string | Uint8Array): Promise<string>;
26
+ get(path: string): Promise<Uint8Array | null>;
27
+ delete(path: string): Promise<boolean>;
28
+ }
29
+ declare class StorageManager {
30
+ private readonly driver;
31
+ constructor(driver: StorageDriver);
32
+ put(path: string, contents: string | Uint8Array): Promise<string>;
33
+ get(path: string): Promise<Uint8Array | null>;
34
+ delete(path: string): Promise<boolean>;
35
+ }
36
+ declare function resolveS3Config(): S3StorageConfig;
37
+ declare function createS3Client(config?: S3StorageConfig): S3Client;
38
+ declare function createStorageDriver(): StorageDriver;
39
+ declare function storage(): StorageManager;
40
+ export type { S3StorageConfig, StorageDriver };
41
+ export { createS3Client, createStorageDriver, LocalStorageDriver, resolveS3Config, S3StorageDriver, StorageManager, storage, };
@@ -0,0 +1,2 @@
1
+ declare function runWithMigrationBypass<T>(callback: () => T | Promise<T>): Promise<T>;
2
+ export { runWithMigrationBypass };
@@ -0,0 +1,3 @@
1
+ import type { TenantContext } from "./tenantContext";
2
+ declare function resolveTenant(tenantId: number): Promise<TenantContext | null>;
3
+ export { resolveTenant };
@@ -0,0 +1,14 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ type TenantContext = {
3
+ id: number;
4
+ slug: string;
5
+ plan: "free" | "pro" | "enterprise";
6
+ region: "eu" | "us" | "apac";
7
+ };
8
+ declare const tenantContext: AsyncLocalStorage<TenantContext>;
9
+ declare function runWithTenant<T>(tenant: TenantContext, callback: () => T | Promise<T>): T | Promise<T>;
10
+ declare function currentTenant(): TenantContext | null;
11
+ declare function currentTenantId(): number;
12
+ declare function rateLimitMultiplierForPlan(plan: TenantContext["plan"]): number;
13
+ export type { TenantContext };
14
+ export { currentTenant, currentTenantId, rateLimitMultiplierForPlan, runWithTenant, tenantContext };
@@ -0,0 +1,7 @@
1
+ import { type TenantContext } from "./tenantContext";
2
+ type TransactionHandle = {
3
+ unsafe(query: string, params?: readonly unknown[]): Promise<unknown[]>;
4
+ };
5
+ declare function applyTenantContextToTransaction(transaction: TransactionHandle, tenantId: number): Promise<void>;
6
+ declare function runWithTenantDatabase<T>(tenant: TenantContext, callback: () => T | Promise<T>): Promise<T>;
7
+ export { applyTenantContextToTransaction, runWithTenantDatabase };
@@ -0,0 +1,6 @@
1
+ import type { TenantContext } from "./tenantContext";
2
+ declare const DEFAULT_TENANT: TenantContext;
3
+ declare function resolveUserTenantId(userId: number): Promise<number>;
4
+ declare function auditChecksum(payload: Record<string, unknown>): string;
5
+ declare function createTenantMiddleware(): (request: Request, next: () => Promise<Response>) => Promise<Response>;
6
+ export { auditChecksum, createTenantMiddleware, DEFAULT_TENANT, resolveUserTenantId };
@@ -0,0 +1,26 @@
1
+ interface OtelSpan {
2
+ traceId: string;
3
+ spanId: string;
4
+ name: string;
5
+ startTimeUnixNano: string;
6
+ endTimeUnixNano: string;
7
+ attributes: Array<{
8
+ key: string;
9
+ value: {
10
+ stringValue: string;
11
+ };
12
+ }>;
13
+ status: {
14
+ code: number;
15
+ };
16
+ }
17
+ declare function createSpan(input: {
18
+ traceId: string;
19
+ name: string;
20
+ startedAt: number;
21
+ endedAt: number;
22
+ attributes?: Record<string, string>;
23
+ }): OtelSpan;
24
+ declare function exportOtelSpan(span: OtelSpan): Promise<void>;
25
+ export type { OtelSpan };
26
+ export { createSpan, exportOtelSpan };
@@ -0,0 +1,10 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ type TraceContext = {
3
+ traceId: string;
4
+ spanId: string;
5
+ };
6
+ declare const traceContextStorage: AsyncLocalStorage<TraceContext>;
7
+ declare function runWithTraceContext<T>(context: TraceContext, callback: () => T | Promise<T>): T | Promise<T>;
8
+ declare function currentTraceId(): string | null;
9
+ export type { TraceContext };
10
+ export { currentTraceId, runWithTraceContext, traceContextStorage };
@@ -0,0 +1,3 @@
1
+ import type { Middleware } from "../http/middleware";
2
+ declare function createTracingMiddleware(): Middleware;
3
+ export { createTracingMiddleware };
@@ -0,0 +1,15 @@
1
+ import type { ViewEngine } from "./viewEngine";
2
+ declare const DEFAULT_VIEWS_DIRECTORY: string;
3
+ declare const DEFAULT_LAYOUT = "layouts/app.eta";
4
+ interface RenderOptions {
5
+ layout?: string | false;
6
+ }
7
+ type LayoutDataResolver = () => Promise<Record<string, unknown>>;
8
+ declare class EtaViewEngine implements ViewEngine {
9
+ private readonly eta;
10
+ private readonly resolveLayoutData?;
11
+ constructor(viewsDirectory?: string, resolveLayoutData?: LayoutDataResolver);
12
+ render(name: string, data?: Record<string, unknown>, options?: RenderOptions): Promise<string>;
13
+ }
14
+ export type { RenderOptions };
15
+ export { DEFAULT_LAYOUT, DEFAULT_VIEWS_DIRECTORY, EtaViewEngine };
@@ -0,0 +1,6 @@
1
+ declare function htmlResponse(html: string, init?: {
2
+ status?: number;
3
+ statusText?: string;
4
+ }): Response;
5
+ declare function isHtmxRequest(request: Request): boolean;
6
+ export { htmlResponse, isHtmxRequest };
@@ -0,0 +1,5 @@
1
+ export { DEFAULT_VIEWS_DIRECTORY, EtaViewEngine } from "./etaViewEngine";
2
+ export { htmlResponse, isHtmxRequest } from "./htmlResponse";
3
+ export type { ViewEngine } from "./viewEngine";
4
+ export type { WebLayoutAuthUser, WebLayoutData } from "./webLayoutData";
5
+ export { resolveWebLayoutData } from "./webLayoutData";
@@ -0,0 +1,6 @@
1
+ interface ViewEngine {
2
+ render(name: string, data?: Record<string, unknown>, options?: {
3
+ layout?: string | false;
4
+ }): Promise<string>;
5
+ }
6
+ export type { ViewEngine };
@@ -0,0 +1,17 @@
1
+ import type { ServiceContainer } from "../../bootstrap/contracts";
2
+ interface WebLayoutAuthUser {
3
+ id: number;
4
+ email: string;
5
+ role: string;
6
+ }
7
+ interface WebLayoutData {
8
+ authUser: WebLayoutAuthUser | null;
9
+ csrfToken: string;
10
+ flash: {
11
+ level: string;
12
+ message: string;
13
+ } | null;
14
+ }
15
+ declare function resolveWebLayoutData(container: ServiceContainer, request?: Request): Promise<Record<string, unknown>>;
16
+ export type { WebLayoutAuthUser, WebLayoutData };
17
+ export { resolveWebLayoutData };
@@ -0,0 +1,6 @@
1
+ import { SQL } from "bun";
2
+ import type { DatabaseConfig } from "../../config/database";
3
+ type DatabaseConnection = InstanceType<typeof SQL>;
4
+ declare function createDatabaseConnection(config: DatabaseConfig): DatabaseConnection;
5
+ export type { DatabaseConnection };
6
+ export { createDatabaseConnection };
@@ -0,0 +1,11 @@
1
+ import { type DatabaseConnection } from "./createConnection";
2
+ declare function getDatabase(): DatabaseConnection;
3
+ declare function pingDatabase(connection?: DatabaseConnection): Promise<boolean>;
4
+ declare function ensureDatabaseConnection(): Promise<DatabaseConnection>;
5
+ declare function closeDatabase(): Promise<void>;
6
+ declare function replaceDatabaseConnectionForTests(connection?: DatabaseConnection): Promise<void>;
7
+ declare function resetDatabaseConnectionForTests(connection: DatabaseConnection): void;
8
+ declare const db: Bun.SQL;
9
+ export default db;
10
+ export type { DatabaseConnection };
11
+ export { closeDatabase, ensureDatabaseConnection, getDatabase, pingDatabase, replaceDatabaseConnectionForTests, resetDatabaseConnectionForTests, };
@@ -0,0 +1,5 @@
1
+ declare const MEMBER_ABILITIES: readonly ["organizations:read", "projects:read", "projects:create", "tasks:read", "tasks:create", "comments:read", "comments:create", "attachments:read", "attachments:create", "auth:tokens:read", "auth:tokens:write"];
2
+ declare const ADMIN_ABILITIES: readonly ["organizations:read", "projects:read", "projects:create", "tasks:read", "tasks:create", "comments:read", "comments:create", "attachments:read", "attachments:create", "auth:tokens:read", "auth:tokens:write", "organizations:create", "organizations:update", "organizations:delete", "projects:update", "projects:delete", "tasks:update", "tasks:delete", "comments:update", "comments:delete", "attachments:delete", "webhooks:read", "webhooks:write", "audit:read"];
3
+ declare const PLATFORM_ADMIN_ABILITIES: readonly ["*"];
4
+ declare function resolveAbilitiesForRole(role: string | null | undefined): string[];
5
+ export { ADMIN_ABILITIES, MEMBER_ABILITIES, PLATFORM_ADMIN_ABILITIES, resolveAbilitiesForRole };
@@ -0,0 +1,4 @@
1
+ export declare const TEST_ADMIN_API_TOKEN = "workhub-admin-test-token";
2
+ export declare const TEST_MEMBER_API_TOKEN = "workhub-member-test-token";
3
+ export declare const USER_ROLES: readonly ["admin", "member"];
4
+ export type UserRole = (typeof USER_ROLES)[number];
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Stable framework surface for application modules and future package extraction.
3
+ * Import from `@getstrata/core` (workspace) or `src/framework/public-api`.
4
+ */
5
+ export type { ServiceProvider } from "../bootstrap/contracts";
6
+ export { ConfigStore, resolveService, ServiceContainer, } from "../bootstrap/contracts";
7
+ export type { AuthUser } from "../core/auth/authContext";
8
+ export { currentAuthUser, runWithAuthUser } from "../core/auth/authContext";
9
+ export { Policy } from "../core/auth/policy";
10
+ export { default as CacheRepository } from "../core/cache/repository";
11
+ export { CACHE_TAGS } from "../core/cache/tags";
12
+ export { default as BaseRepository } from "../core/database/baseRepository";
13
+ export { defineTable } from "../core/database/table";
14
+ export { BadRequestError, ConflictError, ForbiddenError, NotFoundError, PreconditionFailedError, UnauthorizedError, UnprocessableEntityError, ValidationError, } from "../core/errors/http";
15
+ export { EventBus } from "../core/events/eventBus";
16
+ export { auth, cache, config, events, log, mail, policyGate, queue, storage, } from "../core/facades";
17
+ export { createdResponse, jsonResponse, noContentResponse, paginatedResponse, parsePaginationQuery, securedBindRouteModel, withErrorHandling, } from "../core/http";
18
+ export { assertIfMatch, etagFromResource, isEtagEnabled, } from "../core/http/etag";
19
+ export { FormRequest } from "../core/http/formRequest";
20
+ export { createMetricsMiddleware, normalizeMetricPath } from "../core/http/metricsMiddleware";
21
+ export type { Middleware, RouteHandler } from "../core/http/middleware";
22
+ export { WebFormRequest } from "../core/http/webFormRequest";
23
+ export type { MailDriver, MailMessage } from "../core/mail/mailer";
24
+ export { LogMailDriver, Mailer, mailer } from "../core/mail/mailer";
25
+ export type { MetricLabels } from "../core/metrics/prometheus";
26
+ export { PrometheusRegistry, prometheusRegistry } from "../core/metrics/prometheus";
27
+ export type { Queue, QueuePriority } from "../core/queue";
28
+ export { AsyncQueue, createQueue, Job, SyncQueue } from "../core/queue";
29
+ export type { StorageDriver } from "../core/storage/storage";
30
+ export { LocalStorageDriver, StorageManager } from "../core/storage/storage";
package/dist/index.js CHANGED
@@ -285,9 +285,12 @@ function createDatabaseConnection(config) {
285
285
 
286
286
  // ../../src/db/connection/index.ts
287
287
  var connectionHolder = {
288
- connection: createDatabaseConnection(databaseConfig)
288
+ connection: null
289
289
  };
290
290
  function getDatabase() {
291
+ if (!connectionHolder.connection) {
292
+ connectionHolder.connection = createDatabaseConnection(databaseConfig);
293
+ }
291
294
  return connectionHolder.connection;
292
295
  }
293
296
  var POOL_CONNECTION_METHODS = new Set(["begin", "close", "connect"]);
@@ -530,11 +533,23 @@ function buildQueryWhereClause(table, options = {}) {
530
533
  params
531
534
  };
532
535
  }
536
+ function isQueryOrder(value) {
537
+ return "column" in value;
538
+ }
533
539
  function normalizeOrderBy(orderBy) {
534
540
  if (!orderBy) {
535
541
  return [];
536
542
  }
537
- return Array.isArray(orderBy) ? orderBy : [orderBy];
543
+ if (Array.isArray(orderBy)) {
544
+ return orderBy;
545
+ }
546
+ if (isQueryOrder(orderBy)) {
547
+ return [orderBy];
548
+ }
549
+ return Object.entries(orderBy).map(([column, direction]) => ({
550
+ column,
551
+ direction
552
+ }));
538
553
  }
539
554
  function buildOrderByClause(tableName, orderBy) {
540
555
  const parts = normalizeOrderBy(orderBy).map(({ column, direction }) => {
@@ -0,0 +1,14 @@
1
+ import type { OrganizationMemberRecord, OrganizationMemberRole } from "./memberTypes";
2
+ declare class OrganizationMemberRepository {
3
+ constructor();
4
+ findMembership(userId: number, organizationId: number): Promise<OrganizationMemberRecord | null>;
5
+ listForUser(userId: number): Promise<OrganizationMemberRecord[]>;
6
+ listForOrganization(organizationId: number): Promise<OrganizationMemberRecord[]>;
7
+ addMember(input: {
8
+ organizationId: number;
9
+ userId: number;
10
+ role?: OrganizationMemberRole;
11
+ }): Promise<OrganizationMemberRecord>;
12
+ removeMember(organizationId: number, userId: number): Promise<boolean>;
13
+ }
14
+ export default OrganizationMemberRepository;
@@ -0,0 +1,9 @@
1
+ type OrganizationMemberRole = "owner" | "admin" | "member";
2
+ type OrganizationMemberRecord = {
3
+ id: number;
4
+ organization_id: number;
5
+ user_id: number;
6
+ role: OrganizationMemberRole;
7
+ created_at: Date;
8
+ };
9
+ export type { OrganizationMemberRecord, OrganizationMemberRole };
@@ -0,0 +1,8 @@
1
+ import { BaseRepository } from "../../core/database";
2
+ import type { ApiTokenRecord } from "./types";
3
+ declare class ApiTokenRepository extends BaseRepository<ApiTokenRecord, "id"> {
4
+ constructor();
5
+ findByTokenHash(tokenHash: string): Promise<ApiTokenRecord | null>;
6
+ touchLastUsedAt(id: number): Promise<void>;
7
+ }
8
+ export default ApiTokenRepository;
@@ -0,0 +1,3 @@
1
+ import type { ApiTokenRecord } from "./types";
2
+ declare const apiTokenTable: import("../../core/database").TableDefinition<ApiTokenRecord, "id">;
3
+ export { apiTokenTable };
@@ -0,0 +1,23 @@
1
+ import type { OAuthProvider } from "../../core/auth/oauth/types";
2
+ import type OAuthIdentityRepository from "./oauthIdentityRepository";
3
+ import type UserRepository from "./repository";
4
+ import type TokenService from "./tokenService";
5
+ import type { CreatedApiToken } from "./types";
6
+ interface LoginOptions {
7
+ mfaCode?: string;
8
+ }
9
+ declare class AuthService {
10
+ private readonly users;
11
+ private readonly tokens;
12
+ private readonly oauthIdentities;
13
+ private readonly oauthProviders;
14
+ constructor(users: UserRepository, tokens: TokenService, oauthIdentities: OAuthIdentityRepository);
15
+ registerOAuthProvider(provider: OAuthProvider): void;
16
+ getOAuthProvider(name: string): OAuthProvider | undefined;
17
+ loginWithPassword(email: string, password: string, options?: LoginOptions): Promise<CreatedApiToken>;
18
+ loginWithOAuth(providerName: string, code: string): Promise<CreatedApiToken>;
19
+ buildOAuthAuthorizationUrl(providerName: string, state: string): string;
20
+ private findOrCreateOAuthUser;
21
+ }
22
+ export default AuthService;
23
+ export type { LoginOptions };
@@ -0,0 +1,6 @@
1
+ import { BaseRepository } from "../../core/database";
2
+ import type { NotificationRecord } from "./notificationTypes";
3
+ declare class NotificationRepository extends BaseRepository<NotificationRecord, "id"> {
4
+ constructor();
5
+ }
6
+ export default NotificationRepository;
@@ -0,0 +1,25 @@
1
+ import type { PaginatedResult } from "../../core/pagination";
2
+ import type NotificationRepository from "./notificationRepository";
3
+ import type { NotificationRecord } from "./notificationTypes";
4
+ interface CreateNotificationInput {
5
+ userId: number;
6
+ tenantId: number;
7
+ type: string;
8
+ title: string;
9
+ body: string;
10
+ data?: Record<string, unknown>;
11
+ }
12
+ declare class NotificationService {
13
+ private readonly repository;
14
+ constructor(repository: NotificationRepository);
15
+ listForUser(userId: number, options: {
16
+ page: number;
17
+ perPage: number;
18
+ unreadOnly?: boolean;
19
+ }): Promise<PaginatedResult<NotificationRecord>>;
20
+ markRead(userId: number, notificationId: number): Promise<NotificationRecord>;
21
+ markAllRead(userId: number): Promise<number>;
22
+ create(input: CreateNotificationInput): Promise<NotificationRecord>;
23
+ }
24
+ export default NotificationService;
25
+ export type { CreateNotificationInput };
@@ -0,0 +1,3 @@
1
+ import type { NotificationRecord } from "./notificationTypes";
2
+ declare const notificationTable: import("../../core/database").TableDefinition<NotificationRecord, "id">;
3
+ export { notificationTable };
@@ -0,0 +1,12 @@
1
+ interface NotificationRecord {
2
+ id: number;
3
+ user_id: number;
4
+ tenant_id: number;
5
+ type: string;
6
+ title: string;
7
+ body: string;
8
+ data: Record<string, unknown>;
9
+ read_at: Date | null;
10
+ created_at: Date;
11
+ }
12
+ export type { NotificationRecord };
@@ -0,0 +1,9 @@
1
+ import { BaseRepository } from "../../core/database";
2
+ import type { OAuthIdentityRecord } from "./types";
3
+ declare const oauthIdentityTable: import("../../core/database").TableDefinition<OAuthIdentityRecord, "id">;
4
+ declare class OAuthIdentityRepository extends BaseRepository<OAuthIdentityRecord, "id"> {
5
+ constructor();
6
+ findByProviderUser(provider: string, providerUserId: string): Promise<OAuthIdentityRecord | null>;
7
+ }
8
+ export default OAuthIdentityRepository;
9
+ export { oauthIdentityTable };
@@ -0,0 +1,11 @@
1
+ import type { ServiceProvider } from "../../bootstrap/contracts";
2
+ declare const userRepositoryToken = "user.repository";
3
+ declare const apiTokenRepositoryToken = "user.apiTokenRepository";
4
+ declare const tokenServiceToken = "user.tokenService";
5
+ declare const authServiceToken = "user.authService";
6
+ declare const oauthIdentityRepositoryToken = "user.oauthIdentityRepository";
7
+ declare const notificationRepositoryToken = "user.notificationRepository";
8
+ declare const notificationServiceToken = "user.notificationService";
9
+ declare const userProvider: ServiceProvider;
10
+ export default userProvider;
11
+ export { apiTokenRepositoryToken, authServiceToken, notificationRepositoryToken, notificationServiceToken, oauthIdentityRepositoryToken, tokenServiceToken, userRepositoryToken, };
@@ -0,0 +1,12 @@
1
+ import { BaseRepository } from "../../core/database";
2
+ import type { UserRecord } from "./types";
3
+ declare class UserRepository extends BaseRepository<UserRecord, "id"> {
4
+ constructor();
5
+ private decode;
6
+ findById(id: number): Promise<UserRecord | null>;
7
+ findAll(options?: Parameters<BaseRepository<UserRecord, "id">["findAll"]>[0]): Promise<UserRecord[]>;
8
+ create(values: Partial<UserRecord>): Promise<UserRecord>;
9
+ updateByIdOrThrow(id: number, values: Partial<UserRecord>, errorFactory?: (missingId: number) => Error): Promise<UserRecord>;
10
+ findByEmail(email: string): Promise<UserRecord | null>;
11
+ }
12
+ export default UserRepository;
@@ -0,0 +1,3 @@
1
+ import type { UserRecord } from "./types";
2
+ declare const userTable: import("../../core/database").TableDefinition<UserRecord, "id">;
3
+ export { userTable };
@@ -0,0 +1,29 @@
1
+ import type { AuthUser } from "../../core/auth/authContext";
2
+ import type ApiTokenRepository from "./apiTokenRepository";
3
+ import type UserRepository from "./repository";
4
+ import type { ApiTokenRecord, ApiTokenResource, CreatedApiToken, UserRecord } from "./types";
5
+ interface CreateTokenInput {
6
+ name: string;
7
+ abilities?: string[];
8
+ expiresAt?: Date | null;
9
+ expiresInDays?: number;
10
+ }
11
+ declare function toApiTokenResource(record: ApiTokenRecord): ApiTokenResource;
12
+ declare function generatePlainTextToken(): string;
13
+ declare function resolveExpiresAt(input: CreateTokenInput): Date | null;
14
+ declare function normalizeAbilities(value: unknown): string[];
15
+ declare class TokenService {
16
+ private readonly users;
17
+ private readonly tokens;
18
+ constructor(users: UserRepository, tokens: ApiTokenRepository);
19
+ resolveUserFromToken(token: string): Promise<AuthUser | null>;
20
+ createToken(userId: number, input: CreateTokenInput): Promise<CreatedApiToken>;
21
+ listTokensForUser(userId: number): Promise<ApiTokenResource[]>;
22
+ revokeToken(userId: number, tokenId: number): Promise<void>;
23
+ tokenCan(user: AuthUser | null, ability: string): boolean;
24
+ requireAbility(user: AuthUser | null, ability: string): void;
25
+ findByIdOrThrow(id: number): Promise<UserRecord>;
26
+ deleteUserAccount(userId: number): Promise<void>;
27
+ }
28
+ export default TokenService;
29
+ export { generatePlainTextToken, normalizeAbilities, resolveExpiresAt, toApiTokenResource };
@@ -0,0 +1,46 @@
1
+ import type { UserRole } from "../../domain/auth";
2
+ interface UserRecord {
3
+ id: number;
4
+ name: string;
5
+ email: string;
6
+ email_lookup?: string | null;
7
+ role: UserRole;
8
+ tenant_id: number;
9
+ password_hash?: string | null;
10
+ email_verified_at?: Date | null;
11
+ mfa_secret?: string | null;
12
+ mfa_enabled?: boolean;
13
+ created_at: Date;
14
+ updated_at: Date;
15
+ }
16
+ interface OAuthIdentityRecord {
17
+ id: number;
18
+ user_id: number;
19
+ provider: string;
20
+ provider_user_id: string;
21
+ email: string | null;
22
+ created_at: Date;
23
+ }
24
+ interface ApiTokenRecord {
25
+ id: number;
26
+ user_id: number;
27
+ name: string;
28
+ token_hash: string;
29
+ abilities: string[];
30
+ last_used_at: Date | null;
31
+ expires_at: Date | null;
32
+ created_at: Date;
33
+ }
34
+ interface ApiTokenResource {
35
+ id: number;
36
+ name: string;
37
+ abilities: string[];
38
+ last_used_at: string | null;
39
+ expires_at: string | null;
40
+ created_at: string;
41
+ }
42
+ interface CreatedApiToken {
43
+ token: ApiTokenResource;
44
+ plainTextToken: string;
45
+ }
46
+ export type { ApiTokenRecord, ApiTokenResource, CreatedApiToken, OAuthIdentityRecord, UserRecord };
@@ -0,0 +1,16 @@
1
+ interface CacheLike {
2
+ get<T>(key: string): Promise<T | undefined>;
3
+ remember<T>(key: string, callback: () => Promise<T>, ttlMs?: number): Promise<T>;
4
+ forget(key: string): Promise<boolean>;
5
+ flush(): Promise<void>;
6
+ tags(...names: string[]): {
7
+ remember<T>(key: string, callback: () => Promise<T>, ttlMs?: number): Promise<T>;
8
+ flush(): Promise<number>;
9
+ };
10
+ getOrSet<T>(key: string, loader: () => Promise<T>, ttlMs?: number): Promise<T>;
11
+ invalidate(key: string): Promise<boolean>;
12
+ invalidateByPrefix(prefix: string): Promise<number>;
13
+ clear(): Promise<void>;
14
+ size(): Promise<number>;
15
+ }
16
+ export type { CacheLike };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getstrata/core",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Strata — Laravel-inspired Bun framework public API",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -11,20 +11,21 @@
11
11
  },
12
12
  "exports": {
13
13
  ".": {
14
- "types": "./index.ts",
14
+ "types": "./dist/framework/public-api.d.ts",
15
15
  "import": "./dist/index.js",
16
- "default": "./index.ts"
16
+ "default": "./dist/index.js"
17
17
  }
18
18
  },
19
19
  "main": "./dist/index.js",
20
- "types": "./index.ts",
20
+ "types": "./dist/framework/public-api.d.ts",
21
21
  "files": [
22
22
  "dist",
23
- "index.ts",
24
23
  "README.md"
25
24
  ],
26
25
  "scripts": {
27
- "build": "bun build index.ts --outdir dist --target bun --external bun --external eta",
26
+ "build": "bun run build:bundle && bun run build:types",
27
+ "build:bundle": "bun build index.ts --outdir dist --target bun --external bun --external eta",
28
+ "build:types": "tsc -p tsconfig.types.json",
28
29
  "prepublishOnly": "bun run build"
29
30
  },
30
31
  "publishConfig": {
package/index.ts DELETED
@@ -1 +0,0 @@
1
- export * from "../../src/framework/public-api";