@plank-cms/plank 0.13.0 → 0.14.2

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.
@@ -67,7 +67,7 @@ async function ensureMigrationsTable(client) {
67
67
  }
68
68
  async function appliedMigrations(client) {
69
69
  const { rows } = await client.query("SELECT filename FROM plank_migrations ORDER BY filename");
70
- return new Set(rows.map((r) => r.filename));
70
+ return new Set(rows.map((r2) => r2.filename));
71
71
  }
72
72
  async function seedDefaultRoles(client) {
73
73
  const { rows } = await client.query("SELECT COUNT(*) as count FROM plank_roles");
@@ -83,7 +83,7 @@ async function migrate() {
83
83
  try {
84
84
  await client.query("BEGIN");
85
85
  await ensureMigrationsTable(client);
86
- const files = (await readdir(MIGRATIONS_DIR)).filter((f) => f.endsWith(".sql")).sort();
86
+ const files = (await readdir(MIGRATIONS_DIR)).filter((f2) => f2.endsWith(".sql")).sort();
87
87
  const applied = await appliedMigrations(client);
88
88
  for (const file of files) {
89
89
  if (applied.has(file))
@@ -270,7 +270,7 @@ function relationSignature(field) {
270
270
  async function createTable(contentType) {
271
271
  assertSafeIdentifier(contentType.tableName);
272
272
  const quotedTableName = quoteIdentifier(contentType.tableName);
273
- const columnFields = contentType.fields.filter((f) => !isVirtualRelation(f));
273
+ const columnFields = contentType.fields.filter((f2) => !isVirtualRelation(f2));
274
274
  const columns = columnFields.map(buildColumnDef).filter(Boolean);
275
275
  const sql = [
276
276
  `CREATE TABLE IF NOT EXISTS ${quotedTableName} (`,
@@ -300,8 +300,8 @@ async function createTable(contentType) {
300
300
  async function syncTable(next, prev) {
301
301
  assertSafeIdentifier(next.tableName);
302
302
  const quotedTableName = quoteIdentifier(next.tableName);
303
- const prevFields = new Map(prev.fields.map((f) => [f.name, f]));
304
- const nextFields = new Map(next.fields.map((f) => [f.name, f]));
303
+ const prevFields = new Map(prev.fields.map((f2) => [f2.name, f2]));
304
+ const nextFields = new Map(next.fields.map((f2) => [f2.name, f2]));
305
305
  const statements = [];
306
306
  const junctionOps = [];
307
307
  for (const [name, field] of nextFields) {
@@ -390,7 +390,7 @@ async function syncAllTables() {
390
390
  assertSafeIdentifier(ct.tableName);
391
391
  const quotedTableName = quoteIdentifier(ct.tableName);
392
392
  const { rows } = await pool_default.query(`SELECT column_name FROM information_schema.columns WHERE table_name = $1 AND table_schema = 'public'`, [ct.tableName]);
393
- const existingColumns = new Set(rows.map((r) => r.column_name));
393
+ const existingColumns = new Set(rows.map((r2) => r2.column_name));
394
394
  if (!existingColumns.has("localized")) {
395
395
  try {
396
396
  await pool_default.query(`ALTER TABLE ${quotedTableName} ADD COLUMN IF NOT EXISTS localized JSONB`);
@@ -435,9 +435,9 @@ function validateNavigationItems(value, fieldName, errors, path = fieldName, dep
435
435
  if (value.length > MAX_NAVIGATION_ITEMS_PER_LEVEL) {
436
436
  errors.push(`Field "${path}" cannot have more than ${MAX_NAVIGATION_ITEMS_PER_LEVEL} items per level`);
437
437
  }
438
- for (let i = 0; i < value.length; i++) {
439
- const item = value[i];
440
- const itemPath = `${path}[${i}]`;
438
+ for (let i2 = 0; i2 < value.length; i2++) {
439
+ const item = value[i2];
440
+ const itemPath = `${path}[${i2}]`;
441
441
  if (typeof item !== "object" || item === null) {
442
442
  errors.push(`Field "${itemPath}" must be an object`);
443
443
  continue;
@@ -495,7 +495,7 @@ function validate(contentType, payload) {
495
495
  }
496
496
  break;
497
497
  case "media-gallery":
498
- if (!Array.isArray(value) || value.some((v) => typeof v !== "string" || !v.trim())) {
498
+ if (!Array.isArray(value) || value.some((v3) => typeof v3 !== "string" || !v3.trim())) {
499
499
  errors.push(`Field "${field.name}" must be an array of media IDs`);
500
500
  } else if (field.required && value.length === 0) {
501
501
  errors.push(`Field "${field.name}" is required`);
@@ -506,7 +506,7 @@ function validate(contentType, payload) {
506
506
  if (rt === "one-to-many")
507
507
  break;
508
508
  if (rt === "many-to-many") {
509
- if (!Array.isArray(value) || value.some((v) => typeof v !== "string" || !v.trim())) {
509
+ if (!Array.isArray(value) || value.some((v3) => typeof v3 !== "string" || !v3.trim())) {
510
510
  errors.push(`Field "${field.name}" must be an array of IDs`);
511
511
  } else if (field.required && value.length === 0) {
512
512
  errors.push(`Field "${field.name}" is required`);
@@ -524,17 +524,17 @@ function validate(contentType, payload) {
524
524
  } else if (field.required && value.length === 0) {
525
525
  errors.push(`Field "${field.name}" is required`);
526
526
  } else if (field.arrayFields && field.arrayFields.length > 0) {
527
- for (let i = 0; i < value.length; i++) {
528
- const item = value[i];
527
+ for (let i2 = 0; i2 < value.length; i2++) {
528
+ const item = value[i2];
529
529
  if (typeof item !== "object" || item === null) {
530
- errors.push(`Field "${field.name}[${i}]" must be an object`);
530
+ errors.push(`Field "${field.name}[${i2}]" must be an object`);
531
531
  continue;
532
532
  }
533
533
  for (const subField of field.arrayFields) {
534
534
  const subValue = item[subField.name];
535
535
  const subEmpty = subValue === void 0 || subValue === null || subValue === "";
536
536
  if (subField.required && subEmpty) {
537
- errors.push(`Field "${field.name}[${i}].${subField.name}" is required`);
537
+ errors.push(`Field "${field.name}[${i2}].${subField.name}" is required`);
538
538
  }
539
539
  }
540
540
  }
@@ -557,7 +557,7 @@ function validate(contentType, payload) {
557
557
  import express from "express";
558
558
  import cors from "cors";
559
559
  import helmet from "helmet";
560
- import { join as join3, dirname as dirname2 } from "path";
560
+ import { join as join4, dirname as dirname2 } from "path";
561
561
  import { fileURLToPath as fileURLToPath2 } from "url";
562
562
 
563
563
  // ../core/dist/routes/auth.js
@@ -566,23 +566,1453 @@ import { Router } from "express";
566
566
  // ../core/dist/controllers/auth.js
567
567
  import bcrypt from "bcryptjs";
568
568
  import jwt from "jsonwebtoken";
569
+
570
+ // ../../node_modules/.pnpm/@otplib+core@13.4.0/node_modules/@otplib/core/dist/index.js
571
+ var i = class extends Error {
572
+ constructor(e, t2) {
573
+ super(e, t2), this.name = "OTPError";
574
+ }
575
+ };
576
+ var x = class extends i {
577
+ constructor(e) {
578
+ super(e), this.name = "SecretError";
579
+ }
580
+ };
581
+ var h = class extends x {
582
+ constructor(e, t2) {
583
+ super(`Secret must be at least ${e} bytes (${e * 8} bits), got ${t2} bytes`), this.name = "SecretTooShortError";
584
+ }
585
+ };
586
+ var P = class extends x {
587
+ constructor(e, t2) {
588
+ super(`Secret must not exceed ${e} bytes, got ${t2} bytes`), this.name = "SecretTooLongError";
589
+ }
590
+ };
591
+ var m = class extends i {
592
+ constructor(e) {
593
+ super(e), this.name = "CounterError";
594
+ }
595
+ };
596
+ var O = class extends m {
597
+ constructor() {
598
+ super("Counter must be non-negative"), this.name = "CounterNegativeError";
599
+ }
600
+ };
601
+ var T = class extends m {
602
+ constructor() {
603
+ super("Counter exceeds maximum safe integer value"), this.name = "CounterOverflowError";
604
+ }
605
+ };
606
+ var b = class extends m {
607
+ constructor() {
608
+ super("Counter must be a finite integer"), this.name = "CounterNotIntegerError";
609
+ }
610
+ };
611
+ var A = class extends i {
612
+ constructor(e) {
613
+ super(e), this.name = "TimeError";
614
+ }
615
+ };
616
+ var C = class extends A {
617
+ constructor() {
618
+ super("Time must be non-negative"), this.name = "TimeNegativeError";
619
+ }
620
+ };
621
+ var S = class extends A {
622
+ constructor() {
623
+ super("Time must be a finite number"), this.name = "TimeNotFiniteError";
624
+ }
625
+ };
626
+ var B = class extends i {
627
+ constructor(e) {
628
+ super(e), this.name = "PeriodError";
629
+ }
630
+ };
631
+ var w = class extends B {
632
+ constructor(e) {
633
+ super(`Period must be at least ${e} second(s)`), this.name = "PeriodTooSmallError";
634
+ }
635
+ };
636
+ var _ = class extends B {
637
+ constructor(e) {
638
+ super(`Period must not exceed ${e} seconds`), this.name = "PeriodTooLargeError";
639
+ }
640
+ };
641
+ var R = class extends i {
642
+ constructor(e) {
643
+ super(e), this.name = "TokenError";
644
+ }
645
+ };
646
+ var I = class extends R {
647
+ constructor(e, t2) {
648
+ super(`Token must be ${e} digits, got ${t2}`), this.name = "TokenLengthError";
649
+ }
650
+ };
651
+ var M = class extends R {
652
+ constructor() {
653
+ super("Token must contain only digits"), this.name = "TokenFormatError";
654
+ }
655
+ };
656
+ var N = class extends i {
657
+ constructor(e, t2) {
658
+ super(e, t2), this.name = "CryptoError";
659
+ }
660
+ };
661
+ var c = class extends N {
662
+ constructor(e, t2) {
663
+ super(`HMAC computation failed: ${e}`, t2), this.name = "HMACError";
664
+ }
665
+ };
666
+ var v = class extends N {
667
+ constructor(e, t2) {
668
+ super(`Random byte generation failed: ${e}`, t2), this.name = "RandomBytesError";
669
+ }
670
+ };
671
+ var g = class extends i {
672
+ constructor(e) {
673
+ super(e), this.name = "CounterToleranceError";
674
+ }
675
+ };
676
+ var U = class extends g {
677
+ constructor(e, t2) {
678
+ super(`Counter tolerance validation failed: total checks (${t2}) exceeds MAX_WINDOW (${e})`), this.name = "CounterToleranceTooLargeError";
679
+ }
680
+ };
681
+ var X = class extends g {
682
+ constructor() {
683
+ super("Counter tolerance cannot contain negative values"), this.name = "CounterToleranceNegativeError";
684
+ }
685
+ };
686
+ var E = class extends i {
687
+ constructor(e) {
688
+ super(e), this.name = "EpochToleranceError";
689
+ }
690
+ };
691
+ var k = class extends E {
692
+ constructor() {
693
+ super("Epoch tolerance cannot contain negative values"), this.name = "EpochToleranceNegativeError";
694
+ }
695
+ };
696
+ var q = class extends E {
697
+ constructor(e, t2) {
698
+ super(`Epoch tolerance must not exceed ${e} seconds, got ${t2}. Large tolerances can cause performance issues.`), this.name = "EpochToleranceTooLargeError";
699
+ }
700
+ };
701
+ var G = class extends i {
702
+ constructor(e) {
703
+ super(e), this.name = "PluginError";
704
+ }
705
+ };
706
+ var Y = class extends G {
707
+ constructor() {
708
+ super("Crypto plugin is required."), this.name = "CryptoPluginMissingError";
709
+ }
710
+ };
711
+ var L = class extends G {
712
+ constructor() {
713
+ super("Base32 plugin is required."), this.name = "Base32PluginMissingError";
714
+ }
715
+ };
716
+ var a = class extends i {
717
+ constructor(e) {
718
+ super(e), this.name = "ConfigurationError";
719
+ }
720
+ };
721
+ var W = class extends a {
722
+ constructor() {
723
+ super("Secret is required. Use generateSecret() to create one, or provide via { secret: 'YOUR_BASE32_SECRET' }"), this.name = "SecretMissingError";
724
+ }
725
+ };
726
+ var f = class extends i {
727
+ constructor(e) {
728
+ super(e), this.name = "AfterTimeStepError";
729
+ }
730
+ };
731
+ var J = class extends f {
732
+ constructor() {
733
+ super("afterTimeStep must be >= 0"), this.name = "AfterTimeStepNegativeError";
734
+ }
735
+ };
736
+ var Q = class extends f {
737
+ constructor() {
738
+ super("Invalid afterTimeStep: non-integer value"), this.name = "AfterTimeStepNotIntegerError";
739
+ }
740
+ };
741
+ var Z = class extends f {
742
+ constructor() {
743
+ super("Invalid afterTimeStep: cannot be greater than current time step plus window"), this.name = "AfterTimeStepRangeExceededError";
744
+ }
745
+ };
746
+ var yr = new TextEncoder();
747
+ var xr = new TextDecoder();
748
+ var or = 16;
749
+ var sr = 64;
750
+ var ir = 20;
751
+ var ar = 1;
752
+ var ur = 3600;
753
+ var cr = 30;
754
+ var pr = Number.MAX_SAFE_INTEGER;
755
+ var lr = 99;
756
+ var er = /* @__PURE__ */ Symbol("otplib.guardrails.override");
757
+ function y(r2, e, t2) {
758
+ if (typeof e != "number" || !Number.isSafeInteger(e)) throw new a(`Guardrail '${r2}' must be a safe integer`);
759
+ if (e < t2) throw new a(`Guardrail '${r2}' must be >= ${t2}`);
760
+ }
761
+ var d = Object.freeze({ MIN_SECRET_BYTES: or, MAX_SECRET_BYTES: sr, MIN_PERIOD: ar, MAX_PERIOD: ur, MAX_COUNTER: pr, MAX_WINDOW: lr, [er]: false });
762
+ function hr(r2) {
763
+ if (!r2) return d;
764
+ r2.MIN_SECRET_BYTES !== void 0 && y("MIN_SECRET_BYTES", r2.MIN_SECRET_BYTES, 1), r2.MAX_SECRET_BYTES !== void 0 && y("MAX_SECRET_BYTES", r2.MAX_SECRET_BYTES, 1), r2.MIN_PERIOD !== void 0 && y("MIN_PERIOD", r2.MIN_PERIOD, 1), r2.MAX_PERIOD !== void 0 && y("MAX_PERIOD", r2.MAX_PERIOD, 1), r2.MAX_COUNTER !== void 0 && y("MAX_COUNTER", r2.MAX_COUNTER, 0), r2.MAX_WINDOW !== void 0 && y("MAX_WINDOW", r2.MAX_WINDOW, 1);
765
+ let e = { ...d, ...r2 };
766
+ if (e.MIN_SECRET_BYTES > e.MAX_SECRET_BYTES) throw new a("Guardrail 'MIN_SECRET_BYTES' must be <= 'MAX_SECRET_BYTES'");
767
+ if (e.MIN_PERIOD > e.MAX_PERIOD) throw new a("Guardrail 'MIN_PERIOD' must be <= 'MAX_PERIOD'");
768
+ return Object.freeze({ ...e, [er]: true });
769
+ }
770
+ function Or(r2, e = d) {
771
+ if (r2.length < e.MIN_SECRET_BYTES) throw new h(e.MIN_SECRET_BYTES, r2.length);
772
+ if (r2.length > e.MAX_SECRET_BYTES) throw new P(e.MAX_SECRET_BYTES, r2.length);
773
+ }
774
+ function br(r2, e = d) {
775
+ if (typeof r2 == "number") {
776
+ if (!Number.isFinite(r2) || !Number.isInteger(r2)) throw new b();
777
+ if (!Number.isSafeInteger(r2)) throw new T();
778
+ }
779
+ let t2 = typeof r2 == "bigint" ? r2 : BigInt(r2);
780
+ if (t2 < 0n) throw new O();
781
+ if (t2 > BigInt(e.MAX_COUNTER)) throw new T();
782
+ }
783
+ function Ar(r2) {
784
+ if (!Number.isFinite(r2)) throw new S();
785
+ if (r2 < 0) throw new C();
786
+ }
787
+ function Cr(r2, e = d) {
788
+ if (!Number.isInteger(r2) || r2 < e.MIN_PERIOD) throw new w(e.MIN_PERIOD);
789
+ if (r2 > e.MAX_PERIOD) throw new _(e.MAX_PERIOD);
790
+ }
791
+ function Sr(r2, e) {
792
+ if (r2.length !== e) throw new I(e, r2.length);
793
+ if (!/^\d+$/.test(r2)) throw new M();
794
+ }
795
+ function Br(r2, e = d) {
796
+ let [t2, o] = Er(r2);
797
+ if (!Number.isSafeInteger(t2) || !Number.isSafeInteger(o)) throw new g("Counter tolerance values must be safe integers");
798
+ if (t2 < 0 || o < 0) throw new X();
799
+ let n = t2 + o + 1;
800
+ if (n > e.MAX_WINDOW) throw new U(e.MAX_WINDOW, n);
801
+ }
802
+ function wr(r2, e = cr, t2 = d) {
803
+ let [o, n] = Array.isArray(r2) ? r2 : [r2, r2];
804
+ if (!Number.isSafeInteger(o) || !Number.isSafeInteger(n)) throw new E("Epoch tolerance values must be safe integers");
805
+ if (o < 0 || n < 0) throw new k();
806
+ let s = (t2.MAX_WINDOW - 1) * e, u = o + n;
807
+ if (u > s) throw new q(s, u);
808
+ }
809
+ function _r(r2) {
810
+ let e = typeof r2 == "bigint" ? r2 : BigInt(r2), t2 = new ArrayBuffer(8);
811
+ return new DataView(t2).setBigUint64(0, e, false), new Uint8Array(t2);
812
+ }
813
+ function Rr(r2) {
814
+ let e = r2[r2.length - 1] & 15;
815
+ return (r2[e] & 127) << 24 | r2[e + 1] << 16 | r2[e + 2] << 8 | r2[e + 3];
816
+ }
817
+ function Ir(r2, e) {
818
+ let t2 = 10 ** e;
819
+ return (r2 % t2).toString().padStart(e, "0");
820
+ }
821
+ function gr(r2, e) {
822
+ return r2.length === e.length;
823
+ }
824
+ function tr(r2, e) {
825
+ let t2 = rr(r2), o = rr(e);
826
+ if (!gr(t2, o)) return false;
827
+ let n = 0;
828
+ for (let s = 0; s < t2.length; s++) n |= t2[s] ^ o[s];
829
+ return n === 0;
830
+ }
831
+ function rr(r2) {
832
+ return typeof r2 == "string" ? yr.encode(r2) : r2;
833
+ }
834
+ function vr(r2, e) {
835
+ return typeof r2 == "string" ? (nr(e), e.decode(r2)) : r2;
836
+ }
837
+ function Dr(r2) {
838
+ let { crypto: e, base32: t2, length: o = ir } = r2;
839
+ dr(e), nr(t2);
840
+ let n = e.randomBytes(o);
841
+ return t2.encode(n, { padding: false });
842
+ }
843
+ function Er(r2 = 0) {
844
+ return Array.isArray(r2) ? r2 : [0, r2];
845
+ }
846
+ function Ur(r2 = 0) {
847
+ return Array.isArray(r2) ? r2 : [r2, r2];
848
+ }
849
+ function dr(r2) {
850
+ if (!r2) throw new Y();
851
+ }
852
+ function nr(r2) {
853
+ if (!r2) throw new L();
854
+ }
855
+ function Xr(r2) {
856
+ if (!r2) throw new W();
857
+ }
858
+ var K = class {
859
+ constructor(e) {
860
+ this.crypto = e;
861
+ }
862
+ get plugin() {
863
+ return this.crypto;
864
+ }
865
+ async hmac(e, t2, o) {
866
+ try {
867
+ let n = this.crypto.hmac(e, t2, o);
868
+ return n instanceof Promise ? await n : n;
869
+ } catch (n) {
870
+ let s = n instanceof Error ? n.message : String(n);
871
+ throw new c(s, { cause: n });
872
+ }
873
+ }
874
+ hmacSync(e, t2, o) {
875
+ try {
876
+ let n = this.crypto.hmac(e, t2, o);
877
+ if (n instanceof Promise) throw new c("Crypto plugin does not support synchronous HMAC operations");
878
+ return n;
879
+ } catch (n) {
880
+ if (n instanceof c) throw n;
881
+ let s = n instanceof Error ? n.message : String(n);
882
+ throw new c(s, { cause: n });
883
+ }
884
+ }
885
+ randomBytes(e) {
886
+ try {
887
+ return this.crypto.randomBytes(e);
888
+ } catch (t2) {
889
+ let o = t2 instanceof Error ? t2.message : String(t2);
890
+ throw new v(o, { cause: t2 });
891
+ }
892
+ }
893
+ };
894
+ function Wr(r2) {
895
+ return new K(r2);
896
+ }
897
+
898
+ // ../../node_modules/.pnpm/@otplib+uri@13.4.0/node_modules/@otplib/uri/dist/index.js
899
+ function m2(r2) {
900
+ let { type: e, label: s, params: t2 } = r2, i2 = s.split(":").map((c3) => encodeURIComponent(c3)).join(":"), o = `otpauth://${e}/${i2}?`, n = [];
901
+ return t2.secret && n.push(`secret=${encodeURIComponent(t2.secret)}`), t2.issuer && n.push(`issuer=${encodeURIComponent(t2.issuer)}`), t2.algorithm && t2.algorithm !== "sha1" && n.push(`algorithm=${t2.algorithm.toUpperCase()}`), t2.digits && t2.digits !== 6 && n.push(`digits=${t2.digits}`), e === "hotp" && t2.counter !== void 0 && n.push(`counter=${t2.counter}`), e === "totp" && t2.period !== void 0 && t2.period !== 30 && n.push(`period=${t2.period}`), o += n.join("&"), o;
902
+ }
903
+ function x2(r2) {
904
+ let { issuer: e, label: s, secret: t2, algorithm: i2 = "sha1", digits: o = 6, period: n = 30 } = r2, c3 = e ? `${e}:${s}` : s;
905
+ return m2({ type: "totp", label: c3, params: { secret: t2, issuer: e, algorithm: i2, digits: o, period: n } });
906
+ }
907
+ function U2(r2) {
908
+ let { issuer: e, label: s, secret: t2, counter: i2 = 0, algorithm: o = "sha1", digits: n = 6 } = r2, c3 = e ? `${e}:${s}` : s;
909
+ return m2({ type: "hotp", label: c3, params: { secret: t2, issuer: e, algorithm: o, digits: n, counter: i2 } });
910
+ }
911
+
912
+ // ../../node_modules/.pnpm/@otplib+hotp@13.4.0/node_modules/@otplib/hotp/dist/index.js
913
+ function v2(u) {
914
+ let { secret: t2, counter: e, algorithm: r2 = "sha1", digits: i2 = 6, crypto: n, base32: o, guardrails: a2, hooks: s } = u;
915
+ Xr(t2), dr(n);
916
+ let c3 = vr(t2, o);
917
+ Or(c3, a2), br(e, a2);
918
+ let p = Wr(n), l2 = _r(e);
919
+ return { ctx: p, algorithm: r2, digits: i2, secretBytes: c3, counterBytes: l2, hooks: s };
920
+ }
921
+ function F(u) {
922
+ let { ctx: t2, algorithm: e, digits: r2, secretBytes: i2, counterBytes: n, hooks: o } = v2(u), a2 = t2.hmacSync(e, i2, n), s = o?.truncateDigest ? o.truncateDigest(a2) : Rr(a2);
923
+ return o?.encodeToken ? o.encodeToken(s, r2) : Ir(s, r2);
924
+ }
925
+ function G2(u) {
926
+ let { secret: t2, counter: e, token: r2, algorithm: i2 = "sha1", digits: n = 6, crypto: o, base32: a2, counterTolerance: s = 0, guardrails: c3 = hr(), hooks: p } = u;
927
+ Xr(t2), dr(o);
928
+ let l2 = vr(t2, a2);
929
+ Or(l2, c3), br(e, c3), p?.validateToken ? p.validateToken(r2, n) : Sr(r2, n), Br(s, c3);
930
+ let V = typeof e == "bigint" ? Number(e) : e, [f2, d4] = Er(s), R3 = f2 + d4 + 1;
931
+ return { token: r2, counterNum: V, past: f2, future: d4, totalChecks: R3, crypto: o, getGenerateOptions: (B2) => ({ secret: l2, counter: B2, algorithm: i2, digits: n, crypto: o, guardrails: c3, hooks: p }) };
932
+ }
933
+ function Y2(u) {
934
+ let { token: t2, counterNum: e, past: r2, totalChecks: i2, crypto: n, getGenerateOptions: o } = G2(u), a2 = Math.max(0, r2 - e);
935
+ for (let s = a2; s < i2; s++) {
936
+ let c3 = s - r2, p = e + c3, l2 = F(o(p));
937
+ if (n.constantTimeEqual(l2, t2)) return { valid: true, delta: c3 | 0 };
938
+ }
939
+ return { valid: false };
940
+ }
941
+
942
+ // ../../node_modules/.pnpm/@otplib+totp@13.4.0/node_modules/@otplib/totp/dist/index.js
943
+ function k2(r2) {
944
+ let { secret: e, epoch: n = Math.floor(Date.now() / 1e3), t0: o = 0, period: i2 = 30, algorithm: s = "sha1", digits: l2 = 6, crypto: a2, base32: u, guardrails: c3 = hr(), hooks: t2 } = r2;
945
+ Xr(e), dr(a2);
946
+ let p = vr(e, u);
947
+ Or(p, c3), Ar(n), Cr(i2, c3);
948
+ let f2 = Math.floor((n - o) / i2);
949
+ return { secret: p, counter: f2, algorithm: s, digits: l2, crypto: a2, guardrails: c3, hooks: t2 };
950
+ }
951
+ function Z2(r2) {
952
+ let e = k2(r2);
953
+ return F(e);
954
+ }
955
+ function _2(r2, e) {
956
+ if (r2 !== void 0) {
957
+ if (r2 < 0) throw new J();
958
+ if (!Number.isSafeInteger(r2)) throw new Q();
959
+ if (r2 > e) throw new Z();
960
+ }
961
+ }
962
+ function w2(r2, e) {
963
+ return e !== void 0 && r2 <= e;
964
+ }
965
+ function R2(r2) {
966
+ let { secret: e, token: n, epoch: o = Math.floor(Date.now() / 1e3), t0: i2 = 0, period: s = 30, algorithm: l2 = "sha1", digits: a2 = 6, crypto: u, base32: c3, epochTolerance: t2 = 0, afterTimeStep: p, guardrails: f2 = hr(), hooks: T3 } = r2;
967
+ Xr(e), dr(u);
968
+ let m3 = vr(e, c3);
969
+ Or(m3, f2), Ar(o), Cr(s, f2), T3?.validateToken ? T3.validateToken(n, a2) : Sr(n, a2), wr(t2, s, f2);
970
+ let M2 = Math.floor((o - i2) / s), [I3, q2] = Ur(t2), A3 = Math.max(0, Math.floor((o - I3 - i2) / s)), S2 = Math.floor((o + q2 - i2) / s);
971
+ return _2(p, S2), { token: n, crypto: u, minCounter: A3, maxCounter: S2, currentCounter: M2, t0: i2, period: s, afterTimeStep: p, getGenerateOptions: (D) => ({ secret: m3, epoch: D * s + i2, t0: i2, period: s, algorithm: l2, digits: a2, crypto: u, guardrails: f2, hooks: T3 }) };
972
+ }
973
+ function ie(r2) {
974
+ let { token: e, crypto: n, minCounter: o, maxCounter: i2, currentCounter: s, t0: l2, period: a2, afterTimeStep: u, getGenerateOptions: c3 } = R2(r2);
975
+ for (let t2 = o; t2 <= i2; t2++) {
976
+ if (w2(t2, u)) continue;
977
+ let p = Z2(c3(t2));
978
+ if (n.constantTimeEqual(p, e)) return { valid: true, delta: t2 - s, epoch: t2 * a2 + l2, timeStep: t2 };
979
+ }
980
+ return { valid: false };
981
+ }
982
+
983
+ // ../../node_modules/.pnpm/@scure+base@2.2.0/node_modules/@scure/base/index.js
984
+ function isBytes(a2) {
985
+ return a2 instanceof Uint8Array || ArrayBuffer.isView(a2) && a2.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a2 && a2.BYTES_PER_ELEMENT === 1;
986
+ }
987
+ function isArrayOf(isString, arr) {
988
+ if (!Array.isArray(arr))
989
+ return false;
990
+ if (arr.length === 0)
991
+ return true;
992
+ if (isString) {
993
+ return arr.every((item) => typeof item === "string");
994
+ } else {
995
+ return arr.every((item) => Number.isSafeInteger(item));
996
+ }
997
+ }
998
+ function astr(label, input) {
999
+ if (typeof input !== "string")
1000
+ throw new TypeError(`${label}: string expected`);
1001
+ return true;
1002
+ }
1003
+ function anumber(n) {
1004
+ if (typeof n !== "number")
1005
+ throw new TypeError(`number expected, got ${typeof n}`);
1006
+ if (!Number.isSafeInteger(n))
1007
+ throw new RangeError(`invalid integer: ${n}`);
1008
+ }
1009
+ function aArr(input) {
1010
+ if (!Array.isArray(input))
1011
+ throw new TypeError("array expected");
1012
+ }
1013
+ function astrArr(label, input) {
1014
+ if (!isArrayOf(true, input))
1015
+ throw new TypeError(`${label}: array of strings expected`);
1016
+ }
1017
+ function anumArr(label, input) {
1018
+ if (!isArrayOf(false, input))
1019
+ throw new TypeError(`${label}: array of numbers expected`);
1020
+ }
1021
+ // @__NO_SIDE_EFFECTS__
1022
+ function chain(...args) {
1023
+ const id = (a2) => a2;
1024
+ const wrap = (a2, b3) => (c3) => a2(b3(c3));
1025
+ const encode = args.map((x4) => x4.encode).reduceRight(wrap, id);
1026
+ const decode = args.map((x4) => x4.decode).reduce(wrap, id);
1027
+ return { encode, decode };
1028
+ }
1029
+ // @__NO_SIDE_EFFECTS__
1030
+ function alphabet(letters) {
1031
+ const lettersA = typeof letters === "string" ? letters.split("") : letters;
1032
+ const len = lettersA.length;
1033
+ astrArr("alphabet", lettersA);
1034
+ const indexes = new Map(lettersA.map((l2, i2) => [l2, i2]));
1035
+ return {
1036
+ encode: (digits) => {
1037
+ aArr(digits);
1038
+ return digits.map((i2) => {
1039
+ if (!Number.isSafeInteger(i2) || i2 < 0 || i2 >= len)
1040
+ throw new Error(`alphabet.encode: digit index outside alphabet "${i2}". Allowed: ${letters}`);
1041
+ return lettersA[i2];
1042
+ });
1043
+ },
1044
+ decode: (input) => {
1045
+ aArr(input);
1046
+ return input.map((letter) => {
1047
+ astr("alphabet.decode", letter);
1048
+ const i2 = indexes.get(letter);
1049
+ if (i2 === void 0)
1050
+ throw new Error(`Unknown letter: "${letter}". Allowed: ${letters}`);
1051
+ return i2;
1052
+ });
1053
+ }
1054
+ };
1055
+ }
1056
+ // @__NO_SIDE_EFFECTS__
1057
+ function join2(separator = "") {
1058
+ astr("join", separator);
1059
+ return {
1060
+ encode: (from) => {
1061
+ astrArr("join.decode", from);
1062
+ return from.join(separator);
1063
+ },
1064
+ decode: (to) => {
1065
+ astr("join.decode", to);
1066
+ return to.split(separator);
1067
+ }
1068
+ };
1069
+ }
1070
+ // @__NO_SIDE_EFFECTS__
1071
+ function padding(bits, chr = "=") {
1072
+ anumber(bits);
1073
+ astr("padding", chr);
1074
+ return {
1075
+ encode(data) {
1076
+ astrArr("padding.encode", data);
1077
+ while (data.length * bits % 8)
1078
+ data.push(chr);
1079
+ return data;
1080
+ },
1081
+ decode(input) {
1082
+ astrArr("padding.decode", input);
1083
+ let end = input.length;
1084
+ if (end * bits % 8)
1085
+ throw new Error("padding: invalid, string should have whole number of bytes");
1086
+ for (; end > 0 && input[end - 1] === chr; end--) {
1087
+ const last = end - 1;
1088
+ const byte = last * bits;
1089
+ if (byte % 8 === 0)
1090
+ throw new Error("padding: invalid, string has too much padding");
1091
+ }
1092
+ return input.slice(0, end);
1093
+ }
1094
+ };
1095
+ }
1096
+ var gcd = (a2, b3) => b3 === 0 ? a2 : gcd(b3, a2 % b3);
1097
+ var radix2carry = /* @__NO_SIDE_EFFECTS__ */ (from, to) => from + (to - gcd(from, to));
1098
+ var powers = /* @__PURE__ */ (() => {
1099
+ let res = [];
1100
+ for (let i2 = 0; i2 < 40; i2++)
1101
+ res.push(2 ** i2);
1102
+ return res;
1103
+ })();
1104
+ function convertRadix2(data, from, to, padding2) {
1105
+ aArr(data);
1106
+ if (from <= 0 || from > 32)
1107
+ throw new RangeError(`convertRadix2: wrong from=${from}`);
1108
+ if (to <= 0 || to > 32)
1109
+ throw new RangeError(`convertRadix2: wrong to=${to}`);
1110
+ if (/* @__PURE__ */ radix2carry(from, to) > 32) {
1111
+ throw new Error(`convertRadix2: carry overflow from=${from} to=${to} carryBits=${/* @__PURE__ */ radix2carry(from, to)}`);
1112
+ }
1113
+ let carry = 0;
1114
+ let pos = 0;
1115
+ const max = powers[from];
1116
+ const mask = powers[to] - 1;
1117
+ const res = [];
1118
+ for (const n of data) {
1119
+ anumber(n);
1120
+ if (n >= max)
1121
+ throw new Error(`convertRadix2: invalid data word=${n} from=${from}`);
1122
+ carry = carry << from | n;
1123
+ if (pos + from > 32)
1124
+ throw new Error(`convertRadix2: carry overflow pos=${pos} from=${from}`);
1125
+ pos += from;
1126
+ for (; pos >= to; pos -= to)
1127
+ res.push((carry >> pos - to & mask) >>> 0);
1128
+ const pow = powers[pos];
1129
+ if (pow === void 0)
1130
+ throw new Error("invalid carry");
1131
+ carry &= pow - 1;
1132
+ }
1133
+ carry = carry << to - pos & mask;
1134
+ if (!padding2 && pos >= from)
1135
+ throw new Error("Excess padding");
1136
+ if (!padding2 && carry > 0)
1137
+ throw new Error(`Non-zero padding: ${carry}`);
1138
+ if (padding2 && pos > 0)
1139
+ res.push(carry >>> 0);
1140
+ return res;
1141
+ }
1142
+ // @__NO_SIDE_EFFECTS__
1143
+ function radix2(bits, revPadding = false) {
1144
+ anumber(bits);
1145
+ if (bits <= 0 || bits > 32)
1146
+ throw new RangeError("radix2: bits should be in (0..32]");
1147
+ if (/* @__PURE__ */ radix2carry(8, bits) > 32 || /* @__PURE__ */ radix2carry(bits, 8) > 32)
1148
+ throw new RangeError("radix2: carry overflow");
1149
+ return {
1150
+ encode: (bytes) => {
1151
+ if (!isBytes(bytes))
1152
+ throw new TypeError("radix2.encode input should be Uint8Array");
1153
+ return convertRadix2(Array.from(bytes), 8, bits, !revPadding);
1154
+ },
1155
+ decode: (digits) => {
1156
+ anumArr("radix2.decode", digits);
1157
+ return Uint8Array.from(convertRadix2(digits, bits, 8, revPadding));
1158
+ }
1159
+ };
1160
+ }
1161
+ var base32 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ chain(/* @__PURE__ */ radix2(5), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), /* @__PURE__ */ padding(5), /* @__PURE__ */ join2("")));
1162
+
1163
+ // ../../node_modules/.pnpm/@otplib+plugin-base32-scure@13.4.0/node_modules/@otplib/plugin-base32-scure/dist/index.js
1164
+ var r = class {
1165
+ name = "scure";
1166
+ encode(o, e = {}) {
1167
+ let { padding: t2 = false } = e, n = base32.encode(o);
1168
+ return t2 ? n : n.replace(/=+$/, "");
1169
+ }
1170
+ decode(o) {
1171
+ try {
1172
+ let e = o.toUpperCase(), t2 = e.padEnd(Math.ceil(e.length / 8) * 8, "=");
1173
+ return base32.decode(t2);
1174
+ } catch (e) {
1175
+ throw e instanceof Error ? new Error(`Invalid Base32 string: ${e.message}`) : new Error("Invalid Base32 string");
1176
+ }
1177
+ }
1178
+ };
1179
+ var d2 = Object.freeze(new r());
1180
+
1181
+ // ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/utils.js
1182
+ function isBytes2(a2) {
1183
+ return a2 instanceof Uint8Array || ArrayBuffer.isView(a2) && a2.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a2 && a2.BYTES_PER_ELEMENT === 1;
1184
+ }
1185
+ function anumber2(n, title = "") {
1186
+ if (typeof n !== "number") {
1187
+ const prefix = title && `"${title}" `;
1188
+ throw new TypeError(`${prefix}expected number, got ${typeof n}`);
1189
+ }
1190
+ if (!Number.isSafeInteger(n) || n < 0) {
1191
+ const prefix = title && `"${title}" `;
1192
+ throw new RangeError(`${prefix}expected integer >= 0, got ${n}`);
1193
+ }
1194
+ }
1195
+ function abytes(value, length, title = "") {
1196
+ const bytes = isBytes2(value);
1197
+ const len = value?.length;
1198
+ const needsLen = length !== void 0;
1199
+ if (!bytes || needsLen && len !== length) {
1200
+ const prefix = title && `"${title}" `;
1201
+ const ofLen = needsLen ? ` of length ${length}` : "";
1202
+ const got = bytes ? `length=${len}` : `type=${typeof value}`;
1203
+ const message = prefix + "expected Uint8Array" + ofLen + ", got " + got;
1204
+ if (!bytes)
1205
+ throw new TypeError(message);
1206
+ throw new RangeError(message);
1207
+ }
1208
+ return value;
1209
+ }
1210
+ function ahash(h3) {
1211
+ if (typeof h3 !== "function" || typeof h3.create !== "function")
1212
+ throw new TypeError("Hash must wrapped by utils.createHasher");
1213
+ anumber2(h3.outputLen);
1214
+ anumber2(h3.blockLen);
1215
+ if (h3.outputLen < 1)
1216
+ throw new Error('"outputLen" must be >= 1');
1217
+ if (h3.blockLen < 1)
1218
+ throw new Error('"blockLen" must be >= 1');
1219
+ }
1220
+ function aexists(instance, checkFinished = true) {
1221
+ if (instance.destroyed)
1222
+ throw new Error("Hash instance has been destroyed");
1223
+ if (checkFinished && instance.finished)
1224
+ throw new Error("Hash#digest() has already been called");
1225
+ }
1226
+ function aoutput(out, instance) {
1227
+ abytes(out, void 0, "digestInto() output");
1228
+ const min = instance.outputLen;
1229
+ if (out.length < min) {
1230
+ throw new RangeError('"digestInto() output" expected to be of length >=' + min);
1231
+ }
1232
+ }
1233
+ function clean(...arrays) {
1234
+ for (let i2 = 0; i2 < arrays.length; i2++) {
1235
+ arrays[i2].fill(0);
1236
+ }
1237
+ }
1238
+ function createView(arr) {
1239
+ return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
1240
+ }
1241
+ function rotr(word, shift) {
1242
+ return word << 32 - shift | word >>> shift;
1243
+ }
1244
+ function rotl(word, shift) {
1245
+ return word << shift | word >>> 32 - shift >>> 0;
1246
+ }
1247
+ function createHasher(hashCons, info = {}) {
1248
+ const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
1249
+ const tmp = hashCons(void 0);
1250
+ hashC.outputLen = tmp.outputLen;
1251
+ hashC.blockLen = tmp.blockLen;
1252
+ hashC.canXOF = tmp.canXOF;
1253
+ hashC.create = (opts) => hashCons(opts);
1254
+ Object.assign(hashC, info);
1255
+ return Object.freeze(hashC);
1256
+ }
1257
+ function randomBytes(bytesLength = 32) {
1258
+ anumber2(bytesLength, "bytesLength");
1259
+ const cr2 = typeof globalThis === "object" ? globalThis.crypto : null;
1260
+ if (typeof cr2?.getRandomValues !== "function")
1261
+ throw new Error("crypto.getRandomValues must be defined");
1262
+ if (bytesLength > 65536)
1263
+ throw new RangeError(`"bytesLength" expected <= 65536, got ${bytesLength}`);
1264
+ return cr2.getRandomValues(new Uint8Array(bytesLength));
1265
+ }
1266
+ var oidNist = (suffix) => ({
1267
+ // Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet.
1268
+ // Larger suffix values would need base-128 OID encoding and a different length byte.
1269
+ oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
1270
+ });
1271
+
1272
+ // ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/hmac.js
1273
+ var _HMAC = class {
1274
+ oHash;
1275
+ iHash;
1276
+ blockLen;
1277
+ outputLen;
1278
+ canXOF = false;
1279
+ finished = false;
1280
+ destroyed = false;
1281
+ constructor(hash, key) {
1282
+ ahash(hash);
1283
+ abytes(key, void 0, "key");
1284
+ this.iHash = hash.create();
1285
+ if (typeof this.iHash.update !== "function")
1286
+ throw new Error("Expected instance of class which extends utils.Hash");
1287
+ this.blockLen = this.iHash.blockLen;
1288
+ this.outputLen = this.iHash.outputLen;
1289
+ const blockLen = this.blockLen;
1290
+ const pad = new Uint8Array(blockLen);
1291
+ pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
1292
+ for (let i2 = 0; i2 < pad.length; i2++)
1293
+ pad[i2] ^= 54;
1294
+ this.iHash.update(pad);
1295
+ this.oHash = hash.create();
1296
+ for (let i2 = 0; i2 < pad.length; i2++)
1297
+ pad[i2] ^= 54 ^ 92;
1298
+ this.oHash.update(pad);
1299
+ clean(pad);
1300
+ }
1301
+ update(buf) {
1302
+ aexists(this);
1303
+ this.iHash.update(buf);
1304
+ return this;
1305
+ }
1306
+ digestInto(out) {
1307
+ aexists(this);
1308
+ aoutput(out, this);
1309
+ this.finished = true;
1310
+ const buf = out.subarray(0, this.outputLen);
1311
+ this.iHash.digestInto(buf);
1312
+ this.oHash.update(buf);
1313
+ this.oHash.digestInto(buf);
1314
+ this.destroy();
1315
+ }
1316
+ digest() {
1317
+ const out = new Uint8Array(this.oHash.outputLen);
1318
+ this.digestInto(out);
1319
+ return out;
1320
+ }
1321
+ _cloneInto(to) {
1322
+ to ||= Object.create(Object.getPrototypeOf(this), {});
1323
+ const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
1324
+ to = to;
1325
+ to.finished = finished;
1326
+ to.destroyed = destroyed;
1327
+ to.blockLen = blockLen;
1328
+ to.outputLen = outputLen;
1329
+ to.oHash = oHash._cloneInto(to.oHash);
1330
+ to.iHash = iHash._cloneInto(to.iHash);
1331
+ return to;
1332
+ }
1333
+ clone() {
1334
+ return this._cloneInto();
1335
+ }
1336
+ destroy() {
1337
+ this.destroyed = true;
1338
+ this.oHash.destroy();
1339
+ this.iHash.destroy();
1340
+ }
1341
+ };
1342
+ var hmac = /* @__PURE__ */ (() => {
1343
+ const hmac_ = ((hash, key, message) => new _HMAC(hash, key).update(message).digest());
1344
+ hmac_.create = (hash, key) => new _HMAC(hash, key);
1345
+ return hmac_;
1346
+ })();
1347
+
1348
+ // ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/_md.js
1349
+ function Chi(a2, b3, c3) {
1350
+ return a2 & b3 ^ ~a2 & c3;
1351
+ }
1352
+ function Maj(a2, b3, c3) {
1353
+ return a2 & b3 ^ a2 & c3 ^ b3 & c3;
1354
+ }
1355
+ var HashMD = class {
1356
+ blockLen;
1357
+ outputLen;
1358
+ canXOF = false;
1359
+ padOffset;
1360
+ isLE;
1361
+ // For partial updates less than block size
1362
+ buffer;
1363
+ view;
1364
+ finished = false;
1365
+ length = 0;
1366
+ pos = 0;
1367
+ destroyed = false;
1368
+ constructor(blockLen, outputLen, padOffset, isLE) {
1369
+ this.blockLen = blockLen;
1370
+ this.outputLen = outputLen;
1371
+ this.padOffset = padOffset;
1372
+ this.isLE = isLE;
1373
+ this.buffer = new Uint8Array(blockLen);
1374
+ this.view = createView(this.buffer);
1375
+ }
1376
+ update(data) {
1377
+ aexists(this);
1378
+ abytes(data);
1379
+ const { view, buffer, blockLen } = this;
1380
+ const len = data.length;
1381
+ for (let pos = 0; pos < len; ) {
1382
+ const take = Math.min(blockLen - this.pos, len - pos);
1383
+ if (take === blockLen) {
1384
+ const dataView = createView(data);
1385
+ for (; blockLen <= len - pos; pos += blockLen)
1386
+ this.process(dataView, pos);
1387
+ continue;
1388
+ }
1389
+ buffer.set(data.subarray(pos, pos + take), this.pos);
1390
+ this.pos += take;
1391
+ pos += take;
1392
+ if (this.pos === blockLen) {
1393
+ this.process(view, 0);
1394
+ this.pos = 0;
1395
+ }
1396
+ }
1397
+ this.length += data.length;
1398
+ this.roundClean();
1399
+ return this;
1400
+ }
1401
+ digestInto(out) {
1402
+ aexists(this);
1403
+ aoutput(out, this);
1404
+ this.finished = true;
1405
+ const { buffer, view, blockLen, isLE } = this;
1406
+ let { pos } = this;
1407
+ buffer[pos++] = 128;
1408
+ clean(this.buffer.subarray(pos));
1409
+ if (this.padOffset > blockLen - pos) {
1410
+ this.process(view, 0);
1411
+ pos = 0;
1412
+ }
1413
+ for (let i2 = pos; i2 < blockLen; i2++)
1414
+ buffer[i2] = 0;
1415
+ view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
1416
+ this.process(view, 0);
1417
+ const oview = createView(out);
1418
+ const len = this.outputLen;
1419
+ if (len % 4)
1420
+ throw new Error("_sha2: outputLen must be aligned to 32bit");
1421
+ const outLen = len / 4;
1422
+ const state = this.get();
1423
+ if (outLen > state.length)
1424
+ throw new Error("_sha2: outputLen bigger than state");
1425
+ for (let i2 = 0; i2 < outLen; i2++)
1426
+ oview.setUint32(4 * i2, state[i2], isLE);
1427
+ }
1428
+ digest() {
1429
+ const { buffer, outputLen } = this;
1430
+ this.digestInto(buffer);
1431
+ const res = buffer.slice(0, outputLen);
1432
+ this.destroy();
1433
+ return res;
1434
+ }
1435
+ _cloneInto(to) {
1436
+ to ||= new this.constructor();
1437
+ to.set(...this.get());
1438
+ const { blockLen, buffer, length, finished, destroyed, pos } = this;
1439
+ to.destroyed = destroyed;
1440
+ to.finished = finished;
1441
+ to.length = length;
1442
+ to.pos = pos;
1443
+ if (length % blockLen)
1444
+ to.buffer.set(buffer);
1445
+ return to;
1446
+ }
1447
+ clone() {
1448
+ return this._cloneInto();
1449
+ }
1450
+ };
1451
+ var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
1452
+ 1779033703,
1453
+ 3144134277,
1454
+ 1013904242,
1455
+ 2773480762,
1456
+ 1359893119,
1457
+ 2600822924,
1458
+ 528734635,
1459
+ 1541459225
1460
+ ]);
1461
+ var SHA512_IV = /* @__PURE__ */ Uint32Array.from([
1462
+ 1779033703,
1463
+ 4089235720,
1464
+ 3144134277,
1465
+ 2227873595,
1466
+ 1013904242,
1467
+ 4271175723,
1468
+ 2773480762,
1469
+ 1595750129,
1470
+ 1359893119,
1471
+ 2917565137,
1472
+ 2600822924,
1473
+ 725511199,
1474
+ 528734635,
1475
+ 4215389547,
1476
+ 1541459225,
1477
+ 327033209
1478
+ ]);
1479
+
1480
+ // ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/legacy.js
1481
+ var SHA1_IV = /* @__PURE__ */ Uint32Array.from([
1482
+ 1732584193,
1483
+ 4023233417,
1484
+ 2562383102,
1485
+ 271733878,
1486
+ 3285377520
1487
+ ]);
1488
+ var SHA1_W = /* @__PURE__ */ new Uint32Array(80);
1489
+ var _SHA1 = class extends HashMD {
1490
+ A = SHA1_IV[0] | 0;
1491
+ B = SHA1_IV[1] | 0;
1492
+ C = SHA1_IV[2] | 0;
1493
+ D = SHA1_IV[3] | 0;
1494
+ E = SHA1_IV[4] | 0;
1495
+ constructor() {
1496
+ super(64, 20, 8, false);
1497
+ }
1498
+ get() {
1499
+ const { A: A3, B: B2, C: C2, D, E: E2 } = this;
1500
+ return [A3, B2, C2, D, E2];
1501
+ }
1502
+ set(A3, B2, C2, D, E2) {
1503
+ this.A = A3 | 0;
1504
+ this.B = B2 | 0;
1505
+ this.C = C2 | 0;
1506
+ this.D = D | 0;
1507
+ this.E = E2 | 0;
1508
+ }
1509
+ process(view, offset) {
1510
+ for (let i2 = 0; i2 < 16; i2++, offset += 4)
1511
+ SHA1_W[i2] = view.getUint32(offset, false);
1512
+ for (let i2 = 16; i2 < 80; i2++)
1513
+ SHA1_W[i2] = rotl(SHA1_W[i2 - 3] ^ SHA1_W[i2 - 8] ^ SHA1_W[i2 - 14] ^ SHA1_W[i2 - 16], 1);
1514
+ let { A: A3, B: B2, C: C2, D, E: E2 } = this;
1515
+ for (let i2 = 0; i2 < 80; i2++) {
1516
+ let F2, K2;
1517
+ if (i2 < 20) {
1518
+ F2 = Chi(B2, C2, D);
1519
+ K2 = 1518500249;
1520
+ } else if (i2 < 40) {
1521
+ F2 = B2 ^ C2 ^ D;
1522
+ K2 = 1859775393;
1523
+ } else if (i2 < 60) {
1524
+ F2 = Maj(B2, C2, D);
1525
+ K2 = 2400959708;
1526
+ } else {
1527
+ F2 = B2 ^ C2 ^ D;
1528
+ K2 = 3395469782;
1529
+ }
1530
+ const T3 = rotl(A3, 5) + F2 + E2 + K2 + SHA1_W[i2] | 0;
1531
+ E2 = D;
1532
+ D = C2;
1533
+ C2 = rotl(B2, 30);
1534
+ B2 = A3;
1535
+ A3 = T3;
1536
+ }
1537
+ A3 = A3 + this.A | 0;
1538
+ B2 = B2 + this.B | 0;
1539
+ C2 = C2 + this.C | 0;
1540
+ D = D + this.D | 0;
1541
+ E2 = E2 + this.E | 0;
1542
+ this.set(A3, B2, C2, D, E2);
1543
+ }
1544
+ roundClean() {
1545
+ clean(SHA1_W);
1546
+ }
1547
+ destroy() {
1548
+ this.destroyed = true;
1549
+ this.set(0, 0, 0, 0, 0);
1550
+ clean(this.buffer);
1551
+ }
1552
+ };
1553
+ var sha1 = /* @__PURE__ */ createHasher(() => new _SHA1());
1554
+
1555
+ // ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/_u64.js
1556
+ var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
1557
+ var _32n = /* @__PURE__ */ BigInt(32);
1558
+ function fromBig(n, le = false) {
1559
+ if (le)
1560
+ return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
1561
+ return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
1562
+ }
1563
+ function split(lst, le = false) {
1564
+ const len = lst.length;
1565
+ let Ah = new Uint32Array(len);
1566
+ let Al = new Uint32Array(len);
1567
+ for (let i2 = 0; i2 < len; i2++) {
1568
+ const { h: h3, l: l2 } = fromBig(lst[i2], le);
1569
+ [Ah[i2], Al[i2]] = [h3, l2];
1570
+ }
1571
+ return [Ah, Al];
1572
+ }
1573
+ var shrSH = (h3, _l, s) => h3 >>> s;
1574
+ var shrSL = (h3, l2, s) => h3 << 32 - s | l2 >>> s;
1575
+ var rotrSH = (h3, l2, s) => h3 >>> s | l2 << 32 - s;
1576
+ var rotrSL = (h3, l2, s) => h3 << 32 - s | l2 >>> s;
1577
+ var rotrBH = (h3, l2, s) => h3 << 64 - s | l2 >>> s - 32;
1578
+ var rotrBL = (h3, l2, s) => h3 >>> s - 32 | l2 << 64 - s;
1579
+ function add(Ah, Al, Bh, Bl) {
1580
+ const l2 = (Al >>> 0) + (Bl >>> 0);
1581
+ return { h: Ah + Bh + (l2 / 2 ** 32 | 0) | 0, l: l2 | 0 };
1582
+ }
1583
+ var add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);
1584
+ var add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0;
1585
+ var add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);
1586
+ var add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0;
1587
+ var add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
1588
+ var add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0;
1589
+
1590
+ // ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/sha2.js
1591
+ var SHA256_K = /* @__PURE__ */ Uint32Array.from([
1592
+ 1116352408,
1593
+ 1899447441,
1594
+ 3049323471,
1595
+ 3921009573,
1596
+ 961987163,
1597
+ 1508970993,
1598
+ 2453635748,
1599
+ 2870763221,
1600
+ 3624381080,
1601
+ 310598401,
1602
+ 607225278,
1603
+ 1426881987,
1604
+ 1925078388,
1605
+ 2162078206,
1606
+ 2614888103,
1607
+ 3248222580,
1608
+ 3835390401,
1609
+ 4022224774,
1610
+ 264347078,
1611
+ 604807628,
1612
+ 770255983,
1613
+ 1249150122,
1614
+ 1555081692,
1615
+ 1996064986,
1616
+ 2554220882,
1617
+ 2821834349,
1618
+ 2952996808,
1619
+ 3210313671,
1620
+ 3336571891,
1621
+ 3584528711,
1622
+ 113926993,
1623
+ 338241895,
1624
+ 666307205,
1625
+ 773529912,
1626
+ 1294757372,
1627
+ 1396182291,
1628
+ 1695183700,
1629
+ 1986661051,
1630
+ 2177026350,
1631
+ 2456956037,
1632
+ 2730485921,
1633
+ 2820302411,
1634
+ 3259730800,
1635
+ 3345764771,
1636
+ 3516065817,
1637
+ 3600352804,
1638
+ 4094571909,
1639
+ 275423344,
1640
+ 430227734,
1641
+ 506948616,
1642
+ 659060556,
1643
+ 883997877,
1644
+ 958139571,
1645
+ 1322822218,
1646
+ 1537002063,
1647
+ 1747873779,
1648
+ 1955562222,
1649
+ 2024104815,
1650
+ 2227730452,
1651
+ 2361852424,
1652
+ 2428436474,
1653
+ 2756734187,
1654
+ 3204031479,
1655
+ 3329325298
1656
+ ]);
1657
+ var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
1658
+ var SHA2_32B = class extends HashMD {
1659
+ constructor(outputLen) {
1660
+ super(64, outputLen, 8, false);
1661
+ }
1662
+ get() {
1663
+ const { A: A3, B: B2, C: C2, D, E: E2, F: F2, G: G3, H } = this;
1664
+ return [A3, B2, C2, D, E2, F2, G3, H];
1665
+ }
1666
+ // prettier-ignore
1667
+ set(A3, B2, C2, D, E2, F2, G3, H) {
1668
+ this.A = A3 | 0;
1669
+ this.B = B2 | 0;
1670
+ this.C = C2 | 0;
1671
+ this.D = D | 0;
1672
+ this.E = E2 | 0;
1673
+ this.F = F2 | 0;
1674
+ this.G = G3 | 0;
1675
+ this.H = H | 0;
1676
+ }
1677
+ process(view, offset) {
1678
+ for (let i2 = 0; i2 < 16; i2++, offset += 4)
1679
+ SHA256_W[i2] = view.getUint32(offset, false);
1680
+ for (let i2 = 16; i2 < 64; i2++) {
1681
+ const W15 = SHA256_W[i2 - 15];
1682
+ const W2 = SHA256_W[i2 - 2];
1683
+ const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
1684
+ const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
1685
+ SHA256_W[i2] = s1 + SHA256_W[i2 - 7] + s0 + SHA256_W[i2 - 16] | 0;
1686
+ }
1687
+ let { A: A3, B: B2, C: C2, D, E: E2, F: F2, G: G3, H } = this;
1688
+ for (let i2 = 0; i2 < 64; i2++) {
1689
+ const sigma1 = rotr(E2, 6) ^ rotr(E2, 11) ^ rotr(E2, 25);
1690
+ const T1 = H + sigma1 + Chi(E2, F2, G3) + SHA256_K[i2] + SHA256_W[i2] | 0;
1691
+ const sigma0 = rotr(A3, 2) ^ rotr(A3, 13) ^ rotr(A3, 22);
1692
+ const T22 = sigma0 + Maj(A3, B2, C2) | 0;
1693
+ H = G3;
1694
+ G3 = F2;
1695
+ F2 = E2;
1696
+ E2 = D + T1 | 0;
1697
+ D = C2;
1698
+ C2 = B2;
1699
+ B2 = A3;
1700
+ A3 = T1 + T22 | 0;
1701
+ }
1702
+ A3 = A3 + this.A | 0;
1703
+ B2 = B2 + this.B | 0;
1704
+ C2 = C2 + this.C | 0;
1705
+ D = D + this.D | 0;
1706
+ E2 = E2 + this.E | 0;
1707
+ F2 = F2 + this.F | 0;
1708
+ G3 = G3 + this.G | 0;
1709
+ H = H + this.H | 0;
1710
+ this.set(A3, B2, C2, D, E2, F2, G3, H);
1711
+ }
1712
+ roundClean() {
1713
+ clean(SHA256_W);
1714
+ }
1715
+ destroy() {
1716
+ this.destroyed = true;
1717
+ this.set(0, 0, 0, 0, 0, 0, 0, 0);
1718
+ clean(this.buffer);
1719
+ }
1720
+ };
1721
+ var _SHA256 = class extends SHA2_32B {
1722
+ // We cannot use array here since array allows indexing by variable
1723
+ // which means optimizer/compiler cannot use registers.
1724
+ A = SHA256_IV[0] | 0;
1725
+ B = SHA256_IV[1] | 0;
1726
+ C = SHA256_IV[2] | 0;
1727
+ D = SHA256_IV[3] | 0;
1728
+ E = SHA256_IV[4] | 0;
1729
+ F = SHA256_IV[5] | 0;
1730
+ G = SHA256_IV[6] | 0;
1731
+ H = SHA256_IV[7] | 0;
1732
+ constructor() {
1733
+ super(32);
1734
+ }
1735
+ };
1736
+ var K512 = /* @__PURE__ */ (() => split([
1737
+ "0x428a2f98d728ae22",
1738
+ "0x7137449123ef65cd",
1739
+ "0xb5c0fbcfec4d3b2f",
1740
+ "0xe9b5dba58189dbbc",
1741
+ "0x3956c25bf348b538",
1742
+ "0x59f111f1b605d019",
1743
+ "0x923f82a4af194f9b",
1744
+ "0xab1c5ed5da6d8118",
1745
+ "0xd807aa98a3030242",
1746
+ "0x12835b0145706fbe",
1747
+ "0x243185be4ee4b28c",
1748
+ "0x550c7dc3d5ffb4e2",
1749
+ "0x72be5d74f27b896f",
1750
+ "0x80deb1fe3b1696b1",
1751
+ "0x9bdc06a725c71235",
1752
+ "0xc19bf174cf692694",
1753
+ "0xe49b69c19ef14ad2",
1754
+ "0xefbe4786384f25e3",
1755
+ "0x0fc19dc68b8cd5b5",
1756
+ "0x240ca1cc77ac9c65",
1757
+ "0x2de92c6f592b0275",
1758
+ "0x4a7484aa6ea6e483",
1759
+ "0x5cb0a9dcbd41fbd4",
1760
+ "0x76f988da831153b5",
1761
+ "0x983e5152ee66dfab",
1762
+ "0xa831c66d2db43210",
1763
+ "0xb00327c898fb213f",
1764
+ "0xbf597fc7beef0ee4",
1765
+ "0xc6e00bf33da88fc2",
1766
+ "0xd5a79147930aa725",
1767
+ "0x06ca6351e003826f",
1768
+ "0x142929670a0e6e70",
1769
+ "0x27b70a8546d22ffc",
1770
+ "0x2e1b21385c26c926",
1771
+ "0x4d2c6dfc5ac42aed",
1772
+ "0x53380d139d95b3df",
1773
+ "0x650a73548baf63de",
1774
+ "0x766a0abb3c77b2a8",
1775
+ "0x81c2c92e47edaee6",
1776
+ "0x92722c851482353b",
1777
+ "0xa2bfe8a14cf10364",
1778
+ "0xa81a664bbc423001",
1779
+ "0xc24b8b70d0f89791",
1780
+ "0xc76c51a30654be30",
1781
+ "0xd192e819d6ef5218",
1782
+ "0xd69906245565a910",
1783
+ "0xf40e35855771202a",
1784
+ "0x106aa07032bbd1b8",
1785
+ "0x19a4c116b8d2d0c8",
1786
+ "0x1e376c085141ab53",
1787
+ "0x2748774cdf8eeb99",
1788
+ "0x34b0bcb5e19b48a8",
1789
+ "0x391c0cb3c5c95a63",
1790
+ "0x4ed8aa4ae3418acb",
1791
+ "0x5b9cca4f7763e373",
1792
+ "0x682e6ff3d6b2b8a3",
1793
+ "0x748f82ee5defb2fc",
1794
+ "0x78a5636f43172f60",
1795
+ "0x84c87814a1f0ab72",
1796
+ "0x8cc702081a6439ec",
1797
+ "0x90befffa23631e28",
1798
+ "0xa4506cebde82bde9",
1799
+ "0xbef9a3f7b2c67915",
1800
+ "0xc67178f2e372532b",
1801
+ "0xca273eceea26619c",
1802
+ "0xd186b8c721c0c207",
1803
+ "0xeada7dd6cde0eb1e",
1804
+ "0xf57d4f7fee6ed178",
1805
+ "0x06f067aa72176fba",
1806
+ "0x0a637dc5a2c898a6",
1807
+ "0x113f9804bef90dae",
1808
+ "0x1b710b35131c471b",
1809
+ "0x28db77f523047d84",
1810
+ "0x32caab7b40c72493",
1811
+ "0x3c9ebe0a15c9bebc",
1812
+ "0x431d67c49c100d4c",
1813
+ "0x4cc5d4becb3e42b6",
1814
+ "0x597f299cfc657e2a",
1815
+ "0x5fcb6fab3ad6faec",
1816
+ "0x6c44198c4a475817"
1817
+ ].map((n) => BigInt(n))))();
1818
+ var SHA512_Kh = /* @__PURE__ */ (() => K512[0])();
1819
+ var SHA512_Kl = /* @__PURE__ */ (() => K512[1])();
1820
+ var SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);
1821
+ var SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);
1822
+ var SHA2_64B = class extends HashMD {
1823
+ constructor(outputLen) {
1824
+ super(128, outputLen, 16, false);
1825
+ }
1826
+ // prettier-ignore
1827
+ get() {
1828
+ const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
1829
+ return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];
1830
+ }
1831
+ // prettier-ignore
1832
+ set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) {
1833
+ this.Ah = Ah | 0;
1834
+ this.Al = Al | 0;
1835
+ this.Bh = Bh | 0;
1836
+ this.Bl = Bl | 0;
1837
+ this.Ch = Ch | 0;
1838
+ this.Cl = Cl | 0;
1839
+ this.Dh = Dh | 0;
1840
+ this.Dl = Dl | 0;
1841
+ this.Eh = Eh | 0;
1842
+ this.El = El | 0;
1843
+ this.Fh = Fh | 0;
1844
+ this.Fl = Fl | 0;
1845
+ this.Gh = Gh | 0;
1846
+ this.Gl = Gl | 0;
1847
+ this.Hh = Hh | 0;
1848
+ this.Hl = Hl | 0;
1849
+ }
1850
+ process(view, offset) {
1851
+ for (let i2 = 0; i2 < 16; i2++, offset += 4) {
1852
+ SHA512_W_H[i2] = view.getUint32(offset);
1853
+ SHA512_W_L[i2] = view.getUint32(offset += 4);
1854
+ }
1855
+ for (let i2 = 16; i2 < 80; i2++) {
1856
+ const W15h = SHA512_W_H[i2 - 15] | 0;
1857
+ const W15l = SHA512_W_L[i2 - 15] | 0;
1858
+ const s0h = rotrSH(W15h, W15l, 1) ^ rotrSH(W15h, W15l, 8) ^ shrSH(W15h, W15l, 7);
1859
+ const s0l = rotrSL(W15h, W15l, 1) ^ rotrSL(W15h, W15l, 8) ^ shrSL(W15h, W15l, 7);
1860
+ const W2h = SHA512_W_H[i2 - 2] | 0;
1861
+ const W2l = SHA512_W_L[i2 - 2] | 0;
1862
+ const s1h = rotrSH(W2h, W2l, 19) ^ rotrBH(W2h, W2l, 61) ^ shrSH(W2h, W2l, 6);
1863
+ const s1l = rotrSL(W2h, W2l, 19) ^ rotrBL(W2h, W2l, 61) ^ shrSL(W2h, W2l, 6);
1864
+ const SUMl = add4L(s0l, s1l, SHA512_W_L[i2 - 7], SHA512_W_L[i2 - 16]);
1865
+ const SUMh = add4H(SUMl, s0h, s1h, SHA512_W_H[i2 - 7], SHA512_W_H[i2 - 16]);
1866
+ SHA512_W_H[i2] = SUMh | 0;
1867
+ SHA512_W_L[i2] = SUMl | 0;
1868
+ }
1869
+ let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
1870
+ for (let i2 = 0; i2 < 80; i2++) {
1871
+ const sigma1h = rotrSH(Eh, El, 14) ^ rotrSH(Eh, El, 18) ^ rotrBH(Eh, El, 41);
1872
+ const sigma1l = rotrSL(Eh, El, 14) ^ rotrSL(Eh, El, 18) ^ rotrBL(Eh, El, 41);
1873
+ const CHIh = Eh & Fh ^ ~Eh & Gh;
1874
+ const CHIl = El & Fl ^ ~El & Gl;
1875
+ const T1ll = add5L(Hl, sigma1l, CHIl, SHA512_Kl[i2], SHA512_W_L[i2]);
1876
+ const T1h = add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i2], SHA512_W_H[i2]);
1877
+ const T1l = T1ll | 0;
1878
+ const sigma0h = rotrSH(Ah, Al, 28) ^ rotrBH(Ah, Al, 34) ^ rotrBH(Ah, Al, 39);
1879
+ const sigma0l = rotrSL(Ah, Al, 28) ^ rotrBL(Ah, Al, 34) ^ rotrBL(Ah, Al, 39);
1880
+ const MAJh = Ah & Bh ^ Ah & Ch ^ Bh & Ch;
1881
+ const MAJl = Al & Bl ^ Al & Cl ^ Bl & Cl;
1882
+ Hh = Gh | 0;
1883
+ Hl = Gl | 0;
1884
+ Gh = Fh | 0;
1885
+ Gl = Fl | 0;
1886
+ Fh = Eh | 0;
1887
+ Fl = El | 0;
1888
+ ({ h: Eh, l: El } = add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));
1889
+ Dh = Ch | 0;
1890
+ Dl = Cl | 0;
1891
+ Ch = Bh | 0;
1892
+ Cl = Bl | 0;
1893
+ Bh = Ah | 0;
1894
+ Bl = Al | 0;
1895
+ const All = add3L(T1l, sigma0l, MAJl);
1896
+ Ah = add3H(All, T1h, sigma0h, MAJh);
1897
+ Al = All | 0;
1898
+ }
1899
+ ({ h: Ah, l: Al } = add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));
1900
+ ({ h: Bh, l: Bl } = add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));
1901
+ ({ h: Ch, l: Cl } = add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));
1902
+ ({ h: Dh, l: Dl } = add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));
1903
+ ({ h: Eh, l: El } = add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));
1904
+ ({ h: Fh, l: Fl } = add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));
1905
+ ({ h: Gh, l: Gl } = add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));
1906
+ ({ h: Hh, l: Hl } = add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));
1907
+ this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);
1908
+ }
1909
+ roundClean() {
1910
+ clean(SHA512_W_H, SHA512_W_L);
1911
+ }
1912
+ destroy() {
1913
+ this.destroyed = true;
1914
+ clean(this.buffer);
1915
+ this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1916
+ }
1917
+ };
1918
+ var _SHA512 = class extends SHA2_64B {
1919
+ Ah = SHA512_IV[0] | 0;
1920
+ Al = SHA512_IV[1] | 0;
1921
+ Bh = SHA512_IV[2] | 0;
1922
+ Bl = SHA512_IV[3] | 0;
1923
+ Ch = SHA512_IV[4] | 0;
1924
+ Cl = SHA512_IV[5] | 0;
1925
+ Dh = SHA512_IV[6] | 0;
1926
+ Dl = SHA512_IV[7] | 0;
1927
+ Eh = SHA512_IV[8] | 0;
1928
+ El = SHA512_IV[9] | 0;
1929
+ Fh = SHA512_IV[10] | 0;
1930
+ Fl = SHA512_IV[11] | 0;
1931
+ Gh = SHA512_IV[12] | 0;
1932
+ Gl = SHA512_IV[13] | 0;
1933
+ Hh = SHA512_IV[14] | 0;
1934
+ Hl = SHA512_IV[15] | 0;
1935
+ constructor() {
1936
+ super(64);
1937
+ }
1938
+ };
1939
+ var sha256 = /* @__PURE__ */ createHasher(
1940
+ () => new _SHA256(),
1941
+ /* @__PURE__ */ oidNist(1)
1942
+ );
1943
+ var sha512 = /* @__PURE__ */ createHasher(
1944
+ () => new _SHA512(),
1945
+ /* @__PURE__ */ oidNist(3)
1946
+ );
1947
+
1948
+ // ../../node_modules/.pnpm/@otplib+plugin-crypto-noble@13.4.0/node_modules/@otplib/plugin-crypto-noble/dist/index.js
1949
+ var t = class {
1950
+ name = "noble";
1951
+ hmac(r2, n, a2) {
1952
+ return hmac(r2 === "sha1" ? sha1 : r2 === "sha256" ? sha256 : sha512, n, a2);
1953
+ }
1954
+ randomBytes(r2) {
1955
+ return randomBytes(r2);
1956
+ }
1957
+ constantTimeEqual(r2, n) {
1958
+ return tr(r2, n);
1959
+ }
1960
+ };
1961
+ var A2 = Object.freeze(new t());
1962
+
1963
+ // ../../node_modules/.pnpm/otplib@13.4.0/node_modules/otplib/dist/index.js
1964
+ function c2(t2) {
1965
+ return { secret: t2.secret, strategy: t2.strategy ?? "totp", crypto: t2.crypto ?? A2, base32: t2.base32 ?? d2, algorithm: t2.algorithm ?? "sha1", digits: t2.digits ?? 6, period: t2.period ?? 30, epoch: t2.epoch ?? Math.floor(Date.now() / 1e3), t0: t2.t0 ?? 0, counter: t2.counter, guardrails: t2.guardrails ?? hr(), hooks: t2.hooks };
1966
+ }
1967
+ function O3(t2) {
1968
+ return { ...c2(t2), token: t2.token, epochTolerance: t2.epochTolerance ?? 0, counterTolerance: t2.counterTolerance ?? 0, afterTimeStep: t2.afterTimeStep };
1969
+ }
1970
+ function l(t2, e, r2) {
1971
+ if (t2 === "totp") return r2.totp();
1972
+ if (t2 === "hotp") {
1973
+ if (e === void 0) throw new a("Counter is required for HOTP strategy. Example: { strategy: 'hotp', counter: 0 }");
1974
+ return r2.hotp(e);
1975
+ }
1976
+ throw new a(`Unknown OTP strategy: ${t2}. Valid strategies are 'totp' or 'hotp'.`);
1977
+ }
1978
+ function I2(t2) {
1979
+ let { crypto: e = A2, base32: r2 = d2, length: a2 = 20 } = t2 || {};
1980
+ return Dr({ crypto: e, base32: r2, length: a2 });
1981
+ }
1982
+ function T2(t2) {
1983
+ let { strategy: e = "totp", issuer: r2, label: a2, secret: o, algorithm: i2 = "sha1", digits: s = 6, period: n = 30, counter: p } = t2;
1984
+ return l(e, p, { totp: () => x2({ issuer: r2, label: a2, secret: o, algorithm: i2, digits: s, period: n }), hotp: (y2) => U2({ issuer: r2, label: a2, secret: o, algorithm: i2, digits: s, counter: y2 }) });
1985
+ }
1986
+ function d3(t2) {
1987
+ let e = O3(t2), { secret: r2, token: a2, crypto: o, base32: i2, algorithm: s, digits: n, hooks: p } = e, y2 = { secret: r2, token: a2, crypto: o, base32: i2, algorithm: s, digits: n, hooks: p };
1988
+ return l(e.strategy, e.counter, { totp: () => ie({ ...y2, period: e.period, epoch: e.epoch, t0: e.t0, epochTolerance: e.epochTolerance, afterTimeStep: e.afterTimeStep, guardrails: e.guardrails }), hotp: (f2) => Y2({ ...y2, counter: f2, counterTolerance: e.counterTolerance, guardrails: e.guardrails }) });
1989
+ }
1990
+
1991
+ // ../core/dist/controllers/auth.js
569
1992
  import { z, flattenError } from "zod";
570
1993
 
571
1994
  // ../core/dist/media/index.js
572
1995
  import multer from "multer";
573
1996
 
574
1997
  // ../core/dist/lib/encrypt.js
575
- import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
1998
+ import { createCipheriv, createDecipheriv, randomBytes as randomBytes2 } from "crypto";
576
1999
  var ALGORITHM = "aes-256-gcm";
577
2000
  var KEY_LENGTH = 32;
578
2001
  var IV_LENGTH = 12;
579
2002
  var TAG_LENGTH = 16;
580
2003
  function getKey() {
581
2004
  const raw = process.env.PLANK_ENCRYPTION_KEY;
582
- if (!raw)
2005
+ if (!raw) {
2006
+ if (process.env.NODE_ENV === "production") {
2007
+ throw new Error("PLANK_ENCRYPTION_KEY is required in production");
2008
+ }
583
2009
  return null;
2010
+ }
584
2011
  const buf = Buffer.from(raw, "hex");
585
2012
  if (buf.length !== KEY_LENGTH) {
2013
+ if (process.env.NODE_ENV === "production") {
2014
+ throw new Error("PLANK_ENCRYPTION_KEY must be 64 hex chars (32 bytes) in production");
2015
+ }
586
2016
  console.warn("[plank] PLANK_ENCRYPTION_KEY must be 64 hex chars (32 bytes). Falling back to plaintext storage.");
587
2017
  return null;
588
2018
  }
@@ -592,7 +2022,7 @@ function encrypt(plaintext) {
592
2022
  const key = getKey();
593
2023
  if (!key)
594
2024
  return plaintext;
595
- const iv = randomBytes(IV_LENGTH);
2025
+ const iv = randomBytes2(IV_LENGTH);
596
2026
  const cipher = createCipheriv(ALGORITHM, key, iv);
597
2027
  const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
598
2028
  const tag = cipher.getAuthTag();
@@ -624,7 +2054,7 @@ function isSensitive(namespace, key) {
624
2054
  }
625
2055
  async function getSettings(namespace) {
626
2056
  const { rows } = await pool_default.query("SELECT key, value FROM plank_settings WHERE namespace = $1", [namespace]);
627
- return Object.fromEntries(rows.map((r) => [r.key, isSensitive(namespace, r.key) ? decrypt(r.value) : r.value]));
2057
+ return Object.fromEntries(rows.map((r2) => [r2.key, isSensitive(namespace, r2.key) ? decrypt(r2.value) : r2.value]));
628
2058
  }
629
2059
  async function getSetting(namespace, key) {
630
2060
  const { rows } = await pool_default.query("SELECT value FROM plank_settings WHERE namespace = $1 AND key = $2", [namespace, key]);
@@ -639,7 +2069,7 @@ async function setSettings(namespace, values) {
639
2069
  key,
640
2070
  value: isSensitive(namespace, key) ? encrypt(value) : value
641
2071
  }));
642
- const placeholders = entries.map((_, i) => `($1, $${i * 2 + 2}, $${i * 2 + 3})`).join(", ");
2072
+ const placeholders = entries.map((_3, i2) => `($1, $${i2 * 2 + 2}, $${i2 * 2 + 3})`).join(", ");
643
2073
  const params = [namespace];
644
2074
  for (const { key, value } of entries) {
645
2075
  params.push(key, value);
@@ -651,8 +2081,8 @@ async function setSettings(namespace, values) {
651
2081
 
652
2082
  // ../core/dist/media/providers/local.js
653
2083
  import { writeFile, mkdir } from "fs/promises";
654
- import { join as join2, extname } from "path";
655
- import { randomBytes as randomBytes2 } from "crypto";
2084
+ import { join as join3, extname } from "path";
2085
+ import { randomBytes as randomBytes3 } from "crypto";
656
2086
  async function uploadsDir() {
657
2087
  const fromSettings = await getSetting("media", "local.uploads_dir");
658
2088
  return fromSettings ?? process.env.PLANK_UPLOADS_DIR ?? "public/uploads";
@@ -664,27 +2094,27 @@ async function publicUrl() {
664
2094
  var localProvider = {
665
2095
  async upload(file, options) {
666
2096
  const base_dir = await uploadsDir();
667
- const subdir = options?.prefix ? join2(base_dir, options.prefix) : base_dir;
2097
+ const subdir = options?.prefix ? join3(base_dir, options.prefix) : base_dir;
668
2098
  await mkdir(subdir, { recursive: true });
669
2099
  const ext = extname(file.originalname);
670
- const filename = `${randomBytes2(16).toString("hex")}${ext}`;
2100
+ const filename = `${randomBytes3(16).toString("hex")}${ext}`;
671
2101
  const key = options?.prefix ? `${options.prefix}/${filename}` : filename;
672
- await writeFile(join2(base_dir, key), file.buffer);
2102
+ await writeFile(join3(base_dir, key), file.buffer);
673
2103
  const base = await publicUrl();
674
2104
  return { url: `${base}/uploads/${key}`, key };
675
2105
  },
676
2106
  async uploadRaw(buffer, exactKey, mimeType) {
677
2107
  const base_dir = await uploadsDir();
678
- const dir = join2(base_dir, exactKey.split("/").slice(0, -1).join("/"));
2108
+ const dir = join3(base_dir, exactKey.split("/").slice(0, -1).join("/"));
679
2109
  await mkdir(dir, { recursive: true });
680
- await writeFile(join2(base_dir, exactKey), buffer);
2110
+ await writeFile(join3(base_dir, exactKey), buffer);
681
2111
  const base = await publicUrl();
682
2112
  return { url: `${base}/uploads/${exactKey}`, key: exactKey };
683
2113
  },
684
2114
  async delete(key) {
685
2115
  const { unlink } = await import("fs/promises");
686
2116
  const dir = await uploadsDir();
687
- await unlink(join2(dir, key));
2117
+ await unlink(join3(dir, key));
688
2118
  },
689
2119
  async getUrl(key) {
690
2120
  const base = await publicUrl();
@@ -696,7 +2126,7 @@ var localProvider = {
696
2126
  import { S3Client, PutObjectCommand, DeleteObjectCommand } from "@aws-sdk/client-s3";
697
2127
  import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
698
2128
  import { extname as extname2 } from "path";
699
- import { randomBytes as randomBytes3 } from "crypto";
2129
+ import { randomBytes as randomBytes4 } from "crypto";
700
2130
  async function getConfig() {
701
2131
  const [accessKeyId, secretAccessKey, region, bucket, pathPrefix, publicUrl2] = await Promise.all([
702
2132
  getSetting("media", "s3.access_key_id"),
@@ -719,7 +2149,7 @@ function buildClient(cfg) {
719
2149
  }
720
2150
  function buildKey(cfg, filename, prefix) {
721
2151
  const ext = extname2(filename);
722
- const name = `${randomBytes3(16).toString("hex")}${ext}`;
2152
+ const name = `${randomBytes4(16).toString("hex")}${ext}`;
723
2153
  const parts = [cfg.pathPrefix?.replace(/\/$/, ""), prefix, name].filter(Boolean);
724
2154
  return parts.join("/");
725
2155
  }
@@ -773,7 +2203,7 @@ var s3Provider = {
773
2203
  import { S3Client as S3Client2, PutObjectCommand as PutObjectCommand2, DeleteObjectCommand as DeleteObjectCommand2 } from "@aws-sdk/client-s3";
774
2204
  import { getSignedUrl as getSignedUrl2 } from "@aws-sdk/s3-request-presigner";
775
2205
  import { extname as extname3 } from "path";
776
- import { randomBytes as randomBytes4 } from "crypto";
2206
+ import { randomBytes as randomBytes5 } from "crypto";
777
2207
  async function getConfig2() {
778
2208
  const [accessKeyId, secretAccessKey, accountId, bucket, pathPrefix, publicUrl2] = await Promise.all([
779
2209
  getSetting("media", "r2.access_key_id"),
@@ -799,7 +2229,7 @@ function buildClient2(cfg) {
799
2229
  }
800
2230
  function buildKey2(cfg, filename, prefix) {
801
2231
  const ext = extname3(filename);
802
- const name = `${randomBytes4(16).toString("hex")}${ext}`;
2232
+ const name = `${randomBytes5(16).toString("hex")}${ext}`;
803
2233
  const parts = [cfg.pathPrefix?.replace(/\/$/, ""), prefix, name].filter(Boolean);
804
2234
  return parts.join("/");
805
2235
  }
@@ -873,57 +2303,78 @@ var LoginSchema = z.object({
873
2303
  email: z.email(),
874
2304
  password: z.string().min(1)
875
2305
  });
2306
+ var Login2FASchema = z.object({
2307
+ challengeToken: z.string().min(1),
2308
+ code: z.string().trim().length(6)
2309
+ });
876
2310
  var RegisterSchema = z.object({
877
2311
  email: z.email(),
878
2312
  password: z.string().min(8)
879
2313
  });
880
- var loginAttempts = /* @__PURE__ */ new Map();
881
- var RATE_LIMIT_MAX = 10;
882
2314
  var RATE_LIMIT_WINDOW_MS = 15 * 60 * 1e3;
883
- function checkRateLimit(ip) {
884
- const now = Date.now();
885
- const entry = loginAttempts.get(ip);
886
- if (!entry || now > entry.resetAt) {
887
- loginAttempts.set(ip, { count: 1, resetAt: now + RATE_LIMIT_WINDOW_MS });
888
- return true;
889
- }
890
- if (entry.count >= RATE_LIMIT_MAX)
891
- return false;
892
- entry.count++;
893
- return true;
2315
+ var LOGIN_RATE_LIMIT_MAX = 10;
2316
+ var LOGIN_2FA_RATE_LIMIT_MAX = 5;
2317
+ var ACCESS_TOKEN_COOKIE = "plank_session";
2318
+ var ACCESS_TOKEN_EXPIRES_SECONDS = 60 * 15;
2319
+ function isProduction() {
2320
+ return process.env.NODE_ENV === "production";
894
2321
  }
895
- function clearRateLimit(ip) {
896
- loginAttempts.delete(ip);
2322
+ function setSessionCookie(res, token) {
2323
+ res.cookie(ACCESS_TOKEN_COOKIE, token, {
2324
+ httpOnly: true,
2325
+ secure: isProduction(),
2326
+ sameSite: "lax",
2327
+ path: "/",
2328
+ maxAge: ACCESS_TOKEN_EXPIRES_SECONDS * 1e3
2329
+ });
897
2330
  }
898
- async function login(req, res) {
899
- const ip = req.ip ?? "unknown";
900
- if (!checkRateLimit(ip)) {
901
- res.status(429).json({ error: "Too many login attempts. Try again in 15 minutes." });
902
- return;
903
- }
904
- const parsed = LoginSchema.safeParse(req.body);
905
- if (!parsed.success) {
906
- res.status(400).json({ errors: flattenError(parsed.error, (i) => i.message) });
907
- return;
908
- }
909
- const { email, password } = parsed.data;
910
- const { rows } = await pool_default.query(`SELECT id, email, password, role_id, first_name, last_name, avatar_url, job_title, organization, country
911
- FROM plank_users
912
- WHERE email = $1`, [email]);
913
- const user = rows[0];
914
- if (!user || !await bcrypt.compare(password, user.password)) {
915
- res.status(401).json({ error: "Invalid credentials" });
916
- return;
917
- }
2331
+ function clearSessionCookie(res) {
2332
+ res.clearCookie(ACCESS_TOKEN_COOKIE, {
2333
+ httpOnly: true,
2334
+ secure: isProduction(),
2335
+ sameSite: "lax",
2336
+ path: "/"
2337
+ });
2338
+ }
2339
+ async function consumeRateLimit(scope, rateKey, max) {
2340
+ const resetAt = new Date(Date.now() + RATE_LIMIT_WINDOW_MS);
2341
+ const { rows } = await pool_default.query(`INSERT INTO plank_auth_rate_limits (id, scope, rate_key, count, reset_at)
2342
+ VALUES ($1, $2, $3, 1, $4)
2343
+ ON CONFLICT (scope, rate_key)
2344
+ DO UPDATE
2345
+ SET count = CASE
2346
+ WHEN plank_auth_rate_limits.reset_at <= NOW() THEN 1
2347
+ ELSE plank_auth_rate_limits.count + 1
2348
+ END,
2349
+ reset_at = CASE
2350
+ WHEN plank_auth_rate_limits.reset_at <= NOW() THEN $4
2351
+ ELSE plank_auth_rate_limits.reset_at
2352
+ END,
2353
+ updated_at = NOW()
2354
+ RETURNING count, reset_at`, [createId(), scope, rateKey, resetAt]);
2355
+ return (rows[0]?.count ?? max + 1) <= max;
2356
+ }
2357
+ async function clearRateLimit(scope, rateKey) {
2358
+ await pool_default.query("DELETE FROM plank_auth_rate_limits WHERE scope = $1 AND rate_key = $2", [
2359
+ scope,
2360
+ rateKey
2361
+ ]);
2362
+ }
2363
+ function buildAccessToken(payload) {
2364
+ return jwt.sign(payload, process.env.PLANK_JWT_SECRET, { expiresIn: "15m" });
2365
+ }
2366
+ function buildChallengeToken(payload) {
2367
+ return jwt.sign(payload, process.env.PLANK_JWT_SECRET, { expiresIn: "5m" });
2368
+ }
2369
+ async function buildAuthPayload(user) {
918
2370
  const { rows: roleRows } = await pool_default.query("SELECT id, name, permissions FROM plank_roles WHERE id = $1", [user.role_id]);
919
- clearRateLimit(ip);
920
2371
  let avatarUrl = user.avatar_url;
921
2372
  if (avatarUrl && !avatarUrl.startsWith("http")) {
922
2373
  const provider = await getProvider();
923
2374
  avatarUrl = await provider.getUrl(avatarUrl);
924
2375
  }
925
- const token = jwt.sign({ sub: user.id, roleId: user.role_id }, process.env.PLANK_JWT_SECRET, { expiresIn: "7d" });
926
- res.json({
2376
+ const token = buildAccessToken({ sub: user.id, roleId: user.role_id, sv: user.session_version });
2377
+ return {
927
2378
  token,
928
2379
  user: {
929
2380
  id: user.id,
@@ -935,10 +2386,118 @@ async function login(req, res) {
935
2386
  avatarUrl,
936
2387
  jobTitle: user.job_title,
937
2388
  organization: user.organization,
938
- country: user.country
2389
+ country: user.country,
2390
+ twoFactorEnabled: user.two_factor_enabled
939
2391
  }
2392
+ };
2393
+ }
2394
+ async function login(req, res) {
2395
+ const ip = req.ip ?? "unknown";
2396
+ const parsed = LoginSchema.safeParse(req.body);
2397
+ if (!parsed.success) {
2398
+ res.status(400).json({ errors: flattenError(parsed.error, (i2) => i2.message) });
2399
+ return;
2400
+ }
2401
+ const { email, password } = parsed.data;
2402
+ const rateKey = `${ip}:${email.toLowerCase()}`;
2403
+ if (!await consumeRateLimit("login", rateKey, LOGIN_RATE_LIMIT_MAX)) {
2404
+ res.status(429).json({ error: "Too many login attempts. Try again in 15 minutes." });
2405
+ return;
2406
+ }
2407
+ const { rows } = await pool_default.query(`SELECT id, email, password, role_id, first_name, last_name, avatar_url, job_title, organization, country, two_factor_enabled, two_factor_secret, session_version
2408
+ FROM plank_users
2409
+ WHERE email = $1`, [email]);
2410
+ const user = rows[0];
2411
+ if (!user || !await bcrypt.compare(password, user.password)) {
2412
+ res.status(401).json({ error: "Invalid credentials" });
2413
+ return;
2414
+ }
2415
+ await clearRateLimit("login", rateKey);
2416
+ if (user.two_factor_enabled && user.two_factor_secret) {
2417
+ const challengeToken = buildChallengeToken({
2418
+ sub: user.id,
2419
+ roleId: user.role_id,
2420
+ sv: user.session_version,
2421
+ twoFactor: true,
2422
+ jti: createId()
2423
+ });
2424
+ res.json({ requiresTwoFactor: true, challengeToken });
2425
+ return;
2426
+ }
2427
+ const auth = await buildAuthPayload(user);
2428
+ setSessionCookie(res, auth.token);
2429
+ res.json({
2430
+ requiresTwoFactor: false,
2431
+ user: auth.user
2432
+ });
2433
+ }
2434
+ async function loginWithTwoFactor(req, res) {
2435
+ const ip = req.ip ?? "unknown";
2436
+ const parsed = Login2FASchema.safeParse(req.body);
2437
+ if (!parsed.success) {
2438
+ res.status(400).json({ errors: flattenError(parsed.error, (i2) => i2.message) });
2439
+ return;
2440
+ }
2441
+ let payload;
2442
+ try {
2443
+ payload = jwt.verify(parsed.data.challengeToken, process.env.PLANK_JWT_SECRET);
2444
+ } catch {
2445
+ res.status(401).json({ error: "Invalid or expired 2FA challenge" });
2446
+ return;
2447
+ }
2448
+ if (!payload.twoFactor) {
2449
+ res.status(400).json({ error: "Invalid 2FA challenge token" });
2450
+ return;
2451
+ }
2452
+ const rateKey = `${ip}:${payload.sub}:${payload.jti ?? "nojti"}`;
2453
+ if (!await consumeRateLimit("login-2fa", rateKey, LOGIN_2FA_RATE_LIMIT_MAX)) {
2454
+ res.status(429).json({ error: "Too many 2FA attempts. Try again in 15 minutes." });
2455
+ return;
2456
+ }
2457
+ const { rows } = await pool_default.query(`SELECT id, email, role_id, first_name, last_name, avatar_url, job_title, organization, country, two_factor_enabled, two_factor_secret, password, session_version
2458
+ FROM plank_users WHERE id = $1`, [payload.sub]);
2459
+ const user = rows[0];
2460
+ if (!user || !user.two_factor_enabled || !user.two_factor_secret) {
2461
+ res.status(401).json({ error: "2FA is not enabled for this account" });
2462
+ return;
2463
+ }
2464
+ if (user.session_version !== payload.sv) {
2465
+ res.status(401).json({ error: "2FA challenge expired. Start login again." });
2466
+ return;
2467
+ }
2468
+ const result = d3({
2469
+ token: parsed.data.code,
2470
+ secret: decrypt(user.two_factor_secret)
2471
+ });
2472
+ if (!result.valid) {
2473
+ res.status(401).json({ error: "Invalid verification code" });
2474
+ return;
2475
+ }
2476
+ await clearRateLimit("login-2fa", rateKey);
2477
+ const auth = await buildAuthPayload(user);
2478
+ setSessionCookie(res, auth.token);
2479
+ res.json({
2480
+ requiresTwoFactor: false,
2481
+ user: auth.user
940
2482
  });
941
2483
  }
2484
+ async function logout(req, res) {
2485
+ const cookieHeader = req.headers.cookie ?? "";
2486
+ const raw = cookieHeader.split(";").map((c3) => c3.trim()).find((c3) => c3.startsWith(`${ACCESS_TOKEN_COOKIE}=`))?.slice(`${ACCESS_TOKEN_COOKIE}=`.length);
2487
+ if (raw) {
2488
+ try {
2489
+ const payload = jwt.verify(decodeURIComponent(raw), process.env.PLANK_JWT_SECRET);
2490
+ if (payload.sub) {
2491
+ await pool_default.query("UPDATE plank_users SET session_version = session_version + 1 WHERE id = $1", [payload.sub]);
2492
+ }
2493
+ } catch {
2494
+ }
2495
+ }
2496
+ clearSessionCookie(res);
2497
+ const ip = req.ip ?? "unknown";
2498
+ await pool_default.query("DELETE FROM plank_auth_rate_limits WHERE rate_key LIKE $1", [`${ip}:%`]);
2499
+ res.status(204).end();
2500
+ }
942
2501
  async function setup(_req, res) {
943
2502
  const { rows } = await pool_default.query("SELECT COUNT(*) as count FROM plank_users");
944
2503
  res.json({ needsSetup: parseInt(rows[0].count) === 0 });
@@ -951,7 +2510,7 @@ async function register(req, res) {
951
2510
  }
952
2511
  const parsed = RegisterSchema.safeParse(req.body);
953
2512
  if (!parsed.success) {
954
- res.status(400).json({ errors: flattenError(parsed.error, (i) => i.message) });
2513
+ res.status(400).json({ errors: flattenError(parsed.error, (i2) => i2.message) });
955
2514
  return;
956
2515
  }
957
2516
  const { email, password } = parsed.data;
@@ -966,6 +2525,8 @@ async function register(req, res) {
966
2525
  var router = Router();
967
2526
  router.get("/setup", setup);
968
2527
  router.post("/login", login);
2528
+ router.post("/login/2fa", loginWithTwoFactor);
2529
+ router.post("/logout", logout);
969
2530
  router.post("/register", register);
970
2531
  var auth_default = router;
971
2532
 
@@ -974,15 +2535,37 @@ import { Router as Router2 } from "express";
974
2535
 
975
2536
  // ../core/dist/middlewares/authenticate.js
976
2537
  import jwt2 from "jsonwebtoken";
977
- function authenticate(req, res, next) {
2538
+ function cookieValue(raw, key) {
2539
+ if (!raw)
2540
+ return null;
2541
+ const parts = raw.split(";");
2542
+ for (const part of parts) {
2543
+ const [k3, ...rest] = part.trim().split("=");
2544
+ if (k3 === key)
2545
+ return decodeURIComponent(rest.join("="));
2546
+ }
2547
+ return null;
2548
+ }
2549
+ async function authenticate(req, res, next) {
978
2550
  const header = req.headers.authorization;
979
- if (!header?.startsWith("Bearer ")) {
2551
+ const bearer = header?.startsWith("Bearer ") ? header.slice(7) : null;
2552
+ const cookieToken = cookieValue(req.headers.cookie, "plank_session");
2553
+ const token = bearer ?? cookieToken;
2554
+ if (!token) {
980
2555
  res.status(401).json({ error: "Unauthorized" });
981
2556
  return;
982
2557
  }
983
- const token = header.slice(7);
984
2558
  try {
985
2559
  const payload = jwt2.verify(token, process.env.PLANK_JWT_SECRET);
2560
+ if (typeof payload.sv !== "number") {
2561
+ res.status(401).json({ error: "Invalid session token" });
2562
+ return;
2563
+ }
2564
+ const { rows } = await pool_default.query("SELECT session_version FROM plank_users WHERE id = $1", [payload.sub]);
2565
+ if (!rows[0] || rows[0].session_version !== payload.sv) {
2566
+ res.status(401).json({ error: "Session has been revoked" });
2567
+ return;
2568
+ }
986
2569
  req.user = { id: payload.sub, roleId: payload.roleId };
987
2570
  next();
988
2571
  } catch {
@@ -1161,22 +2744,22 @@ async function syncInverseFields(savedCT, prevCT) {
1161
2744
  if (relatedCTCache.has(tableName))
1162
2745
  return relatedCTCache.get(tableName) ?? null;
1163
2746
  const all = await findAllContentTypes();
1164
- const ct = all.find((c) => c.tableName === tableName) ?? null;
2747
+ const ct = all.find((c3) => c3.tableName === tableName) ?? null;
1165
2748
  relatedCTCache.set(tableName, ct);
1166
2749
  return ct;
1167
2750
  }
1168
- const prevRelFields = new Map((prevCT?.fields ?? []).filter((f) => f.type === "relation" && f.relationType !== "one-to-many").map((f) => [f.name, f]));
1169
- const nextRelFields = savedCT.fields.filter((f) => f.type === "relation" && f.relationType !== "one-to-many");
2751
+ const prevRelFields = new Map((prevCT?.fields ?? []).filter((f2) => f2.type === "relation" && f2.relationType !== "one-to-many").map((f2) => [f2.name, f2]));
2752
+ const nextRelFields = savedCT.fields.filter((f2) => f2.type === "relation" && f2.relationType !== "one-to-many");
1170
2753
  for (const [fieldName, prevField] of prevRelFields) {
1171
2754
  if (!prevField.relatedTable)
1172
2755
  continue;
1173
- const nextField = savedCT.fields.find((f) => f.name === fieldName);
2756
+ const nextField = savedCT.fields.find((f2) => f2.name === fieldName);
1174
2757
  const targetChanged = nextField?.relatedTable !== prevField.relatedTable;
1175
2758
  if (!nextField || targetChanged) {
1176
2759
  const relatedCT = await getRelatedCT(prevField.relatedTable);
1177
2760
  if (!relatedCT)
1178
2761
  continue;
1179
- const updated = relatedCT.fields.filter((f) => !(f.type === "relation" && f.relationType === inverseRelationType(prevField.relationType ?? "many-to-one") && f.relatedTable === savedCT.tableName && f.relatedField === fieldName));
2762
+ const updated = relatedCT.fields.filter((f2) => !(f2.type === "relation" && f2.relationType === inverseRelationType(prevField.relationType ?? "many-to-one") && f2.relatedTable === savedCT.tableName && f2.relatedField === fieldName));
1180
2763
  if (updated.length !== relatedCT.fields.length) {
1181
2764
  await updateContentType(relatedCT.slug, { ...relatedCT, fields: updated });
1182
2765
  }
@@ -1189,9 +2772,9 @@ async function syncInverseFields(savedCT, prevCT) {
1189
2772
  if (!relatedCT)
1190
2773
  continue;
1191
2774
  const invType = inverseRelationType(field.relationType ?? "many-to-one");
1192
- const existingInvIdx = relatedCT.fields.findIndex((f) => f.type === "relation" && f.relationType === invType && f.relatedTable === savedCT.tableName && f.relatedField === field.name);
2775
+ const existingInvIdx = relatedCT.fields.findIndex((f2) => f2.type === "relation" && f2.relationType === invType && f2.relatedTable === savedCT.tableName && f2.relatedField === field.name);
1193
2776
  const invField = {
1194
- name: existingInvIdx >= 0 ? relatedCT.fields[existingInvIdx].name : inverseFieldName(savedCT.tableName, field.name, relatedCT.fields.map((f) => f.name)),
2777
+ name: existingInvIdx >= 0 ? relatedCT.fields[existingInvIdx].name : inverseFieldName(savedCT.tableName, field.name, relatedCT.fields.map((f2) => f2.name)),
1195
2778
  type: "relation",
1196
2779
  relationType: invType,
1197
2780
  relatedTable: savedCT.tableName,
@@ -1200,7 +2783,7 @@ async function syncInverseFields(savedCT, prevCT) {
1200
2783
  };
1201
2784
  let updatedFields;
1202
2785
  if (existingInvIdx >= 0) {
1203
- updatedFields = relatedCT.fields.map((f, i) => i === existingInvIdx ? invField : f);
2786
+ updatedFields = relatedCT.fields.map((f2, i2) => i2 === existingInvIdx ? invField : f2);
1204
2787
  } else {
1205
2788
  updatedFields = [...relatedCT.fields, invField];
1206
2789
  }
@@ -1210,7 +2793,7 @@ async function syncInverseFields(savedCT, prevCT) {
1210
2793
  async function removeRelationDependencies(deletedTable) {
1211
2794
  const all = await findAllContentTypes();
1212
2795
  for (const ct of all) {
1213
- const toRemove = ct.fields.filter((f) => f.type === "relation" && f.relatedTable === deletedTable.tableName);
2796
+ const toRemove = ct.fields.filter((f2) => f2.type === "relation" && f2.relatedTable === deletedTable.tableName);
1214
2797
  if (toRemove.length === 0)
1215
2798
  continue;
1216
2799
  for (const field of toRemove) {
@@ -1226,7 +2809,7 @@ async function removeRelationDependencies(deletedTable) {
1226
2809
  await pool_default.query(`DROP TABLE IF EXISTS ${quoteIdentifier(jt)}`);
1227
2810
  }
1228
2811
  }
1229
- const filtered = ct.fields.filter((f) => !(f.type === "relation" && f.relatedTable === deletedTable.tableName));
2812
+ const filtered = ct.fields.filter((f2) => !(f2.type === "relation" && f2.relatedTable === deletedTable.tableName));
1230
2813
  await updateContentType(ct.slug, { ...ct, fields: filtered });
1231
2814
  }
1232
2815
  }
@@ -1245,7 +2828,7 @@ var getContentType = async (req, res) => {
1245
2828
  var createContentType = async (req, res) => {
1246
2829
  const parsed = CreateContentTypeSchema.safeParse(req.body);
1247
2830
  if (!parsed.success) {
1248
- res.status(400).json({ errors: flattenError2(parsed.error, (i) => i.message) });
2831
+ res.status(400).json({ errors: flattenError2(parsed.error, (i2) => i2.message) });
1249
2832
  return;
1250
2833
  }
1251
2834
  const reservedErrors = findReservedIdentifierErrors(parsed.data);
@@ -1270,7 +2853,7 @@ var updateContentType2 = async (req, res) => {
1270
2853
  }
1271
2854
  const parsed = ContentTypeSchema.safeParse(req.body);
1272
2855
  if (!parsed.success) {
1273
- res.status(400).json({ errors: flattenError2(parsed.error, (i) => i.message) });
2856
+ res.status(400).json({ errors: flattenError2(parsed.error, (i2) => i2.message) });
1274
2857
  return;
1275
2858
  }
1276
2859
  const reservedErrors = findReservedIdentifierErrors(parsed.data);
@@ -1322,7 +2905,7 @@ async function listWebhooks(_req, res) {
1322
2905
  async function createWebhook(req, res) {
1323
2906
  const parsed = CreateWebhookSchema.safeParse(req.body);
1324
2907
  if (!parsed.success) {
1325
- res.status(400).json({ errors: flattenError3(parsed.error, (i) => i.message) });
2908
+ res.status(400).json({ errors: flattenError3(parsed.error, (i2) => i2.message) });
1326
2909
  return;
1327
2910
  }
1328
2911
  const { name, url, events } = parsed.data;
@@ -1365,22 +2948,22 @@ function resolveLocalizedRow(row, ct, locale, fallbacks = []) {
1365
2948
  const localized = row.localized && typeof row.localized === "object" ? row.localized : {};
1366
2949
  const resolved = { ...row };
1367
2950
  const localizableTypes = /* @__PURE__ */ new Set(["string", "text", "richtext", "uid"]);
1368
- for (const f of ct.fields) {
1369
- if (!localizableTypes.has(f.type))
2951
+ for (const f2 of ct.fields) {
2952
+ if (!localizableTypes.has(f2.type))
1370
2953
  continue;
1371
2954
  let val = void 0;
1372
- if (locale && localized[locale] && localized[locale][f.name] !== void 0) {
1373
- val = localized[locale][f.name];
2955
+ if (locale && localized[locale] && localized[locale][f2.name] !== void 0) {
2956
+ val = localized[locale][f2.name];
1374
2957
  } else {
1375
2958
  for (const fb of fallbacks) {
1376
- if (localized[fb] && localized[fb][f.name] !== void 0) {
1377
- val = localized[fb][f.name];
2959
+ if (localized[fb] && localized[fb][f2.name] !== void 0) {
2960
+ val = localized[fb][f2.name];
1378
2961
  break;
1379
2962
  }
1380
2963
  }
1381
2964
  }
1382
2965
  if (val !== void 0)
1383
- resolved[f.name] = val;
2966
+ resolved[f2.name] = val;
1384
2967
  }
1385
2968
  return resolved;
1386
2969
  }
@@ -1428,7 +3011,7 @@ async function syncManyToMany(entryId, tableName, field, targetIds) {
1428
3011
  await pool_default.query(`DELETE FROM ${quoteIdentifier(jt)} WHERE source_id = $1`, [entryId]);
1429
3012
  if (targetIds.length === 0)
1430
3013
  return;
1431
- const placeholders = targetIds.map((_, i) => `($1, $${i + 2})`).join(", ");
3014
+ const placeholders = targetIds.map((_3, i2) => `($1, $${i2 + 2})`).join(", ");
1432
3015
  await pool_default.query(`INSERT INTO ${quoteIdentifier(jt)} (source_id, target_id) VALUES ${placeholders} ON CONFLICT DO NOTHING`, [entryId, ...targetIds]);
1433
3016
  }
1434
3017
  async function isUserRole(roleId) {
@@ -1449,7 +3032,7 @@ var listEntries = async (req, res) => {
1449
3032
  const page = Math.max(1, parseInt(String(req.query.page ?? 1)));
1450
3033
  const limit = Math.min(100, Math.max(1, parseInt(String(req.query.limit ?? 20))));
1451
3034
  const offset = (page - 1) * limit;
1452
- const allowedSort = ["created_at", "updated_at", "published_at", ...ct.fields.map((f) => f.name)];
3035
+ const allowedSort = ["created_at", "updated_at", "published_at", ...ct.fields.map((f2) => f2.name)];
1453
3036
  const sortField = allowedSort.includes(String(req.query.sort ?? "")) ? String(req.query.sort) : "created_at";
1454
3037
  const sortDir = req.query.order === "asc" ? "ASC" : "DESC";
1455
3038
  assertSafeIdentifier(sortField);
@@ -1475,7 +3058,7 @@ var listEntries = async (req, res) => {
1475
3058
  if (!locale2)
1476
3059
  return true;
1477
3060
  const localized = row.localized && typeof row.localized === "object" ? row.localized : {};
1478
- const locales = Object.keys(localized).filter((k) => !k.startsWith("_"));
3061
+ const locales = Object.keys(localized).filter((k3) => !k3.startsWith("_"));
1479
3062
  const meta = localized._meta || {};
1480
3063
  const enabled = meta.enabled ?? locales.length > 0;
1481
3064
  const primary = meta.primary;
@@ -1484,7 +3067,7 @@ var listEntries = async (req, res) => {
1484
3067
  }
1485
3068
  return primary === locale2;
1486
3069
  }
1487
- const filtered = rows.filter((r) => entryMatchesLocale(r, locale));
3070
+ const filtered = rows.filter((r2) => entryMatchesLocale(r2, locale));
1488
3071
  const data = await Promise.all(filtered.map(async (row) => {
1489
3072
  const mmIds = await loadManyToManyIds(row.id, ct.tableName, ct.fields);
1490
3073
  const resolved = resolveLocalizedRow(row, ct, locale, fallbacks);
@@ -1498,7 +3081,7 @@ var listEntries = async (req, res) => {
1498
3081
  if (locale) {
1499
3082
  try {
1500
3083
  const { rows: allRows } = await pool_default.query(`SELECT localized FROM ${quotedTableName}`);
1501
- const matching = allRows.filter((r) => entryMatchesLocale(r, locale));
3084
+ const matching = allRows.filter((r2) => entryMatchesLocale(r2, locale));
1502
3085
  total = matching.length;
1503
3086
  } catch (err) {
1504
3087
  }
@@ -1506,14 +3089,14 @@ var listEntries = async (req, res) => {
1506
3089
  res.json({ data, total, page, limit });
1507
3090
  };
1508
3091
  async function loadManyToManyIds(entryId, tableName, fields) {
1509
- const mmFields = fields.filter((f) => f.type === "relation" && (f.relationType ?? "many-to-one") === "many-to-many");
3092
+ const mmFields = fields.filter((f2) => f2.type === "relation" && (f2.relationType ?? "many-to-one") === "many-to-many");
1510
3093
  if (mmFields.length === 0)
1511
3094
  return {};
1512
3095
  const result = {};
1513
- await Promise.all(mmFields.map(async (f) => {
1514
- const jt = junctionTableName2(tableName, f.name);
3096
+ await Promise.all(mmFields.map(async (f2) => {
3097
+ const jt = junctionTableName2(tableName, f2.name);
1515
3098
  const { rows } = await pool_default.query(`SELECT target_id FROM ${quoteIdentifier(jt)} WHERE source_id = $1`, [entryId]);
1516
- result[f.name] = rows.map((r) => r.target_id);
3099
+ result[f2.name] = rows.map((r2) => r2.target_id);
1517
3100
  }));
1518
3101
  return result;
1519
3102
  }
@@ -1559,13 +3142,13 @@ var createEntry = async (req, res) => {
1559
3142
  res.status(403).json({ error: "Single types are read-only for User role" });
1560
3143
  return;
1561
3144
  }
1562
- const mmFields = ct.fields.filter((f) => f.type === "relation" && (f.relationType ?? "many-to-one") === "many-to-many" && req.body[f.name] !== void 0);
1563
- const fields = ct.fields.filter((f) => req.body[f.name] !== void 0 && !isVirtualRelation(f));
1564
- fields.forEach((f) => assertSafeIdentifier(f.name));
3145
+ const mmFields = ct.fields.filter((f2) => f2.type === "relation" && (f2.relationType ?? "many-to-one") === "many-to-many" && req.body[f2.name] !== void 0);
3146
+ const fields = ct.fields.filter((f2) => req.body[f2.name] !== void 0 && !isVirtualRelation(f2));
3147
+ fields.forEach((f2) => assertSafeIdentifier(f2.name));
1565
3148
  if (ct.kind === "single") {
1566
3149
  const { rows: existing } = await pool_default.query(`SELECT id FROM ${quotedTableName} LIMIT 1`);
1567
3150
  if (existing[0]) {
1568
- const setClauses = fields.map((f, i) => f.type === "media-gallery" || f.type === "array" || f.type === "navigation" ? `${quoteIdentifier(f.name)} = $${i + 1}::jsonb` : `${quoteIdentifier(f.name)} = $${i + 1}`).join(", ");
3151
+ const setClauses = fields.map((f2, i2) => f2.type === "media-gallery" || f2.type === "array" || f2.type === "navigation" ? `${quoteIdentifier(f2.name)} = $${i2 + 1}::jsonb` : `${quoteIdentifier(f2.name)} = $${i2 + 1}`).join(", ");
1569
3152
  const extraClauses = [];
1570
3153
  const extraValues2 = [];
1571
3154
  if (req.body.localized !== void 0) {
@@ -1574,10 +3157,10 @@ var createEntry = async (req, res) => {
1574
3157
  }
1575
3158
  const allClauses = [setClauses, ...extraClauses].filter(Boolean).join(", ");
1576
3159
  const values2 = [
1577
- ...fields.map((f) => {
1578
- const v = req.body[f.name];
1579
- const normalized = f.type === "navigation" ? normalizeNavigationItems(v) : v;
1580
- return f.type === "media-gallery" || f.type === "array" || f.type === "navigation" ? JSON.stringify(normalized) : v;
3160
+ ...fields.map((f2) => {
3161
+ const v3 = req.body[f2.name];
3162
+ const normalized = f2.type === "navigation" ? normalizeNavigationItems(v3) : v3;
3163
+ return f2.type === "media-gallery" || f2.type === "array" || f2.type === "navigation" ? JSON.stringify(normalized) : v3;
1581
3164
  }),
1582
3165
  ...extraValues2,
1583
3166
  existing[0].id
@@ -1585,9 +3168,9 @@ var createEntry = async (req, res) => {
1585
3168
  const updateSql = fields.length + extraValues2.length > 0 ? `UPDATE ${quotedTableName} SET ${allClauses}, updated_at = NOW() WHERE id = $${fields.length + extraValues2.length + 1} RETURNING *` : `UPDATE ${quotedTableName} SET updated_at = NOW() WHERE id = $1 RETURNING *`;
1586
3169
  const updateValues = fields.length + extraValues2.length > 0 ? values2 : [existing[0].id];
1587
3170
  const { rows: rows2 } = await pool_default.query(updateSql, updateValues);
1588
- await Promise.all(mmFields.map((f) => {
1589
- const ids = Array.isArray(req.body[f.name]) ? req.body[f.name] : [];
1590
- return syncManyToMany(existing[0].id, ct.tableName, f, ids);
3171
+ await Promise.all(mmFields.map((f2) => {
3172
+ const ids = Array.isArray(req.body[f2.name]) ? req.body[f2.name] : [];
3173
+ return syncManyToMany(existing[0].id, ct.tableName, f2, ids);
1591
3174
  }));
1592
3175
  res.json(normalizeNavigationFields(rows2[0], ct.fields));
1593
3176
  return;
@@ -1603,27 +3186,27 @@ var createEntry = async (req, res) => {
1603
3186
  extraPlaceholders.push(`$${3 + fields.length}::jsonb`);
1604
3187
  extraValues.push(JSON.stringify(req.body.localized));
1605
3188
  }
1606
- const cols = ["id", "created_by", ...fields.map((f) => f.name), ...extraCols].map((col) => quoteIdentifier(col)).join(", ");
3189
+ const cols = ["id", "created_by", ...fields.map((f2) => f2.name), ...extraCols].map((col) => quoteIdentifier(col)).join(", ");
1607
3190
  const placeholders = [
1608
3191
  "$1",
1609
3192
  "$2",
1610
- ...fields.map((f, i) => f.type === "media-gallery" || f.type === "array" || f.type === "navigation" ? `$${i + 3}::jsonb` : `$${i + 3}`),
3193
+ ...fields.map((f2, i2) => f2.type === "media-gallery" || f2.type === "array" || f2.type === "navigation" ? `$${i2 + 3}::jsonb` : `$${i2 + 3}`),
1611
3194
  ...extraPlaceholders
1612
3195
  ].join(", ");
1613
3196
  const values = [
1614
3197
  id,
1615
3198
  userId,
1616
- ...fields.map((f) => {
1617
- const v = req.body[f.name];
1618
- const normalized = f.type === "navigation" ? normalizeNavigationItems(v) : v;
1619
- return f.type === "media-gallery" || f.type === "array" || f.type === "navigation" ? JSON.stringify(normalized) : v;
3199
+ ...fields.map((f2) => {
3200
+ const v3 = req.body[f2.name];
3201
+ const normalized = f2.type === "navigation" ? normalizeNavigationItems(v3) : v3;
3202
+ return f2.type === "media-gallery" || f2.type === "array" || f2.type === "navigation" ? JSON.stringify(normalized) : v3;
1620
3203
  }),
1621
3204
  ...extraValues
1622
3205
  ];
1623
3206
  const { rows } = await pool_default.query(`INSERT INTO ${quotedTableName} (${cols}) VALUES (${placeholders}) RETURNING *`, values);
1624
- await Promise.all(mmFields.map((f) => {
1625
- const ids = Array.isArray(req.body[f.name]) ? req.body[f.name] : [];
1626
- return syncManyToMany(id, ct.tableName, f, ids);
3207
+ await Promise.all(mmFields.map((f2) => {
3208
+ const ids = Array.isArray(req.body[f2.name]) ? req.body[f2.name] : [];
3209
+ return syncManyToMany(id, ct.tableName, f2, ids);
1627
3210
  }));
1628
3211
  res.status(201).json(normalizeNavigationFields(rows[0], ct.fields));
1629
3212
  triggerWebhooks("entry.created", { content_type: req.params.slug, entry_id: rows[0].id });
@@ -1680,10 +3263,10 @@ var updateEntry = async (req, res) => {
1680
3263
  return;
1681
3264
  }
1682
3265
  }
1683
- const mmFields = ct.fields.filter((f) => f.type === "relation" && (f.relationType ?? "many-to-one") === "many-to-many" && req.body[f.name] !== void 0);
1684
- const fields = ct.fields.filter((f) => req.body[f.name] !== void 0 && !isVirtualRelation(f));
1685
- fields.forEach((f) => assertSafeIdentifier(f.name));
1686
- const setClauses = fields.map((f, i) => f.type === "media-gallery" || f.type === "array" || f.type === "navigation" ? `${quoteIdentifier(f.name)} = $${i + 1}::jsonb` : `${quoteIdentifier(f.name)} = $${i + 1}`).join(", ");
3266
+ const mmFields = ct.fields.filter((f2) => f2.type === "relation" && (f2.relationType ?? "many-to-one") === "many-to-many" && req.body[f2.name] !== void 0);
3267
+ const fields = ct.fields.filter((f2) => req.body[f2.name] !== void 0 && !isVirtualRelation(f2));
3268
+ fields.forEach((f2) => assertSafeIdentifier(f2.name));
3269
+ const setClauses = fields.map((f2, i2) => f2.type === "media-gallery" || f2.type === "array" || f2.type === "navigation" ? `${quoteIdentifier(f2.name)} = $${i2 + 1}::jsonb` : `${quoteIdentifier(f2.name)} = $${i2 + 1}`).join(", ");
1687
3270
  const extraClauses = [];
1688
3271
  const extraValues = [];
1689
3272
  if (req.body.localized !== void 0) {
@@ -1692,10 +3275,10 @@ var updateEntry = async (req, res) => {
1692
3275
  }
1693
3276
  const allClauses = [setClauses, ...extraClauses].filter(Boolean).join(", ");
1694
3277
  const values = [
1695
- ...fields.map((f) => {
1696
- const v = req.body[f.name];
1697
- const normalized = f.type === "navigation" ? normalizeNavigationItems(v) : v;
1698
- return f.type === "media-gallery" || f.type === "array" || f.type === "navigation" ? JSON.stringify(normalized) : v;
3278
+ ...fields.map((f2) => {
3279
+ const v3 = req.body[f2.name];
3280
+ const normalized = f2.type === "navigation" ? normalizeNavigationItems(v3) : v3;
3281
+ return f2.type === "media-gallery" || f2.type === "array" || f2.type === "navigation" ? JSON.stringify(normalized) : v3;
1699
3282
  }),
1700
3283
  ...extraValues,
1701
3284
  req.params.id
@@ -1707,9 +3290,9 @@ var updateEntry = async (req, res) => {
1707
3290
  res.status(404).json({ error: "Entry not found" });
1708
3291
  return;
1709
3292
  }
1710
- await Promise.all(mmFields.map((f) => {
1711
- const ids = Array.isArray(req.body[f.name]) ? req.body[f.name] : [];
1712
- return syncManyToMany(req.params.id, ct.tableName, f, ids);
3293
+ await Promise.all(mmFields.map((f2) => {
3294
+ const ids = Array.isArray(req.body[f2.name]) ? req.body[f2.name] : [];
3295
+ return syncManyToMany(req.params.id, ct.tableName, f2, ids);
1713
3296
  }));
1714
3297
  res.json(normalizeNavigationFields(rows[0], ct.fields));
1715
3298
  triggerWebhooks("entry.updated", { content_type: req.params.slug, entry_id: req.params.id });
@@ -1873,6 +3456,13 @@ var UpdateMeSchema = z4.object({
1873
3456
  organization: z4.string().max(150).optional(),
1874
3457
  country: z4.string().max(100).optional()
1875
3458
  });
3459
+ var TwoFactorCodeSchema = z4.object({
3460
+ code: z4.string().trim().length(6)
3461
+ });
3462
+ var DisableTwoFactorSchema = z4.object({
3463
+ password: z4.string().min(1),
3464
+ code: z4.string().trim().length(6)
3465
+ });
1876
3466
  async function resolveAvatarUrl(row) {
1877
3467
  if (!row.avatar_url || row.avatar_url.startsWith("http"))
1878
3468
  return row;
@@ -1892,7 +3482,7 @@ async function listUsers(_req, res) {
1892
3482
  }
1893
3483
  async function getMe(req, res) {
1894
3484
  const { rows } = await pool_default.query(`SELECT u.id, u.email, u.role_id, u.first_name, u.last_name, u.avatar_url,
1895
- u.job_title, u.organization, u.country, u.created_at,
3485
+ u.job_title, u.organization, u.country, u.two_factor_enabled, u.created_at,
1896
3486
  r.permissions
1897
3487
  FROM plank_users u
1898
3488
  JOIN plank_roles r ON r.id = u.role_id
@@ -1902,12 +3492,100 @@ async function getMe(req, res) {
1902
3492
  return;
1903
3493
  }
1904
3494
  const resolved = await resolveAvatarUrl(rows[0]);
1905
- res.json({ ...resolved, permissions: rows[0].permissions });
3495
+ res.json({ ...resolved, permissions: rows[0].permissions, two_factor_enabled: rows[0].two_factor_enabled });
3496
+ }
3497
+ async function getTwoFactorStatus(req, res) {
3498
+ const { rows } = await pool_default.query("SELECT two_factor_enabled FROM plank_users WHERE id = $1", [req.user.id]);
3499
+ if (!rows[0]) {
3500
+ res.status(404).json({ error: "User not found" });
3501
+ return;
3502
+ }
3503
+ res.json({ enabled: rows[0].two_factor_enabled });
3504
+ }
3505
+ async function startTwoFactorSetup(req, res) {
3506
+ const { rows } = await pool_default.query("SELECT email, two_factor_enabled FROM plank_users WHERE id = $1", [req.user.id]);
3507
+ if (!rows[0]) {
3508
+ res.status(404).json({ error: "User not found" });
3509
+ return;
3510
+ }
3511
+ if (rows[0].two_factor_enabled) {
3512
+ res.status(400).json({ error: "2FA is already enabled" });
3513
+ return;
3514
+ }
3515
+ const secret = I2();
3516
+ await pool_default.query("UPDATE plank_users SET two_factor_temp_secret = $1 WHERE id = $2", [
3517
+ encrypt(secret),
3518
+ req.user.id
3519
+ ]);
3520
+ const otpauthUri = T2({ issuer: "Plank CMS", label: rows[0].email, secret });
3521
+ res.json({ otpauthUri, secret });
3522
+ }
3523
+ async function verifyTwoFactorSetup(req, res) {
3524
+ const parsed = TwoFactorCodeSchema.safeParse(req.body);
3525
+ if (!parsed.success) {
3526
+ res.status(400).json({ errors: flattenError4(parsed.error, (i2) => i2.message) });
3527
+ return;
3528
+ }
3529
+ const { rows } = await pool_default.query("SELECT two_factor_temp_secret FROM plank_users WHERE id = $1", [req.user.id]);
3530
+ const tempSecret = rows[0]?.two_factor_temp_secret;
3531
+ if (!tempSecret) {
3532
+ res.status(400).json({ error: "No pending 2FA setup found" });
3533
+ return;
3534
+ }
3535
+ const result = d3({ token: parsed.data.code, secret: decrypt(tempSecret) });
3536
+ if (!result.valid) {
3537
+ res.status(401).json({ error: "Invalid verification code" });
3538
+ return;
3539
+ }
3540
+ await pool_default.query(`UPDATE plank_users
3541
+ SET two_factor_enabled = TRUE,
3542
+ two_factor_secret = two_factor_temp_secret,
3543
+ two_factor_temp_secret = NULL,
3544
+ session_version = session_version + 1
3545
+ WHERE id = $1`, [req.user.id]);
3546
+ res.status(204).end();
3547
+ }
3548
+ async function disableTwoFactor(req, res) {
3549
+ const parsed = DisableTwoFactorSchema.safeParse(req.body);
3550
+ if (!parsed.success) {
3551
+ res.status(400).json({ errors: flattenError4(parsed.error, (i2) => i2.message) });
3552
+ return;
3553
+ }
3554
+ const { rows } = await pool_default.query("SELECT two_factor_enabled, two_factor_secret, password FROM plank_users WHERE id = $1", [req.user.id]);
3555
+ const user = rows[0];
3556
+ if (!user) {
3557
+ res.status(404).json({ error: "User not found" });
3558
+ return;
3559
+ }
3560
+ if (!user.two_factor_enabled || !user.two_factor_secret) {
3561
+ res.status(400).json({ error: "2FA is not enabled" });
3562
+ return;
3563
+ }
3564
+ const passwordOk = await bcrypt2.compare(parsed.data.password, user.password);
3565
+ if (!passwordOk) {
3566
+ res.status(401).json({ error: "Current password is incorrect" });
3567
+ return;
3568
+ }
3569
+ const result = d3({
3570
+ token: parsed.data.code,
3571
+ secret: decrypt(user.two_factor_secret)
3572
+ });
3573
+ if (!result.valid) {
3574
+ res.status(401).json({ error: "Invalid verification code" });
3575
+ return;
3576
+ }
3577
+ await pool_default.query(`UPDATE plank_users
3578
+ SET two_factor_enabled = FALSE,
3579
+ two_factor_secret = NULL,
3580
+ two_factor_temp_secret = NULL,
3581
+ session_version = session_version + 1
3582
+ WHERE id = $1`, [req.user.id]);
3583
+ res.status(204).end();
1906
3584
  }
1907
3585
  async function updateMe(req, res) {
1908
3586
  const parsed = UpdateMeSchema.safeParse(req.body);
1909
3587
  if (!parsed.success) {
1910
- res.status(400).json({ errors: flattenError4(parsed.error, (i) => i.message) });
3588
+ res.status(400).json({ errors: flattenError4(parsed.error, (i2) => i2.message) });
1911
3589
  return;
1912
3590
  }
1913
3591
  const { firstName, lastName, jobTitle, organization, country } = parsed.data;
@@ -1978,7 +3656,7 @@ async function deleteAvatar(req, res) {
1978
3656
  async function changePassword(req, res) {
1979
3657
  const parsed = ChangePasswordSchema.safeParse(req.body);
1980
3658
  if (!parsed.success) {
1981
- res.status(400).json({ errors: flattenError4(parsed.error, (i) => i.message) });
3659
+ res.status(400).json({ errors: flattenError4(parsed.error, (i2) => i2.message) });
1982
3660
  return;
1983
3661
  }
1984
3662
  const { rows } = await pool_default.query("SELECT password FROM plank_users WHERE id = $1", [req.user.id]);
@@ -1992,13 +3670,13 @@ async function changePassword(req, res) {
1992
3670
  return;
1993
3671
  }
1994
3672
  const hashed = await bcrypt2.hash(parsed.data.newPassword, 12);
1995
- await pool_default.query("UPDATE plank_users SET password = $1 WHERE id = $2", [hashed, req.user.id]);
3673
+ await pool_default.query("UPDATE plank_users SET password = $1, session_version = session_version + 1 WHERE id = $2", [hashed, req.user.id]);
1996
3674
  res.status(204).end();
1997
3675
  }
1998
3676
  async function createUser(req, res) {
1999
3677
  const parsed = CreateUserSchema.safeParse(req.body);
2000
3678
  if (!parsed.success) {
2001
- res.status(400).json({ errors: flattenError4(parsed.error, (i) => i.message) });
3679
+ res.status(400).json({ errors: flattenError4(parsed.error, (i2) => i2.message) });
2002
3680
  return;
2003
3681
  }
2004
3682
  const { email, password, roleId } = parsed.data;
@@ -2016,7 +3694,7 @@ async function createUser(req, res) {
2016
3694
  async function updateUser(req, res) {
2017
3695
  const parsed = UpdateUserSchema.safeParse(req.body);
2018
3696
  if (!parsed.success) {
2019
- res.status(400).json({ errors: flattenError4(parsed.error, (i) => i.message) });
3697
+ res.status(400).json({ errors: flattenError4(parsed.error, (i2) => i2.message) });
2020
3698
  return;
2021
3699
  }
2022
3700
  const { email, roleId, firstName, lastName } = parsed.data;
@@ -2124,7 +3802,7 @@ async function resetRoles(_req, res) {
2124
3802
  }
2125
3803
 
2126
3804
  // ../core/dist/controllers/apiTokens.js
2127
- import { randomBytes as randomBytes5, createHash } from "crypto";
3805
+ import { randomBytes as randomBytes6, createHash } from "crypto";
2128
3806
  import { z as z7, flattenError as flattenError5 } from "zod";
2129
3807
  var CreateTokenSchema = z7.object({
2130
3808
  name: z7.string().min(1),
@@ -2140,12 +3818,12 @@ async function listApiTokens(_req, res) {
2140
3818
  async function createApiToken(req, res) {
2141
3819
  const parsed = CreateTokenSchema.safeParse(req.body);
2142
3820
  if (!parsed.success) {
2143
- res.status(400).json({ errors: flattenError5(parsed.error, (i) => i.message) });
3821
+ res.status(400).json({ errors: flattenError5(parsed.error, (i2) => i2.message) });
2144
3822
  return;
2145
3823
  }
2146
3824
  const { name, accessType } = parsed.data;
2147
3825
  const id = createId();
2148
- const token = `plank_${randomBytes5(32).toString("hex")}`;
3826
+ const token = `plank_${randomBytes6(32).toString("hex")}`;
2149
3827
  const hashed = hashToken(token);
2150
3828
  await pool_default.query("INSERT INTO plank_api_tokens (id, name, token, access_type, created_by) VALUES ($1, $2, $3, $4, $5)", [id, name, hashed, accessType, req.user.id]);
2151
3829
  res.status(201).json({ id, name, accessType, token });
@@ -2160,7 +3838,7 @@ async function deleteApiToken(req, res) {
2160
3838
  }
2161
3839
 
2162
3840
  // ../core/dist/controllers/media.js
2163
- import { randomBytes as randomBytes6 } from "crypto";
3841
+ import { randomBytes as randomBytes7 } from "crypto";
2164
3842
  var MEDIA_PREFIX = "media";
2165
3843
  async function listMedia(req, res) {
2166
3844
  const page = Math.max(1, parseInt(req.query.page) || 1);
@@ -2173,18 +3851,18 @@ async function listMedia(req, res) {
2173
3851
  ORDER BY created_at DESC
2174
3852
  LIMIT $1 OFFSET $2`, [limit, offset, folderId]);
2175
3853
  const provider = await getProvider();
2176
- const items = await Promise.all(rows.map(async (r) => ({
2177
- id: r.id,
2178
- filename: r.filename,
2179
- url: await provider.getUrl(r.provider_key),
2180
- mime_type: r.mime_type,
2181
- size: r.size,
2182
- alt: r.alt,
2183
- width: r.width,
2184
- height: r.height,
2185
- folder_id: r.folder_id,
2186
- uploaded_by: r.uploaded_by,
2187
- created_at: r.created_at
3854
+ const items = await Promise.all(rows.map(async (r2) => ({
3855
+ id: r2.id,
3856
+ filename: r2.filename,
3857
+ url: await provider.getUrl(r2.provider_key),
3858
+ mime_type: r2.mime_type,
3859
+ size: r2.size,
3860
+ alt: r2.alt,
3861
+ width: r2.width,
3862
+ height: r2.height,
3863
+ folder_id: r2.folder_id,
3864
+ uploaded_by: r2.uploaded_by,
3865
+ created_at: r2.created_at
2188
3866
  })));
2189
3867
  const total = rows[0] ? parseInt(rows[0].total) : 0;
2190
3868
  res.json({ items, total, page, limit, pages: Math.ceil(total / limit) });
@@ -2206,12 +3884,12 @@ async function uploadMedia(req, res) {
2206
3884
  }
2207
3885
  }
2208
3886
  if (isBundle) {
2209
- const m3u8File = files.find((f) => f.originalname.endsWith(".m3u8"));
3887
+ const m3u8File = files.find((f2) => f2.originalname.endsWith(".m3u8"));
2210
3888
  if (!m3u8File) {
2211
3889
  res.status(400).json({ error: "No .m3u8 file found in bundle" });
2212
3890
  return;
2213
3891
  }
2214
- const bundleId = randomBytes6(8).toString("hex");
3892
+ const bundleId = randomBytes7(8).toString("hex");
2215
3893
  const prefix = [MEDIA_PREFIX, folderId, bundleId].filter(Boolean).join("/");
2216
3894
  const rootDir = m3u8File.originalname.includes("/") ? m3u8File.originalname.split("/")[0] : null;
2217
3895
  const stripRoot = (path) => rootDir && path.startsWith(`${rootDir}/`) ? path.slice(rootDir.length + 1) : path;
@@ -2385,7 +4063,7 @@ function maskSettings(namespace, settings) {
2385
4063
  const sensitive = SENSITIVE_FIELDS2[namespace];
2386
4064
  if (!sensitive)
2387
4065
  return settings;
2388
- return Object.fromEntries(Object.entries(settings).map(([k, v]) => [k, sensitive.has(k) && v ? MASKED : v]));
4066
+ return Object.fromEntries(Object.entries(settings).map(([k3, v3]) => [k3, sensitive.has(k3) && v3 ? MASKED : v3]));
2389
4067
  }
2390
4068
  async function getNamespaceSettings(req, res) {
2391
4069
  const { namespace } = req.params;
@@ -2436,6 +4114,10 @@ router2.post("/users/me/avatar/confirm", confirmAvatar);
2436
4114
  router2.delete("/users/me/avatar", deleteAvatar);
2437
4115
  router2.get("/users/me/prefs/:key", getUserPref);
2438
4116
  router2.put("/users/me/prefs/:key", setUserPref);
4117
+ router2.get("/users/me/2fa", getTwoFactorStatus);
4118
+ router2.post("/users/me/2fa/setup", startTwoFactorSetup);
4119
+ router2.post("/users/me/2fa/verify", verifyTwoFactorSetup);
4120
+ router2.post("/users/me/2fa/disable", disableTwoFactor);
2439
4121
  router2.get("/roles", authorize("settings:users:read"), listRoles);
2440
4122
  router2.put("/roles/:id", authorize("settings:roles:write"), updateRole);
2441
4123
  router2.post("/roles/reset", authorize("settings:roles:write"), resetRoles);
@@ -2519,8 +4201,8 @@ function normalizeNavigationItems2(value) {
2519
4201
  });
2520
4202
  }
2521
4203
  async function resolveMediaFields(entries, ct) {
2522
- const singleFields = ct.fields.filter((f) => f.type === "media").map((f) => f.name);
2523
- const galleryFields = ct.fields.filter((f) => f.type === "media-gallery").map((f) => f.name);
4204
+ const singleFields = ct.fields.filter((f2) => f2.type === "media").map((f2) => f2.name);
4205
+ const galleryFields = ct.fields.filter((f2) => f2.type === "media-gallery").map((f2) => f2.name);
2524
4206
  if (singleFields.length === 0 && galleryFields.length === 0)
2525
4207
  return;
2526
4208
  const idSet = /* @__PURE__ */ new Set();
@@ -2545,8 +4227,8 @@ async function resolveMediaFields(entries, ct) {
2545
4227
  const { rows } = await pool_default.query("SELECT id, provider_key FROM plank_media WHERE id = ANY($1)", [[...idSet]]);
2546
4228
  const provider = await getProvider();
2547
4229
  const urlMap = /* @__PURE__ */ new Map();
2548
- await Promise.all(rows.map(async (r) => {
2549
- urlMap.set(r.id, await provider.getUrl(r.provider_key));
4230
+ await Promise.all(rows.map(async (r2) => {
4231
+ urlMap.set(r2.id, await provider.getUrl(r2.provider_key));
2550
4232
  }));
2551
4233
  for (const entry of entries) {
2552
4234
  for (const name of singleFields) {
@@ -2572,11 +4254,11 @@ var SYSTEM_FIELDS = /* @__PURE__ */ new Set([
2572
4254
  "updated_at"
2573
4255
  ]);
2574
4256
  function stripSystemFields(row) {
2575
- return Object.fromEntries(Object.entries(row).filter(([k]) => !SYSTEM_FIELDS.has(k)));
4257
+ return Object.fromEntries(Object.entries(row).filter(([k3]) => !SYSTEM_FIELDS.has(k3)));
2576
4258
  }
2577
4259
  async function resolveRelationFields(entries, ct) {
2578
- const scalarFields = ct.fields.filter((f) => f.type === "relation" && (f.relationType === "many-to-one" || f.relationType === "one-to-one" || !f.relationType) && f.relatedTable);
2579
- const mmFields = ct.fields.filter((f) => f.type === "relation" && (f.relationType ?? "many-to-one") === "many-to-many" && f.relatedTable);
4260
+ const scalarFields = ct.fields.filter((f2) => f2.type === "relation" && (f2.relationType === "many-to-one" || f2.relationType === "one-to-one" || !f2.relationType) && f2.relatedTable);
4261
+ const mmFields = ct.fields.filter((f2) => f2.type === "relation" && (f2.relationType ?? "many-to-one") === "many-to-many" && f2.relatedTable);
2580
4262
  const entryIds = entries.map((e) => e.id);
2581
4263
  await Promise.all([
2582
4264
  ...scalarFields.map(async (field) => {
@@ -2587,7 +4269,7 @@ async function resolveRelationFields(entries, ct) {
2587
4269
  const { rows } = await pool_default.query(`SELECT * FROM ${field.relatedTable} WHERE id = ANY($1)`, [
2588
4270
  ids
2589
4271
  ]);
2590
- const map = new Map(rows.map((r) => [r.id, stripSystemFields(r)]));
4272
+ const map = new Map(rows.map((r2) => [r2.id, stripSystemFields(r2)]));
2591
4273
  for (const entry of entries) {
2592
4274
  const id = entry[field.name];
2593
4275
  entry[field.name] = id ? map.get(id) ?? null : null;
@@ -2598,7 +4280,7 @@ async function resolveRelationFields(entries, ct) {
2598
4280
  return;
2599
4281
  const jt = `_rel_${ct.tableName}_${field.name}`;
2600
4282
  const { rows: jRows } = await pool_default.query(`SELECT source_id, target_id FROM ${jt} WHERE source_id = ANY($1)`, [entryIds]);
2601
- const allTargetIds = [...new Set(jRows.map((r) => r.target_id))];
4283
+ const allTargetIds = [...new Set(jRows.map((r2) => r2.target_id))];
2602
4284
  const relatedMap = /* @__PURE__ */ new Map();
2603
4285
  if (allTargetIds.length > 0) {
2604
4286
  assertSafeIdentifier(field.relatedTable);
@@ -2639,22 +4321,22 @@ function serializeEntry(row, ct, statusParam, locale, fallbacks = []) {
2639
4321
  if (locale) {
2640
4322
  const localizedContainer = source && typeof source === "object" && source.localized && typeof source.localized === "object" ? source.localized : row.localized && typeof row.localized === "object" ? row.localized : {};
2641
4323
  const localizableTypes = /* @__PURE__ */ new Set(["string", "text", "richtext", "uid"]);
2642
- for (const f of ct.fields) {
2643
- if (!localizableTypes.has(f.type))
4324
+ for (const f2 of ct.fields) {
4325
+ if (!localizableTypes.has(f2.type))
2644
4326
  continue;
2645
4327
  let val = void 0;
2646
- if (localizedContainer[locale] && localizedContainer[locale][f.name] !== void 0) {
2647
- val = localizedContainer[locale][f.name];
4328
+ if (localizedContainer[locale] && localizedContainer[locale][f2.name] !== void 0) {
4329
+ val = localizedContainer[locale][f2.name];
2648
4330
  } else {
2649
4331
  for (const fb of fallbacks) {
2650
- if (localizedContainer[fb] && localizedContainer[fb][f.name] !== void 0) {
2651
- val = localizedContainer[fb][f.name];
4332
+ if (localizedContainer[fb] && localizedContainer[fb][f2.name] !== void 0) {
4333
+ val = localizedContainer[fb][f2.name];
2652
4334
  break;
2653
4335
  }
2654
4336
  }
2655
4337
  }
2656
4338
  if (val !== void 0)
2657
- effective[f.name] = val;
4339
+ effective[f2.name] = val;
2658
4340
  }
2659
4341
  }
2660
4342
  const out = { id: row.id };
@@ -2712,7 +4394,7 @@ var listPublicEntries = async (req, res) => {
2712
4394
  const offset = (page - 1) * limit;
2713
4395
  const locale = req.query.locale ? String(req.query.locale) : void 0;
2714
4396
  const fallbacks = req.query.fallback ? String(req.query.fallback).split(",") : [];
2715
- const knownFields = new Set(ct.fields.map((f) => f.name));
4397
+ const knownFields = new Set(ct.fields.map((f2) => f2.name));
2716
4398
  const systemSortFields = /* @__PURE__ */ new Set(["created_at", "updated_at", "published_at"]);
2717
4399
  const filterClauses = [];
2718
4400
  const filterValues = [];
@@ -2800,7 +4482,7 @@ function errorHandler(err, _req, res, _next) {
2800
4482
  return;
2801
4483
  }
2802
4484
  if (err instanceof ZodError) {
2803
- res.status(400).json({ errors: flattenError6(err, (i) => i.message) });
4485
+ res.status(400).json({ errors: flattenError6(err, (i2) => i2.message) });
2804
4486
  return;
2805
4487
  }
2806
4488
  console.error("[plank] Unhandled error:", err);
@@ -2808,6 +4490,17 @@ function errorHandler(err, _req, res, _next) {
2808
4490
  }
2809
4491
 
2810
4492
  // ../core/dist/app.js
4493
+ function assertSecurityEnv() {
4494
+ if (process.env.NODE_ENV !== "production")
4495
+ return;
4496
+ if (!process.env.PLANK_JWT_SECRET || process.env.PLANK_JWT_SECRET.length < 32) {
4497
+ throw new Error("PLANK_JWT_SECRET is required in production and should be at least 32 characters.");
4498
+ }
4499
+ if (!process.env.PLANK_ENCRYPTION_KEY || process.env.PLANK_ENCRYPTION_KEY.length !== 64) {
4500
+ throw new Error("PLANK_ENCRYPTION_KEY is required in production and must be 64 hex characters.");
4501
+ }
4502
+ }
4503
+ assertSecurityEnv();
2811
4504
  var app = express();
2812
4505
  app.use(helmet({
2813
4506
  contentSecurityPolicy: {
@@ -2826,9 +4519,9 @@ app.use("/cms/auth", cmsCorOptions, auth_default);
2826
4519
  app.use("/cms/admin", cmsCorOptions, admin_default);
2827
4520
  app.use("/api", cors(), public_default);
2828
4521
  app.get("/", (_req, res) => res.redirect("/admin"));
2829
- var adminDist = process.env.PLANK_ADMIN_DIST ?? join3(dirname2(fileURLToPath2(import.meta.url)), "../public/admin");
4522
+ var adminDist = process.env.PLANK_ADMIN_DIST ?? join4(dirname2(fileURLToPath2(import.meta.url)), "../public/admin");
2830
4523
  app.use("/admin", express.static(adminDist));
2831
- app.get("/admin/*path", (_req, res) => res.sendFile(join3(adminDist, "index.html")));
4524
+ app.get("/admin/*path", (_req, res) => res.sendFile(join4(adminDist, "index.html")));
2832
4525
  app.use(errorHandler);
2833
4526
  var app_default = app;
2834
4527
 
@@ -2847,3 +4540,8 @@ async function start() {
2847
4540
  export {
2848
4541
  start
2849
4542
  };
4543
+ /*! Bundled license information:
4544
+
4545
+ @scure/base/index.js:
4546
+ (*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
4547
+ */