@orieljs/framework 0.1.0-alpha.3 → 0.1.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -22,18 +22,32 @@ import {
22
22
  renderToString,
23
23
  styleString,
24
24
  view
25
- } from "./chunk-WEGTH46M.js";
25
+ } from "./chunk-3DETYZMZ.js";
26
26
  import {
27
+ API_ROUTES_STUB,
27
28
  Application as Application2,
28
29
  ApplicationBuilder,
29
30
  BusFake,
30
31
  ClosureKernel,
31
32
  Component,
32
33
  Computed,
34
+ ConvertEmptyStringsToNull,
33
35
  CorruptComponentPayloadError,
34
36
  ErrorBag,
37
+ ErrorHandler,
35
38
  EventFake,
39
+ ExceptionsConfiguration,
40
+ FormUploadedFile,
41
+ HttpException,
42
+ HttpRedirectResponse,
43
+ HttpRedirector,
44
+ HttpResponseException,
45
+ HttpResponseFactory,
46
+ HttpServerError,
47
+ HttpServiceProvider,
48
+ IncomingRequest,
36
49
  InvalidLiveRequestError,
50
+ Kernel,
37
51
  Live,
38
52
  LiveComponentManager,
39
53
  LiveComponentNotFoundError,
@@ -42,8 +56,10 @@ import {
42
56
  Locked,
43
57
  MailFake,
44
58
  MethodNotCallableError,
59
+ MiddlewareConfiguration,
45
60
  NotificationFake,
46
61
  On,
62
+ PERSISTENT_MIDDLEWARE,
47
63
  PendingEvent,
48
64
  PropertyNotUpdatableError,
49
65
  ProviderBootError,
@@ -51,18 +67,69 @@ import {
51
67
  QueueFake,
52
68
  Repository,
53
69
  StorageFake,
70
+ TestRequestScope,
54
71
  Testable,
72
+ TrimStrings,
55
73
  UPDATE_URI,
56
74
  Vite,
57
75
  ViteError,
58
76
  ViteHtml,
77
+ abort,
78
+ abortIf,
79
+ abortUnless,
80
+ addApiRouting,
81
+ applyExceptionCallbacks,
82
+ applyMiddlewareCallbacks,
83
+ back,
84
+ bunRuntime,
85
+ clientAddress,
59
86
  componentName,
87
+ contentDisposition,
88
+ currentRequest,
60
89
  currentVite,
90
+ debugPage,
91
+ detectRuntime,
61
92
  env,
93
+ escapeHtml,
94
+ exceedsJsonDepth,
95
+ extensionFromMime,
96
+ filterRouteList,
97
+ formatRouteList,
98
+ fromEntries,
99
+ ipMatches,
100
+ isBlank,
62
101
  live,
102
+ mergeRecursive,
103
+ minimalPage,
104
+ normalizeLists,
105
+ optionalCookieJar,
106
+ optionalSession,
107
+ parseBracketKey,
108
+ persistentMiddleware,
109
+ redirect,
110
+ registerHttpCommands,
111
+ request,
112
+ requestScope,
113
+ response,
114
+ route,
115
+ routeListRows,
116
+ sanitize,
117
+ serve,
118
+ serveBun,
119
+ serveNode,
120
+ servePublicFile,
121
+ setClientAddress,
122
+ stackFrames,
123
+ statusFor,
124
+ statusText,
125
+ summarizeValidation,
126
+ toWebRequest,
127
+ transformLeaves,
128
+ url,
63
129
  vite,
64
- viteReactRefresh
65
- } from "./chunk-I2OMKIQZ.js";
130
+ viteReactRefresh,
131
+ writeResponse
132
+ } from "./chunk-SBZQ6L3Z.js";
66
133
  import {
67
134
  Arr,
68
135
  BindingResolutionError,
@@ -74,6 +141,7 @@ import {
74
141
  LazyCollection,
75
142
  ServiceProvider,
76
143
  Str,
144
+ __,
77
145
  app,
78
146
  collect,
79
147
  config,
@@ -84,7 +152,7 @@ import {
84
152
  retry,
85
153
  tap,
86
154
  value
87
- } from "./chunk-HU43NADT.js";
155
+ } from "./chunk-DCI2T7WJ.js";
88
156
  import {
89
157
  Application,
90
158
  AuthFactory,
@@ -100,25 +168,22 @@ import {
100
168
  DatabaseManager,
101
169
  Encrypter,
102
170
  EventDispatcher,
103
- ExceptionCallbacks,
104
171
  ExceptionHandler,
105
172
  FailedJobProvider,
106
173
  FilesystemManager,
107
174
  Gate,
108
175
  Hasher,
109
- HttpKernel,
110
176
  HttpRequest,
111
177
  InertiaFactory,
112
178
  InertiaSsrGateway,
113
179
  LogManager,
114
180
  MailManager,
115
- MiddlewareCallbacks,
116
181
  NotificationDispatcher,
117
182
  PasswordBroker,
118
183
  PipelineFactory,
119
184
  QueueManager,
185
+ RateLimiter,
120
186
  Redirector,
121
- ResponseFactory,
122
187
  RouteModelResolver,
123
188
  Router,
124
189
  RoutingPaths,
@@ -128,12 +193,14 @@ import {
128
193
  ValidationFactory,
129
194
  ViewFactory,
130
195
  token
131
- } from "./chunk-S7YC43IH.js";
196
+ } from "./chunk-WSGWYXAO.js";
132
197
 
133
198
  // ../Auth/dist/index.js
134
- import { timingSafeEqual } from "crypto";
135
199
  import { createHash } from "crypto";
136
200
  import { createHash as createHash2 } from "crypto";
201
+ import { timingSafeEqual } from "crypto";
202
+ import { createHash as createHash3 } from "crypto";
203
+ import { createHash as createHash4 } from "crypto";
137
204
  import { createHmac } from "crypto";
138
205
  import { readdir } from "fs/promises";
139
206
  import { join } from "path";
@@ -213,6 +280,24 @@ var PasswordReset = class {
213
280
  }
214
281
  user;
215
282
  };
283
+ var Registered = class {
284
+ constructor(user) {
285
+ this.user = user;
286
+ }
287
+ user;
288
+ };
289
+ var Verified = class {
290
+ constructor(user) {
291
+ this.user = user;
292
+ }
293
+ user;
294
+ };
295
+ var Lockout = class {
296
+ constructor(request2) {
297
+ this.request = request2;
298
+ }
299
+ request;
300
+ };
216
301
  var createUrlCallback;
217
302
  var toMailCallback;
218
303
  var ResetPassword = class {
@@ -261,6 +346,83 @@ var ResetPassword = class {
261
346
  return `/reset-password/${encodeURIComponent(this.token)}?email=${encodeURIComponent(email)}`;
262
347
  }
263
348
  };
349
+ var createUrlCallback2;
350
+ var toMailCallback2;
351
+ var VerifyEmail = class {
352
+ /** Build the verification URL yourself (e.g. for a SPA front end). */
353
+ static createUrlUsing(callback) {
354
+ createUrlCallback2 = callback;
355
+ }
356
+ /** Build the mail yourself (e.g. a MailMessage from the Notifications component). */
357
+ static toMailUsing(callback) {
358
+ toMailCallback2 = callback;
359
+ }
360
+ via() {
361
+ return ["mail"];
362
+ }
363
+ toMail(notifiable) {
364
+ const user = notifiable;
365
+ const url2 = this.verificationUrl(user);
366
+ if (toMailCallback2 !== void 0) return toMailCallback2(user, url2);
367
+ const mail = {
368
+ subject: "Verify Email Address",
369
+ lines: ["Please click the button below to verify your email address."],
370
+ actionText: "Verify Email Address",
371
+ actionUrl: url2,
372
+ outroLines: ["If you did not create an account, no further action is required."]
373
+ };
374
+ return mail;
375
+ }
376
+ verificationUrl(notifiable) {
377
+ if (createUrlCallback2 !== void 0) return createUrlCallback2(notifiable);
378
+ const container = currentContainer();
379
+ if (container === void 0 || !container.bound(UrlGenerator)) {
380
+ throw new Error("VerifyEmail needs the UrlGenerator (Routing) to sign the verification link.");
381
+ }
382
+ const config2 = container.bound(ConfigRepository) ? container.make(ConfigRepository) : void 0;
383
+ const minutes = Number(config2?.get("auth.verification.expire", 60) ?? 60);
384
+ const id = typeof notifiable.getKey === "function" ? notifiable.getKey() : notifiable.getAuthIdentifier?.();
385
+ const hash2 = createHash("sha1").update(notifiable.getEmailForVerification()).digest("hex");
386
+ return container.make(UrlGenerator).temporarySignedRoute("verification.verify", minutes * 60, { id, hash: hash2 });
387
+ }
388
+ };
389
+ var SendEmailVerificationNotification = class {
390
+ async handle(event2) {
391
+ const user = event2.user;
392
+ if (typeof user.hasVerifiedEmail !== "function" || typeof user.sendEmailVerificationNotification !== "function") return;
393
+ if (!user.hasVerifiedEmail()) await user.sendEmailVerificationNotification();
394
+ }
395
+ };
396
+ function equals(known, user) {
397
+ const a = Buffer.from(known);
398
+ const b = Buffer.from(user);
399
+ return a.length === b.length && timingSafeEqual(a, b);
400
+ }
401
+ var EmailVerificationRequest = class {
402
+ static async validate() {
403
+ if (!await new this().authorize()) throw new AuthorizationError();
404
+ return {};
405
+ }
406
+ authorize() {
407
+ const request2 = inject(HttpRequest);
408
+ const user = request2.user();
409
+ if (user === void 0 || user === null) return false;
410
+ const key = typeof user.getKey === "function" ? user.getKey() : user.getAuthIdentifier();
411
+ const hash2 = createHash2("sha1").update(user.getEmailForVerification()).digest("hex");
412
+ return equals(String(key), String(request2.route("id") ?? "")) && equals(hash2, String(request2.route("hash") ?? ""));
413
+ }
414
+ rules() {
415
+ return {};
416
+ }
417
+ /** Marks the signed-in user's email as verified and fires Verified, unless it already was. */
418
+ async fulfill() {
419
+ const user = inject(HttpRequest).user();
420
+ if (user === void 0 || user === null || user.hasVerifiedEmail()) return;
421
+ await user.markEmailAsVerified();
422
+ const container = currentContainer();
423
+ if (container?.bound(EventDispatcher)) await container.make(EventDispatcher).dispatch(new Verified(user));
424
+ }
425
+ };
264
426
  var verificationSender;
265
427
  function sendEmailVerificationUsing(callback) {
266
428
  verificationSender = callback;
@@ -316,19 +478,13 @@ function AuthenticatableModel(Base) {
316
478
  getEmailForVerification() {
317
479
  return String(this.getAttribute("email") ?? "");
318
480
  }
481
+ /** Sends the VerifyEmail notification (a signed link), or what sendEmailVerificationUsing() configured. */
319
482
  async sendEmailVerificationNotification() {
320
- if (verificationSender === void 0) {
321
- throw new Error("No email verification sender is configured. Call sendEmailVerificationUsing() in a service provider.");
322
- }
323
- await verificationSender(this);
483
+ if (verificationSender !== void 0) return verificationSender(this);
484
+ return sendNotification(this, new VerifyEmail());
324
485
  }
325
486
  };
326
487
  }
327
- function equals(known, user) {
328
- const a = Buffer.from(known);
329
- const b = Buffer.from(user);
330
- return a.length === b.length && timingSafeEqual(a, b);
331
- }
332
488
  var EloquentUserProvider = class {
333
489
  constructor(hasher, model) {
334
490
  this.hasher = hasher;
@@ -384,7 +540,7 @@ var EloquentUserProvider = class {
384
540
  return this.model;
385
541
  }
386
542
  };
387
- var GUARD_HASH = createHash("sha1").update("Oriel\\Auth\\SessionGuard").digest("hex");
543
+ var GUARD_HASH = createHash3("sha1").update("Oriel\\Auth\\SessionGuard").digest("hex");
388
544
  var SessionGuard = class {
389
545
  constructor(name, provider, container, options = {}) {
390
546
  this.name = name;
@@ -531,8 +687,8 @@ var SessionGuard = class {
531
687
  const session2 = this.#session();
532
688
  if (session2 === void 0) return;
533
689
  session2.put(this.getName(), id);
534
- const store2 = session2;
535
- if (typeof store2.migrate === "function") await store2.migrate(true);
690
+ const store = session2;
691
+ if (typeof store.migrate === "function") await store.migrate(true);
536
692
  else await session2.regenerate(true);
537
693
  }
538
694
  async #cycleRememberToken(user) {
@@ -579,7 +735,7 @@ function parseStoredDate(value2) {
579
735
  }
580
736
  return Number.isNaN(date.getTime()) ? void 0 : date;
581
737
  }
582
- var sha256 = (value2) => createHash2("sha256").update(value2).digest("hex");
738
+ var sha256 = (value2) => createHash4("sha256").update(value2).digest("hex");
583
739
  function tokenableType(user) {
584
740
  const container = currentContainer();
585
741
  const cls = user.constructor;
@@ -647,7 +803,7 @@ var TokenRepository = class {
647
803
  clock;
648
804
  async create(user, name, abilities = ["*"], expiresAt) {
649
805
  const secret = Str.random(40);
650
- const now4 = this.clock();
806
+ const now5 = this.clock();
651
807
  const attributes = {
652
808
  tokenable_type: tokenableType(user),
653
809
  tokenable_id: user.getAuthIdentifier(),
@@ -656,8 +812,8 @@ var TokenRepository = class {
656
812
  abilities: JSON.stringify(abilities),
657
813
  last_used_at: null,
658
814
  expires_at: expiresAt ?? null,
659
- created_at: now4,
660
- updated_at: now4
815
+ created_at: now5,
816
+ updated_at: now5
661
817
  };
662
818
  const id = await this.#query().insertGetId(attributes);
663
819
  return { accessToken: new PersonalAccessToken({ id, ...attributes }, this), plainTextToken: `${id}|${secret}` };
@@ -678,9 +834,9 @@ var TokenRepository = class {
678
834
  }
679
835
  /** Records the token's use (last_used_at). */
680
836
  async touch(token2) {
681
- const now4 = this.clock();
682
- token2.attributes.last_used_at = now4;
683
- await this.#query().where("id", token2.id).update({ last_used_at: now4 });
837
+ const now5 = this.clock();
838
+ token2.attributes.last_used_at = now5;
839
+ await this.#query().where("id", token2.id).update({ last_used_at: now5 });
684
840
  }
685
841
  async tokensFor(user) {
686
842
  const rows = await this.#query().where("tokenable_type", tokenableType(user)).where("tokenable_id", user.getAuthIdentifier()).get();
@@ -790,15 +946,15 @@ var TokenGuard = class {
790
946
  return { user, token: token2 };
791
947
  }
792
948
  #isValid(token2) {
793
- const now4 = (this.options.clock ?? (() => /* @__PURE__ */ new Date()))().getTime();
949
+ const now5 = (this.options.clock ?? (() => /* @__PURE__ */ new Date()))().getTime();
794
950
  const expiresAt = token2.expiresAt;
795
951
  const rawExpiresAt = token2.attributes.expires_at;
796
952
  if (rawExpiresAt !== null && rawExpiresAt !== void 0 && expiresAt === void 0) return false;
797
- if (expiresAt !== void 0 && expiresAt.getTime() <= now4) return false;
953
+ if (expiresAt !== void 0 && expiresAt.getTime() <= now5) return false;
798
954
  const expiration = this.options.expiration;
799
955
  if (typeof expiration === "number") {
800
956
  const createdAt = token2.createdAt;
801
- if (createdAt === void 0 || createdAt.getTime() + expiration * 6e4 <= now4) return false;
957
+ if (createdAt === void 0 || createdAt.getTime() + expiration * 6e4 <= now5) return false;
802
958
  }
803
959
  return true;
804
960
  }
@@ -1496,6 +1652,7 @@ var AuthServiceProvider = class extends ServiceProvider {
1496
1652
  if (this.app.bound(Router)) {
1497
1653
  this.app.make(Router).aliasMiddleware("auth", Authenticate).aliasMiddleware("guest", RedirectIfAuthenticated).aliasMiddleware("can", Authorize).aliasMiddleware("verified", EnsureEmailIsVerified);
1498
1654
  }
1655
+ if (this.app.bound(EventDispatcher)) this.app.make(EventDispatcher).listen(Registered, SendEmailVerificationNotification);
1499
1656
  await discoverPolicies(this.app.appPath("Policies"), this.app.make(Gate));
1500
1657
  }
1501
1658
  };
@@ -1568,11 +1725,11 @@ var UniqueLock = class _UniqueLock {
1568
1725
  async acquire(job) {
1569
1726
  const members = job;
1570
1727
  const uniqueFor = typeof members.uniqueFor === "function" ? members.uniqueFor.call(job) : members.uniqueFor ?? 0;
1571
- const store2 = members.uniqueVia?.call(job);
1728
+ const store = members.uniqueVia?.call(job);
1572
1729
  const key = _UniqueLock.key(job);
1573
- if (!await this.store(store2).lock(key, uniqueFor > 0 ? uniqueFor : void 0).get()) return void 0;
1730
+ if (!await this.store(store).lock(key, uniqueFor > 0 ? uniqueFor : void 0).get()) return void 0;
1574
1731
  const spec = { key, untilProcessing: members.uniqueUntilProcessing === true };
1575
- if (store2 !== void 0) spec.store = store2;
1732
+ if (store !== void 0) spec.store = store;
1576
1733
  return spec;
1577
1734
  }
1578
1735
  async release(spec) {
@@ -1918,7 +2075,7 @@ var BusServiceProvider = class extends ServiceProvider {
1918
2075
 
1919
2076
  // ../Cache/dist/index.js
1920
2077
  import { setTimeout as sleep } from "timers/promises";
1921
- import { createHash as createHash3 } from "crypto";
2078
+ import { createHash as createHash5 } from "crypto";
1922
2079
  import { link, mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
1923
2080
  import { dirname, join as join2 } from "path";
1924
2081
  import { setTimeout as sleep2 } from "timers/promises";
@@ -1939,8 +2096,8 @@ var TagsNotSupportedError = class extends Error {
1939
2096
  kind = "Server";
1940
2097
  status = 500;
1941
2098
  name = "TagsNotSupportedError";
1942
- constructor(store2) {
1943
- super(`The [${store2}] cache store does not support tags. Only the redis store does.`);
2099
+ constructor(store) {
2100
+ super(`The [${store}] cache store does not support tags. Only the redis store does.`);
1944
2101
  }
1945
2102
  };
1946
2103
  var UnknownCacheStoreError = class extends Error {
@@ -1974,8 +2131,8 @@ function roundTrip(value2) {
1974
2131
  return JSON.parse(serialize(value2));
1975
2132
  }
1976
2133
  var GenericLock = class {
1977
- constructor(store2, name, seconds, owner, pollMs = 50) {
1978
- this.store = store2;
2134
+ constructor(store, name, seconds, owner, pollMs = 50) {
2135
+ this.store = store;
1979
2136
  this.name = name;
1980
2137
  this.seconds = seconds;
1981
2138
  this.pollMs = pollMs;
@@ -2022,10 +2179,10 @@ var GenericLock = class {
2022
2179
  await this.store.forget(this.name);
2023
2180
  }
2024
2181
  };
2025
- var defaultLockFactory = (store2, name, seconds, owner) => new GenericLock(store2, name, seconds, owner);
2182
+ var defaultLockFactory = (store, name, seconds, owner) => new GenericLock(store, name, seconds, owner);
2026
2183
  var Repository2 = class {
2027
- constructor(store2, lockFactory = defaultLockFactory) {
2028
- this.store = store2;
2184
+ constructor(store, lockFactory = defaultLockFactory) {
2185
+ this.store = store;
2029
2186
  this.lockFactory = lockFactory;
2030
2187
  }
2031
2188
  store;
@@ -2195,7 +2352,7 @@ var FileStore = class {
2195
2352
  directory;
2196
2353
  keyPrefix;
2197
2354
  path(key) {
2198
- const hash2 = createHash3("sha1").update(this.keyPrefix + key).digest("hex");
2355
+ const hash2 = createHash5("sha1").update(this.keyPrefix + key).digest("hex");
2199
2356
  return join2(this.directory, hash2.slice(0, 2), hash2.slice(2, 4), hash2);
2200
2357
  }
2201
2358
  tempPath(path) {
@@ -2366,8 +2523,8 @@ var FileStore = class {
2366
2523
  };
2367
2524
  async function insertOrTakeOver(connection, table, row) {
2368
2525
  if (await connection.table(table).insertOrIgnore(row) === 1) return true;
2369
- const now4 = Math.floor(Date.now() / 1e3);
2370
- return await connection.table(table).where("key", row.key).where("expiration", "<=", now4).update(row) > 0;
2526
+ const now5 = Math.floor(Date.now() / 1e3);
2527
+ return await connection.table(table).where("key", row.key).where("expiration", "<=", now5).update(row) > 0;
2371
2528
  }
2372
2529
  var FOREVER_SECONDS = 31536e4;
2373
2530
  var now22 = () => Math.floor(Date.now() / 1e3);
@@ -2799,8 +2956,8 @@ var CacheManager2 = class {
2799
2956
  const table = cfg.table ?? "cache";
2800
2957
  const lockTable = cfg.lockTable ?? "cache_locks";
2801
2958
  const prefix = this.str(cfg.prefix);
2802
- const store2 = new DatabaseStore(connection, table, prefix);
2803
- return new Repository2(store2, (_store, name, seconds, owner) => new DatabaseLock(connection, lockTable, prefix + name, seconds, owner));
2959
+ const store = new DatabaseStore(connection, table, prefix);
2960
+ return new Repository2(store, (_store, name, seconds, owner) => new DatabaseLock(connection, lockTable, prefix + name, seconds, owner));
2804
2961
  }
2805
2962
  buildRedisStore(cfg) {
2806
2963
  const resolved = resolveRedisConfig(
@@ -2808,8 +2965,8 @@ var CacheManager2 = class {
2808
2965
  (connectionName) => this.container.make(ConfigRepository).get(`database.redis.${connectionName}`, {})
2809
2966
  );
2810
2967
  const redis = makeRedisClient(resolved);
2811
- const store2 = new RedisStore(redis, this.str(cfg.prefix));
2812
- return new RedisRepository(store2, redis);
2968
+ const store = new RedisStore(redis, this.str(cfg.prefix));
2969
+ return new RedisRepository(store, redis);
2813
2970
  }
2814
2971
  store(name) {
2815
2972
  const cacheConfig = this.cacheConfig();
@@ -2878,7 +3035,54 @@ var CacheManager2 = class {
2878
3035
  return this.store().tags(names);
2879
3036
  }
2880
3037
  };
3038
+ var now4 = () => Math.floor(Date.now() / 1e3);
3039
+ var CacheRateLimiter = class {
3040
+ constructor(store) {
3041
+ this.store = store;
3042
+ }
3043
+ store;
3044
+ async tooManyAttempts(key, maxAttempts) {
3045
+ const clean = this.cleanKey(key);
3046
+ if (await this.#attempts(clean) >= maxAttempts) {
3047
+ if (await this.store().has(`${clean}:timer`)) return true;
3048
+ await this.store().forget(clean);
3049
+ }
3050
+ return false;
3051
+ }
3052
+ async hit(key, decaySeconds = 60) {
3053
+ const clean = this.cleanKey(key);
3054
+ const cache2 = this.store();
3055
+ await cache2.add(`${clean}:timer`, now4() + decaySeconds, decaySeconds);
3056
+ const added = await cache2.add(clean, 0, decaySeconds);
3057
+ const hits = await cache2.increment(clean);
3058
+ if (!added && hits === 1) await cache2.put(clean, 1, decaySeconds);
3059
+ return hits;
3060
+ }
3061
+ attempts(key) {
3062
+ return this.#attempts(this.cleanKey(key));
3063
+ }
3064
+ async remaining(key, maxAttempts) {
3065
+ return Math.max(0, maxAttempts - await this.#attempts(this.cleanKey(key)));
3066
+ }
3067
+ async availableIn(key) {
3068
+ const timer = await this.store().get(`${this.cleanKey(key)}:timer`);
3069
+ return timer === void 0 ? 0 : Math.max(0, Number(timer) - now4());
3070
+ }
3071
+ async clear(key) {
3072
+ const clean = this.cleanKey(key);
3073
+ await this.store().forget(clean);
3074
+ await this.store().forget(`${clean}:timer`);
3075
+ }
3076
+ /** Laravel's cleanRateLimiterKey(): accented letters become their plain letter ('zoë' and 'zoe' share a key). */
3077
+ cleanKey(key) {
3078
+ return key.normalize("NFKD").replace(/[̀-ͯ]/g, "");
3079
+ }
3080
+ async #attempts(clean) {
3081
+ return Number(await this.store().get(clean) ?? 0);
3082
+ }
3083
+ };
2881
3084
  var Cache = facade(CacheManager);
3085
+ var RateLimiter2 = facade(RateLimiter);
2882
3086
  function cache(arg, ttlSeconds) {
2883
3087
  const manager2 = inject(CacheManager);
2884
3088
  if (arg === void 0) return manager2;
@@ -2906,6 +3110,12 @@ var CacheServiceProvider = class extends ServiceProvider {
2906
3110
  "cache"
2907
3111
  );
2908
3112
  this.app.singleton(CacheManager, (container) => new CacheManager2(container));
3113
+ this.app.singleton(RateLimiter, (container) => {
3114
+ return new CacheRateLimiter(() => {
3115
+ const name = container.make(ConfigRepository).get("cache.limiter", void 0);
3116
+ return container.make(CacheManager).store(name === void 0 || name === "" ? void 0 : name);
3117
+ });
3118
+ });
2909
3119
  }
2910
3120
  };
2911
3121
 
@@ -2920,7 +3130,7 @@ import { start } from "repl";
2920
3130
  import { existsSync as existsSync2, readdirSync } from "fs";
2921
3131
  import { join as join4 } from "path";
2922
3132
  import { pathToFileURL as pathToFileURL2 } from "url";
2923
- import { createHash as createHash4 } from "crypto";
3133
+ import { createHash as createHash6 } from "crypto";
2924
3134
  import { CronExpressionParser } from "cron-parser";
2925
3135
  var InvalidSignatureError = class extends Error {
2926
3136
  name = "InvalidSignatureError";
@@ -2990,7 +3200,7 @@ var NodeConsoleInput = class {
2990
3200
  const line = this.lines.shift();
2991
3201
  if (line !== void 0) return line;
2992
3202
  if (this.ended) throw new Error("Aborted.");
2993
- return new Promise((resolve4, reject) => this.waiting.push({ resolve: resolve4, reject }));
3203
+ return new Promise((resolve3, reject) => this.waiting.push({ resolve: resolve3, reject }));
2994
3204
  }
2995
3205
  close() {
2996
3206
  const rl = this.rl;
@@ -3035,11 +3245,11 @@ var Command = class {
3035
3245
  consoleOutput = new NodeConsoleOutput();
3036
3246
  consoleInput = new NodeConsoleInput();
3037
3247
  /** @internal Set by the kernel before handle() runs. */
3038
- bind(args, options, io2) {
3248
+ bind(args, options, io) {
3039
3249
  this.boundArguments = args;
3040
3250
  this.boundOptions = options;
3041
- this.consoleInput = io2.input;
3042
- this.consoleOutput = io2.output;
3251
+ this.consoleInput = io.input;
3252
+ this.consoleOutput = io.output;
3043
3253
  }
3044
3254
  argument(name) {
3045
3255
  return this.boundArguments[name];
@@ -4009,15 +4219,15 @@ var ScheduleListCommand = class extends Command {
4009
4219
  function summaryOf(event2) {
4010
4220
  return event2.getSummary();
4011
4221
  }
4012
- async function runDueEvents(events, io2, now4) {
4222
+ async function runDueEvents(events, io, now5) {
4013
4223
  const backgroundRuns = [];
4014
4224
  for (const event2 of events) {
4015
- io2.info(`Running scheduled task: ${summaryOf(event2)}`);
4225
+ io.info(`Running scheduled task: ${summaryOf(event2)}`);
4016
4226
  const attempt = async () => {
4017
4227
  try {
4018
- await event2.run(now4);
4228
+ await event2.run(now5);
4019
4229
  } catch (error) {
4020
- io2.error(` Failed: ${error instanceof Error ? error.message : String(error)}`);
4230
+ io.error(` Failed: ${error instanceof Error ? error.message : String(error)}`);
4021
4231
  }
4022
4232
  };
4023
4233
  if (event2.isBackground()) {
@@ -4032,13 +4242,13 @@ var ScheduleRunCommand = class extends Command {
4032
4242
  signature = "schedule:run";
4033
4243
  description = "Run the scheduled commands";
4034
4244
  async handle() {
4035
- const now4 = /* @__PURE__ */ new Date();
4036
- const due = inject(Schedule).dueEvents(now4);
4245
+ const now5 = /* @__PURE__ */ new Date();
4246
+ const due = inject(Schedule).dueEvents(now5);
4037
4247
  if (due.length === 0) {
4038
4248
  this.info("No scheduled commands are ready to run.");
4039
4249
  return 0;
4040
4250
  }
4041
- await runDueEvents(due, this, now4);
4251
+ await runDueEvents(due, this, now5);
4042
4252
  return 0;
4043
4253
  }
4044
4254
  };
@@ -4052,7 +4262,7 @@ var ScheduleWorkCommand = class extends Command {
4052
4262
  description = "Start the schedule worker";
4053
4263
  async handle() {
4054
4264
  const schedule = inject(Schedule);
4055
- const sleep5 = this.workOptions.sleep ?? ((ms) => new Promise((resolve4) => setTimeout(resolve4, ms)));
4265
+ const sleep5 = this.workOptions.sleep ?? ((ms) => new Promise((resolve3) => setTimeout(resolve3, ms)));
4056
4266
  const clock = this.workOptions.now ?? Date.now;
4057
4267
  this.info("Running scheduled tasks every minute.");
4058
4268
  let lastMinute;
@@ -4061,8 +4271,8 @@ var ScheduleWorkCommand = class extends Command {
4061
4271
  const minute = Math.floor(time / 6e4);
4062
4272
  if (minute !== lastMinute) {
4063
4273
  lastMinute = minute;
4064
- const now4 = new Date(time);
4065
- await runDueEvents(schedule.dueEvents(now4), this, now4);
4274
+ const now5 = new Date(time);
4275
+ await runDueEvents(schedule.dueEvents(now5), this, now5);
4066
4276
  }
4067
4277
  await sleep5(Math.max(0, (minute + 1) * 6e4 - clock()) + 10);
4068
4278
  }
@@ -4085,13 +4295,13 @@ var TestCommand = class extends Command {
4085
4295
  if (typeof filter === "string") args.push("--testNamePattern", filter);
4086
4296
  const extra = this.argument("args");
4087
4297
  if (Array.isArray(extra)) args.push(...extra);
4088
- return new Promise((resolve4) => {
4298
+ return new Promise((resolve3) => {
4089
4299
  const child = this.spawner("npx", args);
4090
4300
  child.on("error", (error) => {
4091
4301
  this.error(error.message);
4092
- resolve4(1);
4302
+ resolve3(1);
4093
4303
  });
4094
- child.on("exit", (code) => resolve4(code ?? 1));
4304
+ child.on("exit", (code) => resolve3(code ?? 1));
4095
4305
  });
4096
4306
  }
4097
4307
  };
@@ -4106,10 +4316,10 @@ var TinkerCommand = class extends Command {
4106
4316
  handle() {
4107
4317
  const app2 = inject(Application);
4108
4318
  const startRepl = this.tinkerOptions.start ?? ((options) => start(options));
4109
- return new Promise((resolve4) => {
4319
+ return new Promise((resolve3) => {
4110
4320
  const repl = startRepl({ prompt: "oriel> " });
4111
4321
  repl.context.app = app2;
4112
- repl.on("exit", () => resolve4(0));
4322
+ repl.on("exit", () => resolve3(0));
4113
4323
  });
4114
4324
  }
4115
4325
  };
@@ -4201,11 +4411,11 @@ function parametersToInput(parameters, signature) {
4201
4411
  }
4202
4412
  return { arguments: args, options };
4203
4413
  }
4204
- var Kernel = class {
4205
- constructor(app2, io2 = {}) {
4414
+ var Kernel2 = class {
4415
+ constructor(app2, io = {}) {
4206
4416
  this.app = app2;
4207
- this.defaultInput = io2.input ?? new NodeConsoleInput();
4208
- this.defaultOutput = io2.output ?? new NodeConsoleOutput();
4417
+ this.defaultInput = io.input ?? new NodeConsoleInput();
4418
+ this.defaultOutput = io.output ?? new NodeConsoleOutput();
4209
4419
  }
4210
4420
  app;
4211
4421
  commands = /* @__PURE__ */ new Map();
@@ -4238,22 +4448,22 @@ var Kernel = class {
4238
4448
  return code;
4239
4449
  }
4240
4450
  /** @internal Runs a command with the given I/O. Command.call() passes its own, so nested output isn't swallowed. */
4241
- async callWithIo(command, parameters, io2) {
4451
+ async callWithIo(command, parameters, io) {
4242
4452
  const instance = this.findOrThrow(command);
4243
4453
  const signature = parseSignature(instance.signature);
4244
- return this.execute(instance, signature, parametersToInput(parameters, signature), io2);
4454
+ return this.execute(instance, signature, parametersToInput(parameters, signature), io);
4245
4455
  }
4246
4456
  async handle(argv) {
4247
- const io2 = { input: this.defaultInput, output: this.defaultOutput };
4457
+ const io = { input: this.defaultInput, output: this.defaultOutput };
4248
4458
  this.running++;
4249
4459
  try {
4250
4460
  const [name, ...rest] = this.normalizeTopLevel(argv);
4251
4461
  const instance = this.findOrThrow(name);
4252
4462
  const signature = parseSignature(instance.signature);
4253
4463
  const input = parseArgv(rest, signature);
4254
- return await this.execute(instance, signature, input, io2);
4464
+ return await this.execute(instance, signature, input, io);
4255
4465
  } catch (error) {
4256
- return this.reportTopLevelError(error, io2.output);
4466
+ return this.reportTopLevelError(error, io.output);
4257
4467
  } finally {
4258
4468
  if (--this.running === 0) this.defaultInput.close?.();
4259
4469
  }
@@ -4295,10 +4505,10 @@ var Kernel = class {
4295
4505
  throw new CommandNotFoundError(`Command "${name}" is not defined.`, suggest(name, [...this.commands.keys()]));
4296
4506
  return instance;
4297
4507
  }
4298
- async execute(instance, signature, input, io2) {
4508
+ async execute(instance, signature, input, io) {
4299
4509
  validateRequiredArguments(signature, input);
4300
4510
  const run = Object.create(instance);
4301
- run.bind?.(resolveArguments(signature, input), resolveOptions(signature, input), io2);
4511
+ run.bind?.(resolveArguments(signature, input), resolveOptions(signature, input), io);
4302
4512
  const scope = this.app.createScope();
4303
4513
  scope.instance(ConsoleKernel, this);
4304
4514
  return scope.run(async () => {
@@ -4331,7 +4541,7 @@ function parseTime(time) {
4331
4541
  return [minute, hour];
4332
4542
  }
4333
4543
  function sha1(value2) {
4334
- return createHash4("sha1").update(value2).digest("hex");
4544
+ return createHash6("sha1").update(value2).digest("hex");
4335
4545
  }
4336
4546
  var ScheduledEventImpl = class {
4337
4547
  /**
@@ -4470,21 +4680,21 @@ var ScheduledEventImpl = class {
4470
4680
  * Minute precision: `now` is truncated to the start of its minute, since cron-parser's includesDate() also
4471
4681
  * compares seconds. Without timezone(), expressions are read in app.timezone (UTC by default), as in Laravel.
4472
4682
  */
4473
- isDue(now4) {
4474
- const minute = new Date(Math.floor(now4.getTime() / 6e4) * 6e4);
4683
+ isDue(now5) {
4684
+ const minute = new Date(Math.floor(now5.getTime() / 6e4) * 6e4);
4475
4685
  const parsed = CronExpressionParser.parse(this.cronExpression, { tz: this.zone() });
4476
4686
  if (!parsed.includesDate(minute)) return false;
4477
- return !this.betweenWindow || this.isWithinWindow(now4);
4687
+ return !this.betweenWindow || this.isWithinWindow(now5);
4478
4688
  }
4479
4689
  zone() {
4480
4690
  if (this.tz !== void 0) return this.tz;
4481
4691
  const container = currentContainer();
4482
4692
  return container?.bound(ConfigRepository) ? container.make(ConfigRepository).get("app.timezone", "UTC") : "UTC";
4483
4693
  }
4484
- isWithinWindow(now4) {
4694
+ isWithinWindow(now5) {
4485
4695
  const { start: start2, end } = this.betweenWindow;
4486
4696
  const format = (d) => d.toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit", hour12: false, timeZone: this.zone() });
4487
- const current = format(now4);
4697
+ const current = format(now5);
4488
4698
  return start2 <= end ? current >= start2 && current <= end : current >= start2 || current <= end;
4489
4699
  }
4490
4700
  /**
@@ -4574,8 +4784,8 @@ var ScheduleImpl = class {
4574
4784
  events() {
4575
4785
  return [...this.scheduledEvents];
4576
4786
  }
4577
- dueEvents(now4) {
4578
- return this.scheduledEvents.filter((event2) => event2.isDue(now4));
4787
+ dueEvents(now5) {
4788
+ return this.scheduledEvents.filter((event2) => event2.isDue(now5));
4579
4789
  }
4580
4790
  push(event2) {
4581
4791
  this.scheduledEvents.push(event2);
@@ -4585,7 +4795,7 @@ var ScheduleImpl = class {
4585
4795
  var ConsoleServiceProvider = class extends ServiceProvider {
4586
4796
  register() {
4587
4797
  this.mergeConfigFrom({ stubs: {} }, "console");
4588
- this.app.singleton(ConsoleKernel, () => new Kernel(this.app));
4798
+ this.app.singleton(ConsoleKernel, () => new Kernel2(this.app));
4589
4799
  this.app.singleton(Schedule, () => new ScheduleImpl());
4590
4800
  }
4591
4801
  boot() {
@@ -4644,14 +4854,14 @@ async function runConsoleAndExit(app2, argv = process.argv.slice(2), exit = (cod
4644
4854
  // ../Cookie/dist/index.js
4645
4855
  import { createHmac as createHmac2, timingSafeEqual as timingSafeEqual2 } from "crypto";
4646
4856
  var SAME_SITE = { lax: "Lax", strict: "Strict", none: "None" };
4647
- function serializeCookie(cookie2, now4 = Date.now()) {
4857
+ function serializeCookie(cookie2, now5 = Date.now()) {
4648
4858
  const parts = [];
4649
4859
  if (cookie2.minutes < 0) {
4650
4860
  parts.push(`${cookie2.name}=`, "Expires=Thu, 01 Jan 1970 00:00:00 GMT", "Max-Age=0");
4651
4861
  } else {
4652
4862
  parts.push(`${cookie2.name}=${encodeURIComponent(cookie2.value)}`);
4653
4863
  if (cookie2.minutes > 0) {
4654
- parts.push(`Expires=${new Date(now4 + cookie2.minutes * 6e4).toUTCString()}`, `Max-Age=${cookie2.minutes * 60}`);
4864
+ parts.push(`Expires=${new Date(now5 + cookie2.minutes * 6e4).toUTCString()}`, `Max-Age=${cookie2.minutes * 60}`);
4655
4865
  }
4656
4866
  }
4657
4867
  parts.push(`Path=${cookie2.path}`);
@@ -4774,14 +4984,14 @@ var AddQueuedCookiesToResponse = class {
4774
4984
  }
4775
4985
  };
4776
4986
  var neverEncrypt = /* @__PURE__ */ new Set();
4777
- function isDeletion(attributes, now4 = Date.now()) {
4987
+ function isDeletion(attributes, now5 = Date.now()) {
4778
4988
  for (const part of attributes.split(";")) {
4779
4989
  const equals4 = part.indexOf("=");
4780
4990
  if (equals4 === -1) continue;
4781
4991
  const key = part.slice(0, equals4).trim().toLowerCase();
4782
4992
  const value2 = part.slice(equals4 + 1).trim();
4783
4993
  if (key === "max-age" && Number(value2) <= 0) return true;
4784
- if (key === "expires" && Date.parse(value2) <= now4) return true;
4994
+ if (key === "expires" && Date.parse(value2) <= now5) return true;
4785
4995
  }
4786
4996
  return false;
4787
4997
  }
@@ -8484,9 +8694,9 @@ var BelongsToMany = class extends Relation {
8484
8694
  pivotRow(id, attributes, creating) {
8485
8695
  const row = { ...attributes, [this.foreignPivotKey]: this.getParentKey(), [this.relatedPivotKey]: this.idOf(id) };
8486
8696
  if (this.pivotTimestamps && creating) {
8487
- const now4 = formatDateTime(this.parent.freshTimestamp());
8488
- row[this.pivotTimestamps[0]] ??= now4;
8489
- row[this.pivotTimestamps[1]] ??= now4;
8697
+ const now5 = formatDateTime(this.parent.freshTimestamp());
8698
+ row[this.pivotTimestamps[0]] ??= now5;
8699
+ row[this.pivotTimestamps[1]] ??= now5;
8490
8700
  }
8491
8701
  return row;
8492
8702
  }
@@ -9876,9 +10086,9 @@ var Model = class _Model {
9876
10086
  }
9877
10087
  /** The current time, to the second (the storage precision). */
9878
10088
  freshTimestamp() {
9879
- const now4 = /* @__PURE__ */ new Date();
9880
- now4.setMilliseconds(0);
9881
- return now4;
10089
+ const now5 = /* @__PURE__ */ new Date();
10090
+ now5.setMilliseconds(0);
10091
+ return now5;
9882
10092
  }
9883
10093
  updateTimestamps() {
9884
10094
  const time = this.freshTimestamp();
@@ -11243,7 +11453,7 @@ function databaseConfigDefaults(app2) {
11243
11453
  }
11244
11454
  };
11245
11455
  }
11246
- function currentRequest() {
11456
+ function currentRequest2() {
11247
11457
  const container = currentContainer();
11248
11458
  if (!container?.bound(HttpRequest)) return void 0;
11249
11459
  try {
@@ -11253,13 +11463,13 @@ function currentRequest() {
11253
11463
  }
11254
11464
  }
11255
11465
  function usePaginationResolvers() {
11256
- AbstractPaginator.currentPathResolver = () => currentRequest()?.url() ?? "/";
11466
+ AbstractPaginator.currentPathResolver = () => currentRequest2()?.url() ?? "/";
11257
11467
  AbstractPaginator.currentPageResolver = (pageName) => {
11258
- const page = Number(currentRequest()?.input(pageName));
11468
+ const page = Number(currentRequest2()?.input(pageName));
11259
11469
  return Number.isInteger(page) && page >= 1 ? page : 1;
11260
11470
  };
11261
- AbstractPaginator.queryStringResolver = () => currentRequest()?.query() ?? {};
11262
- AbstractPaginator.currentCursorResolver = (cursorName) => currentRequest()?.input(cursorName);
11471
+ AbstractPaginator.queryStringResolver = () => currentRequest2()?.query() ?? {};
11472
+ AbstractPaginator.currentCursorResolver = (cursorName) => currentRequest2()?.input(cursorName);
11263
11473
  }
11264
11474
  var DatabaseServiceProvider = class extends ServiceProvider {
11265
11475
  register() {
@@ -12679,1866 +12889,93 @@ var HashingServiceProvider = class extends ServiceProvider {
12679
12889
  }
12680
12890
  };
12681
12891
 
12682
- // ../Http/dist/index.js
12683
- import { createReadStream as createReadStream2 } from "fs";
12684
- import { stat as stat3 } from "fs/promises";
12685
- import { basename as basename2 } from "path";
12686
- import { Readable as Readable2 } from "stream";
12687
- import { readFile as readFile4 } from "fs/promises";
12688
- import { fileURLToPath } from "url";
12689
- import { createReadStream as createReadStream22 } from "fs";
12690
- import { stat as stat22 } from "fs/promises";
12691
- import { Readable as Readable22 } from "stream";
12692
- import { relative as relative5, resolve as resolve3, sep as sep4 } from "path";
12693
- import { createServer } from "http";
12694
- import { Readable as Readable3 } from "stream";
12695
- import { pipeline as pipeline2 } from "stream/promises";
12892
+ // ../Inertia/dist/index.js
12696
12893
  import { existsSync as existsSync7 } from "fs";
12697
- import { mkdir as mkdir5, readFile as readFile22, writeFile as writeFile6 } from "fs/promises";
12698
- import { dirname as dirname5 } from "path";
12699
- var HttpException = class extends Error {
12700
- constructor(status, message = "", headers = {}) {
12701
- super(message);
12702
- this.status = status;
12703
- this.headers = headers;
12704
- }
12705
- status;
12706
- headers;
12707
- kind = "Http";
12708
- name = "HttpException";
12894
+ import { join as join10 } from "path";
12895
+ import { createHash as createHash7 } from "crypto";
12896
+ import { existsSync as existsSync23, readFileSync } from "fs";
12897
+ import { spawn as spawn2 } from "child_process";
12898
+ import { existsSync as existsSync33 } from "fs";
12899
+ import { mkdir as mkdir5, writeFile as writeFile6 } from "fs/promises";
12900
+ import { dirname as dirname5, isAbsolute as isAbsolute2, join as join24, relative as relative5 } from "path";
12901
+ import { existsSync as existsSync42, readFileSync as readFileSync2 } from "fs";
12902
+ var Header = {
12903
+ INERTIA: "X-Inertia",
12904
+ ERROR_BAG: "X-Inertia-Error-Bag",
12905
+ LOCATION: "X-Inertia-Location",
12906
+ REDIRECT: "X-Inertia-Redirect",
12907
+ VERSION: "X-Inertia-Version",
12908
+ PARTIAL_COMPONENT: "X-Inertia-Partial-Component",
12909
+ PARTIAL_ONLY: "X-Inertia-Partial-Data",
12910
+ PARTIAL_EXCEPT: "X-Inertia-Partial-Except",
12911
+ RESET: "X-Inertia-Reset",
12912
+ INFINITE_SCROLL_MERGE_INTENT: "X-Inertia-Infinite-Scroll-Merge-Intent",
12913
+ EXCEPT_ONCE_PROPS: "X-Inertia-Except-Once-Props"
12709
12914
  };
12710
- var HttpResponseException = class extends Error {
12711
- constructor(response2) {
12712
- super(`HTTP response exception (${response2.status}).`);
12713
- this.response = response2;
12714
- this.status = response2.status;
12915
+ function parseList(value2) {
12916
+ const items = (value2 ?? "").split(",").filter((item) => item !== "");
12917
+ return items.length === 0 ? void 0 : items;
12918
+ }
12919
+ var Prop = class {
12920
+ constructor(value2) {
12921
+ this.value = value2;
12715
12922
  }
12716
- response;
12717
- kind = "Http";
12718
- name = "HttpResponseException";
12719
- status;
12720
- };
12721
- var HttpServerError = class extends Error {
12722
- kind = "Server";
12723
- status = 500;
12724
- name = "HttpServerError";
12725
- };
12726
- async function readBody2(raw3, limit) {
12727
- if (raw3.body === null) return new Uint8Array(0);
12728
- const declared = Number(raw3.headers.get("content-length") ?? NaN);
12729
- if (limit !== null && Number.isFinite(declared) && declared > limit) {
12730
- await raw3.body.cancel();
12731
- throw new HttpException(413, "Content Too Large");
12923
+ value;
12924
+ mergeState = { merge: false, deep: false, append: true, appendPaths: [], prependPaths: [], matchOn: [] };
12925
+ onceState = { once: false, fresh: false, key: void 0, ttlSeconds: void 0 };
12926
+ deferred = false;
12927
+ deferGroup;
12928
+ /** Calls the callback, if the value is one. */
12929
+ async resolve() {
12930
+ return typeof this.value === "function" ? await this.value() : this.value;
12732
12931
  }
12733
- const reader = raw3.body.getReader();
12734
- const chunks = [];
12735
- let size = 0;
12736
- for (; ; ) {
12737
- const { done, value: value2 } = await reader.read();
12738
- if (done) break;
12739
- size += value2.byteLength;
12740
- if (limit !== null && size > limit) {
12741
- await reader.cancel();
12742
- throw new HttpException(413, "Content Too Large");
12743
- }
12744
- chunks.push(value2);
12932
+ /** Never sent on the first load (OptionalProp, DeferProp). */
12933
+ ignoresFirstLoad() {
12934
+ return false;
12745
12935
  }
12746
- const out = new Uint8Array(size);
12747
- let offset = 0;
12748
- for (const chunk of chunks) {
12749
- out.set(chunk, offset);
12750
- offset += chunk.byteLength;
12936
+ /** Sent even when a partial reload didn't ask for it (AlwaysProp). */
12937
+ isAlways() {
12938
+ return false;
12751
12939
  }
12752
- return out;
12753
- }
12754
- function requestScope() {
12755
- const container = currentContainer();
12756
- return container !== void 0 && container.bound(HttpRequest) ? container : void 0;
12757
- }
12758
- function currentRequest2() {
12759
- return requestScope()?.make(HttpRequest);
12760
- }
12761
- function optionalSession() {
12762
- const scope = requestScope();
12763
- return scope?.bound(Session) ? scope.make(Session) : void 0;
12764
- }
12765
- function optionalCookieJar() {
12766
- const scope = requestScope();
12767
- return scope?.bound(CookieJar) ? scope.make(CookieJar) : void 0;
12768
- }
12769
- function serializeCookie2(cookie2) {
12770
- const parts = [`${encodeURIComponent(cookie2.name)}=${encodeURIComponent(cookie2.value)}`, `Path=${cookie2.path}`];
12771
- if (cookie2.domain !== void 0) parts.push(`Domain=${cookie2.domain}`);
12772
- if (cookie2.secure) parts.push("Secure");
12773
- if (cookie2.httpOnly) parts.push("HttpOnly");
12774
- parts.push(`SameSite=${cookie2.sameSite.charAt(0).toUpperCase()}${cookie2.sameSite.slice(1)}`);
12775
- if (cookie2.minutes < 0) parts.push("Max-Age=0", "Expires=Thu, 01 Jan 1970 00:00:00 GMT");
12776
- else if (cookie2.minutes > 0) parts.push(`Max-Age=${Math.round(cookie2.minutes * 60)}`);
12777
- return parts.join("; ");
12778
- }
12779
- var HttpRedirectResponse = class {
12780
- constructor(targetUrl, status = 302, headers) {
12781
- this.targetUrl = targetUrl;
12782
- this.status = status;
12783
- this.#headers = new Headers(headers);
12940
+ /** Errors are reported and the prop is left out, instead of failing the page (defer(..., { rescue: true })). */
12941
+ shouldRescue() {
12942
+ return false;
12784
12943
  }
12785
- targetUrl;
12786
- status;
12787
- #headers;
12788
- with(key, value2) {
12789
- const session2 = optionalSession();
12790
- if (session2 === void 0) return this;
12791
- if (typeof key === "string") session2.flash(key, value2);
12792
- else for (const [name, item] of Object.entries(key)) session2.flash(name, item);
12944
+ // Once (honoured by OptionalProp, DeferProp, MergeProp and OnceProp) ------------------------------------
12945
+ /** once(), once(false), once(true, { as: 'key', until: 3600 }). */
12946
+ once(value2 = true, options = {}) {
12947
+ this.onceState.once = value2;
12948
+ if (options.as !== void 0) this.onceState.key = options.as;
12949
+ if (options.until !== void 0) this.onceState.ttlSeconds = secondsUntil(options.until);
12793
12950
  return this;
12794
12951
  }
12795
- /** Flashes `errors` as { [bag]: { field: string[] } }, keeping the other bags already flashed. */
12796
- withErrors(errors2, bag = "default") {
12797
- const session2 = optionalSession();
12798
- if (session2 === void 0) return this;
12799
- const source = typeof errors2.toObject === "function" ? errors2.toObject() : errors2;
12800
- const normalized = Object.fromEntries(
12801
- Object.entries(source).map(([field, messages]) => [field, Array.isArray(messages) ? [...messages] : [messages]])
12802
- );
12803
- const existing = session2.get("errors", {});
12804
- session2.flash("errors", { ...existing, [bag]: normalized });
12952
+ /** A custom once key, so pages can share the prop under different names. */
12953
+ as(key) {
12954
+ this.onceState.key = key;
12805
12955
  return this;
12806
12956
  }
12807
- /** Flashes `input`, or the current request's input (files are never part of input()). */
12808
- withInput(input) {
12809
- const session2 = optionalSession();
12810
- if (session2 === void 0) return this;
12811
- session2.flashInput(input ?? currentRequest2()?.input() ?? {});
12957
+ /** Send the prop again even though the client already has it. */
12958
+ fresh(value2 = true) {
12959
+ this.onceState.fresh = value2;
12812
12960
  return this;
12813
12961
  }
12814
- /**
12815
- * Always a Set-Cookie header on this response (Laravel's RedirectResponse::withCookie). A bound CookieJar only
12816
- * supplies the defaults (path, domain, secure, same-site); queueing would lose the cookie outside the web group.
12817
- */
12818
- withCookie(name, value2, minutes = 0) {
12819
- const jar = optionalCookieJar();
12820
- const cookie2 = jar !== void 0 ? jar.make(name, value2, minutes) : { name, value: value2, minutes, path: "/", secure: false, httpOnly: true, sameSite: "lax" };
12821
- this.#headers.append("Set-Cookie", serializeCookie2(cookie2));
12962
+ /** Expire after a number of seconds, or at a Date. */
12963
+ until(delay) {
12964
+ this.onceState.ttlSeconds = secondsUntil(delay);
12822
12965
  return this;
12823
12966
  }
12824
- header(name, value2) {
12825
- this.#headers.set(name, value2);
12826
- return this;
12967
+ // Merging -------------------------------------------------------------------------------------------------
12968
+ isMergeable() {
12969
+ return false;
12827
12970
  }
12828
- toResponse() {
12829
- const headers = new Headers(this.#headers);
12830
- headers.set("Location", this.targetUrl);
12831
- return new Response(null, { status: this.status, headers });
12971
+ shouldMerge() {
12972
+ return this.isMergeable() && this.mergeState.merge;
12832
12973
  }
12833
- };
12834
- var HttpRedirector = class {
12835
- to(path, status = 302, headers) {
12836
- return new HttpRedirectResponse(inject(UrlGenerator).to(path), status, headers);
12974
+ shouldDeepMerge() {
12975
+ return this.mergeState.deep;
12837
12976
  }
12838
- route(name, parameters, status = 302) {
12839
- return new HttpRedirectResponse(inject(UrlGenerator).route(name, parameters), status);
12840
- }
12841
- back(fallback, status = 302) {
12842
- return new HttpRedirectResponse(inject(UrlGenerator).previous(fallback), status);
12843
- }
12844
- /** Pulls url.intended from the session (put there by guest()), else goes to `fallback`. */
12845
- intended(fallback = "/", status = 302) {
12846
- const path = optionalSession()?.pull("url.intended") ?? fallback;
12847
- return this.to(path, status);
12848
- }
12849
- away(url2, status = 302) {
12850
- return new HttpRedirectResponse(url2, status);
12851
- }
12852
- /** Remembers where a guest was going (a GET page, else the previous URL), then redirects to `path`. */
12853
- guest(path, status = 302) {
12854
- const session2 = optionalSession();
12855
- const request2 = currentRequest2();
12856
- if (session2 !== void 0) {
12857
- const intended = request2 !== void 0 && request2.method() === "GET" && !request2.expectsJson() ? request2.fullUrl() : inject(UrlGenerator).previous();
12858
- session2.put("url.intended", intended);
12859
- }
12860
- return this.to(path, status);
12861
- }
12862
- setIntendedUrl(url2) {
12863
- optionalSession()?.put("url.intended", url2);
12864
- }
12865
- refresh(status = 302) {
12866
- return this.to(currentRequest2()?.fullUrl() ?? inject(UrlGenerator).current(), status);
12867
- }
12868
- };
12869
- var KEY = /* @__PURE__ */ Symbol.for("oriel:http.client-address");
12870
- var store = globalThis[KEY] ??= /* @__PURE__ */ new WeakMap();
12871
- function setClientAddress(request2, address) {
12872
- if (address !== void 0 && address !== "") store.set(request2, address);
12873
- }
12874
- function clientAddress(request2) {
12875
- return store.get(request2);
12876
- }
12877
- var TYPES = {
12878
- avif: "image/avif",
12879
- css: "text/css",
12880
- csv: "text/csv",
12881
- doc: "application/msword",
12882
- docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
12883
- gif: "image/gif",
12884
- gz: "application/gzip",
12885
- html: "text/html",
12886
- ico: "image/vnd.microsoft.icon",
12887
- jpg: "image/jpeg",
12888
- js: "text/javascript",
12889
- map: "application/json",
12890
- json: "application/json",
12891
- md: "text/markdown",
12892
- mp3: "audio/mpeg",
12893
- mp4: "video/mp4",
12894
- otf: "font/otf",
12895
- pdf: "application/pdf",
12896
- png: "image/png",
12897
- svg: "image/svg+xml",
12898
- ttf: "font/ttf",
12899
- txt: "text/plain",
12900
- wasm: "application/wasm",
12901
- webm: "video/webm",
12902
- webp: "image/webp",
12903
- woff: "font/woff",
12904
- woff2: "font/woff2",
12905
- xls: "application/vnd.ms-excel",
12906
- xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
12907
- xml: "application/xml",
12908
- zip: "application/zip"
12909
- };
12910
- var ALIASES = { jpeg: "jpg", htm: "html", mjs: "js", text: "txt" };
12911
- var EXTENSIONS2 = Object.fromEntries(Object.entries(TYPES).map(([extension, type]) => [type, extension]));
12912
- function mimeFromExtension2(pathOrExtension) {
12913
- const extension = pathOrExtension.slice(pathOrExtension.lastIndexOf(".") + 1).toLowerCase();
12914
- return TYPES[ALIASES[extension] ?? extension] ?? "application/octet-stream";
12915
- }
12916
- function extensionFromMime(type) {
12917
- return EXTENSIONS2[type.split(";")[0].trim().toLowerCase()];
12918
- }
12919
- var FormUploadedFile = class {
12920
- constructor(file) {
12921
- this.file = file;
12922
- this.clientName = file.name ?? "";
12923
- this.mimeType = file.type === "" ? "application/octet-stream" : file.type;
12924
- this.size = file.size;
12925
- }
12926
- file;
12927
- clientName;
12928
- mimeType;
12929
- size;
12930
- /** Guessed from the MIME type, falling back to the client's extension (Laravel's extension()). */
12931
- extension() {
12932
- return extensionFromMime(this.mimeType) ?? this.clientExtension();
12933
- }
12934
- clientExtension() {
12935
- const dot = this.clientName.lastIndexOf(".");
12936
- return dot === -1 ? "" : this.clientName.slice(dot + 1).toLowerCase();
12937
- }
12938
- /** A random 40-character name with the guessed extension. */
12939
- hashName() {
12940
- const extension = this.extension();
12941
- return extension === "" ? Str.random(40) : `${Str.random(40)}.${extension}`;
12942
- }
12943
- arrayBuffer() {
12944
- return this.file.arrayBuffer();
12945
- }
12946
- text() {
12947
- return this.file.text();
12948
- }
12949
- stream() {
12950
- return this.file.stream();
12951
- }
12952
- store(directory, disk) {
12953
- return inject(FilesystemManager).disk(disk).putFile(directory, this);
12954
- }
12955
- storeAs(directory, name, disk) {
12956
- return inject(FilesystemManager).disk(disk).putFileAs(directory, this, name);
12957
- }
12958
- };
12959
- var FORBIDDEN = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
12960
- var INTEGER_KEY = /^(?:0|[1-9]\d*)$/;
12961
- var isPlainObject2 = (value2) => {
12962
- if (typeof value2 !== "object" || value2 === null || Array.isArray(value2)) return false;
12963
- const prototype = Object.getPrototypeOf(value2);
12964
- return prototype === Object.prototype || prototype === null;
12965
- };
12966
- function parseBracketKey(name) {
12967
- const open = name.indexOf("[");
12968
- if (open <= 0 || !name.endsWith("]")) return [name];
12969
- const segments = [name.slice(0, open)];
12970
- const rest = name.slice(open);
12971
- const matches = rest.match(/\[[^[\]]*\]/g);
12972
- if (matches === null || matches.join("") !== rest) return [name];
12973
- for (const match of matches) segments.push(match.slice(1, -1));
12974
- return segments;
12975
- }
12976
- function normalizeLists(value2) {
12977
- if (Array.isArray(value2)) return value2.map(normalizeLists);
12978
- if (!isPlainObject2(value2)) return value2;
12979
- const keys = Object.keys(value2);
12980
- const out = {};
12981
- for (const key of keys) out[key] = normalizeLists(value2[key]);
12982
- if (keys.length > 0 && keys.every((key, index) => key === String(index))) return keys.map((key) => out[key]);
12983
- return out;
12984
- }
12985
- function fromEntries(entries) {
12986
- const root = {};
12987
- const nextIndex = /* @__PURE__ */ new WeakMap();
12988
- for (const [name, value2] of entries) {
12989
- const segments = parseBracketKey(name);
12990
- if (segments.some((segment) => FORBIDDEN.has(segment))) continue;
12991
- let node = root;
12992
- for (let i = 0; i < segments.length; i++) {
12993
- let segment = segments[i];
12994
- const next = nextIndex.get(node) ?? 0;
12995
- if (segment === "") {
12996
- segment = String(next);
12997
- nextIndex.set(node, next + 1);
12998
- } else if (INTEGER_KEY.test(segment) && Number(segment) >= next) {
12999
- nextIndex.set(node, Number(segment) + 1);
13000
- }
13001
- if (i === segments.length - 1) {
13002
- node[segment] = value2;
13003
- break;
13004
- }
13005
- if (!isPlainObject2(node[segment])) node[segment] = {};
13006
- node = node[segment];
13007
- }
13008
- }
13009
- return normalizeLists(root);
13010
- }
13011
- function sanitize(value2) {
13012
- if (Array.isArray(value2)) return value2.map(sanitize);
13013
- if (!isPlainObject2(value2)) return value2;
13014
- const out = {};
13015
- for (const [key, item] of Object.entries(value2)) if (!FORBIDDEN.has(key)) out[key] = sanitize(item);
13016
- return out;
13017
- }
13018
- function mergeRecursive(base, override) {
13019
- const out = { ...base };
13020
- for (const [key, value2] of Object.entries(override)) {
13021
- if (FORBIDDEN.has(key)) continue;
13022
- const current = out[key];
13023
- out[key] = (isPlainObject2(current) || Array.isArray(current)) && (isPlainObject2(value2) || Array.isArray(value2)) ? normalizeLists(mergeRecursive({ ...current }, { ...value2 })) : value2;
13024
- }
13025
- return out;
13026
- }
13027
- function isBlank(value2) {
13028
- if (value2 === null || value2 === void 0) return true;
13029
- if (typeof value2 === "string") return value2.trim() === "";
13030
- if (Array.isArray(value2)) return value2.length === 0;
13031
- if (isPlainObject2(value2)) return Object.keys(value2).length === 0;
13032
- return false;
13033
- }
13034
- function transformLeaves(tree, transform, prefix = "") {
13035
- const out = {};
13036
- for (const [key, value2] of Object.entries(tree)) out[key] = transformValue(`${prefix}${key}`, value2, transform);
13037
- return out;
13038
- }
13039
- function transformValue(path, value2, transform) {
13040
- if (Array.isArray(value2)) return value2.map((item, index) => transformValue(`${path}.${index}`, item, transform));
13041
- if (isPlainObject2(value2)) return transformLeaves(value2, transform, `${path}.`);
13042
- return transform(path, value2);
13043
- }
13044
- var TRUE_VALUES = /* @__PURE__ */ new Set(["1", "true", "on", "yes"]);
13045
- var normalizeIp = (ip) => ip.trim().replace(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i, "$1");
13046
- function ipv4ToNumber(ip) {
13047
- const parts = ip.split(".");
13048
- if (parts.length !== 4 || parts.some((part) => !/^\d{1,3}$/.test(part) || Number(part) > 255)) return void 0;
13049
- return parts.reduce((total, part) => total * 256 + Number(part), 0);
13050
- }
13051
- function ipMatches(ip, patterns) {
13052
- const address = normalizeIp(ip);
13053
- return patterns.some((pattern) => {
13054
- if (pattern === "*") return true;
13055
- if (!pattern.includes("/")) return normalizeIp(pattern) === address;
13056
- const [range, bits] = pattern.split("/");
13057
- const base = ipv4ToNumber(range);
13058
- const value2 = ipv4ToNumber(address);
13059
- const size = Number(bits);
13060
- if (base === void 0 || value2 === void 0 || !(size >= 0 && size <= 32)) return false;
13061
- const mask = size === 0 ? 0 : ~0 << 32 - size >>> 0;
13062
- return (base & mask) >>> 0 === (value2 & mask) >>> 0;
13063
- });
13064
- }
13065
- var IncomingRequest = class {
13066
- constructor(raw3, options = {}) {
13067
- this.raw = raw3;
13068
- this.#url = new URL(raw3.url);
13069
- this.#trustedProxies = options.trustedProxies ?? [];
13070
- this.#maxBodySize = options.maxBodySize === void 0 ? 8 * 1024 * 1024 : options.maxBodySize;
13071
- this.#query = fromEntries(this.#url.searchParams.entries());
13072
- this.#method = raw3.method.toUpperCase();
13073
- }
13074
- raw;
13075
- #url;
13076
- #trustedProxies;
13077
- #maxBodySize;
13078
- #query;
13079
- #body = {};
13080
- #files = {};
13081
- #content = "";
13082
- #method;
13083
- #cookies;
13084
- #loading;
13085
- #userResolver;
13086
- /** Reads and parses the body (JSON, urlencoded or multipart) once, then applies method spoofing. */
13087
- load() {
13088
- return this.#loading ??= this.#load();
13089
- }
13090
- async #load() {
13091
- const method = this.raw.method.toUpperCase();
13092
- if (method !== "GET" && method !== "HEAD" && this.raw.body !== null) {
13093
- const type = (this.raw.headers.get("content-type") ?? "").toLowerCase();
13094
- const isJson = type.includes("/json") || type.includes("+json");
13095
- const isUrlencoded = type.startsWith("application/x-www-form-urlencoded");
13096
- const isMultipart = type.startsWith("multipart/form-data");
13097
- if (isJson || isUrlencoded || isMultipart) {
13098
- const bytes = await readBody2(this.raw, this.#maxBodySize);
13099
- try {
13100
- if (isJson) {
13101
- this.#content = new TextDecoder().decode(bytes);
13102
- this.#body = this.#parseJson(this.#content);
13103
- } else if (isUrlencoded) {
13104
- this.#content = new TextDecoder().decode(bytes);
13105
- this.#body = fromEntries(new URLSearchParams(this.#content).entries());
13106
- } else {
13107
- this.#parseForm(await new Response(bytes, { headers: { "content-type": this.raw.headers.get("content-type") ?? "" } }).formData());
13108
- }
13109
- } catch {
13110
- }
13111
- }
13112
- }
13113
- if (method === "POST") {
13114
- const override = this.raw.headers.get("x-http-method-override") ?? this.#string(this.#body._method) ?? this.#string(this.#query._method);
13115
- const spoofed = override?.toUpperCase();
13116
- if (spoofed !== void 0 && /^[A-Z]+$/.test(spoofed) && !["GET", "HEAD", "CONNECT", "TRACE"].includes(spoofed)) {
13117
- this.#method = spoofed;
13118
- }
13119
- }
13120
- return this;
13121
- }
13122
- #parseJson(text3) {
13123
- let parsed;
13124
- try {
13125
- parsed = JSON.parse(text3);
13126
- } catch {
13127
- return {};
13128
- }
13129
- if (Array.isArray(parsed)) return sanitize({ ...parsed });
13130
- return isPlainObject2(parsed) ? sanitize(parsed) : {};
13131
- }
13132
- #parseForm(form) {
13133
- const fields = [];
13134
- const files3 = [];
13135
- for (const [name, value2] of form.entries()) {
13136
- if (typeof value2 === "string") fields.push([name, value2]);
13137
- else if (!((value2.name ?? "") === "" && value2.size === 0)) files3.push([name, new FormUploadedFile(value2)]);
13138
- }
13139
- this.#body = fromEntries(fields);
13140
- this.#files = fromEntries(files3);
13141
- }
13142
- #string(value2) {
13143
- return typeof value2 === "string" && value2 !== "" ? value2 : void 0;
13144
- }
13145
- method() {
13146
- return this.#method;
13147
- }
13148
- isMethod(method) {
13149
- return this.#method === method.toUpperCase();
13150
- }
13151
- /** The scheme and host, honouring X-Forwarded-Proto/Host from trusted proxies. */
13152
- root() {
13153
- const trusted = this.#fromTrustedProxy();
13154
- const proto = trusted ? this.raw.headers.get("x-forwarded-proto")?.split(",")[0]?.trim() : void 0;
13155
- const host = trusted ? this.raw.headers.get("x-forwarded-host")?.split(",")[0]?.trim() : void 0;
13156
- const scheme = proto === "https" || proto === "http" ? proto : this.#url.protocol.slice(0, -1);
13157
- return `${scheme}://${host !== void 0 && host !== "" ? host : this.#url.host}`;
13158
- }
13159
- /** The URL without the query string or a trailing slash. */
13160
- url() {
13161
- return `${this.root()}${this.#url.pathname}`.replace(/\/+$/, "");
13162
- }
13163
- fullUrl() {
13164
- return this.#url.search === "" ? this.url() : `${this.url()}${this.#url.search}`;
13165
- }
13166
- /** 'posts/1', or '/' for the root. */
13167
- path() {
13168
- const trimmed = this.#url.pathname.replace(/^\/+|\/+$/g, "");
13169
- return trimmed === "" ? "/" : trimmed;
13170
- }
13171
- decodedPath() {
13172
- try {
13173
- return decodeURIComponent(this.path());
13174
- } catch {
13175
- return this.path();
13176
- }
13177
- }
13178
- secure() {
13179
- return this.root().startsWith("https:");
13180
- }
13181
- /** request.is('admin/*'): wildcard match against the decoded path. */
13182
- is(...patterns) {
13183
- const path = this.decodedPath();
13184
- return patterns.some((pattern) => {
13185
- const trimmed = pattern.replace(/^\/+|\/+$/g, "");
13186
- return Str.is(trimmed === "" ? "/" : trimmed, path);
13187
- });
13188
- }
13189
- routeIs(...names) {
13190
- const name = this.#currentRoute()?.route.getName();
13191
- return name !== void 0 && names.some((pattern) => Str.is(pattern, name));
13192
- }
13193
- header(name, defaultValue) {
13194
- return this.raw.headers.get(name) ?? defaultValue;
13195
- }
13196
- bearerToken() {
13197
- const header = this.header("authorization", "");
13198
- const position = header.toLowerCase().lastIndexOf("bearer ");
13199
- if (position === -1) return void 0;
13200
- const token2 = header.slice(position + 7).split(",")[0].trim();
13201
- return token2 === "" ? void 0 : token2;
13202
- }
13203
- userAgent() {
13204
- return this.header("user-agent");
13205
- }
13206
- /** The socket address, or the right-most untrusted X-Forwarded-For entry when the socket is a trusted proxy. */
13207
- ip() {
13208
- const socket = clientAddress(this.raw);
13209
- if (socket === void 0) return void 0;
13210
- const address = normalizeIp(socket);
13211
- if (!this.#fromTrustedProxy()) return address;
13212
- const chain = (this.raw.headers.get("x-forwarded-for") ?? "").split(",").map((entry) => normalizeIp(entry)).filter((entry) => entry !== "");
13213
- for (let i = chain.length - 1; i >= 0; i--) if (!ipMatches(chain[i], this.#trustedProxies)) return chain[i];
13214
- return chain[0] ?? address;
13215
- }
13216
- #fromTrustedProxy() {
13217
- const socket = clientAddress(this.raw);
13218
- return socket !== void 0 && this.#trustedProxies.length > 0 && ipMatches(socket, this.#trustedProxies);
13219
- }
13220
- ajax() {
13221
- return this.header("x-requested-with") === "XMLHttpRequest";
13222
- }
13223
- pjax() {
13224
- return this.header("x-pjax") === "true";
13225
- }
13226
- /** The first Accept type is JSON. */
13227
- wantsJson() {
13228
- const first = this.header("accept", "").split(",")[0].trim();
13229
- return first.includes("/json") || first.includes("+json");
13230
- }
13231
- /** Laravel: (ajax and not pjax and accepts anything) or wantsJson. */
13232
- expectsJson() {
13233
- const first = this.header("accept", "").split(",")[0].split(";")[0].trim();
13234
- const acceptsAny = first === "" || first === "*/*" || first === "*";
13235
- return this.ajax() && !this.pjax() && acceptsAny || this.wantsJson();
13236
- }
13237
- /** The raw body text for JSON and urlencoded requests ('' otherwise; the raw stream stays unread for other types). */
13238
- content() {
13239
- return this.#content;
13240
- }
13241
- query(key, defaultValue) {
13242
- return Arr.get(this.#query, key, defaultValue);
13243
- }
13244
- /** Body wins over the query string (PHP's $body + $query). Files are not input. */
13245
- input(key, defaultValue) {
13246
- return Arr.get({ ...this.#query, ...this.#body }, key, defaultValue);
13247
- }
13248
- /** Input plus files (array_replace_recursive). */
13249
- all() {
13250
- return mergeRecursive({ ...this.#query, ...this.#body }, this.#files);
13251
- }
13252
- only(...keys) {
13253
- const all = this.all();
13254
- const out = {};
13255
- for (const key of keys.flat()) if (Arr.has(all, key)) Arr.set(out, key, Arr.get(all, key));
13256
- return out;
13257
- }
13258
- except(...keys) {
13259
- const all = structuredCloneInput(this.all());
13260
- for (const key of keys.flat()) Arr.forget(all, key);
13261
- return all;
13262
- }
13263
- has(...keys) {
13264
- const all = this.all();
13265
- return keys.flat().every((key) => Arr.has(all, key));
13266
- }
13267
- hasAny(...keys) {
13268
- const all = this.all();
13269
- return keys.flat().some((key) => Arr.has(all, key));
13270
- }
13271
- missing(...keys) {
13272
- return !this.has(...keys);
13273
- }
13274
- filled(key) {
13275
- return !isBlank(Arr.get(this.all(), key));
13276
- }
13277
- string(key, defaultValue = "") {
13278
- const value2 = this.input(key);
13279
- return value2 === void 0 || value2 === null ? defaultValue : String(value2);
13280
- }
13281
- /** PHP's FILTER_VALIDATE_BOOLEAN: '1', 'true', 'on', 'yes' (any case) and true are true. */
13282
- boolean(key, defaultValue = false) {
13283
- const value2 = this.input(key);
13284
- if (value2 === void 0) return defaultValue;
13285
- if (typeof value2 === "boolean") return value2;
13286
- if (typeof value2 === "number") return value2 === 1;
13287
- return typeof value2 === "string" && TRUE_VALUES.has(value2.trim().toLowerCase());
13288
- }
13289
- /** PHP's intval: leading digits, else 0. */
13290
- integer(key, defaultValue = 0) {
13291
- const value2 = this.input(key);
13292
- if (value2 === void 0) return defaultValue;
13293
- if (typeof value2 === "number") return Number.isFinite(value2) ? Math.trunc(value2) : 0;
13294
- if (typeof value2 === "boolean") return value2 ? 1 : 0;
13295
- const parsed = Number.parseInt(String(value2).trim(), 10);
13296
- return Number.isNaN(parsed) ? 0 : parsed;
13297
- }
13298
- /** Adds or replaces top-level body values. */
13299
- merge(values) {
13300
- this.#body = { ...this.#body, ...sanitize(values) };
13301
- return this;
13302
- }
13303
- /** Rewrites every scalar in the query and the body (TrimStrings and ConvertEmptyStringsToNull use this). */
13304
- transformInput(transform) {
13305
- this.#query = transformLeaves(this.#query, transform);
13306
- this.#body = transformLeaves(this.#body, transform);
13307
- return this;
13308
- }
13309
- file(key) {
13310
- const value2 = Arr.get(this.#files, key);
13311
- return value2 instanceof FormUploadedFile ? value2 : void 0;
13312
- }
13313
- hasFile(key) {
13314
- const value2 = Arr.get(this.#files, key);
13315
- return value2 instanceof FormUploadedFile || Array.isArray(value2) && value2.some((item) => item instanceof FormUploadedFile);
13316
- }
13317
- allFiles() {
13318
- return { ...this.#files };
13319
- }
13320
- cookie(name) {
13321
- return this.cookies()[name];
13322
- }
13323
- cookies() {
13324
- if (this.#cookies === void 0) {
13325
- const cookies = {};
13326
- for (const part of (this.raw.headers.get("cookie") ?? "").split(";")) {
13327
- const index = part.indexOf("=");
13328
- if (index === -1) continue;
13329
- const name = part.slice(0, index).trim();
13330
- if (name === "" || Object.hasOwn(cookies, name)) continue;
13331
- let value2 = part.slice(index + 1).trim();
13332
- if (value2.startsWith('"') && value2.endsWith('"')) value2 = value2.slice(1, -1);
13333
- try {
13334
- cookies[name] = decodeURIComponent(value2);
13335
- } catch {
13336
- cookies[name] = value2;
13337
- }
13338
- }
13339
- this.#cookies = cookies;
13340
- }
13341
- return { ...this.#cookies };
13342
- }
13343
- /** Replaces the parsed cookies (EncryptCookies calls this after decrypting). */
13344
- setCookies(cookies) {
13345
- this.#cookies = { ...cookies };
13346
- }
13347
- /** One route parameter (after model binding), or all of them. */
13348
- route(key) {
13349
- const parameters = this.#currentRoute()?.parameters ?? {};
13350
- return key === void 0 ? { ...parameters } : parameters[key];
13351
- }
13352
- session() {
13353
- return inject(Session);
13354
- }
13355
- user(guard2) {
13356
- return this.#userResolver?.(guard2);
13357
- }
13358
- setUserResolver(resolver) {
13359
- this.#userResolver = resolver;
13360
- }
13361
- /** Validates all() through the ValidationFactory; throws its Validation error on failure. */
13362
- validate(rules, messages, attributes) {
13363
- return inject(ValidationFactory).make(this.all(), rules, messages, attributes).validated();
13364
- }
13365
- #currentRoute() {
13366
- const container = currentContainer();
13367
- return container?.bound(CurrentRoute) ? container.make(CurrentRoute) : void 0;
13368
- }
13369
- };
13370
- function structuredCloneInput(tree) {
13371
- const out = {};
13372
- for (const [key, value2] of Object.entries(tree)) {
13373
- out[key] = isPlainObject2(value2) ? structuredCloneInput(value2) : Array.isArray(value2) ? [...value2] : value2;
13374
- }
13375
- return out;
13376
- }
13377
- function request(key, defaultValue) {
13378
- const current = inject(HttpRequest);
13379
- return key === void 0 ? current : current.input(key, defaultValue);
13380
- }
13381
- function response(content, status, headers) {
13382
- const factory = inject(ResponseFactory);
13383
- return content === void 0 ? factory : factory.make(content, status, headers);
13384
- }
13385
- function redirect(to, status) {
13386
- const redirector = inject(Redirector);
13387
- return to === void 0 ? redirector : redirector.to(to, status);
13388
- }
13389
- function back(fallback, status) {
13390
- return inject(Redirector).back(fallback, status);
13391
- }
13392
- function url(path, query, absolute) {
13393
- const generator = inject(UrlGenerator);
13394
- return path === void 0 ? generator : generator.to(path, query, absolute);
13395
- }
13396
- function route(name, parameters, absolute) {
13397
- return inject(UrlGenerator).route(name, parameters, absolute);
13398
- }
13399
- function abort(status, message = "", headers = {}) {
13400
- if (status instanceof Response) throw new HttpResponseException(status);
13401
- throw new HttpException(status, message, headers);
13402
- }
13403
- function abortIf(condition, status, message = "", headers = {}) {
13404
- if (condition) abort(status, message, headers);
13405
- }
13406
- function abortUnless(condition, status, message = "", headers = {}) {
13407
- if (!condition) abort(status, message, headers);
13408
- }
13409
- function contentDisposition(type, name) {
13410
- const fallback = name.replace(/[^\x20-\x7e]/g, "_").replace(/["\\]/g, "\\$&");
13411
- const header = `${type}; filename="${fallback}"`;
13412
- return /^[\x20-\x7e]*$/.test(name) ? header : `${header}; filename*=UTF-8''${encodeURIComponent(name)}`;
13413
- }
13414
- var HttpResponseFactory = class {
13415
- /** Strings default to text/html; charset=utf-8, as in Laravel. */
13416
- make(content = null, status = 200, headers) {
13417
- const merged = new Headers(headers);
13418
- if (typeof content === "string" && !merged.has("content-type")) merged.set("content-type", "text/html; charset=utf-8");
13419
- return new Response(content, { status, headers: merged });
13420
- }
13421
- json(data, status = 200, headers) {
13422
- const merged = new Headers(headers);
13423
- if (!merged.has("content-type")) merged.set("content-type", "application/json");
13424
- return new Response(JSON.stringify(data === void 0 ? null : data), { status, headers: merged });
13425
- }
13426
- noContent(status = 204) {
13427
- return new Response(null, { status });
13428
- }
13429
- /** Renders a view (through the ViewFactory) into an HTML response. */
13430
- async view(name, data = {}, status = 200, headers) {
13431
- const html2 = await inject(ViewFactory).make(name, data).render();
13432
- return this.make(html2, status, headers);
13433
- }
13434
- /** Streams a file as an attachment. A missing file is a 404. */
13435
- download(path, name = basename2(path), headers) {
13436
- return this.#file(path, "attachment", name, headers);
13437
- }
13438
- /** Streams a file for the browser to display (Laravel's response()->file()). */
13439
- file(path, headers) {
13440
- return this.#file(path, "inline", basename2(path), headers);
13441
- }
13442
- stream(body, status = 200, headers) {
13443
- return new Response(body, { status, headers });
13444
- }
13445
- async #file(path, disposition, name, headers) {
13446
- const info = await stat3(path).catch(() => void 0);
13447
- if (info === void 0 || !info.isFile()) throw new HttpException(404);
13448
- const merged = new Headers(headers);
13449
- if (!merged.has("content-type")) merged.set("content-type", mimeFromExtension2(name));
13450
- merged.set("content-length", String(info.size));
13451
- merged.set("content-disposition", contentDisposition(disposition, name));
13452
- const body = Readable2.toWeb(createReadStream2(path));
13453
- return new Response(body, { status: 200, headers: merged });
13454
- }
13455
- };
13456
- var ConvertEmptyStringsToNull = class {
13457
- async handle(request2, next) {
13458
- if (request2 instanceof IncomingRequest) request2.transformInput((_key, value2) => value2 === "" ? null : value2);
13459
- return next(request2);
13460
- }
13461
- };
13462
- var TRIM = /^[\s\uFEFF\u200B\u200E]+|[\s\uFEFF\u200B\u200E]+$/g;
13463
- var TrimStrings = class {
13464
- /** Dotted input keys left untouched. Override in a subclass to change. */
13465
- except = ["current_password", "password", "password_confirmation"];
13466
- async handle(request2, next) {
13467
- if (request2 instanceof IncomingRequest) {
13468
- request2.transformInput(
13469
- (key, value2) => typeof value2 === "string" && !this.except.includes(key) ? value2.replace(TRIM, "") : value2
13470
- );
13471
- }
13472
- return next(request2);
13473
- }
13474
- };
13475
- var plainServerError = () => new Response("Server Error", { status: 500, headers: { "content-type": "text/plain; charset=utf-8" } });
13476
- var Kernel2 = class {
13477
- constructor(app2) {
13478
- this.app = app2;
13479
- }
13480
- app;
13481
- #middleware = [TrimStrings, ConvertEmptyStringsToNull];
13482
- #requests = /* @__PURE__ */ new WeakMap();
13483
- getGlobalMiddleware() {
13484
- return [...this.#middleware];
13485
- }
13486
- setGlobalMiddleware(middleware) {
13487
- this.#middleware = [...middleware];
13488
- return this;
13489
- }
13490
- appendMiddleware(...middleware) {
13491
- for (const cls of middleware) if (!this.#middleware.includes(cls)) this.#middleware.push(cls);
13492
- return this;
13493
- }
13494
- prependMiddleware(...middleware) {
13495
- for (const cls of [...middleware].reverse()) if (!this.#middleware.includes(cls)) this.#middleware.unshift(cls);
13496
- return this;
13497
- }
13498
- hasMiddleware(middleware) {
13499
- return this.#middleware.includes(middleware);
13500
- }
13501
- /** Runs in the current request scope (Application.handle() opens one); called directly, it opens its own. */
13502
- handle(raw3) {
13503
- const current = currentContainer();
13504
- const scope = current !== void 0 && current !== this.app ? current : this.app.createScope();
13505
- return scope.run(() => this.#handle(raw3, scope));
13506
- }
13507
- async #handle(raw3, scope) {
13508
- let request2;
13509
- let response2;
13510
- try {
13511
- request2 = new IncomingRequest(raw3, { trustedProxies: this.#trustedProxies(), maxBodySize: this.#maxBodySize() });
13512
- scope.instance(HttpRequest, request2);
13513
- const state = { scope, request: request2, middleware: [] };
13514
- this.#requests.set(raw3, state);
13515
- await request2.load();
13516
- response2 = await this.#sendThroughGlobal(state);
13517
- } catch (error) {
13518
- request2 ??= this.#bareRequest(scope, raw3);
13519
- if (request2 !== void 0) {
13520
- response2 = await this.#renderLast(scope, request2, error);
13521
- } else {
13522
- await this.#report(scope, error);
13523
- response2 = plainServerError();
13524
- }
13525
- }
13526
- if (raw3.method.toUpperCase() === "HEAD" && response2.body !== null) {
13527
- await response2.body.cancel().catch(() => void 0);
13528
- response2 = new Response(null, { status: response2.status, statusText: response2.statusText, headers: response2.headers });
13529
- }
13530
- return response2;
13531
- }
13532
- /** The request without options, for rendering an error raised while the real one was being built. */
13533
- #bareRequest(scope, raw3) {
13534
- try {
13535
- const request2 = new IncomingRequest(raw3);
13536
- scope.instance(HttpRequest, request2);
13537
- return request2;
13538
- } catch {
13539
- return void 0;
13540
- }
13541
- }
13542
- /** Runs terminate() on the global and route middleware (inside the request's scope), then Application.terminate(), inside the same scope, so terminating callbacks see the request's bindings. */
13543
- async terminate(raw3, response2) {
13544
- const state = this.#requests.get(raw3);
13545
- if (state !== void 0) {
13546
- this.#requests.delete(raw3);
13547
- await state.scope.run(async () => {
13548
- const route2 = state.scope.bound(CurrentRoute) ? state.scope.make(CurrentRoute).middleware : [];
13549
- for (const middleware of [...state.middleware, ...route2]) {
13550
- if (typeof middleware.terminate !== "function") continue;
13551
- try {
13552
- await middleware.terminate(state.request, response2);
13553
- } catch (error) {
13554
- await this.#report(state.scope, error);
13555
- }
13556
- }
13557
- await this.app.terminate();
13558
- });
13559
- return;
13560
- }
13561
- await this.app.terminate();
13562
- }
13563
- #sendThroughGlobal(state) {
13564
- const { scope, request: request2 } = state;
13565
- const pipes = this.#middleware.map((cls) => {
13566
- const instance = scope.make(cls);
13567
- state.middleware.push(instance);
13568
- return (passable, next) => this.#guard(scope, passable, () => instance.handle(passable, next));
13569
- });
13570
- return scope.make(PipelineFactory).make().send(request2).through(pipes).then((passable) => this.#guard(scope, passable, () => this.#dispatch(scope, passable)));
13571
- }
13572
- #dispatch(scope, request2) {
13573
- return scope.make(Router).dispatch(request2);
13574
- }
13575
- /** Converts a Responsable result, and renders a thrown error at this stage (Laravel's Routing\Pipeline). */
13576
- async #guard(scope, request2, run) {
13577
- try {
13578
- const result = await run();
13579
- if (result instanceof Response) return result;
13580
- const responsable = result;
13581
- if (typeof responsable?.toResponse === "function") return await responsable.toResponse(request2);
13582
- throw new HttpServerError("Middleware must return a Response.");
13583
- } catch (error) {
13584
- if (!scope.bound(ExceptionHandler)) throw error;
13585
- const handler3 = scope.make(ExceptionHandler);
13586
- await handler3.report(error);
13587
- return handler3.render(request2, error);
13588
- }
13589
- }
13590
- /** Last resort: the handler failed or isn't bound. Never throws. */
13591
- async #renderLast(scope, request2, error) {
13592
- if (scope.bound(ExceptionHandler)) {
13593
- try {
13594
- const handler3 = scope.make(ExceptionHandler);
13595
- await handler3.report(error);
13596
- return await handler3.render(request2, error);
13597
- } catch (renderError2) {
13598
- console.error(renderError2);
13599
- }
13600
- } else {
13601
- console.error(error);
13602
- }
13603
- return plainServerError();
13604
- }
13605
- async #report(scope, error) {
13606
- try {
13607
- if (scope.bound(ExceptionHandler)) await scope.make(ExceptionHandler).report(error);
13608
- else console.error(error);
13609
- } catch (reportError) {
13610
- console.error(reportError);
13611
- }
13612
- }
13613
- /** config('http.max_body_size'): bytes, or null for no limit. Anything else is a configuration error. */
13614
- #maxBodySize() {
13615
- if (!this.app.bound(ConfigRepository)) return 8 * 1024 * 1024;
13616
- const value2 = this.app.make(ConfigRepository).get("http.max_body_size", 8 * 1024 * 1024);
13617
- if (value2 === null) return null;
13618
- if (typeof value2 === "number" && Number.isFinite(value2) && value2 >= 0) return value2;
13619
- throw new HttpServerError(
13620
- `Invalid http.max_body_size ${JSON.stringify(value2) ?? String(value2)}: use a number of bytes (0 or more), or null for no limit.`
13621
- );
13622
- }
13623
- /** config('http.trusted_proxies'): an array, or a comma-separated string such as '*' or '10.0.0.0/8,::1'. */
13624
- #trustedProxies() {
13625
- if (!this.app.bound(ConfigRepository)) return [];
13626
- const value2 = this.app.make(ConfigRepository).get("http.trusted_proxies", []);
13627
- if (typeof value2 === "string") return value2.split(",").map((entry) => entry.trim()).filter((entry) => entry !== "");
13628
- return Array.isArray(value2) ? value2.map(String) : [];
13629
- }
13630
- };
13631
- var MiddlewareConfiguration = class {
13632
- constructor(kernel, router, config2) {
13633
- this.kernel = kernel;
13634
- this.router = router;
13635
- this.config = config2;
13636
- }
13637
- kernel;
13638
- router;
13639
- config;
13640
- append(...middleware) {
13641
- this.kernel.appendMiddleware(...middleware);
13642
- return this;
13643
- }
13644
- prepend(...middleware) {
13645
- this.kernel.prependMiddleware(...middleware);
13646
- return this;
13647
- }
13648
- web(options) {
13649
- return this.#modifyGroup("web", options);
13650
- }
13651
- api(options) {
13652
- return this.#modifyGroup("api", options);
13653
- }
13654
- alias(aliases2) {
13655
- for (const [name, middleware] of Object.entries(aliases2)) this.router.aliasMiddleware(name, middleware);
13656
- return this;
13657
- }
13658
- group(name, middleware) {
13659
- this.router.middlewareGroup(name, middleware);
13660
- return this;
13661
- }
13662
- /** Stored in config('http.csrf_except'), which the Session component's VerifyCsrfToken reads. */
13663
- validateCsrfTokens(options) {
13664
- const current = this.config?.get("http.csrf_except", []) ?? [];
13665
- this.config?.set("http.csrf_except", [...current, ...options.except]);
13666
- return this;
13667
- }
13668
- /** Stored in config('http.redirect_guests_to'), which the Auth middleware and the exception handler read. */
13669
- redirectGuestsTo(url2) {
13670
- this.config?.set("http.redirect_guests_to", url2);
13671
- return this;
13672
- }
13673
- /** Laravel 11's redirectUsersTo(): stored in config('http.redirect_users_to') for Auth's RedirectIfAuthenticated. */
13674
- redirectUsersTo(url2) {
13675
- this.config?.set("http.redirect_users_to", url2);
13676
- return this;
13677
- }
13678
- /** Laravel's order: prepends, then the group minus removals, then appends. */
13679
- #modifyGroup(name, { append = [], prepend = [], remove = [] }) {
13680
- const current = this.router.getMiddlewareGroups()[name] ?? [];
13681
- const moved = /* @__PURE__ */ new Set([...append, ...prepend, ...remove]);
13682
- this.router.middlewareGroup(name, [...prepend, ...current.filter((entry) => !moved.has(entry)), ...append]);
13683
- return this;
13684
- }
13685
- };
13686
- function applyMiddlewareCallbacks(app2, kernel) {
13687
- if (!app2.bound(MiddlewareCallbacks)) return;
13688
- const callbacks = app2.make(MiddlewareCallbacks);
13689
- if (callbacks.length === 0) return;
13690
- const config2 = app2.bound(ConfigRepository) ? app2.make(ConfigRepository) : void 0;
13691
- const configurator = new MiddlewareConfiguration(kernel, app2.make(Router), config2);
13692
- for (const callback of callbacks) callback(configurator);
13693
- }
13694
- var STATUS_TEXTS = {
13695
- 400: "Bad Request",
13696
- 401: "Unauthorized",
13697
- 402: "Payment Required",
13698
- 403: "Forbidden",
13699
- 404: "Not Found",
13700
- 405: "Method Not Allowed",
13701
- 408: "Request Timeout",
13702
- 409: "Conflict",
13703
- 410: "Gone",
13704
- 413: "Content Too Large",
13705
- 415: "Unsupported Media Type",
13706
- 419: "Page Expired",
13707
- 422: "Unprocessable Content",
13708
- 429: "Too Many Requests",
13709
- 500: "Server Error",
13710
- 502: "Bad Gateway",
13711
- 503: "Service Unavailable",
13712
- 504: "Gateway Timeout"
13713
- };
13714
- function statusText(status) {
13715
- return STATUS_TEXTS[status] ?? (status >= 500 ? "Server Error" : "Error");
13716
- }
13717
- function escapeHtml(value2) {
13718
- return value2.replace(/[&<>"']/g, (char) => `&#${char.charCodeAt(0)};`);
13719
- }
13720
- function minimalPage(status, message) {
13721
- const title = escapeHtml(message);
13722
- return `<!DOCTYPE html>
13723
- <html lang="en">
13724
- <head>
13725
- <meta charset="utf-8">
13726
- <meta name="viewport" content="width=device-width, initial-scale=1">
13727
- <title>${title}</title>
13728
- <style>body{margin:0;font-family:ui-sans-serif,system-ui,sans-serif;background:#f7fafc;color:#1a202c;display:flex;align-items:center;justify-content:center;min-height:100vh}.code{padding:0 1rem;border-right:1px solid #a0aec0;font-size:1.125rem}.message{padding:0 1rem;font-size:1.125rem;text-transform:uppercase;letter-spacing:.05em}</style>
13729
- </head>
13730
- <body><div class="code">${status}</div><div class="message">${title}</div></body>
13731
- </html>`;
13732
- }
13733
- function stackFrames(error) {
13734
- const frames = [];
13735
- for (const raw3 of (error.stack ?? "").split("\n").slice(1)) {
13736
- const text3 = raw3.trim();
13737
- const match = /(?:\(|@|at )((?:file:\/\/)?(?:\/|[A-Za-z]:\\)[^()]*?):(\d+):(\d+)\)?$/.exec(text3);
13738
- if (match === null) continue;
13739
- const location = match[1];
13740
- const file = location.startsWith("file://") ? fileURLToPath(location) : location;
13741
- frames.push({ file, line: Number(match[2]), column: Number(match[3]), text: text3 });
13742
- }
13743
- return frames;
13744
- }
13745
- async function excerpt(frame, radius = 5) {
13746
- const source = await readFile4(frame.file, "utf8").catch(() => void 0);
13747
- if (source === void 0) return void 0;
13748
- const lines = source.split("\n");
13749
- const start2 = Math.max(1, frame.line - radius);
13750
- const end = Math.min(lines.length, frame.line + radius);
13751
- const rows = [];
13752
- for (let number3 = start2; number3 <= end; number3++) {
13753
- const current = number3 === frame.line ? ' class="current"' : "";
13754
- rows.push(`<tr${current}><td class="n">${number3}</td><td><code>${escapeHtml(lines[number3 - 1] ?? "")}</code></td></tr>`);
13755
- }
13756
- return `<table class="source">${rows.join("")}</table>`;
13757
- }
13758
- async function debugPage(error, method, url2) {
13759
- const err = error instanceof Error ? error : new Error(String(error));
13760
- const frames = stackFrames(err);
13761
- const appFrame = frames.find((frame) => !frame.file.includes("node_modules") && !frame.file.startsWith("node:")) ?? frames[0];
13762
- const source = appFrame === void 0 ? void 0 : await excerpt(appFrame);
13763
- const causes = [];
13764
- for (let cause = err.cause, depth = 0; cause !== void 0 && depth < 5; cause = cause.cause, depth++) {
13765
- causes.push(`<li>${escapeHtml(cause instanceof Error ? `${cause.name}: ${cause.message}` : String(cause))}</li>`);
13766
- }
13767
- return `<!DOCTYPE html>
13768
- <html lang="en">
13769
- <head>
13770
- <meta charset="utf-8">
13771
- <title>${escapeHtml(err.message || err.name)}</title>
13772
- <style>body{margin:0;font-family:ui-sans-serif,system-ui,sans-serif;background:#f3f4f6;color:#111827}main{max-width:1100px;margin:2rem auto;padding:0 1rem}header{background:#fff;border-radius:.5rem;padding:1.5rem;box-shadow:0 1px 3px #0001}.class{color:#dc2626;font-weight:600}.message{font-size:1.5rem;margin:.5rem 0}.request{color:#6b7280}section{background:#fff;border-radius:.5rem;padding:1rem;margin-top:1rem;box-shadow:0 1px 3px #0001;overflow:auto}.source td{padding:0 .5rem;white-space:pre;font-size:.85rem}.source .n{color:#9ca3af;text-align:right}.source .current{background:#fee2e2}ol{font-family:ui-monospace,monospace;font-size:.85rem}</style>
13773
- </head>
13774
- <body><main>
13775
- <header><div class="class">${escapeHtml(err.name)}</div><div class="message">${escapeHtml(err.message)}</div><div class="request">${escapeHtml(method)} ${escapeHtml(url2)}</div></header>
13776
- ${appFrame === void 0 ? "" : `<section><div>${escapeHtml(appFrame.file)}:${appFrame.line}</div>${source ?? ""}</section>`}
13777
- <section><ol>${frames.map((frame) => `<li>${escapeHtml(frame.text)}</li>`).join("")}</ol></section>
13778
- ${causes.length === 0 ? "" : `<section><div>Caused by</div><ul>${causes.join("")}</ul></section>`}
13779
- </main></body>
13780
- </html>`;
13781
- }
13782
- var NOT_REPORTED = /* @__PURE__ */ new Set(["Http", "ModelNotFound", "Validation", "Authentication", "Authorization", "TokenMismatch"]);
13783
- var HTTP_KINDS = /* @__PURE__ */ new Set(["Http", "ModelNotFound", "Authorization", "TokenMismatch"]);
13784
- var kindOf = (error) => typeof error === "object" && error !== null && typeof error.kind === "string" ? error.kind : void 0;
13785
- function statusFor(error) {
13786
- const status = error?.status;
13787
- switch (kindOf(error)) {
13788
- case "Http":
13789
- return status ?? 500;
13790
- case "ModelNotFound":
13791
- return 404;
13792
- case "Authorization":
13793
- return status ?? 403;
13794
- case "TokenMismatch":
13795
- return 419;
13796
- case "Authentication":
13797
- return 401;
13798
- case "Validation":
13799
- return status ?? 422;
13800
- case "Server":
13801
- return status ?? 500;
13802
- default:
13803
- return 500;
13804
- }
13805
- }
13806
- function summarizeValidation(errors2) {
13807
- const messages = Object.values(errors2).flat();
13808
- if (messages.length === 0) return "The given data was invalid.";
13809
- const more = messages.length - 1;
13810
- return more === 0 ? messages[0] : `${messages[0]} (and ${more} more ${more === 1 ? "error" : "errors"})`;
13811
- }
13812
- var isHttpLike = (error) => {
13813
- const kind = kindOf(error);
13814
- return kind !== void 0 && HTTP_KINDS.has(kind);
13815
- };
13816
- var ErrorHandler = class {
13817
- constructor(app2) {
13818
- this.app = app2;
13819
- }
13820
- app;
13821
- /** Input keys never flashed back on a validation redirect. */
13822
- dontFlash = ["current_password", "password", "password_confirmation"];
13823
- #reportCallbacks = [];
13824
- #renderCallbacks = [];
13825
- #dontReport = [];
13826
- #reported = /* @__PURE__ */ new WeakSet();
13827
- reportUsing(callback) {
13828
- this.#reportCallbacks.push(callback);
13829
- }
13830
- renderUsing(callback) {
13831
- this.#renderCallbacks.push(callback);
13832
- }
13833
- ignore(...classes) {
13834
- this.#dontReport.push(...classes);
13835
- }
13836
- shouldReport(error) {
13837
- const kind = kindOf(error);
13838
- if (kind !== void 0 && NOT_REPORTED.has(kind)) return false;
13839
- return !this.#dontReport.some((cls) => error instanceof cls);
13840
- }
13841
- /** Report callbacks first (returning false stops the default log), then LogManager.error(), else console.error. Once per error. */
13842
- async report(error) {
13843
- if (!this.shouldReport(error)) return;
13844
- if (typeof error === "object" && error !== null) {
13845
- if (this.#reported.has(error)) return;
13846
- this.#reported.add(error);
13847
- }
13848
- try {
13849
- for (const callback of this.#reportCallbacks) if (await callback(error) === false) return;
13850
- const container = this.#container();
13851
- if (container.bound(LogManager)) {
13852
- const message = error instanceof Error ? error.message : String(error);
13853
- container.make(LogManager).error(message, { exception: error });
13854
- } else {
13855
- console.error(error);
13856
- }
13857
- } catch (reportError) {
13858
- console.error(reportError);
13859
- }
13860
- }
13861
- async render(request2, error) {
13862
- for (const callback of this.#renderCallbacks) {
13863
- const response3 = await callback(error, request2);
13864
- if (response3 instanceof Response) return response3;
13865
- }
13866
- if (error instanceof HttpResponseException) return error.response;
13867
- const custom = await this.#renderCustom(request2, error);
13868
- if (custom !== void 0) return custom;
13869
- const http = this.#httpRequest(request2);
13870
- const kind = kindOf(error);
13871
- let response2;
13872
- if (kind === "Validation") response2 = await this.#renderValidation(http, error);
13873
- else if (kind === "Authentication") response2 = await this.#renderAuthentication(http, error);
13874
- else if (http.expectsJson()) response2 = this.#renderJson(error);
13875
- else response2 = await this.#renderHtml(http, error);
13876
- const headers = error?.headers;
13877
- if (headers !== void 0) for (const [name, value2] of Object.entries(headers)) response2.headers.set(name, value2);
13878
- return response2;
13879
- }
13880
- /** An error with its own render(request) or toResponse(request) (Laravel's renderable exceptions / Responsable). */
13881
- async #renderCustom(request2, error) {
13882
- if (typeof error !== "object" || error === null) return void 0;
13883
- const candidate = error;
13884
- for (const method of [candidate.render, candidate.toResponse]) {
13885
- if (typeof method !== "function") continue;
13886
- const response2 = await method.call(error, request2);
13887
- if (response2 instanceof Response) return response2;
13888
- }
13889
- return void 0;
13890
- }
13891
- async #renderValidation(request2, error) {
13892
- if (request2.expectsJson()) {
13893
- return this.#json({ message: summarizeValidation(error.errors), errors: error.errors }, statusFor(error));
13894
- }
13895
- const input = { ...request2.input() };
13896
- for (const key of this.dontFlash) delete input[key];
13897
- const container = this.#container();
13898
- if (!container.bound(Redirector)) {
13899
- return this.#redirect(error.redirectTo ?? request2.header("referer") ?? "/");
13900
- }
13901
- const redirector = container.make(Redirector);
13902
- const redirect2 = error.redirectTo !== void 0 ? redirector.to(error.redirectTo) : redirector.back();
13903
- const response2 = await redirect2.withInput(input).withErrors(error.errors, error.errorBag).toResponse(request2);
13904
- return response2;
13905
- }
13906
- async #renderAuthentication(request2, error) {
13907
- if (request2.expectsJson()) return this.#json({ message: error.message || "Unauthenticated." }, 401);
13908
- const target = error.redirectTo ?? this.#guestRedirect(request2);
13909
- const container = this.#container();
13910
- if (!container.bound(Redirector)) return this.#redirect(target);
13911
- const redirector = container.make(Redirector);
13912
- const redirect2 = typeof redirector.guest === "function" ? redirector.guest(target) : redirector.to(target);
13913
- return await redirect2.toResponse(request2);
13914
- }
13915
- /** config('http.redirect_guests_to'), then route('login'), then '/login'. */
13916
- #guestRedirect(request2) {
13917
- const configured = this.#config("http.redirect_guests_to", void 0);
13918
- if (typeof configured === "function") return String(configured(request2));
13919
- if (typeof configured === "string" && configured !== "") return configured;
13920
- const container = this.#container();
13921
- if (container.bound(UrlGenerator)) {
13922
- const url2 = container.make(UrlGenerator);
13923
- if (url2.hasRoute("login")) return url2.route("login");
13924
- }
13925
- return "/login";
13926
- }
13927
- #renderJson(error) {
13928
- const status = statusFor(error);
13929
- if (isHttpLike(error)) {
13930
- const message = error instanceof Error && error.message !== "" ? error.message : statusText(status);
13931
- return this.#json({ message }, status);
13932
- }
13933
- if (!this.#debug()) return this.#json({ message: "Server Error" }, status);
13934
- const err = error instanceof Error ? error : new Error(String(error));
13935
- const [frame] = stackFrames(err);
13936
- return this.#json(
13937
- {
13938
- message: err.message,
13939
- exception: err.name,
13940
- file: frame?.file,
13941
- line: frame?.line,
13942
- trace: stackFrames(err).map((entry) => entry.text)
13943
- },
13944
- status
13945
- );
13946
- }
13947
- async #renderHtml(request2, error) {
13948
- const status = statusFor(error);
13949
- if (!isHttpLike(error) && this.#debug()) {
13950
- return this.#html(await debugPage(error, request2.method(), request2.fullUrl()), status);
13951
- }
13952
- const message = status === 403 && error instanceof Error && error.message !== "" ? error.message : statusText(status);
13953
- const view2 = await this.#errorView(status, error, message);
13954
- return this.#html(view2 ?? minimalPage(status, message), status);
13955
- }
13956
- /** resources/views/errors/{status}.tsx, then errors/4xx or errors/5xx, through the ViewFactory. */
13957
- async #errorView(status, error, message) {
13958
- const container = this.#container();
13959
- if (!container.bound(ViewFactory)) return void 0;
13960
- const views = container.make(ViewFactory);
13961
- for (const name of [`errors.${status}`, `errors.${Math.floor(status / 100)}xx`]) {
13962
- if (!views.exists(name)) continue;
13963
- try {
13964
- return await views.make(name, { exception: error, status, message }).render();
13965
- } catch (viewError) {
13966
- await this.report(viewError);
13967
- return void 0;
13968
- }
13969
- }
13970
- return void 0;
13971
- }
13972
- #httpRequest(request2) {
13973
- if (typeof request2 === "object" && request2 !== null && typeof request2.expectsJson === "function") {
13974
- return request2;
13975
- }
13976
- return new IncomingRequest(request2 instanceof Request ? request2 : new Request("http://localhost/"));
13977
- }
13978
- #json(body, status) {
13979
- return new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
13980
- }
13981
- #html(body, status) {
13982
- return new Response(body, { status, headers: { "content-type": "text/html; charset=utf-8" } });
13983
- }
13984
- #redirect(location) {
13985
- return new Response(null, { status: 302, headers: { Location: location } });
13986
- }
13987
- #debug() {
13988
- return this.#config("app.debug", false) === true;
13989
- }
13990
- #config(key, fallback) {
13991
- return this.app.bound(ConfigRepository) ? this.app.make(ConfigRepository).get(key, fallback) : fallback;
13992
- }
13993
- /** The request scope while handling a request (so scoped services resolve), else the application. */
13994
- #container() {
13995
- return currentContainer() ?? this.app;
13996
- }
13997
- };
13998
- var ExceptionsConfiguration = class {
13999
- constructor(handler3) {
14000
- this.handler = handler3;
14001
- }
14002
- handler;
14003
- report(callback) {
14004
- this.handler.reportUsing(callback);
14005
- return this;
14006
- }
14007
- render(callback) {
14008
- this.handler.renderUsing(callback);
14009
- return this;
14010
- }
14011
- dontReport(...classes) {
14012
- this.handler.ignore(...classes);
14013
- return this;
14014
- }
14015
- };
14016
- function applyExceptionCallbacks(app2, handler3) {
14017
- if (!app2.bound(ExceptionCallbacks)) return;
14018
- const configurator = new ExceptionsConfiguration(handler3);
14019
- for (const callback of app2.make(ExceptionCallbacks)) callback(configurator);
14020
- }
14021
- var HIDDEN_SEGMENT = /^\.|\.(ts|tsx|mts|cts)$|[. ]$/i;
14022
- async function servePublicFile(publicPath, request2) {
14023
- if (request2.method !== "GET" && request2.method !== "HEAD") return void 0;
14024
- let pathname;
14025
- try {
14026
- pathname = decodeURIComponent(new URL(request2.url).pathname);
14027
- } catch {
14028
- return void 0;
14029
- }
14030
- if (pathname === "/" || pathname.includes("\0")) return void 0;
14031
- const root = resolve3(publicPath);
14032
- const file = resolve3(root, `.${pathname}`);
14033
- if (!file.startsWith(root + sep4)) return void 0;
14034
- if (relative5(root, file).split(/[\\/]/).some((segment) => HIDDEN_SEGMENT.test(segment))) return void 0;
14035
- const info = await stat22(file).catch(() => void 0);
14036
- if (info === void 0 || !info.isFile()) return void 0;
14037
- const type = mimeFromExtension2(file);
14038
- const headers = new Headers({
14039
- "content-type": type.startsWith("text/") || type === "application/json" ? `${type}; charset=utf-8` : type,
14040
- "content-length": String(info.size),
14041
- "last-modified": info.mtime.toUTCString()
14042
- });
14043
- if (pathname.startsWith("/build/assets/")) headers.set("cache-control", "public, max-age=31536000, immutable");
14044
- if (request2.method === "HEAD") return new Response(null, { status: 200, headers });
14045
- const body = Readable22.toWeb(createReadStream22(file));
14046
- return new Response(body, { status: 200, headers });
14047
- }
14048
- async function terminateRequest(app2, request2, response2) {
14049
- try {
14050
- if (app2.bound(HttpKernel)) await app2.make(HttpKernel).terminate?.(request2, response2);
14051
- } catch (error) {
14052
- console.error(error);
14053
- }
14054
- }
14055
- async function handleSafely(app2, request2, publicPath) {
14056
- try {
14057
- if (publicPath !== void 0) {
14058
- const file = await servePublicFile(publicPath, request2);
14059
- if (file !== void 0) return file;
14060
- }
14061
- return await app2.handle(request2);
14062
- } catch (error) {
14063
- console.error(error);
14064
- return plainServerError();
14065
- }
14066
- }
14067
- function exitOnSignals(close, closed) {
14068
- const onSignal = () => {
14069
- void close().then(() => process.exit(0));
14070
- };
14071
- process.once("SIGINT", onSignal);
14072
- process.once("SIGTERM", onSignal);
14073
- void closed.then(() => {
14074
- process.off("SIGINT", onSignal);
14075
- process.off("SIGTERM", onSignal);
14076
- });
14077
- }
14078
- var displayHost = (hostname) => hostname.includes(":") ? `[${hostname}]` : hostname;
14079
- function bunRuntime() {
14080
- return globalThis.Bun;
14081
- }
14082
- async function serveBun(app2, options) {
14083
- const bun = bunRuntime();
14084
- if (bun === void 0) throw new HttpServerError("Bun.serve is not available: the process is not running on Bun.");
14085
- let markClosed = () => void 0;
14086
- const closed = new Promise((resolve22) => markClosed = resolve22);
14087
- const server = bun.serve({
14088
- port: options.port,
14089
- hostname: options.hostname,
14090
- async fetch(request2, current) {
14091
- setClientAddress(request2, current.requestIP(request2)?.address);
14092
- const response2 = await handleSafely(app2, request2, options.publicPath);
14093
- setTimeout(() => void terminateRequest(app2, request2, response2), 0);
14094
- return response2;
14095
- },
14096
- error(error) {
14097
- console.error(error);
14098
- return plainServerError();
14099
- }
14100
- });
14101
- let closing;
14102
- const close = () => closing ??= (async () => {
14103
- let timer;
14104
- const forced = new Promise((resolve22) => {
14105
- timer = setTimeout(() => void Promise.resolve(server.stop(true)).then(resolve22), options.shutdownTimeout);
14106
- });
14107
- await Promise.race([Promise.resolve(server.stop(false)), forced]);
14108
- clearTimeout(timer);
14109
- markClosed();
14110
- })();
14111
- if (options.signals) exitOnSignals(close, closed);
14112
- return {
14113
- runtime: "bun",
14114
- hostname: options.hostname,
14115
- port: server.port,
14116
- url: `http://${displayHost(options.hostname)}:${server.port}`,
14117
- close,
14118
- closed
14119
- };
14120
- }
14121
- function requestBody(req) {
14122
- let finished = false;
14123
- const detach = () => {
14124
- finished = true;
14125
- req.off("data", onData);
14126
- req.off("end", onEnd);
14127
- req.off("error", onError);
14128
- req.off("close", onClose);
14129
- };
14130
- let controller;
14131
- const onData = (chunk) => {
14132
- if (finished) return;
14133
- controller.enqueue(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength));
14134
- if ((controller.desiredSize ?? 0) <= 0) req.pause();
14135
- };
14136
- const onEnd = () => {
14137
- if (finished) return;
14138
- detach();
14139
- controller.close();
14140
- };
14141
- const onError = (error) => {
14142
- if (finished) return;
14143
- detach();
14144
- controller.error(error);
14145
- };
14146
- const onClose = () => {
14147
- if (!finished && !req.complete) onError(new Error("The request was aborted."));
14148
- };
14149
- return new ReadableStream(
14150
- {
14151
- start(c) {
14152
- controller = c;
14153
- req.on("data", onData);
14154
- req.on("end", onEnd);
14155
- req.on("error", onError);
14156
- req.on("close", onClose);
14157
- req.pause();
14158
- },
14159
- pull() {
14160
- req.resume();
14161
- },
14162
- cancel() {
14163
- detach();
14164
- }
14165
- },
14166
- { highWaterMark: 0 }
14167
- );
14168
- }
14169
- function toWebRequest(req, res, fallbackHost) {
14170
- const target = req.url ?? "/";
14171
- const url2 = new URL(`http://${req.headers.host ?? fallbackHost}${target.startsWith("/") ? target : `/${target}`}`);
14172
- const headers = new Headers();
14173
- for (let i = 0; i < req.rawHeaders.length; i += 2) {
14174
- const name = req.rawHeaders[i];
14175
- if (!name.startsWith(":")) headers.append(name, req.rawHeaders[i + 1]);
14176
- }
14177
- const method = (req.method ?? "GET").toUpperCase();
14178
- const controller = new AbortController();
14179
- res.once("close", () => {
14180
- if (!res.writableFinished) controller.abort();
14181
- });
14182
- const init = { method, headers, signal: controller.signal };
14183
- if (method !== "GET" && method !== "HEAD") {
14184
- init.body = requestBody(req);
14185
- init.duplex = "half";
14186
- }
14187
- return new Request(url2, init);
14188
- }
14189
- async function writeResponse(res, response2) {
14190
- res.statusCode = response2.status;
14191
- if (response2.statusText !== "") res.statusMessage = response2.statusText;
14192
- response2.headers.forEach((value2, name) => {
14193
- if (name !== "set-cookie") res.setHeader(name, value2);
14194
- });
14195
- const cookies = response2.headers.getSetCookie();
14196
- if (cookies.length > 0) res.setHeader("set-cookie", cookies);
14197
- if (response2.body === null) {
14198
- res.end();
14199
- return;
14200
- }
14201
- await pipeline2(Readable3.fromWeb(response2.body), res);
14202
- }
14203
- async function serveNode(app2, options) {
14204
- const fallbackHost = `${displayHost(options.hostname)}:${options.port}`;
14205
- const server = createServer((req, res) => {
14206
- void (async () => {
14207
- let request2;
14208
- try {
14209
- request2 = toWebRequest(req, res, fallbackHost);
14210
- } catch {
14211
- res.statusCode = 400;
14212
- res.end("Bad Request");
14213
- return;
14214
- }
14215
- setClientAddress(request2, req.socket.remoteAddress);
14216
- const response2 = await handleSafely(app2, request2, options.publicPath);
14217
- try {
14218
- await writeResponse(res, response2);
14219
- } catch {
14220
- res.destroy();
14221
- }
14222
- await terminateRequest(app2, request2, response2);
14223
- })();
14224
- });
14225
- await new Promise((resolve22, reject) => {
14226
- server.once("error", reject);
14227
- server.listen(options.port, options.hostname, () => {
14228
- server.off("error", reject);
14229
- resolve22();
14230
- });
14231
- });
14232
- const address = server.address();
14233
- const closed = new Promise((resolve22) => server.once("close", () => resolve22()));
14234
- let closing;
14235
- const close = () => closing ??= (async () => {
14236
- const done = new Promise((resolve22) => server.close(() => resolve22()));
14237
- server.closeIdleConnections();
14238
- const idle = setInterval(() => server.closeIdleConnections(), 50);
14239
- const force = setTimeout(() => server.closeAllConnections(), options.shutdownTimeout);
14240
- await done;
14241
- clearInterval(idle);
14242
- clearTimeout(force);
14243
- })();
14244
- if (options.signals) exitOnSignals(close, closed);
14245
- return {
14246
- runtime: "node",
14247
- hostname: options.hostname,
14248
- port: address.port,
14249
- url: `http://${displayHost(options.hostname)}:${address.port}`,
14250
- close,
14251
- closed
14252
- };
14253
- }
14254
- function detectRuntime() {
14255
- return bunRuntime() !== void 0 ? "bun" : "node";
14256
- }
14257
- async function serve(app2, options = {}) {
14258
- const resolved = {
14259
- port: options.port ?? Number(process.env.PORT ?? process.env.SERVER_PORT ?? 8e3),
14260
- hostname: options.hostname ?? "127.0.0.1",
14261
- signals: options.signals ?? true,
14262
- shutdownTimeout: options.shutdownTimeout ?? 1e4,
14263
- ...options.publicPath !== false && { publicPath: options.publicPath ?? app2.publicPath() }
14264
- };
14265
- await app2.boot();
14266
- const runtime = options.runtime ?? detectRuntime();
14267
- const server = runtime === "bun" ? await serveBun(app2, resolved) : await serveNode(app2, resolved);
14268
- const onListen = options.onListen ?? ((running) => console.log(`Server running on [${running.url}].`));
14269
- onListen(server);
14270
- return server;
14271
- }
14272
- function io(command) {
14273
- return {
14274
- option: (name) => {
14275
- const value2 = command.option(name);
14276
- return value2 === void 0 || value2 === null || value2 === false || value2 === "" ? void 0 : String(value2);
14277
- },
14278
- flag: (name) => {
14279
- const value2 = command.option(name);
14280
- return value2 === true || value2 === "true" || value2 === "1";
14281
- },
14282
- info: (message) => command.info(message),
14283
- line: (message) => command.line(message),
14284
- warn: (message) => command.warn(message),
14285
- error: (message) => command.error(message)
14286
- };
14287
- }
14288
- var middlewareName = (reference) => typeof reference === "string" ? reference : reference.name;
14289
- function routeListRows(routes) {
14290
- const rows = routes.map((route2) => {
14291
- const listable = route2;
14292
- return {
14293
- method: route2.methods.join("|"),
14294
- uri: route2.uri,
14295
- name: route2.getName() ?? null,
14296
- action: typeof listable.getActionName === "function" ? listable.getActionName() : "Closure",
14297
- middleware: typeof listable.gatherMiddleware === "function" ? listable.gatherMiddleware().map(middlewareName) : []
14298
- };
14299
- });
14300
- return rows.sort((a, b) => a.uri < b.uri ? -1 : a.uri > b.uri ? 1 : 0);
14301
- }
14302
- function filterRouteList(rows, filters) {
14303
- const excluded2 = (filters.exceptPath ?? "").split(",").filter((path) => path !== "");
14304
- return rows.filter((row) => {
14305
- if (filters.name !== void 0 && !(row.name ?? "").includes(filters.name)) return false;
14306
- if (filters.path !== void 0 && !row.uri.includes(filters.path)) return false;
14307
- if (filters.method !== void 0 && !row.method.includes(filters.method.toUpperCase())) return false;
14308
- return !excluded2.some((path) => row.uri.includes(path));
14309
- });
14310
- }
14311
- function formatRouteList(rows, width) {
14312
- const methodWidth = Math.max(...rows.map((row) => row.method.length));
14313
- const lines = rows.map((row) => {
14314
- const spaces = " ".repeat(Math.max(methodWidth + 6 - row.method.length, 0));
14315
- const action = row.action === "Closure" ? row.name ?? "" : row.name === null ? row.action : `${row.name} \u203A ${row.action}`;
14316
- const used = row.method.length + spaces.length + row.uri.length + action.length + 6 + (action === "" ? 0 : 1);
14317
- const dots = ".".repeat(Math.max(width - used, 0));
14318
- return ` ${row.method} ${spaces}${row.uri}${dots === "" ? "" : ` ${dots}`}${action === "" ? "" : ` ${action}`}`;
14319
- });
14320
- const count = `Showing [${rows.length}] ${rows.length === 1 ? "route" : "routes"}`;
14321
- return [...lines, "", `${" ".repeat(Math.max(width - count.length - 2, 0))}${count}`];
14322
- }
14323
- var API_ROUTES_STUB = `import { request, Route } from '@orieljs/framework'
14324
-
14325
- Route.get('/user', () => request().user()).middleware('auth:token')
14326
- `;
14327
- function addApiRouting(source) {
14328
- const code = source.replace(/^[ \t]*\/\/.*$/gm, "");
14329
- if (/withRouting\(\s*\{[^}]*\bapi\s*:/.test(code)) return source;
14330
- const commented = /^([ \t]*)\/\/\s*(api:\s*['"`][^'"`\n]*['"`],?)[ \t]*$/m.exec(source);
14331
- if (commented !== null) return source.replace(commented[0], () => `${commented[1]}${commented[2]}`);
14332
- const web = /^([ \t]*)web:\s*(['"`])[^'"`\n]*\2[ \t]*,?[ \t]*$/m.exec(source);
14333
- if (web !== null) {
14334
- const line = web[0].trimEnd();
14335
- return source.replace(web[0], () => `${line.endsWith(",") ? line : `${line},`}
14336
- ${web[1]}api: 'routes/api.ts',`);
14337
- }
14338
- const inline = /withRouting\(\s*\{/.exec(source);
14339
- if (inline !== null) return source.replace(inline[0], () => `${inline[0]} api: 'routes/api.ts',`);
14340
- const create = /^([ \t]*)\.create\(\)/m.exec(source);
14341
- if (create !== null) return source.replace(create[0], () => `${create[1]}.withRouting({ api: 'routes/api.ts' })
14342
- ${create[0]}`);
14343
- return void 0;
14344
- }
14345
- function registerHttpCommands(kernel, app2, options = {}) {
14346
- const serveApp = options.serve ?? serve;
14347
- const terminalWidth = options.terminalWidth ?? (() => process.stdout.columns ?? 120);
14348
- kernel.command(
14349
- "serve {--host=127.0.0.1 : The host address to serve the application on} {--port= : The port to serve the application on}",
14350
- async function() {
14351
- const out = io(this);
14352
- const port = out.option("port");
14353
- if (port !== void 0 && !/^\d+$/.test(port)) {
14354
- out.error("The --port option must be a number.");
14355
- return 1;
14356
- }
14357
- const server = await serveApp(app2, {
14358
- hostname: out.option("host") ?? "127.0.0.1",
14359
- ...port !== void 0 && { port: Number(port) },
14360
- onListen: (running) => {
14361
- out.info(`Server running on [${running.url}].`);
14362
- out.line("Press Ctrl+C to stop the server");
14363
- }
14364
- });
14365
- await server.closed;
14366
- return 0;
14367
- }
14368
- ).purpose("Serve the application on the Oriel development server");
14369
- kernel.command(
14370
- "route:list {--method= : Filter the routes by method} {--name= : Filter the routes by name} {--path= : Only show routes matching the given path pattern} {--except-path= : Do not display the routes matching the given path pattern} {--reverse : Reverse the ordering of the routes} {--json : Output the route list as JSON}",
14371
- function() {
14372
- const out = io(this);
14373
- if (!app2.bound(Router)) {
14374
- out.error("The router is not available. Is the Routing service provider registered?");
14375
- return 1;
14376
- }
14377
- const all = routeListRows(app2.make(Router).getRoutes());
14378
- if (all.length === 0) {
14379
- out.error("Your application doesn't have any routes.");
14380
- return 0;
14381
- }
14382
- const rows = filterRouteList(all, {
14383
- ...out.option("method") !== void 0 && { method: out.option("method") },
14384
- ...out.option("name") !== void 0 && { name: out.option("name") },
14385
- ...out.option("path") !== void 0 && { path: out.option("path") },
14386
- ...out.option("except-path") !== void 0 && { exceptPath: out.option("except-path") }
14387
- });
14388
- if (rows.length === 0) {
14389
- out.error("Your application doesn't have any routes matching the given criteria.");
14390
- return 0;
14391
- }
14392
- if (out.flag("reverse")) rows.reverse();
14393
- if (out.flag("json")) {
14394
- out.line(JSON.stringify(rows));
14395
- return 0;
14396
- }
14397
- for (const line of formatRouteList(rows, terminalWidth())) out.line(line);
14398
- return 0;
14399
- }
14400
- ).purpose("List all registered routes");
14401
- kernel.command("install:api {--force : Overwrite any existing API routes file}", async function() {
14402
- const out = io(this);
14403
- const routesFile = app2.basePath("routes/api.ts");
14404
- if (existsSync7(routesFile) && !out.flag("force")) {
14405
- out.error("API routes file already exists.");
14406
- } else {
14407
- await mkdir5(dirname5(routesFile), { recursive: true });
14408
- await writeFile6(routesFile, API_ROUTES_STUB);
14409
- out.info("Published API routes file.");
14410
- }
14411
- const bootstrapFile = app2.bootstrapPath("app.ts");
14412
- const source = existsSync7(bootstrapFile) ? await readFile22(bootstrapFile, "utf8") : void 0;
14413
- const updated = source === void 0 ? void 0 : addApiRouting(source);
14414
- if (updated === void 0) {
14415
- out.warn(
14416
- "Unable to automatically add API route definition to bootstrap file. Add api: 'routes/api.ts' to withRouting() in bootstrap/app.ts."
14417
- );
14418
- } else if (updated !== source) {
14419
- await writeFile6(bootstrapFile, updated);
14420
- }
14421
- out.info("API scaffolding installed. Run [oriel migrate] to create the personal access tokens table.");
14422
- return 0;
14423
- }).purpose("Create an API routes file and prepare the application for API authentication");
14424
- }
14425
- var HttpServiceProvider = class extends ServiceProvider {
14426
- register() {
14427
- this.mergeConfigFrom(
14428
- {
14429
- trusted_proxies: [],
14430
- max_body_size: 8 * 1024 * 1024,
14431
- csrf_except: [],
14432
- redirect_guests_to: void 0,
14433
- redirect_users_to: void 0
14434
- },
14435
- "http"
14436
- );
14437
- this.app.singleton(HttpKernel, () => new Kernel2(this.app));
14438
- this.app.singleton(ExceptionHandler, () => {
14439
- const handler3 = new ErrorHandler(this.app);
14440
- applyExceptionCallbacks(this.app, handler3);
14441
- return handler3;
14442
- });
14443
- this.app.singleton(ResponseFactory, () => new HttpResponseFactory());
14444
- this.app.singleton(Redirector, () => new HttpRedirector());
14445
- }
14446
- boot() {
14447
- this.app.booted(() => {
14448
- const kernel = this.app.make(HttpKernel);
14449
- if (kernel instanceof Kernel2 && this.app.bound(Router)) applyMiddlewareCallbacks(this.app, kernel);
14450
- });
14451
- if (this.app.bound(ConsoleKernel)) registerHttpCommands(this.app.make(ConsoleKernel), this.app);
14452
- }
14453
- };
14454
-
14455
- // ../Inertia/dist/index.js
14456
- import { existsSync as existsSync8 } from "fs";
14457
- import { join as join10 } from "path";
14458
- import { createHash as createHash5 } from "crypto";
14459
- import { existsSync as existsSync23, readFileSync } from "fs";
14460
- import { spawn as spawn2 } from "child_process";
14461
- import { existsSync as existsSync33 } from "fs";
14462
- import { mkdir as mkdir6, writeFile as writeFile7 } from "fs/promises";
14463
- import { dirname as dirname6, isAbsolute as isAbsolute2, join as join24, relative as relative6 } from "path";
14464
- import { existsSync as existsSync42, readFileSync as readFileSync2 } from "fs";
14465
- var Header = {
14466
- INERTIA: "X-Inertia",
14467
- ERROR_BAG: "X-Inertia-Error-Bag",
14468
- LOCATION: "X-Inertia-Location",
14469
- REDIRECT: "X-Inertia-Redirect",
14470
- VERSION: "X-Inertia-Version",
14471
- PARTIAL_COMPONENT: "X-Inertia-Partial-Component",
14472
- PARTIAL_ONLY: "X-Inertia-Partial-Data",
14473
- PARTIAL_EXCEPT: "X-Inertia-Partial-Except",
14474
- RESET: "X-Inertia-Reset",
14475
- INFINITE_SCROLL_MERGE_INTENT: "X-Inertia-Infinite-Scroll-Merge-Intent",
14476
- EXCEPT_ONCE_PROPS: "X-Inertia-Except-Once-Props"
14477
- };
14478
- function parseList(value2) {
14479
- const items = (value2 ?? "").split(",").filter((item) => item !== "");
14480
- return items.length === 0 ? void 0 : items;
14481
- }
14482
- var Prop = class {
14483
- constructor(value2) {
14484
- this.value = value2;
14485
- }
14486
- value;
14487
- mergeState = { merge: false, deep: false, append: true, appendPaths: [], prependPaths: [], matchOn: [] };
14488
- onceState = { once: false, fresh: false, key: void 0, ttlSeconds: void 0 };
14489
- deferred = false;
14490
- deferGroup;
14491
- /** Calls the callback, if the value is one. */
14492
- async resolve() {
14493
- return typeof this.value === "function" ? await this.value() : this.value;
14494
- }
14495
- /** Never sent on the first load (OptionalProp, DeferProp). */
14496
- ignoresFirstLoad() {
14497
- return false;
14498
- }
14499
- /** Sent even when a partial reload didn't ask for it (AlwaysProp). */
14500
- isAlways() {
14501
- return false;
14502
- }
14503
- /** Errors are reported and the prop is left out, instead of failing the page (defer(..., { rescue: true })). */
14504
- shouldRescue() {
14505
- return false;
14506
- }
14507
- // Once (honoured by OptionalProp, DeferProp, MergeProp and OnceProp) ------------------------------------
14508
- /** once(), once(false), once(true, { as: 'key', until: 3600 }). */
14509
- once(value2 = true, options = {}) {
14510
- this.onceState.once = value2;
14511
- if (options.as !== void 0) this.onceState.key = options.as;
14512
- if (options.until !== void 0) this.onceState.ttlSeconds = secondsUntil(options.until);
14513
- return this;
14514
- }
14515
- /** A custom once key, so pages can share the prop under different names. */
14516
- as(key) {
14517
- this.onceState.key = key;
14518
- return this;
14519
- }
14520
- /** Send the prop again even though the client already has it. */
14521
- fresh(value2 = true) {
14522
- this.onceState.fresh = value2;
14523
- return this;
14524
- }
14525
- /** Expire after a number of seconds, or at a Date. */
14526
- until(delay) {
14527
- this.onceState.ttlSeconds = secondsUntil(delay);
14528
- return this;
14529
- }
14530
- // Merging -------------------------------------------------------------------------------------------------
14531
- isMergeable() {
14532
- return false;
14533
- }
14534
- shouldMerge() {
14535
- return this.isMergeable() && this.mergeState.merge;
14536
- }
14537
- shouldDeepMerge() {
14538
- return this.mergeState.deep;
14539
- }
14540
- matchesOn() {
14541
- return [...this.mergeState.matchOn];
12977
+ matchesOn() {
12978
+ return [...this.mergeState.matchOn];
14542
12979
  }
14543
12980
  appendsAtRoot() {
14544
12981
  return this.mergeState.append && this.mergesAtRoot();
@@ -15116,9 +13553,9 @@ var Response2 = class {
15116
13553
  }
15117
13554
  };
15118
13555
  function pageExists(component, paths, extensions) {
15119
- return paths.some((path) => extensions.some((extension) => existsSync8(join10(path, `${component}.${extension}`))));
13556
+ return paths.some((path) => extensions.some((extension) => existsSync7(join10(path, `${component}.${extension}`))));
15120
13557
  }
15121
- var ResponseFactory2 = class _ResponseFactory {
13558
+ var ResponseFactory = class _ResponseFactory {
15122
13559
  constructor(app2, parent) {
15123
13560
  this.app = app2;
15124
13561
  this.parent = parent;
@@ -15243,7 +13680,7 @@ function inertiaFactory() {
15243
13680
  const container = currentContainer();
15244
13681
  if (container === void 0) throw new ContainerNotAvailableError("Inertia");
15245
13682
  if (container.bound(HttpRequest)) return container.make(InertiaFactory);
15246
- return container.make(Application).make(ResponseFactory2);
13683
+ return container.make(Application).make(ResponseFactory);
15247
13684
  }
15248
13685
  function inertia(component, props = {}) {
15249
13686
  const factory = inertiaFactory();
@@ -15419,7 +13856,7 @@ function isEmpty(response2) {
15419
13856
  return response2.status === 200 && (response2.body === null || response2.headers.get("content-length") === "0");
15420
13857
  }
15421
13858
  function md5(value2) {
15422
- return createHash5("md5").update(value2).digest("hex");
13859
+ return createHash7("md5").update(value2).digest("hex");
15423
13860
  }
15424
13861
  var EncryptHistory = class {
15425
13862
  #container = inject(Container);
@@ -15498,6 +13935,7 @@ export class {{ class }} extends InertiaMiddleware {
15498
13935
  }
15499
13936
  }
15500
13937
  `;
13938
+ var DEFAULT_EXCEPT_ROUTES = ["live.*"];
15501
13939
  async function loadPageTypes() {
15502
13940
  const specifier = "@orieljs/vite/types";
15503
13941
  try {
@@ -15521,12 +13959,12 @@ function registerInertiaCommands(kernel, app2, gateway, options = {}) {
15521
13959
  }
15522
13960
  const output = absolute(optionText(this.option("output")) ?? config2("inertia.types.routes", "resources/js/oriel/routes.ts"));
15523
13961
  const server = absolute(optionText(this.option("server")) ?? config2("inertia.types.server_routes", "types/routes.d.ts"));
15524
- const table = routeTable(app2.make(Router).getRoutes(), config2("inertia.types.except_routes", []));
15525
- await mkdir6(dirname6(output), { recursive: true });
15526
- await writeFile7(output, renderRoutesModule(table));
15527
- await mkdir6(dirname6(server), { recursive: true });
15528
- await writeFile7(server, renderServerRouteTypes(routeTable(app2.make(Router).getRoutes())));
15529
- this.info(`Route types for ${Object.keys(table).length} named routes written to ${relative6(app2.basePath(), output)}.`);
13962
+ const table = routeTable(app2.make(Router).getRoutes(), config2("inertia.types.except_routes", DEFAULT_EXCEPT_ROUTES));
13963
+ await mkdir5(dirname5(output), { recursive: true });
13964
+ await writeFile6(output, renderRoutesModule(table));
13965
+ await mkdir5(dirname5(server), { recursive: true });
13966
+ await writeFile6(server, renderServerRouteTypes(routeTable(app2.make(Router).getRoutes())));
13967
+ this.info(`Route types for ${Object.keys(table).length} named routes written to ${relative5(app2.basePath(), output)}.`);
15530
13968
  return 0;
15531
13969
  }
15532
13970
  ).purpose("Generate the route table and route name types for the frontend");
@@ -15539,7 +13977,7 @@ function registerInertiaCommands(kernel, app2, gateway, options = {}) {
15539
13977
  const output = absolute(optionText(this.option("output")) ?? config2("inertia.types.pages", "resources/js/oriel/pages.d.ts"));
15540
13978
  const result = await module.generatePageTypes({ root: app2.basePath(), output });
15541
13979
  for (const warning of result.warnings) this.warn(warning);
15542
- this.info(`Page types for ${result.pages} pages written to ${relative6(app2.basePath(), result.output)}.`);
13980
+ this.info(`Page types for ${result.pages} pages written to ${relative5(app2.basePath(), result.output)}.`);
15543
13981
  return 0;
15544
13982
  }).purpose("Generate TypeScript types for the Inertia page props");
15545
13983
  kernel.command("inertia:middleware {name=HandleInertiaRequests : The middleware class name} {--force : Overwrite an existing file}", async function() {
@@ -15550,12 +13988,12 @@ function registerInertiaCommands(kernel, app2, gateway, options = {}) {
15550
13988
  }
15551
13989
  const file = app2.appPath(join24("Http", "Middleware", `${name}.ts`));
15552
13990
  if (existsSync33(file) && this.option("force") !== true) {
15553
- this.error(`Middleware [${relative6(app2.basePath(), file)}] already exists.`);
13991
+ this.error(`Middleware [${relative5(app2.basePath(), file)}] already exists.`);
15554
13992
  return 1;
15555
13993
  }
15556
- await mkdir6(dirname6(file), { recursive: true });
15557
- await writeFile7(file, MIDDLEWARE_STUB2.replace("{{ class }}", () => name));
15558
- this.info(`Middleware [${relative6(app2.basePath(), file)}] created successfully.`);
13994
+ await mkdir5(dirname5(file), { recursive: true });
13995
+ await writeFile6(file, MIDDLEWARE_STUB2.replace("{{ class }}", () => name));
13996
+ this.info(`Middleware [${relative5(app2.basePath(), file)}] created successfully.`);
15559
13997
  return 0;
15560
13998
  }).purpose("Create a new Inertia middleware");
15561
13999
  kernel.command("inertia:start-ssr {--runtime= : The runtime that runs the SSR bundle (node or bun)}", async function() {
@@ -15568,13 +14006,18 @@ function registerInertiaCommands(kernel, app2, gateway, options = {}) {
15568
14006
  this.error("Inertia SSR bundle not found. Build it with `vite build --ssr`, or set `inertia.ssr.bundle`.");
15569
14007
  return 1;
15570
14008
  }
14009
+ const port = urlPort(gateway.productionUrl());
14010
+ if (port === void 0) {
14011
+ this.error(`inertia.ssr.url [${gateway.productionUrl()}] is not a URL.`);
14012
+ return 1;
14013
+ }
15571
14014
  const runtime = optionText(this.option("runtime")) ?? config2("inertia.ssr.runtime", "node");
15572
- const child = (options.spawn ?? spawn2)(runtime, [bundle], { stdio: "inherit" });
15573
- return await new Promise((resolve4) => {
15574
- child.on("exit", (code) => resolve4(code ?? 0));
14015
+ const child = (options.spawn ?? spawn2)(runtime, [bundle], { stdio: "inherit", env: { ...process.env, INERTIA_SSR_PORT: port } });
14016
+ return await new Promise((resolve3) => {
14017
+ child.on("exit", (code) => resolve3(code ?? 0));
15575
14018
  child.on("error", (error) => {
15576
14019
  this.error(`Could not start the SSR server: ${error.message}`);
15577
- resolve4(1);
14020
+ resolve3(1);
15578
14021
  });
15579
14022
  });
15580
14023
  }).purpose("Start the Inertia SSR server");
@@ -15595,6 +14038,15 @@ function registerInertiaCommands(kernel, app2, gateway, options = {}) {
15595
14038
  return 1;
15596
14039
  }).purpose("Check the Inertia SSR server health status");
15597
14040
  }
14041
+ function urlPort(url2) {
14042
+ try {
14043
+ const parsed = new URL(url2);
14044
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
14045
+ return parsed.port !== "" ? parsed.port : parsed.protocol === "https:" ? "443" : "80";
14046
+ } catch {
14047
+ return void 0;
14048
+ }
14049
+ }
15598
14050
  function optionText(value2) {
15599
14051
  return value2 === void 0 || value2 === null || value2 === false || value2 === "" ? void 0 : String(value2);
15600
14052
  }
@@ -15722,12 +14174,13 @@ var InertiaServiceProvider = class extends ServiceProvider {
15722
14174
  expose_shared_prop_keys: true,
15723
14175
  store_previous_url: false,
15724
14176
  history: { encrypt: false },
15725
- types: { pages: "resources/js/oriel/pages.d.ts", routes: "resources/js/oriel/routes.ts", server_routes: "types/routes.d.ts", except_routes: [] }
14177
+ // live.* (Live's update endpoint) stays out of the browser's route table; the server's route names keep it.
14178
+ types: { pages: "resources/js/oriel/pages.d.ts", routes: "resources/js/oriel/routes.ts", server_routes: "types/routes.d.ts", except_routes: [...DEFAULT_EXCEPT_ROUTES] }
15726
14179
  },
15727
14180
  "inertia"
15728
14181
  );
15729
- this.app.singleton(ResponseFactory2, () => new ResponseFactory2(this.app));
15730
- this.app.scoped(InertiaFactory, (container) => container.make(ResponseFactory2).forRequest());
14182
+ this.app.singleton(ResponseFactory, () => new ResponseFactory(this.app));
14183
+ this.app.scoped(InertiaFactory, (container) => container.make(ResponseFactory).forRequest());
15731
14184
  this.app.singleton(HttpGateway, () => new HttpGateway(this.app));
15732
14185
  this.app.singleton(InertiaSsrGateway, (container) => container.make(HttpGateway));
15733
14186
  }
@@ -15740,7 +14193,7 @@ var InertiaServiceProvider = class extends ServiceProvider {
15740
14193
  // ../Log/dist/index.js
15741
14194
  import pino2 from "pino";
15742
14195
  import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync2, readdirSync as readdirSync5, rmSync } from "fs";
15743
- import { basename as basename3, dirname as dirname7, extname as extname3, join as join11 } from "path";
14196
+ import { basename as basename2, dirname as dirname6, extname as extname3, join as join11 } from "path";
15744
14197
  import { Writable } from "stream";
15745
14198
  import "pino";
15746
14199
  var rootKey = {};
@@ -15862,12 +14315,12 @@ function localDay(date) {
15862
14315
  }
15863
14316
  var DATE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
15864
14317
  var DailyRotatingStream = class extends Writable {
15865
- constructor(basePath, days, now4 = () => /* @__PURE__ */ new Date()) {
14318
+ constructor(basePath, days, now5 = () => /* @__PURE__ */ new Date()) {
15866
14319
  super();
15867
14320
  this.days = days;
15868
- this.now = now4;
15869
- this.dir = dirname7(basePath);
15870
- this.stem = basename3(basePath, extname3(basePath) || void 0);
14321
+ this.now = now5;
14322
+ this.dir = dirname6(basePath);
14323
+ this.stem = basename2(basePath, extname3(basePath) || void 0);
15871
14324
  mkdirSync2(this.dir, { recursive: true });
15872
14325
  }
15873
14326
  days;
@@ -15932,8 +14385,8 @@ var DailyRotatingStream = class extends Writable {
15932
14385
  prune() {
15933
14386
  if (this.days <= 0) return;
15934
14387
  const prefix = `${this.stem}-`;
15935
- const now4 = this.now();
15936
- const cutoff = new Date(now4.getFullYear(), now4.getMonth(), now4.getDate() - (this.days - 1)).getTime();
14388
+ const now5 = this.now();
14389
+ const cutoff = new Date(now5.getFullYear(), now5.getMonth(), now5.getDate() - (this.days - 1)).getTime();
15937
14390
  for (const file of readdirSync5(this.dir)) {
15938
14391
  if (!file.startsWith(prefix) || !file.endsWith(".log")) continue;
15939
14392
  const match = DATE_PATTERN.exec(file.slice(prefix.length, -".log".length));
@@ -15996,9 +14449,9 @@ function createSingleChannel(path, minimumLevel = "debug") {
15996
14449
  destination.on("error", (error) => reportLogWriteFailure(path, error));
15997
14450
  return new PinoLogger(pino2(PINO_OPTIONS, destination), minimumLevel);
15998
14451
  }
15999
- function createDailyChannel(path, days = 14, minimumLevel = "debug", now4) {
14452
+ function createDailyChannel(path, days = 14, minimumLevel = "debug", now5) {
16000
14453
  assertLogLevel(minimumLevel);
16001
- const stream = new DailyRotatingStream(path, days, now4);
14454
+ const stream = new DailyRotatingStream(path, days, now5);
16002
14455
  return new PinoLogger(pino2(PINO_OPTIONS, stream), minimumLevel);
16003
14456
  }
16004
14457
  function createStderrChannel(minimumLevel = "debug") {
@@ -16701,7 +15154,8 @@ var MailMessage = class {
16701
15154
  introLines = [];
16702
15155
  actionData;
16703
15156
  outroLines = [];
16704
- salutationLine = "Regards,\nApplication";
15157
+ /** Unset: "Regards," and config('app.name'), as Laravel's template. */
15158
+ salutationLine;
16705
15159
  toAddresses = [];
16706
15160
  ccAddresses = [];
16707
15161
  bccAddresses = [];
@@ -16766,11 +15220,18 @@ var MailMessage = class {
16766
15220
  html2.push(`<p>${escapeHtml2(line)}</p>`);
16767
15221
  text3.push(line);
16768
15222
  }
16769
- html2.push(`<p>${escapeHtml2(this.salutationLine).replace(/\n/g, "<br>")}</p>`);
16770
- text3.push(this.salutationLine);
15223
+ const salutation = this.salutationLine ?? `Regards,
15224
+ ${appName()}`;
15225
+ html2.push(`<p>${escapeHtml2(salutation).replace(/\n/g, "<br>")}</p>`);
15226
+ text3.push(salutation);
16771
15227
  return { html: `<!doctype html><html><body>${html2.join("\n")}</body></html>`, text: text3.join("\n\n") };
16772
15228
  }
16773
15229
  };
15230
+ function appName() {
15231
+ const container = currentContainer();
15232
+ const name = container?.bound(ConfigRepository) ? container.make(ConfigRepository).get("app.name") : void 0;
15233
+ return typeof name === "string" && name !== "" ? name : "Oriel";
15234
+ }
16774
15235
  function escapeHtml2(value2) {
16775
15236
  return value2.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
16776
15237
  }
@@ -16841,9 +15302,9 @@ function wrapRow(row, db) {
16841
15302
  readAt: row.read_at ? parseStoredDate2(row.read_at) : void 0,
16842
15303
  async markAsRead() {
16843
15304
  if (record.readAt) return;
16844
- const now4 = /* @__PURE__ */ new Date();
16845
- await db.table(NOTIFICATIONS_TABLE).where("id", record.id).update({ read_at: now4, updated_at: now4 });
16846
- record.readAt = now4;
15305
+ const now5 = /* @__PURE__ */ new Date();
15306
+ await db.table(NOTIFICATIONS_TABLE).where("id", record.id).update({ read_at: now5, updated_at: now5 });
15307
+ record.readAt = now5;
16847
15308
  },
16848
15309
  async markAsUnread() {
16849
15310
  if (!record.readAt) return;
@@ -16875,7 +15336,7 @@ var DatabaseNotificationChannel = class {
16875
15336
  const model = notifiable;
16876
15337
  if (typeof model.getKey !== "function") throw new NotDatabaseNotifiableError(notifiable.constructor.name);
16877
15338
  const db = requireDatabase();
16878
- const now4 = /* @__PURE__ */ new Date();
15339
+ const now5 = /* @__PURE__ */ new Date();
16879
15340
  await db.table(NOTIFICATIONS_TABLE).insert({
16880
15341
  id: notification.id ?? randomUUID4(),
16881
15342
  type: notification.constructor.name,
@@ -16883,8 +15344,8 @@ var DatabaseNotificationChannel = class {
16883
15344
  notifiable_id: model.getKey(),
16884
15345
  data: JSON.stringify(data),
16885
15346
  read_at: null,
16886
- created_at: now4,
16887
- updated_at: now4
15347
+ created_at: now5,
15348
+ updated_at: now5
16888
15349
  });
16889
15350
  }
16890
15351
  };
@@ -17226,7 +15687,7 @@ import { randomUUID as randomUUID24 } from "crypto";
17226
15687
  import { Redis as Redis2 } from "ioredis";
17227
15688
  import { randomUUID as randomUUID32 } from "crypto";
17228
15689
  import { setTimeout as sleep4 } from "timers/promises";
17229
- import { existsSync as existsSync9, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
15690
+ import { existsSync as existsSync8, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
17230
15691
  import { join as join12 } from "path";
17231
15692
  import { pathToFileURL as pathToFileURL6 } from "url";
17232
15693
  var QueueError = class extends Error {
@@ -17331,7 +15792,7 @@ function resolveClass(registry2, name) {
17331
15792
  if (!registry2.has(name)) throw new JobClassNotFoundError(name);
17332
15793
  return registry2.resolve(name);
17333
15794
  }
17334
- function isPlainObject3(value2) {
15795
+ function isPlainObject2(value2) {
17335
15796
  const proto = Object.getPrototypeOf(value2);
17336
15797
  return proto === Object.prototype || proto === null;
17337
15798
  }
@@ -17385,7 +15846,7 @@ function serializeValue(value2, registry2, path = "data", seen = /* @__PURE__ */
17385
15846
  }
17386
15847
  return { [TAG]: "model", class: name2, key: serializeValue(object.getKey(), registry2, `${path}.key`, seen) ?? null };
17387
15848
  }
17388
- if (isPlainObject3(object)) {
15849
+ if (isPlainObject2(object)) {
17389
15850
  const fields = serializeFields(object, registry2, path, seen);
17390
15851
  return Object.hasOwn(fields, TAG) ? { [TAG]: "object", value: fields } : fields;
17391
15852
  }
@@ -17719,8 +16180,8 @@ var CallQueuedHandler = class {
17719
16180
  const lock = payload.uniqueLock;
17720
16181
  if (!lock || !this.container.bound(CacheManager)) return;
17721
16182
  const cache2 = this.container.make(CacheManager);
17722
- const store2 = lock.store !== void 0 ? cache2.store(lock.store) : cache2;
17723
- await store2.lock(lock.key).forceRelease();
16183
+ const store = lock.store !== void 0 ? cache2.store(lock.store) : cache2;
16184
+ await store.lock(lock.key).forceRelease();
17724
16185
  }
17725
16186
  };
17726
16187
  var WithoutOverlapping = class {
@@ -17957,34 +16418,34 @@ var DatabaseQueue = class extends QueueBase {
17957
16418
  });
17958
16419
  }
17959
16420
  async pushToDatabase(queue, payload, delaySeconds2, attempts, db = this.database()) {
17960
- const now4 = this.currentTime();
16421
+ const now5 = this.currentTime();
17961
16422
  const id = await db.table(this.table).insertGetId({
17962
16423
  queue,
17963
16424
  payload: encodePayload({ ...payload, attempts: 0 }),
17964
16425
  attempts,
17965
16426
  reserved_at: null,
17966
- available_at: now4 + Math.max(0, Math.round(delaySeconds2)),
17967
- created_at: now4
16427
+ available_at: now5 + Math.max(0, Math.round(delaySeconds2)),
16428
+ created_at: now5
17968
16429
  });
17969
16430
  return String(id);
17970
16431
  }
17971
16432
  /** The oldest available row, or the oldest reservation older than retry_after, whichever has the lower id. */
17972
16433
  async getNextAvailableJob(db, queue) {
17973
- const now4 = this.currentTime();
17974
- const available = await db.table(this.table).where("queue", queue).whereNull("reserved_at").where("available_at", "<=", now4).orderBy("id", "asc").lockForUpdate().first();
17975
- const expired = await db.table(this.table).where("queue", queue).whereNotNull("reserved_at").where("reserved_at", "<=", now4 - this.retryAfter).orderBy("id", "asc").lockForUpdate().first();
16434
+ const now5 = this.currentTime();
16435
+ const available = await db.table(this.table).where("queue", queue).whereNull("reserved_at").where("available_at", "<=", now5).orderBy("id", "asc").lockForUpdate().first();
16436
+ const expired = await db.table(this.table).where("queue", queue).whereNotNull("reserved_at").where("reserved_at", "<=", now5 - this.retryAfter).orderBy("id", "asc").lockForUpdate().first();
17976
16437
  if (!available || !expired) return available ?? expired;
17977
16438
  return Number(available.id) <= Number(expired.id) ? available : expired;
17978
16439
  }
17979
16440
  /** Reserves the row only if nobody else changed it since we read it. */
17980
16441
  async markJobAsReserved(db, record) {
17981
- const now4 = this.currentTime();
16442
+ const now5 = this.currentTime();
17982
16443
  const query = db.table(this.table).where("id", record.id).where("attempts", record.attempts);
17983
16444
  if (record.reserved_at === null) query.whereNull("reserved_at");
17984
16445
  else query.where("reserved_at", record.reserved_at);
17985
- const affected = await query.update({ reserved_at: now4, attempts: Number(record.attempts) + 1 });
16446
+ const affected = await query.update({ reserved_at: now5, attempts: Number(record.attempts) + 1 });
17986
16447
  if (affected === 0) return false;
17987
- record.reserved_at = now4;
16448
+ record.reserved_at = now5;
17988
16449
  record.attempts = Number(record.attempts) + 1;
17989
16450
  return true;
17990
16451
  }
@@ -18112,11 +16573,11 @@ var RedisQueue = class extends QueueBase {
18112
16573
  }
18113
16574
  async pop(queue) {
18114
16575
  const key = this.key(queue);
18115
- const now4 = this.now();
18116
- await this.redis().eval(MIGRATE_EXPIRED_JOBS, 3, `${key}:delayed`, key, `${key}:notify`, now4);
18117
- await this.redis().eval(MIGRATE_EXPIRED_JOBS, 3, `${key}:reserved`, key, `${key}:notify`, now4);
16576
+ const now5 = this.now();
16577
+ await this.redis().eval(MIGRATE_EXPIRED_JOBS, 3, `${key}:delayed`, key, `${key}:notify`, now5);
16578
+ await this.redis().eval(MIGRATE_EXPIRED_JOBS, 3, `${key}:reserved`, key, `${key}:notify`, now5);
18118
16579
  for (; ; ) {
18119
- const [job, reserved] = await this.redis().eval(POP, 3, key, `${key}:reserved`, `${key}:notify`, now4 + this.retryAfter);
16580
+ const [job, reserved] = await this.redis().eval(POP, 3, key, `${key}:reserved`, `${key}:notify`, now5 + this.retryAfter);
18120
16581
  if (!job || !reserved) return void 0;
18121
16582
  try {
18122
16583
  return new RedisJob(this.jobContext(), this, job, reserved, this.getQueue(queue));
@@ -18510,8 +16971,8 @@ var DatabaseBatchRepository = class {
18510
16971
  await this.database().table(this.table).where("id", id).update({ finished_at: this.now() });
18511
16972
  }
18512
16973
  async cancel(id) {
18513
- const now4 = this.now();
18514
- await this.database().table(this.table).where("id", id).update({ cancelled_at: now4, finished_at: now4 });
16974
+ const now5 = this.now();
16975
+ await this.database().table(this.table).where("id", id).update({ cancelled_at: now5, finished_at: now5 });
18515
16976
  }
18516
16977
  async delete(id) {
18517
16978
  await this.database().table(this.table).where("id", id).delete();
@@ -18816,13 +17277,13 @@ var Worker = class _Worker {
18816
17277
  }
18817
17278
  }
18818
17279
  };
18819
- var EXTENSIONS3 = [".ts", ".js", ".mts", ".mjs"];
17280
+ var EXTENSIONS2 = [".ts", ".js", ".mts", ".mjs"];
18820
17281
  function files2(directory) {
18821
17282
  const found = [];
18822
17283
  for (const entry of readdirSync6(directory).sort()) {
18823
17284
  const path = join12(directory, entry);
18824
17285
  if (statSync3(path).isDirectory()) found.push(...files2(path));
18825
- else if (EXTENSIONS3.some((extension) => entry.endsWith(extension)) && !entry.endsWith(".d.ts")) found.push(path);
17286
+ else if (EXTENSIONS2.some((extension) => entry.endsWith(extension)) && !entry.endsWith(".d.ts")) found.push(path);
18826
17287
  }
18827
17288
  return found;
18828
17289
  }
@@ -18830,7 +17291,7 @@ var WORKER_DISCOVERY_DIRECTORIES = ["Events", "Listeners", "Mail", "Notification
18830
17291
  var isClass2 = (value2) => typeof value2 === "function" && /^class[\s{]/.test(Function.prototype.toString.call(value2));
18831
17292
  var isJobClass = (value2) => typeof value2.prototype.handle === "function";
18832
17293
  async function discoverClasses(directory, registry2, filter = () => true) {
18833
- if (!existsSync9(directory)) return [];
17294
+ if (!existsSync8(directory)) return [];
18834
17295
  const names = [];
18835
17296
  for (const file of files2(directory)) {
18836
17297
  const module = await import(pathToFileURL6(file).href);
@@ -19041,7 +17502,9 @@ var QueueServiceProvider = class extends ServiceProvider {
19041
17502
  };
19042
17503
 
19043
17504
  // ../Routing/dist/index.js
17505
+ import { createHmac as createHmac4, timingSafeEqual as timingSafeEqual4 } from "crypto";
19044
17506
  import { pathToFileURL as pathToFileURL7 } from "url";
17507
+ import { createHash as createHash8 } from "crypto";
19045
17508
  var NotFoundHttpError = class extends Error {
19046
17509
  kind = "Http";
19047
17510
  status = 404;
@@ -19095,6 +17558,24 @@ var RoutingError = class extends Error {
19095
17558
  status = 500;
19096
17559
  name = "RoutingError";
19097
17560
  };
17561
+ var InvalidUrlSignatureError = class extends Error {
17562
+ kind = "Http";
17563
+ status = 403;
17564
+ name = "InvalidUrlSignatureError";
17565
+ constructor() {
17566
+ super("Invalid signature.");
17567
+ }
17568
+ };
17569
+ var ThrottleRequestsError = class extends Error {
17570
+ constructor(headers = {}) {
17571
+ super("Too Many Attempts.");
17572
+ this.headers = headers;
17573
+ }
17574
+ headers;
17575
+ kind = "Http";
17576
+ status = 429;
17577
+ name = "ThrottleRequestsError";
17578
+ };
19098
17579
  async function toResponse(request2, value2) {
19099
17580
  if (value2 instanceof Response) return value2;
19100
17581
  if (value2 === null || value2 === void 0) return new Response(null, { status: 204 });
@@ -19339,6 +17820,7 @@ var RouteDefinition = class {
19339
17820
  this.#name = (this.#name ?? "") + name;
19340
17821
  return this;
19341
17822
  }
17823
+ /** middleware('auth', 'verified') or middleware(['auth', 'verified']). */
19342
17824
  middleware(...middleware) {
19343
17825
  this.#middleware.push(...middleware.flat());
19344
17826
  return this;
@@ -19796,7 +18278,7 @@ var BaseRouter = class {
19796
18278
  }
19797
18279
  };
19798
18280
  var VALID_URL = /^(#|\/\/|https?:\/\/|(mailto|tel|sms):)/i;
19799
- var isPlainObject4 = (value2) => {
18281
+ var isPlainObject3 = (value2) => {
19800
18282
  if (typeof value2 !== "object" || value2 === null || Array.isArray(value2)) return false;
19801
18283
  const prototype = Object.getPrototypeOf(value2);
19802
18284
  return prototype === Object.prototype || prototype === null;
@@ -19805,7 +18287,7 @@ function buildQuery2(values) {
19805
18287
  const pairs = [];
19806
18288
  const add = (key, value2) => {
19807
18289
  if (value2 === null || value2 === void 0) return;
19808
- if (typeof value2 === "object" && (Array.isArray(value2) || isPlainObject4(value2))) {
18290
+ if (typeof value2 === "object" && (Array.isArray(value2) || isPlainObject3(value2))) {
19809
18291
  for (const [child, nested] of Object.entries(value2)) add(`${key}[${child}]`, nested);
19810
18292
  return;
19811
18293
  }
@@ -19821,6 +18303,17 @@ function routeKey(value2, field) {
19821
18303
  if (field !== void 0) return typeof model.getAttribute === "function" ? model.getAttribute(field) : model[field];
19822
18304
  return typeof model.getRouteKey === "function" ? model.getRouteKey() : value2;
19823
18305
  }
18306
+ function sign(url2, key) {
18307
+ return createHmac4("sha256", key).update(url2).digest("hex");
18308
+ }
18309
+ function safeEquals(expected, given) {
18310
+ const a = Buffer.from(expected);
18311
+ const b = Buffer.from(given);
18312
+ return a.length === b.length && timingSafeEqual4(a, b);
18313
+ }
18314
+ function availableAt(expiration) {
18315
+ return expiration instanceof Date ? Math.floor(expiration.getTime() / 1e3) : Math.floor(Date.now() / 1e3) + expiration;
18316
+ }
19824
18317
  var BaseUrlGenerator = class {
19825
18318
  constructor(router, container) {
19826
18319
  this.router = router;
@@ -19849,8 +18342,8 @@ var BaseUrlGenerator = class {
19849
18342
  route(name, parameters, absolute = true) {
19850
18343
  const route2 = this.router.getByName(name);
19851
18344
  if (route2 === void 0) throw new RouteNotDefinedError(name);
19852
- const named = isPlainObject4(parameters) ? { ...parameters } : {};
19853
- const positional = Array.isArray(parameters) ? [...parameters] : parameters === void 0 || parameters === null || isPlainObject4(parameters) ? [] : [parameters];
18345
+ const named = isPlainObject3(parameters) ? { ...parameters } : {};
18346
+ const positional = Array.isArray(parameters) ? [...parameters] : parameters === void 0 || parameters === null || isPlainObject3(parameters) ? [] : [parameters];
19854
18347
  const values = /* @__PURE__ */ new Map();
19855
18348
  const missing = [];
19856
18349
  for (const parameter of route2.parameters) {
@@ -19908,6 +18401,69 @@ var BaseUrlGenerator = class {
19908
18401
  hasRoute(name) {
19909
18402
  return this.router.getByName(name) !== void 0;
19910
18403
  }
18404
+ /**
18405
+ * Laravel's URL::signedRoute(): the route URL with its parameters sorted by name, then a `signature` query (the
18406
+ * HMAC-SHA256 of that URL, keyed by APP_KEY). `expiration` (a Date, or seconds from now) adds `expires`.
18407
+ * `absolute: false` signs the path only (checked by `signed:relative`).
18408
+ */
18409
+ signedRoute(name, parameters, expiration, absolute = true) {
18410
+ const named = this.#namedParameters(name, parameters);
18411
+ for (const reserved of ["signature", "expires"]) {
18412
+ if (Object.hasOwn(named, reserved)) {
18413
+ throw new RoutingError(`"${reserved}" is a reserved parameter when generating signed routes. Please rename your route parameter.`);
18414
+ }
18415
+ }
18416
+ if (expiration !== void 0) named.expires = availableAt(expiration);
18417
+ const sorted = Object.fromEntries(Object.keys(named).sort().map((key) => [key, named[key]]));
18418
+ const signature = sign(this.route(name, sorted, absolute), this.#signingKeys()[0]);
18419
+ return this.route(name, { ...sorted, signature }, absolute);
18420
+ }
18421
+ /** Laravel's URL::temporarySignedRoute(): a signed URL that expires at `expiration` (a Date, or seconds from now). */
18422
+ temporarySignedRoute(name, expiration, parameters, absolute = true) {
18423
+ return this.signedRoute(name, parameters, expiration, absolute);
18424
+ }
18425
+ /** The request URL carries a correct signature (current or previous APP_KEY) that hasn't expired. */
18426
+ hasValidSignature(request2, absolute = true) {
18427
+ return this.hasCorrectSignature(request2, absolute) && this.signatureHasNotExpired(request2);
18428
+ }
18429
+ /** The signature matches the URL without its `signature` query, in a constant-time comparison. */
18430
+ hasCorrectSignature(request2, absolute = true) {
18431
+ const full = new URL(request2.fullUrl());
18432
+ const path = request2.path();
18433
+ const url2 = absolute ? request2.url() : path === "/" ? "/" : `/${path}`;
18434
+ const query = full.search.slice(1).split("&").filter((pair) => pair !== "" && pair.split("=")[0] !== "signature").join("&");
18435
+ const original = query === "" ? url2 : `${url2}?${query}`;
18436
+ const given = full.searchParams.get("signature") ?? "";
18437
+ return this.#signingKeys().some((key) => safeEquals(sign(original, key), given));
18438
+ }
18439
+ /** No `expires` query, or one that is still in the future. */
18440
+ signatureHasNotExpired(request2) {
18441
+ const expires = new URL(request2.fullUrl()).searchParams.get("expires");
18442
+ if (expires === null || expires === "") return true;
18443
+ const at = Number(expires);
18444
+ return Number.isFinite(at) && Math.floor(Date.now() / 1e3) <= at;
18445
+ }
18446
+ /** Named parameters: an object as is, positional values (a list or one value) by the route's parameter names. */
18447
+ #namedParameters(name, parameters) {
18448
+ if (isPlainObject3(parameters)) return { ...parameters };
18449
+ const route2 = this.router.getByName(name);
18450
+ if (route2 === void 0) throw new RouteNotDefinedError(name);
18451
+ const values = parameters === void 0 || parameters === null ? [] : Array.isArray(parameters) ? parameters : [parameters];
18452
+ const named = {};
18453
+ route2.parameters.forEach((parameter, index) => {
18454
+ if (index < values.length) named[parameter.name] = values[index];
18455
+ });
18456
+ return named;
18457
+ }
18458
+ /** The Encrypter's key, then its previous keys (config app.previous_keys), so rotated keys still verify. */
18459
+ #signingKeys() {
18460
+ const scope = this.#scope();
18461
+ if (scope === void 0 || !scope.bound(Encrypter)) {
18462
+ throw new RoutingError("Signed URLs need the Encrypter: set APP_KEY (oriel key:generate).");
18463
+ }
18464
+ const encrypter = scope.make(Encrypter);
18465
+ return typeof encrypter.getAllKeys === "function" ? encrypter.getAllKeys() : [encrypter.getKey()];
18466
+ }
19911
18467
  #join(path, absolute) {
19912
18468
  const trimmed = path.replace(/^\/+|\/+$/g, "");
19913
18469
  if (!absolute) return `/${trimmed}`;
@@ -19940,6 +18496,60 @@ function healthResponse() {
19940
18496
  const html2 = '<!DOCTYPE html>\n<html lang="en">\n<head>\n<meta charset="utf-8">\n<title>Application up</title>\n</head>\n<body><h1>Application up</h1></body>\n</html>';
19941
18497
  return new Response(html2, { status: 200, headers: { "content-type": "text/html; charset=utf-8" } });
19942
18498
  }
18499
+ var sha12 = (value2) => createHash8("sha1").update(value2).digest("hex");
18500
+ function withHeaders2(response2, headers) {
18501
+ try {
18502
+ for (const [name, value2] of Object.entries(headers)) response2.headers.set(name, value2);
18503
+ return response2;
18504
+ } catch {
18505
+ const copy = new Headers(response2.headers);
18506
+ for (const [name, value2] of Object.entries(headers)) copy.set(name, value2);
18507
+ return new Response(response2.body, { status: response2.status, statusText: response2.statusText, headers: copy });
18508
+ }
18509
+ }
18510
+ var ThrottleRequests = class {
18511
+ async handle(request2, next, maxAttempts = "60", decayMinutes = "1", prefix = "") {
18512
+ const max = Number(maxAttempts);
18513
+ const decay = Number(decayMinutes);
18514
+ if (maxAttempts.trim() === "" || !Number.isInteger(max) || max < 0 || decayMinutes.trim() === "" || !Number.isFinite(decay) || decay <= 0) {
18515
+ throw new RoutingError(
18516
+ `Invalid throttle parameters "${maxAttempts},${decayMinutes}": use throttle:<maxAttempts>,<decayMinutes>[,<prefix>] (named rate limiters are not supported).`
18517
+ );
18518
+ }
18519
+ const limiter = inject(RateLimiter);
18520
+ const key = prefix + this.resolveRequestSignature(request2);
18521
+ if (await limiter.tooManyAttempts(key, max)) {
18522
+ const retryAfter = await limiter.availableIn(key);
18523
+ throw new ThrottleRequestsError({
18524
+ "X-RateLimit-Limit": String(max),
18525
+ "X-RateLimit-Remaining": "0",
18526
+ "Retry-After": String(retryAfter),
18527
+ "X-RateLimit-Reset": String(Math.floor(Date.now() / 1e3) + retryAfter)
18528
+ });
18529
+ }
18530
+ await limiter.hit(key, Math.round(decay * 60));
18531
+ const response2 = await next(request2);
18532
+ return withHeaders2(response2, {
18533
+ "X-RateLimit-Limit": String(max),
18534
+ "X-RateLimit-Remaining": String(await limiter.remaining(key, max))
18535
+ });
18536
+ }
18537
+ /** The signed-in user's identifier, else the client IP, hashed (Laravel's resolveRequestSignature()). */
18538
+ resolveRequestSignature(request2) {
18539
+ const user = request2.user();
18540
+ if (user !== void 0 && user !== null && typeof user.getAuthIdentifier === "function") {
18541
+ return sha12(String(user.getAuthIdentifier()));
18542
+ }
18543
+ return sha12(`|${request2.ip() ?? ""}`);
18544
+ }
18545
+ };
18546
+ var ValidateSignature = class {
18547
+ async handle(request2, next, ...parameters) {
18548
+ const absolute = parameters[0] !== "relative";
18549
+ if (inject(UrlGenerator).hasValidSignature(request2, absolute)) return next(request2);
18550
+ throw new InvalidUrlSignatureError();
18551
+ }
18552
+ };
19943
18553
  var RoutingServiceProvider = class extends ServiceProvider {
19944
18554
  register() {
19945
18555
  this.app.singleton(Router, () => new BaseRouter(this.app));
@@ -19957,23 +18567,28 @@ var RoutingServiceProvider = class extends ServiceProvider {
19957
18567
  * when the route files run.
19958
18568
  */
19959
18569
  boot() {
18570
+ this.app.make(Router).aliasMiddleware("signed", ValidateSignature).aliasMiddleware("throttle", ThrottleRequests);
19960
18571
  this.app.booted(async () => {
19961
18572
  if (!this.app.bound(RoutingPaths)) return;
19962
18573
  const { web, api, health, apiPrefix } = this.app.make(RoutingPaths);
19963
18574
  const router = this.app.make(Router);
19964
18575
  if (health !== void 0) router.get(health, () => healthResponse());
19965
- if (web !== void 0) await router.middleware("web").group(() => loadRoutesFrom(this.app, router, web));
19966
- if (api !== void 0) await router.prefix(apiPrefix).middleware("api").group(() => loadRoutesFrom(this.app, router, api));
18576
+ if (web !== void 0) await router.middleware("web").group(() => this.#load(router, web));
18577
+ if (api !== void 0) await router.prefix(apiPrefix).middleware("api").group(() => this.#load(router, api));
19967
18578
  });
19968
18579
  }
18580
+ /** One file or several, in order: each is imported afresh for this application (a nested import is not). */
18581
+ async #load(router, files3) {
18582
+ for (const file of [files3].flat()) await loadRoutesFrom(this.app, router, file);
18583
+ }
19969
18584
  };
19970
18585
 
19971
18586
  // ../Session/dist/index.js
19972
- import { mkdir as mkdir7, readdir as readdir3, readFile as readFile5, rename as rename3, rm as rm3, stat as stat4, writeFile as writeFile8 } from "fs/promises";
18587
+ import { mkdir as mkdir6, readdir as readdir3, readFile as readFile4, rename as rename3, rm as rm3, stat as stat3, writeFile as writeFile7 } from "fs/promises";
19973
18588
  import { join as join13 } from "path";
19974
18589
  import { Redis as Redis3 } from "ioredis";
19975
18590
  import { randomInt } from "crypto";
19976
- import { timingSafeEqual as timingSafeEqual4 } from "crypto";
18591
+ import { timingSafeEqual as timingSafeEqual5 } from "crypto";
19977
18592
  var unique = (values) => [...new Set(values)];
19978
18593
  var Store = class {
19979
18594
  #id = "";
@@ -20212,18 +18827,18 @@ var FileSessionHandler = class {
20212
18827
  if (!VALID_ID.test(id)) return "";
20213
18828
  const file = join13(this.path, id);
20214
18829
  try {
20215
- const { mtimeMs } = await stat4(file);
18830
+ const { mtimeMs } = await stat3(file);
20216
18831
  if (mtimeMs < this.clock() - this.minutes * 6e4) return "";
20217
- return await readFile5(file, "utf8");
18832
+ return await readFile4(file, "utf8");
20218
18833
  } catch {
20219
18834
  return "";
20220
18835
  }
20221
18836
  }
20222
18837
  async write(id, data) {
20223
18838
  if (!VALID_ID.test(id)) return;
20224
- await mkdir7(this.path, { recursive: true });
18839
+ await mkdir6(this.path, { recursive: true });
20225
18840
  const temporary = join13(this.path, `.${id}.${Str.random(8)}.tmp`);
20226
- await writeFile8(temporary, data, "utf8");
18841
+ await writeFile7(temporary, data, "utf8");
20227
18842
  await rename3(temporary, join13(this.path, id));
20228
18843
  }
20229
18844
  async destroy(id) {
@@ -20234,7 +18849,7 @@ var FileSessionHandler = class {
20234
18849
  const files3 = await readdir3(this.path).catch(() => []);
20235
18850
  for (const file of files3) {
20236
18851
  if (!VALID_ID.test(file)) continue;
20237
- const { mtimeMs } = await stat4(join13(this.path, file)).catch(() => ({ mtimeMs: Number.POSITIVE_INFINITY }));
18852
+ const { mtimeMs } = await stat3(join13(this.path, file)).catch(() => ({ mtimeMs: Number.POSITIVE_INFINITY }));
20238
18853
  if (mtimeMs <= expiration) await rm3(join13(this.path, file), { force: true });
20239
18854
  }
20240
18855
  }
@@ -20542,7 +19157,7 @@ var StartSession = class {
20542
19157
  function equals3(known, user) {
20543
19158
  const a = Buffer.from(known);
20544
19159
  const b = Buffer.from(user);
20545
- return a.length === b.length && timingSafeEqual4(a, b);
19160
+ return a.length === b.length && timingSafeEqual5(a, b);
20546
19161
  }
20547
19162
  var VerifyCsrfToken = class {
20548
19163
  /** URIs (wildcards allowed) excluded from the check, in addition to config('http.csrf_except'). */
@@ -20644,15 +19259,15 @@ var SessionFacade = facade(Session, {
20644
19259
  extend: (driver, factory) => inject(SessionManager).extend(driver, factory)
20645
19260
  });
20646
19261
  function session(key, defaultValue) {
20647
- const store2 = inject(Session);
20648
- if (key === void 0) return store2;
20649
- if (typeof key === "string") return store2.get(key, defaultValue);
20650
- store2.put(key);
19262
+ const store = inject(Session);
19263
+ if (key === void 0) return store;
19264
+ if (typeof key === "string") return store.get(key, defaultValue);
19265
+ store.put(key);
20651
19266
  return void 0;
20652
19267
  }
20653
19268
  function old(key, defaultValue) {
20654
- const store2 = scopeSession();
20655
- return store2 === void 0 ? defaultValue : store2.getOldInput(key, defaultValue);
19269
+ const store = scopeSession();
19270
+ return store === void 0 ? defaultValue : store.getOldInput(key, defaultValue);
20656
19271
  }
20657
19272
  function csrfToken() {
20658
19273
  return inject(Session).token();
@@ -20705,6 +19320,23 @@ var ValidationErrorImpl = class extends Error {
20705
19320
  status = 422;
20706
19321
  name = "ValidationError";
20707
19322
  };
19323
+ var ValidationException = class _ValidationException extends ValidationErrorImpl {
19324
+ /** Messages per field, each a string or a list. */
19325
+ static withMessages(messages) {
19326
+ const errors2 = Object.fromEntries(Object.entries(messages).map(([field, list3]) => [field, typeof list3 === "string" ? [list3] : [...list3]]));
19327
+ return new _ValidationException(errors2);
19328
+ }
19329
+ constructor(errors2, errorBag = "default", redirectTo2) {
19330
+ super(errors2, errorBag, redirectTo2);
19331
+ this.message = summarize(errors2);
19332
+ }
19333
+ };
19334
+ function summarize(errors2) {
19335
+ const messages = Object.values(errors2).flat();
19336
+ if (messages.length === 0) return "The given data was invalid.";
19337
+ const more = messages.length - 1;
19338
+ return more === 0 ? messages[0] : `${messages[0]} (and ${more} more ${more === 1 ? "error" : "errors"})`;
19339
+ }
20708
19340
  var AuthorizationErrorImpl = class extends Error {
20709
19341
  kind = "Authorization";
20710
19342
  status = 403;
@@ -20780,6 +19412,13 @@ var DEFAULT_MESSAGES = {
20780
19412
  alpha_num: "The :attribute field must only contain letters and numbers.",
20781
19413
  alpha_dash: "The :attribute field must only contain letters, numbers, dashes and underscores.",
20782
19414
  regex: "The :attribute field format is invalid.",
19415
+ lowercase: "The :attribute field must be lowercase.",
19416
+ uppercase: "The :attribute field must be uppercase.",
19417
+ current_password: "The password is incorrect.",
19418
+ "password.letters": "The :attribute field must contain at least one letter.",
19419
+ "password.mixed": "The :attribute field must contain at least one uppercase and one lowercase letter.",
19420
+ "password.numbers": "The :attribute field must contain at least one number.",
19421
+ "password.symbols": "The :attribute field must contain at least one symbol.",
20783
19422
  confirmed: "The :attribute field confirmation does not match.",
20784
19423
  same: "The :attribute field must match :other.",
20785
19424
  different: "The :attribute field must be different from :other.",
@@ -20845,6 +19484,17 @@ var MessageBagImpl = class {
20845
19484
  return structuredClone(this.items);
20846
19485
  }
20847
19486
  };
19487
+ var authRules = {
19488
+ current_password: {
19489
+ validate: async (ctx) => {
19490
+ const guard2 = inject(AuthFactory).guard(ctx.parameters[0]);
19491
+ if (await guard2.guest()) return false;
19492
+ const user = await guard2.user();
19493
+ return user !== void 0 && typeof ctx.value === "string" && inject(Hasher).check(ctx.value, user.getAuthPassword());
19494
+ },
19495
+ messageKey: () => "current_password"
19496
+ }
19497
+ };
20848
19498
  function guessColumn(attribute, expandedFromWildcard = false) {
20849
19499
  if (!expandedFromWildcard) return attribute;
20850
19500
  return attribute.split(".").filter((segment) => !/^\d+$/.test(segment)).at(-1) ?? attribute;
@@ -21027,8 +19677,8 @@ function resolveDateParam(rule, param, data) {
21027
19677
  const parsed = parseDate(fieldValue);
21028
19678
  if (!Number.isNaN(parsed)) return parsed;
21029
19679
  }
21030
- const relative7 = relativeDate(param);
21031
- if (relative7 !== void 0) return relative7;
19680
+ const relative6 = relativeDate(param);
19681
+ if (relative6 !== void 0) return relative6;
21032
19682
  const literal = parseDate(param);
21033
19683
  if (!Number.isNaN(literal)) return literal;
21034
19684
  if (FIELD_REFERENCE_RE.test(param)) return Number.NaN;
@@ -21065,6 +19715,14 @@ var formatRules = {
21065
19715
  validate: (ctx) => typeof ctx.value === "string" && ALPHA_DASH_RE.test(ctx.value),
21066
19716
  messageKey: () => "alpha_dash"
21067
19717
  },
19718
+ lowercase: {
19719
+ validate: (ctx) => (typeof ctx.value === "string" || typeof ctx.value === "number") && String(ctx.value).toLowerCase() === String(ctx.value),
19720
+ messageKey: () => "lowercase"
19721
+ },
19722
+ uppercase: {
19723
+ validate: (ctx) => (typeof ctx.value === "string" || typeof ctx.value === "number") && String(ctx.value).toUpperCase() === String(ctx.value),
19724
+ messageKey: () => "uppercase"
19725
+ },
21068
19726
  regex: {
21069
19727
  validate: (ctx) => typeof ctx.value === "string" && compileRegex(ctx.parameters[0] ?? "").test(ctx.value),
21070
19728
  messageKey: () => "regex"
@@ -21186,7 +19844,7 @@ var typeRules = {
21186
19844
  function hasAny(ctx, names) {
21187
19845
  return names.some((name) => ctx.ruleNames.includes(name));
21188
19846
  }
21189
- function isPlainObject5(value2) {
19847
+ function isPlainObject4(value2) {
21190
19848
  if (typeof value2 !== "object" || value2 === null) return false;
21191
19849
  const proto = Object.getPrototypeOf(value2);
21192
19850
  return proto === Object.prototype || proto === null;
@@ -21199,7 +19857,7 @@ function measure(ctx) {
21199
19857
  if (Array.isArray(value2)) return { type: "array", size: value2.length };
21200
19858
  if (isUploadedFileLike(value2)) return { type: "file", size: value2.size / 1024 };
21201
19859
  if (hasAny(ctx, ["file", "image"])) return { type: "file", size: Number.NaN };
21202
- if (isPlainObject5(value2)) return { type: "array", size: Object.keys(value2).length };
19860
+ if (isPlainObject4(value2)) return { type: "array", size: Object.keys(value2).length };
21203
19861
  if (hasAny(ctx, ["array"])) return { type: "array", size: stringLength(value2) };
21204
19862
  return { type: "string", size: stringLength(value2) };
21205
19863
  }
@@ -21246,7 +19904,81 @@ var builtinRules = {
21246
19904
  ...formatRules,
21247
19905
  ...sizeRules,
21248
19906
  ...fileRules,
21249
- ...databaseRules
19907
+ ...databaseRules,
19908
+ ...authRules
19909
+ };
19910
+ var defaultRule;
19911
+ var PasswordRule = class _PasswordRule {
19912
+ #min;
19913
+ #max;
19914
+ #letters = false;
19915
+ #mixedCase = false;
19916
+ #numbers = false;
19917
+ #symbols = false;
19918
+ constructor(min = 8) {
19919
+ this.#min = Math.max(1, min);
19920
+ }
19921
+ /** A password rule of at least `size` characters: PasswordRule.min(12).mixedCase(). */
19922
+ static min(size) {
19923
+ return new _PasswordRule(size);
19924
+ }
19925
+ static defaults(rule) {
19926
+ if (rule !== void 0) {
19927
+ defaultRule = rule ?? void 0;
19928
+ return;
19929
+ }
19930
+ const resolved = typeof defaultRule === "function" ? defaultRule() : defaultRule;
19931
+ return resolved === void 0 ? new _PasswordRule(8) : resolved.#copy();
19932
+ }
19933
+ min(size) {
19934
+ this.#min = Math.max(1, size);
19935
+ return this;
19936
+ }
19937
+ max(size) {
19938
+ this.#max = size;
19939
+ return this;
19940
+ }
19941
+ /** At least one letter. */
19942
+ letters() {
19943
+ this.#letters = true;
19944
+ return this;
19945
+ }
19946
+ /** At least one uppercase and one lowercase letter. */
19947
+ mixedCase() {
19948
+ this.#mixedCase = true;
19949
+ return this;
19950
+ }
19951
+ /** At least one number. */
19952
+ numbers() {
19953
+ this.#numbers = true;
19954
+ return this;
19955
+ }
19956
+ /** At least one symbol (punctuation, a symbol or a space). */
19957
+ symbols() {
19958
+ this.#symbols = true;
19959
+ return this;
19960
+ }
19961
+ validate(attribute, value2, fail) {
19962
+ const name = defaultAttributeName(attribute);
19963
+ const say = (key, replacements = {}) => fail(applyReplacements(DEFAULT_MESSAGES[key], { attribute: name, ...replacements }));
19964
+ if (typeof value2 !== "string") return say("string");
19965
+ const length = [...value2].length;
19966
+ if (length < this.#min) say("min.string", { min: String(this.#min) });
19967
+ if (this.#max !== void 0 && length > this.#max) say("max.string", { max: String(this.#max) });
19968
+ if (this.#mixedCase && !/(\p{Ll}+.*\p{Lu})|(\p{Lu}+.*\p{Ll})/u.test(value2)) say("password.mixed");
19969
+ if (this.#letters && !/\p{L}/u.test(value2)) say("password.letters");
19970
+ if (this.#symbols && !/\p{Z}|\p{S}|\p{P}/u.test(value2)) say("password.symbols");
19971
+ if (this.#numbers && !/\p{N}/u.test(value2)) say("password.numbers");
19972
+ }
19973
+ #copy() {
19974
+ const copy = new _PasswordRule(this.#min);
19975
+ copy.#max = this.#max;
19976
+ copy.#letters = this.#letters;
19977
+ copy.#mixedCase = this.#mixedCase;
19978
+ copy.#numbers = this.#numbers;
19979
+ copy.#symbols = this.#symbols;
19980
+ return copy;
19981
+ }
21250
19982
  };
21251
19983
  var BuiltinRuleObject = class {
21252
19984
  // Declares all 4 contract parameters so a subclass's inferred type (from `Rule.in(...)` etc.) still accepts a
@@ -21319,7 +20051,9 @@ var ExistsRule = class extends BuiltinRuleObject {
21319
20051
  var Rule = {
21320
20052
  in: (values) => new InRule(values),
21321
20053
  unique: (table, column) => new UniqueRule(table, column),
21322
- exists: (table, column) => new ExistsRule(table, column)
20054
+ exists: (table, column) => new ExistsRule(table, column),
20055
+ /** Laravel's Password::defaults(): the application's password rule (at least 8 characters unless PasswordRule.defaults() changed it). */
20056
+ password: () => PasswordRule.defaults()
21323
20057
  };
21324
20058
  var SKIPPED_MODIFIERS = /* @__PURE__ */ new Set(["bail", "nullable", "sometimes"]);
21325
20059
  function buildNested(flat) {
@@ -21434,9 +20168,9 @@ var ValidatorImpl = class {
21434
20168
  const implicit = rule.kind === "named" && (this.registry[rule.name]?.implicit ?? false);
21435
20169
  if (!implicit && (!present2 || isBlank2)) continue;
21436
20170
  if (!implicit && nullable && isNull) continue;
21437
- const message = await this.runRule(rule, field, pattern, value2, names);
21438
- if (message !== void 0) {
21439
- this.bag.add(field, message);
20171
+ const messages = await this.runRule(rule, field, pattern, value2, names);
20172
+ if (messages.length > 0) {
20173
+ for (const message of messages) this.bag.add(field, message);
21440
20174
  if (bail || implicit) break;
21441
20175
  }
21442
20176
  }
@@ -21449,26 +20183,24 @@ var ValidatorImpl = class {
21449
20183
  const expanded = pattern.includes("*");
21450
20184
  if (rule.kind === "object") {
21451
20185
  if (rule.rule instanceof BuiltinRuleObject) {
21452
- if (await rule.rule.passes(field, value2, this.data, expanded)) return void 0;
20186
+ if (await rule.rule.passes(field, value2, this.data, expanded)) return [];
21453
20187
  const ctx2 = { attribute: field, expandedFromWildcard: expanded, value: value2, parameters: [], data: this.data, ruleNames };
21454
- return this.failureMessage(rule.rule.ruleName, this.registry[rule.rule.ruleName], ctx2, pattern);
20188
+ return [this.failureMessage(rule.rule.ruleName, this.registry[rule.rule.ruleName], ctx2, pattern)];
21455
20189
  }
21456
- let failure;
21457
- await rule.rule.validate(field, value2, (message) => {
21458
- failure = message;
21459
- }, this.data);
21460
- return failure;
20190
+ const failures = [];
20191
+ await rule.rule.validate(field, value2, (message) => void failures.push(message), this.data);
20192
+ return failures;
21461
20193
  }
21462
20194
  const builtin = this.registry[rule.name];
21463
20195
  if (!builtin) throw new UnknownValidationRuleError(rule.name);
21464
20196
  const ctx = { attribute: field, expandedFromWildcard: expanded, value: value2, parameters: rule.parameters, data: this.data, ruleNames };
21465
- if (await builtin.validate(ctx)) return void 0;
21466
- return this.failureMessage(rule.name, builtin, ctx, pattern);
20197
+ if (await builtin.validate(ctx)) return [];
20198
+ return [this.failureMessage(rule.name, builtin, ctx, pattern)];
21467
20199
  }
21468
20200
  /** Custom message (concrete field, then wildcard pattern, then rule name) or the default, with :attribute filled. */
21469
20201
  failureMessage(name, builtin, ctx, pattern) {
21470
20202
  const field = ctx.attribute;
21471
- const template = this.customMessages[`${field}.${name}`] ?? this.customMessages[`${pattern}.${name}`] ?? this.customMessages[name] ?? DEFAULT_MESSAGES[builtin?.messageKey(ctx) ?? name] ?? builtin?.defaultMessage ?? "The :attribute field is invalid.";
20203
+ const template = this.customMessages[`${field}.${name}`] ?? this.customMessages[`${pattern}.${name}`] ?? this.customMessages[name] ?? builtin?.message ?? DEFAULT_MESSAGES[builtin?.messageKey(ctx) ?? name] ?? builtin?.defaultMessage ?? "The :attribute field is invalid.";
21472
20204
  const display = this.customAttributes[field] ?? this.customAttributes[pattern] ?? defaultAttributeName(field);
21473
20205
  return applyReplacements(template, { attribute: display, ...builtin?.replacements?.(ctx) ?? {} });
21474
20206
  }
@@ -21482,6 +20214,7 @@ var ValidationFactoryImpl = class {
21482
20214
  this.extended[name] = {
21483
20215
  validate: (ctx) => callback(ctx.attribute, ctx.value, ctx.parameters, ctx.data),
21484
20216
  messageKey: () => name,
20217
+ ...message === void 0 ? {} : { message },
21485
20218
  defaultMessage: message ?? "The :attribute field is invalid."
21486
20219
  };
21487
20220
  }
@@ -21593,6 +20326,7 @@ export {
21593
20326
  CHAIN,
21594
20327
  Cache,
21595
20328
  CacheManager2 as CacheManager,
20329
+ CacheRateLimiter,
21596
20330
  Repository2 as CacheRepositoryImpl,
21597
20331
  CacheServiceProvider,
21598
20332
  CallQueuedHandler,
@@ -21609,7 +20343,7 @@ export {
21609
20343
  ComponentNotFoundError,
21610
20344
  Computed,
21611
20345
  Connection,
21612
- Kernel as ConsoleKernelImpl,
20346
+ Kernel2 as ConsoleKernelImpl,
21613
20347
  ConsoleServiceProvider,
21614
20348
  Container2 as Container,
21615
20349
  ContainerNotAvailableError,
@@ -21646,6 +20380,7 @@ export {
21646
20380
  Dispatchable,
21647
20381
  ELEMENT,
21648
20382
  EloquentUserProvider,
20383
+ EmailVerificationRequest,
21649
20384
  EncryptCookies,
21650
20385
  EncryptError,
21651
20386
  EncryptHistory,
@@ -21695,7 +20430,7 @@ export {
21695
20430
  HelpCommand,
21696
20431
  HtmlString,
21697
20432
  HttpException,
21698
- Kernel2 as HttpKernelImpl,
20433
+ Kernel as HttpKernelImpl,
21699
20434
  HttpRedirectResponse,
21700
20435
  HttpRedirector,
21701
20436
  HttpResponseException,
@@ -21709,7 +20444,7 @@ export {
21709
20444
  InertiaHtml,
21710
20445
  InertiaMiddleware,
21711
20446
  Response2 as InertiaPageResponse,
21712
- ResponseFactory2 as InertiaResponseFactory,
20447
+ ResponseFactory as InertiaResponseFactory,
21713
20448
  InertiaServiceProvider,
21714
20449
  InvalidCacheConfigError,
21715
20450
  InvalidCastError,
@@ -21718,6 +20453,7 @@ export {
21718
20453
  InvalidLogLevelError,
21719
20454
  InvalidRuleParameterError,
21720
20455
  InvalidSignatureError,
20456
+ InvalidUrlSignatureError,
21721
20457
  InvalidViewError,
21722
20458
  JOBS_TABLE_MIGRATION,
21723
20459
  JobClassNotFoundError,
@@ -21736,6 +20472,7 @@ export {
21736
20472
  LocalFilesystem,
21737
20473
  LockTimeoutError,
21738
20474
  Locked,
20475
+ Lockout,
21739
20476
  Log,
21740
20477
  LogChannelCycleError,
21741
20478
  LogManager2 as LogManager,
@@ -21820,12 +20557,14 @@ export {
21820
20557
  On,
21821
20558
  OnceProp,
21822
20559
  OptionalProp,
20560
+ PERSISTENT_MIDDLEWARE,
21823
20561
  PERSONAL_ACCESS_TOKENS_MIGRATION,
21824
20562
  Paginator,
21825
20563
  Password,
21826
20564
  PasswordBroker2 as PasswordBroker,
21827
20565
  PasswordBrokerManager,
21828
20566
  PasswordReset,
20567
+ PasswordRule,
21829
20568
  PathTraversalError,
21830
20569
  PendingBatch,
21831
20570
  PendingChain,
@@ -21854,6 +20593,7 @@ export {
21854
20593
  QueuedConsoleInput,
21855
20594
  QueuedMailSender,
21856
20595
  RESTART_CACHE_KEY,
20596
+ RateLimiter2 as RateLimiter,
21857
20597
  RedirectIfAuthenticated,
21858
20598
  RedisJob,
21859
20599
  RedisLock,
@@ -21862,6 +20602,7 @@ export {
21862
20602
  RedisSessionHandler,
21863
20603
  RedisStore,
21864
20604
  RedisTaggedStore,
20605
+ Registered,
21865
20606
  Relation,
21866
20607
  RelationNotFoundError,
21867
20608
  RelationNotLoadedError,
@@ -21891,6 +20632,7 @@ export {
21891
20632
  SchemaGrammar,
21892
20633
  ScrollProp,
21893
20634
  Seeder,
20635
+ SendEmailVerificationNotification,
21894
20636
  SendQueuedMailable,
21895
20637
  SendQueuedNotifications,
21896
20638
  ServiceProvider,
@@ -21913,7 +20655,10 @@ export {
21913
20655
  SyncQueue,
21914
20656
  TagsNotSupportedError,
21915
20657
  TestCommand,
20658
+ TestRequestScope,
21916
20659
  Testable,
20660
+ ThrottleRequests,
20661
+ ThrottleRequestsError,
21917
20662
  TimeoutExceededError,
21918
20663
  TinkerCommand,
21919
20664
  TokenGuard,
@@ -21944,13 +20689,17 @@ export {
21944
20689
  UnsupportedCipherError,
21945
20690
  UnsupportedOperationError,
21946
20691
  UrlGenerationError,
20692
+ ValidateSignature,
21947
20693
  Validated,
21948
20694
  ValidationErrorImpl,
20695
+ ValidationException,
21949
20696
  ValidationFactoryImpl,
21950
20697
  ValidationServiceProvider,
21951
20698
  Validator,
21952
20699
  ValidatorImpl,
20700
+ Verified,
21953
20701
  VerifyCsrfToken,
20702
+ VerifyEmail,
21954
20703
  View,
21955
20704
  Factory as ViewFactoryImpl,
21956
20705
  ViewFactoryUnavailableError,
@@ -21963,6 +20712,7 @@ export {
21963
20712
  WORKER_DISCOVERY_DIRECTORIES,
21964
20713
  WithoutOverlapping,
21965
20714
  Worker,
20715
+ __,
21966
20716
  abort,
21967
20717
  abortIf,
21968
20718
  abortUnless,
@@ -22001,7 +20751,7 @@ export {
22001
20751
  csrfToken,
22002
20752
  currentContainer,
22003
20753
  currentLogContext,
22004
- currentRequest2 as currentRequest,
20754
+ currentRequest,
22005
20755
  currentVite,
22006
20756
  databaseConfigDefaults,
22007
20757
  debugPage,
@@ -22032,6 +20782,7 @@ export {
22032
20782
  errors,
22033
20783
  escapeHtml,
22034
20784
  event,
20785
+ exceedsJsonDepth,
22035
20786
  expandWildcardKeys,
22036
20787
  extensionFromMime,
22037
20788
  facade,
@@ -22108,6 +20859,7 @@ export {
22108
20859
  parseRuleSpec,
22109
20860
  parseSignature,
22110
20861
  passwordVerify,
20862
+ persistentMiddleware,
22111
20863
  prepareValue,
22112
20864
  queueConfigDefaults,
22113
20865
  queueOptionsOf,