@daloyjs/core 1.0.0-beta.3 → 1.0.0-beta.5
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 +49 -46
- package/dist/app.d.ts +42 -21
- package/dist/app.js +167 -116
- package/dist/docs.d.ts +44 -0
- package/dist/docs.js +47 -8
- package/dist/index.d.ts +17 -17
- package/dist/index.js +5 -5
- package/dist/sbom.cdx.json +9 -9
- package/dist/sbom.spdx.json +5 -5
- package/dist/tenancy.d.ts +16 -7
- package/dist/tenancy.js +16 -7
- package/dist/types.d.ts +26 -1
- package/package.json +6 -5
package/dist/docs.d.ts
CHANGED
|
@@ -254,6 +254,42 @@ export interface DocsAssetOptions {
|
|
|
254
254
|
*/
|
|
255
255
|
crossOrigin?: "anonymous" | "use-credentials";
|
|
256
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Provider-neutral login launcher rendered into generated docs pages.
|
|
259
|
+
*
|
|
260
|
+
* Use this when the OpenAPI docs should expose a visible authorization control
|
|
261
|
+
* that sends developers to a local login form or to an external identity
|
|
262
|
+
* provider such as Entra ID, Auth0, Better Auth, Clerk, Okta, Keycloak, or any
|
|
263
|
+
* other OAuth2/OIDC front end. The launcher only opens the configured URL; it
|
|
264
|
+
* never stores tokens or bypasses the OpenAPI UI's normal security-scheme
|
|
265
|
+
* handling.
|
|
266
|
+
*
|
|
267
|
+
* @since 0.43.0
|
|
268
|
+
*/
|
|
269
|
+
export interface DocsAuthLauncherOptions {
|
|
270
|
+
/**
|
|
271
|
+
* Absolute `http(s)` URL or same-origin/relative URL for the login or
|
|
272
|
+
* authorization entry point. `javascript:`, `data:`, and other executable
|
|
273
|
+
* schemes are refused when the HTML is generated.
|
|
274
|
+
*/
|
|
275
|
+
loginUrl: string;
|
|
276
|
+
/** Button text. Defaults to `"Authorize"`. */
|
|
277
|
+
label?: string;
|
|
278
|
+
/**
|
|
279
|
+
* Accessible helper text shown as the button title and screen-reader label.
|
|
280
|
+
* Defaults to `"Open login or identity provider"`.
|
|
281
|
+
*/
|
|
282
|
+
description?: string;
|
|
283
|
+
/**
|
|
284
|
+
* How to open {@link DocsAuthLauncherOptions.loginUrl}. Defaults to
|
|
285
|
+
* `"popup"` so docs remain open while the provider flow runs.
|
|
286
|
+
*/
|
|
287
|
+
target?: "popup" | "_blank" | "_self";
|
|
288
|
+
/** Popup width in CSS/device pixels. Defaults to `520`. */
|
|
289
|
+
popupWidth?: number;
|
|
290
|
+
/** Popup height in CSS/device pixels. Defaults to `720`. */
|
|
291
|
+
popupHeight?: number;
|
|
292
|
+
}
|
|
257
293
|
/** Shared options for {@link scalarHtml}, {@link swaggerUiHtml}, and {@link redocHtml}. */
|
|
258
294
|
export interface DocsOptions {
|
|
259
295
|
/** Absolute or relative URL of the OpenAPI document to render. */
|
|
@@ -267,6 +303,14 @@ export interface DocsOptions {
|
|
|
267
303
|
assets?: DocsAssetOptions;
|
|
268
304
|
/** CSP `nonce` to apply to inline/script tags; must match the response CSP. */
|
|
269
305
|
scriptNonce?: string;
|
|
306
|
+
/**
|
|
307
|
+
* Optional authorization launcher rendered into the docs page. It gives
|
|
308
|
+
* Scalar, Swagger UI, and Redoc a consistent visible button that opens a
|
|
309
|
+
* local login form or third-party identity-provider authorization URL.
|
|
310
|
+
*
|
|
311
|
+
* @since 0.43.0
|
|
312
|
+
*/
|
|
313
|
+
auth?: DocsAuthLauncherOptions;
|
|
270
314
|
}
|
|
271
315
|
/** Options for {@link scalarHtml}; adds Scalar-specific UI configuration. */
|
|
272
316
|
export interface ScalarHtmlOptions extends DocsOptions {
|
package/dist/docs.js
CHANGED
|
@@ -49,8 +49,7 @@ function integrityAttr(integrity, crossOrigin) {
|
|
|
49
49
|
export function scalarHtml(opts) {
|
|
50
50
|
const title = escapeHtml(opts.title ?? "API Reference");
|
|
51
51
|
const url = escapeHtml(opts.specUrl);
|
|
52
|
-
const scriptUrl = escapeHtml(opts.assets?.scalarScriptUrl ??
|
|
53
|
-
`${JSDELIVR_ORIGIN}/npm/@scalar/api-reference`);
|
|
52
|
+
const scriptUrl = escapeHtml(opts.assets?.scalarScriptUrl ?? `${JSDELIVR_ORIGIN}/npm/@scalar/api-reference`);
|
|
54
53
|
const scriptSri = integrityAttr(opts.assets?.scalarScriptIntegrity, opts.assets?.crossOrigin);
|
|
55
54
|
const nonce = nonceAttr(opts.scriptNonce);
|
|
56
55
|
const configuration = scalarConfigurationAttr(opts.specUrl, opts.configuration);
|
|
@@ -62,6 +61,7 @@ export function scalarHtml(opts) {
|
|
|
62
61
|
</head><body>
|
|
63
62
|
<script id="api-reference" data-url="${url}"${configuration}${nonce}></script>
|
|
64
63
|
<script src="${scriptUrl}"${scriptSri}${nonce}></script>
|
|
64
|
+
${docsAuthLauncherHtml(opts.auth, opts.scriptNonce)}
|
|
65
65
|
</body></html>`;
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
@@ -74,10 +74,8 @@ export function scalarHtml(opts) {
|
|
|
74
74
|
*/
|
|
75
75
|
export function swaggerUiHtml(opts) {
|
|
76
76
|
const title = escapeHtml(opts.title ?? "API Docs");
|
|
77
|
-
const cssUrl = escapeHtml(opts.assets?.swaggerUiCssUrl ??
|
|
78
|
-
|
|
79
|
-
const bundleUrl = escapeHtml(opts.assets?.swaggerUiBundleUrl ??
|
|
80
|
-
`${JSDELIVR_ORIGIN}/npm/swagger-ui-dist/swagger-ui-bundle.js`);
|
|
77
|
+
const cssUrl = escapeHtml(opts.assets?.swaggerUiCssUrl ?? `${JSDELIVR_ORIGIN}/npm/swagger-ui-dist/swagger-ui.css`);
|
|
78
|
+
const bundleUrl = escapeHtml(opts.assets?.swaggerUiBundleUrl ?? `${JSDELIVR_ORIGIN}/npm/swagger-ui-dist/swagger-ui-bundle.js`);
|
|
81
79
|
const cssSri = integrityAttr(opts.assets?.swaggerUiCssIntegrity, opts.assets?.crossOrigin);
|
|
82
80
|
const bundleSri = integrityAttr(opts.assets?.swaggerUiBundleIntegrity, opts.assets?.crossOrigin);
|
|
83
81
|
const nonce = nonceAttr(opts.scriptNonce);
|
|
@@ -97,6 +95,7 @@ export function swaggerUiHtml(opts) {
|
|
|
97
95
|
<div id="swagger"></div>
|
|
98
96
|
<script src="${bundleUrl}"${bundleSri}${nonce}></script>
|
|
99
97
|
<script${nonce}>window.onload=()=>SwaggerUIBundle(${configuration});</script>
|
|
98
|
+
${docsAuthLauncherHtml(opts.auth, opts.scriptNonce)}
|
|
100
99
|
</body></html>`;
|
|
101
100
|
}
|
|
102
101
|
/**
|
|
@@ -115,8 +114,7 @@ export function swaggerUiHtml(opts) {
|
|
|
115
114
|
*/
|
|
116
115
|
export function redocHtml(opts) {
|
|
117
116
|
const title = escapeHtml(opts.title ?? "API Docs");
|
|
118
|
-
const scriptUrl = escapeHtml(opts.assets?.redocScriptUrl ??
|
|
119
|
-
`${JSDELIVR_ORIGIN}/npm/redoc/bundles/redoc.standalone.js`);
|
|
117
|
+
const scriptUrl = escapeHtml(opts.assets?.redocScriptUrl ?? `${JSDELIVR_ORIGIN}/npm/redoc/bundles/redoc.standalone.js`);
|
|
120
118
|
const scriptSri = integrityAttr(opts.assets?.redocScriptIntegrity, opts.assets?.crossOrigin);
|
|
121
119
|
const nonce = nonceAttr(opts.scriptNonce);
|
|
122
120
|
const specArg = jsonForScript(opts.specUrl);
|
|
@@ -130,6 +128,7 @@ export function redocHtml(opts) {
|
|
|
130
128
|
<div id="redoc"></div>
|
|
131
129
|
<script src="${scriptUrl}"${scriptSri}${nonce}></script>
|
|
132
130
|
<script${nonce}>Redoc.init(${specArg},${optionsArg},document.getElementById("redoc"));</script>
|
|
131
|
+
${docsAuthLauncherHtml(opts.auth, opts.scriptNonce)}
|
|
133
132
|
</body></html>`;
|
|
134
133
|
}
|
|
135
134
|
/**
|
|
@@ -238,6 +237,46 @@ function escapeHtml(s) {
|
|
|
238
237
|
function jsonForScript(value) {
|
|
239
238
|
return JSON.stringify(value).replace(/[<\u2028\u2029]/g, (c) => ({ "<": "\\u003c", "\u2028": "\\u2028", "\u2029": "\\u2029" })[c]);
|
|
240
239
|
}
|
|
240
|
+
function docsAuthLauncherHtml(auth, scriptNonce) {
|
|
241
|
+
if (!auth)
|
|
242
|
+
return "";
|
|
243
|
+
const loginUrl = normalizeDocsAuthLoginUrl(auth.loginUrl);
|
|
244
|
+
const label = auth.label ?? "Authorize";
|
|
245
|
+
const description = auth.description ?? "Open login or identity provider";
|
|
246
|
+
const target = auth.target ?? "popup";
|
|
247
|
+
const popupWidth = positiveIntegerOrDefault(auth.popupWidth, 520);
|
|
248
|
+
const popupHeight = positiveIntegerOrDefault(auth.popupHeight, 720);
|
|
249
|
+
const payload = jsonForScript({
|
|
250
|
+
loginUrl,
|
|
251
|
+
target,
|
|
252
|
+
popupWidth,
|
|
253
|
+
popupHeight,
|
|
254
|
+
});
|
|
255
|
+
const nonce = nonceAttr(scriptNonce);
|
|
256
|
+
return `<style>
|
|
257
|
+
.daloy-docs-auth{position:fixed;right:16px;top:16px;z-index:2147483647;display:inline-flex;align-items:center;gap:8px;border:1px solid #1d4ed8;border-radius:6px;background:#2563eb;color:#fff;font:600 14px/1.2 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;padding:10px 14px;box-shadow:0 8px 24px rgba(15,23,42,.18);cursor:pointer}
|
|
258
|
+
.daloy-docs-auth:focus{outline:3px solid rgba(37,99,235,.35);outline-offset:2px}
|
|
259
|
+
</style>
|
|
260
|
+
<button type="button" class="daloy-docs-auth" data-daloy-docs-auth title="${escapeHtml(description)}" aria-label="${escapeHtml(description)}">${escapeHtml(label)}</button>
|
|
261
|
+
<script${nonce}>(()=>{const o=${payload};const b=document.querySelector("[data-daloy-docs-auth]");if(!b)return;b.addEventListener("click",()=>{if(o.target==="_self"){window.location.assign(o.loginUrl);return;}if(o.target==="_blank"){window.open(o.loginUrl,"_blank","noopener,noreferrer");return;}const left=Math.max(0,Math.round((window.screenX||0)+((window.outerWidth||o.popupWidth)-o.popupWidth)/2));const top=Math.max(0,Math.round((window.screenY||0)+((window.outerHeight||o.popupHeight)-o.popupHeight)/2));const features="popup=yes,width="+o.popupWidth+",height="+o.popupHeight+",left="+left+",top="+top+",noopener,noreferrer";window.open(o.loginUrl,"daloy_docs_auth",features);});})();</script>`;
|
|
262
|
+
}
|
|
263
|
+
function normalizeDocsAuthLoginUrl(loginUrl) {
|
|
264
|
+
if (typeof loginUrl !== "string" || loginUrl.trim() === "") {
|
|
265
|
+
throw new TypeError("docs auth loginUrl must be a non-empty string");
|
|
266
|
+
}
|
|
267
|
+
const trimmed = loginUrl.trim();
|
|
268
|
+
const parsed = new URL(trimmed, "https://daloyjs.local");
|
|
269
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
270
|
+
throw new TypeError(`docs auth loginUrl must be an http(s) or relative URL; got ${JSON.stringify(loginUrl)}`);
|
|
271
|
+
}
|
|
272
|
+
return trimmed;
|
|
273
|
+
}
|
|
274
|
+
function positiveIntegerOrDefault(value, fallback) {
|
|
275
|
+
if (typeof value === "number" && Number.isInteger(value) && value > 0) {
|
|
276
|
+
return value;
|
|
277
|
+
}
|
|
278
|
+
return fallback;
|
|
279
|
+
}
|
|
241
280
|
function scalarConfigurationAttr(specUrl, configuration) {
|
|
242
281
|
if (!configuration)
|
|
243
282
|
return "";
|
package/dist/index.d.ts
CHANGED
|
@@ -11,28 +11,28 @@ export type { BehindProxyConfig, ConnInfo } from "./conn-info.js";
|
|
|
11
11
|
export { subdomains, PSL_SNAPSHOT_DATE, PSL_PUBLIC_SUFFIXES, MAX_SNAPSHOT_AGE_DAYS, } from "./subdomains.js";
|
|
12
12
|
export type { SubdomainsOptions, SubdomainsResult } from "./subdomains.js";
|
|
13
13
|
export { defineDependency, DEPENDENCY_MARKER } from "./dependency.js";
|
|
14
|
-
export type { DependencyHooks, DependencyOptions
|
|
14
|
+
export type { DependencyHooks, DependencyOptions } from "./dependency.js";
|
|
15
15
|
export type { RouteDefinition, HttpMethod, PathString, RequestSchemas, ResponsesMap, ResponseSpec, AuthSpec, Hooks, BaseContext, AppState, AuthScheme, AuthContext, HandlerReturn, InferRequest, ParamsOf, PathParams, CallbackDefinition, CallbackMap, CallbackOperation, RouteExample, RouteMeta, } from "./types.js";
|
|
16
16
|
export { HttpError, BadRequestError, ValidationError, NotFoundError, ConflictError, UnauthorizedError, ForbiddenError, MethodNotAllowedError, PayloadTooLargeError, RequestHeaderFieldsTooLargeError, UnsupportedMediaTypeError, TooManyRequestsError, RequestTimeoutError, InternalError, MessageLeakError, httpError, SAFE_CUSTOM_ERROR_RESPONSE_HEADERS, checkCustomErrorResponseHeaders, } from "./errors.js";
|
|
17
17
|
export type { ProblemDetails, ProblemRenderOptions, HttpErrorOptions } from "./errors.js";
|
|
18
18
|
export type { StandardSchemaV1 } from "./schema.js";
|
|
19
19
|
export { validate, isStandardSchema } from "./schema.js";
|
|
20
20
|
export { diffOpenAPI, hasBreakingChanges } from "./openapi-diff.js";
|
|
21
|
-
export type { ChangeSeverity, OpenAPIChange, OpenAPIDiffResult
|
|
21
|
+
export type { ChangeSeverity, OpenAPIChange, OpenAPIDiffResult } from "./openapi-diff.js";
|
|
22
22
|
export { readBodyLimited, safeJsonParse, isForbiddenObjectKey, sanitizeHeaderName, sanitizeHeaderValue, timingSafeEqual, randomId, assertNoDuplicateSingletonHeaders, assertNoReservedInternalHeaders, assertHeaderCountWithinLimit, DEFAULT_MAX_HEADER_COUNT, RESERVED_INBOUND_HEADER_PREFIXES, SMUGGLING_SINGLETON_HEADERS, verifyWebhookSignature, signWebhookPayload, WEBHOOK_DEFAULT_TOLERANCE_SECONDS, assertStrongSecret, MIN_PROD_SECRET_BYTES, WEAK_SECRET_STRINGS, sanitizeFilename, assertSafeRelativePath, hasMongoOperatorKeys, assertNoMongoOperators, } from "./security.js";
|
|
23
23
|
export type { WebhookHmacAlgorithm } from "./security.js";
|
|
24
24
|
export { requestId, secureHeaders, SECURE_HEADERS_MARKER, cors, CORS_HOOK_MARKER, CORS_ORIGIN_ALLOW_MARKER, CORS_WILDCARD_ORIGIN_MARKER, rateLimit, loginThrottle, timing, bearerAuth, basicAuth, csrf, CSRF_HOOK_MARKER, fetchMetadata, requireScopes, REQUIRE_SCOPES_AGGREGATE_KEY, REQUIRE_SCOPES_HOOK_MARKER, _resetSharedRateLimitStoresForTests, } from "./middleware.js";
|
|
25
25
|
export { etag } from "./etag.js";
|
|
26
26
|
export type { ETagOptions } from "./etag.js";
|
|
27
27
|
export { compression, COMPRESSION_HOOK_MARKER, _resetCompressionRuntimeProbeForTests, } from "./compression.js";
|
|
28
|
-
export type { CompressionEncoding, CompressionOptions
|
|
28
|
+
export type { CompressionEncoding, CompressionOptions } from "./compression.js";
|
|
29
29
|
export { createJwtSigner, createJwtVerifier, JwtError, DEFAULT_JWT_MAX_LIFETIME_SECONDS, } from "./jwt.js";
|
|
30
30
|
export type { JwtAlgorithm, JwtKeyMaterial, JwtSignerOptions, JwtVerifierOptions, JwtVerified, } from "./jwt.js";
|
|
31
31
|
export { jwk } from "./jwk.js";
|
|
32
|
-
export type { JwkAlgorithm, JwkOptions, JwkSet, JwkSource, JwkVerifyHook
|
|
32
|
+
export type { JwkAlgorithm, JwkOptions, JwkSet, JwkSource, JwkVerifyHook } from "./jwk.js";
|
|
33
33
|
export { serializeCookie, serializeClearCookie, assertCookieAttributes, readRequestCookie, } from "./cookie.js";
|
|
34
34
|
export type { CookieAttributes, CookieSameSite } from "./cookie.js";
|
|
35
|
-
export { assertTemporalClaims, TemporalClaimError
|
|
35
|
+
export { assertTemporalClaims, TemporalClaimError } from "./time-claims.js";
|
|
36
36
|
export type { TemporalClaims, TemporalClaimErrorCode, AssertTemporalClaimsOptions, } from "./time-claims.js";
|
|
37
37
|
export { every, some, except } from "./combine.js";
|
|
38
38
|
export type { ExceptPredicate } from "./combine.js";
|
|
@@ -42,24 +42,24 @@ export { fetchGuard, SsrfBlockedError } from "./fetch-guard.js";
|
|
|
42
42
|
export type { FetchGuardOptions, SsrfBlockReason } from "./fetch-guard.js";
|
|
43
43
|
export { resilientFetch, CircuitBreaker, CircuitOpenError, FetchTimeoutError, } from "./fetch-resilience.js";
|
|
44
44
|
export type { ResilientFetchOptions, CircuitBreakerOptions, CircuitState, RetryContext, } from "./fetch-resilience.js";
|
|
45
|
-
export { createWebhookSender, MemoryWebhookDeadLetterSink
|
|
45
|
+
export { createWebhookSender, MemoryWebhookDeadLetterSink } from "./webhook-delivery.js";
|
|
46
46
|
export type { WebhookEvent, WebhookSenderOptions, WebhookDeliveryResult, WebhookDeadLetter, WebhookDeadLetterSink, WebhookAttempt, } from "./webhook-delivery.js";
|
|
47
|
-
export { Scheduler, CronParseError, parseCron, nextCronRun
|
|
47
|
+
export { Scheduler, CronParseError, parseCron, nextCronRun } from "./scheduler.js";
|
|
48
48
|
export type { SchedulerOptions, SchedulerLogger, TimerFns, TaskDefinition, TaskHandler, TaskRunContext, TaskErrorInfo, TaskState, CronFields, } from "./scheduler.js";
|
|
49
49
|
export { clientCertAuth, setClientCertificate, getClientCertificate, normalizePeerCertificate, parseForwardedClientCert, } from "./mtls.js";
|
|
50
50
|
export type { ClientCertificate, ClientCertificateSource, ClientCertAuthOptions, ClientCertHeaderConfig, PeerCertificateLike, } from "./mtls.js";
|
|
51
51
|
export { signMessage, signRequest, verifyMessage, verifyRequest, httpSignatureAuth, contentDigest, verifyContentDigest, DEFAULT_SIGNATURE_LABEL, DEFAULT_MAX_SIGNATURE_AGE_SECONDS, DEFAULT_SIGNATURE_CLOCK_SKEW_SECONDS, } from "./http-signatures.js";
|
|
52
52
|
export type { HttpSignatureAlgorithm, HttpSignatureKeyMaterial, HttpSignatureKey, SignMessageOptions, SignRequestOptions, MessageSignature, VerifyMessageOptions, VerifyResult, VerifySuccess, VerifyFailure, KeyResolutionInfo, HttpSignatureAuthOptions, ContentDigestAlgorithm, } from "./http-signatures.js";
|
|
53
|
-
export { autoBan, MemoryAutoBanStore, _resetAutoBanStoresForTests
|
|
53
|
+
export { autoBan, MemoryAutoBanStore, _resetAutoBanStoresForTests } from "./auto-ban.js";
|
|
54
54
|
export type { AutoBanOptions, AutoBanStore, AutoBanRecord, AutoBanEvent, AutoBanStrikeEvent, } from "./auto-ban.js";
|
|
55
55
|
export { botGuard, GOOGLEBOT, BINGBOT, WELL_KNOWN_BOTS } from "./bot-guard.js";
|
|
56
|
-
export type { BotGuardOptions, BotGuardEvent, BotResolver, VerifiedBotRule
|
|
56
|
+
export type { BotGuardOptions, BotGuardEvent, BotResolver, VerifiedBotRule } from "./bot-guard.js";
|
|
57
57
|
export { ipReputation, urlFeed } from "./ip-reputation.js";
|
|
58
58
|
export type { IpReputationOptions, IpReputationFeed, IpReputationMatch, IpReputationController, UrlFeedOptions, } from "./ip-reputation.js";
|
|
59
59
|
export { geoBlock } from "./geo-block.js";
|
|
60
60
|
export type { GeoBlockOptions, GeoBlockDecision, GeoBlockReason, GeoState, CountryFromIp, CountryFromContext, } from "./geo-block.js";
|
|
61
61
|
export { concurrencyLimit } from "./concurrency-limit.js";
|
|
62
|
-
export type { ConcurrencyLimitOptions, ConcurrencyRejection
|
|
62
|
+
export type { ConcurrencyLimitOptions, ConcurrencyRejection } from "./concurrency-limit.js";
|
|
63
63
|
export { requestDecompression, decompressRequestBody, DecompressionBombError, UnsupportedContentEncodingError, MalformedCompressedBodyError, _resetRequestDecompressionProbeForTests, } from "./request-decompression.js";
|
|
64
64
|
export type { RequestDecompressionOptions, RequestDecompressionEncoding, DecompressionBombInfo, } from "./request-decompression.js";
|
|
65
65
|
export { waf } from "./waf.js";
|
|
@@ -67,17 +67,17 @@ export type { WafOptions, WafMode, WafRuleId, WafRuleConfig, WafInspectConfig, W
|
|
|
67
67
|
export { safeRedirect, OpenRedirectBlockedError } from "./safe-redirect.js";
|
|
68
68
|
export type { SafeRedirectOptions, SafeRedirectStatus, SafeRedirectBlockReason, } from "./safe-redirect.js";
|
|
69
69
|
export { loadShedding, LOAD_SHEDDING_MARKER } from "./load-shedding.js";
|
|
70
|
-
export type { LoadSheddingOptions, LoadSheddingSnapshot
|
|
70
|
+
export type { LoadSheddingOptions, LoadSheddingSnapshot } from "./load-shedding.js";
|
|
71
71
|
export { defineConfig, ConfigValidationError } from "./config.js";
|
|
72
|
-
export type { ConfigSource, DefineConfigOptions
|
|
72
|
+
export type { ConfigSource, DefineConfigOptions } from "./config.js";
|
|
73
73
|
export type { RequestIdOptions, SecureHeadersOptions, CspDirectivesOptions, CorsOptions, CorsOriginAllow, RateLimitOptions, RateLimitStore, LoginThrottleOptions, CsrfOptions, CsrfCookieOptions, FetchMetadataOptions, BasicAuthOptions, } from "./middleware.js";
|
|
74
74
|
export type { BearerAuthOptions, BearerAuthVerifyHook } from "./middleware.js";
|
|
75
75
|
export { createLogger, noopLogger, DEFAULT_REDACT_KEYS } from "./logger.js";
|
|
76
|
-
export type { Logger, LogLevel, ConsoleLoggerOptions, LoggerRedactionOptions
|
|
77
|
-
export type { ScalarJsonPrimitive, ScalarJsonValue, ScalarReferenceConfiguration, ScalarTheme, RedocConfiguration, RedocHtmlOptions, SwaggerUiConfiguration, SwaggerUiHtmlOptions, AsyncApiHtmlOptions, DocsAssetOptions, } from "./docs.js";
|
|
76
|
+
export type { Logger, LogLevel, ConsoleLoggerOptions, LoggerRedactionOptions } from "./logger.js";
|
|
77
|
+
export type { ScalarJsonPrimitive, ScalarJsonValue, ScalarReferenceConfiguration, ScalarTheme, RedocConfiguration, RedocHtmlOptions, SwaggerUiConfiguration, SwaggerUiHtmlOptions, AsyncApiHtmlOptions, DocsAssetOptions, DocsAuthLauncherOptions, } from "./docs.js";
|
|
78
78
|
export { formatStartupBanner, printStartupBanner } from "./banner.js";
|
|
79
79
|
export type { StartupBannerLink, StartupBannerOptions } from "./banner.js";
|
|
80
|
-
export { sseStream, sseResponse, ndjsonStream, ndjsonResponse
|
|
80
|
+
export { sseStream, sseResponse, ndjsonStream, ndjsonResponse } from "./streaming.js";
|
|
81
81
|
export type { SSEMessage, StreamOptions, SSEStreamOptions, SSEResponseOptions, NDJSONResponseOptions, } from "./streaming.js";
|
|
82
82
|
export { httpBearerScheme, httpBasicScheme, apiKeyScheme, oauth2Scheme, openIdConnectScheme, REQUIRE_PAYLOAD_AUTH_EXTENSION, securitySchemeRequiresPayloadAuth, toOpenAPISecurityScheme, } from "./security-schemes.js";
|
|
83
83
|
export type { ApiKeyLocation, ApiKeyScheme, ApiKeySchemeOptions, HttpBasicScheme, HttpBasicSchemeOptions, HttpBearerScheme, HttpBearerSchemeOptions, OAuth2AuthorizationCodeFlow, OAuth2ClientCredentialsFlow, OAuth2Flows, OAuth2ImplicitFlow, OAuth2PasswordFlow, OAuth2Scheme, OAuth2SchemeOptions, OpenIdConnectScheme, OpenIdConnectSchemeOptions, SecurityScheme, RequirePayloadAuthExtension, } from "./security-schemes.js";
|
|
@@ -88,11 +88,11 @@ export type { SessionOptions, SessionCookieOptions, SessionContext, SessionRecor
|
|
|
88
88
|
export { idempotency, MemoryIdempotencyStore, _resetSharedIdempotencyStoresForTests, } from "./idempotency.js";
|
|
89
89
|
export type { IdempotencyOptions, IdempotencyStore, IdempotencyRecord, StoredIdempotentResponse, } from "./idempotency.js";
|
|
90
90
|
export { responseCache, MemoryResponseCacheStore, _resetSharedResponseCacheStoresForTests, } from "./response-cache.js";
|
|
91
|
-
export type { ResponseCacheOptions, ResponseCacheStore, CachedResponse
|
|
91
|
+
export type { ResponseCacheOptions, ResponseCacheStore, CachedResponse } from "./response-cache.js";
|
|
92
92
|
export { encodeCursor, decodeCursor, buildLinkHeader, buildPageLinks, paginationQuery, MAX_CURSOR_LENGTH, } from "./pagination.js";
|
|
93
93
|
export type { PaginationLink, PageLinkOptions, PageLinks, PaginationQueryOptions, PaginationParams, PaginationQuerySchema, } from "./pagination.js";
|
|
94
94
|
export { MetricsRegistry, Counter, Gauge, Histogram, httpMetrics, DEFAULT_DURATION_BUCKETS, PROMETHEUS_CONTENT_TYPE, } from "./metrics.js";
|
|
95
|
-
export type { MetricLabels, MetricsRegistryOptions, HttpMetricsOptions
|
|
95
|
+
export type { MetricLabels, MetricsRegistryOptions, HttpMetricsOptions } from "./metrics.js";
|
|
96
96
|
export { fileField, multipartObject, isFileFieldSchema, isMultipartObjectSchema, } from "./multipart.js";
|
|
97
97
|
export type { FileFieldSchema, FileFieldOptions, FileMagicBytesOption, FileMagicBytesSignature, MultipartObjectOptions, MultipartShape, UploadedFile, } from "./multipart.js";
|
|
98
98
|
export { otelTracing, TRACING_SPAN_KIND_SERVER, TRACING_SPAN_STATUS_UNSET, TRACING_SPAN_STATUS_OK, TRACING_SPAN_STATUS_ERROR, } from "./tracing.js";
|
package/dist/index.js
CHANGED
|
@@ -18,16 +18,16 @@ export { compression, COMPRESSION_HOOK_MARKER, _resetCompressionRuntimeProbeForT
|
|
|
18
18
|
export { createJwtSigner, createJwtVerifier, JwtError, DEFAULT_JWT_MAX_LIFETIME_SECONDS, } from "./jwt.js";
|
|
19
19
|
export { jwk } from "./jwk.js";
|
|
20
20
|
export { serializeCookie, serializeClearCookie, assertCookieAttributes, readRequestCookie, } from "./cookie.js";
|
|
21
|
-
export { assertTemporalClaims, TemporalClaimError
|
|
21
|
+
export { assertTemporalClaims, TemporalClaimError } from "./time-claims.js";
|
|
22
22
|
export { every, some, except } from "./combine.js";
|
|
23
23
|
export { ipRestriction } from "./ip-restriction.js";
|
|
24
24
|
export { fetchGuard, SsrfBlockedError } from "./fetch-guard.js";
|
|
25
25
|
export { resilientFetch, CircuitBreaker, CircuitOpenError, FetchTimeoutError, } from "./fetch-resilience.js";
|
|
26
|
-
export { createWebhookSender, MemoryWebhookDeadLetterSink
|
|
27
|
-
export { Scheduler, CronParseError, parseCron, nextCronRun
|
|
26
|
+
export { createWebhookSender, MemoryWebhookDeadLetterSink } from "./webhook-delivery.js";
|
|
27
|
+
export { Scheduler, CronParseError, parseCron, nextCronRun } from "./scheduler.js";
|
|
28
28
|
export { clientCertAuth, setClientCertificate, getClientCertificate, normalizePeerCertificate, parseForwardedClientCert, } from "./mtls.js";
|
|
29
29
|
export { signMessage, signRequest, verifyMessage, verifyRequest, httpSignatureAuth, contentDigest, verifyContentDigest, DEFAULT_SIGNATURE_LABEL, DEFAULT_MAX_SIGNATURE_AGE_SECONDS, DEFAULT_SIGNATURE_CLOCK_SKEW_SECONDS, } from "./http-signatures.js";
|
|
30
|
-
export { autoBan, MemoryAutoBanStore, _resetAutoBanStoresForTests
|
|
30
|
+
export { autoBan, MemoryAutoBanStore, _resetAutoBanStoresForTests } from "./auto-ban.js";
|
|
31
31
|
export { botGuard, GOOGLEBOT, BINGBOT, WELL_KNOWN_BOTS } from "./bot-guard.js";
|
|
32
32
|
export { ipReputation, urlFeed } from "./ip-reputation.js";
|
|
33
33
|
export { geoBlock } from "./geo-block.js";
|
|
@@ -39,7 +39,7 @@ export { loadShedding, LOAD_SHEDDING_MARKER } from "./load-shedding.js";
|
|
|
39
39
|
export { defineConfig, ConfigValidationError } from "./config.js";
|
|
40
40
|
export { createLogger, noopLogger, DEFAULT_REDACT_KEYS } from "./logger.js";
|
|
41
41
|
export { formatStartupBanner, printStartupBanner } from "./banner.js";
|
|
42
|
-
export { sseStream, sseResponse, ndjsonStream, ndjsonResponse
|
|
42
|
+
export { sseStream, sseResponse, ndjsonStream, ndjsonResponse } from "./streaming.js";
|
|
43
43
|
export { httpBearerScheme, httpBasicScheme, apiKeyScheme, oauth2Scheme, openIdConnectScheme, REQUIRE_PAYLOAD_AUTH_EXTENSION, securitySchemeRequiresPayloadAuth, toOpenAPISecurityScheme, } from "./security-schemes.js";
|
|
44
44
|
export { discriminator, discriminatedUnion } from "./discriminator.js";
|
|
45
45
|
export { session, rotateSession, signValue, verifySignedValue, MemorySessionStore, SESSION_HOOK_MARKER, SESSION_SECRETS_MARKER, } from "./session.js";
|
package/dist/sbom.cdx.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bomFormat": "CycloneDX",
|
|
3
3
|
"specVersion": "1.5",
|
|
4
|
-
"serialNumber": "urn:uuid:
|
|
4
|
+
"serialNumber": "urn:uuid:448a4447-0b88-5512-8ce5-485b6688ff4c",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
|
-
"timestamp": "2026-
|
|
7
|
+
"timestamp": "2026-07-01T13:38:31.674Z",
|
|
8
8
|
"tools": [
|
|
9
9
|
{
|
|
10
10
|
"vendor": "DaloyJS",
|
|
11
11
|
"name": "daloy-generate-sbom",
|
|
12
|
-
"version": "1.0.0-beta.
|
|
12
|
+
"version": "1.0.0-beta.5"
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
15
|
"authors": [
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
],
|
|
20
20
|
"component": {
|
|
21
21
|
"type": "library",
|
|
22
|
-
"bom-ref": "pkg:npm/@daloyjs/core@1.0.0-beta.
|
|
22
|
+
"bom-ref": "pkg:npm/@daloyjs/core@1.0.0-beta.5",
|
|
23
23
|
"name": "@daloyjs/core",
|
|
24
|
-
"version": "1.0.0-beta.
|
|
24
|
+
"version": "1.0.0-beta.5",
|
|
25
25
|
"description": "DaloyJS is a runtime-portable, contract-first TypeScript web framework with built-in OpenAPI (Hey API), typed client generation, large-scale maintainability, and security-first defaults. Hono-grade portability, Elysia-grade DX, FastAPI-grade docs, Fastify-grade ops — distributed via pnpm.",
|
|
26
|
-
"purl": "pkg:npm/@daloyjs/core@1.0.0-beta.
|
|
26
|
+
"purl": "pkg:npm/@daloyjs/core@1.0.0-beta.5",
|
|
27
27
|
"licenses": [
|
|
28
28
|
{
|
|
29
29
|
"license": {
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
}
|
|
47
47
|
],
|
|
48
48
|
"swid": {
|
|
49
|
-
"tagId": "swidtag--daloyjs-core-1.0.0-beta.
|
|
49
|
+
"tagId": "swidtag--daloyjs-core-1.0.0-beta.5",
|
|
50
50
|
"name": "@daloyjs/core",
|
|
51
|
-
"version": "1.0.0-beta.
|
|
51
|
+
"version": "1.0.0-beta.5",
|
|
52
52
|
"tagVersion": 0,
|
|
53
53
|
"patch": false
|
|
54
54
|
}
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"components": [],
|
|
58
58
|
"dependencies": [
|
|
59
59
|
{
|
|
60
|
-
"ref": "pkg:npm/@daloyjs/core@1.0.0-beta.
|
|
60
|
+
"ref": "pkg:npm/@daloyjs/core@1.0.0-beta.5",
|
|
61
61
|
"dependsOn": []
|
|
62
62
|
}
|
|
63
63
|
]
|
package/dist/sbom.spdx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"spdxVersion": "SPDX-2.3",
|
|
3
3
|
"dataLicense": "CC0-1.0",
|
|
4
4
|
"SPDXID": "SPDXRef-DOCUMENT",
|
|
5
|
-
"name": "@daloyjs/core-1.0.0-beta.
|
|
6
|
-
"documentNamespace": "https://github.com/daloyjs/daloy/sbom/@daloyjs/core-1.0.0-beta.
|
|
5
|
+
"name": "@daloyjs/core-1.0.0-beta.5",
|
|
6
|
+
"documentNamespace": "https://github.com/daloyjs/daloy/sbom/@daloyjs/core-1.0.0-beta.5-448a4447-0b88-5512-8ce5-485b6688ff4c",
|
|
7
7
|
"creationInfo": {
|
|
8
|
-
"created": "2026-
|
|
8
|
+
"created": "2026-07-01T13:38:31.674Z",
|
|
9
9
|
"creators": [
|
|
10
10
|
"Tool: daloy-generate-sbom",
|
|
11
11
|
"Organization: DaloyJS"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
{
|
|
17
17
|
"SPDXID": "SPDXRef-Package--daloyjs-core",
|
|
18
18
|
"name": "@daloyjs/core",
|
|
19
|
-
"versionInfo": "1.0.0-beta.
|
|
19
|
+
"versionInfo": "1.0.0-beta.5",
|
|
20
20
|
"downloadLocation": "https://github.com/daloyjs/daloy",
|
|
21
21
|
"filesAnalyzed": false,
|
|
22
22
|
"licenseConcluded": "MIT",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
{
|
|
28
28
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
29
29
|
"referenceType": "purl",
|
|
30
|
-
"referenceLocator": "pkg:npm/@daloyjs/core@1.0.0-beta.
|
|
30
|
+
"referenceLocator": "pkg:npm/@daloyjs/core@1.0.0-beta.5"
|
|
31
31
|
}
|
|
32
32
|
]
|
|
33
33
|
}
|
package/dist/tenancy.d.ts
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* once per request, validates and normalizes it, and exposes it on
|
|
6
6
|
* `ctx.state.tenant` for handlers and downstream middleware. It is the
|
|
7
7
|
* single source of truth for "who is this request for" so the per-tenant
|
|
8
|
-
* isolation knobs on the rest of the framework (`rateLimit`
|
|
9
|
-
* `
|
|
10
|
-
* off the same resolved value via {@link tenantScope}.
|
|
8
|
+
* isolation knobs on the rest of the framework (`rateLimit` /
|
|
9
|
+
* `responseCache` `keyGenerator`, `concurrencyLimit` / `idempotency` `scope`)
|
|
10
|
+
* can all key off the same resolved value via {@link tenantScope}.
|
|
11
11
|
*
|
|
12
12
|
* Secure-by-default posture:
|
|
13
13
|
*
|
|
@@ -227,10 +227,19 @@ export interface TenantScopeOptions {
|
|
|
227
227
|
* or poison another tenant's:
|
|
228
228
|
*
|
|
229
229
|
* ```ts
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
230
|
+
* const scope = tenantScope();
|
|
231
|
+
* rateLimit({ windowMs: 60_000, max: 100, keyGenerator: scope });
|
|
232
|
+
* concurrencyLimit({ maxConcurrent: 20, scope });
|
|
233
|
+
* idempotency({ scope }); // CWE-524 cross-tenant cache defense
|
|
234
|
+
* // responseCache's keyGenerator REPLACES the whole key and it takes
|
|
235
|
+
* // ttlSeconds, so fold the tenant in alongside the path yourself:
|
|
236
|
+
* responseCache({
|
|
237
|
+
* ttlSeconds: 30,
|
|
238
|
+
* keyGenerator: (ctx) => {
|
|
239
|
+
* const u = new URL(ctx.request.url);
|
|
240
|
+
* return `${scope(ctx)}:${ctx.request.method} ${u.pathname}${u.search}`;
|
|
241
|
+
* },
|
|
242
|
+
* });
|
|
234
243
|
* ```
|
|
235
244
|
*
|
|
236
245
|
* The `tenant:` prefix keeps these keys from colliding with other key spaces
|
package/dist/tenancy.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* once per request, validates and normalizes it, and exposes it on
|
|
6
6
|
* `ctx.state.tenant` for handlers and downstream middleware. It is the
|
|
7
7
|
* single source of truth for "who is this request for" so the per-tenant
|
|
8
|
-
* isolation knobs on the rest of the framework (`rateLimit`
|
|
9
|
-
* `
|
|
10
|
-
* off the same resolved value via {@link tenantScope}.
|
|
8
|
+
* isolation knobs on the rest of the framework (`rateLimit` /
|
|
9
|
+
* `responseCache` `keyGenerator`, `concurrencyLimit` / `idempotency` `scope`)
|
|
10
|
+
* can all key off the same resolved value via {@link tenantScope}.
|
|
11
11
|
*
|
|
12
12
|
* Secure-by-default posture:
|
|
13
13
|
*
|
|
@@ -270,10 +270,19 @@ export function tenancy(opts) {
|
|
|
270
270
|
* or poison another tenant's:
|
|
271
271
|
*
|
|
272
272
|
* ```ts
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
273
|
+
* const scope = tenantScope();
|
|
274
|
+
* rateLimit({ windowMs: 60_000, max: 100, keyGenerator: scope });
|
|
275
|
+
* concurrencyLimit({ maxConcurrent: 20, scope });
|
|
276
|
+
* idempotency({ scope }); // CWE-524 cross-tenant cache defense
|
|
277
|
+
* // responseCache's keyGenerator REPLACES the whole key and it takes
|
|
278
|
+
* // ttlSeconds, so fold the tenant in alongside the path yourself:
|
|
279
|
+
* responseCache({
|
|
280
|
+
* ttlSeconds: 30,
|
|
281
|
+
* keyGenerator: (ctx) => {
|
|
282
|
+
* const u = new URL(ctx.request.url);
|
|
283
|
+
* return `${scope(ctx)}:${ctx.request.method} ${u.pathname}${u.search}`;
|
|
284
|
+
* },
|
|
285
|
+
* });
|
|
277
286
|
* ```
|
|
278
287
|
*
|
|
279
288
|
* The `tenant:` prefix keeps these keys from colliding with other key spaces
|
package/dist/types.d.ts
CHANGED
|
@@ -422,7 +422,32 @@ export interface RouteDefinition<P extends PathString = PathString, M extends Ht
|
|
|
422
422
|
*/
|
|
423
423
|
meta?: RouteMeta;
|
|
424
424
|
hooks?: Hooks;
|
|
425
|
-
|
|
425
|
+
/**
|
|
426
|
+
* The route handler. Receives the typed, validated {@link BaseContext} and
|
|
427
|
+
* returns either:
|
|
428
|
+
*
|
|
429
|
+
* - a structured result `{ status, body, headers? }` whose `body` is
|
|
430
|
+
* validated against the route's response schema and typed end-to-end into
|
|
431
|
+
* the OpenAPI document and generated client (the common case), or
|
|
432
|
+
* - a raw web-standard {@link Response} as an escape hatch for streaming,
|
|
433
|
+
* proxying, or pre-built bodies (for example an AI SDK
|
|
434
|
+
* `result.toUIMessageStreamResponse()`, or an upstream `fetch()` response
|
|
435
|
+
* forwarded verbatim).
|
|
436
|
+
*
|
|
437
|
+
* A returned `Response` **bypasses response-schema validation and the
|
|
438
|
+
* typed-client body type by design** — there is no schema that can describe
|
|
439
|
+
* an opaque stream. It is still finalized exactly like every other response,
|
|
440
|
+
* so no security control is skipped: headers set via `ctx.set` (including
|
|
441
|
+
* `secureHeaders()` and CORS) are copied onto it, `x-request-id` is added
|
|
442
|
+
* when absent, any `onSend` / `onResponse` hooks run, server-fingerprint
|
|
443
|
+
* headers (`server`, `x-powered-by`) are stripped, and a `HEAD` request still
|
|
444
|
+
* yields an empty body. This mirrors the existing `beforeHandle` `Response`
|
|
445
|
+
* passthrough. Prefer the structured result whenever a schema can describe
|
|
446
|
+
* the payload; reach for `Response` only when it genuinely cannot.
|
|
447
|
+
*
|
|
448
|
+
* @since 0.1.0
|
|
449
|
+
*/
|
|
450
|
+
handler: (ctx: BaseContext<P, Req>) => HandlerReturn<Res> | Response | Promise<HandlerReturn<Res> | Response>;
|
|
426
451
|
}
|
|
427
452
|
/**
|
|
428
453
|
* One operation inside an OpenAPI Callback Object. Mirrors a route minus
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@daloyjs/core",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.5",
|
|
4
4
|
"description": "DaloyJS is a runtime-portable, contract-first TypeScript web framework with built-in OpenAPI (Hey API), typed client generation, large-scale maintainability, and security-first defaults. Hono-grade portability, Elysia-grade DX, FastAPI-grade docs, Fastify-grade ops — distributed via pnpm.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"daloy": "bin/daloy.mjs"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|
|
40
|
-
"node": "
|
|
40
|
+
"node": "^24.0.0 || >=26.0.0",
|
|
41
41
|
"pnpm": ">=11.0.0"
|
|
42
42
|
},
|
|
43
43
|
"exports": {
|
|
@@ -227,9 +227,9 @@
|
|
|
227
227
|
}
|
|
228
228
|
},
|
|
229
229
|
"devDependencies": {
|
|
230
|
-
"@hey-api/openapi-ts": "^0.
|
|
231
|
-
"@types/node": "^
|
|
232
|
-
"fast-check": "^
|
|
230
|
+
"@hey-api/openapi-ts": "^0.99.0",
|
|
231
|
+
"@types/node": "^26.0.1",
|
|
232
|
+
"fast-check": "^4.8.0",
|
|
233
233
|
"prettier": "^3.8.3",
|
|
234
234
|
"tsx": "^4.22.3",
|
|
235
235
|
"typescript": "^6.0.3",
|
|
@@ -240,6 +240,7 @@
|
|
|
240
240
|
"dev": "tsc -w -p tsconfig.json",
|
|
241
241
|
"example": "node --import tsx examples/basic.ts",
|
|
242
242
|
"bench": "node --import tsx bench/router.bench.ts",
|
|
243
|
+
"bench:serverless": "node --import tsx bench/serverless-cold-path.bench.ts",
|
|
243
244
|
"test": "node --import tsx --test tests/**/*.test.ts",
|
|
244
245
|
"test:red-team": "node --import tsx --test tests/red-team-attacks.test.ts tests/red-team-attacks-2.test.ts tests/red-team-attacks-3.test.ts tests/red-team-attacks-4.test.ts tests/red-team-attacks-5.test.ts tests/red-team-attacks-6.test.ts tests/red-team-attacks-7.test.ts tests/red-team-attacks-8.test.ts tests/red-team-attacks-9.test.ts tests/red-team-attacks-10.test.ts",
|
|
245
246
|
"red-team:live": "node --import tsx red-team-live/run.ts",
|