@getstrata/core 0.5.15 → 0.5.17
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/http/securedRouteModelBinding.d.ts +11 -0
- package/dist/bootstrap/membershipService.d.ts +3 -0
- package/dist/bootstrap/queue/defaultJobs.d.ts +2 -0
- package/dist/core/auth/membershipService.d.ts +1 -2
- package/dist/core/http/securedRouteModelBinding.d.ts +2 -11
- package/dist/core/queue/createAppQueue.d.ts +3 -3
- package/dist/entries/cache/createCacheStore.js +376 -0
- package/dist/entries/queue/createAppQueue.js +484 -484
- package/dist/entries/queue/queueMetrics.js +881 -881
- package/dist/framework/public-api.d.ts +1 -0
- package/dist/index.js +394 -20
- package/package.json +7 -2
|
@@ -19,6 +19,7 @@ export { appendOrganizationScope, appendProjectScope, assertOrganizationReadable
|
|
|
19
19
|
export { default as MembershipService, resolveMembershipService, } from "../core/auth/membershipService.ts";
|
|
20
20
|
export { Policy, PolicyGate } from "../core/auth/policy.ts";
|
|
21
21
|
export { createScimAuthMiddleware } from "../core/auth/scimAuthMiddleware.ts";
|
|
22
|
+
export { type CacheDriver, type CreateCacheStoreOptions, createCacheStore, } from "../core/cache/createCacheStore.ts";
|
|
22
23
|
export { default as CacheRepository } from "../core/cache/repository.ts";
|
|
23
24
|
export { CACHE_TAGS } from "../core/cache/tags.ts";
|
|
24
25
|
export type { DatabaseConnection } from "../core/database/baseRepository.ts";
|
package/dist/index.js
CHANGED
|
@@ -3289,6 +3289,15 @@ function assertOrganizationReadable(organizationId) {
|
|
|
3289
3289
|
throw new NotFoundError(`Organization ${organizationId} not found.`);
|
|
3290
3290
|
}
|
|
3291
3291
|
}
|
|
3292
|
+
// ../../src/bootstrap/membershipService.ts
|
|
3293
|
+
function resolveMembershipService() {
|
|
3294
|
+
const dependencies = resolveApplicationDependencies();
|
|
3295
|
+
if (dependencies.container.has("core.membership")) {
|
|
3296
|
+
return dependencies.container.resolve("core.membership");
|
|
3297
|
+
}
|
|
3298
|
+
return new membershipService_default;
|
|
3299
|
+
}
|
|
3300
|
+
|
|
3292
3301
|
// ../../src/core/auth/membershipService.ts
|
|
3293
3302
|
class MembershipService {
|
|
3294
3303
|
members;
|
|
@@ -3343,13 +3352,6 @@ class MembershipService {
|
|
|
3343
3352
|
return this.members.removeMember(organizationId, userId);
|
|
3344
3353
|
}
|
|
3345
3354
|
}
|
|
3346
|
-
function resolveMembershipService() {
|
|
3347
|
-
const dependencies = resolveApplicationDependencies();
|
|
3348
|
-
if (dependencies.container.has("core.membership")) {
|
|
3349
|
-
return dependencies.container.resolve("core.membership");
|
|
3350
|
-
}
|
|
3351
|
-
return new MembershipService;
|
|
3352
|
-
}
|
|
3353
3355
|
var membershipService_default = MembershipService;
|
|
3354
3356
|
// ../../src/core/auth/policy.ts
|
|
3355
3357
|
class Policy {
|
|
@@ -3526,6 +3528,378 @@ function jsonScimError(detail, status) {
|
|
|
3526
3528
|
headers: { "content-type": "application/scim+json" }
|
|
3527
3529
|
});
|
|
3528
3530
|
}
|
|
3531
|
+
// ../../src/core/cache/redisCacheStore.ts
|
|
3532
|
+
var {RedisClient } = globalThis.Bun;
|
|
3533
|
+
var KEY_PREFIX = "workhub:cache:";
|
|
3534
|
+
var TAG_PREFIX = "workhub:cache:tag:";
|
|
3535
|
+
|
|
3536
|
+
class RedisCacheStore {
|
|
3537
|
+
ttlMs;
|
|
3538
|
+
maxEntries;
|
|
3539
|
+
client;
|
|
3540
|
+
inflight = new Map;
|
|
3541
|
+
keyTags = new Map;
|
|
3542
|
+
constructor(redisUrl, ttlMs, maxEntries) {
|
|
3543
|
+
this.ttlMs = ttlMs;
|
|
3544
|
+
this.maxEntries = maxEntries;
|
|
3545
|
+
this.client = new RedisClient(redisUrl);
|
|
3546
|
+
}
|
|
3547
|
+
async get(key) {
|
|
3548
|
+
const raw = await this.client.get(this.storageKey(key));
|
|
3549
|
+
if (raw === null) {
|
|
3550
|
+
return;
|
|
3551
|
+
}
|
|
3552
|
+
return JSON.parse(raw);
|
|
3553
|
+
}
|
|
3554
|
+
async set(key, value, ttlMs) {
|
|
3555
|
+
const resolvedTtlMs = ttlMs ?? this.ttlMs;
|
|
3556
|
+
const payload = JSON.stringify(value);
|
|
3557
|
+
if (resolvedTtlMs > 0) {
|
|
3558
|
+
await this.client.psetex(this.storageKey(key), resolvedTtlMs, payload);
|
|
3559
|
+
} else {
|
|
3560
|
+
await this.client.set(this.storageKey(key), payload);
|
|
3561
|
+
}
|
|
3562
|
+
await this.enforceMaxEntries();
|
|
3563
|
+
}
|
|
3564
|
+
async getOrSet(key, loader, ttlMs) {
|
|
3565
|
+
const cached = await this.get(key);
|
|
3566
|
+
if (cached !== undefined) {
|
|
3567
|
+
return cached;
|
|
3568
|
+
}
|
|
3569
|
+
const inflightRequest = this.inflight.get(key);
|
|
3570
|
+
if (inflightRequest) {
|
|
3571
|
+
return inflightRequest;
|
|
3572
|
+
}
|
|
3573
|
+
const pendingRequest = loader().then(async (value) => {
|
|
3574
|
+
await this.set(key, value, ttlMs);
|
|
3575
|
+
return value;
|
|
3576
|
+
}).finally(() => {
|
|
3577
|
+
this.inflight.delete(key);
|
|
3578
|
+
});
|
|
3579
|
+
this.inflight.set(key, pendingRequest);
|
|
3580
|
+
return pendingRequest;
|
|
3581
|
+
}
|
|
3582
|
+
async attachTags(key, tags) {
|
|
3583
|
+
if (tags.length === 0) {
|
|
3584
|
+
return;
|
|
3585
|
+
}
|
|
3586
|
+
let tagsForKey = this.keyTags.get(key);
|
|
3587
|
+
if (!tagsForKey) {
|
|
3588
|
+
tagsForKey = new Set;
|
|
3589
|
+
this.keyTags.set(key, tagsForKey);
|
|
3590
|
+
}
|
|
3591
|
+
for (const tag of tags) {
|
|
3592
|
+
tagsForKey.add(tag);
|
|
3593
|
+
await this.client.sadd(this.tagKey(tag), key);
|
|
3594
|
+
}
|
|
3595
|
+
}
|
|
3596
|
+
async flushTags(tags) {
|
|
3597
|
+
const keysToRemove = new Set;
|
|
3598
|
+
for (const tag of tags) {
|
|
3599
|
+
const members = await this.client.smembers(this.tagKey(tag));
|
|
3600
|
+
for (const member of members) {
|
|
3601
|
+
keysToRemove.add(member);
|
|
3602
|
+
}
|
|
3603
|
+
}
|
|
3604
|
+
let removed = 0;
|
|
3605
|
+
for (const key of keysToRemove) {
|
|
3606
|
+
if (await this.invalidate(key)) {
|
|
3607
|
+
removed += 1;
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
for (const tag of tags) {
|
|
3611
|
+
await this.client.del(this.tagKey(tag));
|
|
3612
|
+
}
|
|
3613
|
+
return removed;
|
|
3614
|
+
}
|
|
3615
|
+
async invalidate(key) {
|
|
3616
|
+
const deleted = await this.client.del(this.storageKey(key));
|
|
3617
|
+
await this.detachKeyFromTags(key);
|
|
3618
|
+
return deleted > 0;
|
|
3619
|
+
}
|
|
3620
|
+
async invalidateByPrefix(prefix) {
|
|
3621
|
+
const keys = await this.client.keys(`${KEY_PREFIX}*`);
|
|
3622
|
+
let removed = 0;
|
|
3623
|
+
for (const storageKey of keys) {
|
|
3624
|
+
const key = storageKey.slice(KEY_PREFIX.length);
|
|
3625
|
+
if (key === prefix || key.startsWith(`${prefix}?`)) {
|
|
3626
|
+
if (await this.invalidate(key)) {
|
|
3627
|
+
removed += 1;
|
|
3628
|
+
}
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
return removed;
|
|
3632
|
+
}
|
|
3633
|
+
async clear() {
|
|
3634
|
+
const keys = await this.client.keys(`${KEY_PREFIX}*`);
|
|
3635
|
+
if (keys.length > 0) {
|
|
3636
|
+
await this.client.del(...keys);
|
|
3637
|
+
}
|
|
3638
|
+
const tagKeys = await this.client.keys(`${TAG_PREFIX}*`);
|
|
3639
|
+
if (tagKeys.length > 0) {
|
|
3640
|
+
await this.client.del(...tagKeys);
|
|
3641
|
+
}
|
|
3642
|
+
this.inflight.clear();
|
|
3643
|
+
this.keyTags.clear();
|
|
3644
|
+
}
|
|
3645
|
+
async size() {
|
|
3646
|
+
const keys = await this.client.keys(`${KEY_PREFIX}*`);
|
|
3647
|
+
return keys.length;
|
|
3648
|
+
}
|
|
3649
|
+
storageKey(key) {
|
|
3650
|
+
return `${KEY_PREFIX}${key}`;
|
|
3651
|
+
}
|
|
3652
|
+
tagKey(tag) {
|
|
3653
|
+
return `${TAG_PREFIX}${tag}`;
|
|
3654
|
+
}
|
|
3655
|
+
async detachKeyFromTags(key) {
|
|
3656
|
+
const tags = this.keyTags.get(key);
|
|
3657
|
+
if (!tags) {
|
|
3658
|
+
return;
|
|
3659
|
+
}
|
|
3660
|
+
for (const tag of tags) {
|
|
3661
|
+
await this.client.srem(this.tagKey(tag), key);
|
|
3662
|
+
}
|
|
3663
|
+
this.keyTags.delete(key);
|
|
3664
|
+
}
|
|
3665
|
+
async enforceMaxEntries() {
|
|
3666
|
+
const keys = await this.client.keys(`${KEY_PREFIX}*`);
|
|
3667
|
+
if (keys.length <= this.maxEntries) {
|
|
3668
|
+
return;
|
|
3669
|
+
}
|
|
3670
|
+
const overflow = keys.length - this.maxEntries;
|
|
3671
|
+
const keysToRemove = keys.slice(0, overflow);
|
|
3672
|
+
if (keysToRemove.length > 0) {
|
|
3673
|
+
await this.client.del(...keysToRemove);
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
var redisCacheStore_default = RedisCacheStore;
|
|
3678
|
+
|
|
3679
|
+
// ../../src/core/cache/simpleCache.ts
|
|
3680
|
+
class SimpleCache {
|
|
3681
|
+
ttlMs;
|
|
3682
|
+
maxEntries;
|
|
3683
|
+
cache = new Map;
|
|
3684
|
+
inflight = new Map;
|
|
3685
|
+
tagIndex = new Map;
|
|
3686
|
+
keyTags = new Map;
|
|
3687
|
+
constructor(ttlMs = 3600000, maxEntries = 100) {
|
|
3688
|
+
this.ttlMs = ttlMs;
|
|
3689
|
+
this.maxEntries = maxEntries;
|
|
3690
|
+
if (!Number.isFinite(ttlMs) || ttlMs < 0) {
|
|
3691
|
+
throw new RangeError("ttlMs must be a non-negative number.");
|
|
3692
|
+
}
|
|
3693
|
+
if (!Number.isInteger(maxEntries) || maxEntries < 1) {
|
|
3694
|
+
throw new RangeError("maxEntries must be a positive integer.");
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
get(key) {
|
|
3698
|
+
return this.getFreshEntry(key)?.value;
|
|
3699
|
+
}
|
|
3700
|
+
set(key, value, ttlMs) {
|
|
3701
|
+
const now = Date.now();
|
|
3702
|
+
const resolvedTtlMs = ttlMs ?? this.ttlMs;
|
|
3703
|
+
this.cache.set(key, {
|
|
3704
|
+
value,
|
|
3705
|
+
expiresAt: now + resolvedTtlMs,
|
|
3706
|
+
lastAccessedAt: now
|
|
3707
|
+
});
|
|
3708
|
+
this.evictOverflow();
|
|
3709
|
+
}
|
|
3710
|
+
async getOrSet(key, loader, ttlMs) {
|
|
3711
|
+
this.pruneExpired();
|
|
3712
|
+
const cachedEntry = this.getFreshEntry(key);
|
|
3713
|
+
if (cachedEntry) {
|
|
3714
|
+
return cachedEntry.value;
|
|
3715
|
+
}
|
|
3716
|
+
const inflightRequest = this.inflight.get(key);
|
|
3717
|
+
if (inflightRequest) {
|
|
3718
|
+
return inflightRequest;
|
|
3719
|
+
}
|
|
3720
|
+
const pendingRequest = loader().then((value) => {
|
|
3721
|
+
this.set(key, value, ttlMs);
|
|
3722
|
+
return value;
|
|
3723
|
+
}).finally(() => {
|
|
3724
|
+
this.inflight.delete(key);
|
|
3725
|
+
});
|
|
3726
|
+
this.inflight.set(key, pendingRequest);
|
|
3727
|
+
return pendingRequest;
|
|
3728
|
+
}
|
|
3729
|
+
attachTags(key, tags) {
|
|
3730
|
+
if (tags.length === 0) {
|
|
3731
|
+
return;
|
|
3732
|
+
}
|
|
3733
|
+
let tagsForKey = this.keyTags.get(key);
|
|
3734
|
+
if (!tagsForKey) {
|
|
3735
|
+
tagsForKey = new Set;
|
|
3736
|
+
this.keyTags.set(key, tagsForKey);
|
|
3737
|
+
}
|
|
3738
|
+
for (const tag of tags) {
|
|
3739
|
+
tagsForKey.add(tag);
|
|
3740
|
+
let keysForTag = this.tagIndex.get(tag);
|
|
3741
|
+
if (!keysForTag) {
|
|
3742
|
+
keysForTag = new Set;
|
|
3743
|
+
this.tagIndex.set(tag, keysForTag);
|
|
3744
|
+
}
|
|
3745
|
+
keysForTag.add(key);
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
flushTags(tags) {
|
|
3749
|
+
const keysToRemove = new Set;
|
|
3750
|
+
for (const tag of tags) {
|
|
3751
|
+
const keys = this.tagIndex.get(tag);
|
|
3752
|
+
if (!keys) {
|
|
3753
|
+
continue;
|
|
3754
|
+
}
|
|
3755
|
+
for (const key of keys) {
|
|
3756
|
+
keysToRemove.add(key);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
let removed = 0;
|
|
3760
|
+
for (const key of keysToRemove) {
|
|
3761
|
+
if (this.invalidate(key)) {
|
|
3762
|
+
removed += 1;
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3765
|
+
for (const tag of tags) {
|
|
3766
|
+
this.tagIndex.delete(tag);
|
|
3767
|
+
}
|
|
3768
|
+
return removed;
|
|
3769
|
+
}
|
|
3770
|
+
invalidate(key) {
|
|
3771
|
+
const removed = this.cache.delete(key);
|
|
3772
|
+
if (removed) {
|
|
3773
|
+
this.detachKeyFromTags(key);
|
|
3774
|
+
}
|
|
3775
|
+
return removed;
|
|
3776
|
+
}
|
|
3777
|
+
invalidateByPrefix(prefix) {
|
|
3778
|
+
let removed = 0;
|
|
3779
|
+
for (const key of [...this.cache.keys()]) {
|
|
3780
|
+
if (key === prefix || key.startsWith(`${prefix}?`)) {
|
|
3781
|
+
if (this.invalidate(key)) {
|
|
3782
|
+
removed += 1;
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
return removed;
|
|
3787
|
+
}
|
|
3788
|
+
clear() {
|
|
3789
|
+
this.cache.clear();
|
|
3790
|
+
this.inflight.clear();
|
|
3791
|
+
this.tagIndex.clear();
|
|
3792
|
+
this.keyTags.clear();
|
|
3793
|
+
}
|
|
3794
|
+
size() {
|
|
3795
|
+
this.pruneExpired();
|
|
3796
|
+
return this.cache.size;
|
|
3797
|
+
}
|
|
3798
|
+
detachKeyFromTags(key) {
|
|
3799
|
+
const tags = this.keyTags.get(key);
|
|
3800
|
+
if (!tags) {
|
|
3801
|
+
return;
|
|
3802
|
+
}
|
|
3803
|
+
for (const tag of tags) {
|
|
3804
|
+
const keys = this.tagIndex.get(tag);
|
|
3805
|
+
if (!keys) {
|
|
3806
|
+
continue;
|
|
3807
|
+
}
|
|
3808
|
+
keys.delete(key);
|
|
3809
|
+
if (keys.size === 0) {
|
|
3810
|
+
this.tagIndex.delete(tag);
|
|
3811
|
+
}
|
|
3812
|
+
}
|
|
3813
|
+
this.keyTags.delete(key);
|
|
3814
|
+
}
|
|
3815
|
+
getFreshEntry(key) {
|
|
3816
|
+
const entry = this.cache.get(key);
|
|
3817
|
+
if (!entry) {
|
|
3818
|
+
return;
|
|
3819
|
+
}
|
|
3820
|
+
if (entry.expiresAt <= Date.now()) {
|
|
3821
|
+
this.invalidate(key);
|
|
3822
|
+
return;
|
|
3823
|
+
}
|
|
3824
|
+
entry.lastAccessedAt = Date.now();
|
|
3825
|
+
return entry;
|
|
3826
|
+
}
|
|
3827
|
+
pruneExpired() {
|
|
3828
|
+
const now = Date.now();
|
|
3829
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
3830
|
+
if (entry.expiresAt <= now) {
|
|
3831
|
+
this.invalidate(key);
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
evictOverflow() {
|
|
3836
|
+
while (this.cache.size > this.maxEntries) {
|
|
3837
|
+
let oldestKey;
|
|
3838
|
+
let oldestAccessTime = Number.POSITIVE_INFINITY;
|
|
3839
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
3840
|
+
if (entry.lastAccessedAt < oldestAccessTime) {
|
|
3841
|
+
oldestAccessTime = entry.lastAccessedAt;
|
|
3842
|
+
oldestKey = key;
|
|
3843
|
+
}
|
|
3844
|
+
}
|
|
3845
|
+
if (!oldestKey) {
|
|
3846
|
+
return;
|
|
3847
|
+
}
|
|
3848
|
+
this.invalidate(oldestKey);
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
var simpleCache_default = SimpleCache;
|
|
3853
|
+
|
|
3854
|
+
// ../../src/core/cache/simpleCacheStore.ts
|
|
3855
|
+
class SimpleCacheStore {
|
|
3856
|
+
cache;
|
|
3857
|
+
constructor(cache) {
|
|
3858
|
+
this.cache = cache;
|
|
3859
|
+
}
|
|
3860
|
+
get(key) {
|
|
3861
|
+
return Promise.resolve(this.cache.get(key));
|
|
3862
|
+
}
|
|
3863
|
+
set(key, value, ttlMs) {
|
|
3864
|
+
this.cache.set(key, value, ttlMs);
|
|
3865
|
+
return Promise.resolve();
|
|
3866
|
+
}
|
|
3867
|
+
getOrSet(key, loader, ttlMs) {
|
|
3868
|
+
return this.cache.getOrSet(key, loader, ttlMs);
|
|
3869
|
+
}
|
|
3870
|
+
attachTags(key, tags) {
|
|
3871
|
+
this.cache.attachTags(key, tags);
|
|
3872
|
+
return Promise.resolve();
|
|
3873
|
+
}
|
|
3874
|
+
flushTags(tags) {
|
|
3875
|
+
return Promise.resolve(this.cache.flushTags(tags));
|
|
3876
|
+
}
|
|
3877
|
+
invalidate(key) {
|
|
3878
|
+
return Promise.resolve(this.cache.invalidate(key));
|
|
3879
|
+
}
|
|
3880
|
+
invalidateByPrefix(prefix) {
|
|
3881
|
+
return Promise.resolve(this.cache.invalidateByPrefix(prefix));
|
|
3882
|
+
}
|
|
3883
|
+
clear() {
|
|
3884
|
+
this.cache.clear();
|
|
3885
|
+
return Promise.resolve();
|
|
3886
|
+
}
|
|
3887
|
+
size() {
|
|
3888
|
+
return Promise.resolve(this.cache.size());
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3891
|
+
var simpleCacheStore_default = SimpleCacheStore;
|
|
3892
|
+
|
|
3893
|
+
// ../../src/core/cache/createCacheStore.ts
|
|
3894
|
+
function createCacheStore(options) {
|
|
3895
|
+
if (options.driver === "redis") {
|
|
3896
|
+
if (!options.redisUrl) {
|
|
3897
|
+
throw new Error('CACHE_DRIVER="redis" requires REDIS_URL to be set.');
|
|
3898
|
+
}
|
|
3899
|
+
return new redisCacheStore_default(options.redisUrl, options.ttlMs, options.maxEntries);
|
|
3900
|
+
}
|
|
3901
|
+
return new simpleCacheStore_default(new simpleCache_default(options.ttlMs, options.maxEntries));
|
|
3902
|
+
}
|
|
3529
3903
|
// ../../src/core/cache/taggedCache.ts
|
|
3530
3904
|
class TaggedCache {
|
|
3531
3905
|
store;
|
|
@@ -4894,7 +5268,7 @@ function bindRouteModel(param, resolver, handler) {
|
|
|
4894
5268
|
return await handler(request, model);
|
|
4895
5269
|
};
|
|
4896
5270
|
}
|
|
4897
|
-
// ../../src/
|
|
5271
|
+
// ../../src/bootstrap/http/securedRouteModelBinding.ts
|
|
4898
5272
|
function isMutatingPolicyAction(action) {
|
|
4899
5273
|
return action === "update" || action === "delete";
|
|
4900
5274
|
}
|
|
@@ -5050,7 +5424,7 @@ function withErrorHandling(handler) {
|
|
|
5050
5424
|
};
|
|
5051
5425
|
}
|
|
5052
5426
|
// ../../src/core/http/loginThrottleMiddleware.ts
|
|
5053
|
-
var {RedisClient } = globalThis.Bun;
|
|
5427
|
+
var {RedisClient: RedisClient2 } = globalThis.Bun;
|
|
5054
5428
|
function resolveLoginIdentity(request) {
|
|
5055
5429
|
return request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "unknown";
|
|
5056
5430
|
}
|
|
@@ -5069,7 +5443,7 @@ async function resolveLoginEmail(request) {
|
|
|
5069
5443
|
}
|
|
5070
5444
|
}
|
|
5071
5445
|
function createLoginThrottleMiddleware(options) {
|
|
5072
|
-
const client = new
|
|
5446
|
+
const client = new RedisClient2(options.redisUrl);
|
|
5073
5447
|
const prefix = options.keyPrefix ?? "workhub:login-throttle:";
|
|
5074
5448
|
return async (request, next) => {
|
|
5075
5449
|
const identity = resolveLoginIdentity(request);
|
|
@@ -5249,9 +5623,9 @@ function createRequireWebAuthMiddleware(auth2) {
|
|
|
5249
5623
|
};
|
|
5250
5624
|
}
|
|
5251
5625
|
// ../../src/core/http/scimThrottleMiddleware.ts
|
|
5252
|
-
var {RedisClient:
|
|
5626
|
+
var {RedisClient: RedisClient3 } = globalThis.Bun;
|
|
5253
5627
|
function createScimThrottleMiddleware(options) {
|
|
5254
|
-
const client = options.redisUrl ? new
|
|
5628
|
+
const client = options.redisUrl ? new RedisClient3(options.redisUrl) : null;
|
|
5255
5629
|
return async (request, next) => {
|
|
5256
5630
|
const identity = request.headers.get("authorization")?.slice("Bearer ".length, "Bearer ".length + 16) ?? request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "unknown";
|
|
5257
5631
|
const key = `workhub:scim-throttle:${identity}`;
|
|
@@ -5341,7 +5715,7 @@ function createSecurityHeadersMiddleware() {
|
|
|
5341
5715
|
};
|
|
5342
5716
|
}
|
|
5343
5717
|
// ../../src/core/http/throttleMiddleware.ts
|
|
5344
|
-
var {RedisClient:
|
|
5718
|
+
var {RedisClient: RedisClient4 } = globalThis.Bun;
|
|
5345
5719
|
function resolveThrottleIdentity(request) {
|
|
5346
5720
|
const user = currentAuthUser();
|
|
5347
5721
|
if (user?.tokenId !== undefined) {
|
|
@@ -5353,7 +5727,7 @@ function resolveThrottleIdentity(request) {
|
|
|
5353
5727
|
return request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "unknown";
|
|
5354
5728
|
}
|
|
5355
5729
|
function createThrottleMiddleware(options) {
|
|
5356
|
-
const client = new
|
|
5730
|
+
const client = new RedisClient4(options.redisUrl);
|
|
5357
5731
|
const prefix = options.keyPrefix ?? "workhub:throttle:";
|
|
5358
5732
|
return async (request, next) => {
|
|
5359
5733
|
const identity = resolveThrottleIdentity(request);
|
|
@@ -5772,7 +6146,7 @@ async function runQueueJob(envelope, failedJobs) {
|
|
|
5772
6146
|
}
|
|
5773
6147
|
|
|
5774
6148
|
// ../../src/core/queue/redisQueue.ts
|
|
5775
|
-
var {RedisClient:
|
|
6149
|
+
var {RedisClient: RedisClient5 } = globalThis.Bun;
|
|
5776
6150
|
var QUEUE_LIST_KEY = "workhub:queue:default";
|
|
5777
6151
|
var QUEUE_HIGH_KEY = "workhub:queue:high";
|
|
5778
6152
|
var QUEUE_LOW_KEY = "workhub:queue:low";
|
|
@@ -5822,7 +6196,7 @@ function parseQueueJobEnvelope(rawPayload) {
|
|
|
5822
6196
|
class RedisQueue {
|
|
5823
6197
|
client;
|
|
5824
6198
|
constructor(redisUrl) {
|
|
5825
|
-
this.client = new
|
|
6199
|
+
this.client = new RedisClient5(redisUrl);
|
|
5826
6200
|
}
|
|
5827
6201
|
async dispatch(job, payload) {
|
|
5828
6202
|
const name = jobRegistry.resolveName(job);
|
|
@@ -5848,7 +6222,7 @@ class QueueWorker {
|
|
|
5848
6222
|
constructor(redisUrl, failedJobs, timeoutSeconds = 5) {
|
|
5849
6223
|
this.failedJobs = failedJobs;
|
|
5850
6224
|
this.timeoutSeconds = timeoutSeconds;
|
|
5851
|
-
this.client = new
|
|
6225
|
+
this.client = new RedisClient5(redisUrl);
|
|
5852
6226
|
}
|
|
5853
6227
|
requestStop() {
|
|
5854
6228
|
this.stopping = true;
|
|
@@ -5946,7 +6320,7 @@ function createQueueWorker(redisUrl, failedJobs = createFailedJobService()) {
|
|
|
5946
6320
|
return new QueueWorker(redisUrl, failedJobs);
|
|
5947
6321
|
}
|
|
5948
6322
|
// ../../src/core/queue/queueMetrics.ts
|
|
5949
|
-
var {RedisClient:
|
|
6323
|
+
var {RedisClient: RedisClient6 } = globalThis.Bun;
|
|
5950
6324
|
|
|
5951
6325
|
// ../../src/core/security/safeUrl.ts
|
|
5952
6326
|
var BLOCKED_HOSTNAMES = new Set([
|
|
@@ -5956,10 +6330,9 @@ var BLOCKED_HOSTNAMES = new Set([
|
|
|
5956
6330
|
"::1",
|
|
5957
6331
|
"metadata.google.internal"
|
|
5958
6332
|
]);
|
|
5959
|
-
|
|
5960
6333
|
// ../../src/core/queue/queueMetrics.ts
|
|
5961
6334
|
async function readRedisQueueDepth(redisUrl) {
|
|
5962
|
-
const client = new
|
|
6335
|
+
const client = new RedisClient6(redisUrl);
|
|
5963
6336
|
const [high, defaultQueue, low] = await Promise.all([
|
|
5964
6337
|
client.llen(QUEUE_HIGH_KEY),
|
|
5965
6338
|
client.llen(QUEUE_LIST_KEY),
|
|
@@ -6452,6 +6825,7 @@ export {
|
|
|
6452
6825
|
createCsrfProtection,
|
|
6453
6826
|
createCsrfMiddleware,
|
|
6454
6827
|
createCorsMiddleware,
|
|
6828
|
+
createCacheStore,
|
|
6455
6829
|
createBodySizeLimitMiddleware,
|
|
6456
6830
|
createAuthorizeMiddleware,
|
|
6457
6831
|
createAuthMiddleware,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getstrata/core",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.17",
|
|
4
4
|
"description": "Strata — Laravel-inspired Bun framework public API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -90,6 +90,11 @@
|
|
|
90
90
|
"import": "./dist/entries/cache/tags.js",
|
|
91
91
|
"default": "./dist/entries/cache/tags.js"
|
|
92
92
|
},
|
|
93
|
+
"./cache/createCacheStore": {
|
|
94
|
+
"types": "./dist/core/cache/createCacheStore.d.ts",
|
|
95
|
+
"import": "./dist/entries/cache/createCacheStore.js",
|
|
96
|
+
"default": "./dist/entries/cache/createCacheStore.js"
|
|
97
|
+
},
|
|
93
98
|
"./crypto/fieldEncryption": {
|
|
94
99
|
"types": "./dist/core/crypto/fieldEncryption.d.ts",
|
|
95
100
|
"import": "./dist/entries/crypto/fieldEncryption.js",
|
|
@@ -312,7 +317,7 @@
|
|
|
312
317
|
"build:bundle": "bun build index.ts --outdir dist --target bun --external bun --external eta",
|
|
313
318
|
"build:types": "tsc -p tsconfig.types.json",
|
|
314
319
|
"prepublishOnly": "bun run build && bun ../../scripts/prepare-core-package-publish.ts",
|
|
315
|
-
"build:subpaths": "bun build entries/auth/oauth/oidcProvider.ts entries/auth/oauth/providers.ts entries/auth/oauth/samlProvider.ts entries/auth/oauth/types.ts entries/auth/password.ts entries/auth/sessionCookie.ts entries/auth/tokenHash.ts entries/cache/tags.ts entries/crypto/fieldEncryption.ts entries/crypto/mfaSecret.ts entries/database/factory.ts entries/database/seeders.ts entries/database/types.ts entries/errors/http.ts entries/http/contentNegotiation.ts entries/http/csrfToken.ts entries/http/etag.ts entries/http/flashSession.ts entries/http/parseFormBody.ts entries/http/resources.ts entries/http/webErrorResponse.ts entries/http/webFormRequest.ts entries/jobs/dispatchWebhookJob.ts entries/lifecycle/gracefulShutdown.ts entries/metrics/prometheus.ts entries/pagination.ts entries/queue/createAppQueue.ts entries/queue/failedJobService.ts entries/queue/jobRegistry.ts entries/queue/jobRunner.ts entries/queue/queueMetrics.ts entries/queue/publicQueue.ts entries/queue/types.ts entries/security/oauthState.ts entries/security/publicReads.ts entries/security/safeUrl.ts entries/security/stripeWebhook.ts entries/security/tokenExpiry.ts entries/security/totp.ts entries/storage/storage.ts entries/validation/rules.ts entries/view.ts --outdir dist --root . --target bun --external bun --external eta",
|
|
320
|
+
"build:subpaths": "bun build entries/auth/oauth/oidcProvider.ts entries/auth/oauth/providers.ts entries/auth/oauth/samlProvider.ts entries/auth/oauth/types.ts entries/auth/password.ts entries/auth/sessionCookie.ts entries/auth/tokenHash.ts entries/cache/tags.ts entries/cache/createCacheStore.ts entries/crypto/fieldEncryption.ts entries/crypto/mfaSecret.ts entries/database/factory.ts entries/database/seeders.ts entries/database/types.ts entries/errors/http.ts entries/http/contentNegotiation.ts entries/http/csrfToken.ts entries/http/etag.ts entries/http/flashSession.ts entries/http/parseFormBody.ts entries/http/resources.ts entries/http/webErrorResponse.ts entries/http/webFormRequest.ts entries/jobs/dispatchWebhookJob.ts entries/lifecycle/gracefulShutdown.ts entries/metrics/prometheus.ts entries/pagination.ts entries/queue/createAppQueue.ts entries/queue/failedJobService.ts entries/queue/jobRegistry.ts entries/queue/jobRunner.ts entries/queue/queueMetrics.ts entries/queue/publicQueue.ts entries/queue/types.ts entries/security/oauthState.ts entries/security/publicReads.ts entries/security/safeUrl.ts entries/security/stripeWebhook.ts entries/security/tokenExpiry.ts entries/security/totp.ts entries/storage/storage.ts entries/validation/rules.ts entries/view.ts --outdir dist --root . --target bun --external bun --external eta",
|
|
316
321
|
"build:shims": "bun ../../scripts/write-core-shared-shims.ts"
|
|
317
322
|
},
|
|
318
323
|
"publishConfig": {
|