@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,318 @@
1
+ /**
2
+ * Svelar Broadcasting
3
+ *
4
+ * Real-time event broadcasting with multiple drivers and Laravel-style
5
+ * channel authorization. Supports SSE (zero-dependency), Pusher/Soketi
6
+ * (WebSocket via pusher protocol), and a log driver for development.
7
+ *
8
+ * Channel types:
9
+ * - Public channels: Anyone can subscribe
10
+ * - Private channels: Require authorization (prefixed with 'private-')
11
+ * - Presence channels: Require authorization + track who's online (prefixed with 'presence-')
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { Broadcast } from 'svelar/broadcasting';
16
+ *
17
+ * // Configure
18
+ * Broadcast.configure({
19
+ * default: 'sse',
20
+ * drivers: {
21
+ * sse: { driver: 'sse' },
22
+ * pusher: {
23
+ * driver: 'pusher',
24
+ * key: env('PUSHER_KEY'),
25
+ * secret: env('PUSHER_SECRET'),
26
+ * appId: env('PUSHER_APP_ID'),
27
+ * cluster: env('PUSHER_CLUSTER', 'mt1'),
28
+ * host: env('PUSHER_HOST'), // For Soketi
29
+ * port: env<number>('PUSHER_PORT'), // For Soketi
30
+ * useTLS: env<boolean>('PUSHER_TLS', true),
31
+ * },
32
+ * },
33
+ * });
34
+ *
35
+ * // Register channel authorization
36
+ * Broadcast.channel('private-orders.{orderId}', async (user, { orderId }) => {
37
+ * return user.id === (await Order.findOrFail(orderId)).user_id;
38
+ * });
39
+ *
40
+ * Broadcast.channel('presence-chat.{roomId}', async (user, { roomId }) => {
41
+ * const room = await ChatRoom.findOrFail(roomId);
42
+ * if (!room.hasMember(user.id)) return false;
43
+ * return { id: user.id, name: user.name, avatar: user.avatar };
44
+ * });
45
+ *
46
+ * // Broadcast events from anywhere
47
+ * Broadcast.event('OrderShipped', { orderId: 123 })
48
+ * .on('private-orders.123')
49
+ * .send();
50
+ *
51
+ * // Or the shorthand
52
+ * Broadcast.to('private-orders.123').send('OrderShipped', { orderId: 123 });
53
+ * ```
54
+ */
55
+ export interface BroadcastConfig {
56
+ default: string;
57
+ drivers: Record<string, BroadcastDriverConfig>;
58
+ }
59
+ export type BroadcastDriverConfig = {
60
+ driver: 'sse';
61
+ } | {
62
+ driver: 'log';
63
+ } | {
64
+ driver: 'pusher';
65
+ key: string;
66
+ secret: string;
67
+ appId: string;
68
+ cluster?: string;
69
+ host?: string;
70
+ port?: number;
71
+ useTLS?: boolean;
72
+ };
73
+ export interface BroadcastEvent {
74
+ event: string;
75
+ data: any;
76
+ id?: string;
77
+ }
78
+ /** Channel authorization callback */
79
+ export type ChannelAuthCallback = (user: any, params: Record<string, string>) => Promise<boolean | Record<string, any>> | boolean | Record<string, any>;
80
+ /** Presence channel member info */
81
+ export interface PresenceMember {
82
+ id: string | number;
83
+ [key: string]: any;
84
+ }
85
+ export type ChannelType = 'public' | 'private' | 'presence';
86
+ /**
87
+ * Determine channel type from its name.
88
+ * - 'private-xxx' → private
89
+ * - 'presence-xxx' → presence
90
+ * - anything else → public
91
+ */
92
+ export declare function channelType(name: string): ChannelType;
93
+ declare class SSEChannel {
94
+ private subscribers;
95
+ readonly name: string;
96
+ readonly type: ChannelType;
97
+ constructor(name: string);
98
+ /**
99
+ * Create an SSE streaming response for this channel.
100
+ * For private/presence channels, authorization must be checked BEFORE calling this.
101
+ */
102
+ stream(userId?: string | number, userInfo?: Record<string, any>): Response;
103
+ /**
104
+ * Send an event to all subscribers
105
+ */
106
+ send(event: string, data: any, targetUserId?: string | number): void;
107
+ /** Internal send that excludes a specific subscriber (for join/leave events) */
108
+ private sendInternal;
109
+ /**
110
+ * Send to a specific user in this channel
111
+ */
112
+ toUser(userId: string | number): {
113
+ send: (event: string, data: any) => void;
114
+ };
115
+ /**
116
+ * Get the number of active subscribers
117
+ */
118
+ subscriberCount(): number;
119
+ /**
120
+ * Get presence members (for presence channels)
121
+ */
122
+ getMembers(): PresenceMember[];
123
+ /**
124
+ * Check if a user is present in this channel
125
+ */
126
+ hasMember(userId: string | number): boolean;
127
+ /**
128
+ * Whisper — send a client event to other users (not from server).
129
+ * Useful for typing indicators, cursor positions, etc.
130
+ */
131
+ whisper(event: string, data: any, fromUserId: string | number): void;
132
+ }
133
+ /**
134
+ * Pusher/Soketi broadcast driver.
135
+ * Sends events via HTTP API (compatible with Pusher and Soketi).
136
+ * Clients connect using pusher-js.
137
+ */
138
+ declare class PusherDriver {
139
+ private config;
140
+ constructor(config: Extract<BroadcastDriverConfig, {
141
+ driver: 'pusher';
142
+ }>);
143
+ /**
144
+ * Send an event via the Pusher HTTP API
145
+ */
146
+ send(channels: string | string[], event: string, data: any): Promise<void>;
147
+ /**
148
+ * Generate auth signature for private/presence channel subscriptions.
149
+ * Used in the channel authorization endpoint.
150
+ */
151
+ authenticate(socketId: string, channelName: string, presenceData?: {
152
+ user_id: string | number;
153
+ user_info?: Record<string, any>;
154
+ }): Promise<{
155
+ auth: string;
156
+ channel_data?: string;
157
+ }>;
158
+ /** Get the Pusher app key (needed by clients) */
159
+ get key(): string;
160
+ /** Get connection config for the client */
161
+ clientConfig(): Record<string, any>;
162
+ private md5;
163
+ private hmacSha256;
164
+ }
165
+ declare class BroadcastEventBuilder {
166
+ private manager;
167
+ private eventName;
168
+ private eventData;
169
+ private channels;
170
+ constructor(manager: BroadcastManager, eventName: string, eventData: any);
171
+ /** Specify which channel(s) to broadcast on */
172
+ on(...channels: string[]): BroadcastEventBuilder;
173
+ /** Send the event to all specified channels */
174
+ send(): Promise<void>;
175
+ }
176
+ declare class BroadcastManager {
177
+ private config;
178
+ private sseChannels;
179
+ private channelAuth;
180
+ private pusherDriver;
181
+ /**
182
+ * Configure broadcasting drivers.
183
+ */
184
+ configure(config: BroadcastConfig): void;
185
+ /**
186
+ * Register an authorization callback for a private or presence channel.
187
+ * Pattern supports `{param}` placeholders that are extracted from the channel name.
188
+ *
189
+ * Return `true` for private channels to allow access.
190
+ * Return an object with user info for presence channels (or `false` to deny).
191
+ *
192
+ * @example
193
+ * // Private channel
194
+ * Broadcast.channel('private-orders.{orderId}', async (user, { orderId }) => {
195
+ * const order = await Order.findOrFail(orderId);
196
+ * return order.user_id === user.id;
197
+ * });
198
+ *
199
+ * // Presence channel — return user info to share with other members
200
+ * Broadcast.channel('presence-chat.{roomId}', async (user, { roomId }) => {
201
+ * const room = await ChatRoom.findOrFail(roomId);
202
+ * if (!room.hasMember(user.id)) return false;
203
+ * return { id: user.id, name: user.name, avatar: user.avatar };
204
+ * });
205
+ */
206
+ channel(pattern: string, callback: ChannelAuthCallback): void;
207
+ /**
208
+ * Get or create an SSE channel for subscribing.
209
+ */
210
+ channel(name: string): SSEChannel;
211
+ /**
212
+ * Authorize a user to subscribe to a private or presence channel.
213
+ * Called from your channel authorization endpoint.
214
+ *
215
+ * Returns `false` if denied, `true` for private channels,
216
+ * or a presence member object for presence channels.
217
+ */
218
+ authorize(channelName: string, user: any): Promise<false | true | Record<string, any>>;
219
+ /**
220
+ * Authenticate a Pusher channel subscription.
221
+ * Use this in your channel auth endpoint for Pusher/Soketi.
222
+ *
223
+ * @example
224
+ * // src/routes/api/broadcasting/auth/+server.ts
225
+ * export const POST: RequestHandler = async ({ request, locals }) => {
226
+ * if (!locals.user) return new Response('Unauthorized', { status: 401 });
227
+ *
228
+ * const form = await request.formData();
229
+ * const socketId = form.get('socket_id') as string;
230
+ * const channelName = form.get('channel_name') as string;
231
+ *
232
+ * const auth = await Broadcast.authenticatePusher(channelName, socketId, locals.user);
233
+ * if (!auth) return new Response('Forbidden', { status: 403 });
234
+ *
235
+ * return new Response(JSON.stringify(auth), {
236
+ * headers: { 'Content-Type': 'application/json' },
237
+ * });
238
+ * };
239
+ */
240
+ authenticatePusher(channelName: string, socketId: string, user: any): Promise<{
241
+ auth: string;
242
+ channel_data?: string;
243
+ } | false>;
244
+ /**
245
+ * Create an event builder for fluent broadcasting.
246
+ *
247
+ * @example
248
+ * Broadcast.event('OrderShipped', { orderId: 123 })
249
+ * .on('private-orders.123')
250
+ * .send();
251
+ */
252
+ event(name: string, data: any): BroadcastEventBuilder;
253
+ /**
254
+ * Shorthand — get a sender for a channel.
255
+ *
256
+ * @example
257
+ * Broadcast.to('private-orders.123').send('OrderShipped', { orderId: 123 });
258
+ * Broadcast.to('notifications', userId).send('new-message', { text: 'Hello!' });
259
+ */
260
+ to(channelName: string, userId?: string | number): {
261
+ send: (event: string, data: any) => Promise<void>;
262
+ };
263
+ /**
264
+ * Send an event to a channel. Used internally and by the event builder.
265
+ * Routes to the appropriate driver.
266
+ */
267
+ sendToChannel(channelName: string, event: string, data: any, targetUserId?: string | number): Promise<void>;
268
+ /**
269
+ * Subscribe to an SSE channel. For private/presence channels,
270
+ * call `authorize()` first and check the result before calling `subscribe()`.
271
+ *
272
+ * @example
273
+ * // Public channel
274
+ * return Broadcast.subscribe('updates');
275
+ *
276
+ * // Private channel (check auth first)
277
+ * const allowed = await Broadcast.authorize('private-orders.123', locals.user);
278
+ * if (!allowed) return new Response('Forbidden', { status: 403 });
279
+ * return Broadcast.subscribe('private-orders.123', locals.user.id);
280
+ *
281
+ * // Presence channel (pass user info for member tracking)
282
+ * const presenceInfo = await Broadcast.authorize('presence-chat.1', locals.user);
283
+ * if (!presenceInfo) return new Response('Forbidden', { status: 403 });
284
+ * return Broadcast.subscribe('presence-chat.1', locals.user.id, presenceInfo);
285
+ */
286
+ subscribe(channelName: string, userId?: string | number, userInfo?: Record<string, any>): Response;
287
+ /**
288
+ * Get members of a presence channel (SSE driver only)
289
+ */
290
+ members(channelName: string): PresenceMember[];
291
+ /**
292
+ * Get the Pusher driver instance (for advanced usage)
293
+ */
294
+ pusher(): PusherDriver;
295
+ /**
296
+ * Get all active channel names
297
+ */
298
+ activeChannels(): string[];
299
+ /**
300
+ * Get total subscriber count across all SSE channels
301
+ */
302
+ totalSubscribers(): number;
303
+ /**
304
+ * Remove empty SSE channels (cleanup)
305
+ */
306
+ prune(): void;
307
+ /**
308
+ * Match a channel pattern like 'private-orders.{orderId}'
309
+ * against a channel name like 'private-orders.123'.
310
+ * Returns extracted params or null if no match.
311
+ */
312
+ private matchPattern;
313
+ }
314
+ /**
315
+ * Global Broadcast singleton
316
+ */
317
+ export declare const Broadcast: BroadcastManager;
318
+ export {};
@@ -0,0 +1,20 @@
1
+ function b(c,e){let n=Symbol.for(c),t=globalThis;return t[n]||(t[n]=e()),t[n]}function d(c){return c.startsWith("private-")?"private":c.startsWith("presence-")?"presence":"public"}var l=class{subscribers=[];name;type;constructor(e){this.name=e,this.type=d(e)}stream(e,n){let t=this,i=new ReadableStream({start(r){let s={channel:t.name};t.type==="presence"&&(s.members=t.getMembers());let o=`event: connected
2
+ data: ${JSON.stringify(s)}
3
+ id: ${Date.now()}
4
+
5
+ `;r.enqueue(new TextEncoder().encode(o));let a={controller:r,userId:e,userInfo:n};t.subscribers.push(a),t.type==="presence"&&e!==void 0&&t.sendInternal("member:joined",{id:e,...n},a)},cancel(){let r=t.subscribers.findIndex(o=>o.controller===this._controller),s=t.subscribers.length;t.subscribers=t.subscribers.filter(o=>{try{return o.controller.enqueue(new TextEncoder().encode(`:
6
+
7
+ `)),!0}catch{return!1}}),t.type==="presence"&&e!==void 0&&t.subscribers.length<s&&t.sendInternal("member:left",{id:e,...n})}});return new Response(i,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"}})}send(e,n,t){let i=`event: ${e}
8
+ data: ${JSON.stringify(n)}
9
+ id: ${Date.now()}
10
+
11
+ `,r=new TextEncoder().encode(i);for(let s of this.subscribers)if(!(t!==void 0&&s.userId!==t))try{s.controller.enqueue(r)}catch{}}sendInternal(e,n,t){let i=`event: ${e}
12
+ data: ${JSON.stringify(n)}
13
+ id: ${Date.now()}
14
+
15
+ `,r=new TextEncoder().encode(i);for(let s of this.subscribers)if(s!==t)try{s.controller.enqueue(r)}catch{}}toUser(e){return{send:(n,t)=>this.send(n,t,e)}}subscriberCount(){return this.subscribers.length}getMembers(){return this.type!=="presence"?[]:this.subscribers.filter(e=>e.userId!==void 0).map(e=>({id:e.userId,...e.userInfo??{}}))}hasMember(e){return this.subscribers.some(n=>n.userId===e)}whisper(e,n,t){let i=`event: client-${e}
16
+ data: ${JSON.stringify(n)}
17
+ id: ${Date.now()}
18
+
19
+ `,r=new TextEncoder().encode(i);for(let s of this.subscribers)if(s.userId!==t)try{s.controller.enqueue(r)}catch{}}},h=class{config;constructor(e){this.config=e}async send(e,n,t){let i=Array.isArray(e)?e:[e],r=JSON.stringify({name:n,channels:i,data:JSON.stringify(t)}),s=Math.floor(Date.now()/1e3).toString(),o=await this.md5(r),a=["POST",`/apps/${this.config.appId}/events`,[`auth_key=${this.config.key}`,`auth_timestamp=${s}`,"auth_version=1.0",`body_md5=${o}`].join("&")].join(`
20
+ `),u=await this.hmacSha256(this.config.secret,a),y=this.config.useTLS!==!1?"https":"http",v=this.config.host??`api-${this.config.cluster??"mt1"}.pusher.com`,m=this.config.port??(this.config.useTLS!==!1?443:80),w=`${y}://${v}:${m}/apps/${this.config.appId}/events?auth_key=${this.config.key}&auth_timestamp=${s}&auth_version=1.0&body_md5=${o}&auth_signature=${u}`,g=await fetch(w,{method:"POST",headers:{"Content-Type":"application/json"},body:r});if(!g.ok){let C=await g.text();throw new Error(`Pusher API error (${g.status}): ${C}`)}}async authenticate(e,n,t){let i=`${e}:${n}`,r;t&&(r=JSON.stringify(t),i+=`:${r}`);let s=await this.hmacSha256(this.config.secret,i),o=`${this.config.key}:${s}`;return r?{auth:o,channel_data:r}:{auth:o}}get key(){return this.config.key}clientConfig(){let e={key:this.config.key,cluster:this.config.cluster??"mt1"};return this.config.host&&(e.wsHost=this.config.host,e.wsPort=this.config.port??6001,e.wssPort=this.config.port??6001,e.forceTLS=this.config.useTLS??!1,e.enabledTransports=["ws","wss"],e.disableStats=!0),e}async md5(e){let{createHash:n}=await import("crypto");return n("md5").update(e).digest("hex")}async hmacSha256(e,n){let{createHmac:t}=await import("crypto");return t("sha256",e).update(n).digest("hex")}},f=class{constructor(e,n,t){this.manager=e;this.eventName=n;this.eventData=t}channels=[];on(...e){return this.channels.push(...e),this}async send(){for(let e of this.channels)await this.manager.sendToChannel(e,this.eventName,this.eventData)}},p=class{config={default:"sse",drivers:{sse:{driver:"sse"}}};sseChannels=new Map;channelAuth=new Map;pusherDriver=null;configure(e){this.config=e;let n=Object.values(e.drivers).find(t=>t.driver==="pusher");n&&n.driver==="pusher"&&(this.pusherDriver=new h(n))}channel(e,n){if(n){this.channelAuth.set(e,n);return}return this.sseChannels.has(e)||this.sseChannels.set(e,new l(e)),this.sseChannels.get(e)}async authorize(e,n){if(d(e)==="public")return!0;for(let[i,r]of this.channelAuth){let s=this.matchPattern(i,e);if(s!==null)return await r(n,s)}return!1}async authenticatePusher(e,n,t){if(!this.pusherDriver)throw new Error("Pusher driver is not configured. Call Broadcast.configure() first.");let i=d(e);if(i==="public")return!1;let r=await this.authorize(e,t);if(r===!1)return!1;if(i==="presence"){let s=typeof r=="object"?{user_id:r.id??t.id,user_info:r}:{user_id:t.id,user_info:{id:t.id}};return this.pusherDriver.authenticate(n,e,s)}return this.pusherDriver.authenticate(n,e)}event(e,n){return new f(this,e,n)}to(e,n){return{send:async(t,i)=>{await this.sendToChannel(e,t,i,n)}}}async sendToChannel(e,n,t,i){let r=this.config.drivers[this.config.default];switch(r?.driver){case"pusher":this.pusherDriver||(this.pusherDriver=new h(r)),await this.pusherDriver.send(e,n,t);break;case"log":console.log(`[Broadcast] ${e} \u2192 ${n}:`,JSON.stringify(t));break;default:for(let[,s]of this.sseChannels)s.name===e&&s.send(n,t,i);break}}subscribe(e,n,t){return this.channel(e).stream(n,t)}members(e){let n=this.sseChannels.get(e);return n?n.getMembers():[]}pusher(){if(!this.pusherDriver)throw new Error("Pusher driver is not configured.");return this.pusherDriver}activeChannels(){return[...new Set([...this.sseChannels.values()].map(e=>e.name))]}totalSubscribers(){let e=0;for(let n of this.sseChannels.values())e+=n.subscriberCount();return e}prune(){for(let[e,n]of this.sseChannels)n.subscriberCount()===0&&this.sseChannels.delete(e)}matchPattern(e,n){let t=[],i=e.replace(/[.*+?^${}()|[\]\\]/g,a=>a==="{"||a==="}"?a:`\\${a}`).replace(/\\\{(\w+)\\\}/g,(a,u)=>(t.push(u),"([^.]+)")).replace(/\{(\w+)\}/g,(a,u)=>(t.push(u),"([^.]+)")),r=new RegExp(`^${i}$`),s=n.match(r);if(!s)return null;let o={};for(let a=0;a<t.length;a++)o[t[a]]=s[a+1];return o}},T=b("svelar.broadcast",()=>new p);export{T as Broadcast,d as channelType};
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Svelar Cache
3
+ *
4
+ * Laravel-inspired cache with memory, file, and Redis drivers.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { Cache } from 'svelar/cache';
9
+ *
10
+ * Cache.configure({ default: 'memory', stores: { memory: { driver: 'memory' } } });
11
+ *
12
+ * await Cache.put('key', 'value', 3600); // 1 hour TTL
13
+ * const value = await Cache.get('key', 'default');
14
+ * await Cache.forget('key');
15
+ *
16
+ * // Remember pattern (fetch or compute)
17
+ * const users = await Cache.remember('all-users', 600, async () => {
18
+ * return await User.all();
19
+ * });
20
+ * ```
21
+ */
22
+ export type CacheDriver = 'memory' | 'file' | 'redis' | 'null';
23
+ export interface CacheStoreConfig {
24
+ driver: CacheDriver;
25
+ /** Default TTL in seconds */
26
+ ttl?: number;
27
+ /** File cache: directory path */
28
+ path?: string;
29
+ /** Redis cache: connection URL or config */
30
+ url?: string;
31
+ /** Key prefix */
32
+ prefix?: string;
33
+ }
34
+ export interface CacheConfig {
35
+ default: string;
36
+ stores: Record<string, CacheStoreConfig>;
37
+ }
38
+ interface CacheStore {
39
+ get<T = any>(key: string): Promise<T | null>;
40
+ put(key: string, value: any, ttl?: number): Promise<void>;
41
+ forget(key: string): Promise<boolean>;
42
+ flush(): Promise<void>;
43
+ has(key: string): Promise<boolean>;
44
+ increment(key: string, amount?: number): Promise<number>;
45
+ decrement(key: string, amount?: number): Promise<number>;
46
+ }
47
+ declare class CacheManager {
48
+ private config;
49
+ private stores;
50
+ configure(config: CacheConfig): void;
51
+ store(name?: string): CacheStore;
52
+ get<T = any>(key: string, defaultValue?: T): Promise<T | null>;
53
+ put(key: string, value: any, ttl?: number): Promise<void>;
54
+ forget(key: string): Promise<boolean>;
55
+ flush(): Promise<void>;
56
+ has(key: string): Promise<boolean>;
57
+ increment(key: string, amount?: number): Promise<number>;
58
+ decrement(key: string, amount?: number): Promise<number>;
59
+ /**
60
+ * Get or compute a cached value
61
+ */
62
+ remember<T>(key: string, ttl: number, callback: () => T | Promise<T>): Promise<T>;
63
+ /**
64
+ * Get or compute, caching forever
65
+ */
66
+ rememberForever<T>(key: string, callback: () => T | Promise<T>): Promise<T>;
67
+ /**
68
+ * Get and delete
69
+ */
70
+ pull<T = any>(key: string, defaultValue?: T): Promise<T | null>;
71
+ private createStore;
72
+ }
73
+ /**
74
+ * Global Cache singleton
75
+ */
76
+ export declare const Cache: CacheManager;
77
+ export type { CacheStore };
@@ -0,0 +1 @@
1
+ import{readFile as g,writeFile as f,unlink as h,mkdir as l}from"fs/promises";import{join as y,dirname as p}from"path";import{createHash as d}from"crypto";function m(i,e){let r=Symbol.for(i),t=globalThis;return t[r]||(t[r]=e()),t[r]}var a=class{store=new Map;async get(e){let r=this.store.get(e);return r?r.expiresAt&&Date.now()>r.expiresAt?(this.store.delete(e),null):r.value:null}async put(e,r,t){this.store.set(e,{value:r,expiresAt:t?Date.now()+t*1e3:null})}async forget(e){return this.store.delete(e)}async flush(){this.store.clear()}async has(e){let r=this.store.get(e);return r?r.expiresAt&&Date.now()>r.expiresAt?(this.store.delete(e),!1):!0:!1}async increment(e,r=1){let s=(await this.get(e)??0)+r,n=this.store.get(e);return await this.put(e,s,n?.expiresAt?Math.ceil((n.expiresAt-Date.now())/1e3):void 0),s}async decrement(e,r=1){return this.increment(e,-r)}},o=class{basePath;constructor(e){this.basePath=e.path??"storage/cache"}filePath(e){let r=d("md5").update(e).digest("hex");return y(this.basePath,r.slice(0,2),r)}async get(e){let r=this.filePath(e);try{let t=await g(r,"utf-8"),s=JSON.parse(t);return s.expiresAt&&Date.now()>s.expiresAt?(await h(r).catch(()=>{}),null):s.value}catch{return null}}async put(e,r,t){let s=this.filePath(e),n={value:r,expiresAt:t?Date.now()+t*1e3:null};await l(p(s),{recursive:!0}),await f(s,JSON.stringify(n))}async forget(e){try{return await h(this.filePath(e)),!0}catch{return!1}}async flush(){let{rm:e}=await import("fs/promises");await e(this.basePath,{recursive:!0,force:!0}),await l(this.basePath,{recursive:!0})}async has(e){return await this.get(e)!==null}async increment(e,r=1){let s=(await this.get(e)??0)+r;return await this.put(e,s),s}async decrement(e,r=1){return this.increment(e,-r)}},c=class{async get(){return null}async put(){}async forget(){return!0}async flush(){}async has(){return!1}async increment(){return 0}async decrement(){return 0}},u=class{config={default:"memory",stores:{memory:{driver:"memory"}}};stores=new Map;configure(e){this.config=e,this.stores.clear()}store(e){let r=e??this.config.default;if(this.stores.has(r))return this.stores.get(r);let t=this.config.stores[r];if(!t)throw new Error(`Cache store "${r}" is not defined.`);let s=this.createStore(t);return this.stores.set(r,s),s}async get(e,r){let t=this.store();return await t.has(e)?t.get(e):r??null}async put(e,r,t){return this.store().put(e,r,t??this.config.stores[this.config.default]?.ttl)}async forget(e){return this.store().forget(e)}async flush(){return this.store().flush()}async has(e){return this.store().has(e)}async increment(e,r){return this.store().increment(e,r)}async decrement(e,r){return this.store().decrement(e,r)}async remember(e,r,t){let s=await this.store().get(e);if(s!==null)return s;let n=await t();return await this.store().put(e,n,r),n}async rememberForever(e,r){let t=await this.store().get(e);if(t!==null)return t;let s=await r();return await this.store().put(e,s),s}async pull(e,r){let t=await this.get(e,r);return await this.forget(e),t}createStore(e){switch(e.driver){case"memory":return new a;case"file":return new o(e);case"null":return new c;case"redis":throw new Error("Redis cache requires ioredis. Install: npm install ioredis");default:throw new Error(`Unknown cache driver: ${e.driver}`)}}},x=m("svelar.cache",()=>new u);export{x as Cache};
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Svelar CLI Runner
3
+ */
4
+ import { Command } from './Command.js';
5
+ export declare class Cli {
6
+ private commands;
7
+ private version;
8
+ constructor(version?: string);
9
+ /**
10
+ * Register a command
11
+ */
12
+ register(CommandClass: new () => Command): this;
13
+ /**
14
+ * Register a command instance
15
+ */
16
+ add(command: Command): this;
17
+ /**
18
+ * Execute CLI with process arguments
19
+ */
20
+ run(argv?: string[]): Promise<void>;
21
+ private parseArgs;
22
+ private showHelp;
23
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Svelar CLI Command Base
3
+ */
4
+ export interface CommandFlag {
5
+ name: string;
6
+ alias?: string;
7
+ description: string;
8
+ type: 'boolean' | 'string';
9
+ default?: any;
10
+ }
11
+ export declare abstract class Command {
12
+ /** Command name (e.g. 'make:model') */
13
+ abstract name: string;
14
+ /** Description shown in help */
15
+ abstract description: string;
16
+ /** Positional arguments description */
17
+ arguments: string[];
18
+ /** Available flags */
19
+ flags: CommandFlag[];
20
+ /** Execute the command */
21
+ abstract handle(args: string[], flags: Record<string, any>): Promise<void>;
22
+ /**
23
+ * Bootstrap database configuration for CLI commands.
24
+ *
25
+ * Reads a `svelar.database.json` file if present, or uses env vars
26
+ * and sensible defaults (SQLite with `database.db`).
27
+ */
28
+ protected bootstrap(): Promise<void>;
29
+ protected log(message: string): void;
30
+ protected info(message: string): void;
31
+ protected success(message: string): void;
32
+ protected warn(message: string): void;
33
+ protected error(message: string): void;
34
+ protected table(headers: string[], rows: string[][]): void;
35
+ protected newLine(): void;
36
+ }
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Svelar CLI — Laravel-like Artisan for SvelteKit
4
+ *
5
+ * Re-launches with --import ts-resolver.mjs so that dynamic imports of
6
+ * user .ts files (tasks, commands, seeders) resolve .js → .ts correctly.
7
+ */
8
+ export {};