@getstrata/bootstrap 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bootstrap/app.d.ts +7 -0
- package/dist/bootstrap/createRoutes.d.ts +3 -0
- package/dist/bootstrap/createSpaRoutes.d.ts +5 -0
- package/dist/bootstrap/dependencies.d.ts +4 -0
- package/dist/bootstrap/health.d.ts +8 -0
- package/dist/bootstrap/metricsRoutes.d.ts +4 -0
- package/dist/bootstrap/middleware.d.ts +4 -0
- package/dist/bootstrap/public-api.d.ts +1 -1
- package/dist/bootstrap/routes.d.ts +2 -0
- package/dist/bootstrap/scimRoutes.d.ts +24 -0
- package/dist/bootstrap/server.d.ts +1 -0
- package/dist/bootstrap/web/forms.d.ts +1 -5
- package/dist/bootstrap/web/index.d.ts +2 -1
- package/dist/bootstrap/web/routing.d.ts +21 -0
- package/dist/bootstrap/web/server.d.ts +7 -1
- package/dist/bootstrap/web/session.d.ts +0 -1
- package/dist/core/auth/scimAuthMiddleware.d.ts +3 -0
- package/dist/core/crypto/nonCryptographicHash.d.ts +2 -0
- package/dist/core/http/cookies.d.ts +4 -0
- package/dist/core/http/csrfProtection.d.ts +12 -0
- package/dist/core/http/scimThrottleMiddleware.d.ts +9 -0
- package/dist/core/security/scimTenantTokens.d.ts +3 -0
- package/dist/core/security/timingSafeCompare.d.ts +2 -0
- package/dist/framework/public-api.d.ts +4 -0
- package/dist/index.js +159 -103
- package/dist/modules/scim/controller.d.ts +15 -0
- package/dist/modules/scim/scimResponse.d.ts +10 -0
- package/dist/modules/scim/service.d.ts +217 -0
- package/package.json +10 -10
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AppDependencies, AppRouteMap } from "./contracts";
|
|
2
|
+
declare const SPA_DIST_DIRECTORY: string;
|
|
3
|
+
declare function createSpaRoutes(_dependencies: AppDependencies): AppRouteMap;
|
|
4
|
+
declare function mergeSpaRoutes(dependencies: AppDependencies, routes: AppRouteMap): AppRouteMap;
|
|
5
|
+
export { createSpaRoutes, mergeSpaRoutes, SPA_DIST_DIRECTORY };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AppDependencies } from "./contracts";
|
|
2
|
+
declare function checkDatabase(): Promise<boolean>;
|
|
3
|
+
declare function checkRedis(redisUrl: string): Promise<boolean>;
|
|
4
|
+
declare function createHealthRoutes(dependencies: AppDependencies): {
|
|
5
|
+
"/health": () => Promise<Response>;
|
|
6
|
+
"/ready": () => Promise<Response>;
|
|
7
|
+
};
|
|
8
|
+
export { checkDatabase, checkRedis, createHealthRoutes };
|
|
@@ -13,4 +13,4 @@ export { createWebRoutes, mergeWebRoutes } from "./createWebRoutes.ts";
|
|
|
13
13
|
export { createHttpKernel, type HttpKernel, type MiddlewareGroupName } from "./httpKernel.ts";
|
|
14
14
|
export { prefixRouteMap } from "./prefixRouteMap.ts";
|
|
15
15
|
export { coreProviders } from "./providers/index.ts";
|
|
16
|
-
export { CookieSessionStore, createCsrfProtection, createWebServer, type ParsedForm, parseFormBody, type SessionUser, slugify, type WebServerOptions, } from "./web/index.ts";
|
|
16
|
+
export { CookieSessionStore, createCsrfProtection, createRouteKernel, createWebServer, type ParsedForm, parseFormBody, routeParams, type SessionUser, slugify, toRouteRequest, type WebServerOptions, wrapSecuredRouteModelByKey, wrapWebLogin, wrapWebRegister, } from "./web/index.ts";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RouteHandler } from "../core/http/middleware";
|
|
2
|
+
import type { AppDependencies } from "./contracts";
|
|
3
|
+
declare function createScimRoutes(dependencies: AppDependencies): {
|
|
4
|
+
"/scim/v2/ServiceProviderConfig": {
|
|
5
|
+
GET: RouteHandler;
|
|
6
|
+
};
|
|
7
|
+
"/scim/v2/Users": {
|
|
8
|
+
GET: RouteHandler;
|
|
9
|
+
POST: RouteHandler;
|
|
10
|
+
};
|
|
11
|
+
"/scim/v2/Users/:id": {
|
|
12
|
+
GET: RouteHandler;
|
|
13
|
+
PATCH: RouteHandler;
|
|
14
|
+
DELETE: RouteHandler;
|
|
15
|
+
};
|
|
16
|
+
"/scim/v2/Groups": {
|
|
17
|
+
GET: RouteHandler;
|
|
18
|
+
};
|
|
19
|
+
"/scim/v2/Groups/:id": {
|
|
20
|
+
GET: RouteHandler;
|
|
21
|
+
PATCH: RouteHandler;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export { createScimRoutes };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
+
export { type CsrfProtectionOptions, createCsrfProtection, } from "../../core/http/csrfProtection.ts";
|
|
1
2
|
export interface ParsedForm {
|
|
2
3
|
fields: Record<string, string>;
|
|
3
4
|
files: Record<string, File>;
|
|
4
5
|
}
|
|
5
6
|
export declare function parseFormBody(request: Request): Promise<ParsedForm>;
|
|
6
|
-
export declare function createCsrfProtection(secret: string): {
|
|
7
|
-
generate: (sessionKey: string) => string;
|
|
8
|
-
verify: (token: string | undefined, maxAgeMs?: number) => boolean;
|
|
9
|
-
secret: string;
|
|
10
|
-
};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Web-focused bootstrap utilities for sibling apps (getstrata, marketing sites).
|
|
3
3
|
*/
|
|
4
4
|
export { createCsrfProtection, type ParsedForm, parseFormBody } from "./forms.ts";
|
|
5
|
-
export {
|
|
5
|
+
export { createRouteKernel, routeParams, toRouteRequest, wrapSecuredRouteModelByKey, wrapWebLogin, wrapWebRegister, } from "./routing.ts";
|
|
6
|
+
export { convertAppRoutesToBunRoutes, createWebServer, type WebServerOptions } from "./server.ts";
|
|
6
7
|
export { CookieSessionStore, type SessionUser } from "./session.ts";
|
|
7
8
|
export { slugify } from "./slug.ts";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RouteHandler, RouteRequest } from "@getstrata/core";
|
|
2
|
+
import type { AppDependencies } from "../contracts.ts";
|
|
3
|
+
import type { HttpKernel } from "../httpKernel.ts";
|
|
4
|
+
/** Read Bun native `:param` values from a route handler request. */
|
|
5
|
+
export declare function routeParams(request: Request): Record<string, string>;
|
|
6
|
+
/**
|
|
7
|
+
* Attach decoded route params to Bun's native Request for RouteRequest handlers.
|
|
8
|
+
* Mutates the request in place so instanceof Request and Bun internals stay valid.
|
|
9
|
+
*/
|
|
10
|
+
export declare function toRouteRequest<TParams extends Record<string, string>>(request: Request): RouteRequest<TParams>;
|
|
11
|
+
/** Laravel-style secured route-model binding for string keys (slugs, UUIDs). */
|
|
12
|
+
export declare function wrapSecuredRouteModelByKey<TParams extends Record<string, string>, TModel, TParam extends keyof TParams & string>(param: TParam, resolver: (key: string, request: RouteRequest<TParams>) => Promise<TModel>, authorization: {
|
|
13
|
+
resource: string;
|
|
14
|
+
action: "view" | "create" | "update" | "delete";
|
|
15
|
+
}, handler: (request: RouteRequest<TParams>, model: TModel) => Response | Promise<Response>): RouteHandler;
|
|
16
|
+
/** Converts kernel login throttle 429 JSON into an HTML response for web forms. */
|
|
17
|
+
export declare function wrapWebLogin(kernel: HttpKernel, handler: RouteHandler, onThrottled: (request: Request) => Response | Promise<Response>): RouteHandler;
|
|
18
|
+
/** Converts kernel register throttle 429 JSON into an HTML response for web forms. */
|
|
19
|
+
export declare function wrapWebRegister(kernel: HttpKernel, handler: RouteHandler, onThrottled: (request: Request) => Response | Promise<Response>): RouteHandler;
|
|
20
|
+
/** Convenience alias: HttpKernel is the Laravel-style router middleware wrapper. */
|
|
21
|
+
export declare function createRouteKernel(dependencies: AppDependencies): HttpKernel;
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import type { BunRequest } from "bun";
|
|
2
|
+
import type { AppRouteMap } from "../contracts.ts";
|
|
1
3
|
export interface WebServerOptions {
|
|
2
4
|
port: number;
|
|
3
|
-
handle
|
|
5
|
+
handle?: (request: Request) => Promise<Response | null> | Response | null;
|
|
6
|
+
routes?: AppRouteMap;
|
|
4
7
|
publicDir?: string;
|
|
5
8
|
onRequest?: (request: Request) => Promise<void> | void;
|
|
6
9
|
}
|
|
10
|
+
type BunRouteHandler = (request: BunRequest) => Response | Promise<Response>;
|
|
11
|
+
declare function convertAppRoutesToBunRoutes(routes: AppRouteMap): Record<string, Record<string, BunRouteHandler>>;
|
|
7
12
|
export declare function createWebServer(options: WebServerOptions): Bun.Server<undefined>;
|
|
13
|
+
export { convertAppRoutesToBunRoutes };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const DEFAULT_CSRF_TTL_MS: number;
|
|
2
|
+
interface CsrfProtectionOptions {
|
|
3
|
+
expiresIn?: number;
|
|
4
|
+
maxAge?: number;
|
|
5
|
+
}
|
|
6
|
+
declare function createCsrfProtection(secret: string, options?: CsrfProtectionOptions): {
|
|
7
|
+
generate(_sessionKey?: string): string;
|
|
8
|
+
verify(token: string | undefined, _sessionKey?: string): boolean;
|
|
9
|
+
secret: string;
|
|
10
|
+
};
|
|
11
|
+
export type { CsrfProtectionOptions };
|
|
12
|
+
export { createCsrfProtection, DEFAULT_CSRF_TTL_MS };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Middleware } from "./middleware";
|
|
2
|
+
interface ScimThrottleOptions {
|
|
3
|
+
redisUrl?: string;
|
|
4
|
+
maxAttempts: number;
|
|
5
|
+
decaySeconds: number;
|
|
6
|
+
}
|
|
7
|
+
declare function createScimThrottleMiddleware(options: ScimThrottleOptions): Middleware;
|
|
8
|
+
export type { ScimThrottleOptions };
|
|
9
|
+
export { createScimThrottleMiddleware };
|
|
@@ -14,6 +14,7 @@ export { CACHE_TAGS } from "../core/cache/tags.ts";
|
|
|
14
14
|
export type { DatabaseConnection } from "../core/database/baseRepository.ts";
|
|
15
15
|
export { default as BaseRepository } from "../core/database/baseRepository.ts";
|
|
16
16
|
export { bindDatabaseConnection } from "../core/database/bindConnection.ts";
|
|
17
|
+
export { createDatabaseConnection } from "../core/database/connection.ts";
|
|
17
18
|
export { getActiveDatabaseConnection, runWithDatabaseConnection, } from "../core/database/connectionContext.ts";
|
|
18
19
|
export { withMigrationLock } from "../core/database/migrations/advisoryLock.ts";
|
|
19
20
|
export { freshDatabase, getMigrationStatus, loadMigrationsFromDirectory, migrateDatabase, rollbackDatabase, } from "../core/database/migrations/runner.ts";
|
|
@@ -36,7 +37,10 @@ export { BadRequestError, ConflictError, ForbiddenError, NotFoundError, Precondi
|
|
|
36
37
|
export { EventBus } from "../core/events/eventBus.ts";
|
|
37
38
|
export { auth, cache, config, events, log, mail, policyGate, queue, storage, } from "../core/facades/index.ts";
|
|
38
39
|
export { createBodySizeLimitMiddleware } from "../core/http/bodySizeLimitMiddleware.ts";
|
|
40
|
+
export { readBunRequestCookie, readRequestCookie } from "../core/http/cookies.ts";
|
|
39
41
|
export { createCsrfMiddleware } from "../core/http/csrfMiddleware.ts";
|
|
42
|
+
export { createCsrfProtection } from "../core/http/csrfProtection.ts";
|
|
43
|
+
export { createCsrfTokenCookie, readSubmittedCsrfToken, readSubmittedCsrfTokenFromBody, resolveCsrfToken, resolveCsrfTokenForRequest, verifyCsrfToken, } from "../core/http/csrfToken.ts";
|
|
40
44
|
export { assertIfMatch, etagFromResource, isEtagEnabled, } from "../core/http/etag.ts";
|
|
41
45
|
export { FormRequest } from "../core/http/formRequest.ts";
|
|
42
46
|
export { applyMiddlewareToRoutes, composeMiddleware, createAuthMiddleware, createAuthorizeMiddleware, createdResponse, createRequireAuthMiddleware, jsonResponse, noContentResponse, paginatedResponse, parsePaginationQuery, securedBindRouteModel, securedBindRouteModelByKey, withErrorHandling, withMiddleware, } from "../core/http/index.ts";
|
package/dist/index.js
CHANGED
|
@@ -3748,76 +3748,61 @@ function htmlResponse(html, init = {}) {
|
|
|
3748
3748
|
});
|
|
3749
3749
|
}
|
|
3750
3750
|
// ../../src/core/http/csrfToken.ts
|
|
3751
|
-
import {
|
|
3751
|
+
import { timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
3752
|
+
|
|
3753
|
+
// ../../src/core/http/cookies.ts
|
|
3754
|
+
function readRequestCookie(request, name) {
|
|
3755
|
+
const cookies = request.cookies;
|
|
3756
|
+
if (cookies && typeof cookies.get === "function") {
|
|
3757
|
+
const value = cookies.get(name);
|
|
3758
|
+
if (value) {
|
|
3759
|
+
return value;
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
const header = request.headers.get("cookie");
|
|
3763
|
+
if (!header) {
|
|
3764
|
+
return null;
|
|
3765
|
+
}
|
|
3766
|
+
for (const part of header.split(";")) {
|
|
3767
|
+
const idx = part.indexOf("=");
|
|
3768
|
+
if (idx === -1)
|
|
3769
|
+
continue;
|
|
3770
|
+
const cookieName = part.slice(0, idx).trim();
|
|
3771
|
+
if (cookieName !== name)
|
|
3772
|
+
continue;
|
|
3773
|
+
return decodeURIComponent(part.slice(idx + 1).trim());
|
|
3774
|
+
}
|
|
3775
|
+
return null;
|
|
3776
|
+
}
|
|
3777
|
+
|
|
3778
|
+
// ../../src/core/http/csrfToken.ts
|
|
3752
3779
|
var CSRF_COOKIE = "workhub_csrf";
|
|
3753
3780
|
var CSRF_TTL_MS = 60 * 60 * 1000;
|
|
3754
3781
|
function resolveCsrfSecret() {
|
|
3755
3782
|
return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-csrf-secret";
|
|
3756
3783
|
}
|
|
3757
|
-
function
|
|
3758
|
-
|
|
3759
|
-
const signature = createHmac3("sha256", resolveCsrfSecret()).update(payload).digest("hex");
|
|
3760
|
-
return `${payload}.${signature}`;
|
|
3784
|
+
function csrfVerifyOptions() {
|
|
3785
|
+
return { secret: resolveCsrfSecret(), maxAge: CSRF_TTL_MS };
|
|
3761
3786
|
}
|
|
3762
|
-
function
|
|
3763
|
-
const
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
for (const part of cookieHeader.split(";")) {
|
|
3768
|
-
const [name, ...rest] = part.trim().split("=");
|
|
3769
|
-
if (name === CSRF_COOKIE) {
|
|
3770
|
-
return decodeURIComponent(rest.join("="));
|
|
3771
|
-
}
|
|
3772
|
-
}
|
|
3773
|
-
return null;
|
|
3774
|
-
}
|
|
3775
|
-
function parseSignedCsrfValue(cookieValue) {
|
|
3776
|
-
const parts = cookieValue.split(".");
|
|
3777
|
-
if (parts.length !== 3) {
|
|
3778
|
-
return null;
|
|
3779
|
-
}
|
|
3780
|
-
const [token, issuedAtRaw, cookieSignature] = parts;
|
|
3781
|
-
if (!token || !issuedAtRaw || !cookieSignature) {
|
|
3782
|
-
return null;
|
|
3783
|
-
}
|
|
3784
|
-
const issuedAt = Number.parseInt(issuedAtRaw, 10);
|
|
3785
|
-
if (!Number.isFinite(issuedAt)) {
|
|
3786
|
-
return null;
|
|
3787
|
-
}
|
|
3788
|
-
if (Date.now() - issuedAt > CSRF_TTL_MS) {
|
|
3789
|
-
return null;
|
|
3790
|
-
}
|
|
3791
|
-
const expectedSignature = signCsrfToken(token, issuedAt).split(".").pop();
|
|
3792
|
-
if (!expectedSignature) {
|
|
3793
|
-
return null;
|
|
3794
|
-
}
|
|
3795
|
-
const expectedBuffer = Buffer.from(expectedSignature);
|
|
3796
|
-
const actualBuffer = Buffer.from(cookieSignature);
|
|
3797
|
-
if (expectedBuffer.length !== actualBuffer.length) {
|
|
3798
|
-
return null;
|
|
3799
|
-
}
|
|
3800
|
-
if (!timingSafeEqual2(expectedBuffer, actualBuffer)) {
|
|
3801
|
-
return null;
|
|
3787
|
+
function tokensMatch(left, right) {
|
|
3788
|
+
const leftBuffer = Buffer.from(left);
|
|
3789
|
+
const rightBuffer = Buffer.from(right);
|
|
3790
|
+
if (leftBuffer.length !== rightBuffer.length) {
|
|
3791
|
+
return false;
|
|
3802
3792
|
}
|
|
3803
|
-
return
|
|
3793
|
+
return timingSafeEqual2(leftBuffer, rightBuffer);
|
|
3804
3794
|
}
|
|
3805
3795
|
function createCsrfTokenCookie() {
|
|
3806
|
-
const token =
|
|
3807
|
-
const issuedAt = Date.now();
|
|
3808
|
-
const value = signCsrfToken(token, issuedAt);
|
|
3796
|
+
const token = Bun.CSRF.generate(resolveCsrfSecret(), { expiresIn: CSRF_TTL_MS });
|
|
3809
3797
|
return {
|
|
3810
3798
|
token,
|
|
3811
|
-
cookie: `${CSRF_COOKIE}=${encodeURIComponent(
|
|
3799
|
+
cookie: `${CSRF_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Lax; Max-Age=${Math.floor(CSRF_TTL_MS / 1000)}`
|
|
3812
3800
|
};
|
|
3813
3801
|
}
|
|
3814
3802
|
function resolveCsrfToken(request) {
|
|
3815
|
-
const cookieValue =
|
|
3816
|
-
if (cookieValue) {
|
|
3817
|
-
|
|
3818
|
-
if (parsed) {
|
|
3819
|
-
return { token: parsed.token };
|
|
3820
|
-
}
|
|
3803
|
+
const cookieValue = readRequestCookie(request, CSRF_COOKIE);
|
|
3804
|
+
if (cookieValue && Bun.CSRF.verify(cookieValue, csrfVerifyOptions())) {
|
|
3805
|
+
return { token: cookieValue };
|
|
3821
3806
|
}
|
|
3822
3807
|
return createCsrfTokenCookie();
|
|
3823
3808
|
}
|
|
@@ -3840,6 +3825,10 @@ async function readSubmittedCsrfTokenFromBody(request) {
|
|
|
3840
3825
|
if (typeof field === "string" && field.trim().length > 0) {
|
|
3841
3826
|
return field.trim();
|
|
3842
3827
|
}
|
|
3828
|
+
const legacyField = formData.get("_csrf");
|
|
3829
|
+
if (typeof legacyField === "string" && legacyField.trim().length > 0) {
|
|
3830
|
+
return legacyField.trim();
|
|
3831
|
+
}
|
|
3843
3832
|
}
|
|
3844
3833
|
return null;
|
|
3845
3834
|
}
|
|
@@ -3847,20 +3836,14 @@ function verifyCsrfToken(request, submittedToken) {
|
|
|
3847
3836
|
if (!submittedToken) {
|
|
3848
3837
|
return false;
|
|
3849
3838
|
}
|
|
3850
|
-
const cookieValue =
|
|
3839
|
+
const cookieValue = readRequestCookie(request, CSRF_COOKIE);
|
|
3851
3840
|
if (!cookieValue) {
|
|
3852
3841
|
return false;
|
|
3853
3842
|
}
|
|
3854
|
-
|
|
3855
|
-
if (!parsed) {
|
|
3856
|
-
return false;
|
|
3857
|
-
}
|
|
3858
|
-
const submittedBuffer = Buffer.from(submittedToken);
|
|
3859
|
-
const expectedBuffer = Buffer.from(parsed.token);
|
|
3860
|
-
if (submittedBuffer.length !== expectedBuffer.length) {
|
|
3843
|
+
if (!tokensMatch(submittedToken, cookieValue)) {
|
|
3861
3844
|
return false;
|
|
3862
3845
|
}
|
|
3863
|
-
return
|
|
3846
|
+
return Bun.CSRF.verify(submittedToken, csrfVerifyOptions());
|
|
3864
3847
|
}
|
|
3865
3848
|
function resolveCsrfTokenForRequest(request) {
|
|
3866
3849
|
const metaToken = currentRequestMeta().csrfToken;
|
|
@@ -3871,14 +3854,14 @@ function resolveCsrfTokenForRequest(request) {
|
|
|
3871
3854
|
}
|
|
3872
3855
|
|
|
3873
3856
|
// ../../src/core/http/flashSession.ts
|
|
3874
|
-
import { createHmac as
|
|
3857
|
+
import { createHmac as createHmac3, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
3875
3858
|
var FLASH_COOKIE = "workhub_flash";
|
|
3876
3859
|
var FLASH_TTL_MS = 60 * 1000;
|
|
3877
3860
|
function resolveFlashSecret() {
|
|
3878
3861
|
return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || "workhub-dev-flash-secret";
|
|
3879
3862
|
}
|
|
3880
3863
|
function signFlashPayload(payload, issuedAt) {
|
|
3881
|
-
const signature =
|
|
3864
|
+
const signature = createHmac3("sha256", resolveFlashSecret()).update(`${payload}.${issuedAt}`).digest("hex");
|
|
3882
3865
|
return `${payload}.${issuedAt}.${signature}`;
|
|
3883
3866
|
}
|
|
3884
3867
|
function readFlashCookie(request) {
|
|
@@ -4967,9 +4950,9 @@ function createTenantMiddleware() {
|
|
|
4967
4950
|
}
|
|
4968
4951
|
|
|
4969
4952
|
// ../../src/core/tracing/otel.ts
|
|
4970
|
-
import { randomBytes
|
|
4953
|
+
import { randomBytes } from "crypto";
|
|
4971
4954
|
function randomHex(bytes) {
|
|
4972
|
-
return
|
|
4955
|
+
return randomBytes(bytes).toString("hex");
|
|
4973
4956
|
}
|
|
4974
4957
|
function createSpan(input) {
|
|
4975
4958
|
const spanId = randomHex(8);
|
|
@@ -5302,6 +5285,25 @@ function prefixRouteMap(prefix, routes) {
|
|
|
5302
5285
|
}
|
|
5303
5286
|
return prefixed;
|
|
5304
5287
|
}
|
|
5288
|
+
// ../../src/core/http/csrfProtection.ts
|
|
5289
|
+
var DEFAULT_CSRF_TTL_MS = 60 * 60 * 1000;
|
|
5290
|
+
function createCsrfProtection(secret, options = {}) {
|
|
5291
|
+
const expiresIn = options.expiresIn ?? DEFAULT_CSRF_TTL_MS;
|
|
5292
|
+
const maxAge = options.maxAge ?? expiresIn;
|
|
5293
|
+
return {
|
|
5294
|
+
generate(_sessionKey) {
|
|
5295
|
+
return Bun.CSRF.generate(secret, { expiresIn });
|
|
5296
|
+
},
|
|
5297
|
+
verify(token, _sessionKey) {
|
|
5298
|
+
if (!token) {
|
|
5299
|
+
return false;
|
|
5300
|
+
}
|
|
5301
|
+
return Bun.CSRF.verify(token, { secret, maxAge });
|
|
5302
|
+
},
|
|
5303
|
+
secret
|
|
5304
|
+
};
|
|
5305
|
+
}
|
|
5306
|
+
|
|
5305
5307
|
// ../../src/bootstrap/web/forms.ts
|
|
5306
5308
|
async function parseFormBody(request) {
|
|
5307
5309
|
const contentType = request.headers.get("content-type") ?? "";
|
|
@@ -5331,30 +5333,86 @@ async function parseFormBody(request) {
|
|
|
5331
5333
|
}
|
|
5332
5334
|
return { fields, files };
|
|
5333
5335
|
}
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5336
|
+
// ../../src/bootstrap/web/routing.ts
|
|
5337
|
+
import { securedBindRouteModelByKey, withErrorHandling } from "@getstrata/core";
|
|
5338
|
+
function routeParams(request) {
|
|
5339
|
+
const normalized = {};
|
|
5340
|
+
const raw = request.params;
|
|
5341
|
+
if (raw && typeof raw === "object") {
|
|
5342
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
5343
|
+
normalized[key] = decodeURIComponent(String(value));
|
|
5344
|
+
}
|
|
5345
|
+
}
|
|
5346
|
+
return normalized;
|
|
5347
|
+
}
|
|
5348
|
+
function toRouteRequest(request) {
|
|
5349
|
+
const params = routeParams(request);
|
|
5350
|
+
Object.defineProperty(request, "params", {
|
|
5351
|
+
value: params,
|
|
5352
|
+
enumerable: true,
|
|
5353
|
+
configurable: true,
|
|
5354
|
+
writable: true
|
|
5355
|
+
});
|
|
5356
|
+
return request;
|
|
5357
|
+
}
|
|
5358
|
+
function wrapSecuredRouteModelByKey(param, resolver, authorization, handler) {
|
|
5359
|
+
const bound = withErrorHandling(securedBindRouteModelByKey(param, resolver, authorization, handler));
|
|
5360
|
+
return async (request) => bound(toRouteRequest(request));
|
|
5361
|
+
}
|
|
5362
|
+
function wrapWebLogin(kernel, handler, onThrottled) {
|
|
5363
|
+
return wrapWebThrottle(kernel, "login", handler, onThrottled);
|
|
5364
|
+
}
|
|
5365
|
+
function wrapWebRegister(kernel, handler, onThrottled) {
|
|
5366
|
+
return wrapWebThrottle(kernel, "register", handler, onThrottled);
|
|
5367
|
+
}
|
|
5368
|
+
function wrapWebThrottle(kernel, scope, handler, onThrottled) {
|
|
5369
|
+
const throttled = scope === "login" ? kernel.wrapLogin(handler) : kernel.wrapRegister(handler);
|
|
5370
|
+
return async (request) => {
|
|
5371
|
+
const response = await throttled(request);
|
|
5372
|
+
if (response.status === 429) {
|
|
5373
|
+
return onThrottled(request);
|
|
5348
5374
|
}
|
|
5349
|
-
return
|
|
5350
|
-
}
|
|
5351
|
-
|
|
5375
|
+
return response;
|
|
5376
|
+
};
|
|
5377
|
+
}
|
|
5378
|
+
function createRouteKernel(dependencies) {
|
|
5379
|
+
return createHttpKernel(dependencies);
|
|
5352
5380
|
}
|
|
5353
5381
|
// ../../src/bootstrap/web/server.ts
|
|
5382
|
+
function wrapRouteHandler2(handler) {
|
|
5383
|
+
return async (request) => {
|
|
5384
|
+
const response = await handler(request);
|
|
5385
|
+
return response ?? new Response("Not Found", { status: 404 });
|
|
5386
|
+
};
|
|
5387
|
+
}
|
|
5388
|
+
function convertAppRoutesToBunRoutes(routes) {
|
|
5389
|
+
const bunRoutes = {};
|
|
5390
|
+
for (const [path, handler] of Object.entries(routes)) {
|
|
5391
|
+
if (typeof handler === "function") {
|
|
5392
|
+
bunRoutes[path] = { GET: wrapRouteHandler2(handler) };
|
|
5393
|
+
continue;
|
|
5394
|
+
}
|
|
5395
|
+
if (handler && typeof handler === "object" && !Array.isArray(handler)) {
|
|
5396
|
+
const methods = {};
|
|
5397
|
+
for (const [method, methodHandler] of Object.entries(handler)) {
|
|
5398
|
+
if (typeof methodHandler !== "function") {
|
|
5399
|
+
continue;
|
|
5400
|
+
}
|
|
5401
|
+
methods[method.toUpperCase()] = wrapRouteHandler2(methodHandler);
|
|
5402
|
+
}
|
|
5403
|
+
if (Object.keys(methods).length > 0) {
|
|
5404
|
+
bunRoutes[path] = methods;
|
|
5405
|
+
}
|
|
5406
|
+
}
|
|
5407
|
+
}
|
|
5408
|
+
return bunRoutes;
|
|
5409
|
+
}
|
|
5354
5410
|
function createWebServer(options) {
|
|
5355
5411
|
const publicDir = options.publicDir ?? "./public";
|
|
5412
|
+
const bunRoutes = options.routes ? convertAppRoutesToBunRoutes(options.routes) : undefined;
|
|
5356
5413
|
return Bun.serve({
|
|
5357
5414
|
port: options.port,
|
|
5415
|
+
...bunRoutes ? { routes: bunRoutes } : {},
|
|
5358
5416
|
async fetch(request) {
|
|
5359
5417
|
await options.onRequest?.(request);
|
|
5360
5418
|
const url = new URL(request.url);
|
|
@@ -5364,14 +5422,16 @@ function createWebServer(options) {
|
|
|
5364
5422
|
return new Response(file);
|
|
5365
5423
|
}
|
|
5366
5424
|
}
|
|
5367
|
-
|
|
5368
|
-
|
|
5425
|
+
if (options.handle) {
|
|
5426
|
+
const response = await options.handle(request);
|
|
5427
|
+
return response ?? new Response("Not Found", { status: 404 });
|
|
5428
|
+
}
|
|
5429
|
+
return new Response("Not Found", { status: 404 });
|
|
5369
5430
|
}
|
|
5370
5431
|
});
|
|
5371
5432
|
}
|
|
5372
5433
|
// ../../src/bootstrap/web/session.ts
|
|
5373
|
-
import { createHash, randomBytes as
|
|
5374
|
-
|
|
5434
|
+
import { createHash, randomBytes as randomBytes2 } from "crypto";
|
|
5375
5435
|
class CookieSessionStore {
|
|
5376
5436
|
sql;
|
|
5377
5437
|
secret;
|
|
@@ -5397,7 +5457,7 @@ class CookieSessionStore {
|
|
|
5397
5457
|
return header.includes("Secure") ? header : `${header}; Secure`;
|
|
5398
5458
|
}
|
|
5399
5459
|
async create(user) {
|
|
5400
|
-
const id =
|
|
5460
|
+
const id = randomBytes2(32).toString("hex");
|
|
5401
5461
|
const expires = new Date(Date.now() + this.maxAgeSeconds * 1000);
|
|
5402
5462
|
await this.sql.unsafe(`INSERT INTO sessions (id, user_id, expires_at) VALUES ($1, $2, $3)`, [
|
|
5403
5463
|
id,
|
|
@@ -5410,8 +5470,8 @@ class CookieSessionStore {
|
|
|
5410
5470
|
await this.sql.unsafe(`DELETE FROM sessions WHERE id = $1`, [sessionId]);
|
|
5411
5471
|
}
|
|
5412
5472
|
async read(request) {
|
|
5413
|
-
const cookie =
|
|
5414
|
-
const raw = cookie
|
|
5473
|
+
const cookie = readRequestCookie(request, this.cookieName);
|
|
5474
|
+
const raw = cookie ?? null;
|
|
5415
5475
|
if (!raw)
|
|
5416
5476
|
return null;
|
|
5417
5477
|
const [sessionId, signature] = raw.split(".");
|
|
@@ -5435,27 +5495,22 @@ class CookieSessionStore {
|
|
|
5435
5495
|
sign(value) {
|
|
5436
5496
|
return createHash("sha256").update(`${value}.${this.secret}`).digest("hex").slice(0, 32);
|
|
5437
5497
|
}
|
|
5438
|
-
parseCookie(header) {
|
|
5439
|
-
const out = {};
|
|
5440
|
-
for (const part of header.split(";")) {
|
|
5441
|
-
const idx = part.indexOf("=");
|
|
5442
|
-
if (idx === -1)
|
|
5443
|
-
continue;
|
|
5444
|
-
out[part.slice(0, idx).trim()] = decodeURIComponent(part.slice(idx + 1).trim());
|
|
5445
|
-
}
|
|
5446
|
-
return out;
|
|
5447
|
-
}
|
|
5448
5498
|
}
|
|
5449
5499
|
// ../../src/bootstrap/web/slug.ts
|
|
5450
5500
|
function slugify(value) {
|
|
5451
5501
|
return value.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
5452
5502
|
}
|
|
5453
5503
|
export {
|
|
5504
|
+
wrapWebRegister,
|
|
5505
|
+
wrapWebLogin,
|
|
5506
|
+
wrapSecuredRouteModelByKey,
|
|
5507
|
+
toRouteRequest,
|
|
5454
5508
|
slugify,
|
|
5455
5509
|
setActiveApplicationContext2 as setActiveApplicationContext,
|
|
5456
5510
|
scheduleRunCommand,
|
|
5457
5511
|
runProviderPhase,
|
|
5458
5512
|
runDueScheduledTasks,
|
|
5513
|
+
routeParams,
|
|
5459
5514
|
resolveService,
|
|
5460
5515
|
resolveApplicationQueue2 as resolveApplicationQueue,
|
|
5461
5516
|
prefixRouteMap,
|
|
@@ -5464,6 +5519,7 @@ export {
|
|
|
5464
5519
|
getRequiredDependency,
|
|
5465
5520
|
createWebServer,
|
|
5466
5521
|
createWebRoutes,
|
|
5522
|
+
createRouteKernel,
|
|
5467
5523
|
createHttpKernel,
|
|
5468
5524
|
createCsrfProtection,
|
|
5469
5525
|
createAppContext,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AppDependencies } from "@getstrata/bootstrap/contracts";
|
|
2
|
+
declare class ScimController {
|
|
3
|
+
private readonly service;
|
|
4
|
+
constructor(dependencies: AppDependencies);
|
|
5
|
+
readonly serviceProviderConfig: () => Promise<Response>;
|
|
6
|
+
readonly listUsers: (request: Request) => Promise<Response>;
|
|
7
|
+
readonly createUser: (request: Request) => Promise<Response>;
|
|
8
|
+
readonly showUser: (request: Request) => Promise<Response>;
|
|
9
|
+
readonly patchUser: (request: Request) => Promise<Response>;
|
|
10
|
+
readonly deleteUser: (request: Request) => Promise<Response>;
|
|
11
|
+
readonly listGroups: (request: Request) => Promise<Response>;
|
|
12
|
+
readonly showGroup: (request: Request) => Promise<Response>;
|
|
13
|
+
readonly patchGroup: (request: Request) => Promise<Response>;
|
|
14
|
+
}
|
|
15
|
+
export default ScimController;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type EtagVersioned } from "@getstrata/core/http/etag";
|
|
2
|
+
interface ScimResponseOptions {
|
|
3
|
+
status?: number;
|
|
4
|
+
request?: Request;
|
|
5
|
+
etagSource?: EtagVersioned;
|
|
6
|
+
}
|
|
7
|
+
declare function scimResponse(data: unknown, options?: ScimResponseOptions): Response;
|
|
8
|
+
declare function assertScimIfMatch(request: Request, etagSource: EtagVersioned): void;
|
|
9
|
+
export type { ScimResponseOptions };
|
|
10
|
+
export { assertScimIfMatch, scimResponse };
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import type { AppDependencies } from "@getstrata/bootstrap/contracts";
|
|
2
|
+
import OrganizationMemberRepository from "../organization/memberRepository";
|
|
3
|
+
import type UserRepository from "../user/repository";
|
|
4
|
+
interface ScimUserPayload {
|
|
5
|
+
userName?: string;
|
|
6
|
+
name?: {
|
|
7
|
+
formatted?: string;
|
|
8
|
+
};
|
|
9
|
+
active?: boolean;
|
|
10
|
+
emails?: Array<{
|
|
11
|
+
value: string;
|
|
12
|
+
primary?: boolean;
|
|
13
|
+
}>;
|
|
14
|
+
}
|
|
15
|
+
interface ScimPatchOperation {
|
|
16
|
+
op: string;
|
|
17
|
+
path?: string;
|
|
18
|
+
value?: unknown;
|
|
19
|
+
}
|
|
20
|
+
declare class ScimService {
|
|
21
|
+
private readonly users;
|
|
22
|
+
private readonly members;
|
|
23
|
+
constructor(users: UserRepository, members: OrganizationMemberRepository);
|
|
24
|
+
serviceProviderConfig(): {
|
|
25
|
+
schemas: "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"[];
|
|
26
|
+
patch: {
|
|
27
|
+
supported: boolean;
|
|
28
|
+
};
|
|
29
|
+
bulk: {
|
|
30
|
+
supported: boolean;
|
|
31
|
+
};
|
|
32
|
+
filter: {
|
|
33
|
+
supported: boolean;
|
|
34
|
+
};
|
|
35
|
+
changePassword: {
|
|
36
|
+
supported: boolean;
|
|
37
|
+
};
|
|
38
|
+
sort: {
|
|
39
|
+
supported: boolean;
|
|
40
|
+
};
|
|
41
|
+
etag: {
|
|
42
|
+
supported: boolean;
|
|
43
|
+
};
|
|
44
|
+
authenticationSchemes: {
|
|
45
|
+
type: string;
|
|
46
|
+
name: string;
|
|
47
|
+
description: string;
|
|
48
|
+
}[];
|
|
49
|
+
};
|
|
50
|
+
listUsers(startIndex?: number, count?: number): Promise<{
|
|
51
|
+
schemas: "urn:ietf:params:scim:api:messages:2.0:ListResponse"[];
|
|
52
|
+
totalResults: number;
|
|
53
|
+
startIndex: number;
|
|
54
|
+
itemsPerPage: number;
|
|
55
|
+
Resources: {
|
|
56
|
+
schemas: "urn:ietf:params:scim:schemas:core:2.0:User"[];
|
|
57
|
+
id: string;
|
|
58
|
+
userName: string;
|
|
59
|
+
name: {
|
|
60
|
+
formatted: string;
|
|
61
|
+
};
|
|
62
|
+
displayName: string;
|
|
63
|
+
active: boolean;
|
|
64
|
+
emails: {
|
|
65
|
+
value: string;
|
|
66
|
+
primary: boolean;
|
|
67
|
+
type: string;
|
|
68
|
+
}[];
|
|
69
|
+
roles: {
|
|
70
|
+
value: string;
|
|
71
|
+
primary: boolean;
|
|
72
|
+
}[];
|
|
73
|
+
meta: {
|
|
74
|
+
resourceType: string;
|
|
75
|
+
created: string | undefined;
|
|
76
|
+
lastModified: string | undefined;
|
|
77
|
+
};
|
|
78
|
+
}[];
|
|
79
|
+
}>;
|
|
80
|
+
getUser(id: number): Promise<{
|
|
81
|
+
schemas: "urn:ietf:params:scim:schemas:core:2.0:User"[];
|
|
82
|
+
id: string;
|
|
83
|
+
userName: string;
|
|
84
|
+
name: {
|
|
85
|
+
formatted: string;
|
|
86
|
+
};
|
|
87
|
+
displayName: string;
|
|
88
|
+
active: boolean;
|
|
89
|
+
emails: {
|
|
90
|
+
value: string;
|
|
91
|
+
primary: boolean;
|
|
92
|
+
type: string;
|
|
93
|
+
}[];
|
|
94
|
+
roles: {
|
|
95
|
+
value: string;
|
|
96
|
+
primary: boolean;
|
|
97
|
+
}[];
|
|
98
|
+
meta: {
|
|
99
|
+
resourceType: string;
|
|
100
|
+
created: string | undefined;
|
|
101
|
+
lastModified: string | undefined;
|
|
102
|
+
};
|
|
103
|
+
}>;
|
|
104
|
+
findUserRecord(id: number): Promise<import("../user/types").UserRecord>;
|
|
105
|
+
createUser(payload: ScimUserPayload): Promise<{
|
|
106
|
+
schemas: "urn:ietf:params:scim:schemas:core:2.0:User"[];
|
|
107
|
+
id: string;
|
|
108
|
+
userName: string;
|
|
109
|
+
name: {
|
|
110
|
+
formatted: string;
|
|
111
|
+
};
|
|
112
|
+
displayName: string;
|
|
113
|
+
active: boolean;
|
|
114
|
+
emails: {
|
|
115
|
+
value: string;
|
|
116
|
+
primary: boolean;
|
|
117
|
+
type: string;
|
|
118
|
+
}[];
|
|
119
|
+
roles: {
|
|
120
|
+
value: string;
|
|
121
|
+
primary: boolean;
|
|
122
|
+
}[];
|
|
123
|
+
meta: {
|
|
124
|
+
resourceType: string;
|
|
125
|
+
created: string | undefined;
|
|
126
|
+
lastModified: string | undefined;
|
|
127
|
+
};
|
|
128
|
+
}>;
|
|
129
|
+
patchUser(id: number, operations: ScimPatchOperation[]): Promise<{
|
|
130
|
+
schemas: "urn:ietf:params:scim:schemas:core:2.0:User"[];
|
|
131
|
+
id: string;
|
|
132
|
+
userName: string;
|
|
133
|
+
name: {
|
|
134
|
+
formatted: string;
|
|
135
|
+
};
|
|
136
|
+
displayName: string;
|
|
137
|
+
active: boolean;
|
|
138
|
+
emails: {
|
|
139
|
+
value: string;
|
|
140
|
+
primary: boolean;
|
|
141
|
+
type: string;
|
|
142
|
+
}[];
|
|
143
|
+
roles: {
|
|
144
|
+
value: string;
|
|
145
|
+
primary: boolean;
|
|
146
|
+
}[];
|
|
147
|
+
meta: {
|
|
148
|
+
resourceType: string;
|
|
149
|
+
created: string | undefined;
|
|
150
|
+
lastModified: string | undefined;
|
|
151
|
+
};
|
|
152
|
+
}>;
|
|
153
|
+
deleteUser(id: number): Promise<{
|
|
154
|
+
id: number;
|
|
155
|
+
updated_at: Date;
|
|
156
|
+
}>;
|
|
157
|
+
listGroups(startIndex?: number, count?: number): Promise<{
|
|
158
|
+
schemas: "urn:ietf:params:scim:api:messages:2.0:ListResponse"[];
|
|
159
|
+
totalResults: number;
|
|
160
|
+
startIndex: number;
|
|
161
|
+
itemsPerPage: number;
|
|
162
|
+
Resources: {
|
|
163
|
+
schemas: "urn:ietf:params:scim:schemas:core:2.0:Group"[];
|
|
164
|
+
id: string;
|
|
165
|
+
displayName: string;
|
|
166
|
+
externalId: string;
|
|
167
|
+
members: {
|
|
168
|
+
value: string;
|
|
169
|
+
display: string;
|
|
170
|
+
}[];
|
|
171
|
+
meta: {
|
|
172
|
+
resourceType: string;
|
|
173
|
+
lastModified: string;
|
|
174
|
+
};
|
|
175
|
+
}[];
|
|
176
|
+
}>;
|
|
177
|
+
getGroup(id: number): Promise<{
|
|
178
|
+
schemas: "urn:ietf:params:scim:schemas:core:2.0:Group"[];
|
|
179
|
+
id: string;
|
|
180
|
+
displayName: string;
|
|
181
|
+
externalId: string;
|
|
182
|
+
members: {
|
|
183
|
+
value: string;
|
|
184
|
+
display: string;
|
|
185
|
+
}[];
|
|
186
|
+
meta: {
|
|
187
|
+
resourceType: string;
|
|
188
|
+
lastModified: string;
|
|
189
|
+
};
|
|
190
|
+
}>;
|
|
191
|
+
findOrganizationRecord(id: number): Promise<{
|
|
192
|
+
id: number;
|
|
193
|
+
name: string;
|
|
194
|
+
slug: string;
|
|
195
|
+
updated_at: Date;
|
|
196
|
+
}>;
|
|
197
|
+
patchGroup(id: number, operations: ScimPatchOperation[]): Promise<{
|
|
198
|
+
schemas: "urn:ietf:params:scim:schemas:core:2.0:Group"[];
|
|
199
|
+
id: string;
|
|
200
|
+
displayName: string;
|
|
201
|
+
externalId: string;
|
|
202
|
+
members: {
|
|
203
|
+
value: string;
|
|
204
|
+
display: string;
|
|
205
|
+
}[];
|
|
206
|
+
meta: {
|
|
207
|
+
resourceType: string;
|
|
208
|
+
lastModified: string;
|
|
209
|
+
};
|
|
210
|
+
}>;
|
|
211
|
+
private toScimGroup;
|
|
212
|
+
private toScimUser;
|
|
213
|
+
}
|
|
214
|
+
declare function createScimService(dependencies: AppDependencies): ScimService;
|
|
215
|
+
export default ScimService;
|
|
216
|
+
export type { ScimPatchOperation, ScimUserPayload };
|
|
217
|
+
export { createScimService };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getstrata/bootstrap",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Strata application bootstrap — HttpKernel, DI, web session helpers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,42 +16,42 @@
|
|
|
16
16
|
"default": "./dist/index.js"
|
|
17
17
|
},
|
|
18
18
|
"./applicationRegistry": {
|
|
19
|
-
"types": "./dist/
|
|
19
|
+
"types": "./dist/bootstrap/applicationRegistry.d.ts",
|
|
20
20
|
"import": "./dist/entries/applicationRegistry.js",
|
|
21
21
|
"default": "./dist/entries/applicationRegistry.js"
|
|
22
22
|
},
|
|
23
23
|
"./config": {
|
|
24
|
-
"types": "./dist/
|
|
24
|
+
"types": "./dist/bootstrap/config.d.ts",
|
|
25
25
|
"import": "./dist/entries/config.js",
|
|
26
26
|
"default": "./dist/entries/config.js"
|
|
27
27
|
},
|
|
28
28
|
"./context": {
|
|
29
|
-
"types": "./dist/
|
|
29
|
+
"types": "./dist/bootstrap/context.d.ts",
|
|
30
30
|
"import": "./dist/entries/context.js",
|
|
31
31
|
"default": "./dist/entries/context.js"
|
|
32
32
|
},
|
|
33
33
|
"./contracts": {
|
|
34
|
-
"types": "./dist/
|
|
34
|
+
"types": "./dist/bootstrap/contracts.d.ts",
|
|
35
35
|
"import": "./dist/entries/contracts.js",
|
|
36
36
|
"default": "./dist/entries/contracts.js"
|
|
37
37
|
},
|
|
38
38
|
"./createWebRoutes": {
|
|
39
|
-
"types": "./dist/
|
|
39
|
+
"types": "./dist/bootstrap/createWebRoutes.d.ts",
|
|
40
40
|
"import": "./dist/entries/createWebRoutes.js",
|
|
41
41
|
"default": "./dist/entries/createWebRoutes.js"
|
|
42
42
|
},
|
|
43
43
|
"./httpKernel": {
|
|
44
|
-
"types": "./dist/
|
|
44
|
+
"types": "./dist/bootstrap/httpKernel.d.ts",
|
|
45
45
|
"import": "./dist/entries/httpKernel.js",
|
|
46
46
|
"default": "./dist/entries/httpKernel.js"
|
|
47
47
|
},
|
|
48
48
|
"./providers": {
|
|
49
|
-
"types": "./dist/
|
|
49
|
+
"types": "./dist/bootstrap/providers/index.d.ts",
|
|
50
50
|
"import": "./dist/entries/providers.js",
|
|
51
51
|
"default": "./dist/entries/providers.js"
|
|
52
52
|
},
|
|
53
53
|
"./providers/view": {
|
|
54
|
-
"types": "./dist/
|
|
54
|
+
"types": "./dist/bootstrap/providers/view/index.d.ts",
|
|
55
55
|
"import": "./dist/entries/providers/view.js",
|
|
56
56
|
"default": "./dist/entries/providers/view.js"
|
|
57
57
|
}
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"access": "public"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"@getstrata/core": "^0.5.
|
|
76
|
+
"@getstrata/core": "^0.5.9",
|
|
77
77
|
"typescript": "^5.9.0"
|
|
78
78
|
}
|
|
79
79
|
}
|