@orieljs/framework 0.1.0-alpha.4 → 0.1.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +3 -0
- package/dist/{chunk-WSGWYXAO.js → chunk-I63ZFMX6.js} +3 -1
- package/dist/chunk-I63ZFMX6.js.map +1 -0
- package/dist/{chunk-3DETYZMZ.js → chunk-MFTZQMZM.js} +3 -3
- package/dist/chunk-POEP4B2M.js +2613 -0
- package/dist/chunk-POEP4B2M.js.map +1 -0
- package/dist/{chunk-SBZQ6L3Z.js → chunk-ZOEPKBVF.js} +1009 -279
- package/dist/chunk-ZOEPKBVF.js.map +1 -0
- package/dist/contracts.d.ts +63 -1
- package/dist/contracts.js +3 -1
- package/dist/index.d-BJyJx6U1.d.ts +319 -0
- package/dist/index.d.ts +1310 -5533
- package/dist/index.js +1203 -194
- package/dist/index.js.map +1 -1
- package/dist/{jsx-runtime-WKTl3EEw.d.ts → jsx-runtime-CBZQYYDS.d.ts} +2 -47
- package/dist/jsx-runtime.d.ts +2 -2
- package/dist/jsx-runtime.js +3 -3
- package/dist/{testing-D3dCOkTm.d.ts → testing-BM481Hdz.d.ts} +217 -986
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +19 -5
- package/package.json +30 -30
- package/dist/chunk-DCI2T7WJ.js +0 -766
- package/dist/chunk-DCI2T7WJ.js.map +0 -1
- package/dist/chunk-SBZQ6L3Z.js.map +0 -1
- package/dist/chunk-WSGWYXAO.js.map +0 -1
- package/dist/index.d-DOlTeG-8.d.ts +0 -99
- /package/dist/{chunk-3DETYZMZ.js.map → chunk-MFTZQMZM.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
renderToString,
|
|
23
23
|
styleString,
|
|
24
24
|
view
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-MFTZQMZM.js";
|
|
26
26
|
import {
|
|
27
27
|
API_ROUTES_STUB,
|
|
28
28
|
Application as Application2,
|
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
NotificationFake,
|
|
61
61
|
On,
|
|
62
62
|
PERSISTENT_MIDDLEWARE,
|
|
63
|
+
Pagination,
|
|
63
64
|
PendingEvent,
|
|
64
65
|
PropertyNotUpdatableError,
|
|
65
66
|
ProviderBootError,
|
|
@@ -74,6 +75,7 @@ import {
|
|
|
74
75
|
Vite,
|
|
75
76
|
ViteError,
|
|
76
77
|
ViteHtml,
|
|
78
|
+
WithPagination,
|
|
77
79
|
abort,
|
|
78
80
|
abortIf,
|
|
79
81
|
abortUnless,
|
|
@@ -129,7 +131,7 @@ import {
|
|
|
129
131
|
vite,
|
|
130
132
|
viteReactRefresh,
|
|
131
133
|
writeResponse
|
|
132
|
-
} from "./chunk-
|
|
134
|
+
} from "./chunk-ZOEPKBVF.js";
|
|
133
135
|
import {
|
|
134
136
|
Arr,
|
|
135
137
|
BindingResolutionError,
|
|
@@ -141,18 +143,20 @@ import {
|
|
|
141
143
|
LazyCollection,
|
|
142
144
|
ServiceProvider,
|
|
143
145
|
Str,
|
|
146
|
+
Stringable,
|
|
144
147
|
__,
|
|
145
148
|
app,
|
|
146
149
|
collect,
|
|
147
150
|
config,
|
|
148
151
|
currentContainer,
|
|
149
152
|
facade,
|
|
153
|
+
fileType_exports,
|
|
150
154
|
inject,
|
|
151
155
|
now,
|
|
152
156
|
retry,
|
|
153
157
|
tap,
|
|
154
158
|
value
|
|
155
|
-
} from "./chunk-
|
|
159
|
+
} from "./chunk-POEP4B2M.js";
|
|
156
160
|
import {
|
|
157
161
|
Application,
|
|
158
162
|
AuthFactory,
|
|
@@ -179,6 +183,7 @@ import {
|
|
|
179
183
|
LogManager,
|
|
180
184
|
MailManager,
|
|
181
185
|
NotificationDispatcher,
|
|
186
|
+
PaginationState,
|
|
182
187
|
PasswordBroker,
|
|
183
188
|
PipelineFactory,
|
|
184
189
|
QueueManager,
|
|
@@ -193,7 +198,7 @@ import {
|
|
|
193
198
|
ValidationFactory,
|
|
194
199
|
ViewFactory,
|
|
195
200
|
token
|
|
196
|
-
} from "./chunk-
|
|
201
|
+
} from "./chunk-I63ZFMX6.js";
|
|
197
202
|
|
|
198
203
|
// ../Auth/dist/index.js
|
|
199
204
|
import { createHash } from "crypto";
|
|
@@ -1377,6 +1382,39 @@ var AccessGate = class _AccessGate {
|
|
|
1377
1382
|
return registered === void 0 ? [cls.name] : [baseName(registered), cls.name];
|
|
1378
1383
|
}
|
|
1379
1384
|
};
|
|
1385
|
+
var list = (abilities) => typeof abilities === "string" ? [abilities] : [...abilities];
|
|
1386
|
+
function Authorizable(Base) {
|
|
1387
|
+
return class AuthorizableUser extends Base {
|
|
1388
|
+
/** Whether the user has the ability (every one, for a list); the arguments go to the policy or ability callback. */
|
|
1389
|
+
async can(abilities, ...args) {
|
|
1390
|
+
const gate = inject(Gate).forUser(this);
|
|
1391
|
+
for (const ability of list(abilities)) if (!await gate.allows(ability, ...args)) return false;
|
|
1392
|
+
return true;
|
|
1393
|
+
}
|
|
1394
|
+
/** Whether the user has any of the abilities. */
|
|
1395
|
+
async canAny(abilities, ...args) {
|
|
1396
|
+
return inject(Gate).forUser(this).any(list(abilities), ...args);
|
|
1397
|
+
}
|
|
1398
|
+
/** Whether the user lacks the ability (any one, for a list). */
|
|
1399
|
+
async cant(abilities, ...args) {
|
|
1400
|
+
return !await this.can(abilities, ...args);
|
|
1401
|
+
}
|
|
1402
|
+
/** The same as cant(). */
|
|
1403
|
+
cannot(abilities, ...args) {
|
|
1404
|
+
return this.cant(abilities, ...args);
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
var Controller = class {
|
|
1409
|
+
/** Authorizes the ability for the signed-in user (the Gate's authorize()). */
|
|
1410
|
+
async authorize(ability, ...args) {
|
|
1411
|
+
return inject(Gate).authorize(ability, ...args);
|
|
1412
|
+
}
|
|
1413
|
+
/** Authorizes the ability for the given user (Gate.forUser(user).authorize()). */
|
|
1414
|
+
async authorizeForUser(user, ability, ...args) {
|
|
1415
|
+
return inject(Gate).forUser(user).authorize(ability, ...args);
|
|
1416
|
+
}
|
|
1417
|
+
};
|
|
1380
1418
|
var Authorize = class {
|
|
1381
1419
|
#gate = inject(Gate);
|
|
1382
1420
|
async handle(request2, next, ability, ...models) {
|
|
@@ -1618,7 +1656,7 @@ async function discoverPolicies(directory, gate) {
|
|
|
1618
1656
|
return found;
|
|
1619
1657
|
}
|
|
1620
1658
|
var Auth = facade(AuthFactory);
|
|
1621
|
-
var
|
|
1659
|
+
var Gate4 = facade(Gate);
|
|
1622
1660
|
var Password = facade(PasswordBroker, {
|
|
1623
1661
|
broker: (name) => inject(PasswordBrokerManager).broker(name)
|
|
1624
1662
|
});
|
|
@@ -1689,7 +1727,7 @@ var QUEUE_OPTIONS = ["connection", "queue", "delay", "tries", "backoff", "timeou
|
|
|
1689
1727
|
function isQueueable(job) {
|
|
1690
1728
|
if (typeof job !== "object" || job === null) return false;
|
|
1691
1729
|
const members = job;
|
|
1692
|
-
if (members[SHOULD_QUEUE] === true) return true;
|
|
1730
|
+
if (members.shouldQueue === true || members[SHOULD_QUEUE] === true) return true;
|
|
1693
1731
|
if (QUEUE_OPTIONS.some((option) => members[option] !== void 0)) return true;
|
|
1694
1732
|
return typeof members.uniqueId === "function" || typeof members.retryUntil === "function";
|
|
1695
1733
|
}
|
|
@@ -1900,9 +1938,9 @@ var Dispatcher = class {
|
|
|
1900
1938
|
}
|
|
1901
1939
|
#afterResponseList() {
|
|
1902
1940
|
const owner = currentContainer() ?? this.container;
|
|
1903
|
-
let
|
|
1904
|
-
if (
|
|
1905
|
-
return
|
|
1941
|
+
let list4 = this.#afterResponse.get(owner);
|
|
1942
|
+
if (list4 === void 0) this.#afterResponse.set(owner, list4 = []);
|
|
1943
|
+
return list4;
|
|
1906
1944
|
}
|
|
1907
1945
|
/** Runs the job (like dispatchSync) after the response is sent, or after the current queued job. */
|
|
1908
1946
|
dispatchAfterResponse(job) {
|
|
@@ -2051,6 +2089,10 @@ var Dispatchable = class {
|
|
|
2051
2089
|
}
|
|
2052
2090
|
};
|
|
2053
2091
|
var Queueable = class extends Dispatchable {
|
|
2092
|
+
/** ShouldQueue's marker, so subclasses may write `implements ShouldQueue` without the field. */
|
|
2093
|
+
get shouldQueue() {
|
|
2094
|
+
return true;
|
|
2095
|
+
}
|
|
2054
2096
|
};
|
|
2055
2097
|
Object.defineProperty(Queueable.prototype, SHOULD_QUEUE, { value: true });
|
|
2056
2098
|
function dispatch(job) {
|
|
@@ -2921,8 +2963,8 @@ var RedisRepository = class extends Repository2 {
|
|
|
2921
2963
|
redisStore;
|
|
2922
2964
|
redis;
|
|
2923
2965
|
tags(names) {
|
|
2924
|
-
const
|
|
2925
|
-
const taggedStore = this.redisStore.tags(
|
|
2966
|
+
const list4 = Array.isArray(names) ? names : [names];
|
|
2967
|
+
const taggedStore = this.redisStore.tags(list4);
|
|
2926
2968
|
const prefix = this.redisStore.getPrefix();
|
|
2927
2969
|
return new Repository2(taggedStore, (_store, name, seconds, owner) => new RedisLock(this.redis, prefix + name, seconds, owner));
|
|
2928
2970
|
}
|
|
@@ -3748,6 +3790,34 @@ var LISTENER_STUB_PLAIN = `export class {{ class }} {
|
|
|
3748
3790
|
}
|
|
3749
3791
|
}
|
|
3750
3792
|
`;
|
|
3793
|
+
var LISTENER_STUB_QUEUED = `import { {{ event }} } from '{{ eventImport }}'
|
|
3794
|
+
import type { ShouldQueue } from '@orieljs/framework/contracts'
|
|
3795
|
+
|
|
3796
|
+
export class {{ class }} implements ShouldQueue {
|
|
3797
|
+
static listensTo = {{ event }}
|
|
3798
|
+
|
|
3799
|
+
/** Run by the queue worker (node oriel queue:work): remove this line and \`implements ShouldQueue\` to run it right away. */
|
|
3800
|
+
readonly shouldQueue = true
|
|
3801
|
+
|
|
3802
|
+
async handle(_event: {{ event }}): Promise<void> {
|
|
3803
|
+
//
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
`;
|
|
3807
|
+
var LISTENER_STUB_QUEUED_PLAIN = `import type { ShouldQueue } from '@orieljs/framework/contracts'
|
|
3808
|
+
|
|
3809
|
+
export class {{ class }} implements ShouldQueue {
|
|
3810
|
+
// Name the event class (or event name) this listener handles, so app/Listeners discovery registers it:
|
|
3811
|
+
// static listensTo = OrderShipped
|
|
3812
|
+
|
|
3813
|
+
/** Run by the queue worker (node oriel queue:work): remove this line and \`implements ShouldQueue\` to run it right away. */
|
|
3814
|
+
readonly shouldQueue = true
|
|
3815
|
+
|
|
3816
|
+
async handle(_event: unknown): Promise<void> {
|
|
3817
|
+
//
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
`;
|
|
3751
3821
|
var JOB_STUB = `import { Queueable } from '@orieljs/framework'
|
|
3752
3822
|
|
|
3753
3823
|
export class {{ class }} extends Queueable {
|
|
@@ -3765,9 +3835,12 @@ export class {{ class }} extends Dispatchable {
|
|
|
3765
3835
|
}
|
|
3766
3836
|
`;
|
|
3767
3837
|
var MAIL_STUB = `import { Mailable } from '@orieljs/framework'
|
|
3768
|
-
import type { Content, Envelope } from '@orieljs/framework/contracts'
|
|
3838
|
+
import type { Content, Envelope, ShouldQueue } from '@orieljs/framework/contracts'
|
|
3839
|
+
|
|
3840
|
+
export class {{ class }} extends Mailable implements ShouldQueue {
|
|
3841
|
+
/** Sent by the queue worker (node oriel queue:work): remove this line and \`implements ShouldQueue\` to send it right away. */
|
|
3842
|
+
readonly shouldQueue = true
|
|
3769
3843
|
|
|
3770
|
-
export class {{ class }} extends Mailable {
|
|
3771
3844
|
override async envelope(): Promise<Envelope> {
|
|
3772
3845
|
return { subject: '{{ subject }}' }
|
|
3773
3846
|
}
|
|
@@ -3778,9 +3851,12 @@ export class {{ class }} extends Mailable {
|
|
|
3778
3851
|
}
|
|
3779
3852
|
`;
|
|
3780
3853
|
var NOTIFICATION_STUB = `import { MailMessage, Notification } from '@orieljs/framework'
|
|
3781
|
-
import type { Notifiable } from '@orieljs/framework/contracts'
|
|
3854
|
+
import type { Notifiable, ShouldQueue } from '@orieljs/framework/contracts'
|
|
3855
|
+
|
|
3856
|
+
export class {{ class }} extends Notification implements ShouldQueue {
|
|
3857
|
+
/** Sent by the queue worker (node oriel queue:work): remove this line and \`implements ShouldQueue\` to send it right away. */
|
|
3858
|
+
readonly shouldQueue = true
|
|
3782
3859
|
|
|
3783
|
-
export class {{ class }} extends Notification {
|
|
3784
3860
|
via(_notifiable: Notifiable): string[] {
|
|
3785
3861
|
return ['mail']
|
|
3786
3862
|
}
|
|
@@ -3917,15 +3993,12 @@ var MakeCastCommand = class extends GeneratorCommand {
|
|
|
3917
3993
|
}
|
|
3918
3994
|
};
|
|
3919
3995
|
var MakeCommandCommand = class extends GeneratorCommand {
|
|
3920
|
-
/** --command sets the generated signature; without it, Laravel's `app:` plus the kebab-cased name is used. */
|
|
3996
|
+
/** --command sets the generated signature; without it, Laravel's `app:` plus the kebab-cased class name is used. */
|
|
3921
3997
|
signature = "make:command {name} {--command=} {--force}";
|
|
3922
3998
|
description = "Create a new Artisan command";
|
|
3923
3999
|
type() {
|
|
3924
4000
|
return "Console/Commands";
|
|
3925
4001
|
}
|
|
3926
|
-
suffix() {
|
|
3927
|
-
return "Command";
|
|
3928
|
-
}
|
|
3929
4002
|
stub() {
|
|
3930
4003
|
return COMMAND_STUB;
|
|
3931
4004
|
}
|
|
@@ -3933,7 +4006,7 @@ var MakeCommandCommand = class extends GeneratorCommand {
|
|
|
3933
4006
|
const option = this.option("command");
|
|
3934
4007
|
const className = this.qualifyClass(rawName).className;
|
|
3935
4008
|
return {
|
|
3936
|
-
signature: typeof option === "string" ? option : `app:${Str.kebab(className
|
|
4009
|
+
signature: typeof option === "string" ? option : `app:${Str.kebab(className)}`
|
|
3937
4010
|
};
|
|
3938
4011
|
}
|
|
3939
4012
|
};
|
|
@@ -4006,13 +4079,15 @@ var MakeJobCommand = class extends GeneratorCommand {
|
|
|
4006
4079
|
}
|
|
4007
4080
|
};
|
|
4008
4081
|
var MakeListenerCommand = class extends GeneratorCommand {
|
|
4009
|
-
signature = "make:listener {name} {--e|event= : The event class being listened for} {--force}";
|
|
4082
|
+
signature = "make:listener {name} {--e|event= : The event class being listened for} {--queued : Indicates the event listener should be queued} {--force}";
|
|
4010
4083
|
description = "Create a new event listener class";
|
|
4011
4084
|
type() {
|
|
4012
4085
|
return "Listeners";
|
|
4013
4086
|
}
|
|
4014
4087
|
stub() {
|
|
4015
|
-
|
|
4088
|
+
const typed = typeof this.option("event") === "string";
|
|
4089
|
+
if (this.option("queued") === true) return typed ? LISTENER_STUB_QUEUED : LISTENER_STUB_QUEUED_PLAIN;
|
|
4090
|
+
return typed ? LISTENER_STUB : LISTENER_STUB_PLAIN;
|
|
4016
4091
|
}
|
|
4017
4092
|
extraPlaceholders(rawName) {
|
|
4018
4093
|
const event2 = this.option("event");
|
|
@@ -4200,6 +4275,29 @@ var MakeTestCommand = class extends GeneratorCommand {
|
|
|
4200
4275
|
return `${className.replace(/(?<=.)Test$/, "")}.test.ts`;
|
|
4201
4276
|
}
|
|
4202
4277
|
};
|
|
4278
|
+
var ScheduleClearCacheCommand = class extends Command {
|
|
4279
|
+
signature = "schedule:clear-cache";
|
|
4280
|
+
description = "Delete the cached mutex files created by scheduler";
|
|
4281
|
+
async handle() {
|
|
4282
|
+
let cleared = false;
|
|
4283
|
+
if (currentContainer()?.bound(CacheManager)) {
|
|
4284
|
+
const cache2 = inject(CacheManager);
|
|
4285
|
+
for (const event2 of inject(Schedule).events()) {
|
|
4286
|
+
if (!event2.preventsOverlapping) continue;
|
|
4287
|
+
const lock = cache2.lock(event2.mutexName(), event2.expiresAt * 60);
|
|
4288
|
+
if (await lock.get()) {
|
|
4289
|
+
await lock.release();
|
|
4290
|
+
continue;
|
|
4291
|
+
}
|
|
4292
|
+
this.info(`Deleting mutex for [${event2.command ?? event2.getSummaryForDisplay()}]`);
|
|
4293
|
+
await lock.forceRelease();
|
|
4294
|
+
cleared = true;
|
|
4295
|
+
}
|
|
4296
|
+
}
|
|
4297
|
+
if (!cleared) this.info("No mutex files were found.");
|
|
4298
|
+
return 0;
|
|
4299
|
+
}
|
|
4300
|
+
};
|
|
4203
4301
|
var ScheduleListCommand = class extends Command {
|
|
4204
4302
|
signature = "schedule:list";
|
|
4205
4303
|
description = "List the scheduled commands";
|
|
@@ -4211,18 +4309,15 @@ var ScheduleListCommand = class extends Command {
|
|
|
4211
4309
|
}
|
|
4212
4310
|
this.table(
|
|
4213
4311
|
["Command", "Expression"],
|
|
4214
|
-
events.map((event2) => [event2.
|
|
4312
|
+
events.map((event2) => [event2.getSummaryForDisplay(), event2.expression])
|
|
4215
4313
|
);
|
|
4216
4314
|
return 0;
|
|
4217
4315
|
}
|
|
4218
4316
|
};
|
|
4219
|
-
function summaryOf(event2) {
|
|
4220
|
-
return event2.getSummary();
|
|
4221
|
-
}
|
|
4222
4317
|
async function runDueEvents(events, io, now5) {
|
|
4223
4318
|
const backgroundRuns = [];
|
|
4224
4319
|
for (const event2 of events) {
|
|
4225
|
-
io.info(`Running scheduled task: ${
|
|
4320
|
+
io.info(`Running scheduled task: ${event2.getSummaryForDisplay()}`);
|
|
4226
4321
|
const attempt = async () => {
|
|
4227
4322
|
try {
|
|
4228
4323
|
await event2.run(now5);
|
|
@@ -4527,7 +4622,7 @@ var SHOULD_QUEUE2 = /* @__PURE__ */ Symbol.for("oriel:bus.shouldQueue");
|
|
|
4527
4622
|
var QUEUE_OPTIONS2 = ["connection", "queue", "delay", "tries", "backoff", "timeout"];
|
|
4528
4623
|
function isQueueable2(job) {
|
|
4529
4624
|
const members = job;
|
|
4530
|
-
if (members[SHOULD_QUEUE2] === true) return true;
|
|
4625
|
+
if (members.shouldQueue === true || members[SHOULD_QUEUE2] === true) return true;
|
|
4531
4626
|
if (QUEUE_OPTIONS2.some((option) => members[option] !== void 0)) return true;
|
|
4532
4627
|
return typeof members.uniqueId === "function" || typeof members.retryUntil === "function";
|
|
4533
4628
|
}
|
|
@@ -4570,6 +4665,15 @@ var ScheduledEventImpl = class {
|
|
|
4570
4665
|
get expression() {
|
|
4571
4666
|
return this.cronExpression;
|
|
4572
4667
|
}
|
|
4668
|
+
get command() {
|
|
4669
|
+
return this.commandString;
|
|
4670
|
+
}
|
|
4671
|
+
get preventsOverlapping() {
|
|
4672
|
+
return this.overlapExpiryMinutes !== void 0;
|
|
4673
|
+
}
|
|
4674
|
+
get expiresAt() {
|
|
4675
|
+
return this.overlapExpiryMinutes ?? 1440;
|
|
4676
|
+
}
|
|
4573
4677
|
cron(expression) {
|
|
4574
4678
|
this.cronExpression = expression;
|
|
4575
4679
|
return this;
|
|
@@ -4663,15 +4767,19 @@ var ScheduledEventImpl = class {
|
|
|
4663
4767
|
this.eventDescription = description;
|
|
4664
4768
|
return this;
|
|
4665
4769
|
}
|
|
4666
|
-
|
|
4770
|
+
getSummaryForDisplay() {
|
|
4771
|
+
return this.eventName ?? this.eventDescription ?? this.commandString ?? "Closure";
|
|
4772
|
+
}
|
|
4773
|
+
/** Accessors beyond the contract, read back by the schedule:run/schedule:work loop. */
|
|
4667
4774
|
getName() {
|
|
4668
4775
|
return this.eventName;
|
|
4669
4776
|
}
|
|
4670
4777
|
getDescription() {
|
|
4671
4778
|
return this.eventDescription;
|
|
4672
4779
|
}
|
|
4780
|
+
/** The same as getSummaryForDisplay(). */
|
|
4673
4781
|
getSummary() {
|
|
4674
|
-
return this.
|
|
4782
|
+
return this.getSummaryForDisplay();
|
|
4675
4783
|
}
|
|
4676
4784
|
isBackground() {
|
|
4677
4785
|
return this.background;
|
|
@@ -4727,11 +4835,11 @@ var ScheduledEventImpl = class {
|
|
|
4727
4835
|
* Follows Laravel: a command event's mutex is `sha1(expression + full command
|
|
4728
4836
|
* string incl. parameters)` (Laravel's `Event::mutexName()`) — no `name()` required. A closure event (`call()`/
|
|
4729
4837
|
* `job()`) has no command string, so its mutex is `sha1(name())` (Laravel's `CallbackEvent::mutexName()`, which
|
|
4730
|
-
* reads the description `name()` also writes)
|
|
4731
|
-
*
|
|
4838
|
+
* reads the description `name()` also writes), and `sha1('')` while it has no name, as Laravel's
|
|
4839
|
+
* (`requireLockableName()` keeps an unnamed closure from ever taking the lock).
|
|
4732
4840
|
*/
|
|
4733
4841
|
mutexName() {
|
|
4734
|
-
const key = this.commandString !== void 0 ? this.cronExpression + this.commandString : this.eventName;
|
|
4842
|
+
const key = this.commandString !== void 0 ? this.cronExpression + this.commandString : this.eventName ?? "";
|
|
4735
4843
|
return `framework/schedule-${sha1(key)}`;
|
|
4736
4844
|
}
|
|
4737
4845
|
/**
|
|
@@ -4808,6 +4916,7 @@ var ConsoleServiceProvider = class extends ServiceProvider {
|
|
|
4808
4916
|
ScheduleRunCommand,
|
|
4809
4917
|
ScheduleWorkCommand,
|
|
4810
4918
|
ScheduleListCommand,
|
|
4919
|
+
ScheduleClearCacheCommand,
|
|
4811
4920
|
MakeControllerCommand,
|
|
4812
4921
|
MakeModelCommand,
|
|
4813
4922
|
MakeMiddlewareCommand,
|
|
@@ -4837,7 +4946,7 @@ var ConsoleServiceProvider = class extends ServiceProvider {
|
|
|
4837
4946
|
}
|
|
4838
4947
|
};
|
|
4839
4948
|
var Artisan = facade(ConsoleKernel);
|
|
4840
|
-
var
|
|
4949
|
+
var Schedule5 = facade(Schedule);
|
|
4841
4950
|
async function runConsole(app2, argv = process.argv.slice(2)) {
|
|
4842
4951
|
app2.setRunningInConsole(true);
|
|
4843
4952
|
try {
|
|
@@ -4848,7 +4957,17 @@ async function runConsole(app2, argv = process.argv.slice(2)) {
|
|
|
4848
4957
|
}
|
|
4849
4958
|
}
|
|
4850
4959
|
async function runConsoleAndExit(app2, argv = process.argv.slice(2), exit = (code) => process.exit(code)) {
|
|
4851
|
-
|
|
4960
|
+
let code;
|
|
4961
|
+
try {
|
|
4962
|
+
code = await runConsole(app2, argv);
|
|
4963
|
+
} finally {
|
|
4964
|
+
await flushLogs(app2);
|
|
4965
|
+
}
|
|
4966
|
+
exit(code);
|
|
4967
|
+
}
|
|
4968
|
+
async function flushLogs(app2) {
|
|
4969
|
+
if (!app2.bound(LogManager)) return;
|
|
4970
|
+
await app2.make(LogManager).flush?.();
|
|
4852
4971
|
}
|
|
4853
4972
|
|
|
4854
4973
|
// ../Cookie/dist/index.js
|
|
@@ -5452,7 +5571,10 @@ var AbstractPaginator = class _AbstractPaginator {
|
|
|
5452
5571
|
this.collection = items;
|
|
5453
5572
|
return this;
|
|
5454
5573
|
}
|
|
5455
|
-
/**
|
|
5574
|
+
/**
|
|
5575
|
+
* Transforms each item in place, typically for serialization, and returns this paginator typed with the new items:
|
|
5576
|
+
* `posts.through((post) => ({ id: post.id }))`. Each paginator narrows the return type to its own class.
|
|
5577
|
+
*/
|
|
5456
5578
|
through(callback) {
|
|
5457
5579
|
this.collection = this.collection.map(callback);
|
|
5458
5580
|
return this;
|
|
@@ -5552,6 +5674,9 @@ var CursorPaginator = class extends AbstractPaginator {
|
|
|
5552
5674
|
getCursorName() {
|
|
5553
5675
|
return this.cursorName;
|
|
5554
5676
|
}
|
|
5677
|
+
through(callback) {
|
|
5678
|
+
return super.through(callback);
|
|
5679
|
+
}
|
|
5555
5680
|
hasMorePages() {
|
|
5556
5681
|
return this.cursorValue === void 0 && this.hasMore || this.cursorValue !== void 0 && this.cursorValue.pointsToNextItems() && this.hasMore || this.cursorValue !== void 0 && this.cursorValue.pointsToPreviousItems();
|
|
5557
5682
|
}
|
|
@@ -5608,6 +5733,9 @@ var LengthAwarePaginator = class extends AbstractPaginator {
|
|
|
5608
5733
|
total() {
|
|
5609
5734
|
return this.totalValue;
|
|
5610
5735
|
}
|
|
5736
|
+
through(callback) {
|
|
5737
|
+
return super.through(callback);
|
|
5738
|
+
}
|
|
5611
5739
|
lastPage() {
|
|
5612
5740
|
return this.lastPageValue;
|
|
5613
5741
|
}
|
|
@@ -5623,14 +5751,17 @@ var LengthAwarePaginator = class extends AbstractPaginator {
|
|
|
5623
5751
|
nextPageUrl() {
|
|
5624
5752
|
return this.hasMorePages() ? this.url(this.currentPageValue + 1) : null;
|
|
5625
5753
|
}
|
|
5626
|
-
/**
|
|
5754
|
+
/**
|
|
5755
|
+
* The page links Laravel renders: previous, the page window with '...' gaps, next. The labels are plain text
|
|
5756
|
+
* ("« Previous", "Next »"), not Laravel's `«` entities, so a page can print them as text.
|
|
5757
|
+
*/
|
|
5627
5758
|
linkCollection() {
|
|
5628
|
-
const links = [{ url: this.previousPageUrl(), label: "
|
|
5759
|
+
const links = [{ url: this.previousPageUrl(), label: "\xAB Previous", active: false }];
|
|
5629
5760
|
for (const element of this.elements()) {
|
|
5630
5761
|
if (element === "...") links.push({ url: null, label: "...", active: false });
|
|
5631
5762
|
else for (const [page, url2] of element) links.push({ url: url2, label: String(page), active: page === this.currentPageValue });
|
|
5632
5763
|
}
|
|
5633
|
-
links.push({ url: this.nextPageUrl(), label: "Next
|
|
5764
|
+
links.push({ url: this.nextPageUrl(), label: "Next \xBB", active: false });
|
|
5634
5765
|
return links;
|
|
5635
5766
|
}
|
|
5636
5767
|
/** Laravel's UrlWindow: the first pages, the slider around the current page and the last pages, with '...' between. */
|
|
@@ -5693,6 +5824,9 @@ var Paginator = class extends AbstractPaginator {
|
|
|
5693
5824
|
hasMorePages() {
|
|
5694
5825
|
return this.hasMore;
|
|
5695
5826
|
}
|
|
5827
|
+
through(callback) {
|
|
5828
|
+
return super.through(callback);
|
|
5829
|
+
}
|
|
5696
5830
|
hasPages() {
|
|
5697
5831
|
return this.currentPageValue !== 1 || this.hasMore;
|
|
5698
5832
|
}
|
|
@@ -5752,6 +5886,9 @@ var EMPTY = sql2.raw("");
|
|
|
5752
5886
|
var isSqlFragment = (value2) => typeof value2 === "object" && value2 !== null && typeof value2.toOperationNode === "function";
|
|
5753
5887
|
var join8 = (parts, separator = ", ") => sql2.join(parts, sql2.raw(separator));
|
|
5754
5888
|
var clauses = (parts) => join8(parts.filter((part) => part !== void 0), " ");
|
|
5889
|
+
function likeToGlob(pattern) {
|
|
5890
|
+
return pattern.replaceAll("*", "[*]").replaceAll("?", "[?]").replaceAll("%", "*").replaceAll("_", "?");
|
|
5891
|
+
}
|
|
5755
5892
|
var Grammar = class {
|
|
5756
5893
|
constructor(driver) {
|
|
5757
5894
|
this.driver = driver;
|
|
@@ -5832,6 +5969,8 @@ var Grammar = class {
|
|
|
5832
5969
|
}
|
|
5833
5970
|
case "null":
|
|
5834
5971
|
return sql2`${this.wrap(where.column)} ${sql2.raw(where.not ? "is not null" : "is null")}`;
|
|
5972
|
+
case "like":
|
|
5973
|
+
return this.compileWhereLike(where);
|
|
5835
5974
|
case "between":
|
|
5836
5975
|
return sql2`${this.wrap(where.column)} ${sql2.raw(where.not ? "not between" : "between")} ${this.parameter(where.values[0])} and ${this.parameter(where.values[1])}`;
|
|
5837
5976
|
case "column":
|
|
@@ -5844,6 +5983,18 @@ var Grammar = class {
|
|
|
5844
5983
|
return rawWithBindings(where.sql, where.bindings.map((value2) => this.prepare(value2)));
|
|
5845
5984
|
}
|
|
5846
5985
|
}
|
|
5986
|
+
/**
|
|
5987
|
+
* whereLike() per driver, as Laravel 12's grammars: Postgres compares the column as text with ilike (like when
|
|
5988
|
+
* case-sensitive); MySQL uses like (like binary); SQLite uses like, or glob with the pattern translated.
|
|
5989
|
+
*/
|
|
5990
|
+
compileWhereLike(where) {
|
|
5991
|
+
const not = where.not ? "not " : "";
|
|
5992
|
+
const column = this.wrap(where.column);
|
|
5993
|
+
if (this.driver === "pgsql") return sql2`${column}::text ${sql2.raw(`${not}${where.caseSensitive ? "like" : "ilike"}`)} ${this.parameter(where.value)}`;
|
|
5994
|
+
if (this.driver === "mysql") return sql2`${column} ${sql2.raw(`${not}${where.caseSensitive ? "like binary" : "like"}`)} ${this.parameter(where.value)}`;
|
|
5995
|
+
if (where.caseSensitive) return sql2`${column} ${sql2.raw(`${not}glob`)} ${this.parameter(likeToGlob(where.value))}`;
|
|
5996
|
+
return sql2`${column} ${sql2.raw(`${not}like`)} ${this.parameter(where.value)}`;
|
|
5997
|
+
}
|
|
5847
5998
|
compileJoin(joinClause) {
|
|
5848
5999
|
if (joinClause.joinType === "cross") return sql2`cross join ${this.wrapTable(joinClause.table)}`;
|
|
5849
6000
|
return sql2`${sql2.raw(joinClause.joinType)} join ${this.wrapTable(joinClause.table)} ${this.compileWheres(joinClause.wheres, "on") ?? EMPTY}`;
|
|
@@ -6096,6 +6247,25 @@ var Builder = class _Builder {
|
|
|
6096
6247
|
this.wheres.push({ type: "between", column, values, not: true, boolean: "and" });
|
|
6097
6248
|
return this;
|
|
6098
6249
|
}
|
|
6250
|
+
/**
|
|
6251
|
+
* Laravel's whereLike(): the value is the pattern, `%` and `_` included (`whereLike('title', `%${term}%`)`).
|
|
6252
|
+
* Case-insensitive unless caseSensitive: ilike on Postgres, like on MySQL and SQLite (their like already ignores
|
|
6253
|
+
* case: MySQL through the column's collation, SQLite for ASCII letters). Case-sensitive is like on Postgres,
|
|
6254
|
+
* like binary on MySQL and glob on SQLite.
|
|
6255
|
+
*/
|
|
6256
|
+
whereLike(column, value2, caseSensitive = false, boolean = "and", not = false) {
|
|
6257
|
+
this.wheres.push({ type: "like", column, value: value2, caseSensitive, not, boolean });
|
|
6258
|
+
return this;
|
|
6259
|
+
}
|
|
6260
|
+
orWhereLike(column, value2, caseSensitive = false) {
|
|
6261
|
+
return this.whereLike(column, value2, caseSensitive, "or");
|
|
6262
|
+
}
|
|
6263
|
+
whereNotLike(column, value2, caseSensitive = false, boolean = "and") {
|
|
6264
|
+
return this.whereLike(column, value2, caseSensitive, boolean, true);
|
|
6265
|
+
}
|
|
6266
|
+
orWhereNotLike(column, value2, caseSensitive = false) {
|
|
6267
|
+
return this.whereNotLike(column, value2, caseSensitive, "or");
|
|
6268
|
+
}
|
|
6099
6269
|
/** Compares two columns: whereColumn('updated_at', '>', 'created_at'). */
|
|
6100
6270
|
whereColumn(first, operatorOrSecond, second, boolean = "and") {
|
|
6101
6271
|
const [operator, other] = second === void 0 ? ["=", operatorOrSecond] : [operatorOrSecond, second];
|
|
@@ -6219,10 +6389,16 @@ var Builder = class _Builder {
|
|
|
6219
6389
|
this.lockMode = "share";
|
|
6220
6390
|
return this;
|
|
6221
6391
|
}
|
|
6222
|
-
/** Calls callback(this, value) when value is truthy (or the default callback otherwise). */
|
|
6223
6392
|
when(value2, callback, otherwise) {
|
|
6224
|
-
|
|
6225
|
-
|
|
6393
|
+
const resolved = typeof value2 === "function" ? value2(this) : value2;
|
|
6394
|
+
if (resolved) callback(this, resolved);
|
|
6395
|
+
else otherwise?.(this, resolved);
|
|
6396
|
+
return this;
|
|
6397
|
+
}
|
|
6398
|
+
unless(value2, callback, otherwise) {
|
|
6399
|
+
const resolved = typeof value2 === "function" ? value2(this) : value2;
|
|
6400
|
+
if (!resolved) callback(this, resolved);
|
|
6401
|
+
else otherwise?.(this, resolved);
|
|
6226
6402
|
return this;
|
|
6227
6403
|
}
|
|
6228
6404
|
tap(callback) {
|
|
@@ -7909,6 +8085,18 @@ var Builder2 = class extends Builder {
|
|
|
7909
8085
|
whereBetween(column, values) {
|
|
7910
8086
|
return super.whereBetween(column, values);
|
|
7911
8087
|
}
|
|
8088
|
+
whereLike(column, value2, caseSensitive = false, boolean = "and", not = false) {
|
|
8089
|
+
return super.whereLike(column, value2, caseSensitive, boolean, not);
|
|
8090
|
+
}
|
|
8091
|
+
orWhereLike(column, value2, caseSensitive = false) {
|
|
8092
|
+
return super.orWhereLike(column, value2, caseSensitive);
|
|
8093
|
+
}
|
|
8094
|
+
whereNotLike(column, value2, caseSensitive = false, boolean = "and") {
|
|
8095
|
+
return super.whereNotLike(column, value2, caseSensitive, boolean);
|
|
8096
|
+
}
|
|
8097
|
+
orWhereNotLike(column, value2, caseSensitive = false) {
|
|
8098
|
+
return super.orWhereNotLike(column, value2, caseSensitive);
|
|
8099
|
+
}
|
|
7912
8100
|
orderBy(column, direction = "asc") {
|
|
7913
8101
|
return super.orderBy(column, direction);
|
|
7914
8102
|
}
|
|
@@ -8098,12 +8286,19 @@ var Builder2 = class extends Builder {
|
|
|
8098
8286
|
const key = column.includes(".") ? column.slice(column.lastIndexOf(".") + 1) : column;
|
|
8099
8287
|
return new Collection(rows.map((row) => this.model.newInstance().setRawAttributes({ [key]: row[key] }).getAttribute(key)));
|
|
8100
8288
|
}
|
|
8289
|
+
/** Whether `id` can't be one of the model's unique ids (not a UUID for HasUuids): it matches no row. */
|
|
8290
|
+
isMalformedKey(id) {
|
|
8291
|
+
return this.model.uniqueIds().includes(this.model.getKeyName()) && !this.model.isValidUniqueId(id);
|
|
8292
|
+
}
|
|
8293
|
+
/** A malformed unique id (HasUuids, HasUlids) finds nothing without a query, as route model binding does. */
|
|
8101
8294
|
async find(id) {
|
|
8295
|
+
if (this.isMalformedKey(id)) return void 0;
|
|
8102
8296
|
return this.clone().whereKey(id).first();
|
|
8103
8297
|
}
|
|
8104
8298
|
async findMany(ids) {
|
|
8105
|
-
|
|
8106
|
-
|
|
8299
|
+
const keys = ids.filter((id) => !this.isMalformedKey(id));
|
|
8300
|
+
if (!keys.length) return new Collection();
|
|
8301
|
+
return this.clone().whereKey(keys).get();
|
|
8107
8302
|
}
|
|
8108
8303
|
async findOrFail(id) {
|
|
8109
8304
|
if (Array.isArray(id)) {
|
|
@@ -8740,6 +8935,8 @@ var HasOneOrMany = class extends Relation {
|
|
|
8740
8935
|
foreignKey;
|
|
8741
8936
|
localKey;
|
|
8742
8937
|
morph;
|
|
8938
|
+
/** The relation on each related model that chaperone() points back at the parent. */
|
|
8939
|
+
inverseRelationship;
|
|
8743
8940
|
/** 'post_id' */
|
|
8744
8941
|
getForeignKeyName() {
|
|
8745
8942
|
return this.foreignKey.slice(this.foreignKey.lastIndexOf(".") + 1);
|
|
@@ -8761,6 +8958,61 @@ var HasOneOrMany = class extends Relation {
|
|
|
8761
8958
|
getMorphClass() {
|
|
8762
8959
|
return this.morph?.value;
|
|
8763
8960
|
}
|
|
8961
|
+
/**
|
|
8962
|
+
* Laravel's chaperone(): every related model this relation loads, eagerly or lazily, or makes, gets the parent as
|
|
8963
|
+
* its `relation` (guessed when not given: post_id → post, the parent's class, owner), so reading it needs no query:
|
|
8964
|
+
* `comments() { return this.hasMany(Comment).chaperone() }`.
|
|
8965
|
+
*/
|
|
8966
|
+
chaperone(relation) {
|
|
8967
|
+
const name = relation ?? this.guessInverseRelation();
|
|
8968
|
+
if (name === void 0 || !this.model.isRelation(name)) throw new RelationNotFoundError(this.model.constructor.name, name ?? "null");
|
|
8969
|
+
this.inverseRelationship = name;
|
|
8970
|
+
return this;
|
|
8971
|
+
}
|
|
8972
|
+
/** Laravel's inverse(): chaperone() under its other name. */
|
|
8973
|
+
inverse(relation) {
|
|
8974
|
+
return this.chaperone(relation);
|
|
8975
|
+
}
|
|
8976
|
+
withoutChaperone() {
|
|
8977
|
+
this.inverseRelationship = void 0;
|
|
8978
|
+
return this;
|
|
8979
|
+
}
|
|
8980
|
+
withoutInverse() {
|
|
8981
|
+
return this.withoutChaperone();
|
|
8982
|
+
}
|
|
8983
|
+
getInverseRelationship() {
|
|
8984
|
+
return this.inverseRelationship;
|
|
8985
|
+
}
|
|
8986
|
+
/** The first of the possible names that is a relation of the related model. */
|
|
8987
|
+
guessInverseRelation() {
|
|
8988
|
+
return this.getPossibleInverseRelations().find((name) => this.model.isRelation(name));
|
|
8989
|
+
}
|
|
8990
|
+
/** Laravel's candidates: the morph name, the foreign key without the parent's key, the parent's class, owner, parent. */
|
|
8991
|
+
getPossibleInverseRelations() {
|
|
8992
|
+
const key = this.parent.getKeyName();
|
|
8993
|
+
const names = [
|
|
8994
|
+
this.morph ? Str.beforeLast(this.getMorphType(), "_type") : "",
|
|
8995
|
+
Str.camel(Str.beforeLast(this.getForeignKeyName(), key)),
|
|
8996
|
+
Str.camel(Str.beforeLast(this.parent.getForeignKey(), key)),
|
|
8997
|
+
Str.camel(this.parent.constructor.name),
|
|
8998
|
+
"owner",
|
|
8999
|
+
this.parent.constructor === this.model.constructor ? "parent" : ""
|
|
9000
|
+
];
|
|
9001
|
+
return [...new Set(names.filter((name) => name !== ""))];
|
|
9002
|
+
}
|
|
9003
|
+
/** Sets the parent on a related model, when chaperone() named the relation. */
|
|
9004
|
+
applyInverseRelationToModel(model, parent = this.parent) {
|
|
9005
|
+
if (model && this.inverseRelationship !== void 0) model.setRelation(this.inverseRelationship, parent);
|
|
9006
|
+
return model;
|
|
9007
|
+
}
|
|
9008
|
+
applyInverseRelationToMany(models, parent = this.parent) {
|
|
9009
|
+
for (const model of models) this.applyInverseRelationToModel(model, parent);
|
|
9010
|
+
return models;
|
|
9011
|
+
}
|
|
9012
|
+
/** The relation query's rows (get(), first(), paginate(), …), pointing back at the parent with chaperone(). */
|
|
9013
|
+
async runSelect() {
|
|
9014
|
+
return this.applyInverseRelationToMany(await super.runSelect());
|
|
9015
|
+
}
|
|
8764
9016
|
addConstraints() {
|
|
8765
9017
|
this.where(this.foreignKey, "=", this.getParentKey());
|
|
8766
9018
|
this.whereNotNull(this.foreignKey);
|
|
@@ -8794,7 +9046,7 @@ var HasOneOrMany = class extends Relation {
|
|
|
8794
9046
|
setForeignAttributes(model) {
|
|
8795
9047
|
model.setAttribute(this.getForeignKeyName(), this.getParentKey());
|
|
8796
9048
|
if (this.morph) model.setAttribute(this.getMorphType(), this.morph.value);
|
|
8797
|
-
return model;
|
|
9049
|
+
return this.applyInverseRelationToModel(model);
|
|
8798
9050
|
}
|
|
8799
9051
|
async saveMany(models) {
|
|
8800
9052
|
const saved = [];
|
|
@@ -9113,7 +9365,8 @@ var HasMany = class extends HasOneOrMany {
|
|
|
9113
9365
|
match(models, results, relation) {
|
|
9114
9366
|
const dictionary = this.buildDictionary(results);
|
|
9115
9367
|
for (const model of models) {
|
|
9116
|
-
|
|
9368
|
+
const children = this.applyInverseRelationToMany(dictionary.get(String(model.getAttribute(this.localKey))) ?? [], model);
|
|
9369
|
+
model.setRelation(relation, new Collection(children));
|
|
9117
9370
|
}
|
|
9118
9371
|
return models;
|
|
9119
9372
|
}
|
|
@@ -9222,7 +9475,7 @@ var HasOne = class extends HasOneOrMany {
|
|
|
9222
9475
|
match(models, results, relation) {
|
|
9223
9476
|
const dictionary = this.buildDictionary(results);
|
|
9224
9477
|
for (const model of models) {
|
|
9225
|
-
model.setRelation(relation, dictionary.get(String(model.getAttribute(this.localKey)))?.[0] ?? null);
|
|
9478
|
+
model.setRelation(relation, this.applyInverseRelationToModel(dictionary.get(String(model.getAttribute(this.localKey)))?.[0] ?? null, model));
|
|
9226
9479
|
}
|
|
9227
9480
|
return models;
|
|
9228
9481
|
}
|
|
@@ -9282,6 +9535,7 @@ function methodOf(model, name) {
|
|
|
9282
9535
|
const value2 = Reflect.get(Object.getPrototypeOf(model), name);
|
|
9283
9536
|
return typeof value2 === "function" ? value2 : void 0;
|
|
9284
9537
|
}
|
|
9538
|
+
var serializing = /* @__PURE__ */ new WeakSet();
|
|
9285
9539
|
function serializeDate(date) {
|
|
9286
9540
|
return date.toISOString().replace(/\.(\d{3})Z$/, ".$1000Z");
|
|
9287
9541
|
}
|
|
@@ -9472,6 +9726,14 @@ var Model = class _Model {
|
|
|
9472
9726
|
const query = this.query();
|
|
9473
9727
|
return Reflect.apply(query.where, query, args);
|
|
9474
9728
|
}
|
|
9729
|
+
static when(...args) {
|
|
9730
|
+
const query = this.query();
|
|
9731
|
+
return Reflect.apply(query.when, query, args);
|
|
9732
|
+
}
|
|
9733
|
+
static unless(...args) {
|
|
9734
|
+
const query = this.query();
|
|
9735
|
+
return Reflect.apply(query.unless, query, args);
|
|
9736
|
+
}
|
|
9475
9737
|
static whereKey(id) {
|
|
9476
9738
|
return this.query().whereKey(id);
|
|
9477
9739
|
}
|
|
@@ -9490,6 +9752,13 @@ var Model = class _Model {
|
|
|
9490
9752
|
static whereBetween(column, values) {
|
|
9491
9753
|
return this.query().whereBetween(column, values);
|
|
9492
9754
|
}
|
|
9755
|
+
/** Post.whereLike('title', `%${term}%`): case-insensitive unless caseSensitive (see the query builder's whereLike()). */
|
|
9756
|
+
static whereLike(column, value2, caseSensitive = false) {
|
|
9757
|
+
return this.query().whereLike(column, value2, caseSensitive);
|
|
9758
|
+
}
|
|
9759
|
+
static whereNotLike(column, value2, caseSensitive = false) {
|
|
9760
|
+
return this.query().whereNotLike(column, value2, caseSensitive);
|
|
9761
|
+
}
|
|
9493
9762
|
static whereColumn(first, operatorOrSecond, second) {
|
|
9494
9763
|
return this.query().whereColumn(first, operatorOrSecond, second);
|
|
9495
9764
|
}
|
|
@@ -9675,8 +9944,8 @@ var Model = class _Model {
|
|
|
9675
9944
|
/** Guarded names match case-insensitively: SQLite and MySQL column names are case-insensitive. */
|
|
9676
9945
|
isGuarded(key) {
|
|
9677
9946
|
if (this.guarded.length === 0) return false;
|
|
9678
|
-
const
|
|
9679
|
-
return this.guarded.some((guarded) => guarded === "*" || guarded.toLowerCase() ===
|
|
9947
|
+
const lower2 = key.toLowerCase();
|
|
9948
|
+
return this.guarded.some((guarded) => guarded === "*" || guarded.toLowerCase() === lower2);
|
|
9680
9949
|
}
|
|
9681
9950
|
totallyGuarded() {
|
|
9682
9951
|
return !_Model.isUnguarded() && this.fillable.length === 0 && this.guarded.length === 1 && this.guarded[0] === "*";
|
|
@@ -9722,7 +9991,7 @@ var Model = class _Model {
|
|
|
9722
9991
|
/** Every cast, including the implied ones: the incrementing key (int) and the timestamp columns (datetime). */
|
|
9723
9992
|
getCasts() {
|
|
9724
9993
|
const implied = {};
|
|
9725
|
-
if (this.
|
|
9994
|
+
if (this.getIncrementing()) implied[this.getKeyName()] = this.getKeyType() === "int" ? "int" : "string";
|
|
9726
9995
|
if (this.usesTimestamps()) {
|
|
9727
9996
|
const created = this.getCreatedAtColumn();
|
|
9728
9997
|
const updated = this.getUpdatedAtColumn();
|
|
@@ -9845,6 +10114,29 @@ var Model = class _Model {
|
|
|
9845
10114
|
getIncrementing() {
|
|
9846
10115
|
return this.incrementing;
|
|
9847
10116
|
}
|
|
10117
|
+
/** Whether new rows get unique string ids before `creating` (HasUuids, HasUlids). */
|
|
10118
|
+
usesUniqueIds() {
|
|
10119
|
+
return false;
|
|
10120
|
+
}
|
|
10121
|
+
/** The columns that get a unique id (HasUuids and HasUlids: the primary key). */
|
|
10122
|
+
uniqueIds() {
|
|
10123
|
+
return [];
|
|
10124
|
+
}
|
|
10125
|
+
/** A new unique id (HasUuids: a version 7 UUID; HasUlids: a lower-case ULID). */
|
|
10126
|
+
newUniqueId() {
|
|
10127
|
+
return void 0;
|
|
10128
|
+
}
|
|
10129
|
+
/** Whether a value has the shape of this model's unique ids (HasUuids: a UUID). Any value passes by default. */
|
|
10130
|
+
isValidUniqueId(_value) {
|
|
10131
|
+
return true;
|
|
10132
|
+
}
|
|
10133
|
+
/** Fills each empty unique id column with newUniqueId() (Laravel's setUniqueIds()). */
|
|
10134
|
+
setUniqueIds() {
|
|
10135
|
+
for (const column of this.uniqueIds()) {
|
|
10136
|
+
const value2 = this.getAttribute(column);
|
|
10137
|
+
if (value2 === void 0 || value2 === null || value2 === "") this.setAttribute(column, this.newUniqueId());
|
|
10138
|
+
}
|
|
10139
|
+
}
|
|
9848
10140
|
getKey() {
|
|
9849
10141
|
return this.getAttribute(this.getKeyName());
|
|
9850
10142
|
}
|
|
@@ -9876,11 +10168,13 @@ var Model = class _Model {
|
|
|
9876
10168
|
}
|
|
9877
10169
|
/**
|
|
9878
10170
|
* The model a route parameter value points at: where <field or route key> = value (global scopes apply, so a
|
|
9879
|
-
* soft-deleted row isn't found). A non-numeric value for an integer primary key
|
|
10171
|
+
* soft-deleted row isn't found). A non-numeric value for an integer primary key, or a value that isn't a UUID
|
|
10172
|
+
* (ULID) for a unique id column, finds nothing without a query.
|
|
9880
10173
|
*/
|
|
9881
10174
|
async resolveRouteBinding(value2, field) {
|
|
9882
10175
|
const column = field ?? this.getRouteKeyName();
|
|
9883
|
-
if (column === this.getKeyName() && this.
|
|
10176
|
+
if (column === this.getKeyName() && this.getKeyType() === "int" && !/^-?\d+$/.test(value2)) return void 0;
|
|
10177
|
+
if (this.uniqueIds().includes(column) && !this.isValidUniqueId(value2)) return void 0;
|
|
9884
10178
|
return this.resolveRouteBindingQuery(this.newQuery(), value2, column).first();
|
|
9885
10179
|
}
|
|
9886
10180
|
/** Override to customize the binding query (Laravel's resolveRouteBindingQuery()). */
|
|
@@ -10098,6 +10392,7 @@ var Model = class _Model {
|
|
|
10098
10392
|
if (!this.exists && created && !this.isDirty(created)) this.setAttribute(created, time);
|
|
10099
10393
|
}
|
|
10100
10394
|
async performInsert(query) {
|
|
10395
|
+
if (this.usesUniqueIds()) this.setUniqueIds();
|
|
10101
10396
|
if (await this.fireModelEvent("creating") === false) return false;
|
|
10102
10397
|
if (this.usesTimestamps()) this.updateTimestamps();
|
|
10103
10398
|
const attributes = this.getAttributes();
|
|
@@ -10281,6 +10576,10 @@ var Model = class _Model {
|
|
|
10281
10576
|
if (!instance.getConnectionName()) instance.setConnection(this.getConnectionName());
|
|
10282
10577
|
return instance;
|
|
10283
10578
|
}
|
|
10579
|
+
/** Whether the model has a relation method called `name` (Laravel's isRelation()). */
|
|
10580
|
+
isRelation(name) {
|
|
10581
|
+
return !(name in _Model.prototype) && methodOf(this, name) !== void 0;
|
|
10582
|
+
}
|
|
10284
10583
|
/** Calls the relation method `name` (post.comments()) and checks that it returns a relation. */
|
|
10285
10584
|
getRelationInstance(name) {
|
|
10286
10585
|
if (name in _Model.prototype) throw new RelationNotFoundError(this.constructor.name, name);
|
|
@@ -10375,9 +10674,18 @@ var Model = class _Model {
|
|
|
10375
10674
|
this.appends = [.../* @__PURE__ */ new Set([...this.appends, ...attributes.flat()])];
|
|
10376
10675
|
return this;
|
|
10377
10676
|
}
|
|
10378
|
-
/**
|
|
10677
|
+
/**
|
|
10678
|
+
* Attributes (through accessors and casts, dates as ISO strings), appends and loaded relations, minus hidden ones.
|
|
10679
|
+
* A model met again while its own toArray() runs (a child chaperone() pointed back at it) gives its attributes only.
|
|
10680
|
+
*/
|
|
10379
10681
|
toArray() {
|
|
10380
|
-
|
|
10682
|
+
if (serializing.has(this)) return this.attributesToArray();
|
|
10683
|
+
serializing.add(this);
|
|
10684
|
+
try {
|
|
10685
|
+
return { ...this.attributesToArray(), ...this.relationsToArray() };
|
|
10686
|
+
} finally {
|
|
10687
|
+
serializing.delete(this);
|
|
10688
|
+
}
|
|
10381
10689
|
}
|
|
10382
10690
|
toJSON() {
|
|
10383
10691
|
return this.toArray();
|
|
@@ -10448,6 +10756,118 @@ var Pivot = class extends Model {
|
|
|
10448
10756
|
incrementing = false;
|
|
10449
10757
|
timestamps = false;
|
|
10450
10758
|
};
|
|
10759
|
+
function uniqueStringIds(Base, generate, valid) {
|
|
10760
|
+
return class WithUniqueStringIds extends Base {
|
|
10761
|
+
usesUniqueIds() {
|
|
10762
|
+
return true;
|
|
10763
|
+
}
|
|
10764
|
+
uniqueIds() {
|
|
10765
|
+
return [this.getKeyName()];
|
|
10766
|
+
}
|
|
10767
|
+
newUniqueId() {
|
|
10768
|
+
return generate();
|
|
10769
|
+
}
|
|
10770
|
+
isValidUniqueId(value2) {
|
|
10771
|
+
return valid(value2);
|
|
10772
|
+
}
|
|
10773
|
+
getKeyType() {
|
|
10774
|
+
return this.uniqueIds().includes(this.getKeyName()) ? "string" : super.getKeyType();
|
|
10775
|
+
}
|
|
10776
|
+
getIncrementing() {
|
|
10777
|
+
return this.uniqueIds().includes(this.getKeyName()) ? false : super.getIncrementing();
|
|
10778
|
+
}
|
|
10779
|
+
};
|
|
10780
|
+
}
|
|
10781
|
+
function HasUuids(Base) {
|
|
10782
|
+
return uniqueStringIds(Base, () => Str.uuid7(), Str.isUuid);
|
|
10783
|
+
}
|
|
10784
|
+
function HasUlids(Base) {
|
|
10785
|
+
return uniqueStringIds(Base, () => Str.ulid().toLowerCase(), Str.isUlid);
|
|
10786
|
+
}
|
|
10787
|
+
var DatabaseNotification = class extends HasUuids(Model) {
|
|
10788
|
+
table = "notifications";
|
|
10789
|
+
keyType = "string";
|
|
10790
|
+
incrementing = false;
|
|
10791
|
+
guarded = [];
|
|
10792
|
+
casts = { data: "array", read_at: "datetime" };
|
|
10793
|
+
/** The model the notification was sent to. */
|
|
10794
|
+
notifiable() {
|
|
10795
|
+
return this.morphTo("notifiable");
|
|
10796
|
+
}
|
|
10797
|
+
/** Sets read_at to now and saves, unless it is already read. */
|
|
10798
|
+
async markAsRead() {
|
|
10799
|
+
if (this.unread()) await this.forceFill({ read_at: this.freshTimestamp() }).save();
|
|
10800
|
+
}
|
|
10801
|
+
/** Clears read_at and saves, unless it is already unread. */
|
|
10802
|
+
async markAsUnread() {
|
|
10803
|
+
if (this.read()) await this.forceFill({ read_at: null }).save();
|
|
10804
|
+
}
|
|
10805
|
+
read() {
|
|
10806
|
+
return this.read_at !== null && this.read_at !== void 0;
|
|
10807
|
+
}
|
|
10808
|
+
unread() {
|
|
10809
|
+
return !this.read();
|
|
10810
|
+
}
|
|
10811
|
+
/** `query.read()`: only read notifications. */
|
|
10812
|
+
static scopeRead(query) {
|
|
10813
|
+
return query.whereNotNull("read_at");
|
|
10814
|
+
}
|
|
10815
|
+
/** `query.unread()`: only unread notifications. */
|
|
10816
|
+
static scopeUnread(query) {
|
|
10817
|
+
return query.whereNull("read_at");
|
|
10818
|
+
}
|
|
10819
|
+
};
|
|
10820
|
+
var DatabaseNotificationCollection = class extends Collection {
|
|
10821
|
+
/** Marks every notification as read (one save each, as in Laravel). */
|
|
10822
|
+
async markAsRead() {
|
|
10823
|
+
for (const notification of this.all()) await notification.markAsRead();
|
|
10824
|
+
}
|
|
10825
|
+
/** Marks every notification as unread. */
|
|
10826
|
+
async markAsUnread() {
|
|
10827
|
+
for (const notification of this.all()) await notification.markAsUnread();
|
|
10828
|
+
}
|
|
10829
|
+
};
|
|
10830
|
+
var DatabaseNotificationsRelation = class extends MorphMany {
|
|
10831
|
+
async get() {
|
|
10832
|
+
return new DatabaseNotificationCollection(await this.runSelect());
|
|
10833
|
+
}
|
|
10834
|
+
async getResults() {
|
|
10835
|
+
const key = this.getParentKey();
|
|
10836
|
+
return key === null || key === void 0 ? new DatabaseNotificationCollection() : this.get();
|
|
10837
|
+
}
|
|
10838
|
+
initRelation(models, relation) {
|
|
10839
|
+
for (const model of models) model.setRelation(relation, new DatabaseNotificationCollection());
|
|
10840
|
+
return models;
|
|
10841
|
+
}
|
|
10842
|
+
match(models, results, relation) {
|
|
10843
|
+
const dictionary = this.buildDictionary(results);
|
|
10844
|
+
for (const model of models) {
|
|
10845
|
+
model.setRelation(relation, new DatabaseNotificationCollection(dictionary.get(String(model.getAttribute(this.localKey))) ?? []));
|
|
10846
|
+
}
|
|
10847
|
+
return models;
|
|
10848
|
+
}
|
|
10849
|
+
};
|
|
10850
|
+
function HasDatabaseNotifications(Base) {
|
|
10851
|
+
class WithDatabaseNotifications extends Base {
|
|
10852
|
+
notifications() {
|
|
10853
|
+
const related = this.newRelatedInstance(DatabaseNotification);
|
|
10854
|
+
return new DatabaseNotificationsRelation(
|
|
10855
|
+
related,
|
|
10856
|
+
this,
|
|
10857
|
+
related.qualifyColumn("notifiable_type"),
|
|
10858
|
+
related.qualifyColumn("notifiable_id"),
|
|
10859
|
+
this.getKeyName()
|
|
10860
|
+
).latest();
|
|
10861
|
+
}
|
|
10862
|
+
readNotifications() {
|
|
10863
|
+
return this.notifications().whereNotNull("read_at");
|
|
10864
|
+
}
|
|
10865
|
+
unreadNotifications() {
|
|
10866
|
+
return this.notifications().whereNull("read_at");
|
|
10867
|
+
}
|
|
10868
|
+
}
|
|
10869
|
+
return WithDatabaseNotifications;
|
|
10870
|
+
}
|
|
10451
10871
|
var Migration = class {
|
|
10452
10872
|
/** The connection to run on (default: the default connection). */
|
|
10453
10873
|
connection = void 0;
|
|
@@ -10858,7 +11278,7 @@ var TypeGenerator = class {
|
|
|
10858
11278
|
}
|
|
10859
11279
|
};
|
|
10860
11280
|
var text = (value2) => typeof value2 === "string" && value2 !== "" ? value2 : void 0;
|
|
10861
|
-
var
|
|
11281
|
+
var list2 = (value2) => Array.isArray(value2) ? value2.map(String) : text(value2) ? [String(value2)] : [];
|
|
10862
11282
|
var integer = (value2) => {
|
|
10863
11283
|
const number3 = Number(value2 ?? 0);
|
|
10864
11284
|
return Number.isInteger(number3) && number3 > 0 ? number3 : 0;
|
|
@@ -10874,7 +11294,7 @@ function confirmToProceed(context, command) {
|
|
|
10874
11294
|
return false;
|
|
10875
11295
|
}
|
|
10876
11296
|
function migrationPaths(context, command) {
|
|
10877
|
-
const paths =
|
|
11297
|
+
const paths = list2(command.option("path"));
|
|
10878
11298
|
if (!paths.length) return [context.app.databasePath("migrations")];
|
|
10879
11299
|
return paths.map((path) => isAbsolute(path) ? path : context.app.basePath(path));
|
|
10880
11300
|
}
|
|
@@ -10897,6 +11317,11 @@ async function generateModelTypes(context) {
|
|
|
10897
11317
|
await new TypeGenerator({ outputFile, importSource: context.typesImportSource }).write((await context.models()).all());
|
|
10898
11318
|
return relative2(context.app.basePath(), outputFile);
|
|
10899
11319
|
}
|
|
11320
|
+
async function writeModelTypes(context, command) {
|
|
11321
|
+
if (context.app.isProduction() || !existsSync4(context.app.basePath("types"))) return;
|
|
11322
|
+
const written = await generateModelTypes(context);
|
|
11323
|
+
if (written) command.line(`Model types written to ${written}.`);
|
|
11324
|
+
}
|
|
10900
11325
|
async function seedIfRequested(context, command) {
|
|
10901
11326
|
const seeder = text(command.option("seeder"));
|
|
10902
11327
|
if (command.option("seed") !== true && seeder === void 0) return;
|
|
@@ -10908,10 +11333,7 @@ function registerMigrationCommands(kernel, context) {
|
|
|
10908
11333
|
if (!confirmToProceed(context, command)) return 1;
|
|
10909
11334
|
await migrator(context, command).run(migrationPaths(context, command), { step: command.option("step") === true });
|
|
10910
11335
|
await seedIfRequested(context, command);
|
|
10911
|
-
|
|
10912
|
-
const written = await generateModelTypes(context);
|
|
10913
|
-
if (written) command.line(`Model types written to ${written}.`);
|
|
10914
|
-
}
|
|
11336
|
+
await writeModelTypes(context, command);
|
|
10915
11337
|
return 0;
|
|
10916
11338
|
});
|
|
10917
11339
|
define(kernel, "migrate:install {--database=}", "Create the migration repository", async (command) => {
|
|
@@ -10942,12 +11364,14 @@ function registerMigrationCommands(kernel, context) {
|
|
|
10942
11364
|
else await instance.reset(paths);
|
|
10943
11365
|
await instance.run(paths);
|
|
10944
11366
|
await seedIfRequested(context, command);
|
|
11367
|
+
await writeModelTypes(context, command);
|
|
10945
11368
|
return 0;
|
|
10946
11369
|
});
|
|
10947
11370
|
define(kernel, "migrate:fresh {--database=} {--force} {--path=*} {--seed} {--seeder=}", "Drop all tables and re-run all migrations", async (command) => {
|
|
10948
11371
|
if (!confirmToProceed(context, command)) return 1;
|
|
10949
11372
|
await migrator(context, command).fresh(migrationPaths(context, command));
|
|
10950
11373
|
await seedIfRequested(context, command);
|
|
11374
|
+
await writeModelTypes(context, command);
|
|
10951
11375
|
return 0;
|
|
10952
11376
|
});
|
|
10953
11377
|
define(kernel, "migrate:status {--database=} {--path=*}", "Show the status of each migration", async (command) => {
|
|
@@ -11462,9 +11886,21 @@ function currentRequest2() {
|
|
|
11462
11886
|
return void 0;
|
|
11463
11887
|
}
|
|
11464
11888
|
}
|
|
11889
|
+
function paginationState() {
|
|
11890
|
+
const container = currentContainer();
|
|
11891
|
+
if (!container?.bound(PaginationState)) return void 0;
|
|
11892
|
+
try {
|
|
11893
|
+
return container.make(PaginationState);
|
|
11894
|
+
} catch (error) {
|
|
11895
|
+
if (error instanceof BindingResolutionError) return void 0;
|
|
11896
|
+
throw error;
|
|
11897
|
+
}
|
|
11898
|
+
}
|
|
11465
11899
|
function usePaginationResolvers() {
|
|
11466
|
-
AbstractPaginator.currentPathResolver = () => currentRequest2()?.url() ?? "/";
|
|
11900
|
+
AbstractPaginator.currentPathResolver = () => paginationState()?.currentPath() ?? currentRequest2()?.url() ?? "/";
|
|
11467
11901
|
AbstractPaginator.currentPageResolver = (pageName) => {
|
|
11902
|
+
const state = paginationState()?.currentPage(pageName);
|
|
11903
|
+
if (state !== void 0) return state;
|
|
11468
11904
|
const page = Number(currentRequest2()?.input(pageName));
|
|
11469
11905
|
return Number.isInteger(page) && page >= 1 ? page : 1;
|
|
11470
11906
|
};
|
|
@@ -11713,8 +12149,8 @@ function decrypt(payload, unserialize = true) {
|
|
|
11713
12149
|
return inject(Encrypter).decrypt(payload, unserialize);
|
|
11714
12150
|
}
|
|
11715
12151
|
function previousKeys(value2) {
|
|
11716
|
-
const
|
|
11717
|
-
return
|
|
12152
|
+
const list4 = Array.isArray(value2) ? value2 : typeof value2 === "string" ? value2.split(",") : [];
|
|
12153
|
+
return list4.map((key) => String(key).trim()).filter((key) => key !== "");
|
|
11718
12154
|
}
|
|
11719
12155
|
var EncryptionServiceProvider = class extends ServiceProvider {
|
|
11720
12156
|
register() {
|
|
@@ -11846,8 +12282,8 @@ var SHOULD_QUEUE22 = /* @__PURE__ */ Symbol.for("oriel:bus.shouldQueue");
|
|
|
11846
12282
|
var QUEUE_OPTION_KEYS = ["connection", "queue", "delay", "tries", "backoff", "timeout"];
|
|
11847
12283
|
function isQueueableListener(cls, instance) {
|
|
11848
12284
|
const members = instance;
|
|
11849
|
-
if (members[SHOULD_QUEUE22] === true) return true;
|
|
11850
12285
|
const statics = cls;
|
|
12286
|
+
if (members.shouldQueue === true || statics.shouldQueue === true || members[SHOULD_QUEUE22] === true) return true;
|
|
11851
12287
|
if (QUEUE_OPTION_KEYS.some((key) => members[key] !== void 0 || statics[key] !== void 0)) return true;
|
|
11852
12288
|
return typeof members.uniqueId === "function" || typeof members.retryUntil === "function" || typeof statics.uniqueId === "function" || typeof statics.retryUntil === "function";
|
|
11853
12289
|
}
|
|
@@ -11892,9 +12328,9 @@ var Dispatcher2 = class {
|
|
|
11892
12328
|
throw new InvalidListenerError(label);
|
|
11893
12329
|
}
|
|
11894
12330
|
for (const event2 of Array.isArray(events) ? events : [events]) {
|
|
11895
|
-
const
|
|
11896
|
-
|
|
11897
|
-
this.listeners.set(event2,
|
|
12331
|
+
const list4 = this.listeners.get(event2) ?? [];
|
|
12332
|
+
list4.push(listener);
|
|
12333
|
+
this.listeners.set(event2, list4);
|
|
11898
12334
|
}
|
|
11899
12335
|
}
|
|
11900
12336
|
hasListeners(event2) {
|
|
@@ -11904,10 +12340,14 @@ var Dispatcher2 = class {
|
|
|
11904
12340
|
forget(event2) {
|
|
11905
12341
|
this.listeners.delete(event2);
|
|
11906
12342
|
}
|
|
12343
|
+
/** Laravel's getRawListeners(): each event's listeners as registered (closures, classes, [class, method]). A copy. */
|
|
12344
|
+
getRawListeners() {
|
|
12345
|
+
return new Map([...this.listeners].map(([event2, list4]) => [event2, [...list4]]));
|
|
12346
|
+
}
|
|
11907
12347
|
/** Introspection for the event:list command. Not part of the EventDispatcher contract. */
|
|
11908
12348
|
registeredEvents() {
|
|
11909
12349
|
const rows = [];
|
|
11910
|
-
for (const [key,
|
|
12350
|
+
for (const [key, list4] of this.listeners) rows.push({ event: nameOf(key), listeners: list4.length });
|
|
11911
12351
|
return rows.sort((a, b) => a.event.localeCompare(b.event));
|
|
11912
12352
|
}
|
|
11913
12353
|
subscribe(subscriber) {
|
|
@@ -11951,8 +12391,8 @@ var Dispatcher2 = class {
|
|
|
11951
12391
|
const exact = [...this.listeners.get(key) ?? []];
|
|
11952
12392
|
const wildcardLists = typeof key === "string" ? this.wildcardPatternsFor(key).map((pattern) => [...this.listeners.get(pattern) ?? []]) : [];
|
|
11953
12393
|
for (const listener of exact) yield { listener, wildcard: false };
|
|
11954
|
-
for (const
|
|
11955
|
-
for (const listener of
|
|
12394
|
+
for (const list4 of wildcardLists) {
|
|
12395
|
+
for (const listener of list4) yield { listener, wildcard: true };
|
|
11956
12396
|
}
|
|
11957
12397
|
}
|
|
11958
12398
|
wildcardPatternsFor(event2) {
|
|
@@ -12039,6 +12479,7 @@ import { dirname as dirname4, extname as extname2, resolve as resolve2 } from "p
|
|
|
12039
12479
|
import { Readable } from "stream";
|
|
12040
12480
|
import { pipeline } from "stream/promises";
|
|
12041
12481
|
import { resolve, sep as sep3 } from "path";
|
|
12482
|
+
import { posix } from "path";
|
|
12042
12483
|
import {
|
|
12043
12484
|
CopyObjectCommand,
|
|
12044
12485
|
DeleteObjectCommand,
|
|
@@ -12109,24 +12550,54 @@ var MIME_TYPES = {
|
|
|
12109
12550
|
zip: "application/zip",
|
|
12110
12551
|
gz: "application/gzip",
|
|
12111
12552
|
tar: "application/x-tar",
|
|
12553
|
+
"7z": "application/x-7z-compressed",
|
|
12554
|
+
rar: "application/vnd.rar",
|
|
12555
|
+
epub: "application/epub+zip",
|
|
12556
|
+
rtf: "application/rtf",
|
|
12557
|
+
doc: "application/msword",
|
|
12558
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
12559
|
+
xls: "application/vnd.ms-excel",
|
|
12560
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
12561
|
+
ppt: "application/vnd.ms-powerpoint",
|
|
12562
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
12563
|
+
odt: "application/vnd.oasis.opendocument.text",
|
|
12564
|
+
ods: "application/vnd.oasis.opendocument.spreadsheet",
|
|
12565
|
+
odp: "application/vnd.oasis.opendocument.presentation",
|
|
12112
12566
|
png: "image/png",
|
|
12113
12567
|
jpg: "image/jpeg",
|
|
12114
12568
|
jpeg: "image/jpeg",
|
|
12115
12569
|
gif: "image/gif",
|
|
12116
12570
|
webp: "image/webp",
|
|
12571
|
+
avif: "image/avif",
|
|
12117
12572
|
svg: "image/svg+xml",
|
|
12118
12573
|
ico: "image/x-icon",
|
|
12119
12574
|
bmp: "image/bmp",
|
|
12575
|
+
tif: "image/tiff",
|
|
12576
|
+
tiff: "image/tiff",
|
|
12577
|
+
heic: "image/heic",
|
|
12578
|
+
heif: "image/heif",
|
|
12120
12579
|
mp3: "audio/mpeg",
|
|
12580
|
+
m4a: "audio/mp4",
|
|
12121
12581
|
wav: "audio/wav",
|
|
12582
|
+
ogg: "audio/ogg",
|
|
12583
|
+
oga: "audio/ogg",
|
|
12584
|
+
opus: "audio/ogg",
|
|
12585
|
+
flac: "audio/flac",
|
|
12586
|
+
aac: "audio/aac",
|
|
12122
12587
|
mp4: "video/mp4",
|
|
12588
|
+
mov: "video/quicktime",
|
|
12123
12589
|
webm: "video/webm",
|
|
12590
|
+
ogv: "video/ogg",
|
|
12591
|
+
avi: "video/x-msvideo",
|
|
12124
12592
|
woff: "font/woff",
|
|
12125
12593
|
woff2: "font/woff2",
|
|
12126
|
-
ttf: "font/ttf"
|
|
12594
|
+
ttf: "font/ttf",
|
|
12595
|
+
otf: "font/otf",
|
|
12596
|
+
wasm: "application/wasm"
|
|
12127
12597
|
};
|
|
12128
12598
|
function mimeFromExtension(extension) {
|
|
12129
|
-
|
|
12599
|
+
const key = extension.replace(/^\./, "").toLowerCase();
|
|
12600
|
+
return Object.hasOwn(MIME_TYPES, key) ? MIME_TYPES[key] : void 0;
|
|
12130
12601
|
}
|
|
12131
12602
|
function resolveDiskPath(root, path) {
|
|
12132
12603
|
const resolvedRoot = resolve(root);
|
|
@@ -12206,7 +12677,7 @@ var LocalFilesystem = class {
|
|
|
12206
12677
|
async putFileAs(directory, file, name, options) {
|
|
12207
12678
|
const path = joinDiskPath(directory, name);
|
|
12208
12679
|
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
12209
|
-
await this.put(path, bytes,
|
|
12680
|
+
await this.put(path, bytes, options);
|
|
12210
12681
|
return path;
|
|
12211
12682
|
}
|
|
12212
12683
|
async delete(paths) {
|
|
@@ -12371,27 +12842,37 @@ var S3Filesystem = class {
|
|
|
12371
12842
|
const response2 = await this.getObject(path);
|
|
12372
12843
|
return response2.Body.transformToWebStream();
|
|
12373
12844
|
}
|
|
12845
|
+
/** Sends the type of the path when the options name none (Laravel's S3 adapter detects one too). */
|
|
12374
12846
|
async put(path, contents, options) {
|
|
12375
12847
|
const body = contents instanceof ReadableStream ? await collectStream(contents) : contents;
|
|
12376
|
-
await this.
|
|
12377
|
-
new PutObjectCommand({
|
|
12378
|
-
Bucket: this.config.bucket,
|
|
12379
|
-
Key: path,
|
|
12380
|
-
Body: body,
|
|
12381
|
-
ContentType: options?.mimeType,
|
|
12382
|
-
ACL: options?.visibility === "public" ? "public-read" : void 0
|
|
12383
|
-
})
|
|
12384
|
-
);
|
|
12848
|
+
await this.putObject(path, body, options?.mimeType ?? mimeFromExtension(posix.extname(path)), options);
|
|
12385
12849
|
return true;
|
|
12386
12850
|
}
|
|
12387
12851
|
async putFile(directory, file, options) {
|
|
12388
12852
|
return this.putFileAs(directory, file, uniqueFileName(file.extension()), options);
|
|
12389
12853
|
}
|
|
12854
|
+
/**
|
|
12855
|
+
* Sends the upload's own type: its extension(), which follows what a request upload's bytes show (the client's claim
|
|
12856
|
+
* counts only where extension() keeps it). Never the MIME type the client sent as such, nor the name it is stored
|
|
12857
|
+
* under (an app may name it after the client's file name): S3, or a CDN in front of it, serves the object with this
|
|
12858
|
+
* type. An upload of no known type is sent with none (served as binary).
|
|
12859
|
+
*/
|
|
12390
12860
|
async putFileAs(directory, file, name, options) {
|
|
12391
12861
|
const path = joinDiskPath(directory, name);
|
|
12392
|
-
await this.
|
|
12862
|
+
await this.putObject(path, new Uint8Array(await file.arrayBuffer()), options?.mimeType ?? mimeFromExtension(file.extension()), options);
|
|
12393
12863
|
return path;
|
|
12394
12864
|
}
|
|
12865
|
+
async putObject(path, body, contentType, options) {
|
|
12866
|
+
await this.client.send(
|
|
12867
|
+
new PutObjectCommand({
|
|
12868
|
+
Bucket: this.config.bucket,
|
|
12869
|
+
Key: path,
|
|
12870
|
+
Body: body,
|
|
12871
|
+
ContentType: contentType,
|
|
12872
|
+
ACL: options?.visibility === "public" ? "public-read" : void 0
|
|
12873
|
+
})
|
|
12874
|
+
);
|
|
12875
|
+
}
|
|
12395
12876
|
async delete(paths) {
|
|
12396
12877
|
for (const path of Array.isArray(paths) ? paths : [paths]) {
|
|
12397
12878
|
await this.client.send(new DeleteObjectCommand({ Bucket: this.config.bucket, Key: path }));
|
|
@@ -13814,8 +14295,8 @@ var InertiaMiddleware = class {
|
|
|
13814
14295
|
bag,
|
|
13815
14296
|
Object.fromEntries(
|
|
13816
14297
|
Object.entries(fields ?? {}).map(([field, messages]) => {
|
|
13817
|
-
const
|
|
13818
|
-
return [field, this.withAllErrors ?
|
|
14298
|
+
const list4 = Array.isArray(messages) ? messages.map(String) : [String(messages)];
|
|
14299
|
+
return [field, this.withAllErrors ? list4 : list4[0] ?? ""];
|
|
13819
14300
|
})
|
|
13820
14301
|
)
|
|
13821
14302
|
])
|
|
@@ -14422,6 +14903,42 @@ var DailyRotatingStream = class extends Writable {
|
|
|
14422
14903
|
stream.end();
|
|
14423
14904
|
}
|
|
14424
14905
|
};
|
|
14906
|
+
function destinationCloser(destination) {
|
|
14907
|
+
const opened = new Promise((resolve3) => {
|
|
14908
|
+
const onReady = () => {
|
|
14909
|
+
destination.off("error", onError);
|
|
14910
|
+
resolve3(true);
|
|
14911
|
+
};
|
|
14912
|
+
const onError = () => {
|
|
14913
|
+
destination.off("ready", onReady);
|
|
14914
|
+
destination.flushSync = () => {
|
|
14915
|
+
};
|
|
14916
|
+
resolve3(false);
|
|
14917
|
+
};
|
|
14918
|
+
destination.once("ready", onReady);
|
|
14919
|
+
destination.once("error", onError);
|
|
14920
|
+
});
|
|
14921
|
+
let closing;
|
|
14922
|
+
const close = async () => {
|
|
14923
|
+
if (!await opened) return;
|
|
14924
|
+
await new Promise((resolve3) => {
|
|
14925
|
+
destination.once("close", () => resolve3());
|
|
14926
|
+
destination.once("error", () => resolve3());
|
|
14927
|
+
destination.end();
|
|
14928
|
+
});
|
|
14929
|
+
};
|
|
14930
|
+
return () => closing ??= close();
|
|
14931
|
+
}
|
|
14932
|
+
function writableCloser(stream) {
|
|
14933
|
+
let closing;
|
|
14934
|
+
const close = () => new Promise((resolve3) => {
|
|
14935
|
+
if (stream.writableFinished || stream.destroyed) return resolve3();
|
|
14936
|
+
stream.once("finish", () => resolve3());
|
|
14937
|
+
stream.once("error", () => resolve3());
|
|
14938
|
+
stream.end();
|
|
14939
|
+
});
|
|
14940
|
+
return () => closing ??= close();
|
|
14941
|
+
}
|
|
14425
14942
|
var PINO_METHOD = {
|
|
14426
14943
|
emergency: "fatal",
|
|
14427
14944
|
alert: "fatal",
|
|
@@ -14433,12 +14950,25 @@ var PINO_METHOD = {
|
|
|
14433
14950
|
debug: "debug"
|
|
14434
14951
|
};
|
|
14435
14952
|
var PinoLogger = class extends BaseLogger {
|
|
14436
|
-
constructor(pinoInstance, minimumLevel = "debug") {
|
|
14953
|
+
constructor(pinoInstance, minimumLevel = "debug", closeDestination = async () => {
|
|
14954
|
+
}) {
|
|
14437
14955
|
super(minimumLevel);
|
|
14438
14956
|
this.pinoInstance = pinoInstance;
|
|
14957
|
+
this.closeDestination = closeDestination;
|
|
14439
14958
|
}
|
|
14440
14959
|
pinoInstance;
|
|
14960
|
+
closeDestination;
|
|
14961
|
+
flushing;
|
|
14962
|
+
/**
|
|
14963
|
+
* Writes out every entry still buffered and closes the destination. pino writes asynchronously, so a process
|
|
14964
|
+
* awaits this before it exits (runConsoleAndExit does). The channel takes no entries afterwards: they're dropped.
|
|
14965
|
+
* Not in Laravel, whose handlers write synchronously.
|
|
14966
|
+
*/
|
|
14967
|
+
flush() {
|
|
14968
|
+
return this.flushing ??= this.closeDestination();
|
|
14969
|
+
}
|
|
14441
14970
|
write(level2, message, context) {
|
|
14971
|
+
if (this.flushing) return;
|
|
14442
14972
|
this.pinoInstance[PINO_METHOD[level2]]({ ...context, rfc5424Level: level2 }, message);
|
|
14443
14973
|
}
|
|
14444
14974
|
};
|
|
@@ -14447,19 +14977,19 @@ function createSingleChannel(path, minimumLevel = "debug") {
|
|
|
14447
14977
|
assertLogLevel(minimumLevel);
|
|
14448
14978
|
const destination = pino2.destination({ dest: path, mkdir: true, sync: false });
|
|
14449
14979
|
destination.on("error", (error) => reportLogWriteFailure(path, error));
|
|
14450
|
-
return new PinoLogger(pino2(PINO_OPTIONS, destination), minimumLevel);
|
|
14980
|
+
return new PinoLogger(pino2(PINO_OPTIONS, destination), minimumLevel, destinationCloser(destination));
|
|
14451
14981
|
}
|
|
14452
14982
|
function createDailyChannel(path, days = 14, minimumLevel = "debug", now5) {
|
|
14453
14983
|
assertLogLevel(minimumLevel);
|
|
14454
14984
|
const stream = new DailyRotatingStream(path, days, now5);
|
|
14455
|
-
return new PinoLogger(pino2(PINO_OPTIONS, stream), minimumLevel);
|
|
14985
|
+
return new PinoLogger(pino2(PINO_OPTIONS, stream), minimumLevel, writableCloser(stream));
|
|
14456
14986
|
}
|
|
14457
14987
|
function createStderrChannel(minimumLevel = "debug") {
|
|
14458
14988
|
assertLogLevel(minimumLevel);
|
|
14459
14989
|
const destination = pino2.destination({ dest: 2, sync: false });
|
|
14460
14990
|
destination.on("error", () => {
|
|
14461
14991
|
});
|
|
14462
|
-
return new PinoLogger(pino2(PINO_OPTIONS, destination), minimumLevel);
|
|
14992
|
+
return new PinoLogger(pino2(PINO_OPTIONS, destination), minimumLevel, destinationCloser(destination));
|
|
14463
14993
|
}
|
|
14464
14994
|
var Log = facade(LogManager);
|
|
14465
14995
|
function logger(message, context) {
|
|
@@ -14509,6 +15039,7 @@ var StackLogger = class {
|
|
|
14509
15039
|
return this;
|
|
14510
15040
|
}
|
|
14511
15041
|
};
|
|
15042
|
+
var isFlushable = (channel) => typeof channel.flush === "function";
|
|
14512
15043
|
var level = (config2) => config2.level ?? "debug";
|
|
14513
15044
|
var LogManager2 = class {
|
|
14514
15045
|
constructor(container) {
|
|
@@ -14550,6 +15081,16 @@ var LogManager2 = class {
|
|
|
14550
15081
|
stack(channels) {
|
|
14551
15082
|
return new StackLogger(channels.map((name) => this.channel(name)));
|
|
14552
15083
|
}
|
|
15084
|
+
/**
|
|
15085
|
+
* Writes out and closes every channel resolved so far, then forgets them, so the next entry opens its file again.
|
|
15086
|
+
* pino writes asynchronously, so a console process awaits this before it exits (runConsoleAndExit does). Not in
|
|
15087
|
+
* Laravel, whose handlers write synchronously.
|
|
15088
|
+
*/
|
|
15089
|
+
async flush() {
|
|
15090
|
+
const channels = [...this.channels.values()];
|
|
15091
|
+
this.channels.clear();
|
|
15092
|
+
await Promise.all(channels.filter(isFlushable).map((channel) => channel.flush()));
|
|
15093
|
+
}
|
|
14553
15094
|
log(logLevel, message, context) {
|
|
14554
15095
|
this.channel().log(logLevel, message, context);
|
|
14555
15096
|
}
|
|
@@ -14667,8 +15208,8 @@ function normalizeAddress(recipient) {
|
|
|
14667
15208
|
}
|
|
14668
15209
|
function normalizeAddresses(recipients) {
|
|
14669
15210
|
if (recipients === void 0) return [];
|
|
14670
|
-
const
|
|
14671
|
-
return
|
|
15211
|
+
const list4 = Array.isArray(recipients) ? recipients : [recipients];
|
|
15212
|
+
return list4.map(normalizeAddress);
|
|
14672
15213
|
}
|
|
14673
15214
|
function formatAddress(address) {
|
|
14674
15215
|
return address.name ? `${address.name} <${address.address}>` : address.address;
|
|
@@ -14837,7 +15378,7 @@ var Mailable = class {
|
|
|
14837
15378
|
var SHOULD_QUEUE4 = /* @__PURE__ */ Symbol.for("oriel:bus.shouldQueue");
|
|
14838
15379
|
function isQueueableMailable(mailable) {
|
|
14839
15380
|
const record = mailable;
|
|
14840
|
-
if (record[SHOULD_QUEUE4] === true) return true;
|
|
15381
|
+
if (record.shouldQueue === true || record[SHOULD_QUEUE4] === true) return true;
|
|
14841
15382
|
return record.connection !== void 0 || record.queue !== void 0 || record.delay !== void 0 || record.tries !== void 0 || record.backoff !== void 0 || record.timeout !== void 0 || typeof record.uniqueId === "function" || typeof record.retryUntil === "function";
|
|
14842
15383
|
}
|
|
14843
15384
|
var MailerImpl = class {
|
|
@@ -14926,6 +15467,9 @@ var PendingMail = class {
|
|
|
14926
15467
|
async send(mailable) {
|
|
14927
15468
|
return this.mailer.send(mailable, this.overrides());
|
|
14928
15469
|
}
|
|
15470
|
+
async sendNow(mailable) {
|
|
15471
|
+
return this.mailer.sendNow(mailable, this.overrides());
|
|
15472
|
+
}
|
|
14929
15473
|
async queue(mailable) {
|
|
14930
15474
|
await this.mailer.queue(mailable, this.overrides());
|
|
14931
15475
|
}
|
|
@@ -15049,9 +15593,9 @@ var MailManager2 = class {
|
|
|
15049
15593
|
async queue(mailable) {
|
|
15050
15594
|
await this.mailer().queue(mailable);
|
|
15051
15595
|
}
|
|
15052
|
-
/**
|
|
15053
|
-
async sendNow(
|
|
15054
|
-
return this.mailer(
|
|
15596
|
+
/** Sends through the default mailer at once, even when the mailable is queueable (Laravel's Mail::sendNow()). */
|
|
15597
|
+
async sendNow(mailable) {
|
|
15598
|
+
return this.mailer().sendNow(mailable);
|
|
15055
15599
|
}
|
|
15056
15600
|
extend(transport, factory) {
|
|
15057
15601
|
this.drivers.set(transport, factory);
|
|
@@ -15074,7 +15618,10 @@ var MailServiceProvider = class extends ServiceProvider {
|
|
|
15074
15618
|
"mail"
|
|
15075
15619
|
);
|
|
15076
15620
|
this.app.singleton(MailManager, (container) => new MailManager2(container));
|
|
15077
|
-
this.app.singleton(QueuedMailSender, (container) =>
|
|
15621
|
+
this.app.singleton(QueuedMailSender, (container) => {
|
|
15622
|
+
const manager2 = container.make(MailManager);
|
|
15623
|
+
return { sendNow: (mailerName, mailable, overrides) => manager2.mailer(mailerName).sendNow(mailable, overrides) };
|
|
15624
|
+
});
|
|
15078
15625
|
this.app.make(ClassRegistry).register(SendQueuedMailable, "Mail.SendQueuedMailable");
|
|
15079
15626
|
}
|
|
15080
15627
|
};
|
|
@@ -15281,51 +15828,14 @@ var MailNotificationChannel = class {
|
|
|
15281
15828
|
const mailable = isMailable(result) ? result : mailableFromMessage(toMailMessage(result, notification.constructor.name), to);
|
|
15282
15829
|
const container = currentContainer();
|
|
15283
15830
|
if (!container?.bound(MailManager)) throw new MailUnavailableError();
|
|
15284
|
-
await container.make(MailManager).
|
|
15831
|
+
await container.make(MailManager).sendNow(mailable);
|
|
15285
15832
|
}
|
|
15286
15833
|
};
|
|
15287
15834
|
var NOTIFICATIONS_TABLE = "notifications";
|
|
15288
|
-
|
|
15289
|
-
function parseStoredDate2(value2) {
|
|
15290
|
-
if (value2 instanceof Date) return value2;
|
|
15291
|
-
if (typeof value2 === "number") return new Date(value2);
|
|
15292
|
-
const text3 = String(value2);
|
|
15293
|
-
return ZONELESS_TIMESTAMP.test(text3) ? /* @__PURE__ */ new Date(`${text3.replace(" ", "T")}Z`) : new Date(text3);
|
|
15294
|
-
}
|
|
15295
|
-
function wrapRow(row, db) {
|
|
15296
|
-
const record = {
|
|
15297
|
-
id: String(row.id),
|
|
15298
|
-
type: String(row.type),
|
|
15299
|
-
data: JSON.parse(String(row.data)),
|
|
15300
|
-
createdAt: parseStoredDate2(row.created_at),
|
|
15301
|
-
updatedAt: parseStoredDate2(row.updated_at),
|
|
15302
|
-
readAt: row.read_at ? parseStoredDate2(row.read_at) : void 0,
|
|
15303
|
-
async markAsRead() {
|
|
15304
|
-
if (record.readAt) return;
|
|
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;
|
|
15308
|
-
},
|
|
15309
|
-
async markAsUnread() {
|
|
15310
|
-
if (!record.readAt) return;
|
|
15311
|
-
await db.table(NOTIFICATIONS_TABLE).where("id", record.id).update({ read_at: null, updated_at: /* @__PURE__ */ new Date() });
|
|
15312
|
-
record.readAt = void 0;
|
|
15313
|
-
}
|
|
15314
|
-
};
|
|
15315
|
-
return record;
|
|
15316
|
-
}
|
|
15317
|
-
function requireDatabase() {
|
|
15835
|
+
function requireDatabase(connection) {
|
|
15318
15836
|
const container = currentContainer();
|
|
15319
15837
|
if (!container?.bound(DatabaseManager)) throw new DatabaseUnavailableError();
|
|
15320
|
-
return container.make(DatabaseManager).connection();
|
|
15321
|
-
}
|
|
15322
|
-
async function fetchNotifications(notifiableType, notifiableId, filter = "all") {
|
|
15323
|
-
const db = requireDatabase();
|
|
15324
|
-
let query = db.table(NOTIFICATIONS_TABLE).where("notifiable_type", notifiableType).where("notifiable_id", notifiableId).orderBy("created_at", "desc");
|
|
15325
|
-
if (filter === "unread") query = query.whereNull("read_at");
|
|
15326
|
-
if (filter === "read") query = query.whereNotNull("read_at");
|
|
15327
|
-
const rows = await query.get();
|
|
15328
|
-
return rows.all().map((row) => wrapRow(row, db));
|
|
15838
|
+
return container.make(DatabaseManager).connection(connection);
|
|
15329
15839
|
}
|
|
15330
15840
|
var DatabaseNotificationChannel = class {
|
|
15331
15841
|
async send(notifiable, notification) {
|
|
@@ -15335,12 +15845,12 @@ var DatabaseNotificationChannel = class {
|
|
|
15335
15845
|
const data = notification.toDatabase ? notification.toDatabase(notifiable) : notification.toArray(notifiable);
|
|
15336
15846
|
const model = notifiable;
|
|
15337
15847
|
if (typeof model.getKey !== "function") throw new NotDatabaseNotifiableError(notifiable.constructor.name);
|
|
15338
|
-
const db = requireDatabase();
|
|
15848
|
+
const db = requireDatabase(typeof model.getConnectionName === "function" ? model.getConnectionName() : void 0);
|
|
15339
15849
|
const now5 = /* @__PURE__ */ new Date();
|
|
15340
15850
|
await db.table(NOTIFICATIONS_TABLE).insert({
|
|
15341
15851
|
id: notification.id ?? randomUUID4(),
|
|
15342
15852
|
type: notification.constructor.name,
|
|
15343
|
-
notifiable_type: notifiable.constructor.name,
|
|
15853
|
+
notifiable_type: typeof model.getMorphClass === "function" ? model.getMorphClass() : notifiable.constructor.name,
|
|
15344
15854
|
notifiable_id: model.getKey(),
|
|
15345
15855
|
data: JSON.stringify(data),
|
|
15346
15856
|
read_at: null,
|
|
@@ -15374,13 +15884,8 @@ function resolveDispatcher() {
|
|
|
15374
15884
|
if (!container?.bound(NotificationDispatcher)) throw new NotificationDispatcherUnavailableError();
|
|
15375
15885
|
return container.make(NotificationDispatcher);
|
|
15376
15886
|
}
|
|
15377
|
-
function
|
|
15378
|
-
|
|
15379
|
-
if (typeof model.getKey !== "function") throw new NotDatabaseNotifiableError(instance.constructor.name);
|
|
15380
|
-
return model.getKey();
|
|
15381
|
-
}
|
|
15382
|
-
function Notifiable(Base) {
|
|
15383
|
-
return class NotifiableMixin extends Base {
|
|
15887
|
+
function RoutesNotifications(Base) {
|
|
15888
|
+
return class RoutesNotificationsMixin extends Base {
|
|
15384
15889
|
routeNotificationFor(channel, notification) {
|
|
15385
15890
|
const custom = this[`routeNotificationFor${Str.studly(channel)}`];
|
|
15386
15891
|
if (typeof custom === "function") return custom.call(this, notification);
|
|
@@ -15397,15 +15902,6 @@ function Notifiable(Base) {
|
|
|
15397
15902
|
async notifyNow(notification, channels) {
|
|
15398
15903
|
await resolveDispatcher().sendNow(this, notification, channels);
|
|
15399
15904
|
}
|
|
15400
|
-
notifications() {
|
|
15401
|
-
return fetchNotifications(this.constructor.name, requireKey(this));
|
|
15402
|
-
}
|
|
15403
|
-
unreadNotifications() {
|
|
15404
|
-
return fetchNotifications(this.constructor.name, requireKey(this), "unread");
|
|
15405
|
-
}
|
|
15406
|
-
readNotifications() {
|
|
15407
|
-
return fetchNotifications(this.constructor.name, requireKey(this), "read");
|
|
15408
|
-
}
|
|
15409
15905
|
};
|
|
15410
15906
|
}
|
|
15411
15907
|
var AnonymousNotifiable = class {
|
|
@@ -15475,7 +15971,7 @@ var SendQueuedNotifications = class {
|
|
|
15475
15971
|
SendQueuedNotifications.prototype[SHOULD_QUEUE5] = true;
|
|
15476
15972
|
function isQueueableNotification(notification) {
|
|
15477
15973
|
const record = notification;
|
|
15478
|
-
if (record[SHOULD_QUEUE5] === true) return true;
|
|
15974
|
+
if (record.shouldQueue === true || record[SHOULD_QUEUE5] === true) return true;
|
|
15479
15975
|
return record.connection !== void 0 || record.queue !== void 0 || record.delay !== void 0 || record.tries !== void 0 || record.backoff !== void 0 || record.timeout !== void 0 || typeof record.uniqueId === "function" || typeof record.retryUntil === "function";
|
|
15480
15976
|
}
|
|
15481
15977
|
function forNotifiable(notification) {
|
|
@@ -15513,12 +16009,12 @@ var Dispatcher3 = class {
|
|
|
15513
16009
|
return channel;
|
|
15514
16010
|
}
|
|
15515
16011
|
async send(notifiables, notification) {
|
|
15516
|
-
const
|
|
15517
|
-
if (
|
|
16012
|
+
const list4 = toNotifiableList(notifiables);
|
|
16013
|
+
if (list4.length === 0) return;
|
|
15518
16014
|
if (isQueueableNotification(notification)) {
|
|
15519
16015
|
if (!this.container.bound(BusDispatcher)) throw new NotificationQueueUnavailableError();
|
|
15520
16016
|
const bus = this.container.make(BusDispatcher);
|
|
15521
|
-
for (const notifiable of
|
|
16017
|
+
for (const notifiable of list4) {
|
|
15522
16018
|
const own = forNotifiable(notification);
|
|
15523
16019
|
for (const channel of notification.via(notifiable)) {
|
|
15524
16020
|
await bus.dispatch(new SendQueuedNotifications([notifiable], own, [channel]));
|
|
@@ -15526,11 +16022,11 @@ var Dispatcher3 = class {
|
|
|
15526
16022
|
}
|
|
15527
16023
|
return;
|
|
15528
16024
|
}
|
|
15529
|
-
await this.sendNow(
|
|
16025
|
+
await this.sendNow(list4, notification);
|
|
15530
16026
|
}
|
|
15531
16027
|
async sendNow(notifiables, notification, channels) {
|
|
15532
|
-
const
|
|
15533
|
-
for (const notifiable of
|
|
16028
|
+
const list4 = toNotifiableList(notifiables);
|
|
16029
|
+
for (const notifiable of list4) {
|
|
15534
16030
|
const own = forNotifiable(notification);
|
|
15535
16031
|
const names = channels ?? notification.via(notifiable);
|
|
15536
16032
|
for (const name of names) {
|
|
@@ -15687,6 +16183,8 @@ import { randomUUID as randomUUID24 } from "crypto";
|
|
|
15687
16183
|
import { Redis as Redis2 } from "ioredis";
|
|
15688
16184
|
import { randomUUID as randomUUID32 } from "crypto";
|
|
15689
16185
|
import { setTimeout as sleep4 } from "timers/promises";
|
|
16186
|
+
import { spawn as spawnProcess } from "child_process";
|
|
16187
|
+
import { setTimeout as sleep22 } from "timers/promises";
|
|
15690
16188
|
import { existsSync as existsSync8, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
|
|
15691
16189
|
import { join as join12 } from "path";
|
|
15692
16190
|
import { pathToFileURL as pathToFileURL6 } from "url";
|
|
@@ -15775,6 +16273,40 @@ function isModel(value2) {
|
|
|
15775
16273
|
const candidate = value2;
|
|
15776
16274
|
return typeof candidate.getKey === "function" && typeof candidate.getKeyName === "function" && typeof candidate.getTable === "function" && typeof candidate.exists === "boolean";
|
|
15777
16275
|
}
|
|
16276
|
+
var isModelList = (value2) => typeof value2 === "object" && value2 !== null && !isModel(value2) && typeof value2[Symbol.iterator] === "function";
|
|
16277
|
+
function queueableRelations(model, visiting = /* @__PURE__ */ new Set()) {
|
|
16278
|
+
if (visiting.has(model)) return [];
|
|
16279
|
+
visiting.add(model);
|
|
16280
|
+
try {
|
|
16281
|
+
const relations = [];
|
|
16282
|
+
for (const [name, value2] of Object.entries(model.getRelations?.() ?? {})) {
|
|
16283
|
+
if (typeof model[name] !== "function") continue;
|
|
16284
|
+
relations.push(name);
|
|
16285
|
+
for (const nested of nestedRelations(value2, visiting)) relations.push(`${name}.${nested}`);
|
|
16286
|
+
}
|
|
16287
|
+
return [...new Set(relations)];
|
|
16288
|
+
} finally {
|
|
16289
|
+
visiting.delete(model);
|
|
16290
|
+
}
|
|
16291
|
+
}
|
|
16292
|
+
function nestedRelations(value2, visiting) {
|
|
16293
|
+
if (isModel(value2)) return queueableRelations(value2, visiting);
|
|
16294
|
+
if (!isModelList(value2)) return [];
|
|
16295
|
+
const members = [...value2].filter(isModel).map((member) => queueableRelations(member, visiting));
|
|
16296
|
+
if (members.length === 0) return [];
|
|
16297
|
+
return members.reduce((shared2, next) => shared2.filter((path) => next.includes(path)));
|
|
16298
|
+
}
|
|
16299
|
+
async function findForRestoration(model, key, connection) {
|
|
16300
|
+
if (connection !== void 0) {
|
|
16301
|
+
const instance = new model();
|
|
16302
|
+
if (typeof instance.setConnection === "function" && typeof instance.newQueryWithoutScopes === "function") {
|
|
16303
|
+
instance.setConnection(connection);
|
|
16304
|
+
return instance.newQueryWithoutScopes().find(key);
|
|
16305
|
+
}
|
|
16306
|
+
}
|
|
16307
|
+
const query = typeof model.withoutGlobalScopes === "function" ? model.withoutGlobalScopes() : model;
|
|
16308
|
+
return query.find(key);
|
|
16309
|
+
}
|
|
15778
16310
|
function classNameOf(registry2, cls) {
|
|
15779
16311
|
const existing = registry2.nameOf(cls);
|
|
15780
16312
|
if (existing !== void 0) return existing;
|
|
@@ -15844,7 +16376,12 @@ function serializeValue(value2, registry2, path = "data", seen = /* @__PURE__ */
|
|
|
15844
16376
|
if (!object.exists) {
|
|
15845
16377
|
throw new JobSerializationError(`Cannot serialize [${path}]: the [${name2}] model hasn't been saved, so it has no key to store.`);
|
|
15846
16378
|
}
|
|
15847
|
-
|
|
16379
|
+
const encoded = { [TAG]: "model", class: name2, key: serializeValue(object.getKey(), registry2, `${path}.key`, seen) ?? null };
|
|
16380
|
+
const connection = object.getConnectionName?.();
|
|
16381
|
+
if (connection !== void 0) encoded.connection = connection;
|
|
16382
|
+
const relations = queueableRelations(object);
|
|
16383
|
+
if (relations.length > 0) encoded.relations = relations;
|
|
16384
|
+
return encoded;
|
|
15848
16385
|
}
|
|
15849
16386
|
if (isPlainObject2(object)) {
|
|
15850
16387
|
const fields = serializeFields(object, registry2, path, seen);
|
|
@@ -15900,9 +16437,10 @@ async function restoreValue(value2, registry2) {
|
|
|
15900
16437
|
const name = value2.class;
|
|
15901
16438
|
const model = resolveClass(registry2, name);
|
|
15902
16439
|
const key = await restoreValue(value2.key, registry2);
|
|
15903
|
-
const
|
|
15904
|
-
const found = await query.find(key);
|
|
16440
|
+
const found = await findForRestoration(model, key, typeof value2.connection === "string" ? value2.connection : void 0);
|
|
15905
16441
|
if (found === void 0 || found === null) throw new MissingModelError(name, [key]);
|
|
16442
|
+
const relations = Array.isArray(value2.relations) ? value2.relations.map(String) : [];
|
|
16443
|
+
if (relations.length > 0) await (found.loadMissing ?? found.load)?.call(found, ...relations);
|
|
15906
16444
|
return found;
|
|
15907
16445
|
}
|
|
15908
16446
|
case "instance": {
|
|
@@ -17019,7 +17557,7 @@ var DatabaseBatchRepository = class {
|
|
|
17019
17557
|
var defaultWorkerOptions = () => ({
|
|
17020
17558
|
name: "default",
|
|
17021
17559
|
backoff: 0,
|
|
17022
|
-
memory:
|
|
17560
|
+
memory: 512,
|
|
17023
17561
|
timeout: 60,
|
|
17024
17562
|
sleep: 3,
|
|
17025
17563
|
maxTries: 1,
|
|
@@ -17277,6 +17815,142 @@ var Worker = class _Worker {
|
|
|
17277
17815
|
}
|
|
17278
17816
|
}
|
|
17279
17817
|
};
|
|
17818
|
+
var defaultListenerOptions = () => ({
|
|
17819
|
+
name: "default",
|
|
17820
|
+
backoff: 0,
|
|
17821
|
+
memory: 512,
|
|
17822
|
+
timeout: 60,
|
|
17823
|
+
sleep: 3,
|
|
17824
|
+
maxTries: 1,
|
|
17825
|
+
rest: 0,
|
|
17826
|
+
stopWhenEmpty: false
|
|
17827
|
+
});
|
|
17828
|
+
function lineSplitter(emit) {
|
|
17829
|
+
let rest = "";
|
|
17830
|
+
return {
|
|
17831
|
+
push(chunk) {
|
|
17832
|
+
const lines = (rest + chunk).split("\n");
|
|
17833
|
+
rest = lines.pop() ?? "";
|
|
17834
|
+
for (const line of lines) emit(line.endsWith("\r") ? line.slice(0, -1) : line);
|
|
17835
|
+
},
|
|
17836
|
+
end() {
|
|
17837
|
+
if (rest !== "") emit(rest);
|
|
17838
|
+
rest = "";
|
|
17839
|
+
}
|
|
17840
|
+
};
|
|
17841
|
+
}
|
|
17842
|
+
function currentRuntime() {
|
|
17843
|
+
const script = process.argv[1];
|
|
17844
|
+
if (script === void 0) throw new QueueError("queue:listen can't tell which script started this process, so it can't start workers.");
|
|
17845
|
+
return { command: process.execPath, args: [...process.execArgv, script] };
|
|
17846
|
+
}
|
|
17847
|
+
var Listener = class _Listener {
|
|
17848
|
+
constructor(manager2, config2) {
|
|
17849
|
+
this.manager = manager2;
|
|
17850
|
+
this.config = config2;
|
|
17851
|
+
}
|
|
17852
|
+
manager;
|
|
17853
|
+
config;
|
|
17854
|
+
static EXIT_SUCCESS = 0;
|
|
17855
|
+
shouldQuit = false;
|
|
17856
|
+
child;
|
|
17857
|
+
resting;
|
|
17858
|
+
/** Runs until stopped, the queue is empty (with stopWhenEmpty) or the memory limit is reached. Returns the exit code. */
|
|
17859
|
+
async listen(connection, queue, options) {
|
|
17860
|
+
const stopListening = this.listenForSignals();
|
|
17861
|
+
try {
|
|
17862
|
+
const command = this.makeCommand(connection, queue, options);
|
|
17863
|
+
while (!this.shouldQuit) {
|
|
17864
|
+
if (options.stopWhenEmpty && await this.isEmpty(connection, queue)) break;
|
|
17865
|
+
if (this.shouldQuit) break;
|
|
17866
|
+
await this.runProcess(command, options.timeout);
|
|
17867
|
+
if (this.shouldQuit || this.memoryExceeded(options.memory)) break;
|
|
17868
|
+
if (options.rest > 0) await this.rest(options.rest);
|
|
17869
|
+
}
|
|
17870
|
+
return _Listener.EXIT_SUCCESS;
|
|
17871
|
+
} finally {
|
|
17872
|
+
stopListening();
|
|
17873
|
+
}
|
|
17874
|
+
}
|
|
17875
|
+
/** Laravel's createCommand(): the runtime, the CLI script and `queue:work <connection> --once …`, plus `--timeout`. */
|
|
17876
|
+
makeCommand(connection, queue, options) {
|
|
17877
|
+
const { command, args } = this.config.runtime ?? currentRuntime();
|
|
17878
|
+
const backoff = Array.isArray(options.backoff) ? options.backoff.join(",") : String(options.backoff);
|
|
17879
|
+
return [
|
|
17880
|
+
command,
|
|
17881
|
+
...args,
|
|
17882
|
+
"queue:work",
|
|
17883
|
+
connection,
|
|
17884
|
+
"--once",
|
|
17885
|
+
`--name=${options.name}`,
|
|
17886
|
+
`--queue=${queue}`,
|
|
17887
|
+
`--backoff=${backoff}`,
|
|
17888
|
+
`--memory=${options.memory}`,
|
|
17889
|
+
`--sleep=${options.sleep}`,
|
|
17890
|
+
`--tries=${options.maxTries}`,
|
|
17891
|
+
`--timeout=${options.timeout}`
|
|
17892
|
+
];
|
|
17893
|
+
}
|
|
17894
|
+
/** Stops after the running process, which gets the same signal (SIGTERM/SIGINT/SIGQUIT call this). */
|
|
17895
|
+
stop(signal = "SIGTERM") {
|
|
17896
|
+
this.shouldQuit = true;
|
|
17897
|
+
this.child?.kill(signal);
|
|
17898
|
+
this.resting?.abort();
|
|
17899
|
+
}
|
|
17900
|
+
memoryExceeded(limitMb) {
|
|
17901
|
+
return limitMb > 0 && process.memoryUsage().heapUsed / 1024 / 1024 >= limitMb;
|
|
17902
|
+
}
|
|
17903
|
+
listenForSignals() {
|
|
17904
|
+
const signals = ["SIGTERM", "SIGINT", "SIGQUIT"];
|
|
17905
|
+
const handlers = signals.map((signal) => [signal, () => this.stop(signal)]);
|
|
17906
|
+
for (const [signal, handler3] of handlers) process.on(signal, handler3);
|
|
17907
|
+
return () => {
|
|
17908
|
+
for (const [signal, handler3] of handlers) process.off(signal, handler3);
|
|
17909
|
+
};
|
|
17910
|
+
}
|
|
17911
|
+
async isEmpty(connection, queue) {
|
|
17912
|
+
const queues = this.manager.connection(connection);
|
|
17913
|
+
for (const name of queue.split(",")) if (await queues.size(name.trim()) > 0) return false;
|
|
17914
|
+
return true;
|
|
17915
|
+
}
|
|
17916
|
+
runProcess([command, ...args], timeout) {
|
|
17917
|
+
const output = this.config.output ?? (() => {
|
|
17918
|
+
});
|
|
17919
|
+
return new Promise((resolve3, reject) => {
|
|
17920
|
+
const child = (this.config.spawn ?? spawnProcess)(command, args, { cwd: this.config.commandPath, env: process.env, stdio: ["ignore", "pipe", "pipe"] });
|
|
17921
|
+
this.child = child;
|
|
17922
|
+
const stdout = lineSplitter((line) => output("out", line));
|
|
17923
|
+
const stderr = lineSplitter((line) => output("err", line));
|
|
17924
|
+
child.stdout?.setEncoding("utf8").on("data", (chunk) => stdout.push(chunk));
|
|
17925
|
+
child.stderr?.setEncoding("utf8").on("data", (chunk) => stderr.push(chunk));
|
|
17926
|
+
const timer = timeout > 0 ? setTimeout(() => {
|
|
17927
|
+
output("err", `The process "${[command, ...args].join(" ")}" exceeded the timeout of ${timeout} seconds.`);
|
|
17928
|
+
child.kill("SIGKILL");
|
|
17929
|
+
}, timeout * 1e3) : void 0;
|
|
17930
|
+
let settled = false;
|
|
17931
|
+
const settle = () => {
|
|
17932
|
+
if (settled) return false;
|
|
17933
|
+
settled = true;
|
|
17934
|
+
clearTimeout(timer);
|
|
17935
|
+
this.child = void 0;
|
|
17936
|
+
stdout.end();
|
|
17937
|
+
stderr.end();
|
|
17938
|
+
return true;
|
|
17939
|
+
};
|
|
17940
|
+
child.once("error", (error) => settle() && reject(error));
|
|
17941
|
+
child.once("close", () => settle() && resolve3());
|
|
17942
|
+
});
|
|
17943
|
+
}
|
|
17944
|
+
async rest(seconds) {
|
|
17945
|
+
this.resting = new AbortController();
|
|
17946
|
+
try {
|
|
17947
|
+
await sleep22(seconds * 1e3, void 0, { signal: this.resting.signal });
|
|
17948
|
+
} catch {
|
|
17949
|
+
} finally {
|
|
17950
|
+
this.resting = void 0;
|
|
17951
|
+
}
|
|
17952
|
+
}
|
|
17953
|
+
};
|
|
17280
17954
|
var EXTENSIONS2 = [".ts", ".js", ".mts", ".mjs"];
|
|
17281
17955
|
function files2(directory) {
|
|
17282
17956
|
const found = [];
|
|
@@ -17305,7 +17979,7 @@ function discoverJobs(directory, registry2) {
|
|
|
17305
17979
|
return discoverClasses(directory, registry2, isJobClass);
|
|
17306
17980
|
}
|
|
17307
17981
|
var text2 = (value2) => optionalString2(value2) || void 0;
|
|
17308
|
-
var
|
|
17982
|
+
var list3 = (value2) => Array.isArray(value2) ? value2.map(String) : text2(value2) ? [String(value2)] : [];
|
|
17309
17983
|
var number2 = (value2, fallback) => {
|
|
17310
17984
|
const parsed = Number(value2);
|
|
17311
17985
|
return value2 === void 0 || value2 === null || value2 === "" || Number.isNaN(parsed) ? fallback : parsed;
|
|
@@ -17315,6 +17989,22 @@ function localTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
|
17315
17989
|
const pad2 = (n) => String(n).padStart(2, "0");
|
|
17316
17990
|
return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())} ${pad2(date.getHours())}:${pad2(date.getMinutes())}:${pad2(date.getSeconds())}`;
|
|
17317
17991
|
}
|
|
17992
|
+
function processingMessage(queue) {
|
|
17993
|
+
return `Processing jobs from the [${queue}] ${Str.plural("queue", queue.split(",").length)}.`;
|
|
17994
|
+
}
|
|
17995
|
+
function listenerOptionsFrom(option) {
|
|
17996
|
+
const defaults = defaultListenerOptions();
|
|
17997
|
+
return {
|
|
17998
|
+
name: text2(option("name")) ?? defaults.name,
|
|
17999
|
+
backoff: text2(option("backoff")) ?? defaults.backoff,
|
|
18000
|
+
memory: number2(option("memory"), defaults.memory),
|
|
18001
|
+
timeout: number2(option("timeout"), defaults.timeout),
|
|
18002
|
+
sleep: number2(option("sleep"), defaults.sleep),
|
|
18003
|
+
maxTries: number2(option("tries"), defaults.maxTries),
|
|
18004
|
+
rest: number2(option("rest"), defaults.rest),
|
|
18005
|
+
stopWhenEmpty: option("stop-when-empty") === true
|
|
18006
|
+
};
|
|
18007
|
+
}
|
|
17318
18008
|
function workerOptionsFrom(option) {
|
|
17319
18009
|
const defaults = defaultWorkerOptions();
|
|
17320
18010
|
return {
|
|
@@ -17345,7 +18035,7 @@ function registerQueueCommands(kernel, context) {
|
|
|
17345
18035
|
return false;
|
|
17346
18036
|
};
|
|
17347
18037
|
define2(
|
|
17348
|
-
"queue:work {connection? : The name of the queue connection to work} {--name=default : The name of the worker} {--queue= : The names of the queues to work} {--once : Only process the next job on the queue} {--stop-when-empty : Stop when the queue is empty} {--backoff=0 : Seconds to wait before retrying a job that failed} {--max-jobs=0 : The number of jobs to process before stopping} {--max-time=0 : The maximum number of seconds the worker should run} {--memory=
|
|
18038
|
+
"queue:work {connection? : The name of the queue connection to work} {--name=default : The name of the worker} {--queue= : The names of the queues to work} {--once : Only process the next job on the queue} {--stop-when-empty : Stop when the queue is empty} {--backoff=0 : Seconds to wait before retrying a job that failed} {--max-jobs=0 : The number of jobs to process before stopping} {--max-time=0 : The maximum number of seconds the worker should run} {--memory=512 : The memory limit in megabytes, measured as V8 heap in use (a Node app on tsx uses about 115 MB at idle)} {--sleep=3 : Seconds to sleep when no job is available} {--rest=0 : Seconds to rest between jobs} {--timeout=60 : The number of seconds a child process can run} {--tries=1 : Number of times to attempt a job before logging it failed}",
|
|
17349
18039
|
"Start processing jobs on the queue as a daemon",
|
|
17350
18040
|
async (out) => {
|
|
17351
18041
|
const connection = text2(out.argument("connection")) ?? defaultConnection();
|
|
@@ -17362,13 +18052,34 @@ function registerQueueCommands(kernel, context) {
|
|
|
17362
18052
|
exception: (error, job) => out.error(`${job ? `${name(job)}: ` : ""}${errorClass(error)}`)
|
|
17363
18053
|
});
|
|
17364
18054
|
const options = workerOptionsFrom((option) => out.option(option));
|
|
17365
|
-
out.info(
|
|
18055
|
+
out.info(processingMessage(queue));
|
|
17366
18056
|
if (out.option("once") === true) {
|
|
17367
18057
|
return worker.runNextJob(connection, queue, options);
|
|
17368
18058
|
}
|
|
17369
18059
|
return worker.daemon(connection, queue, options);
|
|
17370
18060
|
}
|
|
17371
18061
|
);
|
|
18062
|
+
define2(
|
|
18063
|
+
"queue:listen {connection? : The name of connection} {--name=default : The name of the worker} {--backoff=0 : The number of seconds to wait before retrying a job that encountered an uncaught exception} {--memory=512 : The memory limit in megabytes, measured as V8 heap in use (a Node app on tsx uses about 115 MB at idle)} {--queue= : The queue to listen on} {--sleep=3 : Number of seconds to sleep when no job is available} {--rest=0 : Number of seconds to rest between jobs} {--timeout=60 : The number of seconds a child process can run} {--tries=1 : Number of times to attempt a job before logging it failed} {--stop-when-empty : Stop when the queue is empty}",
|
|
18064
|
+
"Listen to a given queue",
|
|
18065
|
+
async (out) => {
|
|
18066
|
+
const connection = text2(out.argument("connection")) ?? defaultConnection();
|
|
18067
|
+
const queue = text2(out.option("queue")) ?? defaultQueue(connection);
|
|
18068
|
+
const banner = processingMessage(queue);
|
|
18069
|
+
out.info(banner);
|
|
18070
|
+
const listener = new Listener(container.make(QueueManager), {
|
|
18071
|
+
commandPath: context.app.basePath(),
|
|
18072
|
+
spawn: context.spawn,
|
|
18073
|
+
// Each `queue:work` starts with the same line as this command; it's shown once.
|
|
18074
|
+
output: (type, line) => {
|
|
18075
|
+
if (line === banner) return;
|
|
18076
|
+
if (type === "out") out.line(line);
|
|
18077
|
+
else out.error(line);
|
|
18078
|
+
}
|
|
18079
|
+
});
|
|
18080
|
+
return listener.listen(connection, queue, listenerOptionsFrom((option) => out.option(option)));
|
|
18081
|
+
}
|
|
18082
|
+
);
|
|
17372
18083
|
define2("queue:restart", "Restart queue worker daemons after their current job", async (out) => {
|
|
17373
18084
|
if (!container.bound(CacheManager)) {
|
|
17374
18085
|
out.error("queue:restart needs a cache store. Register the CacheServiceProvider.");
|
|
@@ -17393,7 +18104,7 @@ function registerQueueCommands(kernel, context) {
|
|
|
17393
18104
|
'queue:retry {id?* : The ID of the failed job or "all" to retry all jobs} {--queue= : Retry all of the failed jobs for the specified queue}',
|
|
17394
18105
|
"Retry a failed queue job",
|
|
17395
18106
|
async (out) => {
|
|
17396
|
-
const ids = await retryableIds(
|
|
18107
|
+
const ids = await retryableIds(list3(out.argument("id")), text2(out.option("queue")));
|
|
17397
18108
|
if (ids.length === 0) {
|
|
17398
18109
|
out.info("No retryable jobs found.");
|
|
17399
18110
|
return 0;
|
|
@@ -17835,6 +18546,32 @@ var RouteDefinition = class {
|
|
|
17835
18546
|
this.#compiled = void 0;
|
|
17836
18547
|
return this;
|
|
17837
18548
|
}
|
|
18549
|
+
/** Laravel's whereAlpha(): ASCII letters only. One parameter name or several. */
|
|
18550
|
+
whereAlpha(parameters) {
|
|
18551
|
+
return this.#assign(parameters, "[a-zA-Z]+");
|
|
18552
|
+
}
|
|
18553
|
+
/** Laravel's whereAlphaNumeric(): ASCII letters and digits. */
|
|
18554
|
+
whereAlphaNumeric(parameters) {
|
|
18555
|
+
return this.#assign(parameters, "[a-zA-Z0-9]+");
|
|
18556
|
+
}
|
|
18557
|
+
/** Laravel's whereNumber(): digits only. */
|
|
18558
|
+
whereNumber(parameters) {
|
|
18559
|
+
return this.#assign(parameters, "[0-9]+");
|
|
18560
|
+
}
|
|
18561
|
+
/** Laravel's whereUlid(): 26 Crockford base-32 characters, the first at most 7. */
|
|
18562
|
+
whereUlid(parameters) {
|
|
18563
|
+
return this.#assign(parameters, "[0-7][0-9a-hjkmnp-tv-zA-HJKMNP-TV-Z]{25}");
|
|
18564
|
+
}
|
|
18565
|
+
/** Laravel's whereUuid(): five groups of hex digits (8-4-4-4-12), any version. */
|
|
18566
|
+
whereUuid(parameters) {
|
|
18567
|
+
return this.#assign(parameters, "[\\da-fA-F]{8}-[\\da-fA-F]{4}-[\\da-fA-F]{4}-[\\da-fA-F]{4}-[\\da-fA-F]{12}");
|
|
18568
|
+
}
|
|
18569
|
+
/** Laravel's whereIn(): one of the values. Unlike Laravel, each value is matched literally (`c++` is not a pattern). */
|
|
18570
|
+
whereIn(parameters, values) {
|
|
18571
|
+
const first = typeof parameters === "string" ? parameters : parameters[0];
|
|
18572
|
+
if (values.length === 0 && first !== void 0) throw new Error(`Routing requirement for "${first}" cannot be empty.`);
|
|
18573
|
+
return this.#assign(parameters, values.map((value2) => escapeRegex(String(value2))).join("|"));
|
|
18574
|
+
}
|
|
17838
18575
|
gatherMiddleware() {
|
|
17839
18576
|
return [...this.#middleware];
|
|
17840
18577
|
}
|
|
@@ -17865,6 +18602,10 @@ var RouteDefinition = class {
|
|
|
17865
18602
|
if (this.uri === "/") return [];
|
|
17866
18603
|
return this.uri.split("/").map((segment) => WHOLE_OPTIONAL.test(segment) ? 2 : segment.includes("{") ? 1 : 0);
|
|
17867
18604
|
}
|
|
18605
|
+
#assign(parameters, pattern) {
|
|
18606
|
+
const names = typeof parameters === "string" ? [parameters] : parameters;
|
|
18607
|
+
return this.where(Object.fromEntries(names.map((name) => [name, pattern])));
|
|
18608
|
+
}
|
|
17868
18609
|
#regex(patterns, version) {
|
|
17869
18610
|
if (this.#compiled !== void 0 && this.#compiled.version === version) return this.#compiled.regex;
|
|
17870
18611
|
const wheres = { ...patterns, ...this.#wheres };
|
|
@@ -18215,6 +18956,14 @@ var BaseRouter = class {
|
|
|
18215
18956
|
getModel(parameter) {
|
|
18216
18957
|
return this.#models.get(parameter);
|
|
18217
18958
|
}
|
|
18959
|
+
/**
|
|
18960
|
+
* Binds a matched route's raw parameter values as a request to it would: Route.bind() callbacks, Route.model(),
|
|
18961
|
+
* then implicit binding through the RouteModelResolver of `container`. A missing model throws
|
|
18962
|
+
* RouteModelNotFoundError (404). Live uses it to check a page route's `can:` middleware again on each update.
|
|
18963
|
+
*/
|
|
18964
|
+
substituteBindings(route2, values, container) {
|
|
18965
|
+
return substituteBindings(this, route2, values, container);
|
|
18966
|
+
}
|
|
18218
18967
|
aliasMiddleware(name, middleware) {
|
|
18219
18968
|
this.#aliases[name] = middleware;
|
|
18220
18969
|
return this;
|
|
@@ -18228,20 +18977,20 @@ var BaseRouter = class {
|
|
|
18228
18977
|
return this;
|
|
18229
18978
|
}
|
|
18230
18979
|
pushMiddlewareToGroup(group, middleware) {
|
|
18231
|
-
const
|
|
18232
|
-
if (!
|
|
18980
|
+
const list4 = this.#groups[group] ??= [];
|
|
18981
|
+
if (!list4.includes(middleware)) list4.push(middleware);
|
|
18233
18982
|
return this;
|
|
18234
18983
|
}
|
|
18235
18984
|
prependMiddlewareToGroup(group, middleware) {
|
|
18236
|
-
const
|
|
18237
|
-
if (!
|
|
18985
|
+
const list4 = this.#groups[group] ??= [];
|
|
18986
|
+
if (!list4.includes(middleware)) list4.unshift(middleware);
|
|
18238
18987
|
return this;
|
|
18239
18988
|
}
|
|
18240
18989
|
hasMiddlewareGroup(name) {
|
|
18241
18990
|
return Object.hasOwn(this.#groups, name);
|
|
18242
18991
|
}
|
|
18243
18992
|
getMiddlewareGroups() {
|
|
18244
|
-
return Object.fromEntries(Object.entries(this.#groups).map(([name,
|
|
18993
|
+
return Object.fromEntries(Object.entries(this.#groups).map(([name, list4]) => [name, [...list4]]));
|
|
18245
18994
|
}
|
|
18246
18995
|
/** Every route, in registration order. */
|
|
18247
18996
|
getRoutes() {
|
|
@@ -18483,6 +19232,48 @@ var BaseUrlGenerator = class {
|
|
|
18483
19232
|
}
|
|
18484
19233
|
};
|
|
18485
19234
|
var Route = facade(Router);
|
|
19235
|
+
var DiagnosingHealth = class {
|
|
19236
|
+
};
|
|
19237
|
+
var escapeHtml3 = (value2) => value2.replace(/[&<>"']/g, (char) => `&#${char.charCodeAt(0)};`);
|
|
19238
|
+
var STYLE = ':root{color-scheme:dark}*{box-sizing:border-box;margin:0}html{background:#05050b}body{min-height:100vh;display:grid;place-items:center;padding:20px;background:#1a1a1a;color:#fff;font:400 16px/1.7 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}main{display:flex;align-items:center;gap:20px;width:100%;max-width:640px;padding:20px 32px;border-radius:18px;background:#212121}.dot{flex:none;width:12px;height:12px;border-radius:50%;background:#74ec5a}.dot.down{background:#ff3543}h1{font-size:21px;line-height:1.4;font-weight:600}p{color:#a3a3a3}.time{color:#ba94ff}';
|
|
19239
|
+
function healthResponse(page = {}) {
|
|
19240
|
+
const healthy = page.healthy ?? true;
|
|
19241
|
+
const time = page.milliseconds === void 0 ? "" : ` Response rendered in <span class="time">${Math.round(page.milliseconds)} ms</span>.`;
|
|
19242
|
+
const html2 = `<!DOCTYPE html>
|
|
19243
|
+
<html lang="en">
|
|
19244
|
+
<head>
|
|
19245
|
+
<meta charset="utf-8">
|
|
19246
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
19247
|
+
<title>${escapeHtml3(page.appName ?? "Oriel")}</title>
|
|
19248
|
+
<style>${STYLE}</style>
|
|
19249
|
+
</head>
|
|
19250
|
+
<body>
|
|
19251
|
+
<main>
|
|
19252
|
+
<span class="${healthy ? "dot" : "dot down"}" aria-hidden="true"></span>
|
|
19253
|
+
<div>
|
|
19254
|
+
<h1>Application ${healthy ? "up" : "experiencing problems"}</h1>
|
|
19255
|
+
<p>HTTP request received.${time}</p>
|
|
19256
|
+
</div>
|
|
19257
|
+
</main>
|
|
19258
|
+
</body>
|
|
19259
|
+
</html>
|
|
19260
|
+
`;
|
|
19261
|
+
return new Response(html2, { status: healthy ? 200 : 500, headers: { "content-type": "text/html; charset=utf-8" } });
|
|
19262
|
+
}
|
|
19263
|
+
async function diagnoseHealth(app2) {
|
|
19264
|
+
const started = performance.now();
|
|
19265
|
+
const config2 = app2.bound(ConfigRepository) ? app2.make(ConfigRepository) : void 0;
|
|
19266
|
+
let healthy = true;
|
|
19267
|
+
try {
|
|
19268
|
+
if (app2.bound(EventDispatcher)) await app2.make(EventDispatcher).dispatch(new DiagnosingHealth());
|
|
19269
|
+
} catch (error) {
|
|
19270
|
+
if (config2?.get("app.debug", false) === true) throw error;
|
|
19271
|
+
if (app2.bound(ExceptionHandler)) await app2.make(ExceptionHandler).report(error);
|
|
19272
|
+
healthy = false;
|
|
19273
|
+
}
|
|
19274
|
+
const appName2 = String(config2?.get("app.name", "Oriel") ?? "Oriel");
|
|
19275
|
+
return healthResponse({ healthy, appName: appName2, milliseconds: performance.now() - started });
|
|
19276
|
+
}
|
|
18486
19277
|
var generation2 = 0;
|
|
18487
19278
|
async function loadRoutesFrom(app2, router, file) {
|
|
18488
19279
|
const url2 = `${pathToFileURL7(file).href}?oriel-routes=${++generation2}`;
|
|
@@ -18492,10 +19283,6 @@ async function loadRoutesFrom(app2, router, file) {
|
|
|
18492
19283
|
));
|
|
18493
19284
|
if (typeof module.default === "function") await app2.run(() => module.default(router));
|
|
18494
19285
|
}
|
|
18495
|
-
function healthResponse() {
|
|
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>';
|
|
18497
|
-
return new Response(html2, { status: 200, headers: { "content-type": "text/html; charset=utf-8" } });
|
|
18498
|
-
}
|
|
18499
19286
|
var sha12 = (value2) => createHash8("sha1").update(value2).digest("hex");
|
|
18500
19287
|
function withHeaders2(response2, headers) {
|
|
18501
19288
|
try {
|
|
@@ -18572,7 +19359,7 @@ var RoutingServiceProvider = class extends ServiceProvider {
|
|
|
18572
19359
|
if (!this.app.bound(RoutingPaths)) return;
|
|
18573
19360
|
const { web, api, health, apiPrefix } = this.app.make(RoutingPaths);
|
|
18574
19361
|
const router = this.app.make(Router);
|
|
18575
|
-
if (health !== void 0) router.get(health, () =>
|
|
19362
|
+
if (health !== void 0) router.get(health, () => diagnoseHealth(this.app));
|
|
18576
19363
|
if (web !== void 0) await router.middleware("web").group(() => this.#load(router, web));
|
|
18577
19364
|
if (api !== void 0) await router.prefix(apiPrefix).middleware("api").group(() => this.#load(router, api));
|
|
18578
19365
|
});
|
|
@@ -18656,8 +19443,8 @@ var Store = class {
|
|
|
18656
19443
|
for (const [name, item] of Object.entries(values)) Arr.set(this.#attributes, name, item);
|
|
18657
19444
|
}
|
|
18658
19445
|
push(key, value2) {
|
|
18659
|
-
const
|
|
18660
|
-
this.put(key, [...Array.isArray(
|
|
19446
|
+
const list4 = this.get(key, []);
|
|
19447
|
+
this.put(key, [...Array.isArray(list4) ? list4 : [list4], value2]);
|
|
18661
19448
|
}
|
|
18662
19449
|
increment(key, amount = 1) {
|
|
18663
19450
|
const value2 = Number(this.get(key, 0)) + amount;
|
|
@@ -19323,7 +20110,7 @@ var ValidationErrorImpl = class extends Error {
|
|
|
19323
20110
|
var ValidationException = class _ValidationException extends ValidationErrorImpl {
|
|
19324
20111
|
/** Messages per field, each a string or a list. */
|
|
19325
20112
|
static withMessages(messages) {
|
|
19326
|
-
const errors2 = Object.fromEntries(Object.entries(messages).map(([field,
|
|
20113
|
+
const errors2 = Object.fromEntries(Object.entries(messages).map(([field, list4]) => [field, typeof list4 === "string" ? [list4] : [...list4]]));
|
|
19327
20114
|
return new _ValidationException(errors2);
|
|
19328
20115
|
}
|
|
19329
20116
|
constructor(errors2, errorBag = "default", redirectTo2) {
|
|
@@ -19434,6 +20221,9 @@ var DEFAULT_MESSAGES = {
|
|
|
19434
20221
|
file: "The :attribute field must be a file.",
|
|
19435
20222
|
image: "The :attribute field must be an image.",
|
|
19436
20223
|
mimes: "The :attribute field must be a file of type: :values.",
|
|
20224
|
+
mimetypes: "The :attribute field must be a file of type: :values.",
|
|
20225
|
+
extensions: "The :attribute field must have one of the following extensions: :values.",
|
|
20226
|
+
dimensions: "The :attribute field has invalid image dimensions.",
|
|
19437
20227
|
"max.string": "The :attribute field must not be greater than :max characters.",
|
|
19438
20228
|
"max.numeric": "The :attribute field must not be greater than :max.",
|
|
19439
20229
|
"max.array": "The :attribute field must not have more than :max items.",
|
|
@@ -19524,6 +20314,90 @@ var databaseRules = {
|
|
|
19524
20314
|
messageKey: () => "exists"
|
|
19525
20315
|
}
|
|
19526
20316
|
};
|
|
20317
|
+
var FRAME_MARKERS = /* @__PURE__ */ new Set([192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207]);
|
|
20318
|
+
var MAX_JPEG_STEPS = 1024;
|
|
20319
|
+
var MAX_BOXES = 1024;
|
|
20320
|
+
var fourcc = (view2, offset) => String.fromCharCode(view2.getUint8(offset), view2.getUint8(offset + 1), view2.getUint8(offset + 2), view2.getUint8(offset + 3));
|
|
20321
|
+
var u24le = (view2, offset) => view2.getUint8(offset) | view2.getUint8(offset + 1) << 8 | view2.getUint8(offset + 2) << 16;
|
|
20322
|
+
var READERS = {
|
|
20323
|
+
"image/png": (view2) => fourcc(view2, 12) === "IHDR" ? { width: view2.getUint32(16), height: view2.getUint32(20) } : void 0,
|
|
20324
|
+
"image/gif": (view2) => ({ width: view2.getUint16(6, true), height: view2.getUint16(8, true) }),
|
|
20325
|
+
"image/bmp": (view2) => view2.getUint32(14, true) === 12 ? { width: view2.getUint16(18, true), height: view2.getUint16(20, true) } : { width: Math.abs(view2.getInt32(18, true)), height: Math.abs(view2.getInt32(22, true)) },
|
|
20326
|
+
"image/jpeg": jpeg,
|
|
20327
|
+
"image/webp": webp,
|
|
20328
|
+
"image/avif": avif
|
|
20329
|
+
};
|
|
20330
|
+
function imageDimensions(bytes, mime) {
|
|
20331
|
+
const reader = READERS[mime];
|
|
20332
|
+
if (!reader) return void 0;
|
|
20333
|
+
try {
|
|
20334
|
+
const size = reader(new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength));
|
|
20335
|
+
return size && size.width > 0 && size.height > 0 ? size : void 0;
|
|
20336
|
+
} catch (error) {
|
|
20337
|
+
if (error instanceof RangeError) return void 0;
|
|
20338
|
+
throw error;
|
|
20339
|
+
}
|
|
20340
|
+
}
|
|
20341
|
+
function jpeg(view2) {
|
|
20342
|
+
let offset = 2;
|
|
20343
|
+
for (let step = 0; step < MAX_JPEG_STEPS && offset + 4 <= view2.byteLength; step++) {
|
|
20344
|
+
if (view2.getUint8(offset) !== 255) return void 0;
|
|
20345
|
+
const marker = view2.getUint8(offset + 1);
|
|
20346
|
+
if (marker === 255) offset += 1;
|
|
20347
|
+
else if (marker === 216 || marker === 1 || marker >= 208 && marker <= 215) offset += 2;
|
|
20348
|
+
else if (marker === 217 || marker === 218) return void 0;
|
|
20349
|
+
else if (FRAME_MARKERS.has(marker)) return { height: view2.getUint16(offset + 5), width: view2.getUint16(offset + 7) };
|
|
20350
|
+
else offset += 2 + view2.getUint16(offset + 2);
|
|
20351
|
+
}
|
|
20352
|
+
return void 0;
|
|
20353
|
+
}
|
|
20354
|
+
function webp(view2) {
|
|
20355
|
+
const chunk = fourcc(view2, 12);
|
|
20356
|
+
if (chunk === "VP8 ") {
|
|
20357
|
+
if (view2.getUint8(23) !== 157 || view2.getUint8(24) !== 1 || view2.getUint8(25) !== 42) return void 0;
|
|
20358
|
+
return { width: view2.getUint16(26, true) & 16383, height: view2.getUint16(28, true) & 16383 };
|
|
20359
|
+
}
|
|
20360
|
+
if (chunk === "VP8L") {
|
|
20361
|
+
if (view2.getUint8(20) !== 47) return void 0;
|
|
20362
|
+
const bits = view2.getUint32(21, true);
|
|
20363
|
+
return { width: (bits & 16383) + 1, height: (bits >>> 14 & 16383) + 1 };
|
|
20364
|
+
}
|
|
20365
|
+
if (chunk === "VP8X") return { width: u24le(view2, 24) + 1, height: u24le(view2, 27) + 1 };
|
|
20366
|
+
return void 0;
|
|
20367
|
+
}
|
|
20368
|
+
function* boxes(view2, start2, end) {
|
|
20369
|
+
let offset = start2;
|
|
20370
|
+
for (let count = 0; count < MAX_BOXES && offset + 8 <= end; count++) {
|
|
20371
|
+
let size = view2.getUint32(offset);
|
|
20372
|
+
let header = 8;
|
|
20373
|
+
if (size === 1) {
|
|
20374
|
+
size = Number(view2.getBigUint64(offset + 8));
|
|
20375
|
+
header = 16;
|
|
20376
|
+
} else if (size === 0) {
|
|
20377
|
+
size = end - offset;
|
|
20378
|
+
}
|
|
20379
|
+
if (size < header || offset + size > end) return;
|
|
20380
|
+
yield { type: fourcc(view2, offset + 4), start: offset + header, end: offset + size };
|
|
20381
|
+
offset += size;
|
|
20382
|
+
}
|
|
20383
|
+
}
|
|
20384
|
+
var findBox = (view2, start2, end, type) => {
|
|
20385
|
+
for (const box of boxes(view2, start2, end)) if (box.type === type) return box;
|
|
20386
|
+
return void 0;
|
|
20387
|
+
};
|
|
20388
|
+
function avif(view2) {
|
|
20389
|
+
const meta = findBox(view2, 0, view2.byteLength, "meta");
|
|
20390
|
+
const iprp = meta && findBox(view2, meta.start + 4, meta.end, "iprp");
|
|
20391
|
+
const ipco = iprp && findBox(view2, iprp.start, iprp.end, "ipco");
|
|
20392
|
+
if (!ipco) return void 0;
|
|
20393
|
+
let largest;
|
|
20394
|
+
for (const box of boxes(view2, ipco.start, ipco.end)) {
|
|
20395
|
+
if (box.type !== "ispe") continue;
|
|
20396
|
+
const size = { width: view2.getUint32(box.start + 4), height: view2.getUint32(box.start + 8) };
|
|
20397
|
+
if (!largest || size.width * size.height > largest.width * largest.height) largest = size;
|
|
20398
|
+
}
|
|
20399
|
+
return largest;
|
|
20400
|
+
}
|
|
19527
20401
|
function splitParameters(name, raw3) {
|
|
19528
20402
|
return name === "regex" || name === "not_regex" ? [raw3] : raw3.split(",");
|
|
19529
20403
|
}
|
|
@@ -19571,25 +20445,139 @@ function expandWildcardKeys(pattern, data) {
|
|
|
19571
20445
|
}
|
|
19572
20446
|
return paths;
|
|
19573
20447
|
}
|
|
19574
|
-
var
|
|
20448
|
+
var { BINARY_AND_MARKUP_TYPES, detectFileType, EMPTY: EMPTY2, RASTER_IMAGES, SVG, TEXT } = fileType_exports;
|
|
20449
|
+
var inspections = /* @__PURE__ */ new WeakMap();
|
|
20450
|
+
function inspect(file) {
|
|
20451
|
+
let inspection = inspections.get(file);
|
|
20452
|
+
if (!inspection) {
|
|
20453
|
+
inspection = file.arrayBuffer().then((buffer) => {
|
|
20454
|
+
const bytes = new Uint8Array(buffer);
|
|
20455
|
+
const type = detectFileType(bytes);
|
|
20456
|
+
return { type, dimensions: RASTER_IMAGES.has(type.mime) ? imageDimensions(bytes, type.mime) : void 0 };
|
|
20457
|
+
});
|
|
20458
|
+
inspections.set(file, inspection);
|
|
20459
|
+
}
|
|
20460
|
+
return inspection;
|
|
20461
|
+
}
|
|
20462
|
+
function clientExtension(file) {
|
|
20463
|
+
const name = file.clientName.slice(Math.max(file.clientName.lastIndexOf("/"), file.clientName.lastIndexOf("\\")) + 1);
|
|
20464
|
+
const dot = name.lastIndexOf(".");
|
|
20465
|
+
return dot === -1 ? "" : name.slice(dot + 1).trim().toLowerCase();
|
|
20466
|
+
}
|
|
20467
|
+
var PHP_EXTENSIONS = /* @__PURE__ */ new Set(["php", "php3", "php4", "php5", "php7", "php8", "phtml", "phar"]);
|
|
20468
|
+
var blocksPhp = (file, allowed) => !allowed.includes("php") && PHP_EXTENSIONS.has(clientExtension(file));
|
|
20469
|
+
var TEXT_FORMATS = /* @__PURE__ */ new Set(["txt", "text", "csv", "tsv", "json", "md"]);
|
|
20470
|
+
var RECOGNISED_EXTENSIONS = new Set(BINARY_AND_MARKUP_TYPES.flatMap(({ extensions }) => extensions));
|
|
20471
|
+
var lower = (values) => values.map((value2) => value2.trim().toLowerCase());
|
|
20472
|
+
function meetsMimes(type, extension, allowed) {
|
|
20473
|
+
if (type === EMPTY2) return false;
|
|
20474
|
+
if (type === TEXT && allowed.has("txt")) return true;
|
|
20475
|
+
if (type !== TEXT && type.extensions.length > 0) return type.extensions.some((name) => allowed.has(name));
|
|
20476
|
+
if (!allowed.has(extension) || RECOGNISED_EXTENSIONS.has(extension)) return false;
|
|
20477
|
+
return type === TEXT || !TEXT_FORMATS.has(extension);
|
|
20478
|
+
}
|
|
20479
|
+
function allowedExtensions(ctx) {
|
|
20480
|
+
const allowed = new Set(lower(ctx.parameters));
|
|
20481
|
+
if (allowed.has("jpg") || allowed.has("jpeg")) allowed.add("jpg").add("jpeg");
|
|
20482
|
+
return allowed;
|
|
20483
|
+
}
|
|
20484
|
+
var listed = (ctx) => ({ values: ctx.parameters.join(", ") });
|
|
20485
|
+
var DIMENSION_KEYS = ["width", "height", "min_width", "min_height", "max_width", "max_height", "ratio"];
|
|
20486
|
+
function namedParameter(parameter) {
|
|
20487
|
+
const at = parameter.indexOf("=");
|
|
20488
|
+
return at === -1 ? [parameter, ""] : [parameter.slice(0, at), parameter.slice(at + 1)];
|
|
20489
|
+
}
|
|
20490
|
+
function parseRatio(value2) {
|
|
20491
|
+
const match = /^(\d+(?:\.\d+)?|\.\d+)(?:\/(\d+))?$/.exec(value2.trim());
|
|
20492
|
+
if (!match) return void 0;
|
|
20493
|
+
const ratio = Number(match[1]) / Number(match[2] ?? 1);
|
|
20494
|
+
return Number.isFinite(ratio) && ratio > 0 ? ratio : void 0;
|
|
20495
|
+
}
|
|
20496
|
+
function dimensionConstraints(parameters) {
|
|
20497
|
+
if (parameters.length === 0) throw new InvalidRuleParameterError("dimensions", "", `expected one or more of ${DIMENSION_KEYS.join(", ")}`);
|
|
20498
|
+
const constraints = {};
|
|
20499
|
+
for (const parameter of parameters) {
|
|
20500
|
+
const [key, value2] = namedParameter(parameter);
|
|
20501
|
+
if (!DIMENSION_KEYS.includes(key)) {
|
|
20502
|
+
throw new InvalidRuleParameterError("dimensions", parameter, `expected one of ${DIMENSION_KEYS.join(", ")}`);
|
|
20503
|
+
}
|
|
20504
|
+
const number3 = key === "ratio" ? parseRatio(value2) : /^\d+$/.test(value2) ? Number(value2) : void 0;
|
|
20505
|
+
if (number3 === void 0) {
|
|
20506
|
+
throw new InvalidRuleParameterError("dimensions", parameter, key === "ratio" ? "expected a ratio such as 3/2 or 1.5" : "expected a whole number of pixels");
|
|
20507
|
+
}
|
|
20508
|
+
constraints[key] = number3;
|
|
20509
|
+
}
|
|
20510
|
+
return constraints;
|
|
20511
|
+
}
|
|
20512
|
+
function meetsDimensions(constraints, { width, height }) {
|
|
20513
|
+
const { width: exactWidth, height: exactHeight, min_width, max_width, min_height, max_height, ratio } = constraints;
|
|
20514
|
+
if (exactWidth !== void 0 && width !== exactWidth) return false;
|
|
20515
|
+
if (exactHeight !== void 0 && height !== exactHeight) return false;
|
|
20516
|
+
if (min_width !== void 0 && width < min_width) return false;
|
|
20517
|
+
if (max_width !== void 0 && width > max_width) return false;
|
|
20518
|
+
if (min_height !== void 0 && height < min_height) return false;
|
|
20519
|
+
if (max_height !== void 0 && height > max_height) return false;
|
|
20520
|
+
return ratio === void 0 || Math.abs(ratio - width / height) <= 1 / (Math.max((width + height) / 2, height) + 1);
|
|
20521
|
+
}
|
|
19575
20522
|
var fileRules = {
|
|
19576
20523
|
file: { validate: (ctx) => isUploadedFileLike(ctx.value), messageKey: () => "file" },
|
|
20524
|
+
/** A JPEG, PNG, GIF, WebP, AVIF or BMP by its bytes; SVG only as `image:allow_svg` (Laravel 12). */
|
|
19577
20525
|
image: {
|
|
19578
|
-
validate: (ctx) => {
|
|
19579
|
-
if (!isUploadedFileLike(ctx.value)) return false;
|
|
19580
|
-
|
|
19581
|
-
return
|
|
20526
|
+
validate: async (ctx) => {
|
|
20527
|
+
if (!isUploadedFileLike(ctx.value) || blocksPhp(ctx.value, [])) return false;
|
|
20528
|
+
const { type } = await inspect(ctx.value);
|
|
20529
|
+
return RASTER_IMAGES.has(type.mime) || type === SVG && ctx.parameters.includes("allow_svg");
|
|
19582
20530
|
},
|
|
19583
20531
|
messageKey: () => "image"
|
|
19584
20532
|
},
|
|
19585
20533
|
mimes: {
|
|
19586
|
-
validate: (ctx) => {
|
|
20534
|
+
validate: async (ctx) => {
|
|
19587
20535
|
if (!isUploadedFileLike(ctx.value)) return false;
|
|
19588
|
-
const allowed = ctx
|
|
19589
|
-
|
|
20536
|
+
const allowed = allowedExtensions(ctx);
|
|
20537
|
+
if (blocksPhp(ctx.value, [...allowed])) return false;
|
|
20538
|
+
return meetsMimes((await inspect(ctx.value)).type, clientExtension(ctx.value), allowed);
|
|
19590
20539
|
},
|
|
19591
20540
|
messageKey: () => "mimes",
|
|
19592
|
-
replacements:
|
|
20541
|
+
replacements: listed
|
|
20542
|
+
},
|
|
20543
|
+
/**
|
|
20544
|
+
* The detected MIME type is listed, or its `type/*` wildcard is. `image/*` includes SVG (`image/svg+xml`), as in
|
|
20545
|
+
* Laravel: the rule for photos is `image`.
|
|
20546
|
+
*/
|
|
20547
|
+
mimetypes: {
|
|
20548
|
+
validate: async (ctx) => {
|
|
20549
|
+
if (!isUploadedFileLike(ctx.value)) return false;
|
|
20550
|
+
const allowed = lower(ctx.parameters);
|
|
20551
|
+
if (blocksPhp(ctx.value, allowed)) return false;
|
|
20552
|
+
const { mime } = (await inspect(ctx.value)).type;
|
|
20553
|
+
return allowed.includes(mime) || allowed.includes(`${mime.split("/")[0]}/*`);
|
|
20554
|
+
},
|
|
20555
|
+
messageKey: () => "mimetypes",
|
|
20556
|
+
replacements: listed
|
|
20557
|
+
},
|
|
20558
|
+
/**
|
|
20559
|
+
* The pixel size read from the image's header meets every constraint: width, height, min_width, max_width,
|
|
20560
|
+
* min_height, max_height, ratio. SVG and images whose header can't be read fail.
|
|
20561
|
+
*/
|
|
20562
|
+
dimensions: {
|
|
20563
|
+
validate: async (ctx) => {
|
|
20564
|
+
const constraints = dimensionConstraints(ctx.parameters);
|
|
20565
|
+
if (!isUploadedFileLike(ctx.value)) return false;
|
|
20566
|
+
const { dimensions } = await inspect(ctx.value);
|
|
20567
|
+
return dimensions !== void 0 && meetsDimensions(constraints, dimensions);
|
|
20568
|
+
},
|
|
20569
|
+
messageKey: () => "dimensions",
|
|
20570
|
+
replacements: (ctx) => Object.fromEntries(ctx.parameters.map(namedParameter))
|
|
20571
|
+
},
|
|
20572
|
+
/** The client file name's extension is listed (Laravel 11). It checks the name only: pair it with mimes or image. */
|
|
20573
|
+
extensions: {
|
|
20574
|
+
validate: (ctx) => {
|
|
20575
|
+
if (!isUploadedFileLike(ctx.value)) return false;
|
|
20576
|
+
const allowed = lower(ctx.parameters);
|
|
20577
|
+
return !blocksPhp(ctx.value, allowed) && allowed.includes(clientExtension(ctx.value));
|
|
20578
|
+
},
|
|
20579
|
+
messageKey: () => "extensions",
|
|
20580
|
+
replacements: listed
|
|
19593
20581
|
}
|
|
19594
20582
|
};
|
|
19595
20583
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
@@ -20276,6 +21264,11 @@ var Notification2 = class extends Notification {
|
|
|
20276
21264
|
return NotificationFake.fake(...args);
|
|
20277
21265
|
}
|
|
20278
21266
|
};
|
|
21267
|
+
|
|
21268
|
+
// notifiable.ts
|
|
21269
|
+
function Notifiable(Base) {
|
|
21270
|
+
return RoutesNotifications(HasDatabaseNotifications(Base));
|
|
21271
|
+
}
|
|
20279
21272
|
export {
|
|
20280
21273
|
API_ROUTES_STUB,
|
|
20281
21274
|
AboutCommand,
|
|
@@ -20299,6 +21292,7 @@ export {
|
|
|
20299
21292
|
AuthenticatableModel,
|
|
20300
21293
|
Authenticate,
|
|
20301
21294
|
AuthenticationError,
|
|
21295
|
+
Authorizable,
|
|
20302
21296
|
AuthorizationError,
|
|
20303
21297
|
AuthorizationErrorImpl,
|
|
20304
21298
|
Authorize,
|
|
@@ -20347,6 +21341,7 @@ export {
|
|
|
20347
21341
|
ConsoleServiceProvider,
|
|
20348
21342
|
Container2 as Container,
|
|
20349
21343
|
ContainerNotAvailableError,
|
|
21344
|
+
Controller,
|
|
20350
21345
|
ControllerMethodNotFoundError,
|
|
20351
21346
|
ConvertEmptyStringsToNull,
|
|
20352
21347
|
Cookie,
|
|
@@ -20368,7 +21363,10 @@ export {
|
|
|
20368
21363
|
DatabaseJob,
|
|
20369
21364
|
DatabaseLock,
|
|
20370
21365
|
DatabaseManagerImpl,
|
|
21366
|
+
DatabaseNotification,
|
|
20371
21367
|
DatabaseNotificationChannel,
|
|
21368
|
+
DatabaseNotificationCollection,
|
|
21369
|
+
DatabaseNotificationsRelation,
|
|
20372
21370
|
DatabaseQueue,
|
|
20373
21371
|
DatabaseServiceProvider,
|
|
20374
21372
|
DatabaseSessionHandler,
|
|
@@ -20377,6 +21375,7 @@ export {
|
|
|
20377
21375
|
DatabaseUnavailableError,
|
|
20378
21376
|
DecryptError,
|
|
20379
21377
|
DeferProp,
|
|
21378
|
+
DiagnosingHealth,
|
|
20380
21379
|
Dispatchable,
|
|
20381
21380
|
ELEMENT,
|
|
20382
21381
|
EloquentUserProvider,
|
|
@@ -20412,17 +21411,20 @@ export {
|
|
|
20412
21411
|
FormRequest,
|
|
20413
21412
|
FormUploadedFile,
|
|
20414
21413
|
Fragment,
|
|
20415
|
-
|
|
21414
|
+
Gate4 as Gate,
|
|
20416
21415
|
GateResponse,
|
|
20417
21416
|
GeneratorCommand,
|
|
20418
21417
|
GenericLock,
|
|
20419
21418
|
Grammar,
|
|
20420
21419
|
GroupRegistrar,
|
|
20421
21420
|
HasApiTokens,
|
|
21421
|
+
HasDatabaseNotifications,
|
|
20422
21422
|
HasMany,
|
|
20423
21423
|
HasManyThrough,
|
|
20424
21424
|
HasOne,
|
|
20425
21425
|
HasOneOrMany,
|
|
21426
|
+
HasUlids,
|
|
21427
|
+
HasUuids,
|
|
20426
21428
|
Hash,
|
|
20427
21429
|
HashAlgorithmError,
|
|
20428
21430
|
HashManager,
|
|
@@ -20559,6 +21561,7 @@ export {
|
|
|
20559
21561
|
OptionalProp,
|
|
20560
21562
|
PERSISTENT_MIDDLEWARE,
|
|
20561
21563
|
PERSONAL_ACCESS_TOKENS_MIGRATION,
|
|
21564
|
+
Pagination,
|
|
20562
21565
|
Paginator,
|
|
20563
21566
|
Password,
|
|
20564
21567
|
PasswordBroker2 as PasswordBroker,
|
|
@@ -20586,6 +21589,7 @@ export {
|
|
|
20586
21589
|
Queue2 as Queue,
|
|
20587
21590
|
QueueBase,
|
|
20588
21591
|
QueueError,
|
|
21592
|
+
Listener as QueueListener,
|
|
20589
21593
|
QueueManager2 as QueueManager,
|
|
20590
21594
|
QueueServiceProvider,
|
|
20591
21595
|
QueueUnavailableError,
|
|
@@ -20613,13 +21617,15 @@ export {
|
|
|
20613
21617
|
RouteModelNotFoundError,
|
|
20614
21618
|
RouteModelResolverImpl,
|
|
20615
21619
|
RouteNotDefinedError,
|
|
21620
|
+
RoutesNotifications,
|
|
20616
21621
|
RoutingError,
|
|
20617
21622
|
RoutingServiceProvider,
|
|
20618
21623
|
Rule,
|
|
20619
21624
|
S3Filesystem,
|
|
20620
21625
|
SSR_RENDER_FAILED,
|
|
20621
21626
|
STORAGE_LINK_SIGNATURE,
|
|
20622
|
-
|
|
21627
|
+
Schedule5 as Schedule,
|
|
21628
|
+
ScheduleClearCacheCommand,
|
|
20623
21629
|
ScheduleImpl,
|
|
20624
21630
|
ScheduleListCommand,
|
|
20625
21631
|
ScheduleNameRequiredError,
|
|
@@ -20651,6 +21657,7 @@ export {
|
|
|
20651
21657
|
StartSession,
|
|
20652
21658
|
Storage2 as Storage,
|
|
20653
21659
|
Str,
|
|
21660
|
+
Stringable,
|
|
20654
21661
|
SyncJob,
|
|
20655
21662
|
SyncQueue,
|
|
20656
21663
|
TagsNotSupportedError,
|
|
@@ -20710,6 +21717,7 @@ export {
|
|
|
20710
21717
|
ViteError,
|
|
20711
21718
|
ViteHtml,
|
|
20712
21719
|
WORKER_DISCOVERY_DIRECTORIES,
|
|
21720
|
+
WithPagination,
|
|
20713
21721
|
WithoutOverlapping,
|
|
20714
21722
|
Worker,
|
|
20715
21723
|
__,
|
|
@@ -20758,6 +21766,7 @@ export {
|
|
|
20758
21766
|
decodePayload,
|
|
20759
21767
|
decrypt,
|
|
20760
21768
|
defaultAttributeName,
|
|
21769
|
+
defaultListenerOptions,
|
|
20761
21770
|
defaultLockFactory,
|
|
20762
21771
|
defaultProviders,
|
|
20763
21772
|
defaultWorkerOptions,
|
|
@@ -20787,7 +21796,6 @@ export {
|
|
|
20787
21796
|
extensionFromMime,
|
|
20788
21797
|
facade,
|
|
20789
21798
|
fake,
|
|
20790
|
-
fetchNotifications,
|
|
20791
21799
|
filterRouteList,
|
|
20792
21800
|
formatAddress,
|
|
20793
21801
|
formatDate,
|
|
@@ -20824,6 +21832,7 @@ export {
|
|
|
20824
21832
|
isUploadedFileLike,
|
|
20825
21833
|
joinDiskPath,
|
|
20826
21834
|
keyGenerateHandler,
|
|
21835
|
+
listenerOptionsFrom,
|
|
20827
21836
|
live,
|
|
20828
21837
|
loadRelations,
|
|
20829
21838
|
loadRoutesFrom,
|