@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,135 @@
1
+ /**
2
+ * Svelar Hooks
3
+ *
4
+ * Integration with SvelteKit's hooks system.
5
+ * Provides a Laravel-like middleware pipeline for all incoming requests.
6
+ *
7
+ * @module svelar/hooks
8
+ *
9
+ * @example Simple (auto-wired defaults)
10
+ * ```ts
11
+ * // src/hooks.server.ts
12
+ * import { createSvelarApp } from 'svelar/hooks';
13
+ * import { auth } from './app';
14
+ *
15
+ * export const { handle, handleError } = createSvelarApp({ auth });
16
+ * ```
17
+ *
18
+ * @example Advanced (manual pipeline)
19
+ * ```ts
20
+ * import { createSvelarHooks } from 'svelar/hooks';
21
+ * import { CorsMiddleware } from 'svelar/middleware';
22
+ *
23
+ * export const handle = createSvelarHooks({
24
+ * middleware: [CorsMiddleware],
25
+ * });
26
+ * ```
27
+ */
28
+ import { Middleware, type MiddlewareHandler } from '../middleware/Middleware.js';
29
+ import { Application } from '../container/Application.js';
30
+ import { type SessionStore } from '../session/Session.js';
31
+ import { type AuthManager } from '../auth/Auth.js';
32
+ import { type ErrorHandlerConfig } from '../errors/Handler.js';
33
+ export interface SvelarHooksConfig {
34
+ /** Global middleware to run on every request */
35
+ middleware?: Array<(new () => Middleware) | Middleware | MiddlewareHandler>;
36
+ /** Named middleware for per-route usage */
37
+ namedMiddleware?: Record<string, (new () => Middleware) | Middleware | MiddlewareHandler>;
38
+ /** Error handler */
39
+ onError?: (error: unknown, event: any) => void | Response | Promise<void | Response>;
40
+ /** Application instance (optional — for DI integration) */
41
+ app?: Application;
42
+ }
43
+ export interface SvelarAppConfig {
44
+ /** Auth manager instance */
45
+ auth?: AuthManager;
46
+ /** Session secret key (defaults to APP_KEY env var) */
47
+ secret?: string;
48
+ /** Session store (default: MemorySessionStore — lost on restart) */
49
+ sessionStore?: SessionStore;
50
+ /** Session lifetime in seconds (default: 86400 = 24h) */
51
+ sessionLifetime?: number;
52
+ /** Rate limit: max requests per window (default: 100) */
53
+ rateLimit?: number;
54
+ /** Rate limit: window in ms (default: 60000 = 1min) */
55
+ rateLimitWindow?: number;
56
+ /** CSRF: paths to protect (default: ['/api/']) */
57
+ csrfPaths?: string[];
58
+ /** CSRF: paths to exclude (default: ['/api/webhooks']) */
59
+ csrfExcludePaths?: string[];
60
+ /** Auth throttle: max login attempts (default: 5) */
61
+ authThrottleAttempts?: number;
62
+ /** Auth throttle: decay in minutes (default: 1) */
63
+ authThrottleDecay?: number;
64
+ /** Enable debug error output (default: auto from NODE_ENV) */
65
+ debug?: boolean;
66
+ /** Additional global middleware to append */
67
+ middleware?: Array<(new () => Middleware) | Middleware | MiddlewareHandler>;
68
+ /** Named middleware for per-route usage */
69
+ namedMiddleware?: Record<string, (new () => Middleware) | Middleware | MiddlewareHandler>;
70
+ /** i18n configuration — if provided, auto-wires paraglide */
71
+ i18n?: {
72
+ paraglideMiddleware: (request: Request, callback: (args: {
73
+ request: Request;
74
+ locale: string;
75
+ }) => Response | Promise<Response>) => Response | Promise<Response>;
76
+ getTextDirection?: (locale: string) => string;
77
+ };
78
+ /** Error handler config overrides */
79
+ errorConfig?: Partial<ErrorHandlerConfig>;
80
+ }
81
+ /**
82
+ * Creates a fully-wired SvelteKit hooks setup with sensible defaults.
83
+ * One-liner setup inspired by Laravel's bootstrap.
84
+ *
85
+ * Returns `{ handle, handleError }` ready to export from hooks.server.ts.
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * import { createSvelarApp } from 'svelar/hooks';
90
+ * import { auth } from './app';
91
+ *
92
+ * export const { handle, handleError } = createSvelarApp({ auth });
93
+ * ```
94
+ *
95
+ * @example With i18n
96
+ * ```ts
97
+ * import { createSvelarApp } from 'svelar/hooks';
98
+ * import { auth } from './app';
99
+ * import { paraglideMiddleware } from '$lib/paraglide/server';
100
+ * import { getTextDirection } from '$lib/paraglide/runtime';
101
+ *
102
+ * export const { handle, handleError } = createSvelarApp({
103
+ * auth,
104
+ * i18n: { paraglideMiddleware, getTextDirection },
105
+ * });
106
+ * ```
107
+ */
108
+ export declare function createSvelarApp(appConfig?: SvelarAppConfig): {
109
+ handle: any;
110
+ handleError: (input: {
111
+ error: unknown;
112
+ event: any;
113
+ status: number;
114
+ message: string;
115
+ }) => any;
116
+ };
117
+ /**
118
+ * Creates a SvelteKit `handle` hook with Svelar middleware pipeline.
119
+ * For advanced use when you want full control over the middleware stack.
120
+ */
121
+ export declare function createSvelarHooks(hookConfig?: SvelarHooksConfig): ({ event, resolve, }: {
122
+ event: any;
123
+ resolve: (event: any) => Promise<Response>;
124
+ }) => Promise<Response>;
125
+ /**
126
+ * Sequence multiple SvelteKit handle hooks together.
127
+ * Similar to SvelteKit's `sequence` helper.
128
+ */
129
+ export declare function sequence(...handlers: Array<(opts: {
130
+ event: any;
131
+ resolve: (event: any) => Promise<Response>;
132
+ }) => Promise<Response>>): ({ event, resolve, }: {
133
+ event: any;
134
+ resolve: (event: any) => Promise<Response>;
135
+ }) => Promise<Response>;
@@ -0,0 +1,5 @@
1
+ var se=(a,e)=>()=>(a&&(e=a(a=0)),e);function X(a,e){let t=Symbol.for(a),n=globalThis;return n[t]||(n[t]=e()),n[t]}var B=se(()=>{"use strict"});var l=class{},m=class{middleware=[];namedMiddleware=new Map;use(e){return typeof e=="function"&&"prototype"in e&&typeof e.prototype?.handle=="function"?this.middleware.push(new e):this.middleware.push(e),this}register(e,t){return typeof t=="function"&&"prototype"in t&&typeof t.prototype?.handle=="function"?this.namedMiddleware.set(e,new t):this.namedMiddleware.set(e,t),this}get(e){return this.namedMiddleware.get(e)}async execute(e,t,n){let s=[...this.middleware];if(n)for(let i of n){let o=this.namedMiddleware.get(i);o&&s.push(o)}let r=t;for(let i=s.length-1;i>=0;i--){let o=s[i],c=r;typeof o.handle=="function"?r=()=>o.handle(e,c):r=()=>o(e,c)}return r()}count(){return this.middleware.length}};var w=class extends l{requests=new Map;maxRequests;windowMs;constructor(e={}){super(),this.maxRequests=e.maxRequests??60,this.windowMs=e.windowMs??6e4}async handle(e,t){let n=e.event.request.headers.get("x-forwarded-for")??e.event.getClientAddress?.()??"unknown",s=Date.now(),r=this.requests.get(n);if(r&&s<r.resetAt){if(r.count>=this.maxRequests)return new Response(JSON.stringify({error:"Too many requests"}),{status:429,headers:{"Content-Type":"application/json","Retry-After":String(Math.ceil((r.resetAt-s)/1e3))}});r.count++}else this.requests.set(n,{count:1,resetAt:s+this.windowMs});return t()}};var y=class extends l{cookieName;headerName;fieldName;excludePaths;onlyPaths;constructor(e={}){super(),this.cookieName=e.cookieName??"XSRF-TOKEN",this.headerName=e.headerName??"X-CSRF-Token",this.fieldName=e.fieldName??"_csrf",this.excludePaths=e.excludePaths??[],this.onlyPaths=e.onlyPaths??null}async handle(e,t){let{event:n}=e,s=n.request.method.toUpperCase();if(["GET","HEAD","OPTIONS"].includes(s))return this.setTokenAndContinue(e,t);if((n.request.headers.get("authorization")??"").startsWith("Bearer "))return t();let i=n.url.pathname;if(this.onlyPaths&&!this.onlyPaths.some(u=>i.startsWith(u)))return this.setTokenAndContinue(e,t);if(this.excludePaths.some(u=>i.startsWith(u)))return t();let o=this.getCookieToken(n),c=n.request.headers.get(this.headerName)??await this.getBodyToken(n);return!o||!c||!this.timingSafeEqual(o,c)?new Response(JSON.stringify({message:"CSRF token mismatch"}),{status:419,headers:{"Content-Type":"application/json"}}):t()}async setTokenAndContinue(e,t){let n=await t();if(!(n instanceof Response))return n;let r=this.getCookieToken(e.event)||this.generateToken();return n.headers.append("Set-Cookie",`${this.cookieName}=${r}; Path=/; SameSite=Lax`),n}getCookieToken(e){let n=(e.request.headers.get("cookie")??"").match(new RegExp(`${this.cookieName}=([^;]+)`));return n?n[1]:null}async getBodyToken(e){try{let t=e.request.headers.get("content-type")??"";if(t.includes("application/x-www-form-urlencoded")||t.includes("multipart/form-data"))return(await e.request.clone().formData()).get(this.fieldName);if(t.includes("application/json"))return(await e.request.clone().json())[this.fieldName]??null}catch{}return null}generateToken(){let e=new Uint8Array(32);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}timingSafeEqual(e,t){if(e.length!==t.length)return!1;let n=new TextEncoder,s=n.encode(e),r=n.encode(t),i=0;for(let o=0;o<s.length;o++)i|=s[o]^r[o];return i===0}},v=class extends l{allowedOrigins;constructor(e={}){super(),this.allowedOrigins=new Set(e.allowedOrigins??[])}async handle(e,t){let{event:n}=e,s=n.request.method.toUpperCase();if(["GET","HEAD","OPTIONS"].includes(s)||(n.request.headers.get("authorization")??"").startsWith("Bearer "))return t();let i=n.request.headers.get("origin");if(!i)return t();let o=n.url.origin;return i===o||this.allowedOrigins.has(i)?t():new Response(JSON.stringify({message:"Cross-origin request blocked"}),{status:403,headers:{"Content-Type":"application/json"}})}};var E=class extends l{attempts=new Map;maxAttempts;decayMinutes;constructor(e={}){super(),this.maxAttempts=e.maxAttempts??5,this.decayMinutes=e.decayMinutes??1}async handle(e,t){let s=`${e.event.request.headers.get("x-forwarded-for")??e.event.getClientAddress?.()??"unknown"}:${e.event.url.pathname}`,r=Date.now(),i=this.attempts.get(s);if(i){if(r<i.blockedUntil){let c=Math.ceil((i.blockedUntil-r)/1e3);return new Response(JSON.stringify({message:"Too many attempts. Please try again later.",retry_after:c}),{status:429,headers:{"Content-Type":"application/json","Retry-After":String(c)}})}if(i.count>=this.maxAttempts){i.blockedUntil=r+this.decayMinutes*6e4,i.count=0;let c=this.decayMinutes*60;return new Response(JSON.stringify({message:"Too many attempts. Please try again later.",retry_after:c}),{status:429,headers:{"Content-Type":"application/json","Retry-After":String(c)}})}}let o=await t();if(o instanceof Response&&o.status>=400&&o.status<500){let c=this.attempts.get(s)??{count:0,blockedUntil:0};if(c.count++,this.attempts.set(s,c),this.attempts.size>1e4)for(let[u,N]of this.attempts)r>N.blockedUntil+this.decayMinutes*6e4*2&&this.attempts.delete(u)}return o}};import{randomBytes as re,createHmac as V,timingSafeEqual as ie}from"crypto";import{promises as me}from"fs";import{join as ye}from"path";var x=class a{constructor(e,t){this.id=e;t&&(this.data={...t},this.data._flash&&(this.previousFlashData=this.data._flash,delete this.data._flash))}data={};dirty=!1;flashData={};previousFlashData={};get(e,t){return e in this.flashData?this.flashData[e]:e in this.previousFlashData?this.previousFlashData[e]:e in this.data?this.data[e]:t}set(e,t){this.data[e]=t,this.dirty=!0}has(e){return e in this.data||e in this.flashData||e in this.previousFlashData}forget(e){delete this.data[e],this.dirty=!0}flush(){this.data={},this.dirty=!0}flash(e,t){this.flashData[e]=t,this.dirty=!0}all(){return{...this.data,...this.previousFlashData,...this.flashData}}isDirty(){return this.dirty||Object.keys(this.flashData).length>0}toPersist(){let e={...this.data};return Object.keys(this.flashData).length>0&&(e._flash=this.flashData),e}regenerateId(){let e=this.id,t=a.generateId();this.id=t,this.dirty=!0;let n=p.get(e);return n instanceof g&&n.markOldSessionId(e),p.delete(e),t}static generateId(){return re(32).toString("hex")}},p=new Map,g=class{sessions=new Map;oldSessionIds=new Set;async read(e){if(this.oldSessionIds.has(e))return null;let t=this.sessions.get(e);return t?Date.now()>t.expiresAt?(this.sessions.delete(e),null):t.data:null}async write(e,t,n){this.sessions.set(e,{data:t,expiresAt:Date.now()+n*1e3}),p.set(e,this)}async destroy(e){this.sessions.delete(e),p.delete(e)}async gc(e){let t=Date.now();for(let[n,s]of this.sessions)t>s.expiresAt&&(this.sessions.delete(n),p.delete(n))}markOldSessionId(e){this.oldSessionIds.add(e),this.sessions.delete(e)}};var T=class extends l{config;constructor(e){super(),this.config={cookieName:"svelar_session",lifetime:7200,secret:process.env.APP_KEY??(()=>{throw new Error("APP_KEY is not set. Set it in your .env file before using sessions.")})(),path:"/",domain:"",secure:process.env.NODE_ENV==="production",httpOnly:!0,sameSite:"lax",...e}}async handle(e,t){let n=e.event.request.headers.get("cookie")??"",s=this.getSessionIdFromCookie(n),r=null;if(s){let c=this.verifySignedId(s);c?(r=await this.config.store.read(c),s=c):s=null}s||(s=x.generateId());let i=new x(s,r??{});e.event.locals.session=i,e.locals.session=i;let o=await t();if(i.isDirty()&&await this.config.store.write(i.id,i.toPersist(),this.config.lifetime),o instanceof Response){let c=this.signId(i.id),u=this.buildCookieString(c);o.headers.append("Set-Cookie",u)}return o}getSessionIdFromCookie(e){let t=e.split(";").map(n=>n.trim());for(let n of t){let[s,...r]=n.split("=");if(s===this.config.cookieName)return decodeURIComponent(r.join("="))}return null}signId(e){let t=V("sha256",this.config.secret).update(e).digest("base64url");return`${e}.${t}`}verifySignedId(e){let t=e.lastIndexOf(".");if(t===-1)return null;let n=e.slice(0,t),s=e.slice(t+1),r=V("sha256",this.config.secret).update(n).digest("base64url");if(s.length!==r.length)return null;let i=Buffer.from(s),o=Buffer.from(r);if(i.length!==o.length)return null;try{if(ie(i,o))return n}catch{}return null}buildCookieString(e){let t=[`${this.config.cookieName}=${encodeURIComponent(e)}`];return t.push(`Path=${this.config.path}`),t.push(`Max-Age=${this.config.lifetime}`),this.config.domain&&t.push(`Domain=${this.config.domain}`),this.config.secure&&t.push("Secure"),this.config.httpOnly&&t.push("HttpOnly"),t.push(`SameSite=${this.config.sameSite}`),t.join("; ")}};import{createHmac as Te,randomBytes as be}from"crypto";var b=class extends l{constructor(t){super();this.authManager=t}async handle(t,n){let s=null;if(t.event.locals.session&&(s=await this.authManager.resolveFromSession(t.event.locals.session)),!s){let r=t.event.request.headers.get("authorization");if(r?.startsWith("Bearer ")){let i=r.slice(7);try{s=await this.authManager.resolveFromToken(i)}catch{s=await this.authManager.resolveFromApiToken(i)}}}return t.event.locals.user=s,t.event.locals.auth=this.authManager,n()}};B();import{appendFile as ae,mkdir as oe}from"fs/promises";import{dirname as ce}from"path";var S={debug:0,info:1,warn:2,error:3,fatal:4},f=class{minLevel;format;constructor(e){this.minLevel=e.level??"debug",this.format=e.format??"text"}write(e){if(S[e.level]<S[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]??"",r=e.level.toUpperCase().padEnd(5),i=Object.keys(e.context).length>0?` ${JSON.stringify(e.context)}`:"",o=e.level==="error"||e.level==="fatal"?"error":"log";console[o](`${s}[${e.timestamp}] ${r}${n} ${e.message}${i}`)}},D=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(S[e.level]<S[this.minLevel])return;this.initialized||(await oe(ce(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 ae(this.path,t)}},M=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)}}},_=class{minLevel="debug";write(){}},I=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 U(this.resolveChannel(e))}debug(e,t={}){this.writeToDefault({level:"debug",message:e,context:t,timestamp:d()})}info(e,t={}){this.writeToDefault({level:"info",message:e,context:t,timestamp:d()})}warn(e,t={}){this.writeToDefault({level:"warn",message:e,context:t,timestamp:d()})}error(e,t={}){this.writeToDefault({level:"error",message:e,context:t,timestamp:d()})}fatal(e,t={}){this.writeToDefault({level:"fatal",message:e,context:t,timestamp:d()})}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 f({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 f(e);case"file":return new D(e);case"stack":return new M(e,t=>this.resolveChannel(t));case"null":return new _;default:return new f(e)}}},U=class{constructor(e){this.channel=e}debug(e,t={}){this.channel.write({level:"debug",message:e,context:t,timestamp:d()})}info(e,t={}){this.channel.write({level:"info",message:e,context:t,timestamp:d()})}warn(e,t={}){this.channel.write({level:"warn",message:e,context:t,timestamp:d()})}error(e,t={}){this.channel.write({level:"error",message:e,context:t,timestamp:d()})}fatal(e,t={}){this.channel.write({level:"fatal",message:e,context:t,timestamp:d()})}};function d(){return new Date().toISOString()}var Y=X("svelar.log",()=>new I);var h=class extends Error{constructor(t,n,s){super(n);this.statusCode=t;this.details=s;this.name="HttpError"}},$=class extends h{constructor(e="The requested resource was not found"){super(404,e),this.name="NotFoundError"}},H=class extends h{constructor(e="Unauthenticated"){super(401,e),this.name="UnauthorizedError"}},F=class extends h{constructor(e="You do not have permission to perform this action"){super(403,e),this.name="ForbiddenError"}},R=class extends h{constructor(t,n="The given data was invalid"){super(422,n,{errors:t});this.errors=t;this.name="ValidationError"}};var C=class{config;constructor(e={}){this.config={debug:process.env.NODE_ENV!=="production",dontReport:[R,$,H,F],...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 r=e instanceof Error?e:new Error(String(e));return this.reportError(r,t),r instanceof h?{message:r.message,status:r.statusCode,...r.details??{},...this.config.debug?{stack:r.stack}:{}}:{message:this.config.debug?r.message:"An unexpected error occurred",status:n,...this.config.debug?{stack:r.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(Y.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 h){let n={message:e.message};return e instanceof R&&(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 $e(a={}){let{auth:e,secret:t=process.env.APP_KEY||(()=>{throw new Error("APP_KEY is not set. Set it in your .env file.")})(),sessionStore:n,sessionLifetime:s=86400,rateLimit:r=100,rateLimitWindow:i=6e4,csrfPaths:o=["/api/"],csrfExcludePaths:c=["/api/webhooks"],authThrottleAttempts:u=5,authThrottleDecay:N=1,debug:K=process.env.NODE_ENV!=="production",middleware:z=[],namedMiddleware:G={},i18n:q,errorConfig:Z={}}=a,A=[new v,new w({maxRequests:r,windowMs:i}),new y({onlyPaths:o,excludePaths:c}),new T({store:n??new g,secret:t,lifetime:s})];e&&A.push(new b(e)),A.push(...z);let Q={"auth-throttle":new E({maxAttempts:u,decayMinutes:N}),...G},j=new C({debug:K,...Z}),J=le({middleware:A,namedMiddleware:Q,onError:(k,O)=>j.handle(k,O)}),P;if(q){let{paraglideMiddleware:k,getTextDirection:O=()=>"ltr"}=q;P=de(async({event:L,resolve:ee})=>k(L.request,({request:te,locale:W})=>(L.request=te,ee(L,{transformPageChunk:({html:ne})=>ne.replace("%lang%",W).replace("%dir%",O(W))}))),J)}else P=J;return{handle:P,handleError:j.handleSvelteKitError()}}function le(a={}){let e=new m;if(a.middleware)for(let t of a.middleware)e.use(t);if(a.namedMiddleware)for(let[t,n]of Object.entries(a.namedMiddleware))e.register(t,n);return async function({event:n,resolve:s}){let r={event:n,params:n.params??{},locals:n.locals??{}};try{a.app&&!a.app.isBooted()&&await a.app.bootstrap();let i=await e.execute(r,async()=>s(n));return i instanceof Response?i:s(n)}catch(i){if(a.onError){let o=await a.onError(i,n);if(o instanceof Response)return o}return console.error("[Svelar] Unhandled error in hooks:",i),new Response(JSON.stringify({message:process.env.NODE_ENV==="production"?"Internal server error":i.message}),{status:500,headers:{"Content-Type":"application/json"}})}}}function de(...a){return async function({event:t,resolve:n}){let s=n;for(let r=a.length-1;r>=0;r--){let i=a[r],o=s;s=c=>i({event:c,resolve:o})}return s(t)}}export{$e as createSvelarApp,le as createSvelarHooks,de as sequence};
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Svelar HTTP Utilities
3
+ *
4
+ * Client-side: CSRF-aware fetch wrapper, automatic error toast handling.
5
+ * Server-side: Fluent HTTP client for third-party API calls (Postmark, Stripe, etc.)
6
+ *
7
+ * @module svelar/http
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * // Client-side (browser)
12
+ * import { apiFetch } from '@beeblock/svelar/http';
13
+ * const res = await apiFetch('/api/posts', { method: 'POST', body: JSON.stringify({ title: 'Hello' }) });
14
+ *
15
+ * // Server-side (third-party APIs)
16
+ * import { Http } from '@beeblock/svelar/http';
17
+ * const response = await Http.withToken(POSTMARK_TOKEN)
18
+ * .baseUrl('https://api.postmarkapp.com')
19
+ * .post('/email', { From: 'hi@example.com', To: 'user@example.com', Subject: 'Hello' });
20
+ * ```
21
+ */
22
+ export interface ApiFetchOptions extends RequestInit {
23
+ /** Custom CSRF cookie name (default: 'XSRF-TOKEN') */
24
+ csrfCookieName?: string;
25
+ /** Custom CSRF header name (default: 'X-CSRF-Token') */
26
+ csrfHeaderName?: string;
27
+ /** Show toast on error responses (default: true) */
28
+ showToast?: boolean;
29
+ /** Custom error messages by status code */
30
+ errorMessages?: Record<number, string>;
31
+ }
32
+ export interface ApiResponse<T = any> {
33
+ data: T | null;
34
+ error: ApiError | null;
35
+ status: number;
36
+ ok: boolean;
37
+ response: Response;
38
+ }
39
+ export interface ApiError {
40
+ message: string;
41
+ status: number;
42
+ errors?: Record<string, string[]>;
43
+ details?: Record<string, any>;
44
+ }
45
+ /**
46
+ * Register the toast function from the UI layer.
47
+ * Called automatically when <Toaster /> mounts.
48
+ * Can also be called manually for custom toast implementations.
49
+ */
50
+ export declare function registerToast(fn: (variant: string, title: string, opts?: any) => void): void;
51
+ /**
52
+ * CSRF-aware fetch wrapper with automatic error toast notifications.
53
+ *
54
+ * Features:
55
+ * - Attaches CSRF token from cookies on mutation requests
56
+ * - Shows toast notifications on error responses
57
+ * - Handles network errors gracefully
58
+ * - 401 responses can trigger redirect to login
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * import { apiFetch } from 'svelar/http';
63
+ *
64
+ * // POST with auto error toast
65
+ * const res = await apiFetch('/api/posts', {
66
+ * method: 'POST',
67
+ * body: JSON.stringify({ title: 'Hello', body: 'World' }),
68
+ * });
69
+ *
70
+ * // Disable toast for manual error handling
71
+ * const res = await apiFetch('/api/users', { showToast: false });
72
+ *
73
+ * // Custom error message for specific status
74
+ * const res = await apiFetch('/api/billing', {
75
+ * method: 'POST',
76
+ * errorMessages: { 402: 'Payment required. Please update your billing.' },
77
+ * });
78
+ * ```
79
+ */
80
+ export declare function apiFetch(url: string, options?: ApiFetchOptions): Promise<Response>;
81
+ /**
82
+ * Typed JSON fetch — returns parsed data or error, never throws.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * import { apiFetchJson } from 'svelar/http';
87
+ *
88
+ * const { data, error, ok } = await apiFetchJson<User[]>('/api/users');
89
+ * if (ok) {
90
+ * console.log(data); // User[]
91
+ * } else {
92
+ * console.log(error); // ApiError
93
+ * }
94
+ * ```
95
+ */
96
+ export declare function apiFetchJson<T = any>(url: string, options?: ApiFetchOptions): Promise<ApiResponse<T>>;
97
+ /**
98
+ * Extract a cookie value by name from document.cookie.
99
+ */
100
+ export declare function getCsrfToken(cookieName?: string): string | null;
101
+ /**
102
+ * Fetch wrapper that signs requests with HMAC-SHA256.
103
+ * Use with SignatureMiddleware on the server.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * import { signedFetch } from 'svelar/http';
108
+ *
109
+ * const res = await signedFetch('/api/webhooks', {
110
+ * method: 'POST',
111
+ * body: JSON.stringify({ event: 'order.created' }),
112
+ * signingSecret: 'your-shared-secret',
113
+ * });
114
+ * ```
115
+ */
116
+ export declare function signedFetch(url: string, options: ApiFetchOptions & {
117
+ signingSecret: string;
118
+ signatureHeader?: string;
119
+ timestampHeader?: string;
120
+ }): Promise<Response>;
121
+ /**
122
+ * Build a URL with query parameters.
123
+ *
124
+ * @example
125
+ * ```ts
126
+ * buildUrl('/api/posts', { page: 1, per_page: 10 });
127
+ * // => '/api/posts?page=1&per_page=10'
128
+ * ```
129
+ */
130
+ export declare function buildUrl(base: string, params?: Record<string, string | number | boolean | undefined | null>): string;
131
+ export interface HttpClientResponse<T = any> {
132
+ data: T;
133
+ status: number;
134
+ headers: Headers;
135
+ ok: boolean;
136
+ }
137
+ export interface HttpClientConfig {
138
+ baseUrl?: string;
139
+ headers?: Record<string, string>;
140
+ timeout?: number;
141
+ retries?: number;
142
+ retryDelay?: number;
143
+ }
144
+ export declare class HttpClient {
145
+ private _baseUrl;
146
+ private _headers;
147
+ private _timeout;
148
+ private _retries;
149
+ private _retryDelay;
150
+ private _query;
151
+ constructor(config?: HttpClientConfig);
152
+ private clone;
153
+ baseUrl(url: string): HttpClient;
154
+ withHeaders(headers: Record<string, string>): HttpClient;
155
+ withToken(token: string, type?: 'Bearer' | string): HttpClient;
156
+ withBasicAuth(username: string, password: string): HttpClient;
157
+ accept(contentType: string): HttpClient;
158
+ contentType(type: string): HttpClient;
159
+ timeout(ms: number): HttpClient;
160
+ retry(times: number, delayMs?: number): HttpClient;
161
+ query(params: Record<string, string | number | boolean | undefined | null>): HttpClient;
162
+ get<T = any>(path: string): Promise<HttpClientResponse<T>>;
163
+ post<T = any>(path: string, body?: unknown): Promise<HttpClientResponse<T>>;
164
+ put<T = any>(path: string, body?: unknown): Promise<HttpClientResponse<T>>;
165
+ patch<T = any>(path: string, body?: unknown): Promise<HttpClientResponse<T>>;
166
+ delete<T = any>(path: string, body?: unknown): Promise<HttpClientResponse<T>>;
167
+ private request;
168
+ private buildFullUrl;
169
+ }
170
+ export declare class HttpRequestError extends Error {
171
+ readonly status: number;
172
+ readonly body: any;
173
+ constructor(message: string, status: number, body: any);
174
+ }
175
+ /**
176
+ * Server-side HTTP client factory.
177
+ * Returns a new HttpClient instance for making authenticated API calls to third-party services.
178
+ *
179
+ * @example
180
+ * ```ts
181
+ * import { Http } from '@beeblock/svelar/http';
182
+ *
183
+ * // Postmark
184
+ * const res = await Http.withToken(POSTMARK_TOKEN, 'X-Postmark-Server-Token')
185
+ * .baseUrl('https://api.postmarkapp.com')
186
+ * .post('/email', { From: 'hi@example.com', To: 'user@example.com' });
187
+ *
188
+ * // Stripe
189
+ * const res = await Http.withToken(STRIPE_SECRET)
190
+ * .baseUrl('https://api.stripe.com/v1')
191
+ * .contentType('application/x-www-form-urlencoded')
192
+ * .post('/customers', 'email=user@example.com');
193
+ *
194
+ * // Custom header auth
195
+ * const res = await Http.withHeaders({ 'X-API-Key': API_KEY })
196
+ * .baseUrl('https://api.mailchimp.com/3.0')
197
+ * .retry(3)
198
+ * .get('/lists');
199
+ * ```
200
+ */
201
+ export declare const Http: HttpClient;
@@ -0,0 +1,2 @@
1
+ var T={400:"Invalid request. Please check your input.",401:"Your session has expired. Please sign in again.",403:"You don't have permission to do this.",404:"The requested resource was not found.",405:"This action is not allowed.",409:"A conflict occurred. Please refresh and try again.",419:"Page expired. Please refresh and try again.",422:"The submitted data is invalid.",429:"Too many requests. Please wait a moment.",500:"Something went wrong on our end.",502:"Service temporarily unavailable. Try again shortly.",503:"Service is under maintenance. Try again shortly.",504:"Request timed out. Please try again."},w=null;function P(s){w=s}function g(s,t,e){w&&w(s,t,{description:e})}async function R(s,t={}){let{csrfCookieName:e="XSRF-TOKEN",csrfHeaderName:r="X-CSRF-Token",showToast:n=!0,errorMessages:c={},...i}=t,p=(i.method||"GET").toUpperCase(),u=new Headers(i.headers);if(["POST","PUT","PATCH","DELETE"].includes(p)){let o=A(e);o&&u.set(r,o)}i.body&&typeof i.body=="string"&&!u.has("Content-Type")&&u.set("Content-Type","application/json"),u.has("Accept")||u.set("Accept","application/json");try{let o=await fetch(s,{...i,headers:u});return!o.ok&&n&&await E(o,{...T,...c}),o}catch(o){throw n&&g("error","Network Error","Unable to connect. Check your internet connection."),o}}async function x(s,t={}){try{let e=await R(s,t),r=null,n=null;if((e.headers.get("content-type")??"").includes("application/json")){let i=await e.json();e.ok?r=i:n={message:i.message??T[e.status]??"An error occurred",status:e.status,errors:i.errors,details:i}}else e.ok?r=await e.text():n={message:T[e.status]??`Error ${e.status}`,status:e.status};return{data:r,error:n,status:e.status,ok:e.ok,response:e}}catch(e){return{data:null,error:{message:e.message??"Network error",status:0},status:0,ok:!1,response:new Response(null,{status:0})}}}async function E(s,t){let e="";try{if((s.headers.get("content-type")??"").includes("application/json")){let i=await s.clone().json();if(e=i.message??"",s.status===422&&i.errors){let p=Object.entries(i.errors).map(([u,o])=>`${u}: ${o.join(", ")}`).slice(0,3).join(`
2
+ `);g("warning",t[422]??"Validation Error",p);return}}}catch{}let r=e||t[s.status]||`Error ${s.status}`,n=s.status>=500?"error":s.status===429?"warning":"error";if(s.status===401){g("warning",r,"Please sign in to continue.");return}g(n,r)}function A(s="XSRF-TOKEN"){if(typeof document>"u")return null;let t=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),e=document.cookie.match(new RegExp(`(?:^|;\\s*)${t}=([^;]*)`));return e?decodeURIComponent(e[1]):null}async function U(s,t){let{signingSecret:e,signatureHeader:r="X-Signature",timestampHeader:n="X-Timestamp",...c}=t,i=(c.method||"GET").toUpperCase(),p=typeof c.body=="string"?c.body:"",u=Math.floor(Date.now()/1e3),o=new URL(s,"http://localhost"),l=o.pathname+o.search,y=`${u}.${i}.${l}.${p}`,a=new TextEncoder,m=a.encode(e),d=a.encode(y),H=await crypto.subtle.importKey("raw",m,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),_=await crypto.subtle.sign("HMAC",H,d),C=Array.from(new Uint8Array(_),k=>k.toString(16).padStart(2,"0")).join(""),f=new Headers(c.headers);return f.set(r,C),f.set(n,String(u)),R(s,{...c,headers:f,method:i})}function v(s,t){if(!t)return s;let e=new URL(s,"http://localhost");for(let[r,n]of Object.entries(t))n!=null&&e.searchParams.set(r,String(n));return e.pathname+e.search}var b=class s{_baseUrl="";_headers={};_timeout=3e4;_retries=0;_retryDelay=1e3;_query={};constructor(t){t?.baseUrl&&(this._baseUrl=t.baseUrl),t?.headers&&(this._headers={...t.headers}),t?.timeout&&(this._timeout=t.timeout),t?.retries&&(this._retries=t.retries),t?.retryDelay&&(this._retryDelay=t.retryDelay)}clone(){let t=new s;return t._baseUrl=this._baseUrl,t._headers={...this._headers},t._timeout=this._timeout,t._retries=this._retries,t._retryDelay=this._retryDelay,t._query={...this._query},t}baseUrl(t){let e=this.clone();return e._baseUrl=t,e}withHeaders(t){let e=this.clone();return e._headers={...e._headers,...t},e}withToken(t,e="Bearer"){return this.withHeaders({Authorization:`${e} ${t}`})}withBasicAuth(t,e){let r=Buffer.from(`${t}:${e}`).toString("base64");return this.withHeaders({Authorization:`Basic ${r}`})}accept(t){return this.withHeaders({Accept:t})}contentType(t){return this.withHeaders({"Content-Type":t})}timeout(t){let e=this.clone();return e._timeout=t,e}retry(t,e=1e3){let r=this.clone();return r._retries=t,r._retryDelay=e,r}query(t){let e=this.clone();for(let[r,n]of Object.entries(t))n!=null&&(e._query[r]=String(n));return e}async get(t){return this.request("GET",t)}async post(t,e){return this.request("POST",t,e)}async put(t,e){return this.request("PUT",t,e)}async patch(t,e){return this.request("PATCH",t,e)}async delete(t,e){return this.request("DELETE",t,e)}async request(t,e,r){let n=this.buildFullUrl(e),c={...this._headers},i;r!==void 0&&(c["Content-Type"]||(c["Content-Type"]="application/json"),i=typeof r=="string"?r:JSON.stringify(r)),c.Accept||(c.Accept="application/json");let p=null,u=1+this._retries;for(let o=0;o<u;o++){o>0&&await new Promise(l=>setTimeout(l,this._retryDelay*o));try{let l=new AbortController,y=setTimeout(()=>l.abort(),this._timeout),a=await fetch(n,{method:t,headers:c,body:i,signal:l.signal});if(clearTimeout(y),!a.ok&&a.status<500&&o<u-1,!a.ok&&a.status>=500&&o<u-1){p=new h(`HTTP ${a.status}: ${a.statusText}`,a.status,await a.text());continue}let m=a.headers.get("content-type")??"",d;if(m.includes("application/json")?d=await a.json():d=await a.text(),!a.ok)throw new h(`HTTP ${a.status}: ${typeof d=="string"?d:JSON.stringify(d)}`,a.status,d);return{data:d,status:a.status,headers:a.headers,ok:!0}}catch(l){if(l instanceof h)throw l;if(p=l,l.name==="AbortError"&&(p=new h("Request timed out",0,null)),o>=u-1)break}}throw p??new Error("HTTP request failed")}buildFullUrl(t){let e=this._baseUrl?`${this._baseUrl.replace(/\/+$/,"")}/${t.replace(/^\/+/,"")}`:t,r=Object.entries(this._query);if(r.length>0){let n=new URL(e);for(let[c,i]of r)n.searchParams.set(c,i);e=n.toString()}return e}},h=class extends Error{constructor(e,r,n){super(e);this.status=r;this.body=n;this.name="HttpRequestError"}},S=new b;export{S as Http,b as HttpClient,h as HttpRequestError,R as apiFetch,x as apiFetchJson,v as buildUrl,A as getCsrfToken,P as registerToast,U as signedFetch};
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Svelar i18n Integration
3
+ *
4
+ * Helpers for integrating paraglide-js 2.x with SvelteKit.
5
+ * Provides middleware composers, reroute hook creators, and the LanguageSwitcher component.
6
+ *
7
+ * @module svelar/i18n
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * // hooks.server.ts
12
+ * import { createI18nHandle } from 'svelar/i18n';
13
+ * import { paraglideMiddleware } from '$lib/paraglide/server';
14
+ * import { getTextDirection } from '$lib/paraglide/runtime';
15
+ *
16
+ * const i18nHandle = createI18nHandle({ paraglideMiddleware, getTextDirection });
17
+ * ```
18
+ */
19
+ import type { Handle } from '@sveltejs/kit';
20
+ export interface I18nHandleConfig {
21
+ /**
22
+ * The paraglide middleware function from `$lib/paraglide/server`.
23
+ * Signature: (request, callback) => Response
24
+ */
25
+ paraglideMiddleware: (request: Request, callback: (args: {
26
+ request: Request;
27
+ locale: string;
28
+ }) => Response | Promise<Response>) => Response | Promise<Response>;
29
+ /**
30
+ * The getTextDirection function from `$lib/paraglide/runtime`.
31
+ * Returns 'ltr' or 'rtl' for a given locale.
32
+ */
33
+ getTextDirection?: (locale: string) => string;
34
+ /**
35
+ * HTML lang attribute placeholder (default: '%lang%')
36
+ */
37
+ langPlaceholder?: string;
38
+ /**
39
+ * HTML dir attribute placeholder (default: '%dir%')
40
+ */
41
+ dirPlaceholder?: string;
42
+ }
43
+ export interface RerouteConfig {
44
+ /**
45
+ * The deLocalizeUrl function from `$lib/paraglide/runtime`.
46
+ * Strips the locale prefix from URLs for SvelteKit routing.
47
+ */
48
+ deLocalizeUrl: (url: URL) => {
49
+ pathname: string;
50
+ };
51
+ }
52
+ /**
53
+ * Creates a SvelteKit `Handle` hook that wires paraglide-js middleware
54
+ * for server-side locale detection and HTML attribute injection.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * import { createI18nHandle } from 'svelar/i18n';
59
+ * import { paraglideMiddleware } from '$lib/paraglide/server';
60
+ * import { getTextDirection } from '$lib/paraglide/runtime';
61
+ *
62
+ * export const i18nHandle = createI18nHandle({ paraglideMiddleware, getTextDirection });
63
+ * ```
64
+ */
65
+ export declare function createI18nHandle(config: I18nHandleConfig): Handle;
66
+ /**
67
+ * Creates a SvelteKit `Reroute` function that strips locale prefixes
68
+ * from URLs so SvelteKit's file-based routing works correctly.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * // hooks.ts (client-side)
73
+ * import { createReroute } from 'svelar/i18n';
74
+ * import { deLocalizeUrl } from '$lib/paraglide/runtime';
75
+ *
76
+ * export const reroute = createReroute({ deLocalizeUrl });
77
+ * ```
78
+ */
79
+ export declare function createReroute(config: RerouteConfig): (request: {
80
+ url: URL;
81
+ }) => string;
@@ -0,0 +1 @@
1
+ function d(e){let{paraglideMiddleware:r,getTextDirection:a=()=>"ltr",langPlaceholder:l="%lang%",dirPlaceholder:o="%dir%"}=e;return({event:t,resolve:i})=>r(t.request,({request:s,locale:n})=>(t.request=s,i(t,{transformPageChunk:({html:c})=>c.replace(l,n).replace(o,a(n))})))}function u(e){return r=>e.deLocalizeUrl(r.url).pathname}export{d as createI18nHandle,u as createReroute};
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Svelar — Laravel-inspired framework on top of SvelteKit 2
3
+ *
4
+ * @module svelar
5
+ */
6
+ export { Model, type ModelAttributes, type ModelHooks } from './orm/Model.js';
7
+ export { QueryBuilder } from './orm/QueryBuilder.js';
8
+ export { HasOne, HasMany, BelongsTo, BelongsToMany } from './orm/Relationship.js';
9
+ export { Connection, type DatabaseConfig, type DatabaseDriver, type ConnectionsConfig } from './database/Connection.js';
10
+ export { Schema, schema, TableBuilder, ColumnBuilder } from './database/SchemaBuilder.js';
11
+ export { Migration, Migrator } from './database/Migration.js';
12
+ export { Seeder } from './database/Seeder.js';
13
+ export { Container, container } from './container/Container.js';
14
+ export { ServiceProvider } from './container/ServiceProvider.js';
15
+ export { Application } from './container/Application.js';
16
+ export { Middleware, MiddlewareStack, CorsMiddleware, RateLimitMiddleware, LoggingMiddleware, CsrfMiddleware, OriginMiddleware, ThrottleMiddleware, SignatureMiddleware } from './middleware/Middleware.js';
17
+ export type { MiddlewareContext, NextFunction, MiddlewareHandler } from './middleware/Middleware.js';
18
+ export { Controller, resource, ValidationError, NotFoundError, UnauthorizedError, ForbiddenError } from './routing/Controller.js';
19
+ export type { RequestEvent } from './routing/Controller.js';
20
+ export { createSvelarHooks, sequence } from './hooks/index.js';
21
+ export { config, env } from './config/Config.js';
22
+ export { z, rules, validate } from './validation/index.js';
23
+ export { AuthManager, AuthenticateMiddleware, RequireAuthMiddleware, signJwt, verifyJwt } from './auth/Auth.js';
24
+ export type { AuthConfig, AuthUser, GuardType, JwtConfig, JwtPayload } from './auth/Auth.js';
25
+ export { Hash } from './hashing/Hash.js';
26
+ export type { HashDriver, HashConfig } from './hashing/Hash.js';
27
+ export { Session, SessionMiddleware, MemorySessionStore, DatabaseSessionStore, FileSessionStore, RedisSessionStore } from './session/Session.js';
28
+ export type { SessionStore, SessionConfig, SessionData } from './session/Session.js';
29
+ export { ErrorHandler, HttpError, abort, abortIf, abortUnless, ModelNotFoundError } from './errors/Handler.js';
30
+ export type { ErrorHandlerConfig } from './errors/Handler.js';
31
+ export { Event, EventDispatcher } from './events/index.js';
32
+ export type { EventClass, EventListener, Subscriber } from './events/index.js';
33
+ export { FormRequest, FormValidationError, FormAuthorizationError } from './routing/FormRequest.js';
34
+ export { Storage } from './storage/index.js';
35
+ export type { StorageConfig, DiskConfig, FileInfo } from './storage/index.js';
36
+ export { Log } from './logging/index.js';
37
+ export type { LogLevel, LogConfig, LogChannelConfig } from './logging/index.js';
38
+ export { Cache } from './cache/index.js';
39
+ export type { CacheConfig, CacheStoreConfig, CacheDriver } from './cache/index.js';
40
+ export { Queue, Job } from './queue/index.js';
41
+ export type { QueueConfig, DispatchOptions } from './queue/index.js';
42
+ export { Mailer, Mailable } from './mail/index.js';
43
+ export type { MailerConfig, MailMessage, SendResult } from './mail/index.js';
44
+ export { Notifier, Notification } from './notifications/index.js';
45
+ export type { Notifiable, NotificationChannel } from './notifications/index.js';
46
+ export { Broadcast } from './broadcasting/index.js';
47
+ export { apiFetch, getCsrfToken, buildUrl } from './http/index.js';
48
+ export type { ApiFetchOptions } from './http/index.js';
49
+ export { createI18nHandle, createReroute } from './i18n/index.js';
50
+ export type { I18nHandleConfig, RerouteConfig } from './i18n/index.js';
51
+ export { createFormAction, loadForm, validateForm } from './forms/index.js';
52
+ export type { FormActionOptions } from './forms/index.js';
53
+ export { createSvelarApp } from './hooks/index.js';
54
+ export type { SvelarAppConfig } from './hooks/index.js';