@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,154 @@
1
+ /**
2
+ * Svelar Excel
3
+ *
4
+ * Excel import/export with streaming support for large files.
5
+ * Uses ExcelJS under the hood (requires `npm install exceljs`).
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { Excel, Spreadsheet } from '@beeblock/svelar/excel';
10
+ *
11
+ * // Quick export from array of objects
12
+ * const buffer = await Excel.export({
13
+ * sheets: [{
14
+ * name: 'Users',
15
+ * columns: [
16
+ * { header: 'Name', key: 'name', width: 30 },
17
+ * { header: 'Email', key: 'email', width: 40 },
18
+ * { header: 'Created', key: 'createdAt', width: 20 },
19
+ * ],
20
+ * rows: users,
21
+ * }],
22
+ * });
23
+ *
24
+ * // Quick import
25
+ * const rows = await Excel.import(buffer, { sheet: 'Users' });
26
+ * // [{ name: 'John', email: 'john@example.com', createdAt: '2026-01-01' }, ...]
27
+ *
28
+ * // Streaming export (low memory for large datasets)
29
+ * const buffer = await Excel.stream({
30
+ * sheets: [{
31
+ * name: 'Orders',
32
+ * columns: [
33
+ * { header: 'Order ID', key: 'id' },
34
+ * { header: 'Total', key: 'total' },
35
+ * ],
36
+ * rows: async function* () {
37
+ * let page = 1;
38
+ * while (true) {
39
+ * const batch = await Order.query().page(page, 1000);
40
+ * if (batch.length === 0) break;
41
+ * for (const order of batch) yield order;
42
+ * page++;
43
+ * }
44
+ * },
45
+ * }],
46
+ * });
47
+ *
48
+ * // Streaming import (low memory)
49
+ * await Excel.importStream(buffer, {
50
+ * sheet: 'Orders',
51
+ * onRow: async (row, index) => {
52
+ * await Order.create(row);
53
+ * },
54
+ * });
55
+ *
56
+ * // Advanced: Spreadsheet builder
57
+ * const spreadsheet = new Spreadsheet();
58
+ * spreadsheet
59
+ * .sheet('Report')
60
+ * .columns([
61
+ * { header: 'Month', key: 'month', width: 15 },
62
+ * { header: 'Revenue', key: 'revenue', width: 15, style: { numFmt: '"$"#,##0.00' } },
63
+ * ])
64
+ * .addRows(data)
65
+ * .headerStyle({ font: { bold: true }, fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF4472C4' } } })
66
+ * .autoFilter();
67
+ *
68
+ * const buffer = await spreadsheet.toBuffer();
69
+ * ```
70
+ */
71
+ export interface ColumnDef {
72
+ header: string;
73
+ key: string;
74
+ width?: number;
75
+ style?: Record<string, any>;
76
+ }
77
+ export interface SheetDef {
78
+ name: string;
79
+ columns: ColumnDef[];
80
+ rows: Record<string, any>[] | (() => AsyncIterable<Record<string, any>>);
81
+ }
82
+ export interface ExportOptions {
83
+ sheets: SheetDef[];
84
+ creator?: string;
85
+ }
86
+ export interface ImportOptions {
87
+ /** Sheet name or 1-based index (default: 1) */
88
+ sheet?: string | number;
89
+ /** Map column headers to keys. If not provided, uses first row as headers. */
90
+ headerRow?: number;
91
+ }
92
+ export interface ImportStreamOptions extends ImportOptions {
93
+ onRow: (row: Record<string, any>, index: number) => void | Promise<void>;
94
+ }
95
+ export declare class SheetBuilder {
96
+ private spreadsheet;
97
+ readonly name: string;
98
+ private _columns;
99
+ private _rows;
100
+ private _headerStyle;
101
+ private _autoFilter;
102
+ private _frozenRows;
103
+ private _frozenCols;
104
+ constructor(spreadsheet: Spreadsheet, name: string);
105
+ columns(cols: ColumnDef[]): this;
106
+ addRow(row: Record<string, any>): this;
107
+ addRows(rows: Record<string, any>[]): this;
108
+ headerStyle(style: Record<string, any>): this;
109
+ autoFilter(): this;
110
+ freeze(rows: number, cols?: number): this;
111
+ /** Start a new sheet on the same spreadsheet */
112
+ sheet(name: string): SheetBuilder;
113
+ /** Build to buffer */
114
+ toBuffer(): Promise<Buffer>;
115
+ /** @internal */
116
+ _apply(worksheet: any): void;
117
+ }
118
+ export declare class Spreadsheet {
119
+ private sheets;
120
+ private _creator;
121
+ creator(name: string): this;
122
+ sheet(name: string): SheetBuilder;
123
+ toBuffer(): Promise<Buffer>;
124
+ }
125
+ declare class ExcelManager {
126
+ /**
127
+ * Export data to an Excel buffer.
128
+ */
129
+ export(options: ExportOptions): Promise<Buffer>;
130
+ /**
131
+ * Streaming export for large datasets.
132
+ * Rows can be provided as an async generator to keep memory low.
133
+ */
134
+ stream(options: ExportOptions): Promise<Buffer>;
135
+ /**
136
+ * Import an Excel file into an array of objects.
137
+ * Uses the first row as headers by default.
138
+ */
139
+ import(input: Buffer | string, options?: ImportOptions): Promise<Record<string, any>[]>;
140
+ /**
141
+ * Streaming import for large files.
142
+ * Processes rows one at a time without loading the entire file into memory.
143
+ */
144
+ importStream(input: Buffer | string, options: ImportStreamOptions): Promise<void>;
145
+ /**
146
+ * Create a Spreadsheet builder for advanced use cases.
147
+ */
148
+ create(): Spreadsheet;
149
+ }
150
+ /**
151
+ * Global Excel singleton
152
+ */
153
+ export declare const Excel: ExcelManager;
154
+ export {};
@@ -0,0 +1 @@
1
+ function g(a,e){let t=Symbol.for(a),r=globalThis;return r[t]||(r[t]=e()),r[t]}async function u(){try{return await import("exceljs")}catch(a){throw a.code==="MODULE_NOT_FOUND"||a.code==="ERR_MODULE_NOT_FOUND"?new Error("Excel support requires exceljs. Install: npm install exceljs"):a}}function S(a,e){return e?typeof e=="number"?a.worksheets[e-1]:a.getWorksheet(e):a.worksheets[0]}function R(a,e){let t={};for(let r=0;r<e.length;r++){let s=a.getCell(r+1);t[e[r]]=s.value}return t}var d=class{constructor(e,t){this.spreadsheet=e;this.name=t}_columns=[];_rows=[];_headerStyle=null;_autoFilter=!1;_frozenRows=0;_frozenCols=0;columns(e){return this._columns=e,this}addRow(e){return this._rows.push(e),this}addRows(e){return this._rows.push(...e),this}headerStyle(e){return this._headerStyle=e,this}autoFilter(){return this._autoFilter=!0,this}freeze(e,t=0){return this._frozenRows=e,this._frozenCols=t,this}sheet(e){return this.spreadsheet.sheet(e)}async toBuffer(){return this.spreadsheet.toBuffer()}_apply(e){this._columns.length&&(e.columns=this._columns.map(t=>({header:t.header,key:t.key,width:t.width,style:t.style})));for(let t of this._rows)e.addRow(t);if(this._headerStyle&&e.rowCount>0){let t=e.getRow(1);for(let r of Object.keys(this._headerStyle))t[r]=this._headerStyle[r];t.commit?.()}this._autoFilter&&this._columns.length&&(e.autoFilter={from:{row:1,column:1},to:{row:1,column:this._columns.length}}),(this._frozenRows>0||this._frozenCols>0)&&(e.views=[{state:"frozen",xSplit:this._frozenCols,ySplit:this._frozenRows}])}},w=class{sheets=[];_creator="Svelar";creator(e){return this._creator=e,this}sheet(e){let t=new d(this,e);return this.sheets.push(t),t}async toBuffer(){let e=await u(),t=new e.Workbook;t.creator=this._creator,t.created=new Date;for(let r of this.sheets){let s=t.addWorksheet(r.name);r._apply(s)}return t.xlsx.writeBuffer()}},m=class{async export(e){let t=await u(),r=new t.Workbook;r.creator=e.creator??"Svelar",r.created=new Date;for(let s of e.sheets){let n=r.addWorksheet(s.name);n.columns=s.columns.map(o=>({header:o.header,key:o.key,width:o.width,style:o.style}));let c=Array.isArray(s.rows)?s.rows:null;if(c)for(let o of c)n.addRow(o)}return r.xlsx.writeBuffer()}async stream(e){let t=await u(),{PassThrough:r}=await import("stream"),s=new r,n=[];s.on("data",o=>n.push(o));let c=new t.stream.xlsx.WorkbookWriter({stream:s,useStyles:!0,useSharedStrings:!0});c.creator=e.creator??"Svelar";for(let o of e.sheets){let l=c.addWorksheet(o.name);if(l.columns=o.columns.map(i=>({header:i.header,key:i.key,width:i.width,style:i.style})),Array.isArray(o.rows))for(let i of o.rows)l.addRow(i).commit();else{let i=o.rows();for await(let h of i)l.addRow(h).commit()}l.commit()}return await c.commit(),Buffer.concat(n)}async import(e,t={}){let r=await u(),s=new r.Workbook;typeof e=="string"?await s.xlsx.readFile(e):await s.xlsx.load(e);let n=S(s,t.sheet);if(!n)throw new Error("Worksheet not found");let c=t.headerRow??1,o=n.getRow(c),l=[];o.eachCell({includeEmpty:!0},(h,f)=>{l[f-1]=String(h.value??`col${f}`)});let i=[];return n.eachRow({includeEmpty:!1},(h,f)=>{f<=c||i.push(R(h,l))}),i}async importStream(e,t){let r=await u(),{Readable:s}=await import("stream"),n=t.sheet,c=t.headerRow??1,o;typeof e=="string"?o=(await import("fs")).createReadStream(e):o=s.from(e);let l=new r.stream.xlsx.WorkbookReader(o,{}),i=[],h=0;for await(let f of l)if(!(n&&(typeof n=="string"&&f.name!==n||typeof n=="number"&&f.id!==n))){for await(let y of f){if(h++,h===c){y.eachCell({includeEmpty:!0},(_,p)=>{i[p-1]=String(_.value??`col${p}`)});continue}if(h<=c)continue;let x=R(y,i);await t.onRow(x,h-c-1)}break}}create(){return new w}},v=g("svelar.excel",()=>new m);export{v as Excel,d as SheetBuilder,w as Spreadsheet};
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Svelar Feature Flags
3
+ *
4
+ * Database-backed feature flags with per-user, per-team, and percentage
5
+ * rollout support. Tables are auto-created on first use — no migration required.
6
+ *
7
+ * Usage:
8
+ * import { Features } from '@beeblock/svelar/feature-flags';
9
+ *
10
+ * Features.configure({ driver: 'database' });
11
+ *
12
+ * // Define flags (typically in app.ts)
13
+ * Features.define('new-dashboard', { description: 'Redesigned dashboard UI' });
14
+ * Features.define('beta-api', { description: 'Beta API v2', percentage: 20 });
15
+ *
16
+ * // Check flags
17
+ * if (await Features.enabled('new-dashboard')) { ... }
18
+ * if (await Features.enabledFor('beta-api', userId)) { ... }
19
+ * if (await Features.enabledForTeam('beta-api', teamId)) { ... }
20
+ */
21
+ export interface FeatureFlag {
22
+ id: string;
23
+ name: string;
24
+ description: string;
25
+ enabled: boolean;
26
+ /** 0–100. When set, the flag is enabled for this percentage of users (consistent hashing). */
27
+ percentage: number | null;
28
+ metadata?: Record<string, any>;
29
+ createdAt: number;
30
+ updatedAt: number;
31
+ }
32
+ export interface FeatureFlagOverride {
33
+ id: string;
34
+ flagName: string;
35
+ /** 'user' or 'team' */
36
+ scopeType: 'user' | 'team';
37
+ scopeId: string | number;
38
+ enabled: boolean;
39
+ createdAt: number;
40
+ }
41
+ export interface FeatureFlagsConfig {
42
+ driver: 'database' | 'memory';
43
+ table?: string;
44
+ overridesTable?: string;
45
+ }
46
+ export interface FeatureFlagDefinition {
47
+ description?: string;
48
+ enabled?: boolean;
49
+ percentage?: number | null;
50
+ }
51
+ declare class FeatureFlagManager {
52
+ private config;
53
+ private memFlags;
54
+ private memOverrides;
55
+ private tablesEnsured;
56
+ configure(config: FeatureFlagsConfig): void;
57
+ private get flagsTable();
58
+ private get overridesTable();
59
+ private get useDb();
60
+ private getConnection;
61
+ /**
62
+ * Auto-create feature_flags and feature_flag_overrides tables on first use.
63
+ */
64
+ ensureTables(): Promise<void>;
65
+ private rowToFlag;
66
+ private rowToOverride;
67
+ /**
68
+ * Define (or update) a feature flag. Safe to call multiple times —
69
+ * if the flag already exists, it updates description/percentage only.
70
+ */
71
+ define(name: string, opts?: FeatureFlagDefinition): Promise<FeatureFlag>;
72
+ /**
73
+ * Get a flag by name.
74
+ */
75
+ getFlag(name: string): Promise<FeatureFlag | null>;
76
+ /**
77
+ * List all flags.
78
+ */
79
+ allFlags(): Promise<FeatureFlag[]>;
80
+ /**
81
+ * Update a flag's properties.
82
+ */
83
+ updateFlag(name: string, data: Partial<Pick<FeatureFlag, 'description' | 'enabled' | 'percentage' | 'metadata'>>): Promise<FeatureFlag | null>;
84
+ /**
85
+ * Delete a flag and all its overrides.
86
+ */
87
+ deleteFlag(name: string): Promise<boolean>;
88
+ /**
89
+ * Globally enable a flag.
90
+ */
91
+ enable(name: string): Promise<void>;
92
+ /**
93
+ * Globally disable a flag.
94
+ */
95
+ disable(name: string): Promise<void>;
96
+ /**
97
+ * Check if a flag is globally enabled (ignores per-user/team overrides).
98
+ */
99
+ enabled(name: string): Promise<boolean>;
100
+ /**
101
+ * Check if a flag is enabled for a specific user.
102
+ *
103
+ * Resolution order:
104
+ * 1. User-level override (if exists) — wins
105
+ * 2. Percentage rollout (if configured) — consistent per user
106
+ * 3. Global enabled/disabled state
107
+ */
108
+ enabledFor(name: string, userId: string | number): Promise<boolean>;
109
+ /**
110
+ * Check if a flag is enabled for a specific team.
111
+ *
112
+ * Resolution order:
113
+ * 1. Team-level override (if exists) — wins
114
+ * 2. Percentage rollout (if configured) — consistent per team
115
+ * 3. Global enabled/disabled state
116
+ */
117
+ enabledForTeam(name: string, teamId: string | number): Promise<boolean>;
118
+ /**
119
+ * Set an override for a specific user or team.
120
+ */
121
+ setOverride(flagName: string, scopeType: 'user' | 'team', scopeId: string | number, enabled: boolean): Promise<FeatureFlagOverride>;
122
+ /**
123
+ * Remove an override for a specific user or team.
124
+ */
125
+ removeOverride(flagName: string, scopeType: 'user' | 'team', scopeId: string | number): Promise<boolean>;
126
+ /**
127
+ * Get a specific override.
128
+ */
129
+ getOverride(flagName: string, scopeType: 'user' | 'team', scopeId: string | number): Promise<FeatureFlagOverride | null>;
130
+ /**
131
+ * List all overrides for a flag.
132
+ */
133
+ getOverrides(flagName: string): Promise<FeatureFlagOverride[]>;
134
+ /**
135
+ * Enable a flag for a specific user.
136
+ */
137
+ enableFor(name: string, userId: string | number): Promise<void>;
138
+ /**
139
+ * Disable a flag for a specific user.
140
+ */
141
+ disableFor(name: string, userId: string | number): Promise<void>;
142
+ /**
143
+ * Enable a flag for a specific team.
144
+ */
145
+ enableForTeam(name: string, teamId: string | number): Promise<void>;
146
+ /**
147
+ * Disable a flag for a specific team.
148
+ */
149
+ disableForTeam(name: string, teamId: string | number): Promise<void>;
150
+ /**
151
+ * Deterministic percentage check using a simple hash.
152
+ * The same flag+identifier always produces the same result,
153
+ * so a user consistently sees the feature (or doesn't).
154
+ */
155
+ private inPercentage;
156
+ }
157
+ export declare const Features: FeatureFlagManager;
158
+ export {};
@@ -0,0 +1,59 @@
1
+ var w=Object.defineProperty;var b=(d,e)=>()=>(d&&(e=d(d=0)),e);var E=(d,e)=>{for(var t in e)w(d,t,{get:e[t],enumerable:!0})};function u(d,e){let t=Symbol.for(d),a=globalThis;return a[t]||(a[t]=e()),a[t]}var m=b(()=>{"use strict"});var f={};E(f,{Connection:()=>N});var p,N,h=b(()=>{"use strict";m();p=class{connections=new Map;config=null;defaultName="default";configure(e){this.config=e,this.defaultName=e.default}async connection(e){let t=e??this.defaultName;if(this.connections.has(t))return this.connections.get(t).drizzle;if(!this.config)throw new Error("Database not configured. Call Connection.configure() first, or register DatabaseServiceProvider.");let a=this.config.connections[t];if(!a)throw new Error(`Database connection "${t}" is not defined in configuration.`);let r=await this.createConnection(a);return this.connections.set(t,r),r.drizzle}async rawClient(e){let t=e??this.defaultName;return await this.connection(t),this.connections.get(t).rawClient}async raw(e,t=[],a){let r=await this.connection(a),n=this.getConfig(a);switch(n.driver){case"sqlite":{let i=await this.rawClient(a),o=t.map(l=>typeof l=="boolean"?l?1:0:l instanceof Date?l.toISOString():l),s=i.prepare(e),c=e.trimStart().toUpperCase();return c.startsWith("SELECT")||c.startsWith("PRAGMA")||c.startsWith("WITH")?s.all(...o):s.run(...o)}case"postgres":return(await this.rawClient(a))(e,...t);case"mysql":{let i=await this.rawClient(a),[o]=await i.execute(e,t);return o}default:throw new Error(`Unsupported driver: ${n.driver}`)}}getDriver(e){return this.getConfig(e).driver}getConfig(e){let t=e??this.defaultName;if(!this.config)throw new Error("Database not configured.");let a=this.config.connections[t];if(!a)throw new Error(`Database connection "${t}" is not defined.`);return a}async disconnect(e){if(e){let t=this.connections.get(e);t&&(await this.closeConnection(t),this.connections.delete(e))}else{for(let[t,a]of this.connections)await this.closeConnection(a);this.connections.clear()}}isConnected(e){return this.connections.has(e??this.defaultName)}async transaction(e,t){let a=this.getConfig(t),r=await this.rawClient(t);switch(a.driver){case"sqlite":{r.exec("BEGIN");try{let n=await e();return r.exec("COMMIT"),n}catch(n){throw r.exec("ROLLBACK"),n}}case"postgres":{await r`BEGIN`;try{let n=await e();return await r`COMMIT`,n}catch(n){throw await r`ROLLBACK`,n}}case"mysql":{let n=await r.getConnection();await n.beginTransaction();try{let i=await e();return await n.commit(),n.release(),i}catch(i){throw await n.rollback(),n.release(),i}}default:throw new Error(`Unsupported driver: ${a.driver}`)}}async createConnection(e){switch(e.driver){case"sqlite":return this.createSQLiteConnection(e);case"postgres":return this.createPostgresConnection(e);case"mysql":return this.createMySQLConnection(e);default:throw new Error(`Unsupported database driver: ${e.driver}`)}}async createSQLiteConnection(e){let t=e.filename??e.database??":memory:";try{let a=(await import("better-sqlite3")).default,{drizzle:r}=await import("drizzle-orm/better-sqlite3"),n=new a(t);return n.pragma("journal_mode = WAL"),n.pragma("foreign_keys = ON"),{drizzle:r(n),config:e,rawClient:n}}catch(a){let r;try{r=(await new Function("mod","return import(mod)")("node:sqlite")).DatabaseSync}catch{throw new Error(`No SQLite driver available. Install better-sqlite3 (npm install better-sqlite3) or use Node.js v22+ which includes built-in SQLite support. Original error: ${a instanceof Error?a.message:String(a)}`)}let n=new r(t);n.exec("PRAGMA journal_mode = WAL"),n.exec("PRAGMA foreign_keys = ON");let i={prepare(s){let c=n.prepare(s);return{all(...l){return c.all(...l)},run(...l){return c.run(...l)},get(...l){return c.get(...l)}}},exec(s){n.exec(s)},pragma(s){return n.prepare(`PRAGMA ${s}`).all()},close(){n.close()}},o;try{let{drizzle:s}=await import("drizzle-orm/better-sqlite3");o=s(i)}catch{o=i}return{drizzle:o,config:e,rawClient:i}}}async createPostgresConnection(e){let t=(await import("postgres")).default,{drizzle:a}=await import("drizzle-orm/postgres-js"),r=e.url??`postgres://${e.user}:${e.password}@${e.host??"localhost"}:${e.port??5432}/${e.database}`,n=t(r);return{drizzle:a(n),config:e,rawClient:n}}async createMySQLConnection(e){let t=await import("mysql2/promise"),{drizzle:a}=await import("drizzle-orm/mysql2"),r=t.createPool({host:e.host??"localhost",port:e.port??3306,database:e.database,user:e.user,password:e.password,uri:e.url});return{drizzle:a(r),config:e,rawClient:r}}async closeConnection(e){try{switch(e.config.driver){case"sqlite":e.rawClient.close();break;case"postgres":await e.rawClient.end();break;case"mysql":await e.rawClient.end();break}}catch{}}},N=u("svelar.connection",()=>new p)});m();import{randomUUID as g}from"crypto";var T=class{config={driver:"memory"};memFlags=[];memOverrides=[];tablesEnsured=!1;configure(e){this.config={...this.config,...e},this.tablesEnsured=!1}get flagsTable(){return this.config.table||"feature_flags"}get overridesTable(){return this.config.overridesTable||"feature_flag_overrides"}get useDb(){return this.config.driver==="database"}async getConnection(){let{Connection:e}=await Promise.resolve().then(()=>(h(),f));return e}async ensureTables(){if(this.tablesEnsured||!this.useDb)return;let e=await this.getConnection(),t=e.getDriver(),a=this.flagsTable,r=this.overridesTable;switch(t){case"sqlite":await e.raw(`CREATE TABLE IF NOT EXISTS ${a} (
2
+ id TEXT PRIMARY KEY,
3
+ name TEXT NOT NULL UNIQUE,
4
+ description TEXT NOT NULL DEFAULT '',
5
+ enabled INTEGER NOT NULL DEFAULT 0,
6
+ percentage INTEGER,
7
+ metadata TEXT,
8
+ created_at TEXT NOT NULL,
9
+ updated_at TEXT NOT NULL
10
+ )`),await e.raw(`CREATE TABLE IF NOT EXISTS ${r} (
11
+ id TEXT PRIMARY KEY,
12
+ flag_name TEXT NOT NULL,
13
+ scope_type TEXT NOT NULL,
14
+ scope_id TEXT NOT NULL,
15
+ enabled INTEGER NOT NULL DEFAULT 1,
16
+ created_at TEXT NOT NULL,
17
+ UNIQUE(flag_name, scope_type, scope_id)
18
+ )`);break;case"postgres":await e.raw(`CREATE TABLE IF NOT EXISTS ${a} (
19
+ id VARCHAR(255) PRIMARY KEY,
20
+ name VARCHAR(255) NOT NULL UNIQUE,
21
+ description TEXT NOT NULL DEFAULT '',
22
+ enabled BOOLEAN NOT NULL DEFAULT FALSE,
23
+ percentage INTEGER,
24
+ metadata JSONB,
25
+ created_at TIMESTAMPTZ NOT NULL,
26
+ updated_at TIMESTAMPTZ NOT NULL
27
+ )`),await e.raw(`CREATE TABLE IF NOT EXISTS ${r} (
28
+ id VARCHAR(255) PRIMARY KEY,
29
+ flag_name VARCHAR(255) NOT NULL,
30
+ scope_type VARCHAR(50) NOT NULL,
31
+ scope_id VARCHAR(255) NOT NULL,
32
+ enabled BOOLEAN NOT NULL DEFAULT TRUE,
33
+ created_at TIMESTAMPTZ NOT NULL,
34
+ UNIQUE(flag_name, scope_type, scope_id)
35
+ )`);break;case"mysql":await e.raw(`CREATE TABLE IF NOT EXISTS ${a} (
36
+ id VARCHAR(255) PRIMARY KEY,
37
+ name VARCHAR(255) NOT NULL UNIQUE,
38
+ description TEXT NOT NULL,
39
+ enabled TINYINT(1) NOT NULL DEFAULT 0,
40
+ percentage INT,
41
+ metadata JSON,
42
+ created_at DATETIME NOT NULL,
43
+ updated_at DATETIME NOT NULL
44
+ ) ENGINE=InnoDB`),await e.raw(`CREATE TABLE IF NOT EXISTS ${r} (
45
+ id VARCHAR(255) PRIMARY KEY,
46
+ flag_name VARCHAR(255) NOT NULL,
47
+ scope_type VARCHAR(50) NOT NULL,
48
+ scope_id VARCHAR(255) NOT NULL,
49
+ enabled TINYINT(1) NOT NULL DEFAULT 1,
50
+ created_at DATETIME NOT NULL,
51
+ UNIQUE(flag_name, scope_type, scope_id)
52
+ ) ENGINE=InnoDB`);break}this.tablesEnsured=!0}rowToFlag(e){return{id:e.id,name:e.name,description:e.description||"",enabled:!!e.enabled,percentage:e.percentage!=null?Number(e.percentage):null,metadata:e.metadata?typeof e.metadata=="string"?JSON.parse(e.metadata):e.metadata:void 0,createdAt:new Date(e.created_at).getTime(),updatedAt:new Date(e.updated_at).getTime()}}rowToOverride(e){return{id:e.id,flagName:e.flag_name,scopeType:e.scope_type,scopeId:e.scope_id,enabled:!!e.enabled,createdAt:new Date(e.created_at).getTime()}}async define(e,t={}){let a=await this.getFlag(e);if(a){let i={};return t.description!==void 0&&(i.description=t.description),t.percentage!==void 0&&(i.percentage=t.percentage),t.enabled!==void 0&&(i.enabled=t.enabled),Object.keys(i).length>0?await this.updateFlag(e,i):a}let r=Date.now(),n={id:g(),name:e,description:t.description||"",enabled:t.enabled??!1,percentage:t.percentage??null,createdAt:r,updatedAt:r};if(this.useDb){await this.ensureTables();let i=await this.getConnection(),o=new Date(r).toISOString();await i.raw(`INSERT INTO ${this.flagsTable} (id, name, description, enabled, percentage, metadata, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,[n.id,n.name,n.description,n.enabled?1:0,n.percentage,null,o,o])}else this.memFlags.push(n);return n}async getFlag(e){if(this.useDb){await this.ensureTables();let a=await(await this.getConnection()).raw(`SELECT * FROM ${this.flagsTable} WHERE name = ?`,[e]);return a.length>0?this.rowToFlag(a[0]):null}return this.memFlags.find(t=>t.name===e)||null}async allFlags(){return this.useDb?(await this.ensureTables(),(await(await this.getConnection()).raw(`SELECT * FROM ${this.flagsTable} ORDER BY name`)).map(a=>this.rowToFlag(a))):[...this.memFlags].sort((e,t)=>e.name.localeCompare(t.name))}async updateFlag(e,t){if(this.useDb){await this.ensureTables();let r=await this.getConnection(),n=await this.getFlag(e);if(!n)return null;let i=new Date().toISOString(),o=t.description??n.description,s=t.enabled??n.enabled,c=t.percentage!==void 0?t.percentage:n.percentage,l=t.metadata!==void 0?JSON.stringify(t.metadata):n.metadata?JSON.stringify(n.metadata):null;return await r.raw(`UPDATE ${this.flagsTable} SET description = ?, enabled = ?, percentage = ?, metadata = ?, updated_at = ? WHERE name = ?`,[o,s?1:0,c,l,i,e]),this.getFlag(e)}let a=this.memFlags.find(r=>r.name===e);return a?(t.description!==void 0&&(a.description=t.description),t.enabled!==void 0&&(a.enabled=t.enabled),t.percentage!==void 0&&(a.percentage=t.percentage),t.metadata!==void 0&&(a.metadata=t.metadata),a.updatedAt=Date.now(),a):null}async deleteFlag(e){if(this.useDb){await this.ensureTables();let a=await this.getConnection();return await a.raw(`DELETE FROM ${this.overridesTable} WHERE flag_name = ?`,[e]),await a.raw(`DELETE FROM ${this.flagsTable} WHERE name = ?`,[e]),!0}let t=this.memFlags.findIndex(a=>a.name===e);return t===-1?!1:(this.memFlags.splice(t,1),this.memOverrides=this.memOverrides.filter(a=>a.flagName!==e),!0)}async enable(e){await this.updateFlag(e,{enabled:!0})}async disable(e){await this.updateFlag(e,{enabled:!1})}async enabled(e){let t=await this.getFlag(e);return t?t.enabled:!1}async enabledFor(e,t){let a=await this.getFlag(e);if(!a)return!1;let r=await this.getOverride(e,"user",t);return r?r.enabled:a.percentage!=null?this.inPercentage(e,String(t),a.percentage):a.enabled}async enabledForTeam(e,t){let a=await this.getFlag(e);if(!a)return!1;let r=await this.getOverride(e,"team",t);return r?r.enabled:a.percentage!=null?this.inPercentage(e,`team:${t}`,a.percentage):a.enabled}async setOverride(e,t,a,r){let n=Date.now();if(this.useDb){await this.ensureTables();let s=await this.getConnection(),c=new Date(n).toISOString();switch(s.getDriver()){case"sqlite":await s.raw(`INSERT INTO ${this.overridesTable} (id, flag_name, scope_type, scope_id, enabled, created_at)
53
+ VALUES (?, ?, ?, ?, ?, ?)
54
+ ON CONFLICT(flag_name, scope_type, scope_id)
55
+ DO UPDATE SET enabled = ?, created_at = ?`,[g(),e,t,String(a),r?1:0,c,r?1:0,c]);break;case"postgres":await s.raw(`INSERT INTO ${this.overridesTable} (id, flag_name, scope_type, scope_id, enabled, created_at)
56
+ VALUES ($1, $2, $3, $4, $5, $6)
57
+ ON CONFLICT(flag_name, scope_type, scope_id)
58
+ DO UPDATE SET enabled = $5, created_at = $6`,[g(),e,t,String(a),r,c]);break;case"mysql":await s.raw(`DELETE FROM ${this.overridesTable} WHERE flag_name = ? AND scope_type = ? AND scope_id = ?`,[e,t,String(a)]),await s.raw(`INSERT INTO ${this.overridesTable} (id, flag_name, scope_type, scope_id, enabled, created_at)
59
+ VALUES (?, ?, ?, ?, ?, ?)`,[g(),e,t,String(a),r?1:0,c]);break}return await this.getOverride(e,t,a)}let i=this.memOverrides.find(s=>s.flagName===e&&s.scopeType===t&&s.scopeId===String(a));if(i)return i.enabled=r,i;let o={id:g(),flagName:e,scopeType:t,scopeId:String(a),enabled:r,createdAt:n};return this.memOverrides.push(o),o}async removeOverride(e,t,a){if(this.useDb)return await this.ensureTables(),await(await this.getConnection()).raw(`DELETE FROM ${this.overridesTable} WHERE flag_name = ? AND scope_type = ? AND scope_id = ?`,[e,t,String(a)]),!0;let r=this.memOverrides.findIndex(n=>n.flagName===e&&n.scopeType===t&&n.scopeId===String(a));return r===-1?!1:(this.memOverrides.splice(r,1),!0)}async getOverride(e,t,a){if(this.useDb){await this.ensureTables();let n=await(await this.getConnection()).raw(`SELECT * FROM ${this.overridesTable} WHERE flag_name = ? AND scope_type = ? AND scope_id = ?`,[e,t,String(a)]);return n.length>0?this.rowToOverride(n[0]):null}return this.memOverrides.find(r=>r.flagName===e&&r.scopeType===t&&r.scopeId===String(a))||null}async getOverrides(e){return this.useDb?(await this.ensureTables(),(await(await this.getConnection()).raw(`SELECT * FROM ${this.overridesTable} WHERE flag_name = ?`,[e])).map(r=>this.rowToOverride(r))):this.memOverrides.filter(t=>t.flagName===e)}async enableFor(e,t){await this.setOverride(e,"user",t,!0)}async disableFor(e,t){await this.setOverride(e,"user",t,!1)}async enableForTeam(e,t){await this.setOverride(e,"team",t,!0)}async disableForTeam(e,t){await this.setOverride(e,"team",t,!1)}inPercentage(e,t,a){if(a>=100)return!0;if(a<=0)return!1;let r=`${e}:${t}`,n=2166136261;for(let i=0;i<r.length;i++)n^=r.charCodeAt(i),n=n*16777619>>>0;return n%100<a}},F=u("svelar.feature-flags",()=>new T);export{F as Features};
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Svelar Forms Integration
3
+ *
4
+ * Bridges sveltekit-superforms with Svelar's validation layer.
5
+ * Provides helpers for creating forms with Zod schemas and server-side validation.
6
+ *
7
+ * @module svelar/forms
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * // +page.server.ts
12
+ * import { createFormAction, loadForm } from 'svelar/forms';
13
+ * import { z } from 'zod';
14
+ *
15
+ * const schema = z.object({ title: z.string().min(3), body: z.string().min(10) });
16
+ *
17
+ * export const load = async (event) => ({
18
+ * form: await loadForm(schema),
19
+ * });
20
+ *
21
+ * export const actions = {
22
+ * default: createFormAction(schema, async (data, event) => {
23
+ * await Post.create(data);
24
+ * }),
25
+ * };
26
+ * ```
27
+ */
28
+ import { z } from 'zod';
29
+ export type { z };
30
+ export interface FormActionOptions<T extends z.ZodTypeAny> {
31
+ /** Redirect URL on success */
32
+ redirectTo?: string;
33
+ /** Custom error message on failure */
34
+ errorMessage?: string;
35
+ /** Whether to reset form after success (default: true) */
36
+ resetOnSuccess?: boolean;
37
+ }
38
+ /**
39
+ * Creates a server-side form action handler with Zod validation.
40
+ * Compatible with sveltekit-superforms.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * import { createFormAction } from 'svelar/forms';
45
+ * import { createPostSchema } from '$lib/schemas/post';
46
+ *
47
+ * export const actions = {
48
+ * default: createFormAction(createPostSchema, async (data, event) => {
49
+ * const user = event.locals.user;
50
+ * await Post.create({ ...data, user_id: user.id });
51
+ * }),
52
+ * };
53
+ * ```
54
+ */
55
+ export declare function createFormAction<T extends z.ZodTypeAny>(schema: T, handler: (data: z.infer<T>, event: any) => Promise<void | Record<string, any>>, options?: FormActionOptions<T>): (event: any) => Promise<Record<string, any> | import("@sveltejs/kit").ActionFailure<{
56
+ form: import("sveltekit-superforms").SuperValidated<{}, any, {}>;
57
+ }> | {
58
+ form: import("sveltekit-superforms").SuperValidated<{}, any, {}>;
59
+ }>;
60
+ /**
61
+ * Load an empty form for a given schema.
62
+ * Use this in SvelteKit `load` functions.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * export const load = async () => ({
67
+ * form: await loadForm(mySchema),
68
+ * });
69
+ * ```
70
+ */
71
+ export declare function loadForm<T extends z.ZodTypeAny>(schema: T, data?: Partial<z.infer<T>>): Promise<import("sveltekit-superforms").SuperValidated<{}, any, z.TypeOf<T>>>;
72
+ /**
73
+ * Validate form data against a Zod schema (server-side).
74
+ * Returns the validated data or throws a FormValidationError.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * const data = await validateForm(event, createPostSchema);
79
+ * ```
80
+ */
81
+ export declare function validateForm<T extends z.ZodTypeAny>(event: any, schema: T): Promise<z.infer<T>>;
@@ -0,0 +1 @@
1
+ var R=Object.defineProperty;var x=(r,e)=>()=>(r&&(e=r(r=0)),e);var b=(r,e)=>{for(var t in e)R(r,t,{get:e[t],enumerable:!0})};var h={};b(h,{FormAuthorizationError:()=>l,FormRequest:()=>g,FormValidationError:()=>p});var g,p,l,T=x(()=>{"use strict";g=class{authorize(e){return!0}messages(){return{}}attributes(){return{}}passedValidation(e){return e}failedValidation(e){throw new p(e)}failedAuthorization(){throw new l}async parseBody(e){let t=e.request.headers.get("content-type")??"";if(t.includes("application/json"))return e.request.json();if(t.includes("multipart/form-data")||t.includes("application/x-www-form-urlencoded")){let s=await e.request.formData();return Object.fromEntries(s)}return Object.fromEntries(e.url.searchParams)}static async validate(e){let t=new this;await t.authorize(e)||t.failedAuthorization();let n=await t.parseBody(e),i={...Object.fromEntries(e.url.searchParams),...e.params,...n},c=t.rules().safeParse(i);if(!c.success){let a={},o=t.messages(),m=t.attributes();for(let y of c.error.issues){let d=y.path.join("."),f=m[d]??d;a[f]||(a[f]=[]);let w=`${d}.${y.code}`,z=o[w]??o[d];a[f].push(z??y.message)}t.failedValidation(a)}return t.passedValidation(c.data)}},p=class extends Error{constructor(t){super("The given data was invalid.");this.errors=t;this.name="FormValidationError"}statusCode=422;toResponse(){return new Response(JSON.stringify({message:this.message,errors:this.errors}),{status:422,headers:{"Content-Type":"application/json"}})}},l=class extends Error{statusCode=403;constructor(e="This action is unauthorized."){super(e),this.name="FormAuthorizationError"}toResponse(){return new Response(JSON.stringify({message:this.message}),{status:403,headers:{"Content-Type":"application/json"}})}}});function E(r,e,t={}){return async s=>{let{superValidate:n,fail:i,message:u}=await import("sveltekit-superforms"),{zod:c}=await import("sveltekit-superforms/adapters"),a=await n(s,c(r));if(!a.valid)return i(400,{form:a});try{let o=await e(a.data,s);if(t.redirectTo){let{redirect:m}=await import("@sveltejs/kit");throw m(303,t.redirectTo)}return o??{form:a}}catch(o){if(o?.status>=300&&o?.status<400)throw o;return u(a,t.errorMessage||o.message||"An error occurred",{status:o.status||400})}}}async function P(r,e){let{superValidate:t}=await import("sveltekit-superforms"),{zod:s}=await import("sveltekit-superforms/adapters");return t(e??null,s(r))}async function j(r,e){let t=await r.request.formData(),s={};for(let[i,u]of t.entries())s[i]=u;let n=e.safeParse(s);if(!n.success){let{FormValidationError:i}=await Promise.resolve().then(()=>(T(),h));throw new i(n.error.flatten().fieldErrors)}return n.data}export{E as createFormAction,P as loadForm,j as validateForm};
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Svelar Hashing
3
+ *
4
+ * Password hashing with bcrypt and argon2 support.
5
+ * Falls back to a built-in scrypt implementation for zero-dependency usage.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { Hash } from 'svelar';
10
+ *
11
+ * const hashed = await Hash.make('my-password');
12
+ * const valid = await Hash.verify('my-password', hashed);
13
+ * ```
14
+ */
15
+ export type HashDriver = 'scrypt' | 'bcrypt' | 'argon2';
16
+ export interface HashConfig {
17
+ driver: HashDriver;
18
+ /** scrypt: CPU/memory cost (default: 16384) */
19
+ scryptCost?: number;
20
+ /** bcrypt: rounds (default: 12) */
21
+ bcryptRounds?: number;
22
+ }
23
+ declare class HashManager {
24
+ private config;
25
+ /**
26
+ * Configure the hash manager
27
+ */
28
+ configure(config: Partial<HashConfig>): void;
29
+ /**
30
+ * Hash a plain text value
31
+ */
32
+ make(value: string): Promise<string>;
33
+ /**
34
+ * Verify a plain text value against a hash
35
+ */
36
+ verify(value: string, hash: string): Promise<boolean>;
37
+ /**
38
+ * Check if a hash needs to be rehashed (e.g. cost parameter changed)
39
+ */
40
+ needsRehash(hash: string): boolean;
41
+ /**
42
+ * Generate a random string (useful for tokens, API keys)
43
+ */
44
+ randomString(length?: number): string;
45
+ /**
46
+ * Generate a random token (URL-safe base64)
47
+ */
48
+ randomToken(bytes?: number): string;
49
+ }
50
+ export declare const Hash: HashManager;
51
+ export {};
@@ -0,0 +1 @@
1
+ export { Hash, type HashDriver, type HashConfig } from './Hash.js';
@@ -0,0 +1 @@
1
+ import{randomBytes as p,scrypt as u,timingSafeEqual as b}from"crypto";function y(e,r){let t=Symbol.for(e),s=globalThis;return s[t]||(s[t]=r()),s[t]}async function l(e,r=16384){let t=p(16),s=64,o=await new Promise((n,a)=>{u(e,t,s,{N:r,r:8,p:1},(i,c)=>{i?a(i):n(c)})});return`$scrypt$N=${r}$${t.toString("base64")}$${o.toString("base64")}`}async function m(e,r){let t=r.split("$");if(t.length!==5||t[1]!=="scrypt")return!1;let s=parseInt(t[2].replace("N=",""),10),o=Buffer.from(t[3],"base64"),n=Buffer.from(t[4],"base64"),a=n.length,i=await new Promise((c,h)=>{u(e,o,a,{N:s,r:8,p:1},(g,d)=>{g?h(g):c(d)})});return b(i,n)}var f=class{config={driver:"scrypt",scryptCost:16384,bcryptRounds:12};configure(r){Object.assign(this.config,r)}async make(r){switch(this.config.driver){case"scrypt":return l(r,this.config.scryptCost);case"bcrypt":try{return(await import("bcrypt")).default.hash(r,this.config.bcryptRounds??12)}catch{throw new Error('bcrypt driver requires the "bcrypt" package. Install it: npm install bcrypt')}case"argon2":try{return(await import("argon2")).default.hash(r)}catch{throw new Error('argon2 driver requires the "argon2" package. Install it: npm install argon2')}default:throw new Error(`Unsupported hash driver: ${this.config.driver}`)}}async verify(r,t){if(t.startsWith("$scrypt$"))return m(r,t);if(t.startsWith("$2b$")||t.startsWith("$2a$")||t.startsWith("$2y$"))try{return(await import("bcrypt")).default.compare(r,t)}catch{throw new Error("bcrypt package required to verify bcrypt hashes.")}if(t.startsWith("$argon2"))try{return(await import("argon2")).default.verify(t,r)}catch{throw new Error("argon2 package required to verify argon2 hashes.")}return!1}needsRehash(r){if(this.config.driver==="scrypt"&&r.startsWith("$scrypt$")){let t=r.match(/N=(\d+)/);if(t)return parseInt(t[1],10)!==this.config.scryptCost}if(this.config.driver==="bcrypt"&&(r.startsWith("$2b$")||r.startsWith("$2a$"))){let t=r.match(/\$2[aby]\$(\d+)\$/);if(t)return parseInt(t[1],10)!==this.config.bcryptRounds}return this.config.driver==="scrypt"&&!r.startsWith("$scrypt$")||this.config.driver==="bcrypt"&&!r.startsWith("$2")||this.config.driver==="argon2"&&!r.startsWith("$argon2")}randomString(r=32){return p(Math.ceil(r/2)).toString("hex").slice(0,r)}randomToken(r=32){return p(r).toString("base64url")}},$=y("svelar.hash",()=>new f);export{$ as Hash};