@getstrata/core 0.5.5 → 0.5.6

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.
@@ -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(this).getTable().primaryKey;
1580
+ return resolveModelRepository(Model).getTable().primaryKey;
1581
1581
  }
1582
1582
  static hydrateAttributes(attributes) {
1583
- const casts = modelStatics(this).$casts ?? {};
1583
+ const casts = modelStatics(Model).$casts ?? {};
1584
1584
  return applyCasts(attributes, casts, "hydrate");
1585
1585
  }
1586
1586
  static dehydrateAttributes(attributes) {
1587
- const casts = modelStatics(this).$casts ?? {};
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(this);
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(this);
1598
- const existing = modelGlobalScopes.get(this) ?? [];
1599
- modelGlobalScopes.set(this, [
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(this);
1609
+ const repository = resolveModelRepository(Model);
1610
1610
  let query = repository.query();
1611
- for (const scope of getGlobalScopes(this)) {
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(this);
1619
- const repository = resolveModelRepository(this);
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(this);
1630
- const repository = resolveModelRepository(this);
1629
+ const statics = modelStatics(Model);
1630
+ const repository = resolveModelRepository(Model);
1631
1631
  const primaryKey = repository.getTable().primaryKey;
1632
- const record = await Model.query.call(this).where({ [primaryKey]: id }).first();
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(this, id);
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(`${this.name} ${String(id)} not found.`);
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(this);
1645
- let query = Model.query.call(this);
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(this);
1658
- let query = Model.query.call(this).where(where);
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 { createHmac as createHmac4, randomBytes as randomBytes2, timingSafeEqual } from "crypto";
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 signCsrfToken(token, issuedAt) {
2827
- const payload = `${token}.${issuedAt}`;
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 readCsrfCookie(request) {
2832
- const cookieHeader = request.headers.get("cookie");
2833
- if (!cookieHeader) {
2834
- return null;
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 { token, issuedAt };
2865
+ return timingSafeEqual(leftBuffer, rightBuffer);
2873
2866
  }
2874
2867
  function createCsrfTokenCookie() {
2875
- const token = randomBytes2(24).toString("hex");
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(value)}; Path=/; SameSite=Lax; Max-Age=3600`
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 = readCsrfCookie(request);
2885
- if (cookieValue) {
2886
- const parsed = parseSignedCsrfValue(cookieValue);
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 = readCsrfCookie(request);
2911
+ const cookieValue = readRequestCookie(request, CSRF_COOKIE);
2920
2912
  if (!cookieValue) {
2921
2913
  return false;
2922
2914
  }
2923
- const parsed = parseSignedCsrfValue(cookieValue);
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 timingSafeEqual(submittedBuffer, expectedBuffer);
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 createHmac5, timingSafeEqual as timingSafeEqual2 } from "crypto";
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 = createHmac5("sha256", resolveFlashSecret()).update(`${payload}.${issuedAt}`).digest("hex");
2936
+ const signature = createHmac4("sha256", resolveFlashSecret()).update(`${payload}.${issuedAt}`).digest("hex");
2951
2937
  return `${payload}.${issuedAt}.${signature}`;
2952
2938
  }
2953
2939
  function readFlashCookie(request) {
@@ -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(this).getTable().primaryKey;
1580
+ return resolveModelRepository(Model).getTable().primaryKey;
1581
1581
  }
1582
1582
  static hydrateAttributes(attributes) {
1583
- const casts = modelStatics(this).$casts ?? {};
1583
+ const casts = modelStatics(Model).$casts ?? {};
1584
1584
  return applyCasts(attributes, casts, "hydrate");
1585
1585
  }
1586
1586
  static dehydrateAttributes(attributes) {
1587
- const casts = modelStatics(this).$casts ?? {};
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(this);
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(this);
1598
- const existing = modelGlobalScopes.get(this) ?? [];
1599
- modelGlobalScopes.set(this, [
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(this);
1609
+ const repository = resolveModelRepository(Model);
1610
1610
  let query = repository.query();
1611
- for (const scope of getGlobalScopes(this)) {
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(this);
1619
- const repository = resolveModelRepository(this);
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(this);
1630
- const repository = resolveModelRepository(this);
1629
+ const statics = modelStatics(Model);
1630
+ const repository = resolveModelRepository(Model);
1631
1631
  const primaryKey = repository.getTable().primaryKey;
1632
- const record = await Model.query.call(this).where({ [primaryKey]: id }).first();
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(this, id);
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(`${this.name} ${String(id)} not found.`);
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(this);
1645
- let query = Model.query.call(this);
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(this);
1658
- let query = Model.query.call(this).where(where);
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 { createHmac as createHmac4, randomBytes as randomBytes2, timingSafeEqual } from "crypto";
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 signCsrfToken(token, issuedAt) {
2827
- const payload = `${token}.${issuedAt}`;
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 readCsrfCookie(request) {
2832
- const cookieHeader = request.headers.get("cookie");
2833
- if (!cookieHeader) {
2834
- return null;
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 { token, issuedAt };
2865
+ return timingSafeEqual(leftBuffer, rightBuffer);
2873
2866
  }
2874
2867
  function createCsrfTokenCookie() {
2875
- const token = randomBytes2(24).toString("hex");
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(value)}; Path=/; SameSite=Lax; Max-Age=3600`
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 = readCsrfCookie(request);
2885
- if (cookieValue) {
2886
- const parsed = parseSignedCsrfValue(cookieValue);
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 = readCsrfCookie(request);
2911
+ const cookieValue = readRequestCookie(request, CSRF_COOKIE);
2920
2912
  if (!cookieValue) {
2921
2913
  return false;
2922
2914
  }
2923
- const parsed = parseSignedCsrfValue(cookieValue);
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 timingSafeEqual(submittedBuffer, expectedBuffer);
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 createHmac5, timingSafeEqual as timingSafeEqual2 } from "crypto";
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 = createHmac5("sha256", resolveFlashSecret()).update(`${payload}.${issuedAt}`).digest("hex");
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 = createHash2("sha256").update(JSON.stringify(data)).digest("hex").slice(0, 32);
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 = createHash2("sha256").update(`${String(resource.id ?? "0")}:${versionText}`).digest("hex").slice(0, 32);
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(this).getTable().primaryKey;
1754
+ return resolveModelRepository(Model).getTable().primaryKey;
1755
1755
  }
1756
1756
  static hydrateAttributes(attributes) {
1757
- const casts = modelStatics(this).$casts ?? {};
1757
+ const casts = modelStatics(Model).$casts ?? {};
1758
1758
  return applyCasts(attributes, casts, "hydrate");
1759
1759
  }
1760
1760
  static dehydrateAttributes(attributes) {
1761
- const casts = modelStatics(this).$casts ?? {};
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(this);
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(this);
1772
- const existing = modelGlobalScopes.get(this) ?? [];
1773
- modelGlobalScopes.set(this, [
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(this);
1783
+ const repository = resolveModelRepository(Model);
1784
1784
  let query = repository.query();
1785
- for (const scope of getGlobalScopes(this)) {
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(this);
1793
- const repository = resolveModelRepository(this);
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(this);
1804
- const repository = resolveModelRepository(this);
1803
+ const statics = modelStatics(Model);
1804
+ const repository = resolveModelRepository(Model);
1805
1805
  const primaryKey = repository.getTable().primaryKey;
1806
- const record = await Model.query.call(this).where({ [primaryKey]: id }).first();
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(this, id);
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(`${this.name} ${String(id)} not found.`);
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(this);
1819
- let query = Model.query.call(this);
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(this);
1832
- let query = Model.query.call(this).where(where);
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
  }