@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,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelar Schema Builder
|
|
3
|
+
*
|
|
4
|
+
* Laravel-like schema builder that generates raw SQL for migrations.
|
|
5
|
+
* Database-agnostic: produces the right SQL for SQLite, PostgreSQL, or MySQL.
|
|
6
|
+
*/
|
|
7
|
+
import { type DatabaseDriver } from './Connection.js';
|
|
8
|
+
export interface ColumnDefinition {
|
|
9
|
+
name: string;
|
|
10
|
+
type: string;
|
|
11
|
+
nullable: boolean;
|
|
12
|
+
defaultValue?: any;
|
|
13
|
+
primaryKey: boolean;
|
|
14
|
+
autoIncrement: boolean;
|
|
15
|
+
unique: boolean;
|
|
16
|
+
unsigned: boolean;
|
|
17
|
+
references?: {
|
|
18
|
+
table: string;
|
|
19
|
+
column: string;
|
|
20
|
+
onDelete?: string;
|
|
21
|
+
onUpdate?: string;
|
|
22
|
+
};
|
|
23
|
+
check?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare class ColumnBuilder {
|
|
26
|
+
private column;
|
|
27
|
+
constructor(column: ColumnDefinition);
|
|
28
|
+
nullable(): ColumnBuilder;
|
|
29
|
+
notNullable(): ColumnBuilder;
|
|
30
|
+
default(value: any): ColumnBuilder;
|
|
31
|
+
primary(): ColumnBuilder;
|
|
32
|
+
unique(): ColumnBuilder;
|
|
33
|
+
unsigned(): ColumnBuilder;
|
|
34
|
+
references(column: string, table: string): ForeignKeyBuilder;
|
|
35
|
+
/** @internal */
|
|
36
|
+
build(): ColumnDefinition;
|
|
37
|
+
}
|
|
38
|
+
export declare class ForeignKeyBuilder {
|
|
39
|
+
private column;
|
|
40
|
+
constructor(column: ColumnDefinition);
|
|
41
|
+
onDelete(action: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION'): ForeignKeyBuilder;
|
|
42
|
+
onUpdate(action: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION'): ForeignKeyBuilder;
|
|
43
|
+
}
|
|
44
|
+
export declare class TableBuilder {
|
|
45
|
+
private columns;
|
|
46
|
+
private indices;
|
|
47
|
+
private compositePrimary;
|
|
48
|
+
private addColumn;
|
|
49
|
+
increments(name?: string): ColumnBuilder;
|
|
50
|
+
bigIncrements(name?: string): ColumnBuilder;
|
|
51
|
+
string(name: string, length?: number): ColumnBuilder;
|
|
52
|
+
text(name: string): ColumnBuilder;
|
|
53
|
+
integer(name: string): ColumnBuilder;
|
|
54
|
+
bigInteger(name: string): ColumnBuilder;
|
|
55
|
+
float(name: string): ColumnBuilder;
|
|
56
|
+
decimal(name: string, precision?: number, scale?: number): ColumnBuilder;
|
|
57
|
+
boolean(name: string): ColumnBuilder;
|
|
58
|
+
date(name: string): ColumnBuilder;
|
|
59
|
+
datetime(name: string): ColumnBuilder;
|
|
60
|
+
timestamp(name: string): ColumnBuilder;
|
|
61
|
+
timestamps(): void;
|
|
62
|
+
json(name: string): ColumnBuilder;
|
|
63
|
+
blob(name: string): ColumnBuilder;
|
|
64
|
+
enum(name: string, values: string[]): ColumnBuilder;
|
|
65
|
+
uuid(name?: string): ColumnBuilder;
|
|
66
|
+
ulid(name?: string): ColumnBuilder;
|
|
67
|
+
jsonb(name: string): ColumnBuilder;
|
|
68
|
+
primary(columns: string[]): void;
|
|
69
|
+
index(columns: string | string[], name?: string): void;
|
|
70
|
+
uniqueIndex(columns: string | string[], name?: string): void;
|
|
71
|
+
foreign(column: string): ColumnBuilder;
|
|
72
|
+
/** @internal */
|
|
73
|
+
toSQL(tableName: string, driver: DatabaseDriver): string[];
|
|
74
|
+
private columnToSQL;
|
|
75
|
+
private mapSQLiteType;
|
|
76
|
+
private mapPostgresType;
|
|
77
|
+
private mapMySQLType;
|
|
78
|
+
}
|
|
79
|
+
export declare class Schema {
|
|
80
|
+
private connectionName?;
|
|
81
|
+
constructor(connectionName?: string | undefined);
|
|
82
|
+
createTable(name: string, callback: (table: TableBuilder) => void): Promise<void>;
|
|
83
|
+
dropTable(name: string): Promise<void>;
|
|
84
|
+
dropTableIfExists(name: string): Promise<void>;
|
|
85
|
+
renameTable(from: string, to: string): Promise<void>;
|
|
86
|
+
hasTable(name: string): Promise<boolean>;
|
|
87
|
+
addColumn(table: string, callback: (tb: TableBuilder) => void): Promise<void>;
|
|
88
|
+
dropColumn(table: string, column: string): Promise<void>;
|
|
89
|
+
}
|
|
90
|
+
/** Default schema instance */
|
|
91
|
+
export declare const schema: Schema;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { Connection, type DatabaseConfig, type DatabaseDriver, type ConnectionsConfig, type DrizzleInstance } from './Connection.js';
|
|
2
|
+
export { Schema, schema, TableBuilder, ColumnBuilder, ForeignKeyBuilder, type ColumnDefinition } from './SchemaBuilder.js';
|
|
3
|
+
export { Migration, Migrator, type MigrationFile } from './Migration.js';
|
|
4
|
+
export { Seeder } from './Seeder.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
function f(u,t){let e=Symbol.for(u),n=globalThis;return n[e]||(n[e]=t()),n[e]}var p=class{connections=new Map;config=null;defaultName="default";configure(t){this.config=t,this.defaultName=t.default}async connection(t){let e=t??this.defaultName;if(this.connections.has(e))return this.connections.get(e).drizzle;if(!this.config)throw new Error("Database not configured. Call Connection.configure() first, or register DatabaseServiceProvider.");let n=this.config.connections[e];if(!n)throw new Error(`Database connection "${e}" is not defined in configuration.`);let r=await this.createConnection(n);return this.connections.set(e,r),r.drizzle}async rawClient(t){let e=t??this.defaultName;return await this.connection(e),this.connections.get(e).rawClient}async raw(t,e=[],n){let r=await this.connection(n),i=this.getConfig(n);switch(i.driver){case"sqlite":{let a=await this.rawClient(n),o=e.map(l=>typeof l=="boolean"?l?1:0:l instanceof Date?l.toISOString():l),c=a.prepare(t),m=t.trimStart().toUpperCase();return m.startsWith("SELECT")||m.startsWith("PRAGMA")||m.startsWith("WITH")?c.all(...o):c.run(...o)}case"postgres":return(await this.rawClient(n))(t,...e);case"mysql":{let a=await this.rawClient(n),[o]=await a.execute(t,e);return o}default:throw new Error(`Unsupported driver: ${i.driver}`)}}getDriver(t){return this.getConfig(t).driver}getConfig(t){let e=t??this.defaultName;if(!this.config)throw new Error("Database not configured.");let n=this.config.connections[e];if(!n)throw new Error(`Database connection "${e}" is not defined.`);return n}async disconnect(t){if(t){let e=this.connections.get(t);e&&(await this.closeConnection(e),this.connections.delete(t))}else{for(let[e,n]of this.connections)await this.closeConnection(n);this.connections.clear()}}isConnected(t){return this.connections.has(t??this.defaultName)}async transaction(t,e){let n=this.getConfig(e),r=await this.rawClient(e);switch(n.driver){case"sqlite":{r.exec("BEGIN");try{let i=await t();return r.exec("COMMIT"),i}catch(i){throw r.exec("ROLLBACK"),i}}case"postgres":{await r`BEGIN`;try{let i=await t();return await r`COMMIT`,i}catch(i){throw await r`ROLLBACK`,i}}case"mysql":{let i=await r.getConnection();await i.beginTransaction();try{let a=await t();return await i.commit(),i.release(),a}catch(a){throw await i.rollback(),i.release(),a}}default:throw new Error(`Unsupported driver: ${n.driver}`)}}async createConnection(t){switch(t.driver){case"sqlite":return this.createSQLiteConnection(t);case"postgres":return this.createPostgresConnection(t);case"mysql":return this.createMySQLConnection(t);default:throw new Error(`Unsupported database driver: ${t.driver}`)}}async createSQLiteConnection(t){let e=t.filename??t.database??":memory:";try{let n=(await import("better-sqlite3")).default,{drizzle:r}=await import("drizzle-orm/better-sqlite3"),i=new n(e);return i.pragma("journal_mode = WAL"),i.pragma("foreign_keys = ON"),{drizzle:r(i),config:t,rawClient:i}}catch(n){let r;try{r=(await new Function("mod","return import(mod)")("node:sqlite")).DatabaseSync}catch{throw new Error(`No SQLite driver available. Install better-sqlite3 (npm install better-sqlite3) or use Node.js v22+ which includes built-in SQLite support. Original error: ${n instanceof Error?n.message:String(n)}`)}let i=new r(e);i.exec("PRAGMA journal_mode = WAL"),i.exec("PRAGMA foreign_keys = ON");let a={prepare(c){let m=i.prepare(c);return{all(...l){return m.all(...l)},run(...l){return m.run(...l)},get(...l){return m.get(...l)}}},exec(c){i.exec(c)},pragma(c){return i.prepare(`PRAGMA ${c}`).all()},close(){i.close()}},o;try{let{drizzle:c}=await import("drizzle-orm/better-sqlite3");o=c(a)}catch{o=a}return{drizzle:o,config:t,rawClient:a}}}async createPostgresConnection(t){let e=(await import("postgres")).default,{drizzle:n}=await import("drizzle-orm/postgres-js"),r=t.url??`postgres://${t.user}:${t.password}@${t.host??"localhost"}:${t.port??5432}/${t.database}`,i=e(r);return{drizzle:n(i),config:t,rawClient:i}}async createMySQLConnection(t){let e=await import("mysql2/promise"),{drizzle:n}=await import("drizzle-orm/mysql2"),r=e.createPool({host:t.host??"localhost",port:t.port??3306,database:t.database,user:t.user,password:t.password,uri:t.url});return{drizzle:n(r),config:t,rawClient:r}}async closeConnection(t){try{switch(t.config.driver){case"sqlite":t.rawClient.close();break;case"postgres":await t.rawClient.end();break;case"mysql":await t.rawClient.end();break}}catch{}}},s=f("svelar.connection",()=>new p);var d=class{constructor(t){this.column=t}nullable(){return this.column.nullable=!0,this}notNullable(){return this.column.nullable=!1,this}default(t){return this.column.defaultValue=t,this}primary(){return this.column.primaryKey=!0,this}unique(){return this.column.unique=!0,this}unsigned(){return this.column.unsigned=!0,this}references(t,e){return this.column.references={table:e,column:t},new w(this.column)}build(){return this.column}},w=class{constructor(t){this.column=t}onDelete(t){return this.column.references.onDelete=t,this}onUpdate(t){return this.column.references.onUpdate=t,this}},h=class{columns=[];indices=[];compositePrimary=null;addColumn(t,e){let n={name:t,type:e,nullable:!1,primaryKey:!1,autoIncrement:!1,unique:!1,unsigned:!1};return this.columns.push(n),new d(n)}increments(t="id"){let e={name:t,type:"INTEGER",nullable:!1,primaryKey:!0,autoIncrement:!0,unique:!1,unsigned:!0};return this.columns.push(e),new d(e)}bigIncrements(t="id"){let e={name:t,type:"BIGINT",nullable:!1,primaryKey:!0,autoIncrement:!0,unique:!1,unsigned:!0};return this.columns.push(e),new d(e)}string(t,e=255){return this.addColumn(t,`VARCHAR(${e})`)}text(t){return this.addColumn(t,"TEXT")}integer(t){return this.addColumn(t,"INTEGER")}bigInteger(t){return this.addColumn(t,"BIGINT")}float(t){return this.addColumn(t,"FLOAT")}decimal(t,e=8,n=2){return this.addColumn(t,`DECIMAL(${e},${n})`)}boolean(t){return this.addColumn(t,"BOOLEAN")}date(t){return this.addColumn(t,"DATE")}datetime(t){return this.addColumn(t,"DATETIME")}timestamp(t){return this.addColumn(t,"TIMESTAMP")}timestamps(){this.timestamp("created_at").nullable(),this.timestamp("updated_at").nullable()}json(t){return this.addColumn(t,"JSON")}blob(t){return this.addColumn(t,"BLOB")}enum(t,e){return this.addColumn(t,`ENUM(${e.map(n=>`'${n}'`).join(",")})`)}uuid(t="id"){return this.addColumn(t,"UUID")}ulid(t="id"){return this.addColumn(t,"ULID")}jsonb(t){return this.addColumn(t,"JSONB")}primary(t){this.compositePrimary=t}index(t,e){let n=Array.isArray(t)?t:[t];this.indices.push({columns:n,unique:!1,name:e})}uniqueIndex(t,e){let n=Array.isArray(t)?t:[t];this.indices.push({columns:n,unique:!0,name:e})}foreign(t){let e=this.columns.find(n=>n.name===t);if(!e)throw new Error(`Column "${t}" must be defined before adding a foreign key.`);return new d(e)}toSQL(t,e){let n=[],r=[];for(let i of this.columns)r.push(this.columnToSQL(i,e));this.compositePrimary&&r.push(`PRIMARY KEY (${this.compositePrimary.join(", ")})`);for(let i of this.columns)if(i.references){let a=`FOREIGN KEY (${i.name}) REFERENCES ${i.references.table}(${i.references.column})`;i.references.onDelete&&(a+=` ON DELETE ${i.references.onDelete}`),i.references.onUpdate&&(a+=` ON UPDATE ${i.references.onUpdate}`),r.push(a)}n.push(`CREATE TABLE ${t} (
|
|
2
|
+
${r.join(`,
|
|
3
|
+
`)}
|
|
4
|
+
)`);for(let i of this.indices){let a=i.name??`idx_${t}_${i.columns.join("_")}`,o=i.unique?"UNIQUE ":"";n.push(`CREATE ${o}INDEX ${a} ON ${t} (${i.columns.join(", ")})`)}return n}columnToSQL(t,e){let n=t.name,r=t.type;if(e==="sqlite"?r=this.mapSQLiteType(r,t):e==="postgres"?r=this.mapPostgresType(r,t):e==="mysql"&&(r=this.mapMySQLType(r,t)),n+=` ${r}`,t.primaryKey&&!this.compositePrimary&&(n+=" PRIMARY KEY",t.autoIncrement&&(e==="sqlite"?n+=" AUTOINCREMENT":e==="postgres"||e==="mysql"&&(n+=" AUTO_INCREMENT"))),!t.nullable&&!t.primaryKey&&(n+=" NOT NULL"),t.unique&&!t.primaryKey&&(n+=" UNIQUE"),t.defaultValue!==void 0){let i=typeof t.defaultValue=="string"?`'${t.defaultValue}'`:t.defaultValue===null?"NULL":t.defaultValue;n+=` DEFAULT ${i}`}return n}mapSQLiteType(t,e){return t==="BOOLEAN"?"INTEGER":t==="UUID"||t==="ULID"||t.startsWith("ENUM")||t==="JSON"||t==="JSONB"?"TEXT":t==="BIGINT"&&e.autoIncrement?"INTEGER":t}mapPostgresType(t,e){return e.autoIncrement&&t==="INTEGER"?"SERIAL":e.autoIncrement&&t==="BIGINT"?"BIGSERIAL":t==="DATETIME"?"TIMESTAMP":t==="BLOB"?"BYTEA":t.startsWith("ENUM")?"TEXT":t==="UUID"?"UUID":t==="ULID"?"VARCHAR(26)":t==="JSON"||t==="JSONB"?"JSONB":t}mapMySQLType(t,e){return t==="BOOLEAN"?"TINYINT(1)":t==="UUID"?"CHAR(36)":t==="ULID"?"CHAR(26)":t==="JSONB"?"JSON":t==="TIMESTAMP"?"DATETIME":e.unsigned&&!t.startsWith("DECIMAL")?`${t} UNSIGNED`:t}},g=class{constructor(t){this.connectionName=t}async createTable(t,e){let n=new h;e(n);let r=s.getDriver(this.connectionName),i=n.toSQL(t,r);for(let a of i)await s.raw(a,[],this.connectionName)}async dropTable(t){await s.raw(`DROP TABLE IF EXISTS ${t}`,[],this.connectionName)}async dropTableIfExists(t){await s.raw(`DROP TABLE IF EXISTS ${t}`,[],this.connectionName)}async renameTable(t,e){s.getDriver(this.connectionName)==="mysql"?await s.raw(`RENAME TABLE ${t} TO ${e}`,[],this.connectionName):await s.raw(`ALTER TABLE ${t} RENAME TO ${e}`,[],this.connectionName)}async hasTable(t){let e=s.getDriver(this.connectionName),n;switch(e){case"sqlite":n=await s.raw("SELECT name FROM sqlite_master WHERE type='table' AND name=?",[t],this.connectionName);break;case"postgres":n=await s.raw("SELECT tablename FROM pg_tables WHERE tablename = $1",[t],this.connectionName);break;case"mysql":n=await s.raw("SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_NAME = ?",[t],this.connectionName);break;default:throw new Error(`Unsupported driver: ${e}`)}return n.length>0}async addColumn(t,e){let n=new h;e(n);let r=s.getDriver(this.connectionName),i=n.columns;for(let a of i){let o=n.columnToSQL(a,r);await s.raw(`ALTER TABLE ${t} ADD COLUMN ${o}`,[],this.connectionName)}}async dropColumn(t,e){await s.raw(`ALTER TABLE ${t} DROP COLUMN ${e}`,[],this.connectionName)}},T=f("svelar.schema",()=>new g);var C=class{schema=new g},E=class{migrationsTable="svelar_migrations";connectionName;constructor(t){this.connectionName=t}async ensureMigrationsTable(){let t=new g(this.connectionName);await t.hasTable(this.migrationsTable)||await t.createTable(this.migrationsTable,n=>{n.increments("id"),n.string("migration").unique(),n.integer("batch"),n.timestamp("ran_at").default("CURRENT_TIMESTAMP")})}async run(t){await this.ensureMigrationsTable();let e=await this.getRanMigrations(),n=t.filter(a=>!e.includes(a.name));if(n.length===0)return[];let r=await this.getNextBatch(),i=[];for(let a of n)await a.migration.up(),await s.raw(`INSERT INTO ${this.migrationsTable} (migration, batch) VALUES (?, ?)`,[a.name,r],this.connectionName),i.push(a.name);return i}async rollback(t){await this.ensureMigrationsTable();let e=await this.getLastBatch();if(e===0)return[];let n=await s.raw(`SELECT migration FROM ${this.migrationsTable} WHERE batch = ? ORDER BY id DESC`,[e],this.connectionName),r=[];for(let i of n){let a=i.migration,o=t.find(c=>c.name===a);o&&(await o.migration.down(),await s.raw(`DELETE FROM ${this.migrationsTable} WHERE migration = ?`,[a],this.connectionName),r.push(a))}return r}async reset(t){let e=[];for(;;){let n=await this.rollback(t);if(n.length===0)break;e.push(...n)}return e}async refresh(t){let e=await this.reset(t),n=await this.run(t);return{reset:e,migrated:n}}async fresh(t){let e=await this.dropAllTables(),n=await this.run(t);return{dropped:e,migrated:n}}async dropAllTables(){let t=s.getDriver(this.connectionName),e=[];switch(t){case"sqlite":{e=(await s.raw("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'",[],this.connectionName)).map(r=>r.name),await s.raw("PRAGMA foreign_keys = OFF",[],this.connectionName);for(let r of e)await s.raw(`DROP TABLE IF EXISTS "${r}"`,[],this.connectionName);await s.raw("PRAGMA foreign_keys = ON",[],this.connectionName);break}case"mysql":{e=(await s.raw("SHOW TABLES",[],this.connectionName)).map(r=>Object.values(r)[0]),await s.raw("SET FOREIGN_KEY_CHECKS = 0",[],this.connectionName);for(let r of e)await s.raw(`DROP TABLE IF EXISTS \`${r}\``,[],this.connectionName);await s.raw("SET FOREIGN_KEY_CHECKS = 1",[],this.connectionName);break}case"postgres":{e=(await s.raw("SELECT tablename FROM pg_tables WHERE schemaname = 'public'",[],this.connectionName)).map(r=>r.tablename);for(let r of e)await s.raw(`DROP TABLE IF EXISTS "${r}" CASCADE`,[],this.connectionName);break}default:throw new Error(`Unsupported driver for fresh: ${t}`)}return e}async getRanMigrations(){try{return(await s.raw(`SELECT migration FROM ${this.migrationsTable} ORDER BY batch, id`,[],this.connectionName)).map(e=>e.migration)}catch{return[]}}async status(t){let e=await this.getRanMigrations(),n=new Map;try{let r=await s.raw(`SELECT migration, batch FROM ${this.migrationsTable}`,[],this.connectionName);for(let i of r)n.set(i.migration,i.batch)}catch{}return t.map(r=>({name:r.name,ran:e.includes(r.name),batch:n.get(r.name)??null}))}async getNextBatch(){return await this.getLastBatch()+1}async getLastBatch(){try{return(await s.raw(`SELECT MAX(batch) as max_batch FROM ${this.migrationsTable}`,[],this.connectionName))[0]?.max_batch??0}catch{return 0}}};var b=class{async call(t){await new t().run()}};export{d as ColumnBuilder,s as Connection,w as ForeignKeyBuilder,C as Migration,E as Migrator,g as Schema,b as Seeder,h as TableBuilder,T as schema};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelar Email Templates
|
|
3
|
+
* Reusable, customizable email templates with variable interpolation.
|
|
4
|
+
*/
|
|
5
|
+
export interface EmailTemplate {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
subject: string;
|
|
9
|
+
html: string;
|
|
10
|
+
text?: string;
|
|
11
|
+
variables: string[];
|
|
12
|
+
category?: string;
|
|
13
|
+
active: boolean;
|
|
14
|
+
createdAt: number;
|
|
15
|
+
updatedAt: number;
|
|
16
|
+
}
|
|
17
|
+
export interface RenderResult {
|
|
18
|
+
subject: string;
|
|
19
|
+
html: string;
|
|
20
|
+
text?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface TemplateConfig {
|
|
23
|
+
driver: 'database' | 'memory' | 'file';
|
|
24
|
+
path?: string;
|
|
25
|
+
table?: string;
|
|
26
|
+
}
|
|
27
|
+
declare class EmailTemplateManager {
|
|
28
|
+
private config;
|
|
29
|
+
private templates;
|
|
30
|
+
constructor();
|
|
31
|
+
configure(config: TemplateConfig): void;
|
|
32
|
+
/** Register a template */
|
|
33
|
+
register(template: Omit<EmailTemplate, 'id' | 'createdAt' | 'updatedAt'>): Promise<EmailTemplate>;
|
|
34
|
+
/** Render a template with variables */
|
|
35
|
+
render(name: string, variables: Record<string, any>): Promise<RenderResult>;
|
|
36
|
+
/** Get a template by name */
|
|
37
|
+
get(name: string): Promise<EmailTemplate | null>;
|
|
38
|
+
/** List all templates */
|
|
39
|
+
list(category?: string): Promise<EmailTemplate[]>;
|
|
40
|
+
/** Update a template */
|
|
41
|
+
update(name: string, data: Partial<EmailTemplate>): Promise<EmailTemplate | null>;
|
|
42
|
+
/** Delete a template */
|
|
43
|
+
delete(name: string): Promise<boolean>;
|
|
44
|
+
/** Register built-in default templates */
|
|
45
|
+
private registerDefaults;
|
|
46
|
+
/** Simple template engine — replaces {{var}}, {{#if}}, {{#each}} */
|
|
47
|
+
private interpolate;
|
|
48
|
+
private getNestedValue;
|
|
49
|
+
}
|
|
50
|
+
export declare const EmailTemplates: EmailTemplateManager;
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
var y=Object.defineProperty;var f=(p,e)=>()=>(p&&(e=p(p=0)),e);var b=(p,e)=>{for(var t in e)y(p,t,{get:e[t],enumerable:!0})};function m(p,e){let t=Symbol.for(p),n=globalThis;return n[t]||(n[t]=e()),n[t]}var d=f(()=>{"use strict"});var w={};b(w,{Connection:()=>C});var h,C,v=f(()=>{"use strict";d();h=class{connections=new Map;config=null;defaultName="default";configure(e){this.config=e,this.defaultName=e.default}async connection(e){let t=e??this.defaultName;if(this.connections.has(t))return this.connections.get(t).drizzle;if(!this.config)throw new Error("Database not configured. Call Connection.configure() first, or register DatabaseServiceProvider.");let n=this.config.connections[t];if(!n)throw new Error(`Database connection "${t}" is not defined in configuration.`);let r=await this.createConnection(n);return this.connections.set(t,r),r.drizzle}async rawClient(e){let t=e??this.defaultName;return await this.connection(t),this.connections.get(t).rawClient}async raw(e,t=[],n){let r=await this.connection(n),i=this.getConfig(n);switch(i.driver){case"sqlite":{let a=await this.rawClient(n),c=t.map(o=>typeof o=="boolean"?o?1:0:o instanceof Date?o.toISOString():o),s=a.prepare(e),l=e.trimStart().toUpperCase();return l.startsWith("SELECT")||l.startsWith("PRAGMA")||l.startsWith("WITH")?s.all(...c):s.run(...c)}case"postgres":return(await this.rawClient(n))(e,...t);case"mysql":{let a=await this.rawClient(n),[c]=await a.execute(e,t);return c}default:throw new Error(`Unsupported driver: ${i.driver}`)}}getDriver(e){return this.getConfig(e).driver}getConfig(e){let t=e??this.defaultName;if(!this.config)throw new Error("Database not configured.");let n=this.config.connections[t];if(!n)throw new Error(`Database connection "${t}" is not defined.`);return n}async disconnect(e){if(e){let t=this.connections.get(e);t&&(await this.closeConnection(t),this.connections.delete(e))}else{for(let[t,n]of this.connections)await this.closeConnection(n);this.connections.clear()}}isConnected(e){return this.connections.has(e??this.defaultName)}async transaction(e,t){let n=this.getConfig(t),r=await this.rawClient(t);switch(n.driver){case"sqlite":{r.exec("BEGIN");try{let i=await e();return r.exec("COMMIT"),i}catch(i){throw r.exec("ROLLBACK"),i}}case"postgres":{await r`BEGIN`;try{let i=await e();return await r`COMMIT`,i}catch(i){throw await r`ROLLBACK`,i}}case"mysql":{let i=await r.getConnection();await i.beginTransaction();try{let a=await e();return await i.commit(),i.release(),a}catch(a){throw await i.rollback(),i.release(),a}}default:throw new Error(`Unsupported driver: ${n.driver}`)}}async createConnection(e){switch(e.driver){case"sqlite":return this.createSQLiteConnection(e);case"postgres":return this.createPostgresConnection(e);case"mysql":return this.createMySQLConnection(e);default:throw new Error(`Unsupported database driver: ${e.driver}`)}}async createSQLiteConnection(e){let t=e.filename??e.database??":memory:";try{let n=(await import("better-sqlite3")).default,{drizzle:r}=await import("drizzle-orm/better-sqlite3"),i=new n(t);return i.pragma("journal_mode = WAL"),i.pragma("foreign_keys = ON"),{drizzle:r(i),config:e,rawClient:i}}catch(n){let r;try{r=(await new Function("mod","return import(mod)")("node:sqlite")).DatabaseSync}catch{throw new Error(`No SQLite driver available. Install better-sqlite3 (npm install better-sqlite3) or use Node.js v22+ which includes built-in SQLite support. Original error: ${n instanceof Error?n.message:String(n)}`)}let i=new r(t);i.exec("PRAGMA journal_mode = WAL"),i.exec("PRAGMA foreign_keys = ON");let a={prepare(s){let l=i.prepare(s);return{all(...o){return l.all(...o)},run(...o){return l.run(...o)},get(...o){return l.get(...o)}}},exec(s){i.exec(s)},pragma(s){return i.prepare(`PRAGMA ${s}`).all()},close(){i.close()}},c;try{let{drizzle:s}=await import("drizzle-orm/better-sqlite3");c=s(a)}catch{c=a}return{drizzle:c,config:e,rawClient:a}}}async createPostgresConnection(e){let t=(await import("postgres")).default,{drizzle:n}=await import("drizzle-orm/postgres-js"),r=e.url??`postgres://${e.user}:${e.password}@${e.host??"localhost"}:${e.port??5432}/${e.database}`,i=t(r);return{drizzle:n(i),config:e,rawClient:i}}async createMySQLConnection(e){let t=await import("mysql2/promise"),{drizzle:n}=await import("drizzle-orm/mysql2"),r=t.createPool({host:e.host??"localhost",port:e.port??3306,database:e.database,user:e.user,password:e.password,uri:e.url});return{drizzle:n(r),config:e,rawClient:r}}async closeConnection(e){try{switch(e.config.driver){case"sqlite":e.rawClient.close();break;case"postgres":await e.rawClient.end();break;case"mysql":await e.rawClient.end();break}}catch{}}},C=m("svelar.connection",()=>new h)});d();import{randomUUID as u}from"crypto";var g=class{config={driver:"memory"};templates=new Map;constructor(){this.registerDefaults()}configure(e){this.config=e}async register(e){let t={...e,id:u(),createdAt:Date.now(),updatedAt:Date.now()};if(this.config.driver==="memory")this.templates.set(e.name,t);else if(this.config.driver==="database")try{let{Connection:n}=await Promise.resolve().then(()=>(v(),w));await n.connection()}catch{this.templates.set(e.name,t)}return t}async render(e,t){let n=await this.get(e);if(!n)throw new Error(`Template "${e}" not found`);let r=this.interpolate(n.subject,t),i=this.interpolate(n.html,t),a=n.text?this.interpolate(n.text,t):void 0;return{subject:r,html:i,text:a}}async get(e){return this.templates.get(e)||null}async list(e){let t=Array.from(this.templates.values());return e&&(t=t.filter(n=>n.category===e)),t}async update(e,t){let n=this.templates.get(e);return n?(Object.assign(n,t,{updatedAt:Date.now()}),n):null}async delete(e){return this.templates.delete(e)}registerDefaults(){this.templates.set("welcome",{id:u(),name:"welcome",subject:"Welcome to {{appName}}, {{user.name}}!",html:`
|
|
2
|
+
<h1>Welcome, {{user.name}}!</h1>
|
|
3
|
+
<p>Thank you for joining {{appName}}.</p>
|
|
4
|
+
<p>Your account has been created with the email: <strong>{{user.email}}</strong></p>
|
|
5
|
+
<p><a href="{{confirmUrl}}">Confirm your email address</a></p>
|
|
6
|
+
`,text:`Welcome, {{user.name}}!
|
|
7
|
+
|
|
8
|
+
Confirm your email: {{confirmUrl}}`,variables:["appName","user.name","user.email","confirmUrl"],category:"auth",active:!0,createdAt:Date.now(),updatedAt:Date.now()}),this.templates.set("password-reset",{id:u(),name:"password-reset",subject:"Reset your {{appName}} password",html:`
|
|
9
|
+
<h1>Password Reset</h1>
|
|
10
|
+
<p>Hi {{user.name}},</p>
|
|
11
|
+
<p>Click the link below to reset your password. This link expires in 1 hour.</p>
|
|
12
|
+
<p><a href="{{resetUrl}}">Reset Password</a></p>
|
|
13
|
+
<p>If you didn't request this, you can ignore this email.</p>
|
|
14
|
+
`,text:`Reset your password: {{resetUrl}}
|
|
15
|
+
|
|
16
|
+
This link expires in 1 hour.`,variables:["appName","user.name","resetUrl"],category:"auth",active:!0,createdAt:Date.now(),updatedAt:Date.now()}),this.templates.set("email-verification",{id:u(),name:"email-verification",subject:"Verify your email address",html:`
|
|
17
|
+
<h1>Verify Your Email</h1>
|
|
18
|
+
<p>Hi {{user.name}},</p>
|
|
19
|
+
<p><a href="{{verifyUrl}}">Click here to verify your email address</a></p>
|
|
20
|
+
<p>This link expires in 24 hours.</p>
|
|
21
|
+
`,text:"Verify your email: {{verifyUrl}}",variables:["user.name","verifyUrl"],category:"auth",active:!0,createdAt:Date.now(),updatedAt:Date.now()}),this.templates.set("team-invitation",{id:u(),name:"team-invitation",subject:"{{inviter.name}} invited you to join {{team.name}}",html:`
|
|
22
|
+
<h1>Team Invitation</h1>
|
|
23
|
+
<p>Hi {{user.name}},</p>
|
|
24
|
+
<p><strong>{{inviter.name}}</strong> has invited you to join the team <strong>{{team.name}}</strong>.</p>
|
|
25
|
+
<p><a href="{{acceptUrl}}">Accept Invitation</a></p>
|
|
26
|
+
<p>This invitation expires in 3 days.</p>
|
|
27
|
+
`,text:"Accept: {{acceptUrl}}",variables:["user.name","inviter.name","team.name","acceptUrl"],category:"notification",active:!0,createdAt:Date.now(),updatedAt:Date.now()}),this.templates.set("invoice",{id:u(),name:"invoice",subject:"Invoice #{{invoice.number}} from {{appName}}",html:`
|
|
28
|
+
<h1>Invoice #{{invoice.number}}</h1>
|
|
29
|
+
<p>Hi {{customer.name}},</p>
|
|
30
|
+
<p>Thank you for your purchase!</p>
|
|
31
|
+
<p><strong>Amount:</strong> {{invoice.amount}}</p>
|
|
32
|
+
<p><strong>Date:</strong> {{invoice.date}}</p>
|
|
33
|
+
<p><a href="{{invoiceUrl}}">View Invoice</a></p>
|
|
34
|
+
`,text:`Invoice #{{invoice.number}}
|
|
35
|
+
Amount: {{invoice.amount}}`,variables:["appName","customer.name","invoice.number","invoice.amount","invoice.date","invoiceUrl"],category:"billing",active:!0,createdAt:Date.now(),updatedAt:Date.now()}),this.templates.set("subscription-confirmation",{id:u(),name:"subscription-confirmation",subject:"Subscription Confirmation",html:`
|
|
36
|
+
<h1>Subscription Confirmed</h1>
|
|
37
|
+
<p>Hi {{user.name}},</p>
|
|
38
|
+
<p>Your {{plan.name}} plan is now active.</p>
|
|
39
|
+
<p><strong>Price:</strong> {{plan.price}} / {{plan.interval}}</p>
|
|
40
|
+
<p>Your next billing date is {{nextBillingDate}}.</p>
|
|
41
|
+
`,text:`Your {{plan.name}} plan is active.
|
|
42
|
+
Next billing: {{nextBillingDate}}`,variables:["user.name","plan.name","plan.price","plan.interval","nextBillingDate"],category:"billing",active:!0,createdAt:Date.now(),updatedAt:Date.now()}),this.templates.set("otp-code",{id:u(),name:"otp-code",subject:"Your {{appName}} verification code: {{code}}",html:`
|
|
43
|
+
<h1>Your Verification Code</h1>
|
|
44
|
+
<p>Hi {{user.name}},</p>
|
|
45
|
+
<p>Your one-time verification code is:</p>
|
|
46
|
+
<p style="font-size: 32px; font-weight: bold; letter-spacing: 8px; text-align: center; padding: 16px; background: #f3f4f6; border-radius: 8px; font-family: monospace;">{{code}}</p>
|
|
47
|
+
<p>This code expires in {{expiresMinutes}} minutes.</p>
|
|
48
|
+
<p>If you didn't request this code, you can safely ignore this email.</p>
|
|
49
|
+
`,text:`Your verification code: {{code}}
|
|
50
|
+
|
|
51
|
+
This code expires in {{expiresMinutes}} minutes.`,variables:["appName","user.name","code","expiresMinutes","purpose"],category:"auth",active:!0,createdAt:Date.now(),updatedAt:Date.now()}),this.templates.set("subscription-canceled",{id:u(),name:"subscription-canceled",subject:"Your subscription has been canceled",html:`
|
|
52
|
+
<h1>Subscription Canceled</h1>
|
|
53
|
+
<p>Hi {{user.name}},</p>
|
|
54
|
+
<p>Your {{plan.name}} subscription has been canceled.</p>
|
|
55
|
+
<p>You have access until {{accessUntilDate}}.</p>
|
|
56
|
+
`,text:`Your {{plan.name}} subscription is canceled.
|
|
57
|
+
Access until: {{accessUntilDate}}`,variables:["user.name","plan.name","accessUntilDate"],category:"billing",active:!0,createdAt:Date.now(),updatedAt:Date.now()})}interpolate(e,t){let n=e;return n=n.replace(/\{\{#if\s+(\w+(?:\.\w+)*)\}\}([\s\S]*?)\{\{\/if\}\}/g,(r,i,a)=>this.getNestedValue(t,i)?a:""),n=n.replace(/\{\{#each\s+(\w+(?:\.\w+)*)\}\}([\s\S]*?)\{\{\/each\}\}/g,(r,i,a)=>{let c=this.getNestedValue(t,i);return Array.isArray(c)?c.map((s,l)=>{let o={...t,this:s,$index:l};return this.interpolate(a,o)}).join(""):""}),n=n.replace(/\{\{([\w.$]+)\}\}/g,(r,i)=>{let a=this.getNestedValue(t,i);return a!=null?String(a):""}),n}getNestedValue(e,t){return t.split(".").reduce((n,r)=>n?.[r],e)}},P=m("svelar.emailTemplates",()=>new g);export{P as EmailTemplates};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelar Error Handler
|
|
3
|
+
*
|
|
4
|
+
* Centralized error handling with structured responses,
|
|
5
|
+
* error reporting, and SvelteKit integration.
|
|
6
|
+
*
|
|
7
|
+
* Errors are automatically logged via the Svelar Log system
|
|
8
|
+
* (console, file, stack channels) instead of leaking to the UI.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* // hooks.server.ts
|
|
13
|
+
* import { ErrorHandler } from 'svelar/errors';
|
|
14
|
+
*
|
|
15
|
+
* const handler = new ErrorHandler({
|
|
16
|
+
* debug: process.env.NODE_ENV !== 'production',
|
|
17
|
+
* report: async (error) => {
|
|
18
|
+
* // Send to Sentry, Datadog, etc.
|
|
19
|
+
* },
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* export const handleError = handler.handleSvelteKitError();
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare class HttpError extends Error {
|
|
26
|
+
readonly statusCode: number;
|
|
27
|
+
readonly details?: Record<string, any> | undefined;
|
|
28
|
+
constructor(statusCode: number, message: string, details?: Record<string, any> | undefined);
|
|
29
|
+
}
|
|
30
|
+
export declare class NotFoundError extends HttpError {
|
|
31
|
+
constructor(message?: string);
|
|
32
|
+
}
|
|
33
|
+
export declare class UnauthorizedError extends HttpError {
|
|
34
|
+
constructor(message?: string);
|
|
35
|
+
}
|
|
36
|
+
export declare class ForbiddenError extends HttpError {
|
|
37
|
+
constructor(message?: string);
|
|
38
|
+
}
|
|
39
|
+
export declare class ValidationError extends HttpError {
|
|
40
|
+
readonly errors: Record<string, string[]>;
|
|
41
|
+
constructor(errors: Record<string, string[]>, message?: string);
|
|
42
|
+
}
|
|
43
|
+
export declare class ConflictError extends HttpError {
|
|
44
|
+
constructor(message?: string);
|
|
45
|
+
}
|
|
46
|
+
export declare class TooManyRequestsError extends HttpError {
|
|
47
|
+
readonly retryAfter?: number | undefined;
|
|
48
|
+
constructor(message?: string, retryAfter?: number | undefined);
|
|
49
|
+
}
|
|
50
|
+
export declare class ServiceUnavailableError extends HttpError {
|
|
51
|
+
constructor(message?: string);
|
|
52
|
+
}
|
|
53
|
+
export declare class ModelNotFoundError extends NotFoundError {
|
|
54
|
+
constructor(model: string, id?: any);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Throw an HTTP error (like Laravel's abort())
|
|
58
|
+
*/
|
|
59
|
+
export declare function abort(statusCode: number, message?: string): never;
|
|
60
|
+
/**
|
|
61
|
+
* Abort if a condition is true
|
|
62
|
+
*/
|
|
63
|
+
export declare function abortIf(condition: boolean, statusCode: number, message?: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* Abort unless a condition is true
|
|
66
|
+
*/
|
|
67
|
+
export declare function abortUnless(condition: boolean, statusCode: number, message?: string): void;
|
|
68
|
+
export interface ErrorHandlerConfig {
|
|
69
|
+
/** Show detailed errors (stack traces, etc.) */
|
|
70
|
+
debug?: boolean;
|
|
71
|
+
/** Custom error reporter (e.g. Sentry) */
|
|
72
|
+
report?: (error: Error, context?: Record<string, any>) => void | Promise<void>;
|
|
73
|
+
/** Errors that should not be reported */
|
|
74
|
+
dontReport?: Array<new (...args: any[]) => Error>;
|
|
75
|
+
/** Custom render function */
|
|
76
|
+
render?: (error: Error, event?: any) => Response | Promise<Response>;
|
|
77
|
+
}
|
|
78
|
+
export declare class ErrorHandler {
|
|
79
|
+
private config;
|
|
80
|
+
constructor(config?: ErrorHandlerConfig);
|
|
81
|
+
/**
|
|
82
|
+
* Handle an error and return a Response
|
|
83
|
+
*/
|
|
84
|
+
handle(error: Error | unknown, event?: any): Promise<Response>;
|
|
85
|
+
/**
|
|
86
|
+
* Create a SvelteKit-compatible handleError hook
|
|
87
|
+
*/
|
|
88
|
+
handleSvelteKitError(): (input: {
|
|
89
|
+
error: unknown;
|
|
90
|
+
event: any;
|
|
91
|
+
status: number;
|
|
92
|
+
message: string;
|
|
93
|
+
}) => any;
|
|
94
|
+
/**
|
|
95
|
+
* Create an error-handling middleware
|
|
96
|
+
*/
|
|
97
|
+
middleware(): (ctx: any, next: () => Promise<Response | void>) => Promise<Response | void>;
|
|
98
|
+
private reportError;
|
|
99
|
+
private renderError;
|
|
100
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ErrorHandler, HttpError, NotFoundError, UnauthorizedError, ForbiddenError, ValidationError, ConflictError, TooManyRequestsError, ServiceUnavailableError, ModelNotFoundError, abort, abortIf, abortUnless, type ErrorHandlerConfig, } from './Handler.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{appendFile as $,mkdir as N}from"fs/promises";import{dirname as D}from"path";function R(r,e){let t=Symbol.for(r),n=globalThis;return n[t]||(n[t]=e()),n[t]}var d={debug:0,info:1,warn:2,error:3,fatal:4},l=class{minLevel;format;constructor(e){this.minLevel=e.level??"debug",this.format=e.format??"text"}write(e){if(d[e.level]<d[this.minLevel])return;if(this.format==="json"){console.log(JSON.stringify(e));return}let t={debug:"\x1B[90m",info:"\x1B[34m",warn:"\x1B[33m",error:"\x1B[31m",fatal:"\x1B[35m"},n="\x1B[0m",s=t[e.level]??"",i=e.level.toUpperCase().padEnd(5),k=Object.keys(e.context).length>0?` ${JSON.stringify(e.context)}`:"",T=e.level==="error"||e.level==="fatal"?"error":"log";console[T](`${s}[${e.timestamp}] ${i}${n} ${e.message}${k}`)}},f=class{minLevel;path;format;initialized=!1;constructor(e){this.minLevel=e.level??"info",this.path=e.path??"storage/logs/app.log",this.format=e.format??"text"}async write(e){if(d[e.level]<d[this.minLevel])return;this.initialized||(await N(D(this.path),{recursive:!0}),this.initialized=!0);let t;if(this.format==="json")t=JSON.stringify(e)+`
|
|
2
|
+
`;else{let n=e.level.toUpperCase().padEnd(5),s=Object.keys(e.context).length>0?` ${JSON.stringify(e.context)}`:"";t=`[${e.timestamp}] ${n} ${e.message}${s}
|
|
3
|
+
`}await $(this.path,t)}},p=class{minLevel="debug";channelNames;resolver;constructor(e,t){this.channelNames=e.channels??[],this.resolver=t,this.minLevel=e.level??"debug"}async write(e){for(let t of this.channelNames){let n=this.resolver(t);n&&await n.write(e)}}},m=class{minLevel="debug";write(){}},v=class{config={default:"console",channels:{console:{driver:"console",level:"debug"}}};channels=new Map;configure(e){this.config=e,this.channels.clear()}channel(e){return new b(this.resolveChannel(e))}debug(e,t={}){this.writeToDefault({level:"debug",message:e,context:t,timestamp:a()})}info(e,t={}){this.writeToDefault({level:"info",message:e,context:t,timestamp:a()})}warn(e,t={}){this.writeToDefault({level:"warn",message:e,context:t,timestamp:a()})}error(e,t={}){this.writeToDefault({level:"error",message:e,context:t,timestamp:a()})}fatal(e,t={}){this.writeToDefault({level:"fatal",message:e,context:t,timestamp:a()})}writeToDefault(e){this.resolveChannel(this.config.default).write(e)}resolveChannel(e){if(this.channels.has(e))return this.channels.get(e);let t=this.config.channels[e];if(!t){let s=new l({driver:"console"});return this.channels.set(e,s),s}let n=this.createChannel(t);return this.channels.set(e,n),n}createChannel(e){switch(e.driver){case"console":return new l(e);case"file":return new f(e);case"stack":return new p(e,t=>this.resolveChannel(t));case"null":return new m;default:return new l(e)}}},b=class{constructor(e){this.channel=e}debug(e,t={}){this.channel.write({level:"debug",message:e,context:t,timestamp:a()})}info(e,t={}){this.channel.write({level:"info",message:e,context:t,timestamp:a()})}warn(e,t={}){this.channel.write({level:"warn",message:e,context:t,timestamp:a()})}error(e,t={}){this.channel.write({level:"error",message:e,context:t,timestamp:a()})}fatal(e,t={}){this.channel.write({level:"fatal",message:e,context:t,timestamp:a()})}};function a(){return new Date().toISOString()}var S=R("svelar.log",()=>new v);var o=class extends Error{constructor(t,n,s){super(n);this.statusCode=t;this.details=s;this.name="HttpError"}},c=class extends o{constructor(e="The requested resource was not found"){super(404,e),this.name="NotFoundError"}},u=class extends o{constructor(e="Unauthenticated"){super(401,e),this.name="UnauthorizedError"}},h=class extends o{constructor(e="You do not have permission to perform this action"){super(403,e),this.name="ForbiddenError"}},g=class extends o{constructor(t,n="The given data was invalid"){super(422,n,{errors:t});this.errors=t;this.name="ValidationError"}},w=class extends o{constructor(e="Resource conflict"){super(409,e),this.name="ConflictError"}},x=class extends o{constructor(t="Too many requests",n){super(429,t,n?{retryAfter:n}:void 0);this.retryAfter=n;this.name="TooManyRequestsError"}},y=class extends o{constructor(e="Service temporarily unavailable"){super(503,e),this.name="ServiceUnavailableError"}},L=class extends c{constructor(e,t){super(t?`${e} with ID ${t} not found`:`${e} not found`),this.name="ModelNotFoundError"}};function C(r,e){throw new o(r,e??P(r))}function O(r,e,t){r&&C(e,t)}function j(r,e,t){r||C(e,t)}var E=class{config;constructor(e={}){this.config={debug:process.env.NODE_ENV!=="production",dontReport:[g,c,u,h],...e}}async handle(e,t){let n=e instanceof Error?e:new Error(String(e));return await this.reportError(n,t),this.config.render?this.config.render(n,t):this.renderError(n)}handleSvelteKitError(){return({error:e,event:t,status:n,message:s})=>{let i=e instanceof Error?e:new Error(String(e));return this.reportError(i,t),i instanceof o?{message:i.message,status:i.statusCode,...i.details??{},...this.config.debug?{stack:i.stack}:{}}:{message:this.config.debug?i.message:"An unexpected error occurred",status:n,...this.config.debug?{stack:i.stack}:{}}}}middleware(){let e=this;return async(t,n)=>{try{return await n()}catch(s){return e.handle(s,t.event)}}}async reportError(e,t){if(this.config.dontReport){for(let s of this.config.dontReport)if(e instanceof s)return}let n={error:e.name,...t?.url?{url:t.url.toString()}:{},...e.stack?{stack:e.stack}:{}};if(S.error(e.message,n),this.config.report)try{await this.config.report(e,t?{url:t.url?.toString()}:void 0)}catch{}}renderError(e){if(e instanceof o){let n={message:e.message};return e instanceof g&&(n.errors=e.errors),e.details&&Object.assign(n,e.details),this.config.debug&&(n.exception=e.name,n.stack=e.stack?.split(`
|
|
4
|
+
`).map(s=>s.trim())),new Response(JSON.stringify(n),{status:e.statusCode,headers:{"Content-Type":"application/json"}})}let t={message:this.config.debug?e.message:"Internal server error"};return this.config.debug&&(t.exception=e.name,t.stack=e.stack?.split(`
|
|
5
|
+
`).map(n=>n.trim())),new Response(JSON.stringify(t),{status:500,headers:{"Content-Type":"application/json"}})}};function P(r){return{400:"Bad request",401:"Unauthenticated",403:"Forbidden",404:"Not found",405:"Method not allowed",409:"Conflict",419:"Page expired",422:"Unprocessable entity",429:"Too many requests",500:"Internal server error",502:"Bad gateway",503:"Service unavailable",504:"Gateway timeout"}[r]??"An error occurred"}export{w as ConflictError,E as ErrorHandler,h as ForbiddenError,o as HttpError,L as ModelNotFoundError,c as NotFoundError,y as ServiceUnavailableError,x as TooManyRequestsError,u as UnauthorizedError,g as ValidationError,C as abort,O as abortIf,j as abortUnless};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelar EventServiceProvider
|
|
3
|
+
*
|
|
4
|
+
* Base class for registering event-to-listener mappings and model observers
|
|
5
|
+
* in a declarative way. Extend this in your app to wire up all event handling.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { EventServiceProvider } from '@beeblock/svelar/events';
|
|
10
|
+
* import { UserRegistered } from '../events/UserRegistered.js';
|
|
11
|
+
* import { SendWelcomeEmail } from '../listeners/SendWelcomeEmail.js';
|
|
12
|
+
* import { User } from '../modules/users/User.js';
|
|
13
|
+
* import { UserObserver } from '../modules/users/UserObserver.js';
|
|
14
|
+
*
|
|
15
|
+
* export class AppEventServiceProvider extends EventServiceProvider {
|
|
16
|
+
* protected listen = {
|
|
17
|
+
* [UserRegistered.name]: [SendWelcomeEmail],
|
|
18
|
+
* 'order.created': [NotifyWarehouse, SendOrderConfirmation],
|
|
19
|
+
* };
|
|
20
|
+
*
|
|
21
|
+
* protected observers = {
|
|
22
|
+
* [User.name]: [UserObserver],
|
|
23
|
+
* };
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
import { ServiceProvider } from '../container/ServiceProvider.js';
|
|
28
|
+
import { Event, type EventListener } from './index.js';
|
|
29
|
+
import type { ModelObserver } from '../orm/Observer.js';
|
|
30
|
+
export type ListenerClass = new () => {
|
|
31
|
+
handle(event: any): void | Promise<void>;
|
|
32
|
+
};
|
|
33
|
+
export type ListenMap = Record<string, (ListenerClass | EventListener)[]>;
|
|
34
|
+
export type ObserverMap = Record<string, (new () => ModelObserver)[]>;
|
|
35
|
+
export declare abstract class EventServiceProvider extends ServiceProvider {
|
|
36
|
+
/**
|
|
37
|
+
* Map of event names/classes to their listeners.
|
|
38
|
+
*
|
|
39
|
+
* Keys can be class names (for class-based events) or string event names.
|
|
40
|
+
* Values are arrays of Listener classes or inline functions.
|
|
41
|
+
*/
|
|
42
|
+
protected listen: ListenMap;
|
|
43
|
+
/**
|
|
44
|
+
* Map of model class names to their observer classes.
|
|
45
|
+
*
|
|
46
|
+
* Keys are model class names (e.g. 'User').
|
|
47
|
+
* Values are arrays of observer class constructors.
|
|
48
|
+
*/
|
|
49
|
+
protected observers: ObserverMap;
|
|
50
|
+
/**
|
|
51
|
+
* The subscriber classes to register.
|
|
52
|
+
* Each subscriber's subscribe() method receives the EventDispatcher.
|
|
53
|
+
*/
|
|
54
|
+
protected subscribe: (new () => {
|
|
55
|
+
subscribe(events: typeof Event): void;
|
|
56
|
+
})[];
|
|
57
|
+
register(): void;
|
|
58
|
+
boot(): Promise<void>;
|
|
59
|
+
private registerListeners;
|
|
60
|
+
private registerSubscribers;
|
|
61
|
+
private registerObservers;
|
|
62
|
+
/**
|
|
63
|
+
* Check if a listener entry is a class (has a handle method) vs an inline function
|
|
64
|
+
*/
|
|
65
|
+
private isListenerClass;
|
|
66
|
+
private static modelRegistry;
|
|
67
|
+
/**
|
|
68
|
+
* Register a model class so observers can be attached by name.
|
|
69
|
+
* Call this in your app setup or in a service provider's register().
|
|
70
|
+
*/
|
|
71
|
+
static registerModel(ModelClass: {
|
|
72
|
+
name: string;
|
|
73
|
+
observe(observer: ModelObserver): void;
|
|
74
|
+
}): void;
|
|
75
|
+
/**
|
|
76
|
+
* Register multiple model classes at once.
|
|
77
|
+
*/
|
|
78
|
+
static registerModels(...models: {
|
|
79
|
+
name: string;
|
|
80
|
+
observe(observer: ModelObserver): void;
|
|
81
|
+
}[]): void;
|
|
82
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelar Listener
|
|
3
|
+
*
|
|
4
|
+
* Base class for event listeners. Listeners encapsulate the logic
|
|
5
|
+
* that runs in response to a dispatched event.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { Listener } from '@beeblock/svelar/events';
|
|
10
|
+
*
|
|
11
|
+
* export class SendWelcomeEmail extends Listener {
|
|
12
|
+
* async handle(event: UserRegistered) {
|
|
13
|
+
* await Mail.to(event.user.email).send(new WelcomeEmail(event.user));
|
|
14
|
+
* }
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare abstract class Listener<T = any> {
|
|
19
|
+
/**
|
|
20
|
+
* Handle the event.
|
|
21
|
+
*/
|
|
22
|
+
abstract handle(event: T): void | Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Determine whether the listener should handle the event.
|
|
25
|
+
* Override to add conditional logic.
|
|
26
|
+
*/
|
|
27
|
+
shouldHandle(_event: T): boolean;
|
|
28
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelar Events
|
|
3
|
+
*
|
|
4
|
+
* Laravel-inspired event dispatcher with typed events, listeners, and subscribers.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { Event } from 'svelar/events';
|
|
9
|
+
*
|
|
10
|
+
* // Define an event
|
|
11
|
+
* class UserRegistered {
|
|
12
|
+
* constructor(public readonly user: User) {}
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* // Register a listener
|
|
16
|
+
* Event.listen(UserRegistered, async (event) => {
|
|
17
|
+
* await sendWelcomeEmail(event.user);
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* // Dispatch
|
|
21
|
+
* await Event.dispatch(new UserRegistered(user));
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export type EventClass<T = any> = new (...args: any[]) => T;
|
|
25
|
+
export type EventListener<T = any> = (event: T) => void | Promise<void>;
|
|
26
|
+
export type WildcardListener = (eventName: string, event: any) => void | Promise<void>;
|
|
27
|
+
export interface Subscriber {
|
|
28
|
+
subscribe(events: EventDispatcher): void;
|
|
29
|
+
}
|
|
30
|
+
export declare class EventDispatcher {
|
|
31
|
+
private listeners;
|
|
32
|
+
private wildcardListeners;
|
|
33
|
+
private onceListeners;
|
|
34
|
+
/**
|
|
35
|
+
* Register an event listener
|
|
36
|
+
*/
|
|
37
|
+
listen<T>(event: EventClass<T> | string, listener: EventListener<T>): () => void;
|
|
38
|
+
/**
|
|
39
|
+
* Register a one-time listener
|
|
40
|
+
*/
|
|
41
|
+
once<T>(event: EventClass<T> | string, listener: EventListener<T>): () => void;
|
|
42
|
+
/**
|
|
43
|
+
* Register a wildcard listener (called for every event)
|
|
44
|
+
*/
|
|
45
|
+
onAny(listener: WildcardListener): () => void;
|
|
46
|
+
/**
|
|
47
|
+
* Dispatch an event
|
|
48
|
+
*/
|
|
49
|
+
dispatch<T extends object>(event: T): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Dispatch an event by string name with payload
|
|
52
|
+
*/
|
|
53
|
+
emit(name: string, payload?: any): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Register a subscriber (an object that subscribes to multiple events)
|
|
56
|
+
*/
|
|
57
|
+
subscribe(subscriber: Subscriber): void;
|
|
58
|
+
/**
|
|
59
|
+
* Remove all listeners for an event
|
|
60
|
+
*/
|
|
61
|
+
forget(event: EventClass | string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Remove all listeners
|
|
64
|
+
*/
|
|
65
|
+
flush(): void;
|
|
66
|
+
/**
|
|
67
|
+
* Check if an event has listeners
|
|
68
|
+
*/
|
|
69
|
+
hasListeners(event: EventClass | string): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Get the count of listeners for an event
|
|
72
|
+
*/
|
|
73
|
+
listenerCount(event: EventClass | string): number;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Global event dispatcher singleton
|
|
77
|
+
*/
|
|
78
|
+
export declare const Event: EventDispatcher;
|
|
79
|
+
export { Listener } from './Listener.js';
|
|
80
|
+
export { EventServiceProvider, type ListenMap, type ObserverMap, type ListenerClass } from './EventServiceProvider.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function v(n,e){let s=Symbol.for(n),t=globalThis;return t[s]||(t[s]=e()),t[s]}var c=class{shouldHandle(e){return!0}};var o=class{app;constructor(e){this.app=e}boot(){}};var l=class n extends o{listen={};observers={};subscribe=[];register(){}async boot(){this.registerListeners(),this.registerSubscribers(),await this.registerObservers()}registerListeners(){for(let[e,s]of Object.entries(this.listen))for(let t of s)if(this.isListenerClass(t)){let i=new t;a.listen(e,async r=>{"shouldHandle"in i&&typeof i.shouldHandle=="function"&&!i.shouldHandle(r)||await i.handle(r)})}else a.listen(e,t)}registerSubscribers(){for(let e of this.subscribe){let s=new e;a.subscribe(s)}}async registerObservers(){for(let[e,s]of Object.entries(this.observers)){let t=n.modelRegistry.get(e);if(!t){console.warn(`[EventServiceProvider] Model "${e}" not found in registry. Register it with EventServiceProvider.registerModel(${e}).`);continue}for(let i of s)t.observe(new i)}}isListenerClass(e){return typeof e=="function"&&e.prototype&&typeof e.prototype.handle=="function"}static modelRegistry=new Map;static registerModel(e){this.modelRegistry.set(e.name,e)}static registerModels(...e){for(let s of e)this.registerModel(s)}};var d=class{listeners=new Map;wildcardListeners=[];onceListeners=new Map;listen(e,s){let t=typeof e=="string"?e:e.name;return this.listeners.has(t)||this.listeners.set(t,[]),this.listeners.get(t).push(s),()=>{let i=this.listeners.get(t);if(i){let r=i.indexOf(s);r>=0&&i.splice(r,1)}}}once(e,s){let t=typeof e=="string"?e:e.name;return this.onceListeners.has(t)||this.onceListeners.set(t,[]),this.onceListeners.get(t).push(s),()=>{let i=this.onceListeners.get(t);if(i){let r=i.indexOf(s);r>=0&&i.splice(r,1)}}}onAny(e){return this.wildcardListeners.push(e),()=>{let s=this.wildcardListeners.indexOf(e);s>=0&&this.wildcardListeners.splice(s,1)}}async dispatch(e){let s=e.constructor.name,t=this.listeners.get(s)??[];for(let r of t)await r(e);let i=this.onceListeners.get(s)??[];for(let r of i)await r(e);this.onceListeners.delete(s);for(let r of this.wildcardListeners)await r(s,e)}async emit(e,s){let t=this.listeners.get(e)??[];for(let r of t)await r(s);let i=this.onceListeners.get(e)??[];for(let r of i)await r(s);this.onceListeners.delete(e);for(let r of this.wildcardListeners)await r(e,s)}subscribe(e){e.subscribe(this)}forget(e){let s=typeof e=="string"?e:e.name;this.listeners.delete(s),this.onceListeners.delete(s)}flush(){this.listeners.clear(),this.onceListeners.clear(),this.wildcardListeners=[]}hasListeners(e){let s=typeof e=="string"?e:e.name;return(this.listeners.get(s)?.length??0)>0||(this.onceListeners.get(s)?.length??0)>0||this.wildcardListeners.length>0}listenerCount(e){let s=typeof e=="string"?e:e.name;return(this.listeners.get(s)?.length??0)+(this.onceListeners.get(s)?.length??0)}},a=v("svelar.event",()=>new d);export{a as Event,d as EventDispatcher,l as EventServiceProvider,c as Listener};
|