@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.
Files changed (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -0
  3. package/dist/actions/index.d.ts +101 -0
  4. package/dist/actions/index.js +1 -0
  5. package/dist/api-keys/index.d.ts +58 -0
  6. package/dist/api-keys/index.js +1 -0
  7. package/dist/audit/index.d.ts +52 -0
  8. package/dist/audit/index.js +1 -0
  9. package/dist/auth/Auth.d.ts +283 -0
  10. package/dist/auth/Gate.d.ts +166 -0
  11. package/dist/auth/index.d.ts +2 -0
  12. package/dist/auth/index.js +80 -0
  13. package/dist/broadcasting/client.d.ts +195 -0
  14. package/dist/broadcasting/client.js +1 -0
  15. package/dist/broadcasting/index.d.ts +318 -0
  16. package/dist/broadcasting/index.js +20 -0
  17. package/dist/cache/index.d.ts +77 -0
  18. package/dist/cache/index.js +1 -0
  19. package/dist/cli/Cli.d.ts +23 -0
  20. package/dist/cli/Command.d.ts +36 -0
  21. package/dist/cli/bin.d.ts +8 -0
  22. package/dist/cli/bin.js +5856 -0
  23. package/dist/cli/commands/KeyGenerateCommand.d.ts +16 -0
  24. package/dist/cli/commands/MakeActionCommand.d.ts +15 -0
  25. package/dist/cli/commands/MakeBroadcastingCommand.d.ts +29 -0
  26. package/dist/cli/commands/MakeChannelCommand.d.ts +18 -0
  27. package/dist/cli/commands/MakeCommandCommand.d.ts +16 -0
  28. package/dist/cli/commands/MakeConfigCommand.d.ts +13 -0
  29. package/dist/cli/commands/MakeControllerCommand.d.ts +28 -0
  30. package/dist/cli/commands/MakeDashboardCommand.d.ts +34 -0
  31. package/dist/cli/commands/MakeDockerCommand.d.ts +32 -0
  32. package/dist/cli/commands/MakeEventCommand.d.ts +11 -0
  33. package/dist/cli/commands/MakeJobCommand.d.ts +11 -0
  34. package/dist/cli/commands/MakeListenerCommand.d.ts +16 -0
  35. package/dist/cli/commands/MakeMiddlewareCommand.d.ts +11 -0
  36. package/dist/cli/commands/MakeMigrationCommand.d.ts +17 -0
  37. package/dist/cli/commands/MakeModelCommand.d.ts +25 -0
  38. package/dist/cli/commands/MakeObserverCommand.d.ts +23 -0
  39. package/dist/cli/commands/MakePluginCommand.d.ts +11 -0
  40. package/dist/cli/commands/MakeProviderCommand.d.ts +11 -0
  41. package/dist/cli/commands/MakeRepositoryCommand.d.ts +22 -0
  42. package/dist/cli/commands/MakeRequestCommand.d.ts +15 -0
  43. package/dist/cli/commands/MakeResourceCommand.d.ts +30 -0
  44. package/dist/cli/commands/MakeRouteCommand.d.ts +42 -0
  45. package/dist/cli/commands/MakeSchemaCommand.d.ts +20 -0
  46. package/dist/cli/commands/MakeSeederCommand.d.ts +11 -0
  47. package/dist/cli/commands/MakeServiceCommand.d.ts +28 -0
  48. package/dist/cli/commands/MakeTaskCommand.d.ts +12 -0
  49. package/dist/cli/commands/MigrateCommand.d.ts +26 -0
  50. package/dist/cli/commands/NewCommand.d.ts +21 -0
  51. package/dist/cli/commands/NewCommandTemplates.d.ts +123 -0
  52. package/dist/cli/commands/PluginInstallCommand.d.ts +16 -0
  53. package/dist/cli/commands/PluginListCommand.d.ts +11 -0
  54. package/dist/cli/commands/PluginPublishCommand.d.ts +22 -0
  55. package/dist/cli/commands/QueueFailedCommand.d.ts +9 -0
  56. package/dist/cli/commands/QueueFlushCommand.d.ts +9 -0
  57. package/dist/cli/commands/QueueRetryCommand.d.ts +16 -0
  58. package/dist/cli/commands/QueueWorkCommand.d.ts +25 -0
  59. package/dist/cli/commands/RoutesListCommand.d.ts +30 -0
  60. package/dist/cli/commands/ScheduleRunCommand.d.ts +15 -0
  61. package/dist/cli/commands/SeedCommand.d.ts +14 -0
  62. package/dist/cli/commands/TinkerCommand.d.ts +10 -0
  63. package/dist/cli/index.d.ts +36 -0
  64. package/dist/cli/index.js +1973 -0
  65. package/dist/cli/ts-resolve-hook.mjs +74 -0
  66. package/dist/cli/ts-resolver.mjs +8 -0
  67. package/dist/config/Config.d.ts +65 -0
  68. package/dist/config/index.d.ts +1 -0
  69. package/dist/config/index.js +1 -0
  70. package/dist/container/Application.d.ts +33 -0
  71. package/dist/container/Container.d.ts +70 -0
  72. package/dist/container/ServiceProvider.d.ts +21 -0
  73. package/dist/container/index.d.ts +3 -0
  74. package/dist/container/index.js +1 -0
  75. package/dist/dashboard/index.d.ts +123 -0
  76. package/dist/dashboard/index.js +5 -0
  77. package/dist/database/Connection.d.ts +80 -0
  78. package/dist/database/Migration.d.ts +76 -0
  79. package/dist/database/SchemaBuilder.d.ts +91 -0
  80. package/dist/database/Seeder.d.ts +9 -0
  81. package/dist/database/index.d.ts +4 -0
  82. package/dist/database/index.js +4 -0
  83. package/dist/email-templates/index.d.ts +51 -0
  84. package/dist/email-templates/index.js +57 -0
  85. package/dist/errors/Handler.d.ts +100 -0
  86. package/dist/errors/index.d.ts +1 -0
  87. package/dist/errors/index.js +5 -0
  88. package/dist/events/EventServiceProvider.d.ts +82 -0
  89. package/dist/events/Listener.d.ts +28 -0
  90. package/dist/events/index.d.ts +80 -0
  91. package/dist/events/index.js +1 -0
  92. package/dist/excel/index.d.ts +154 -0
  93. package/dist/excel/index.js +1 -0
  94. package/dist/feature-flags/index.d.ts +158 -0
  95. package/dist/feature-flags/index.js +59 -0
  96. package/dist/forms/index.d.ts +81 -0
  97. package/dist/forms/index.js +1 -0
  98. package/dist/hashing/Hash.d.ts +51 -0
  99. package/dist/hashing/index.d.ts +1 -0
  100. package/dist/hashing/index.js +1 -0
  101. package/dist/hooks/index.d.ts +135 -0
  102. package/dist/hooks/index.js +5 -0
  103. package/dist/http/index.d.ts +201 -0
  104. package/dist/http/index.js +2 -0
  105. package/dist/i18n/index.d.ts +81 -0
  106. package/dist/i18n/index.js +1 -0
  107. package/dist/index.d.ts +54 -0
  108. package/dist/index.js +127 -0
  109. package/dist/logging/LogViewer.d.ts +95 -0
  110. package/dist/logging/LogViewer.js +1 -0
  111. package/dist/logging/index.d.ts +83 -0
  112. package/dist/logging/index.js +3 -0
  113. package/dist/mail/index.d.ts +149 -0
  114. package/dist/mail/index.js +1 -0
  115. package/dist/middleware/Middleware.d.ts +208 -0
  116. package/dist/middleware/index.d.ts +1 -0
  117. package/dist/middleware/index.js +1 -0
  118. package/dist/notifications/index.d.ts +85 -0
  119. package/dist/notifications/index.js +2 -0
  120. package/dist/orm/Model.d.ts +123 -0
  121. package/dist/orm/Observer.d.ts +34 -0
  122. package/dist/orm/QueryBuilder.d.ts +119 -0
  123. package/dist/orm/Relationship.d.ts +58 -0
  124. package/dist/orm/index.d.ts +4 -0
  125. package/dist/orm/index.js +1 -0
  126. package/dist/pagination/index.d.ts +8 -0
  127. package/dist/pagination/index.js +0 -0
  128. package/dist/pdf/GeneratePdfJob.d.ts +99 -0
  129. package/dist/pdf/GeneratePdfJob.js +41 -0
  130. package/dist/pdf/index.d.ts +328 -0
  131. package/dist/pdf/index.js +41 -0
  132. package/dist/permissions/index.d.ts +161 -0
  133. package/dist/permissions/index.js +60 -0
  134. package/dist/plugins/BootstrapPlugins.d.ts +11 -0
  135. package/dist/plugins/PluginInstaller.d.ts +30 -0
  136. package/dist/plugins/PluginInstaller.js +1 -0
  137. package/dist/plugins/PluginPublisher.d.ts +32 -0
  138. package/dist/plugins/PluginPublisher.js +1 -0
  139. package/dist/plugins/PluginRegistry.d.ts +55 -0
  140. package/dist/plugins/PluginRegistry.js +1 -0
  141. package/dist/plugins/index.d.ts +206 -0
  142. package/dist/plugins/index.js +1 -0
  143. package/dist/queue/JobMonitor.d.ts +109 -0
  144. package/dist/queue/JobMonitor.js +5 -0
  145. package/dist/queue/index.d.ts +279 -0
  146. package/dist/queue/index.js +5 -0
  147. package/dist/repositories/index.d.ts +147 -0
  148. package/dist/repositories/index.js +1 -0
  149. package/dist/routing/Controller.d.ts +115 -0
  150. package/dist/routing/FormRequest.d.ts +94 -0
  151. package/dist/routing/Resource.d.ts +213 -0
  152. package/dist/routing/Response.d.ts +138 -0
  153. package/dist/routing/index.d.ts +4 -0
  154. package/dist/routing/index.js +5 -0
  155. package/dist/scheduler/ScheduleMonitor.d.ts +141 -0
  156. package/dist/scheduler/ScheduleMonitor.js +1 -0
  157. package/dist/scheduler/SchedulerLock.d.ts +33 -0
  158. package/dist/scheduler/index.d.ts +208 -0
  159. package/dist/scheduler/index.js +34 -0
  160. package/dist/services/index.d.ts +79 -0
  161. package/dist/services/index.js +1 -0
  162. package/dist/session/Session.d.ts +166 -0
  163. package/dist/session/index.d.ts +1 -0
  164. package/dist/session/index.js +16 -0
  165. package/dist/storage/index.d.ts +154 -0
  166. package/dist/storage/index.js +1 -0
  167. package/dist/support/Pipeline.d.ts +65 -0
  168. package/dist/support/date.d.ts +136 -0
  169. package/dist/support/date.js +1 -0
  170. package/dist/support/index.d.ts +8 -0
  171. package/dist/support/index.js +1 -0
  172. package/dist/support/singleton.d.ts +10 -0
  173. package/dist/support/uuid.d.ts +40 -0
  174. package/dist/teams/index.d.ts +91 -0
  175. package/dist/teams/index.js +78 -0
  176. package/dist/uploads/index.d.ts +63 -0
  177. package/dist/uploads/index.js +2 -0
  178. package/dist/validation/index.d.ts +46 -0
  179. package/dist/validation/index.js +1 -0
  180. package/dist/webhooks/index.d.ts +66 -0
  181. package/dist/webhooks/index.js +1 -0
  182. package/package.json +338 -0
  183. package/src/i18n/LanguageSwitcher.svelte +47 -0
  184. package/src/i18n/index.ts +113 -0
  185. package/src/ui/Alert.svelte +22 -0
  186. package/src/ui/Avatar.svelte +18 -0
  187. package/src/ui/AvatarFallback.svelte +18 -0
  188. package/src/ui/AvatarImage.svelte +12 -0
  189. package/src/ui/Badge.svelte +27 -0
  190. package/src/ui/Button.svelte +51 -0
  191. package/src/ui/Card.svelte +15 -0
  192. package/src/ui/CardContent.svelte +15 -0
  193. package/src/ui/CardDescription.svelte +15 -0
  194. package/src/ui/CardFooter.svelte +15 -0
  195. package/src/ui/CardHeader.svelte +15 -0
  196. package/src/ui/CardTitle.svelte +15 -0
  197. package/src/ui/Icon.svelte +81 -0
  198. package/src/ui/Input.svelte +40 -0
  199. package/src/ui/Label.svelte +20 -0
  200. package/src/ui/Separator.svelte +10 -0
  201. package/src/ui/Tabs.svelte +23 -0
  202. package/src/ui/TabsContent.svelte +27 -0
  203. package/src/ui/TabsList.svelte +19 -0
  204. package/src/ui/TabsTrigger.svelte +28 -0
  205. package/src/ui/Toaster.svelte +279 -0
  206. package/src/ui/index.ts +31 -0
  207. package/src/ui/toast.ts +212 -0
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Svelar Permissions
3
+ *
4
+ * Spatie-inspired roles & permissions system. Provides:
5
+ * - Role model with permissions assignment
6
+ * - Permission model
7
+ * - HasRoles trait (mixin) for any model
8
+ * - RequirePermission / RequireRole middleware
9
+ * - Default migrations for roles, permissions, and pivot tables
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { Permission, Role, HasRoles } from 'svelar/permissions';
14
+ *
15
+ * // Models are auto-configured after migrations run
16
+ * const admin = await Role.create({ name: 'admin', guard: 'web' });
17
+ * const perm = await Permission.create({ name: 'manage-users', guard: 'web' });
18
+ *
19
+ * await admin.givePermission(perm);
20
+ *
21
+ * // On a user model:
22
+ * class User extends HasRoles(Model) { ... }
23
+ *
24
+ * await user.assignRole('admin');
25
+ * await user.givePermission('edit-posts');
26
+ *
27
+ * user.hasRole('admin'); // true
28
+ * user.hasPermission('manage-users'); // true (via admin role)
29
+ * user.can('edit-posts'); // true (direct permission)
30
+ * ```
31
+ */
32
+ import { Middleware, type MiddlewareContext, type NextFunction } from '../middleware/Middleware.js';
33
+ export interface PermissionRecord {
34
+ id: number;
35
+ name: string;
36
+ guard: string;
37
+ description?: string;
38
+ created_at?: string;
39
+ updated_at?: string;
40
+ }
41
+ export interface RoleRecord {
42
+ id: number;
43
+ name: string;
44
+ guard: string;
45
+ description?: string;
46
+ created_at?: string;
47
+ updated_at?: string;
48
+ }
49
+ declare class PermissionManager {
50
+ private connectionGetter?;
51
+ /**
52
+ * Configure the database connection for permissions
53
+ */
54
+ configure(getConnection: () => Promise<any>): void;
55
+ private db;
56
+ createPermission(data: {
57
+ name: string;
58
+ guard?: string;
59
+ description?: string;
60
+ }): Promise<PermissionRecord>;
61
+ findPermission(name: string, guard?: string): Promise<PermissionRecord | null>;
62
+ findPermissionById(id: number): Promise<PermissionRecord | null>;
63
+ allPermissions(guard?: string): Promise<PermissionRecord[]>;
64
+ deletePermission(name: string, guard?: string): Promise<void>;
65
+ createRole(data: {
66
+ name: string;
67
+ guard?: string;
68
+ description?: string;
69
+ }): Promise<RoleRecord>;
70
+ findRole(name: string, guard?: string): Promise<RoleRecord | null>;
71
+ findRoleById(id: number): Promise<RoleRecord | null>;
72
+ allRoles(guard?: string): Promise<RoleRecord[]>;
73
+ deleteRole(name: string, guard?: string): Promise<void>;
74
+ giveRolePermission(roleId: number, permissionId: number): Promise<void>;
75
+ revokeRolePermission(roleId: number, permissionId: number): Promise<void>;
76
+ getRolePermissions(roleId: number): Promise<PermissionRecord[]>;
77
+ roleHasPermission(roleId: number, permissionName: string): Promise<boolean>;
78
+ assignRole(modelType: string, modelId: number, roleId: number): Promise<void>;
79
+ removeRole(modelType: string, modelId: number, roleId: number): Promise<void>;
80
+ getModelRoles(modelType: string, modelId: number): Promise<RoleRecord[]>;
81
+ modelHasRole(modelType: string, modelId: number, roleName: string): Promise<boolean>;
82
+ giveModelPermission(modelType: string, modelId: number, permissionId: number): Promise<void>;
83
+ revokeModelPermission(modelType: string, modelId: number, permissionId: number): Promise<void>;
84
+ getModelDirectPermissions(modelType: string, modelId: number): Promise<PermissionRecord[]>;
85
+ /**
86
+ * Get ALL permissions for a model (direct + via roles)
87
+ */
88
+ getModelAllPermissions(modelType: string, modelId: number): Promise<PermissionRecord[]>;
89
+ /**
90
+ * Check if a model has a permission (direct or via role)
91
+ */
92
+ modelHasPermission(modelType: string, modelId: number, permissionName: string): Promise<boolean>;
93
+ /**
94
+ * Sync roles for a model (remove all, then assign new ones)
95
+ */
96
+ syncRoles(modelType: string, modelId: number, roleNames: string[], guard?: string): Promise<void>;
97
+ /**
98
+ * Sync permissions for a model (remove all direct, then assign new ones)
99
+ */
100
+ syncPermissions(modelType: string, modelId: number, permissionNames: string[], guard?: string): Promise<void>;
101
+ }
102
+ /**
103
+ * Mixin that adds role & permission methods to any Model class.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * class User extends HasRoles(Model) {
108
+ * static table = 'users';
109
+ * // ...
110
+ * }
111
+ *
112
+ * const user = await User.find(1);
113
+ * await user.assignRole('admin');
114
+ * await user.givePermission('manage-users');
115
+ *
116
+ * console.log(await user.hasRole('admin')); // true
117
+ * console.log(await user.can('manage-users')); // true
118
+ * ```
119
+ */
120
+ type Constructor = new (...args: any[]) => any;
121
+ export interface HasRolesInstance {
122
+ readonly _modelType: string;
123
+ readonly _modelId: number;
124
+ assignRole(roleName: string, guard?: string): Promise<void>;
125
+ removeRole(roleName: string, guard?: string): Promise<void>;
126
+ hasRole(roleName: string, guard?: string): Promise<boolean>;
127
+ givePermission(permissionName: string, guard?: string): Promise<void>;
128
+ revokePermission(permissionName: string, guard?: string): Promise<void>;
129
+ hasPermission(permissionName: string, guard?: string): Promise<boolean>;
130
+ can(permissionName: string, guard?: string): Promise<boolean>;
131
+ getRoles(): Promise<RoleRecord[]>;
132
+ getAllPermissions(): Promise<PermissionRecord[]>;
133
+ getDirectPermissions(): Promise<PermissionRecord[]>;
134
+ }
135
+ export declare function HasRoles<TBase extends Constructor>(Base: TBase): TBase & (new (...args: any[]) => HasRolesInstance);
136
+ /**
137
+ * Middleware that requires a specific permission
138
+ */
139
+ export declare class RequirePermissionMiddleware extends Middleware {
140
+ private permission;
141
+ constructor(permission: string);
142
+ handle(ctx: MiddlewareContext, next: NextFunction): Promise<Response | void>;
143
+ }
144
+ /**
145
+ * Middleware that requires a specific role
146
+ */
147
+ export declare class RequireRoleMiddleware extends Middleware {
148
+ private role;
149
+ constructor(role: string);
150
+ handle(ctx: MiddlewareContext, next: NextFunction): Promise<Response | void>;
151
+ }
152
+ /**
153
+ * SQL statements for creating the permissions tables.
154
+ * These are database-agnostic and work with SQLite, PostgreSQL, and MySQL.
155
+ */
156
+ export declare const PERMISSIONS_MIGRATION_SQL: {
157
+ up: string[];
158
+ down: string[];
159
+ };
160
+ export declare const Permissions: PermissionManager;
161
+ export {};
@@ -0,0 +1,60 @@
1
+ var T=Object.defineProperty;var E=(c,e)=>()=>(c&&(e=c(c=0)),e);var P=(c,e)=>{for(var s in e)T(c,s,{get:e[s],enumerable:!0})};function p(c,e){let s=Symbol.for(c),t=globalThis;return t[s]||(t[s]=e()),t[s]}var h=E(()=>{"use strict"});var R={};P(R,{Connection:()=>b});var g,b,y=E(()=>{"use strict";h();g=class{connections=new Map;config=null;defaultName="default";configure(e){this.config=e,this.defaultName=e.default}async connection(e){let s=e??this.defaultName;if(this.connections.has(s))return this.connections.get(s).drizzle;if(!this.config)throw new Error("Database not configured. Call Connection.configure() first, or register DatabaseServiceProvider.");let t=this.config.connections[s];if(!t)throw new Error(`Database connection "${s}" is not defined in configuration.`);let n=await this.createConnection(t);return this.connections.set(s,n),n.drizzle}async rawClient(e){let s=e??this.defaultName;return await this.connection(s),this.connections.get(s).rawClient}async raw(e,s=[],t){let n=await this.connection(t),r=this.getConfig(t);switch(r.driver){case"sqlite":{let i=await this.rawClient(t),a=s.map(l=>typeof l=="boolean"?l?1:0:l instanceof Date?l.toISOString():l),d=i.prepare(e),m=e.trimStart().toUpperCase();return m.startsWith("SELECT")||m.startsWith("PRAGMA")||m.startsWith("WITH")?d.all(...a):d.run(...a)}case"postgres":return(await this.rawClient(t))(e,...s);case"mysql":{let i=await this.rawClient(t),[a]=await i.execute(e,s);return a}default:throw new Error(`Unsupported driver: ${r.driver}`)}}getDriver(e){return this.getConfig(e).driver}getConfig(e){let s=e??this.defaultName;if(!this.config)throw new Error("Database not configured.");let t=this.config.connections[s];if(!t)throw new Error(`Database connection "${s}" is not defined.`);return t}async disconnect(e){if(e){let s=this.connections.get(e);s&&(await this.closeConnection(s),this.connections.delete(e))}else{for(let[s,t]of this.connections)await this.closeConnection(t);this.connections.clear()}}isConnected(e){return this.connections.has(e??this.defaultName)}async transaction(e,s){let t=this.getConfig(s),n=await this.rawClient(s);switch(t.driver){case"sqlite":{n.exec("BEGIN");try{let r=await e();return n.exec("COMMIT"),r}catch(r){throw n.exec("ROLLBACK"),r}}case"postgres":{await n`BEGIN`;try{let r=await e();return await n`COMMIT`,r}catch(r){throw await n`ROLLBACK`,r}}case"mysql":{let r=await n.getConnection();await r.beginTransaction();try{let i=await e();return await r.commit(),r.release(),i}catch(i){throw await r.rollback(),r.release(),i}}default:throw new Error(`Unsupported driver: ${t.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 s=e.filename??e.database??":memory:";try{let t=(await import("better-sqlite3")).default,{drizzle:n}=await import("drizzle-orm/better-sqlite3"),r=new t(s);return r.pragma("journal_mode = WAL"),r.pragma("foreign_keys = ON"),{drizzle:n(r),config:e,rawClient:r}}catch(t){let n;try{n=(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: ${t instanceof Error?t.message:String(t)}`)}let r=new n(s);r.exec("PRAGMA journal_mode = WAL"),r.exec("PRAGMA foreign_keys = ON");let i={prepare(d){let m=r.prepare(d);return{all(...l){return m.all(...l)},run(...l){return m.run(...l)},get(...l){return m.get(...l)}}},exec(d){r.exec(d)},pragma(d){return r.prepare(`PRAGMA ${d}`).all()},close(){r.close()}},a;try{let{drizzle:d}=await import("drizzle-orm/better-sqlite3");a=d(i)}catch{a=i}return{drizzle:a,config:e,rawClient:i}}}async createPostgresConnection(e){let s=(await import("postgres")).default,{drizzle:t}=await import("drizzle-orm/postgres-js"),n=e.url??`postgres://${e.user}:${e.password}@${e.host??"localhost"}:${e.port??5432}/${e.database}`,r=s(n);return{drizzle:t(r),config:e,rawClient:r}}async createMySQLConnection(e){let s=await import("mysql2/promise"),{drizzle:t}=await import("drizzle-orm/mysql2"),n=s.createPool({host:e.host??"localhost",port:e.port??3306,database:e.database,user:e.user,password:e.password,uri:e.url});return{drizzle:t(n),config:e,rawClient:n}}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{}}},b=p("svelar.connection",()=>new g)});var u=class{};h();var w=class{connectionGetter;configure(e){this.connectionGetter=e}async db(){if(this.connectionGetter)return this.connectionGetter();let{Connection:e}=await Promise.resolve().then(()=>(y(),R));return e}async createPermission(e){let s=await this.db(),t=new Date().toISOString(),n=e.guard??"web";return await s.raw("INSERT INTO permissions (name, guard, description, created_at, updated_at) VALUES (?, ?, ?, ?, ?)",[e.name,n,e.description??null,t,t]),(await s.raw("SELECT * FROM permissions WHERE name = ? AND guard = ?",[e.name,n]))[0]}async findPermission(e,s="web"){return(await(await this.db()).raw("SELECT * FROM permissions WHERE name = ? AND guard = ?",[e,s]))[0]??null}async findPermissionById(e){return(await(await this.db()).raw("SELECT * FROM permissions WHERE id = ?",[e]))[0]??null}async allPermissions(e="web"){return(await this.db()).raw("SELECT * FROM permissions WHERE guard = ? ORDER BY name",[e])}async deletePermission(e,s="web"){await(await this.db()).raw("DELETE FROM permissions WHERE name = ? AND guard = ?",[e,s])}async createRole(e){let s=await this.db(),t=new Date().toISOString(),n=e.guard??"web";return await s.raw("INSERT INTO roles (name, guard, description, created_at, updated_at) VALUES (?, ?, ?, ?, ?)",[e.name,n,e.description??null,t,t]),(await s.raw("SELECT * FROM roles WHERE name = ? AND guard = ?",[e.name,n]))[0]}async findRole(e,s="web"){return(await(await this.db()).raw("SELECT * FROM roles WHERE name = ? AND guard = ?",[e,s]))[0]??null}async findRoleById(e){return(await(await this.db()).raw("SELECT * FROM roles WHERE id = ?",[e]))[0]??null}async allRoles(e="web"){return(await this.db()).raw("SELECT * FROM roles WHERE guard = ? ORDER BY name",[e])}async deleteRole(e,s="web"){await(await this.db()).raw("DELETE FROM roles WHERE name = ? AND guard = ?",[e,s])}async giveRolePermission(e,s){let t=await this.db();try{await t.raw("INSERT INTO role_has_permissions (role_id, permission_id) VALUES (?, ?)",[e,s])}catch{}}async revokeRolePermission(e,s){await(await this.db()).raw("DELETE FROM role_has_permissions WHERE role_id = ? AND permission_id = ?",[e,s])}async getRolePermissions(e){return(await this.db()).raw(`SELECT p.* FROM permissions p
2
+ INNER JOIN role_has_permissions rp ON p.id = rp.permission_id
3
+ WHERE rp.role_id = ?
4
+ ORDER BY p.name`,[e])}async roleHasPermission(e,s){return(await(await this.db()).raw(`SELECT 1 FROM role_has_permissions rp
5
+ INNER JOIN permissions p ON p.id = rp.permission_id
6
+ WHERE rp.role_id = ? AND p.name = ?`,[e,s])).length>0}async assignRole(e,s,t){let n=await this.db();try{await n.raw("INSERT INTO model_has_roles (model_type, model_id, role_id) VALUES (?, ?, ?)",[e,s,t])}catch{}}async removeRole(e,s,t){await(await this.db()).raw("DELETE FROM model_has_roles WHERE model_type = ? AND model_id = ? AND role_id = ?",[e,s,t])}async getModelRoles(e,s){return(await this.db()).raw(`SELECT r.* FROM roles r
7
+ INNER JOIN model_has_roles mr ON r.id = mr.role_id
8
+ WHERE mr.model_type = ? AND mr.model_id = ?
9
+ ORDER BY r.name`,[e,s])}async modelHasRole(e,s,t){return(await(await this.db()).raw(`SELECT 1 FROM model_has_roles mr
10
+ INNER JOIN roles r ON r.id = mr.role_id
11
+ WHERE mr.model_type = ? AND mr.model_id = ? AND r.name = ?`,[e,s,t])).length>0}async giveModelPermission(e,s,t){let n=await this.db();try{await n.raw("INSERT INTO model_has_permissions (model_type, model_id, permission_id) VALUES (?, ?, ?)",[e,s,t])}catch{}}async revokeModelPermission(e,s,t){await(await this.db()).raw("DELETE FROM model_has_permissions WHERE model_type = ? AND model_id = ? AND permission_id = ?",[e,s,t])}async getModelDirectPermissions(e,s){return(await this.db()).raw(`SELECT p.* FROM permissions p
12
+ INNER JOIN model_has_permissions mp ON p.id = mp.permission_id
13
+ WHERE mp.model_type = ? AND mp.model_id = ?
14
+ ORDER BY p.name`,[e,s])}async getModelAllPermissions(e,s){return(await this.db()).raw(`SELECT DISTINCT p.* FROM permissions p
15
+ LEFT JOIN model_has_permissions mp
16
+ ON p.id = mp.permission_id AND mp.model_type = ? AND mp.model_id = ?
17
+ LEFT JOIN role_has_permissions rp ON p.id = rp.permission_id
18
+ LEFT JOIN model_has_roles mr
19
+ ON rp.role_id = mr.role_id AND mr.model_type = ? AND mr.model_id = ?
20
+ WHERE mp.permission_id IS NOT NULL OR mr.role_id IS NOT NULL
21
+ ORDER BY p.name`,[e,s,e,s])}async modelHasPermission(e,s,t){let n=await this.db();return(await n.raw(`SELECT 1 FROM model_has_permissions mp
22
+ INNER JOIN permissions p ON p.id = mp.permission_id
23
+ WHERE mp.model_type = ? AND mp.model_id = ? AND p.name = ?`,[e,s,t])).length>0?!0:(await n.raw(`SELECT 1 FROM model_has_roles mr
24
+ INNER JOIN role_has_permissions rp ON rp.role_id = mr.role_id
25
+ INNER JOIN permissions p ON p.id = rp.permission_id
26
+ WHERE mr.model_type = ? AND mr.model_id = ? AND p.name = ?`,[e,s,t])).length>0}async syncRoles(e,s,t,n="web"){await(await this.db()).raw("DELETE FROM model_has_roles WHERE model_type = ? AND model_id = ?",[e,s]);for(let i of t){let a=await this.findRole(i,n);a&&await this.assignRole(e,s,a.id)}}async syncPermissions(e,s,t,n="web"){await(await this.db()).raw("DELETE FROM model_has_permissions WHERE model_type = ? AND model_id = ?",[e,s]);for(let i of t){let a=await this.findPermission(i,n);a&&await this.giveModelPermission(e,s,a.id)}}};function I(c){class e extends c{get _modelType(){return this.constructor.name||"User"}get _modelId(){return this.id??this.getAttribute?.("id")}async assignRole(t,n="web"){let r=await o.findRole(t,n);if(!r)throw new Error(`Role "${t}" does not exist.`);await o.assignRole(this._modelType,this._modelId,r.id)}async removeRole(t,n="web"){let r=await o.findRole(t,n);r&&await o.removeRole(this._modelType,this._modelId,r.id)}async syncRoles(t,n="web"){await o.syncRoles(this._modelType,this._modelId,t,n)}async hasRole(t){return o.modelHasRole(this._modelType,this._modelId,t)}async hasAnyRole(...t){for(let n of t)if(await this.hasRole(n))return!0;return!1}async hasAllRoles(...t){for(let n of t)if(!await this.hasRole(n))return!1;return!0}async getRoles(){return o.getModelRoles(this._modelType,this._modelId)}async givePermission(t,n="web"){let r=await o.findPermission(t,n);if(!r)throw new Error(`Permission "${t}" does not exist.`);await o.giveModelPermission(this._modelType,this._modelId,r.id)}async revokePermission(t,n="web"){let r=await o.findPermission(t,n);r&&await o.revokeModelPermission(this._modelType,this._modelId,r.id)}async syncPermissions(t,n="web"){await o.syncPermissions(this._modelType,this._modelId,t,n)}async hasPermission(t){return o.modelHasPermission(this._modelType,this._modelId,t)}async can(t){return this.hasPermission(t)}async cannot(t){return!await this.hasPermission(t)}async getAllPermissions(){return o.getModelAllPermissions(this._modelType,this._modelId)}async getDirectPermissions(){return o.getModelDirectPermissions(this._modelType,this._modelId)}}return e}var f=class extends u{constructor(s){super();this.permission=s}async handle(s,t){let n=s.event.locals.user;if(!n)return new Response(JSON.stringify({message:"Unauthenticated"}),{status:401,headers:{"Content-Type":"application/json"}});let r=n.constructor?.name||"User",i=n.id??n.getAttribute?.("id");return await o.modelHasPermission(r,i,this.permission)?t():new Response(JSON.stringify({message:`Missing permission: ${this.permission}`}),{status:403,headers:{"Content-Type":"application/json"}})}},N=class extends u{constructor(s){super();this.role=s}async handle(s,t){let n=s.event.locals.user;if(!n)return new Response(JSON.stringify({message:"Unauthenticated"}),{status:401,headers:{"Content-Type":"application/json"}});let r=n.constructor?.name||"User",i=n.id??n.getAttribute?.("id");return await o.modelHasRole(r,i,this.role)?t():new Response(JSON.stringify({message:`Missing role: ${this.role}`}),{status:403,headers:{"Content-Type":"application/json"}})}},S={up:[`CREATE TABLE IF NOT EXISTS permissions (
27
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
28
+ name VARCHAR(255) NOT NULL,
29
+ guard VARCHAR(255) NOT NULL DEFAULT 'web',
30
+ description TEXT,
31
+ created_at DATETIME,
32
+ updated_at DATETIME,
33
+ UNIQUE(name, guard)
34
+ )`,`CREATE TABLE IF NOT EXISTS roles (
35
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
36
+ name VARCHAR(255) NOT NULL,
37
+ guard VARCHAR(255) NOT NULL DEFAULT 'web',
38
+ description TEXT,
39
+ created_at DATETIME,
40
+ updated_at DATETIME,
41
+ UNIQUE(name, guard)
42
+ )`,`CREATE TABLE IF NOT EXISTS role_has_permissions (
43
+ role_id INTEGER NOT NULL,
44
+ permission_id INTEGER NOT NULL,
45
+ PRIMARY KEY (role_id, permission_id),
46
+ FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
47
+ FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
48
+ )`,`CREATE TABLE IF NOT EXISTS model_has_roles (
49
+ model_type VARCHAR(255) NOT NULL,
50
+ model_id INTEGER NOT NULL,
51
+ role_id INTEGER NOT NULL,
52
+ PRIMARY KEY (model_type, model_id, role_id),
53
+ FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
54
+ )`,`CREATE TABLE IF NOT EXISTS model_has_permissions (
55
+ model_type VARCHAR(255) NOT NULL,
56
+ model_id INTEGER NOT NULL,
57
+ permission_id INTEGER NOT NULL,
58
+ PRIMARY KEY (model_type, model_id, permission_id),
59
+ FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
60
+ )`],down:["DROP TABLE IF EXISTS model_has_permissions","DROP TABLE IF EXISTS model_has_roles","DROP TABLE IF EXISTS role_has_permissions","DROP TABLE IF EXISTS roles","DROP TABLE IF EXISTS permissions"]},o=p("svelar.permissions",()=>new w);export{I as HasRoles,S as PERMISSIONS_MIGRATION_SQL,o as Permissions,f as RequirePermissionMiddleware,N as RequireRoleMiddleware};
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Svelar Bootstrap Plugins
3
+ *
4
+ * Auto-discovers and boots enabled plugins at app startup.
5
+ */
6
+ import type { Container } from '../container/Container.js';
7
+ /**
8
+ * Bootstrap plugins from the plugin registry
9
+ * Loads enabled plugins from configuration and boots them
10
+ */
11
+ export declare function bootstrapPlugins(app: Container, enabledPlugins?: string[]): Promise<void>;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Svelar Plugin Installer
3
+ *
4
+ * Handles installing plugins from npm and wiring them up.
5
+ */
6
+ import { type PublishResult } from './PluginPublisher.js';
7
+ export interface InstallResult {
8
+ success: boolean;
9
+ pluginName: string;
10
+ version: string;
11
+ published: PublishResult | null;
12
+ error?: string;
13
+ }
14
+ declare class PluginInstallerService {
15
+ /**
16
+ * Install a plugin package and register it
17
+ */
18
+ install(packageName: string, options?: {
19
+ publish?: boolean;
20
+ }): Promise<InstallResult>;
21
+ /**
22
+ * Uninstall a plugin
23
+ */
24
+ uninstall(pluginName: string): Promise<boolean>;
25
+ private runNpmInstall;
26
+ private runNpmUninstall;
27
+ private loadPluginClass;
28
+ }
29
+ export declare const PluginInstaller: PluginInstallerService;
30
+ export {};
@@ -0,0 +1 @@
1
+ var b=(u=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(u,{get:(s,e)=>(typeof require<"u"?require:s)[e]}):u)(function(u){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+u+'" is not supported')});function f(u,s){let e=Symbol.for(u),i=globalThis;return i[e]||(i[e]=s()),i[e]}var y=class{plugins=new Map;enabledPlugins=new Set;async discover(){let{join:s}=await import("path"),{existsSync:e,readdirSync:i}=await import("fs"),{readFile:c}=await import("fs/promises"),o=[],t=s(process.cwd(),"node_modules");if(!e(t))return o;try{let p=i(t,{withFileTypes:!0});for(let l of p){if(!l.isDirectory())continue;let g=l.name;if(g.startsWith("."))continue;let a=g.startsWith("svelar-");if(!a)continue;let d=s(t,g,"package.json");if(e(d))try{let n=await c(d,"utf-8"),r=JSON.parse(n),m=r.keywords?.includes("svelar-plugin");if(!a&&!m)continue;let h={name:r.name||g,version:r.version||"0.0.0",description:r.description||"",packageName:g,installed:!0,enabled:!1,hasConfig:!!r.svelar?.config,hasMigrations:!!r.svelar?.migrations};o.push(h),this.plugins.set(h.name,h)}catch{}}}catch{}return o}enable(s){let e=this.plugins.get(s);if(!e)throw new Error(`Plugin "${s}" not found in registry.`);this.enabledPlugins.add(s),e.enabled=!0}disable(s){this.enabledPlugins.delete(s);let e=this.plugins.get(s);e&&(e.enabled=!1)}isEnabled(s){return this.enabledPlugins.has(s)}list(){return[...this.plugins.values()]}listEnabled(){return[...this.plugins.values()].filter(s=>this.enabledPlugins.has(s.name))}get(s){return this.plugins.get(s)}register(s){this.plugins.set(s.name,s)}},w=f("svelar.pluginRegistry",()=>new y);var P=class{async publish(s,e){let{mkdir:i,copyFile:c}=await import("fs/promises"),{join:o,dirname:t}=await import("path"),{existsSync:p}=await import("fs"),l={configs:[],migrations:[],assets:[]},g=s.publishables?.()||{};for(let[a,d]of Object.entries(g))for(let n of d){if(e?.only&&n.type!==e.only)continue;let r=o(process.cwd(),n.dest),m=t(r);if(!(p(r)&&!e?.force))try{await i(m,{recursive:!0}),await c(n.source,r),n.type==="config"?l.configs.push(r):n.type==="migration"?l.migrations.push(r):n.type==="asset"&&l.assets.push(r)}catch(h){console.warn(`Failed to publish ${n.source} to ${r}:`,h)}}return l}async preview(s){let e={configs:[],migrations:[],assets:[]},i=s.publishables?.()||{};for(let[c,o]of Object.entries(i))for(let t of o){let p=b("path").join(process.cwd(),t.dest);t.type==="config"?e.configs.push(p):t.type==="migration"?e.migrations.push(p):t.type==="asset"&&e.assets.push(p)}return e}},M=f("svelar.pluginPublisher",()=>new P);var v=class{async install(s,e){let{spawn:i}=await import("child_process"),{promisify:c}=await import("util"),{join:o}=await import("path"),{readFile:t}=await import("fs/promises"),{existsSync:p}=await import("fs");try{await this.runNpmInstall(s);let l=w,g=await l.discover(),a;for(let n of g)if(n.packageName===s||n.name===s){a=n;break}if(!a)return{success:!1,pluginName:s,version:"0.0.0",published:null,error:`Plugin not found after installation. Make sure ${s} is a valid Svelar plugin.`};l.enable(a.name);let d=null;if(e?.publish!==!1)try{let n=await this.loadPluginClass(a.packageName);n&&(d=await M.publish(new n))}catch(n){console.warn("Failed to publish plugin assets:",n)}return{success:!0,pluginName:a.name,version:a.version,published:d}}catch(l){return{success:!1,pluginName:s,version:"0.0.0",published:null,error:l?.message??String(l)}}}async uninstall(s){try{let e=w,i=e.get(s);return i?(e.disable(s),await this.runNpmUninstall(i.packageName),!0):!1}catch(e){return console.error("Failed to uninstall plugin:",e),!1}}async runNpmInstall(s){return new Promise((e,i)=>{let{spawn:c}=b("child_process"),o=c("npm",["install",s],{cwd:process.cwd(),stdio:"inherit"});o.on("close",t=>{t===0?e():i(new Error(`npm install exited with code ${t}`))}),o.on("error",i)})}async runNpmUninstall(s){return new Promise((e,i)=>{let{spawn:c}=b("child_process"),o=c("npm",["uninstall",s],{cwd:process.cwd(),stdio:"inherit"});o.on("close",t=>{t===0?e():i(new Error(`npm uninstall exited with code ${t}`))}),o.on("error",i)})}async loadPluginClass(s){try{let e=await import(s);return e.default||Object.values(e)[0]}catch{return null}}},I=f("svelar.pluginInstaller",()=>new v);export{I as PluginInstaller};
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Svelar Plugin Publisher
3
+ *
4
+ * Handles publishing a plugin's configuration files, migrations,
5
+ * and assets to the user's application.
6
+ */
7
+ import type { Plugin } from './index.js';
8
+ export interface PublishResult {
9
+ configs: string[];
10
+ migrations: string[];
11
+ assets: string[];
12
+ }
13
+ export interface PublishableFile {
14
+ source: string;
15
+ dest: string;
16
+ type: 'config' | 'migration' | 'asset';
17
+ }
18
+ declare class PluginPublisherService {
19
+ /**
20
+ * Publish a plugin's publishable assets
21
+ */
22
+ publish(plugin: Plugin, options?: {
23
+ force?: boolean;
24
+ only?: 'config' | 'migrations' | 'assets';
25
+ }): Promise<PublishResult>;
26
+ /**
27
+ * Check what would be published without actually publishing
28
+ */
29
+ preview(plugin: Plugin): Promise<PublishResult>;
30
+ }
31
+ export declare const PluginPublisher: PluginPublisherService;
32
+ export {};
@@ -0,0 +1 @@
1
+ var y=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,s)=>(typeof require<"u"?require:t)[s]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});function p(e,t){let s=Symbol.for(e),i=globalThis;return i[s]||(i[s]=t()),i[s]}var u=class{async publish(t,s){let{mkdir:i,copyFile:f}=await import("fs/promises"),{join:a,dirname:r}=await import("path"),{existsSync:l}=await import("fs"),c={configs:[],migrations:[],assets:[]},g=t.publishables?.()||{};for(let[P,b]of Object.entries(g))for(let o of b){if(s?.only&&o.type!==s.only)continue;let n=a(process.cwd(),o.dest),h=r(n);if(!(l(n)&&!s?.force))try{await i(h,{recursive:!0}),await f(o.source,n),o.type==="config"?c.configs.push(n):o.type==="migration"?c.migrations.push(n):o.type==="asset"&&c.assets.push(n)}catch(m){console.warn(`Failed to publish ${o.source} to ${n}:`,m)}}return c}async preview(t){let s={configs:[],migrations:[],assets:[]},i=t.publishables?.()||{};for(let[f,a]of Object.entries(i))for(let r of a){let l=y("path").join(process.cwd(),r.dest);r.type==="config"?s.configs.push(l):r.type==="migration"?s.migrations.push(l):r.type==="asset"&&s.assets.push(l)}return s}},j=p("svelar.pluginPublisher",()=>new u);export{j as PluginPublisher};
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Svelar Plugin Registry
3
+ *
4
+ * Discovers and manages installed plugins by scanning node_modules
5
+ * for packages with the 'svelar-plugin' keyword or 'svelar-' prefix.
6
+ */
7
+ export interface PluginMeta {
8
+ name: string;
9
+ version: string;
10
+ description: string;
11
+ packageName: string;
12
+ installed: boolean;
13
+ enabled: boolean;
14
+ hasConfig: boolean;
15
+ hasMigrations: boolean;
16
+ }
17
+ declare class PluginRegistryService {
18
+ private plugins;
19
+ private enabledPlugins;
20
+ /**
21
+ * Scan node_modules for svelar plugins
22
+ * Looks for packages with 'svelar-plugin' keyword or starting with 'svelar-'
23
+ */
24
+ discover(): Promise<PluginMeta[]>;
25
+ /**
26
+ * Register a plugin as enabled
27
+ */
28
+ enable(name: string): void;
29
+ /**
30
+ * Disable a plugin
31
+ */
32
+ disable(name: string): void;
33
+ /**
34
+ * Check if plugin is enabled
35
+ */
36
+ isEnabled(name: string): boolean;
37
+ /**
38
+ * Get all registered plugin metadata
39
+ */
40
+ list(): PluginMeta[];
41
+ /**
42
+ * Get enabled plugins
43
+ */
44
+ listEnabled(): PluginMeta[];
45
+ /**
46
+ * Get a plugin by name
47
+ */
48
+ get(name: string): PluginMeta | undefined;
49
+ /**
50
+ * Register a plugin in the registry
51
+ */
52
+ register(meta: PluginMeta): void;
53
+ }
54
+ export declare const PluginRegistry: PluginRegistryService;
55
+ export {};
@@ -0,0 +1 @@
1
+ function p(g,n){let e=Symbol.for(g),i=globalThis;return i[e]||(i[e]=n()),i[e]}var l=class{plugins=new Map;enabledPlugins=new Set;async discover(){let{join:n}=await import("path"),{existsSync:e,readdirSync:i}=await import("fs"),{readFile:h}=await import("fs/promises"),a=[],o=n(process.cwd(),"node_modules");if(!e(o))return a;try{let f=i(o,{withFileTypes:!0});for(let u of f){if(!u.isDirectory())continue;let s=u.name;if(s.startsWith("."))continue;let c=s.startsWith("svelar-");if(!c)continue;let d=n(o,s,"package.json");if(e(d))try{let b=await h(d,"utf-8"),t=JSON.parse(b),P=t.keywords?.includes("svelar-plugin");if(!c&&!P)continue;let r={name:t.name||s,version:t.version||"0.0.0",description:t.description||"",packageName:s,installed:!0,enabled:!1,hasConfig:!!t.svelar?.config,hasMigrations:!!t.svelar?.migrations};a.push(r),this.plugins.set(r.name,r)}catch{}}}catch{}return a}enable(n){let e=this.plugins.get(n);if(!e)throw new Error(`Plugin "${n}" not found in registry.`);this.enabledPlugins.add(n),e.enabled=!0}disable(n){this.enabledPlugins.delete(n);let e=this.plugins.get(n);e&&(e.enabled=!1)}isEnabled(n){return this.enabledPlugins.has(n)}list(){return[...this.plugins.values()]}listEnabled(){return[...this.plugins.values()].filter(n=>this.enabledPlugins.has(n.name))}get(n){return this.plugins.get(n)}register(n){this.plugins.set(n.name,n)}},y=p("svelar.pluginRegistry",()=>new l);export{y as PluginRegistry};
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Svelar Plugin System
3
+ *
4
+ * Extensible plugin architecture inspired by Laravel packages.
5
+ * Plugins can register service providers, middleware, commands,
6
+ * routes, migrations, and configuration.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { Plugin, PluginManager } from 'svelar/plugins';
11
+ *
12
+ * // Define a plugin
13
+ * class StripePlugin extends Plugin {
14
+ * name = 'svelar-stripe';
15
+ * version = '1.0.0';
16
+ *
17
+ * async register(app) {
18
+ * app.singleton('stripe', () => new Stripe(process.env.STRIPE_KEY));
19
+ * }
20
+ *
21
+ * async boot(app) {
22
+ * // Register routes, middleware, etc.
23
+ * }
24
+ *
25
+ * migrations() {
26
+ * return ['create_payments_table', 'create_subscriptions_table'];
27
+ * }
28
+ *
29
+ * config() {
30
+ * return {
31
+ * key: 'stripe',
32
+ * defaults: { currency: 'usd', webhook_secret: '' },
33
+ * };
34
+ * }
35
+ * }
36
+ *
37
+ * // Register plugins
38
+ * const plugins = new PluginManager(app);
39
+ * plugins.use(new StripePlugin());
40
+ * await plugins.boot();
41
+ * ```
42
+ */
43
+ import type { Container } from '../container/Container.js';
44
+ import type { Middleware } from '../middleware/Middleware.js';
45
+ export interface PluginConfig {
46
+ key: string;
47
+ defaults: Record<string, any>;
48
+ }
49
+ export interface PluginMigration {
50
+ name: string;
51
+ up: () => Promise<void>;
52
+ down: () => Promise<void>;
53
+ }
54
+ export interface PluginRoute {
55
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
56
+ path: string;
57
+ handler: (event: any) => Promise<Response>;
58
+ middleware?: string[];
59
+ }
60
+ export interface PluginCommand {
61
+ name: string;
62
+ description: string;
63
+ handler: (args: string[]) => Promise<void>;
64
+ }
65
+ export type PluginHook = 'app:boot' | 'app:shutdown' | 'request:before' | 'request:after' | 'model:creating' | 'model:created' | 'model:updating' | 'model:updated' | 'model:deleting' | 'model:deleted' | string;
66
+ export declare abstract class Plugin {
67
+ /** Unique plugin identifier (e.g., 'svelar-stripe') */
68
+ abstract readonly name: string;
69
+ /** Plugin version (semver) */
70
+ abstract readonly version: string;
71
+ /** Human-readable description */
72
+ description?: string;
73
+ /** Plugin dependencies (other plugin names) */
74
+ dependencies?: string[];
75
+ /**
76
+ * Register services, bindings, and configuration.
77
+ * Called before boot.
78
+ */
79
+ register(app: Container): Promise<void>;
80
+ /**
81
+ * Bootstrap the plugin after all plugins are registered.
82
+ * Use for setup that depends on other services.
83
+ */
84
+ boot(app: Container): Promise<void>;
85
+ /**
86
+ * Clean up when the plugin is unloaded
87
+ */
88
+ shutdown(): Promise<void>;
89
+ /**
90
+ * Return migration files this plugin provides
91
+ */
92
+ migrations(): string[];
93
+ /**
94
+ * Return default configuration for this plugin
95
+ */
96
+ config(): PluginConfig | null;
97
+ /**
98
+ * Return middleware this plugin provides
99
+ */
100
+ middleware(): Array<{
101
+ name: string;
102
+ handler: Middleware | ((ctx: any, next: any) => Promise<any>);
103
+ }>;
104
+ /**
105
+ * Return CLI commands this plugin provides
106
+ */
107
+ commands(): PluginCommand[];
108
+ /**
109
+ * Return API routes this plugin provides
110
+ */
111
+ routes(): PluginRoute[];
112
+ /**
113
+ * Return event listeners this plugin registers
114
+ */
115
+ listeners(): Array<{
116
+ event: string;
117
+ handler: (...args: any[]) => void | Promise<void>;
118
+ }>;
119
+ /**
120
+ * Return publishable files (configs, migrations, assets)
121
+ * Map of type -> array of { source, dest, type }
122
+ */
123
+ publishables?(): Record<string, Array<{
124
+ source: string;
125
+ dest: string;
126
+ type: 'config' | 'migration' | 'asset';
127
+ }>>;
128
+ }
129
+ export declare class PluginManager {
130
+ private app;
131
+ private plugins;
132
+ private registered;
133
+ private booted;
134
+ private hooks;
135
+ constructor(app: Container);
136
+ /**
137
+ * Register a plugin
138
+ */
139
+ use(plugin: Plugin): this;
140
+ /**
141
+ * Register multiple plugins
142
+ */
143
+ useMany(plugins: Plugin[]): this;
144
+ /**
145
+ * Register and boot all plugins (respects dependency order)
146
+ */
147
+ boot(): Promise<void>;
148
+ /**
149
+ * Shutdown all plugins (reverse order)
150
+ */
151
+ shutdown(): Promise<void>;
152
+ /**
153
+ * Get a registered plugin by name
154
+ */
155
+ get<T extends Plugin>(name: string): T | undefined;
156
+ /**
157
+ * Check if a plugin is registered
158
+ */
159
+ has(name: string): boolean;
160
+ /**
161
+ * Get all registered plugin names
162
+ */
163
+ names(): string[];
164
+ /**
165
+ * Get all plugins
166
+ */
167
+ all(): Plugin[];
168
+ /**
169
+ * Register a hook listener
170
+ */
171
+ on(hook: PluginHook, handler: (...args: any[]) => Promise<void> | void): void;
172
+ /**
173
+ * Trigger a hook
174
+ */
175
+ triggerHook(hook: PluginHook, ...args: any[]): Promise<void>;
176
+ /**
177
+ * Get all routes from all plugins
178
+ */
179
+ getRoutes(): PluginRoute[];
180
+ /**
181
+ * Get all commands from all plugins
182
+ */
183
+ getCommands(): PluginCommand[];
184
+ /**
185
+ * Get all middleware from all plugins
186
+ */
187
+ getMiddleware(): Array<{
188
+ name: string;
189
+ handler: any;
190
+ }>;
191
+ /**
192
+ * Get all migrations from all plugins
193
+ */
194
+ getMigrations(): string[];
195
+ /**
196
+ * Get all configurations from all plugins
197
+ */
198
+ getConfigs(): PluginConfig[];
199
+ private registerPlugin;
200
+ private bootPlugin;
201
+ private resolveDependencyOrder;
202
+ }
203
+ /**
204
+ * Load plugins from a directory (for auto-discovery)
205
+ */
206
+ export declare function discoverPlugins(pluginDir: string): Promise<Plugin[]>;
@@ -0,0 +1 @@
1
+ var g=class{description;dependencies;async register(t){}async boot(t){}async shutdown(){}migrations(){return[]}config(){return null}middleware(){return[]}commands(){return[]}routes(){return[]}listeners(){return[]}publishables(){return{}}},d=class{constructor(t){this.app=t}plugins=new Map;registered=new Set;booted=new Set;hooks=new Map;use(t){if(this.plugins.has(t.name))throw new Error(`Plugin "${t.name}" is already registered.`);return this.plugins.set(t.name,t),this}useMany(t){for(let e of t)this.use(e);return this}async boot(){let t=this.resolveDependencyOrder();for(let e of t)await this.registerPlugin(e);for(let e of t)await this.bootPlugin(e);await this.triggerHook("app:boot")}async shutdown(){await this.triggerHook("app:shutdown");let t=[...this.booted].reverse();for(let e of t){let i=this.plugins.get(e);i&&await i.shutdown()}}get(t){return this.plugins.get(t)}has(t){return this.plugins.has(t)}names(){return[...this.plugins.keys()]}all(){return[...this.plugins.values()]}on(t,e){this.hooks.has(t)||this.hooks.set(t,[]),this.hooks.get(t).push(e)}async triggerHook(t,...e){let i=this.hooks.get(t);if(i)for(let n of i)await n(...e)}getRoutes(){let t=[];for(let e of this.plugins.values())t.push(...e.routes());return t}getCommands(){let t=[];for(let e of this.plugins.values())t.push(...e.commands());return t}getMiddleware(){let t=[];for(let e of this.plugins.values())t.push(...e.middleware());return t}getMigrations(){let t=[];for(let e of this.plugins.values())t.push(...e.migrations());return t}getConfigs(){let t=[];for(let e of this.plugins.values()){let i=e.config();i&&t.push(i)}return t}async registerPlugin(t){if(this.registered.has(t))return;let e=this.plugins.get(t);if(!e)throw new Error(`Plugin "${t}" not found.`);let i=e.config();i&&this.app.instance(`config.${i.key}`,i.defaults);for(let{event:n,handler:s}of e.listeners())this.on(n,s);await e.register(this.app),this.registered.add(t)}async bootPlugin(t){if(this.booted.has(t))return;let e=this.plugins.get(t);e&&(await e.boot(this.app),this.booted.add(t))}resolveDependencyOrder(){let t=new Set,e=[],i=(n,s)=>{if(t.has(n))return;if(s.has(n))throw new Error(`Circular plugin dependency detected: ${[...s,n].join(" -> ")}`);s.add(n);let o=this.plugins.get(n);if(o?.dependencies)for(let r of o.dependencies){if(!this.plugins.has(r))throw new Error(`Plugin "${n}" requires "${r}" which is not registered.`);i(r,s)}s.delete(n),t.add(n),e.push(n)};for(let n of this.plugins.keys())i(n,new Set);return e}};async function u(a){let{readdir:t}=await import("fs/promises"),{join:e}=await import("path"),i=[];try{let n=await t(a,{withFileTypes:!0});for(let s of n)if(s.isDirectory())try{let o=await import(e(a,s.name,"index.js")),r=o.default||o[Object.keys(o)[0]];r&&r.prototype instanceof g&&i.push(new r)}catch{}else if(s.isFile()&&(s.name.endsWith(".ts")||s.name.endsWith(".js")))try{let o=await import(e(a,s.name)),r=o.default||o[Object.keys(o)[0]];r&&r.prototype instanceof g&&i.push(new r)}catch{}}catch{}return i}export{g as Plugin,d as PluginManager,u as discoverPlugins};