@beeblock/svelar 0.4.0
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/LICENSE +21 -0
- package/README.md +110 -0
- package/dist/actions/index.d.ts +101 -0
- package/dist/actions/index.js +1 -0
- package/dist/api-keys/index.d.ts +58 -0
- package/dist/api-keys/index.js +1 -0
- package/dist/audit/index.d.ts +52 -0
- package/dist/audit/index.js +1 -0
- package/dist/auth/Auth.d.ts +283 -0
- package/dist/auth/Gate.d.ts +166 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +80 -0
- package/dist/broadcasting/client.d.ts +195 -0
- package/dist/broadcasting/client.js +1 -0
- package/dist/broadcasting/index.d.ts +318 -0
- package/dist/broadcasting/index.js +20 -0
- package/dist/cache/index.d.ts +77 -0
- package/dist/cache/index.js +1 -0
- package/dist/cli/Cli.d.ts +23 -0
- package/dist/cli/Command.d.ts +36 -0
- package/dist/cli/bin.d.ts +8 -0
- package/dist/cli/bin.js +5856 -0
- package/dist/cli/commands/KeyGenerateCommand.d.ts +16 -0
- package/dist/cli/commands/MakeActionCommand.d.ts +15 -0
- package/dist/cli/commands/MakeBroadcastingCommand.d.ts +29 -0
- package/dist/cli/commands/MakeChannelCommand.d.ts +18 -0
- package/dist/cli/commands/MakeCommandCommand.d.ts +16 -0
- package/dist/cli/commands/MakeConfigCommand.d.ts +13 -0
- package/dist/cli/commands/MakeControllerCommand.d.ts +28 -0
- package/dist/cli/commands/MakeDashboardCommand.d.ts +34 -0
- package/dist/cli/commands/MakeDockerCommand.d.ts +32 -0
- package/dist/cli/commands/MakeEventCommand.d.ts +11 -0
- package/dist/cli/commands/MakeJobCommand.d.ts +11 -0
- package/dist/cli/commands/MakeListenerCommand.d.ts +16 -0
- package/dist/cli/commands/MakeMiddlewareCommand.d.ts +11 -0
- package/dist/cli/commands/MakeMigrationCommand.d.ts +17 -0
- package/dist/cli/commands/MakeModelCommand.d.ts +25 -0
- package/dist/cli/commands/MakeObserverCommand.d.ts +23 -0
- package/dist/cli/commands/MakePluginCommand.d.ts +11 -0
- package/dist/cli/commands/MakeProviderCommand.d.ts +11 -0
- package/dist/cli/commands/MakeRepositoryCommand.d.ts +22 -0
- package/dist/cli/commands/MakeRequestCommand.d.ts +15 -0
- package/dist/cli/commands/MakeResourceCommand.d.ts +30 -0
- package/dist/cli/commands/MakeRouteCommand.d.ts +42 -0
- package/dist/cli/commands/MakeSchemaCommand.d.ts +20 -0
- package/dist/cli/commands/MakeSeederCommand.d.ts +11 -0
- package/dist/cli/commands/MakeServiceCommand.d.ts +28 -0
- package/dist/cli/commands/MakeTaskCommand.d.ts +12 -0
- package/dist/cli/commands/MigrateCommand.d.ts +26 -0
- package/dist/cli/commands/NewCommand.d.ts +21 -0
- package/dist/cli/commands/NewCommandTemplates.d.ts +123 -0
- package/dist/cli/commands/PluginInstallCommand.d.ts +16 -0
- package/dist/cli/commands/PluginListCommand.d.ts +11 -0
- package/dist/cli/commands/PluginPublishCommand.d.ts +22 -0
- package/dist/cli/commands/QueueFailedCommand.d.ts +9 -0
- package/dist/cli/commands/QueueFlushCommand.d.ts +9 -0
- package/dist/cli/commands/QueueRetryCommand.d.ts +16 -0
- package/dist/cli/commands/QueueWorkCommand.d.ts +25 -0
- package/dist/cli/commands/RoutesListCommand.d.ts +30 -0
- package/dist/cli/commands/ScheduleRunCommand.d.ts +15 -0
- package/dist/cli/commands/SeedCommand.d.ts +14 -0
- package/dist/cli/commands/TinkerCommand.d.ts +10 -0
- package/dist/cli/index.d.ts +36 -0
- package/dist/cli/index.js +1973 -0
- package/dist/cli/ts-resolve-hook.mjs +74 -0
- package/dist/cli/ts-resolver.mjs +8 -0
- package/dist/config/Config.d.ts +65 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.js +1 -0
- package/dist/container/Application.d.ts +33 -0
- package/dist/container/Container.d.ts +70 -0
- package/dist/container/ServiceProvider.d.ts +21 -0
- package/dist/container/index.d.ts +3 -0
- package/dist/container/index.js +1 -0
- package/dist/dashboard/index.d.ts +123 -0
- package/dist/dashboard/index.js +5 -0
- package/dist/database/Connection.d.ts +80 -0
- package/dist/database/Migration.d.ts +76 -0
- package/dist/database/SchemaBuilder.d.ts +91 -0
- package/dist/database/Seeder.d.ts +9 -0
- package/dist/database/index.d.ts +4 -0
- package/dist/database/index.js +4 -0
- package/dist/email-templates/index.d.ts +51 -0
- package/dist/email-templates/index.js +57 -0
- package/dist/errors/Handler.d.ts +100 -0
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.js +5 -0
- package/dist/events/EventServiceProvider.d.ts +82 -0
- package/dist/events/Listener.d.ts +28 -0
- package/dist/events/index.d.ts +80 -0
- package/dist/events/index.js +1 -0
- package/dist/excel/index.d.ts +154 -0
- package/dist/excel/index.js +1 -0
- package/dist/feature-flags/index.d.ts +158 -0
- package/dist/feature-flags/index.js +59 -0
- package/dist/forms/index.d.ts +81 -0
- package/dist/forms/index.js +1 -0
- package/dist/hashing/Hash.d.ts +51 -0
- package/dist/hashing/index.d.ts +1 -0
- package/dist/hashing/index.js +1 -0
- package/dist/hooks/index.d.ts +135 -0
- package/dist/hooks/index.js +5 -0
- package/dist/http/index.d.ts +201 -0
- package/dist/http/index.js +2 -0
- package/dist/i18n/index.d.ts +81 -0
- package/dist/i18n/index.js +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +127 -0
- package/dist/logging/LogViewer.d.ts +95 -0
- package/dist/logging/LogViewer.js +1 -0
- package/dist/logging/index.d.ts +83 -0
- package/dist/logging/index.js +3 -0
- package/dist/mail/index.d.ts +149 -0
- package/dist/mail/index.js +1 -0
- package/dist/middleware/Middleware.d.ts +208 -0
- package/dist/middleware/index.d.ts +1 -0
- package/dist/middleware/index.js +1 -0
- package/dist/notifications/index.d.ts +85 -0
- package/dist/notifications/index.js +2 -0
- package/dist/orm/Model.d.ts +123 -0
- package/dist/orm/Observer.d.ts +34 -0
- package/dist/orm/QueryBuilder.d.ts +119 -0
- package/dist/orm/Relationship.d.ts +58 -0
- package/dist/orm/index.d.ts +4 -0
- package/dist/orm/index.js +1 -0
- package/dist/pagination/index.d.ts +8 -0
- package/dist/pagination/index.js +0 -0
- package/dist/pdf/GeneratePdfJob.d.ts +99 -0
- package/dist/pdf/GeneratePdfJob.js +41 -0
- package/dist/pdf/index.d.ts +328 -0
- package/dist/pdf/index.js +41 -0
- package/dist/permissions/index.d.ts +161 -0
- package/dist/permissions/index.js +60 -0
- package/dist/plugins/BootstrapPlugins.d.ts +11 -0
- package/dist/plugins/PluginInstaller.d.ts +30 -0
- package/dist/plugins/PluginInstaller.js +1 -0
- package/dist/plugins/PluginPublisher.d.ts +32 -0
- package/dist/plugins/PluginPublisher.js +1 -0
- package/dist/plugins/PluginRegistry.d.ts +55 -0
- package/dist/plugins/PluginRegistry.js +1 -0
- package/dist/plugins/index.d.ts +206 -0
- package/dist/plugins/index.js +1 -0
- package/dist/queue/JobMonitor.d.ts +109 -0
- package/dist/queue/JobMonitor.js +5 -0
- package/dist/queue/index.d.ts +279 -0
- package/dist/queue/index.js +5 -0
- package/dist/repositories/index.d.ts +147 -0
- package/dist/repositories/index.js +1 -0
- package/dist/routing/Controller.d.ts +115 -0
- package/dist/routing/FormRequest.d.ts +94 -0
- package/dist/routing/Resource.d.ts +213 -0
- package/dist/routing/Response.d.ts +138 -0
- package/dist/routing/index.d.ts +4 -0
- package/dist/routing/index.js +5 -0
- package/dist/scheduler/ScheduleMonitor.d.ts +141 -0
- package/dist/scheduler/ScheduleMonitor.js +1 -0
- package/dist/scheduler/SchedulerLock.d.ts +33 -0
- package/dist/scheduler/index.d.ts +208 -0
- package/dist/scheduler/index.js +34 -0
- package/dist/services/index.d.ts +79 -0
- package/dist/services/index.js +1 -0
- package/dist/session/Session.d.ts +166 -0
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.js +16 -0
- package/dist/storage/index.d.ts +154 -0
- package/dist/storage/index.js +1 -0
- package/dist/support/Pipeline.d.ts +65 -0
- package/dist/support/date.d.ts +136 -0
- package/dist/support/date.js +1 -0
- package/dist/support/index.d.ts +8 -0
- package/dist/support/index.js +1 -0
- package/dist/support/singleton.d.ts +10 -0
- package/dist/support/uuid.d.ts +40 -0
- package/dist/teams/index.d.ts +91 -0
- package/dist/teams/index.js +78 -0
- package/dist/uploads/index.d.ts +63 -0
- package/dist/uploads/index.js +2 -0
- package/dist/validation/index.d.ts +46 -0
- package/dist/validation/index.js +1 -0
- package/dist/webhooks/index.d.ts +66 -0
- package/dist/webhooks/index.js +1 -0
- package/package.json +338 -0
- package/src/i18n/LanguageSwitcher.svelte +47 -0
- package/src/i18n/index.ts +113 -0
- package/src/ui/Alert.svelte +22 -0
- package/src/ui/Avatar.svelte +18 -0
- package/src/ui/AvatarFallback.svelte +18 -0
- package/src/ui/AvatarImage.svelte +12 -0
- package/src/ui/Badge.svelte +27 -0
- package/src/ui/Button.svelte +51 -0
- package/src/ui/Card.svelte +15 -0
- package/src/ui/CardContent.svelte +15 -0
- package/src/ui/CardDescription.svelte +15 -0
- package/src/ui/CardFooter.svelte +15 -0
- package/src/ui/CardHeader.svelte +15 -0
- package/src/ui/CardTitle.svelte +15 -0
- package/src/ui/Icon.svelte +81 -0
- package/src/ui/Input.svelte +40 -0
- package/src/ui/Label.svelte +20 -0
- package/src/ui/Separator.svelte +10 -0
- package/src/ui/Tabs.svelte +23 -0
- package/src/ui/TabsContent.svelte +27 -0
- package/src/ui/TabsList.svelte +19 -0
- package/src/ui/TabsTrigger.svelte +28 -0
- package/src/ui/Toaster.svelte +279 -0
- package/src/ui/index.ts +31 -0
- package/src/ui/toast.ts +212 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelar Controller
|
|
3
|
+
*
|
|
4
|
+
* Laravel-inspired base Controller class for SvelteKit route handlers.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* // src/lib/controllers/UserController.ts
|
|
9
|
+
* class UserController extends Controller {
|
|
10
|
+
* async index(event: RequestEvent) {
|
|
11
|
+
* const users = await User.all();
|
|
12
|
+
* return this.json(users);
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* async show(event: RequestEvent) {
|
|
16
|
+
* const user = await User.findOrFail(event.params.id);
|
|
17
|
+
* return this.json(user);
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* async store(event: RequestEvent) {
|
|
21
|
+
* const data = await this.validate(event, {
|
|
22
|
+
* email: z.string().email(),
|
|
23
|
+
* name: z.string().min(2),
|
|
24
|
+
* });
|
|
25
|
+
* const user = await User.create(data);
|
|
26
|
+
* return this.json(user, 201);
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* // src/routes/api/users/+server.ts
|
|
31
|
+
* import { UserController } from '$lib/controllers/UserController';
|
|
32
|
+
* const ctrl = new UserController();
|
|
33
|
+
* export const GET = ctrl.handle('index');
|
|
34
|
+
* export const POST = ctrl.handle('store');
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
import { z, type ZodObject, type ZodRawShape } from 'zod';
|
|
38
|
+
import { type MiddlewareHandler, Middleware } from '../middleware/Middleware.js';
|
|
39
|
+
export interface RequestEvent {
|
|
40
|
+
request: Request;
|
|
41
|
+
url: URL;
|
|
42
|
+
params: Record<string, string>;
|
|
43
|
+
locals: Record<string, any>;
|
|
44
|
+
getClientAddress: () => string;
|
|
45
|
+
cookies: any;
|
|
46
|
+
platform: any;
|
|
47
|
+
}
|
|
48
|
+
export declare abstract class Controller {
|
|
49
|
+
private controllerMiddleware;
|
|
50
|
+
/**
|
|
51
|
+
* Register middleware for this controller
|
|
52
|
+
*/
|
|
53
|
+
protected middleware(middleware: Middleware | MiddlewareHandler | (new () => Middleware), options?: {
|
|
54
|
+
only?: string[];
|
|
55
|
+
except?: string[];
|
|
56
|
+
}): void;
|
|
57
|
+
/**
|
|
58
|
+
* Create a SvelteKit-compatible request handler bound to a controller method.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* export const GET = ctrl.handle('index');
|
|
63
|
+
* export const POST = ctrl.handle('store');
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
handle(method: string): (event: RequestEvent) => Promise<Response>;
|
|
67
|
+
protected json(data: any, status?: number, headers?: Record<string, string>): Response;
|
|
68
|
+
protected text(content: string, status?: number): Response;
|
|
69
|
+
protected html(content: string, status?: number): Response;
|
|
70
|
+
protected redirect(url: string, status?: number): Response;
|
|
71
|
+
protected noContent(): Response;
|
|
72
|
+
protected created(data?: any): Response;
|
|
73
|
+
protected validate<T extends ZodRawShape>(event: RequestEvent, schema: ZodObject<T> | T): Promise<z.infer<ZodObject<T>>>;
|
|
74
|
+
/**
|
|
75
|
+
* Validate query parameters
|
|
76
|
+
*/
|
|
77
|
+
protected validateQuery<T extends ZodRawShape>(event: RequestEvent, schema: ZodObject<T> | T): z.infer<ZodObject<T>>;
|
|
78
|
+
/**
|
|
79
|
+
* Validate route parameters
|
|
80
|
+
*/
|
|
81
|
+
protected validateParams<T extends ZodRawShape>(event: RequestEvent, schema: ZodObject<T> | T): z.infer<ZodObject<T>>;
|
|
82
|
+
protected handleError(error: any, event: RequestEvent): Response;
|
|
83
|
+
private callMethod;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Helper to bind all CRUD methods of a ResourceController to SvelteKit handlers.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* // src/routes/api/users/+server.ts
|
|
91
|
+
* import { resource } from 'svelar/routing';
|
|
92
|
+
* import { UserController } from '$lib/controllers/UserController';
|
|
93
|
+
*
|
|
94
|
+
* const { GET, POST } = resource(UserController);
|
|
95
|
+
* export { GET, POST };
|
|
96
|
+
*
|
|
97
|
+
* // src/routes/api/users/[id]/+server.ts
|
|
98
|
+
* const { GET, PUT, DELETE } = resource(UserController, true);
|
|
99
|
+
* export { GET, PUT, DELETE };
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare function resource<T extends Controller>(ControllerClass: new () => T, isSingleResource?: boolean): Record<string, (event: RequestEvent) => Promise<Response>>;
|
|
103
|
+
export declare class ValidationError extends Error {
|
|
104
|
+
errors: Record<string, string[]>;
|
|
105
|
+
constructor(zodError: z.ZodError);
|
|
106
|
+
}
|
|
107
|
+
export declare class NotFoundError extends Error {
|
|
108
|
+
constructor(message?: string);
|
|
109
|
+
}
|
|
110
|
+
export declare class UnauthorizedError extends Error {
|
|
111
|
+
constructor(message?: string);
|
|
112
|
+
}
|
|
113
|
+
export declare class ForbiddenError extends Error {
|
|
114
|
+
constructor(message?: string);
|
|
115
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelar Form Request
|
|
3
|
+
*
|
|
4
|
+
* Dedicated validation classes for complex request validation.
|
|
5
|
+
* Inspired by Laravel's Form Request.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { FormRequest } from 'svelar/routing';
|
|
10
|
+
* import { z } from 'svelar/validation';
|
|
11
|
+
*
|
|
12
|
+
* class CreateUserRequest extends FormRequest {
|
|
13
|
+
* rules() {
|
|
14
|
+
* return z.object({
|
|
15
|
+
* name: z.string().min(2).max(100),
|
|
16
|
+
* email: z.string().email(),
|
|
17
|
+
* password: z.string().min(8),
|
|
18
|
+
* password_confirmation: z.string(),
|
|
19
|
+
* }).refine(data => data.password === data.password_confirmation, {
|
|
20
|
+
* message: 'Passwords do not match',
|
|
21
|
+
* path: ['password_confirmation'],
|
|
22
|
+
* });
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* authorize(event: RequestEvent): boolean {
|
|
26
|
+
* return true; // Or check event.locals.user
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* messages() {
|
|
30
|
+
* return {
|
|
31
|
+
* 'name.min': 'Name must be at least 2 characters',
|
|
32
|
+
* };
|
|
33
|
+
* }
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* // In a controller:
|
|
37
|
+
* const data = await CreateUserRequest.validate(event);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
import { z, type ZodTypeAny } from 'zod';
|
|
41
|
+
import type { RequestEvent } from './Controller.js';
|
|
42
|
+
export declare abstract class FormRequest {
|
|
43
|
+
/**
|
|
44
|
+
* Define the validation rules (return a Zod schema)
|
|
45
|
+
*/
|
|
46
|
+
abstract rules(): ZodTypeAny;
|
|
47
|
+
/**
|
|
48
|
+
* Determine if the user is authorized to make this request.
|
|
49
|
+
* Override to add authorization logic.
|
|
50
|
+
*/
|
|
51
|
+
authorize(event: RequestEvent): boolean | Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Custom error messages (optional override).
|
|
54
|
+
* Keys are 'field.rule' format.
|
|
55
|
+
*/
|
|
56
|
+
messages(): Record<string, string>;
|
|
57
|
+
/**
|
|
58
|
+
* Custom attribute names for error messages (optional).
|
|
59
|
+
*/
|
|
60
|
+
attributes(): Record<string, string>;
|
|
61
|
+
/**
|
|
62
|
+
* Transform data after validation (optional).
|
|
63
|
+
*/
|
|
64
|
+
passedValidation(data: any): any;
|
|
65
|
+
/**
|
|
66
|
+
* Called when validation fails (optional override).
|
|
67
|
+
* By default throws a Response.
|
|
68
|
+
*/
|
|
69
|
+
failedValidation(errors: Record<string, string[]>): never;
|
|
70
|
+
/**
|
|
71
|
+
* Called when authorization fails (optional override).
|
|
72
|
+
*/
|
|
73
|
+
failedAuthorization(): never;
|
|
74
|
+
/**
|
|
75
|
+
* Parse request body based on content type
|
|
76
|
+
*/
|
|
77
|
+
protected parseBody(event: RequestEvent): Promise<any>;
|
|
78
|
+
/**
|
|
79
|
+
* Validate a request using this FormRequest class.
|
|
80
|
+
* Static factory method for convenience.
|
|
81
|
+
*/
|
|
82
|
+
static validate<T extends FormRequest>(this: new () => T, event: RequestEvent): Promise<z.infer<ReturnType<T['rules']>>>;
|
|
83
|
+
}
|
|
84
|
+
export declare class FormValidationError extends Error {
|
|
85
|
+
readonly errors: Record<string, string[]>;
|
|
86
|
+
readonly statusCode = 422;
|
|
87
|
+
constructor(errors: Record<string, string[]>);
|
|
88
|
+
toResponse(): Response;
|
|
89
|
+
}
|
|
90
|
+
export declare class FormAuthorizationError extends Error {
|
|
91
|
+
readonly statusCode = 403;
|
|
92
|
+
constructor(message?: string);
|
|
93
|
+
toResponse(): Response;
|
|
94
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelar Resource (API Response Transformer)
|
|
3
|
+
*
|
|
4
|
+
* Laravel-inspired JsonResource for shaping API responses.
|
|
5
|
+
* Controls exactly what data is exposed and how it's structured.
|
|
6
|
+
*
|
|
7
|
+
* The second generic `TShape` defines the API contract — the shape returned
|
|
8
|
+
* by `toJSON()`. Export this type from your resource file and import it on
|
|
9
|
+
* the frontend. Define once, use everywhere.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // Define the contract once
|
|
14
|
+
* export interface UserData {
|
|
15
|
+
* id: number;
|
|
16
|
+
* name: string;
|
|
17
|
+
* email: string;
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* export class UserResource extends Resource<User, UserData> {
|
|
21
|
+
* toJSON(): UserData {
|
|
22
|
+
* return {
|
|
23
|
+
* id: this.data.id,
|
|
24
|
+
* name: this.data.name,
|
|
25
|
+
* email: this.data.email,
|
|
26
|
+
* };
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* // Frontend — import the same type
|
|
31
|
+
* import type { UserData } from '$lib/modules/auth/UserResource';
|
|
32
|
+
* const { data } = await apiFetchJson<{ data: UserData }>('/api/users/1');
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* Extract the output shape from a Resource class.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* type User = InferResource<UserResource>;
|
|
41
|
+
* // { id: number; name: string; email: string; }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export type InferResource<R> = R extends Resource<any, infer TShape> ? TShape : never;
|
|
45
|
+
/**
|
|
46
|
+
* Wrapped single resource response shape.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* type UserResponse = ResourceData<UserResource>;
|
|
51
|
+
* // { data: { id: number; name: string; email: string; } }
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export type ResourceData<R> = R extends Resource<any, infer TShape> ? {
|
|
55
|
+
data: TShape;
|
|
56
|
+
[key: string]: any;
|
|
57
|
+
} : never;
|
|
58
|
+
/**
|
|
59
|
+
* Wrapped collection response shape with pagination metadata.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* type UsersResponse = ResourceCollection<UserResource>;
|
|
64
|
+
* // { data: UserData[]; meta?: { total: number; page: number; ... } }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export type ResourceCollection<R> = R extends Resource<any, infer TShape> ? {
|
|
68
|
+
data: TShape[];
|
|
69
|
+
meta?: Record<string, any>;
|
|
70
|
+
[key: string]: any;
|
|
71
|
+
} : never;
|
|
72
|
+
export declare abstract class Resource<TModel = any, TShape extends Record<string, any> = Record<string, any>> {
|
|
73
|
+
protected data: TModel;
|
|
74
|
+
constructor(data: TModel);
|
|
75
|
+
/**
|
|
76
|
+
* Define the response shape. Override this in your resource class.
|
|
77
|
+
* The return type should match TShape for full type safety.
|
|
78
|
+
*/
|
|
79
|
+
abstract toJSON(): TShape;
|
|
80
|
+
/**
|
|
81
|
+
* Define top-level data included alongside the resource.
|
|
82
|
+
* Override this to add roles, permissions, related context, etc.
|
|
83
|
+
* Called automatically by make(), collection(), and paginate().
|
|
84
|
+
*
|
|
85
|
+
* Can be sync or async.
|
|
86
|
+
*/
|
|
87
|
+
toWith(): Record<string, any> | Promise<Record<string, any>>;
|
|
88
|
+
/**
|
|
89
|
+
* Define metadata included under the "meta" key.
|
|
90
|
+
* Override this to add counts, flags, or computed summaries.
|
|
91
|
+
* Called automatically by make(), collection(), and paginate().
|
|
92
|
+
*
|
|
93
|
+
* Can be sync or async.
|
|
94
|
+
*/
|
|
95
|
+
toAdditional(): Record<string, any> | Promise<Record<string, any>>;
|
|
96
|
+
/**
|
|
97
|
+
* Wrap a single item in a resource.
|
|
98
|
+
*/
|
|
99
|
+
static make<TModel, TShape extends Record<string, any>, R extends Resource<TModel, TShape>>(this: new (data: TModel) => R, data: TModel): ResourceResponse;
|
|
100
|
+
/**
|
|
101
|
+
* Wrap an array of items in resources.
|
|
102
|
+
*/
|
|
103
|
+
static collection<TModel, TShape extends Record<string, any>, R extends Resource<TModel, TShape>>(this: new (data: TModel) => R, items: TModel[]): ResourceCollectionResponse;
|
|
104
|
+
/**
|
|
105
|
+
* Wrap a PaginationResult — transforms items and auto-includes pagination metadata.
|
|
106
|
+
*
|
|
107
|
+
* Accepts the result of `Model.query().paginate()` or `Repository.paginate()`.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* const result = await User.query().paginate(page, 20);
|
|
112
|
+
* return UserResource.paginate(result).toResponse();
|
|
113
|
+
* // { data: [...], meta: { total, page, per_page, last_page, has_more } }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
static paginate<TModel, TShape extends Record<string, any>, R extends Resource<TModel, TShape>>(this: new (data: TModel) => R, result: {
|
|
117
|
+
data: TModel[];
|
|
118
|
+
total: number;
|
|
119
|
+
page: number;
|
|
120
|
+
perPage: number;
|
|
121
|
+
lastPage: number;
|
|
122
|
+
hasMore: boolean;
|
|
123
|
+
}): ResourceCollectionResponse;
|
|
124
|
+
}
|
|
125
|
+
export declare class ResourceResponse {
|
|
126
|
+
private data;
|
|
127
|
+
private meta;
|
|
128
|
+
private extra;
|
|
129
|
+
private wrap;
|
|
130
|
+
private statusCode;
|
|
131
|
+
private extraHeaders;
|
|
132
|
+
private deferredWith;
|
|
133
|
+
private deferredAdditional;
|
|
134
|
+
constructor(data: Record<string, any>);
|
|
135
|
+
/** @internal — used by Resource.make() to attach toWith() */
|
|
136
|
+
_deferWith(result: Record<string, any> | Promise<Record<string, any>>): void;
|
|
137
|
+
/** @internal — used by Resource.make() to attach toAdditional() */
|
|
138
|
+
_deferAdditional(result: Record<string, any> | Promise<Record<string, any>>): void;
|
|
139
|
+
/**
|
|
140
|
+
* Add metadata to the response (nested under "meta").
|
|
141
|
+
*/
|
|
142
|
+
additional(meta: Record<string, any>): this;
|
|
143
|
+
/**
|
|
144
|
+
* Add top-level data alongside the resource.
|
|
145
|
+
*
|
|
146
|
+
* For data that should always be included, override `toWith()` in
|
|
147
|
+
* the Resource class instead — then controllers don't need to repeat it.
|
|
148
|
+
*/
|
|
149
|
+
with(data: Record<string, any>): this;
|
|
150
|
+
/**
|
|
151
|
+
* Change the wrapping key (default: "data"). Use null to unwrap.
|
|
152
|
+
*/
|
|
153
|
+
wrapper(key: string | null): this;
|
|
154
|
+
/**
|
|
155
|
+
* Set the HTTP status code.
|
|
156
|
+
*/
|
|
157
|
+
status(code: number): this;
|
|
158
|
+
/**
|
|
159
|
+
* Add response headers.
|
|
160
|
+
*/
|
|
161
|
+
headers(headers: Record<string, string>): this;
|
|
162
|
+
/**
|
|
163
|
+
* Build the plain object (for serialization or testing).
|
|
164
|
+
*/
|
|
165
|
+
toObject(): Promise<Record<string, any>>;
|
|
166
|
+
/**
|
|
167
|
+
* Convert to a Response object for SvelteKit handlers.
|
|
168
|
+
*/
|
|
169
|
+
toResponse(): Promise<Response>;
|
|
170
|
+
}
|
|
171
|
+
export declare class ResourceCollectionResponse {
|
|
172
|
+
private items;
|
|
173
|
+
private meta;
|
|
174
|
+
private extra;
|
|
175
|
+
private wrap;
|
|
176
|
+
private statusCode;
|
|
177
|
+
private extraHeaders;
|
|
178
|
+
private deferredInstances;
|
|
179
|
+
constructor(items: Record<string, any>[]);
|
|
180
|
+
/** @internal — used by Resource.collection()/paginate() */
|
|
181
|
+
_deferCollectionExtras(instances: Resource[]): void;
|
|
182
|
+
/**
|
|
183
|
+
* Add metadata (pagination, totals, etc.) — nested under "meta".
|
|
184
|
+
*/
|
|
185
|
+
additional(meta: Record<string, any>): this;
|
|
186
|
+
/**
|
|
187
|
+
* Add top-level data alongside the collection.
|
|
188
|
+
*
|
|
189
|
+
* For data that should always be included, override `toWith()` in
|
|
190
|
+
* the Resource class instead.
|
|
191
|
+
*/
|
|
192
|
+
with(data: Record<string, any>): this;
|
|
193
|
+
/**
|
|
194
|
+
* Change the wrapping key.
|
|
195
|
+
*/
|
|
196
|
+
wrapper(key: string | null): this;
|
|
197
|
+
/**
|
|
198
|
+
* Set HTTP status code.
|
|
199
|
+
*/
|
|
200
|
+
status(code: number): this;
|
|
201
|
+
/**
|
|
202
|
+
* Add response headers.
|
|
203
|
+
*/
|
|
204
|
+
headers(headers: Record<string, string>): this;
|
|
205
|
+
/**
|
|
206
|
+
* Build the plain object.
|
|
207
|
+
*/
|
|
208
|
+
toObject(): Promise<Record<string, any>>;
|
|
209
|
+
/**
|
|
210
|
+
* Convert to a Response object.
|
|
211
|
+
*/
|
|
212
|
+
toResponse(): Promise<Response>;
|
|
213
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelar Response Classes
|
|
3
|
+
*
|
|
4
|
+
* Laravel-inspired dedicated response objects for SvelteKit route handlers.
|
|
5
|
+
* These provide a fluent, testable API for building HTTP responses outside
|
|
6
|
+
* of controllers.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { JsonResponse, RedirectResponse } from '@beeblock/svelar/routing';
|
|
11
|
+
*
|
|
12
|
+
* return new JsonResponse({ name: 'John' });
|
|
13
|
+
* return new JsonResponse({ message: 'Created' }, 201);
|
|
14
|
+
* return JsonResponse.success({ id: 1 });
|
|
15
|
+
* return JsonResponse.error('Not found', 404);
|
|
16
|
+
* return new RedirectResponse('/login');
|
|
17
|
+
* return new DownloadResponse(buffer, 'report.pdf');
|
|
18
|
+
* return new StreamedResponse(readableStream, 'text/event-stream');
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare class JsonResponse {
|
|
22
|
+
private statusCode;
|
|
23
|
+
private body;
|
|
24
|
+
private extraHeaders;
|
|
25
|
+
constructor(data?: any, status?: number, headers?: Record<string, string>);
|
|
26
|
+
/**
|
|
27
|
+
* Set response headers (fluent).
|
|
28
|
+
*/
|
|
29
|
+
header(name: string, value: string): this;
|
|
30
|
+
/**
|
|
31
|
+
* Set multiple headers (fluent).
|
|
32
|
+
*/
|
|
33
|
+
headers(headers: Record<string, string>): this;
|
|
34
|
+
/**
|
|
35
|
+
* Set the status code (fluent).
|
|
36
|
+
*/
|
|
37
|
+
status(code: number): this;
|
|
38
|
+
/**
|
|
39
|
+
* Convert to a Response object.
|
|
40
|
+
*/
|
|
41
|
+
toResponse(): Response;
|
|
42
|
+
/** 200 with data */
|
|
43
|
+
static success(data: any, headers?: Record<string, string>): Response;
|
|
44
|
+
/** 201 Created */
|
|
45
|
+
static created(data: any, headers?: Record<string, string>): Response;
|
|
46
|
+
/** Error response with message */
|
|
47
|
+
static error(message: string, status?: number, errors?: Record<string, string[]>): Response;
|
|
48
|
+
/** 422 Validation Error */
|
|
49
|
+
static validationError(errors: Record<string, string[]>, message?: string): Response;
|
|
50
|
+
/** 204 No Content */
|
|
51
|
+
static noContent(): Response;
|
|
52
|
+
}
|
|
53
|
+
export declare class RedirectResponse {
|
|
54
|
+
private statusCode;
|
|
55
|
+
private url;
|
|
56
|
+
private extraHeaders;
|
|
57
|
+
constructor(url: string, status?: number);
|
|
58
|
+
/**
|
|
59
|
+
* Set additional headers.
|
|
60
|
+
*/
|
|
61
|
+
header(name: string, value: string): this;
|
|
62
|
+
/**
|
|
63
|
+
* Convert to a Response object.
|
|
64
|
+
*/
|
|
65
|
+
toResponse(): Response;
|
|
66
|
+
/** 302 Temporary redirect */
|
|
67
|
+
static to(url: string): Response;
|
|
68
|
+
/** 301 Permanent redirect */
|
|
69
|
+
static permanent(url: string): Response;
|
|
70
|
+
/** 307 Temporary redirect (preserves method) */
|
|
71
|
+
static temporary(url: string): Response;
|
|
72
|
+
/** Redirect back using Referer header, with a fallback URL */
|
|
73
|
+
static back(request: Request, fallback?: string): Response;
|
|
74
|
+
}
|
|
75
|
+
export declare class DownloadResponse {
|
|
76
|
+
private statusCode;
|
|
77
|
+
private body;
|
|
78
|
+
private filename;
|
|
79
|
+
private contentType;
|
|
80
|
+
private extraHeaders;
|
|
81
|
+
constructor(body: BodyInit, filename: string, contentType?: string);
|
|
82
|
+
/**
|
|
83
|
+
* Set additional headers.
|
|
84
|
+
*/
|
|
85
|
+
header(name: string, value: string): this;
|
|
86
|
+
/**
|
|
87
|
+
* Set the status code.
|
|
88
|
+
*/
|
|
89
|
+
status(code: number): this;
|
|
90
|
+
/**
|
|
91
|
+
* Convert to a Response object with Content-Disposition: attachment.
|
|
92
|
+
*/
|
|
93
|
+
toResponse(): Response;
|
|
94
|
+
/** Download from a string or buffer */
|
|
95
|
+
static make(body: BodyInit, filename: string, contentType?: string): Response;
|
|
96
|
+
/** Download JSON as a file */
|
|
97
|
+
static json(data: any, filename?: string): Response;
|
|
98
|
+
/** Download CSV */
|
|
99
|
+
static csv(content: string, filename?: string): Response;
|
|
100
|
+
private inferContentType;
|
|
101
|
+
}
|
|
102
|
+
export declare class StreamedResponse {
|
|
103
|
+
private statusCode;
|
|
104
|
+
private body;
|
|
105
|
+
private contentType;
|
|
106
|
+
private extraHeaders;
|
|
107
|
+
constructor(body: ReadableStream | BodyInit, contentType?: string);
|
|
108
|
+
/**
|
|
109
|
+
* Set additional headers.
|
|
110
|
+
*/
|
|
111
|
+
header(name: string, value: string): this;
|
|
112
|
+
/**
|
|
113
|
+
* Set the status code.
|
|
114
|
+
*/
|
|
115
|
+
status(code: number): this;
|
|
116
|
+
/**
|
|
117
|
+
* Convert to a Response object.
|
|
118
|
+
*/
|
|
119
|
+
toResponse(): Response;
|
|
120
|
+
/**
|
|
121
|
+
* Create an SSE (Server-Sent Events) stream from a generator function.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* return StreamedResponse.sse(async function* () {
|
|
126
|
+
* yield { event: 'update', data: { count: 1 } };
|
|
127
|
+
* yield { data: 'plain text message' };
|
|
128
|
+
* });
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
static sse(generator: () => AsyncGenerator<{
|
|
132
|
+
event?: string;
|
|
133
|
+
data: any;
|
|
134
|
+
id?: string;
|
|
135
|
+
}, void, unknown>): Response;
|
|
136
|
+
/** Create a simple text stream */
|
|
137
|
+
static text(body: ReadableStream): Response;
|
|
138
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { Controller, resource, ValidationError, NotFoundError, UnauthorizedError, ForbiddenError, type RequestEvent, } from './Controller.js';
|
|
2
|
+
export { FormRequest, FormValidationError, FormAuthorizationError } from './FormRequest.js';
|
|
3
|
+
export { Resource, ResourceResponse, ResourceCollectionResponse, type InferResource, type ResourceData, type ResourceCollection, } from './Resource.js';
|
|
4
|
+
export { JsonResponse, RedirectResponse, DownloadResponse, StreamedResponse } from './Response.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{z as l}from"zod";var h=class{},g=class{middleware=[];namedMiddleware=new Map;use(e){return typeof e=="function"&&"prototype"in e&&typeof e.prototype?.handle=="function"?this.middleware.push(new e):this.middleware.push(e),this}register(e,t){return typeof t=="function"&&"prototype"in t&&typeof t.prototype?.handle=="function"?this.namedMiddleware.set(e,new t):this.namedMiddleware.set(e,t),this}get(e){return this.namedMiddleware.get(e)}async execute(e,t,s){let n=[...this.middleware];if(s)for(let o of s){let i=this.namedMiddleware.get(o);i&&n.push(i)}let a=t;for(let o=n.length-1;o>=0;o--){let i=n[o],d=a;typeof i.handle=="function"?a=()=>i.handle(e,d):a=()=>i(e,d)}return a()}count(){return this.middleware.length}};var T=class{controllerMiddleware=[];middleware(e,t){let s;typeof e=="function"&&e.prototype instanceof h?s=new e:s=e,this.controllerMiddleware.push({middleware:s,only:t?.only,except:t?.except})}handle(e){return async t=>{try{let s=this.controllerMiddleware.filter(n=>!(n.only&&!n.only.includes(e)||n.except&&n.except.includes(e)));if(s.length>0){let n=new g;for(let{middleware:i}of s)n.use(i);let a={event:t,params:t.params,locals:t.locals},o=await n.execute(a,async()=>this.callMethod(e,t));if(o instanceof Response)return o}return await this.callMethod(e,t)}catch(s){return this.handleError(s,t)}}}json(e,t=200,s={}){let n=JSON.stringify(e,null,2);return new Response(n,{status:t,headers:{"Content-Type":"application/json",...s}})}text(e,t=200){return new Response(e,{status:t,headers:{"Content-Type":"text/plain"}})}html(e,t=200){return new Response(e,{status:t,headers:{"Content-Type":"text/html"}})}redirect(e,t=302){return new Response(null,{status:t,headers:{Location:e}})}noContent(){return new Response(null,{status:204})}created(e){return e?this.json(e,201):new Response(null,{status:201})}async validate(e,t){let s=t instanceof l.ZodObject?t:l.object(t),n,a=e.request.headers.get("content-type")??"";if(a.includes("application/json"))n=await e.request.json();else if(a.includes("multipart/form-data")||a.includes("application/x-www-form-urlencoded")){let i=await e.request.formData();n=Object.fromEntries(i)}else n=Object.fromEntries(e.url.searchParams);let o=s.safeParse(n);if(!o.success)throw new c(o.error);return o.data}validateQuery(e,t){let s=t instanceof l.ZodObject?t:l.object(t),n=Object.fromEntries(e.url.searchParams),a=s.safeParse(n);if(!a.success)throw new c(a.error);return a.data}validateParams(e,t){let n=(t instanceof l.ZodObject?t:l.object(t)).safeParse(e.params);if(!n.success)throw new c(n.error);return n.data}handleError(e,t){return e instanceof c?this.json({message:"Validation failed",errors:e.errors},422):e instanceof m?this.json({message:e.message||"Not found"},404):e instanceof y?this.json({message:e.message||"Unauthorized"},401):e instanceof f?this.json({message:e.message||"Forbidden"},403):(console.error("[Svelar] Controller error:",e),this.json({message:process.env.NODE_ENV==="production"?"Internal server error":e.message},500))}async callMethod(e,t){let s=this[e];if(typeof s!="function")throw new Error(`Method "${e}" not found on controller "${this.constructor.name}".`);let n=await s.call(this,t);return n instanceof Response?n:this.json(n)}};function H(r,e=!1){let t=new r;return e?{GET:t.handle("show"),PUT:t.handle("update"),PATCH:t.handle("update"),DELETE:t.handle("destroy")}:{GET:t.handle("index"),POST:t.handle("store")}}var c=class extends Error{errors;constructor(e){super("Validation failed"),this.name="ValidationError",this.errors={};for(let t of e.issues){let s=t.path.join(".");this.errors[s]||(this.errors[s]=[]),this.errors[s].push(t.message)}}},m=class extends Error{constructor(e="Not found"){super(e),this.name="NotFoundError"}},y=class extends Error{constructor(e="Unauthorized"){super(e),this.name="UnauthorizedError"}},f=class extends Error{constructor(e="Forbidden"){super(e),this.name="ForbiddenError"}};var C=class{authorize(e){return!0}messages(){return{}}attributes(){return{}}passedValidation(e){return e}failedValidation(e){throw new R(e)}failedAuthorization(){throw new w}async parseBody(e){let t=e.request.headers.get("content-type")??"";if(t.includes("application/json"))return e.request.json();if(t.includes("multipart/form-data")||t.includes("application/x-www-form-urlencoded")){let s=await e.request.formData();return Object.fromEntries(s)}return Object.fromEntries(e.url.searchParams)}static async validate(e){let t=new this;await t.authorize(e)||t.failedAuthorization();let n=await t.parseBody(e),a={...Object.fromEntries(e.url.searchParams),...e.params,...n},i=t.rules().safeParse(a);if(!i.success){let d={},A=t.messages(),E=t.attributes();for(let b of i.error.issues){let p=b.path.join("."),v=E[p]??p;d[v]||(d[v]=[]);let N=`${p}.${b.code}`,q=A[N]??A[p];d[v].push(q??b.message)}t.failedValidation(d)}return t.passedValidation(i.data)}},R=class extends Error{constructor(t){super("The given data was invalid.");this.errors=t;this.name="FormValidationError"}statusCode=422;toResponse(){return new Response(JSON.stringify({message:this.message,errors:this.errors}),{status:422,headers:{"Content-Type":"application/json"}})}},w=class extends Error{statusCode=403;constructor(e="This action is unauthorized."){super(e),this.name="FormAuthorizationError"}toResponse(){return new Response(JSON.stringify({message:this.message}),{status:403,headers:{"Content-Type":"application/json"}})}};var M=class{constructor(e){this.data=e}toWith(){return{}}toAdditional(){return{}}static make(e){let t=new this(e),s=new x(t.toJSON());return s._deferWith(t.toWith()),s._deferAdditional(t.toAdditional()),s}static collection(e){let t=this,s=e.map(o=>new t(o)),n=s.map(o=>o.toJSON()),a=new u(n);return s.length>0&&a._deferCollectionExtras(s),a}static paginate(e){let t=this,s=e.data.map(o=>new t(o)),n=s.map(o=>o.toJSON()),a=new u(n).additional({total:e.total,page:e.page,per_page:e.perPage,last_page:e.lastPage,has_more:e.hasMore});return s.length>0&&a._deferCollectionExtras(s),a}},x=class{constructor(e){this.data=e}meta={};extra={};wrap="data";statusCode=200;extraHeaders={};deferredWith=null;deferredAdditional=null;_deferWith(e){this.deferredWith=e}_deferAdditional(e){this.deferredAdditional=e}additional(e){return this.meta={...this.meta,...e},this}with(e){return this.extra={...this.extra,...e},this}wrapper(e){return this.wrap=e??"",this}status(e){return this.statusCode=e,this}headers(e){return this.extraHeaders={...this.extraHeaders,...e},this}async toObject(){if(this.deferredWith){let t=await this.deferredWith;t&&Object.keys(t).length>0&&(this.extra={...t,...this.extra})}if(this.deferredAdditional){let t=await this.deferredAdditional;t&&Object.keys(t).length>0&&(this.meta={...t,...this.meta})}let e={};return this.wrap?e[this.wrap]=this.data:Object.assign(e,this.data),Object.keys(this.meta).length>0&&(e.meta=this.meta),Object.assign(e,this.extra),e}async toResponse(){let e=await this.toObject();return new Response(JSON.stringify(e,null,2),{status:this.statusCode,headers:{"Content-Type":"application/json",...this.extraHeaders}})}},u=class{constructor(e){this.items=e}meta={};extra={};wrap="data";statusCode=200;extraHeaders={};deferredInstances=null;_deferCollectionExtras(e){this.deferredInstances=e}additional(e){return this.meta={...this.meta,...e},this}with(e){return this.extra={...this.extra,...e},this}wrapper(e){return this.wrap=e??"",this}status(e){return this.statusCode=e,this}headers(e){return this.extraHeaders={...this.extraHeaders,...e},this}async toObject(){if(this.deferredInstances&&this.deferredInstances.length>0){let t=this.deferredInstances[0],s=await t.toWith();s&&Object.keys(s).length>0&&(this.extra={...s,...this.extra});let n=await t.toAdditional();n&&Object.keys(n).length>0&&(this.meta={...n,...this.meta})}let e={};if(this.wrap)e[this.wrap]=this.items;else return{items:this.items,...this.meta,...this.extra};return Object.keys(this.meta).length>0&&(e.meta=this.meta),Object.assign(e,this.extra),e}async toResponse(){let e=await this.toObject();return new Response(JSON.stringify(e,null,2),{status:this.statusCode,headers:{"Content-Type":"application/json",...this.extraHeaders}})}};var j=class r{statusCode;body;extraHeaders={};constructor(e=null,t=200,s={}){this.body=e,this.statusCode=t,this.extraHeaders=s}header(e,t){return this.extraHeaders[e]=t,this}headers(e){return Object.assign(this.extraHeaders,e),this}status(e){return this.statusCode=e,this}toResponse(){return new Response(JSON.stringify(this.body,null,2),{status:this.statusCode,headers:{"Content-Type":"application/json",...this.extraHeaders}})}static success(e,t){return new r(e,200,t).toResponse()}static created(e,t){return new r(e,201,t).toResponse()}static error(e,t=500,s){let n={message:e};return s&&(n.errors=s),new r(n,t).toResponse()}static validationError(e,t="Validation failed"){return new r({message:t,errors:e},422).toResponse()}static noContent(){return new Response(null,{status:204})}},P=class r{statusCode;url;extraHeaders={};constructor(e,t=302){this.url=e,this.statusCode=t}header(e,t){return this.extraHeaders[e]=t,this}toResponse(){return new Response(null,{status:this.statusCode,headers:{Location:this.url,...this.extraHeaders}})}static to(e){return new r(e,302).toResponse()}static permanent(e){return new r(e,301).toResponse()}static temporary(e){return new r(e,307).toResponse()}static back(e,t="/"){let s=e.headers.get("referer")??t;return new r(s,302).toResponse()}},S=class r{statusCode=200;body;filename;contentType;extraHeaders={};constructor(e,t,s){this.body=e,this.filename=t,this.contentType=s??this.inferContentType(t)}header(e,t){return this.extraHeaders[e]=t,this}status(e){return this.statusCode=e,this}toResponse(){return new Response(this.body,{status:this.statusCode,headers:{"Content-Type":this.contentType,"Content-Disposition":`attachment; filename="${this.filename}"`,...this.extraHeaders}})}static make(e,t,s){return new r(e,t,s).toResponse()}static json(e,t="data.json"){let s=JSON.stringify(e,null,2);return new r(s,t,"application/json").toResponse()}static csv(e,t="export.csv"){return new r(e,t,"text/csv; charset=utf-8").toResponse()}inferContentType(e){let t=e.split(".").pop()?.toLowerCase();return{json:"application/json",csv:"text/csv",txt:"text/plain",pdf:"application/pdf",zip:"application/zip",xml:"application/xml",html:"text/html",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",svg:"image/svg+xml",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document"}[t??""]??"application/octet-stream"}},O=class r{statusCode=200;body;contentType;extraHeaders={};constructor(e,t="text/event-stream"){this.body=e,this.contentType=t}header(e,t){return this.extraHeaders[e]=t,this}status(e){return this.statusCode=e,this}toResponse(){return new Response(this.body,{status:this.statusCode,headers:{"Content-Type":this.contentType,"Cache-Control":"no-cache",Connection:"keep-alive",...this.extraHeaders}})}static sse(e){let t=new ReadableStream({async start(s){let n=new TextEncoder;try{for await(let a of e()){let o="";a.id&&(o+=`id: ${a.id}
|
|
2
|
+
`),a.event&&(o+=`event: ${a.event}
|
|
3
|
+
`);let i=typeof a.data=="string"?a.data:JSON.stringify(a.data);o+=`data: ${i}
|
|
4
|
+
|
|
5
|
+
`,s.enqueue(n.encode(o))}}catch{}finally{s.close()}}});return new r(t,"text/event-stream").toResponse()}static text(e){return new r(e,"text/plain").toResponse()}};export{T as Controller,S as DownloadResponse,f as ForbiddenError,w as FormAuthorizationError,C as FormRequest,R as FormValidationError,j as JsonResponse,m as NotFoundError,P as RedirectResponse,M as Resource,u as ResourceCollectionResponse,x as ResourceResponse,O as StreamedResponse,y as UnauthorizedError,c as ValidationError,H as resource};
|