@getstrata/core 0.5.5 → 0.5.7
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 +3 -0
- package/dist/bootstrap/discoverModules.d.ts +4 -0
- package/dist/bootstrap/modules.d.ts +1 -0
- package/dist/bootstrap/routeRegistry.d.ts +14 -0
- package/dist/core/audit/exportAuditLogs.d.ts +8 -0
- package/dist/core/audit/siemFormatter.d.ts +30 -0
- package/dist/core/auth/membershipScope.d.ts +16 -0
- package/dist/core/auth/membershipService.d.ts +20 -0
- package/dist/core/auth/scimAuthMiddleware.d.ts +3 -0
- package/dist/core/auth/sessionCookie.d.ts +6 -0
- package/dist/core/auth/sessionGuard.d.ts +9 -0
- package/dist/core/cache/createCacheStore.d.ts +11 -0
- package/dist/core/cache/keys.d.ts +2 -0
- package/dist/core/cache/modelCacheTags.d.ts +3 -0
- package/dist/core/cache/redisCacheStore.d.ts +23 -0
- package/dist/core/cache/simpleCache.d.ts +23 -0
- package/dist/core/cache/simpleCacheStore.d.ts +16 -0
- package/dist/core/config/envSchema.d.ts +12 -0
- package/dist/core/crypto/nonCryptographicHash.d.ts +2 -0
- package/dist/core/database/factory.d.ts +6 -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/jobs/dispatchWebhookJob.d.ts +14 -0
- package/dist/core/jobs/invalidateCacheTagsJob.d.ts +12 -0
- package/dist/core/openapi/generator.d.ts +22 -0
- package/dist/core/openapi/validate.d.ts +3 -0
- package/dist/core/queue/createAppQueue.d.ts +6 -0
- package/dist/core/queue/queueMetrics.d.ts +15 -0
- package/dist/core/security/oauthState.d.ts +8 -0
- package/dist/core/security/safeFetch.d.ts +8 -0
- package/dist/core/security/safeUrl.d.ts +5 -0
- package/dist/core/security/scimTenantTokens.d.ts +3 -0
- package/dist/core/security/stripeWebhook.d.ts +2 -0
- package/dist/core/security/timingSafeCompare.d.ts +2 -0
- package/dist/domain/scim.d.ts +9 -0
- package/dist/entries/auth/guard.js +20 -20
- package/dist/entries/database.js +20 -20
- package/dist/entries/http/csrfToken.js +49 -65
- package/dist/entries/http/etag.js +6 -4
- package/dist/entries/http/webErrorResponse.js +73 -87
- package/dist/entries/http.js +80 -90
- package/dist/entries/queue/createAppQueue.js +20 -20
- package/dist/entries/queue/publicQueue.js +20 -20
- package/dist/entries/queue/queueMetrics.js +20 -20
- package/dist/entries/view.js +73 -87
- package/dist/framework/public-api.d.ts +4 -0
- package/dist/index.js +121 -107
- package/package.json +61 -58
package/dist/entries/http.js
CHANGED
|
@@ -1577,26 +1577,26 @@ class Model {
|
|
|
1577
1577
|
throw new Error(`${this.constructor.name}.primaryKey() is not implemented.`);
|
|
1578
1578
|
}
|
|
1579
1579
|
static primaryKeyField() {
|
|
1580
|
-
return resolveModelRepository(
|
|
1580
|
+
return resolveModelRepository(Model).getTable().primaryKey;
|
|
1581
1581
|
}
|
|
1582
1582
|
static hydrateAttributes(attributes) {
|
|
1583
|
-
const casts = modelStatics(
|
|
1583
|
+
const casts = modelStatics(Model).$casts ?? {};
|
|
1584
1584
|
return applyCasts(attributes, casts, "hydrate");
|
|
1585
1585
|
}
|
|
1586
1586
|
static dehydrateAttributes(attributes) {
|
|
1587
|
-
const casts = modelStatics(
|
|
1587
|
+
const casts = modelStatics(Model).$casts ?? {};
|
|
1588
1588
|
return applyCasts(attributes, casts, "dehydrate");
|
|
1589
1589
|
}
|
|
1590
1590
|
static fromRecord(record, repository, exists = true) {
|
|
1591
|
-
const statics = modelStatics(
|
|
1591
|
+
const statics = modelStatics(Model);
|
|
1592
1592
|
const hydrated = statics.hydrateAttributes(record);
|
|
1593
1593
|
return new statics(hydrated, repository, exists);
|
|
1594
1594
|
}
|
|
1595
1595
|
static boot() {}
|
|
1596
1596
|
static addGlobalScope(_name, scope) {
|
|
1597
|
-
ensureBooted(
|
|
1598
|
-
const existing = modelGlobalScopes.get(
|
|
1599
|
-
modelGlobalScopes.set(
|
|
1597
|
+
ensureBooted(Model);
|
|
1598
|
+
const existing = modelGlobalScopes.get(Model) ?? [];
|
|
1599
|
+
modelGlobalScopes.set(Model, [
|
|
1600
1600
|
...existing,
|
|
1601
1601
|
scope
|
|
1602
1602
|
]);
|
|
@@ -1606,17 +1606,17 @@ class Model {
|
|
|
1606
1606
|
}
|
|
1607
1607
|
static query() {
|
|
1608
1608
|
ensureBooted(this);
|
|
1609
|
-
const repository = resolveModelRepository(
|
|
1609
|
+
const repository = resolveModelRepository(Model);
|
|
1610
1610
|
let query = repository.query();
|
|
1611
|
-
for (const scope of getGlobalScopes(
|
|
1611
|
+
for (const scope of getGlobalScopes(Model)) {
|
|
1612
1612
|
query = scope(query);
|
|
1613
1613
|
}
|
|
1614
1614
|
return query;
|
|
1615
1615
|
}
|
|
1616
1616
|
static async create(attributes) {
|
|
1617
1617
|
const statics = modelStatics(this);
|
|
1618
|
-
ensureBooted(
|
|
1619
|
-
const repository = resolveModelRepository(
|
|
1618
|
+
ensureBooted(Model);
|
|
1619
|
+
const repository = resolveModelRepository(Model);
|
|
1620
1620
|
const table = repository.getTable();
|
|
1621
1621
|
const timestamps = statics.$timestamps ?? true;
|
|
1622
1622
|
const assignable = filterMassAssignable(statics.$fillable, statics.$guarded, attributes);
|
|
@@ -1626,23 +1626,23 @@ class Model {
|
|
|
1626
1626
|
return statics.fromRecord(record, repository, true);
|
|
1627
1627
|
}
|
|
1628
1628
|
static async find(id) {
|
|
1629
|
-
const statics = modelStatics(
|
|
1630
|
-
const repository = resolveModelRepository(
|
|
1629
|
+
const statics = modelStatics(Model);
|
|
1630
|
+
const repository = resolveModelRepository(Model);
|
|
1631
1631
|
const primaryKey = repository.getTable().primaryKey;
|
|
1632
|
-
const record = await Model.query.call(
|
|
1632
|
+
const record = await Model.query.call(Model).where({ [primaryKey]: id }).first();
|
|
1633
1633
|
return record ? statics.fromRecord(record, repository, true) : null;
|
|
1634
1634
|
}
|
|
1635
1635
|
static async findOrFail(id, errorFactory) {
|
|
1636
|
-
const model = await Model.find.call(
|
|
1636
|
+
const model = await Model.find.call(Model, id);
|
|
1637
1637
|
if (model) {
|
|
1638
1638
|
return model;
|
|
1639
1639
|
}
|
|
1640
|
-
throw errorFactory?.(id) ?? new NotFoundError(`${
|
|
1640
|
+
throw errorFactory?.(id) ?? new NotFoundError(`${Model.name} ${String(id)} not found.`);
|
|
1641
1641
|
}
|
|
1642
1642
|
static async all(options = {}) {
|
|
1643
1643
|
const statics = modelStatics(this);
|
|
1644
|
-
const repository = resolveModelRepository(
|
|
1645
|
-
let query = Model.query.call(
|
|
1644
|
+
const repository = resolveModelRepository(Model);
|
|
1645
|
+
let query = Model.query.call(Model);
|
|
1646
1646
|
if (options.orderBy) {
|
|
1647
1647
|
query = query.orderBy(options.orderBy);
|
|
1648
1648
|
}
|
|
@@ -1654,8 +1654,8 @@ class Model {
|
|
|
1654
1654
|
}
|
|
1655
1655
|
static async firstWhere(where, options = {}) {
|
|
1656
1656
|
const statics = modelStatics(this);
|
|
1657
|
-
const repository = resolveModelRepository(
|
|
1658
|
-
let query = Model.query.call(
|
|
1657
|
+
const repository = resolveModelRepository(Model);
|
|
1658
|
+
let query = Model.query.call(Model).where(where);
|
|
1659
1659
|
if (options.orderBy) {
|
|
1660
1660
|
query = query.orderBy(options.orderBy);
|
|
1661
1661
|
}
|
|
@@ -2817,76 +2817,64 @@ function hashApiToken(token) {
|
|
|
2817
2817
|
var tokenServiceToken = CORE_TOKEN_SERVICE_TOKEN;
|
|
2818
2818
|
|
|
2819
2819
|
// ../../src/core/http/csrfToken.ts
|
|
2820
|
-
import {
|
|
2820
|
+
import { timingSafeEqual } from "crypto";
|
|
2821
|
+
|
|
2822
|
+
// ../../src/core/http/cookies.ts
|
|
2823
|
+
function readRequestCookie(request, name) {
|
|
2824
|
+
const cookies = request.cookies;
|
|
2825
|
+
if (cookies && typeof cookies.get === "function") {
|
|
2826
|
+
const value = cookies.get(name);
|
|
2827
|
+
if (value) {
|
|
2828
|
+
return value;
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
const header = request.headers.get("cookie");
|
|
2832
|
+
if (!header) {
|
|
2833
|
+
return null;
|
|
2834
|
+
}
|
|
2835
|
+
for (const part of header.split(";")) {
|
|
2836
|
+
const idx = part.indexOf("=");
|
|
2837
|
+
if (idx === -1)
|
|
2838
|
+
continue;
|
|
2839
|
+
const cookieName = part.slice(0, idx).trim();
|
|
2840
|
+
if (cookieName !== name)
|
|
2841
|
+
continue;
|
|
2842
|
+
return decodeURIComponent(part.slice(idx + 1).trim());
|
|
2843
|
+
}
|
|
2844
|
+
return null;
|
|
2845
|
+
}
|
|
2846
|
+
function readBunRequestCookie(request, name) {
|
|
2847
|
+
return request.cookies.get(name) ?? readRequestCookie(request, name);
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
// ../../src/core/http/csrfToken.ts
|
|
2821
2851
|
var CSRF_COOKIE = "workhub_csrf";
|
|
2822
2852
|
var CSRF_TTL_MS = 60 * 60 * 1000;
|
|
2823
2853
|
function resolveCsrfSecret() {
|
|
2824
2854
|
return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-csrf-secret";
|
|
2825
2855
|
}
|
|
2826
|
-
function
|
|
2827
|
-
|
|
2828
|
-
const signature = createHmac4("sha256", resolveCsrfSecret()).update(payload).digest("hex");
|
|
2829
|
-
return `${payload}.${signature}`;
|
|
2856
|
+
function csrfVerifyOptions() {
|
|
2857
|
+
return { secret: resolveCsrfSecret(), maxAge: CSRF_TTL_MS };
|
|
2830
2858
|
}
|
|
2831
|
-
function
|
|
2832
|
-
const
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
for (const part of cookieHeader.split(";")) {
|
|
2837
|
-
const [name, ...rest] = part.trim().split("=");
|
|
2838
|
-
if (name === CSRF_COOKIE) {
|
|
2839
|
-
return decodeURIComponent(rest.join("="));
|
|
2840
|
-
}
|
|
2841
|
-
}
|
|
2842
|
-
return null;
|
|
2843
|
-
}
|
|
2844
|
-
function parseSignedCsrfValue(cookieValue) {
|
|
2845
|
-
const parts = cookieValue.split(".");
|
|
2846
|
-
if (parts.length !== 3) {
|
|
2847
|
-
return null;
|
|
2848
|
-
}
|
|
2849
|
-
const [token, issuedAtRaw, cookieSignature] = parts;
|
|
2850
|
-
if (!token || !issuedAtRaw || !cookieSignature) {
|
|
2851
|
-
return null;
|
|
2852
|
-
}
|
|
2853
|
-
const issuedAt = Number.parseInt(issuedAtRaw, 10);
|
|
2854
|
-
if (!Number.isFinite(issuedAt)) {
|
|
2855
|
-
return null;
|
|
2856
|
-
}
|
|
2857
|
-
if (Date.now() - issuedAt > CSRF_TTL_MS) {
|
|
2858
|
-
return null;
|
|
2859
|
-
}
|
|
2860
|
-
const expectedSignature = signCsrfToken(token, issuedAt).split(".").pop();
|
|
2861
|
-
if (!expectedSignature) {
|
|
2862
|
-
return null;
|
|
2863
|
-
}
|
|
2864
|
-
const expectedBuffer = Buffer.from(expectedSignature);
|
|
2865
|
-
const actualBuffer = Buffer.from(cookieSignature);
|
|
2866
|
-
if (expectedBuffer.length !== actualBuffer.length) {
|
|
2867
|
-
return null;
|
|
2868
|
-
}
|
|
2869
|
-
if (!timingSafeEqual(expectedBuffer, actualBuffer)) {
|
|
2870
|
-
return null;
|
|
2859
|
+
function tokensMatch(left, right) {
|
|
2860
|
+
const leftBuffer = Buffer.from(left);
|
|
2861
|
+
const rightBuffer = Buffer.from(right);
|
|
2862
|
+
if (leftBuffer.length !== rightBuffer.length) {
|
|
2863
|
+
return false;
|
|
2871
2864
|
}
|
|
2872
|
-
return
|
|
2865
|
+
return timingSafeEqual(leftBuffer, rightBuffer);
|
|
2873
2866
|
}
|
|
2874
2867
|
function createCsrfTokenCookie() {
|
|
2875
|
-
const token =
|
|
2876
|
-
const issuedAt = Date.now();
|
|
2877
|
-
const value = signCsrfToken(token, issuedAt);
|
|
2868
|
+
const token = Bun.CSRF.generate(resolveCsrfSecret(), { expiresIn: CSRF_TTL_MS });
|
|
2878
2869
|
return {
|
|
2879
2870
|
token,
|
|
2880
|
-
cookie: `${CSRF_COOKIE}=${encodeURIComponent(
|
|
2871
|
+
cookie: `${CSRF_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Lax; Max-Age=${Math.floor(CSRF_TTL_MS / 1000)}`
|
|
2881
2872
|
};
|
|
2882
2873
|
}
|
|
2883
2874
|
function resolveCsrfToken(request) {
|
|
2884
|
-
const cookieValue =
|
|
2885
|
-
if (cookieValue) {
|
|
2886
|
-
|
|
2887
|
-
if (parsed) {
|
|
2888
|
-
return { token: parsed.token };
|
|
2889
|
-
}
|
|
2875
|
+
const cookieValue = readRequestCookie(request, CSRF_COOKIE);
|
|
2876
|
+
if (cookieValue && Bun.CSRF.verify(cookieValue, csrfVerifyOptions())) {
|
|
2877
|
+
return { token: cookieValue };
|
|
2890
2878
|
}
|
|
2891
2879
|
return createCsrfTokenCookie();
|
|
2892
2880
|
}
|
|
@@ -2909,6 +2897,10 @@ async function readSubmittedCsrfTokenFromBody(request) {
|
|
|
2909
2897
|
if (typeof field === "string" && field.trim().length > 0) {
|
|
2910
2898
|
return field.trim();
|
|
2911
2899
|
}
|
|
2900
|
+
const legacyField = formData.get("_csrf");
|
|
2901
|
+
if (typeof legacyField === "string" && legacyField.trim().length > 0) {
|
|
2902
|
+
return legacyField.trim();
|
|
2903
|
+
}
|
|
2912
2904
|
}
|
|
2913
2905
|
return null;
|
|
2914
2906
|
}
|
|
@@ -2916,20 +2908,14 @@ function verifyCsrfToken(request, submittedToken) {
|
|
|
2916
2908
|
if (!submittedToken) {
|
|
2917
2909
|
return false;
|
|
2918
2910
|
}
|
|
2919
|
-
const cookieValue =
|
|
2911
|
+
const cookieValue = readRequestCookie(request, CSRF_COOKIE);
|
|
2920
2912
|
if (!cookieValue) {
|
|
2921
2913
|
return false;
|
|
2922
2914
|
}
|
|
2923
|
-
|
|
2924
|
-
if (!parsed) {
|
|
2925
|
-
return false;
|
|
2926
|
-
}
|
|
2927
|
-
const submittedBuffer = Buffer.from(submittedToken);
|
|
2928
|
-
const expectedBuffer = Buffer.from(parsed.token);
|
|
2929
|
-
if (submittedBuffer.length !== expectedBuffer.length) {
|
|
2915
|
+
if (!tokensMatch(submittedToken, cookieValue)) {
|
|
2930
2916
|
return false;
|
|
2931
2917
|
}
|
|
2932
|
-
return
|
|
2918
|
+
return Bun.CSRF.verify(submittedToken, csrfVerifyOptions());
|
|
2933
2919
|
}
|
|
2934
2920
|
function resolveCsrfTokenForRequest(request) {
|
|
2935
2921
|
const metaToken = currentRequestMeta().csrfToken;
|
|
@@ -2940,14 +2926,14 @@ function resolveCsrfTokenForRequest(request) {
|
|
|
2940
2926
|
}
|
|
2941
2927
|
|
|
2942
2928
|
// ../../src/core/http/flashSession.ts
|
|
2943
|
-
import { createHmac as
|
|
2929
|
+
import { createHmac as createHmac4, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
2944
2930
|
var FLASH_COOKIE = "workhub_flash";
|
|
2945
2931
|
var FLASH_TTL_MS = 60 * 1000;
|
|
2946
2932
|
function resolveFlashSecret() {
|
|
2947
2933
|
return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || "workhub-dev-flash-secret";
|
|
2948
2934
|
}
|
|
2949
2935
|
function signFlashPayload(payload, issuedAt) {
|
|
2950
|
-
const signature =
|
|
2936
|
+
const signature = createHmac4("sha256", resolveFlashSecret()).update(`${payload}.${issuedAt}`).digest("hex");
|
|
2951
2937
|
return `${payload}.${issuedAt}.${signature}`;
|
|
2952
2938
|
}
|
|
2953
2939
|
function readFlashCookie(request) {
|
|
@@ -3166,8 +3152,12 @@ function createAuthorizeMiddleware(gate, auth, resource, action) {
|
|
|
3166
3152
|
return await next();
|
|
3167
3153
|
};
|
|
3168
3154
|
}
|
|
3155
|
+
// ../../src/core/crypto/nonCryptographicHash.ts
|
|
3156
|
+
function nonCryptographicDigest(input) {
|
|
3157
|
+
return Bun.hash(input).toString(16);
|
|
3158
|
+
}
|
|
3159
|
+
|
|
3169
3160
|
// ../../src/core/http/etag.ts
|
|
3170
|
-
import { createHash as createHash2 } from "crypto";
|
|
3171
3161
|
function isEtagEnabled() {
|
|
3172
3162
|
return (process.env.FEATURE_ETAG ?? "true") !== "false";
|
|
3173
3163
|
}
|
|
@@ -3175,13 +3165,13 @@ function formatWeakEtag(digest) {
|
|
|
3175
3165
|
return `W/"${digest}"`;
|
|
3176
3166
|
}
|
|
3177
3167
|
function computeEtagFromJson(data) {
|
|
3178
|
-
const digest =
|
|
3168
|
+
const digest = nonCryptographicDigest(JSON.stringify(data)).slice(0, 32);
|
|
3179
3169
|
return formatWeakEtag(digest);
|
|
3180
3170
|
}
|
|
3181
3171
|
function etagFromResource(resource) {
|
|
3182
3172
|
const version = resource.updated_at ?? resource.created_at ?? "";
|
|
3183
3173
|
const versionText = version instanceof Date ? version.toISOString() : version ? String(version) : "0";
|
|
3184
|
-
const digest =
|
|
3174
|
+
const digest = nonCryptographicDigest(`${String(resource.id ?? "0")}:${versionText}`).slice(0, 32);
|
|
3185
3175
|
return formatWeakEtag(digest);
|
|
3186
3176
|
}
|
|
3187
3177
|
function normalizeEtag(value) {
|
|
@@ -1751,26 +1751,26 @@ class Model {
|
|
|
1751
1751
|
throw new Error(`${this.constructor.name}.primaryKey() is not implemented.`);
|
|
1752
1752
|
}
|
|
1753
1753
|
static primaryKeyField() {
|
|
1754
|
-
return resolveModelRepository(
|
|
1754
|
+
return resolveModelRepository(Model).getTable().primaryKey;
|
|
1755
1755
|
}
|
|
1756
1756
|
static hydrateAttributes(attributes) {
|
|
1757
|
-
const casts = modelStatics(
|
|
1757
|
+
const casts = modelStatics(Model).$casts ?? {};
|
|
1758
1758
|
return applyCasts(attributes, casts, "hydrate");
|
|
1759
1759
|
}
|
|
1760
1760
|
static dehydrateAttributes(attributes) {
|
|
1761
|
-
const casts = modelStatics(
|
|
1761
|
+
const casts = modelStatics(Model).$casts ?? {};
|
|
1762
1762
|
return applyCasts(attributes, casts, "dehydrate");
|
|
1763
1763
|
}
|
|
1764
1764
|
static fromRecord(record, repository, exists = true) {
|
|
1765
|
-
const statics = modelStatics(
|
|
1765
|
+
const statics = modelStatics(Model);
|
|
1766
1766
|
const hydrated = statics.hydrateAttributes(record);
|
|
1767
1767
|
return new statics(hydrated, repository, exists);
|
|
1768
1768
|
}
|
|
1769
1769
|
static boot() {}
|
|
1770
1770
|
static addGlobalScope(_name, scope) {
|
|
1771
|
-
ensureBooted(
|
|
1772
|
-
const existing = modelGlobalScopes.get(
|
|
1773
|
-
modelGlobalScopes.set(
|
|
1771
|
+
ensureBooted(Model);
|
|
1772
|
+
const existing = modelGlobalScopes.get(Model) ?? [];
|
|
1773
|
+
modelGlobalScopes.set(Model, [
|
|
1774
1774
|
...existing,
|
|
1775
1775
|
scope
|
|
1776
1776
|
]);
|
|
@@ -1780,17 +1780,17 @@ class Model {
|
|
|
1780
1780
|
}
|
|
1781
1781
|
static query() {
|
|
1782
1782
|
ensureBooted(this);
|
|
1783
|
-
const repository = resolveModelRepository(
|
|
1783
|
+
const repository = resolveModelRepository(Model);
|
|
1784
1784
|
let query = repository.query();
|
|
1785
|
-
for (const scope of getGlobalScopes(
|
|
1785
|
+
for (const scope of getGlobalScopes(Model)) {
|
|
1786
1786
|
query = scope(query);
|
|
1787
1787
|
}
|
|
1788
1788
|
return query;
|
|
1789
1789
|
}
|
|
1790
1790
|
static async create(attributes) {
|
|
1791
1791
|
const statics = modelStatics(this);
|
|
1792
|
-
ensureBooted(
|
|
1793
|
-
const repository = resolveModelRepository(
|
|
1792
|
+
ensureBooted(Model);
|
|
1793
|
+
const repository = resolveModelRepository(Model);
|
|
1794
1794
|
const table = repository.getTable();
|
|
1795
1795
|
const timestamps = statics.$timestamps ?? true;
|
|
1796
1796
|
const assignable = filterMassAssignable(statics.$fillable, statics.$guarded, attributes);
|
|
@@ -1800,23 +1800,23 @@ class Model {
|
|
|
1800
1800
|
return statics.fromRecord(record, repository, true);
|
|
1801
1801
|
}
|
|
1802
1802
|
static async find(id) {
|
|
1803
|
-
const statics = modelStatics(
|
|
1804
|
-
const repository = resolveModelRepository(
|
|
1803
|
+
const statics = modelStatics(Model);
|
|
1804
|
+
const repository = resolveModelRepository(Model);
|
|
1805
1805
|
const primaryKey = repository.getTable().primaryKey;
|
|
1806
|
-
const record = await Model.query.call(
|
|
1806
|
+
const record = await Model.query.call(Model).where({ [primaryKey]: id }).first();
|
|
1807
1807
|
return record ? statics.fromRecord(record, repository, true) : null;
|
|
1808
1808
|
}
|
|
1809
1809
|
static async findOrFail(id, errorFactory) {
|
|
1810
|
-
const model = await Model.find.call(
|
|
1810
|
+
const model = await Model.find.call(Model, id);
|
|
1811
1811
|
if (model) {
|
|
1812
1812
|
return model;
|
|
1813
1813
|
}
|
|
1814
|
-
throw errorFactory?.(id) ?? new NotFoundError(`${
|
|
1814
|
+
throw errorFactory?.(id) ?? new NotFoundError(`${Model.name} ${String(id)} not found.`);
|
|
1815
1815
|
}
|
|
1816
1816
|
static async all(options = {}) {
|
|
1817
1817
|
const statics = modelStatics(this);
|
|
1818
|
-
const repository = resolveModelRepository(
|
|
1819
|
-
let query = Model.query.call(
|
|
1818
|
+
const repository = resolveModelRepository(Model);
|
|
1819
|
+
let query = Model.query.call(Model);
|
|
1820
1820
|
if (options.orderBy) {
|
|
1821
1821
|
query = query.orderBy(options.orderBy);
|
|
1822
1822
|
}
|
|
@@ -1828,8 +1828,8 @@ class Model {
|
|
|
1828
1828
|
}
|
|
1829
1829
|
static async firstWhere(where, options = {}) {
|
|
1830
1830
|
const statics = modelStatics(this);
|
|
1831
|
-
const repository = resolveModelRepository(
|
|
1832
|
-
let query = Model.query.call(
|
|
1831
|
+
const repository = resolveModelRepository(Model);
|
|
1832
|
+
let query = Model.query.call(Model).where(where);
|
|
1833
1833
|
if (options.orderBy) {
|
|
1834
1834
|
query = query.orderBy(options.orderBy);
|
|
1835
1835
|
}
|
|
@@ -1353,26 +1353,26 @@ class Model {
|
|
|
1353
1353
|
throw new Error(`${this.constructor.name}.primaryKey() is not implemented.`);
|
|
1354
1354
|
}
|
|
1355
1355
|
static primaryKeyField() {
|
|
1356
|
-
return resolveModelRepository(
|
|
1356
|
+
return resolveModelRepository(Model).getTable().primaryKey;
|
|
1357
1357
|
}
|
|
1358
1358
|
static hydrateAttributes(attributes) {
|
|
1359
|
-
const casts = modelStatics(
|
|
1359
|
+
const casts = modelStatics(Model).$casts ?? {};
|
|
1360
1360
|
return applyCasts(attributes, casts, "hydrate");
|
|
1361
1361
|
}
|
|
1362
1362
|
static dehydrateAttributes(attributes) {
|
|
1363
|
-
const casts = modelStatics(
|
|
1363
|
+
const casts = modelStatics(Model).$casts ?? {};
|
|
1364
1364
|
return applyCasts(attributes, casts, "dehydrate");
|
|
1365
1365
|
}
|
|
1366
1366
|
static fromRecord(record, repository, exists = true) {
|
|
1367
|
-
const statics = modelStatics(
|
|
1367
|
+
const statics = modelStatics(Model);
|
|
1368
1368
|
const hydrated = statics.hydrateAttributes(record);
|
|
1369
1369
|
return new statics(hydrated, repository, exists);
|
|
1370
1370
|
}
|
|
1371
1371
|
static boot() {}
|
|
1372
1372
|
static addGlobalScope(_name, scope) {
|
|
1373
|
-
ensureBooted(
|
|
1374
|
-
const existing = modelGlobalScopes.get(
|
|
1375
|
-
modelGlobalScopes.set(
|
|
1373
|
+
ensureBooted(Model);
|
|
1374
|
+
const existing = modelGlobalScopes.get(Model) ?? [];
|
|
1375
|
+
modelGlobalScopes.set(Model, [
|
|
1376
1376
|
...existing,
|
|
1377
1377
|
scope
|
|
1378
1378
|
]);
|
|
@@ -1382,17 +1382,17 @@ class Model {
|
|
|
1382
1382
|
}
|
|
1383
1383
|
static query() {
|
|
1384
1384
|
ensureBooted(this);
|
|
1385
|
-
const repository = resolveModelRepository(
|
|
1385
|
+
const repository = resolveModelRepository(Model);
|
|
1386
1386
|
let query = repository.query();
|
|
1387
|
-
for (const scope of getGlobalScopes(
|
|
1387
|
+
for (const scope of getGlobalScopes(Model)) {
|
|
1388
1388
|
query = scope(query);
|
|
1389
1389
|
}
|
|
1390
1390
|
return query;
|
|
1391
1391
|
}
|
|
1392
1392
|
static async create(attributes) {
|
|
1393
1393
|
const statics = modelStatics(this);
|
|
1394
|
-
ensureBooted(
|
|
1395
|
-
const repository = resolveModelRepository(
|
|
1394
|
+
ensureBooted(Model);
|
|
1395
|
+
const repository = resolveModelRepository(Model);
|
|
1396
1396
|
const table = repository.getTable();
|
|
1397
1397
|
const timestamps = statics.$timestamps ?? true;
|
|
1398
1398
|
const assignable = filterMassAssignable(statics.$fillable, statics.$guarded, attributes);
|
|
@@ -1402,23 +1402,23 @@ class Model {
|
|
|
1402
1402
|
return statics.fromRecord(record, repository, true);
|
|
1403
1403
|
}
|
|
1404
1404
|
static async find(id) {
|
|
1405
|
-
const statics = modelStatics(
|
|
1406
|
-
const repository = resolveModelRepository(
|
|
1405
|
+
const statics = modelStatics(Model);
|
|
1406
|
+
const repository = resolveModelRepository(Model);
|
|
1407
1407
|
const primaryKey = repository.getTable().primaryKey;
|
|
1408
|
-
const record = await Model.query.call(
|
|
1408
|
+
const record = await Model.query.call(Model).where({ [primaryKey]: id }).first();
|
|
1409
1409
|
return record ? statics.fromRecord(record, repository, true) : null;
|
|
1410
1410
|
}
|
|
1411
1411
|
static async findOrFail(id, errorFactory) {
|
|
1412
|
-
const model = await Model.find.call(
|
|
1412
|
+
const model = await Model.find.call(Model, id);
|
|
1413
1413
|
if (model) {
|
|
1414
1414
|
return model;
|
|
1415
1415
|
}
|
|
1416
|
-
throw errorFactory?.(id) ?? new NotFoundError(`${
|
|
1416
|
+
throw errorFactory?.(id) ?? new NotFoundError(`${Model.name} ${String(id)} not found.`);
|
|
1417
1417
|
}
|
|
1418
1418
|
static async all(options = {}) {
|
|
1419
1419
|
const statics = modelStatics(this);
|
|
1420
|
-
const repository = resolveModelRepository(
|
|
1421
|
-
let query = Model.query.call(
|
|
1420
|
+
const repository = resolveModelRepository(Model);
|
|
1421
|
+
let query = Model.query.call(Model);
|
|
1422
1422
|
if (options.orderBy) {
|
|
1423
1423
|
query = query.orderBy(options.orderBy);
|
|
1424
1424
|
}
|
|
@@ -1430,8 +1430,8 @@ class Model {
|
|
|
1430
1430
|
}
|
|
1431
1431
|
static async firstWhere(where, options = {}) {
|
|
1432
1432
|
const statics = modelStatics(this);
|
|
1433
|
-
const repository = resolveModelRepository(
|
|
1434
|
-
let query = Model.query.call(
|
|
1433
|
+
const repository = resolveModelRepository(Model);
|
|
1434
|
+
let query = Model.query.call(Model).where(where);
|
|
1435
1435
|
if (options.orderBy) {
|
|
1436
1436
|
query = query.orderBy(options.orderBy);
|
|
1437
1437
|
}
|
|
@@ -1761,26 +1761,26 @@ class Model {
|
|
|
1761
1761
|
throw new Error(`${this.constructor.name}.primaryKey() is not implemented.`);
|
|
1762
1762
|
}
|
|
1763
1763
|
static primaryKeyField() {
|
|
1764
|
-
return resolveModelRepository(
|
|
1764
|
+
return resolveModelRepository(Model).getTable().primaryKey;
|
|
1765
1765
|
}
|
|
1766
1766
|
static hydrateAttributes(attributes) {
|
|
1767
|
-
const casts = modelStatics(
|
|
1767
|
+
const casts = modelStatics(Model).$casts ?? {};
|
|
1768
1768
|
return applyCasts(attributes, casts, "hydrate");
|
|
1769
1769
|
}
|
|
1770
1770
|
static dehydrateAttributes(attributes) {
|
|
1771
|
-
const casts = modelStatics(
|
|
1771
|
+
const casts = modelStatics(Model).$casts ?? {};
|
|
1772
1772
|
return applyCasts(attributes, casts, "dehydrate");
|
|
1773
1773
|
}
|
|
1774
1774
|
static fromRecord(record, repository, exists = true) {
|
|
1775
|
-
const statics = modelStatics(
|
|
1775
|
+
const statics = modelStatics(Model);
|
|
1776
1776
|
const hydrated = statics.hydrateAttributes(record);
|
|
1777
1777
|
return new statics(hydrated, repository, exists);
|
|
1778
1778
|
}
|
|
1779
1779
|
static boot() {}
|
|
1780
1780
|
static addGlobalScope(_name, scope) {
|
|
1781
|
-
ensureBooted(
|
|
1782
|
-
const existing = modelGlobalScopes.get(
|
|
1783
|
-
modelGlobalScopes.set(
|
|
1781
|
+
ensureBooted(Model);
|
|
1782
|
+
const existing = modelGlobalScopes.get(Model) ?? [];
|
|
1783
|
+
modelGlobalScopes.set(Model, [
|
|
1784
1784
|
...existing,
|
|
1785
1785
|
scope
|
|
1786
1786
|
]);
|
|
@@ -1790,17 +1790,17 @@ class Model {
|
|
|
1790
1790
|
}
|
|
1791
1791
|
static query() {
|
|
1792
1792
|
ensureBooted(this);
|
|
1793
|
-
const repository = resolveModelRepository(
|
|
1793
|
+
const repository = resolveModelRepository(Model);
|
|
1794
1794
|
let query = repository.query();
|
|
1795
|
-
for (const scope of getGlobalScopes(
|
|
1795
|
+
for (const scope of getGlobalScopes(Model)) {
|
|
1796
1796
|
query = scope(query);
|
|
1797
1797
|
}
|
|
1798
1798
|
return query;
|
|
1799
1799
|
}
|
|
1800
1800
|
static async create(attributes) {
|
|
1801
1801
|
const statics = modelStatics(this);
|
|
1802
|
-
ensureBooted(
|
|
1803
|
-
const repository = resolveModelRepository(
|
|
1802
|
+
ensureBooted(Model);
|
|
1803
|
+
const repository = resolveModelRepository(Model);
|
|
1804
1804
|
const table = repository.getTable();
|
|
1805
1805
|
const timestamps = statics.$timestamps ?? true;
|
|
1806
1806
|
const assignable = filterMassAssignable(statics.$fillable, statics.$guarded, attributes);
|
|
@@ -1810,23 +1810,23 @@ class Model {
|
|
|
1810
1810
|
return statics.fromRecord(record, repository, true);
|
|
1811
1811
|
}
|
|
1812
1812
|
static async find(id) {
|
|
1813
|
-
const statics = modelStatics(
|
|
1814
|
-
const repository = resolveModelRepository(
|
|
1813
|
+
const statics = modelStatics(Model);
|
|
1814
|
+
const repository = resolveModelRepository(Model);
|
|
1815
1815
|
const primaryKey = repository.getTable().primaryKey;
|
|
1816
|
-
const record = await Model.query.call(
|
|
1816
|
+
const record = await Model.query.call(Model).where({ [primaryKey]: id }).first();
|
|
1817
1817
|
return record ? statics.fromRecord(record, repository, true) : null;
|
|
1818
1818
|
}
|
|
1819
1819
|
static async findOrFail(id, errorFactory) {
|
|
1820
|
-
const model = await Model.find.call(
|
|
1820
|
+
const model = await Model.find.call(Model, id);
|
|
1821
1821
|
if (model) {
|
|
1822
1822
|
return model;
|
|
1823
1823
|
}
|
|
1824
|
-
throw errorFactory?.(id) ?? new NotFoundError(`${
|
|
1824
|
+
throw errorFactory?.(id) ?? new NotFoundError(`${Model.name} ${String(id)} not found.`);
|
|
1825
1825
|
}
|
|
1826
1826
|
static async all(options = {}) {
|
|
1827
1827
|
const statics = modelStatics(this);
|
|
1828
|
-
const repository = resolveModelRepository(
|
|
1829
|
-
let query = Model.query.call(
|
|
1828
|
+
const repository = resolveModelRepository(Model);
|
|
1829
|
+
let query = Model.query.call(Model);
|
|
1830
1830
|
if (options.orderBy) {
|
|
1831
1831
|
query = query.orderBy(options.orderBy);
|
|
1832
1832
|
}
|
|
@@ -1838,8 +1838,8 @@ class Model {
|
|
|
1838
1838
|
}
|
|
1839
1839
|
static async firstWhere(where, options = {}) {
|
|
1840
1840
|
const statics = modelStatics(this);
|
|
1841
|
-
const repository = resolveModelRepository(
|
|
1842
|
-
let query = Model.query.call(
|
|
1841
|
+
const repository = resolveModelRepository(Model);
|
|
1842
|
+
let query = Model.query.call(Model).where(where);
|
|
1843
1843
|
if (options.orderBy) {
|
|
1844
1844
|
query = query.orderBy(options.orderBy);
|
|
1845
1845
|
}
|