@getstrata/core 2.0.2 → 2.0.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/CHANGELOG.md +8 -0
- package/dist/core/database/baseRepository.d.ts +2 -0
- package/dist/core/database/dialect.d.ts +4 -0
- package/dist/core/database/mysqlConnection.d.ts +12 -2
- package/dist/core/database/sqliteConnection.d.ts +2 -1
- package/dist/core/database/transaction.d.ts +2 -2
- package/dist/core/database/transactionControl.d.ts +2 -1
- package/dist/core/events/eventBus.d.ts +4 -0
- package/dist/core/events/outbox/index.d.ts +55 -0
- package/dist/core/events/outbox/migration.d.ts +7 -0
- package/dist/core/http/requestMetaContext.d.ts +2 -0
- package/dist/core/http/response.d.ts +2 -1
- package/dist/core/openapi/registeredRoute.d.ts +40 -1
- package/dist/core/security/safeFetch.d.ts +1 -0
- package/dist/entries/audit/exportAuditLogs.js +137 -17
- package/dist/entries/auth/basicAuthGuard.js +18 -0
- package/dist/entries/auth/oauth/oidcProvider.js +100 -17
- package/dist/entries/auth/oauth/providers.js +100 -17
- package/dist/entries/auth/oauth/samlProvider.js +18 -0
- package/dist/entries/auth/oneTimeToken.js +18 -0
- package/dist/entries/auth/passwordLogin.js +18 -0
- package/dist/entries/auth/saml/samlServiceProvider.js +18 -0
- package/dist/entries/auth/scimAuthMiddleware.js +37 -0
- package/dist/entries/database/migrations.js +18 -0
- package/dist/entries/database/sqliteConnection.js +101 -7
- package/dist/entries/events/outbox.js +1 -0
- package/dist/entries/http/response.js +39 -5
- package/dist/entries/jobs/exportAuditLogsJob.js +137 -17
- package/dist/entries/openapi/generator.js +42 -12
- package/dist/entries/openapi/validate.js +10 -0
- package/dist/entries/security/safeFetch.js +100 -17
- package/dist/entries/tenant/databaseTenantContext.js +37 -0
- package/dist/entries/tenant/tenantDatabaseScope.js +37 -0
- package/dist/entries/tracing/tracingMiddleware.js +100 -17
- package/dist/framework/public-api.d.ts +3 -1
- package/dist/index.js +649 -60
- package/package.json +6 -1
|
@@ -355,50 +355,133 @@ async function resolveSafeOutboundTarget(rawUrl, options = {}) {
|
|
|
355
355
|
|
|
356
356
|
// ../../src/core/security/safeFetch.ts
|
|
357
357
|
var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
|
|
358
|
+
function untilAborted(work, signal) {
|
|
359
|
+
signal.throwIfAborted();
|
|
360
|
+
return new Promise((resolve, reject) => {
|
|
361
|
+
const onAbort = () => reject(signal.reason);
|
|
362
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
363
|
+
work.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
function preserveResponseMetadata(response, original) {
|
|
367
|
+
Object.defineProperties(response, {
|
|
368
|
+
url: { value: original.url },
|
|
369
|
+
redirected: { value: original.redirected },
|
|
370
|
+
type: { value: original.type }
|
|
371
|
+
});
|
|
372
|
+
const clone = response.clone.bind(response);
|
|
373
|
+
response.clone = () => preserveResponseMetadata(clone(), original);
|
|
374
|
+
return response;
|
|
375
|
+
}
|
|
376
|
+
function withBodyDeadline(response, signal, release) {
|
|
377
|
+
if (!response.body) {
|
|
378
|
+
release();
|
|
379
|
+
return response;
|
|
380
|
+
}
|
|
381
|
+
const reader = response.body.getReader();
|
|
382
|
+
let stopped = false;
|
|
383
|
+
let bodyController;
|
|
384
|
+
const stop = (reason, errorBody) => {
|
|
385
|
+
if (stopped)
|
|
386
|
+
return;
|
|
387
|
+
stopped = true;
|
|
388
|
+
release();
|
|
389
|
+
signal.removeEventListener("abort", onAbort);
|
|
390
|
+
if (errorBody)
|
|
391
|
+
bodyController.error(reason);
|
|
392
|
+
reader.cancel(reason).catch(() => {}).finally(() => reader.releaseLock());
|
|
393
|
+
};
|
|
394
|
+
const onAbort = () => stop(signal.reason, true);
|
|
395
|
+
const body = new ReadableStream({
|
|
396
|
+
start(controller) {
|
|
397
|
+
bodyController = controller;
|
|
398
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
399
|
+
if (signal.aborted)
|
|
400
|
+
onAbort();
|
|
401
|
+
},
|
|
402
|
+
async pull(controller) {
|
|
403
|
+
try {
|
|
404
|
+
const result = await untilAborted(reader.read(), signal);
|
|
405
|
+
if (stopped)
|
|
406
|
+
return;
|
|
407
|
+
if (result.done) {
|
|
408
|
+
stopped = true;
|
|
409
|
+
release();
|
|
410
|
+
signal.removeEventListener("abort", onAbort);
|
|
411
|
+
reader.releaseLock();
|
|
412
|
+
controller.close();
|
|
413
|
+
} else {
|
|
414
|
+
controller.enqueue(result.value);
|
|
415
|
+
}
|
|
416
|
+
} catch (error) {
|
|
417
|
+
stop(error, true);
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
cancel(reason) {
|
|
421
|
+
stop(reason, false);
|
|
422
|
+
}
|
|
423
|
+
}, { highWaterMark: 0 });
|
|
424
|
+
return preserveResponseMetadata(new Response(body, {
|
|
425
|
+
status: response.status,
|
|
426
|
+
statusText: response.statusText,
|
|
427
|
+
headers: response.headers
|
|
428
|
+
}), response);
|
|
429
|
+
}
|
|
358
430
|
async function safeFetch(input, init = {}, options = {}) {
|
|
431
|
+
init.signal?.throwIfAborted();
|
|
359
432
|
const timeoutMs = options.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
|
|
433
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
434
|
+
throw new RangeError("safeFetch timeoutMs must be a positive finite number.");
|
|
435
|
+
}
|
|
360
436
|
const maxRedirects = options.maxRedirects ?? 0;
|
|
361
|
-
const resolveDns = options.resolveDns ?? true;
|
|
362
437
|
const urlOptions = {
|
|
363
438
|
allowHttp: options.allowHttp,
|
|
364
|
-
resolveDns,
|
|
439
|
+
resolveDns: options.resolveDns ?? true,
|
|
365
440
|
allowPrivate: options.allowPrivate
|
|
366
441
|
};
|
|
367
442
|
const controller = new AbortController;
|
|
368
|
-
const
|
|
443
|
+
const forwardAbort = () => controller.abort(init.signal?.reason);
|
|
444
|
+
init.signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
445
|
+
const timeout = setTimeout(() => controller.abort(new DOMException("The operation timed out.", "TimeoutError")), timeoutMs);
|
|
446
|
+
const release = () => {
|
|
447
|
+
clearTimeout(timeout);
|
|
448
|
+
init.signal?.removeEventListener("abort", forwardAbort);
|
|
449
|
+
};
|
|
369
450
|
try {
|
|
370
|
-
let current = await resolveSafeOutboundTarget(input, urlOptions);
|
|
451
|
+
let current = await untilAborted(resolveSafeOutboundTarget(input, urlOptions), controller.signal);
|
|
371
452
|
let redirectCount = 0;
|
|
372
453
|
while (true) {
|
|
454
|
+
controller.signal.throwIfAborted();
|
|
373
455
|
const address = current.addresses[0];
|
|
374
456
|
const fetchUrl = address ? pinUrlToAddress(current.url, address).toString() : current.url.toString();
|
|
375
457
|
const headers = new Headers(init.headers);
|
|
376
|
-
if (address && !headers.has("host"))
|
|
458
|
+
if (address && !headers.has("host"))
|
|
377
459
|
headers.set("Host", current.url.host);
|
|
378
|
-
}
|
|
379
460
|
const fetchInit = {
|
|
380
461
|
...init,
|
|
381
462
|
headers,
|
|
382
463
|
signal: controller.signal,
|
|
383
464
|
redirect: "manual"
|
|
384
465
|
};
|
|
385
|
-
if (address)
|
|
466
|
+
if (address)
|
|
386
467
|
fetchInit.tls = { serverName: current.url.hostname };
|
|
387
|
-
|
|
388
|
-
const response = await fetch(fetchUrl, fetchInit);
|
|
468
|
+
const response = await untilAborted(fetch(fetchUrl, fetchInit), controller.signal);
|
|
389
469
|
if (response.status >= 300 && response.status < 400) {
|
|
390
470
|
const location = response.headers.get("location");
|
|
391
|
-
if (
|
|
392
|
-
|
|
471
|
+
if (location && redirectCount < maxRedirects) {
|
|
472
|
+
if (response.body)
|
|
473
|
+
await untilAborted(response.body.cancel(), controller.signal);
|
|
474
|
+
current = await untilAborted(resolveSafeOutboundTarget(new URL(location, current.url).toString(), urlOptions), controller.signal);
|
|
475
|
+
redirectCount++;
|
|
476
|
+
continue;
|
|
393
477
|
}
|
|
394
|
-
current = await resolveSafeOutboundTarget(new URL(location, current.url).toString(), urlOptions);
|
|
395
|
-
redirectCount += 1;
|
|
396
|
-
continue;
|
|
397
478
|
}
|
|
398
|
-
return response;
|
|
479
|
+
return withBodyDeadline(response, controller.signal, release);
|
|
399
480
|
}
|
|
400
|
-
}
|
|
401
|
-
|
|
481
|
+
} catch (error) {
|
|
482
|
+
controller.abort(error);
|
|
483
|
+
release();
|
|
484
|
+
throw error;
|
|
402
485
|
}
|
|
403
486
|
}
|
|
404
487
|
|
|
@@ -64,7 +64,7 @@ export { loadSeedersFromDirectory, runSeedersFromDirectory, } from "../core/data
|
|
|
64
64
|
export type { Seeder, SeederDatabase } from "../core/database/seeders/types.ts";
|
|
65
65
|
export { createSqliteConnection } from "../core/database/sqliteConnection.ts";
|
|
66
66
|
export { defineTable } from "../core/database/table.ts";
|
|
67
|
-
export { requestTransactionRollback, runInTransaction } from "../core/database/transaction.ts";
|
|
67
|
+
export { hasActiveTransaction, requestTransactionRollback, runInTransaction, } from "../core/database/transaction.ts";
|
|
68
68
|
export type { QueryJoin, QueryJoinOn, QueryOptions, QueryOrder, QuerySelectItem, QueryWhere, } from "../core/database/types.ts";
|
|
69
69
|
export type { WhereNode } from "../core/database/whereBuilder.ts";
|
|
70
70
|
export { WhereBuilder } from "../core/database/whereBuilder.ts";
|
|
@@ -72,6 +72,8 @@ export { BadRequestError, ConflictError, ForbiddenError, HttpError, InternalServ
|
|
|
72
72
|
export type { EventListener } from "../core/events/eventBus.ts";
|
|
73
73
|
export { EventBus, eventBus, readSharedEventBus } from "../core/events/eventBus.ts";
|
|
74
74
|
export { dispatchModelEvent, modelEventName, runWithDeferredModelEvents, } from "../core/events/index.ts";
|
|
75
|
+
export type { DurableEvent, DurableListener, SqlOutboxOptions, } from "../core/events/outbox/index.ts";
|
|
76
|
+
export { createOutboxMigration, SqlOutbox } from "../core/events/outbox/index.ts";
|
|
75
77
|
export { auth, cache, config, events, log, mail, policyGate, queue, storage, } from "../core/facades/index.ts";
|
|
76
78
|
export { createBodySizeLimitMiddleware } from "../core/http/bodySizeLimitMiddleware.ts";
|
|
77
79
|
export { readClientIp, trustForwardedFor } from "../core/http/clientIp.ts";
|