h3ravel-monorepo 0.1.1

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 (176) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/.github/workflows/release.yml +42 -0
  4. package/.husky/pre-commit +1 -0
  5. package/LICENSE +21 -0
  6. package/README.md +65 -0
  7. package/docs/.gitkeep +0 -0
  8. package/eslint.config.js +17 -0
  9. package/examples/basic-app/.env.example +54 -0
  10. package/examples/basic-app/package.json +27 -0
  11. package/examples/basic-app/public/h3ravel-logo.svg +23 -0
  12. package/examples/basic-app/public/main.js +13 -0
  13. package/examples/basic-app/src/Exceptions/.gitkeep +0 -0
  14. package/examples/basic-app/src/config/app.ts +125 -0
  15. package/examples/basic-app/src/config/filesystem.ts +59 -0
  16. package/examples/basic-app/src/http/controllers/HomeController.ts +17 -0
  17. package/examples/basic-app/src/http/controllers/UserController.ts +29 -0
  18. package/examples/basic-app/src/http/middlewares/AuthMiddleware.ts +8 -0
  19. package/examples/basic-app/src/index.ts +30 -0
  20. package/examples/basic-app/src/resources/views/index.edge +383 -0
  21. package/examples/basic-app/src/routes/api.ts +17 -0
  22. package/examples/basic-app/src/routes/web.ts +6 -0
  23. package/examples/basic-app/src/storage/app/public/.gitkeep +0 -0
  24. package/examples/basic-app/tsconfig.json +8 -0
  25. package/package.json +36 -0
  26. package/packages/cache/node_modules/.bin/tsc +21 -0
  27. package/packages/cache/node_modules/.bin/tsserver +21 -0
  28. package/packages/cache/package.json +26 -0
  29. package/packages/cache/src/CacheManager.ts +1 -0
  30. package/packages/cache/src/Contracts/.gitkeep +0 -0
  31. package/packages/cache/src/Drivers/MemoryCache.ts +1 -0
  32. package/packages/cache/src/Drivers/RedisCache.ts +1 -0
  33. package/packages/cache/src/Helpers.ts +1 -0
  34. package/packages/cache/src/Providers/CacheServiceProvider.ts +16 -0
  35. package/packages/cache/src/index.ts +9 -0
  36. package/packages/cache/tests/.gitkeep +0 -0
  37. package/packages/cache/tsconfig.json +9 -0
  38. package/packages/cache/vite.config.ts +9 -0
  39. package/packages/config/node_modules/.bin/tsc +21 -0
  40. package/packages/config/node_modules/.bin/tsserver +21 -0
  41. package/packages/config/package.json +34 -0
  42. package/packages/config/src/ConfigRepository.ts +51 -0
  43. package/packages/config/src/Contracts/.gitkeep +0 -0
  44. package/packages/config/src/EnvLoader.ts +16 -0
  45. package/packages/config/src/Helpers.ts +1 -0
  46. package/packages/config/src/Providers/ConfigServiceProvider.ts +46 -0
  47. package/packages/config/src/index.ts +8 -0
  48. package/packages/config/tests/.gitkeep +0 -0
  49. package/packages/config/tsconfig.json +8 -0
  50. package/packages/config/vite.config.ts +9 -0
  51. package/packages/console/node_modules/.bin/tsc +21 -0
  52. package/packages/console/node_modules/.bin/tsserver +21 -0
  53. package/packages/console/package.json +26 -0
  54. package/packages/console/src/Commands/MakeController.ts +1 -0
  55. package/packages/console/src/Commands/MakeModel.ts +1 -0
  56. package/packages/console/src/Commands/MakeResource.ts +1 -0
  57. package/packages/console/src/Contracts/.gitkeep +0 -0
  58. package/packages/console/src/IO/.gitkeep +0 -0
  59. package/packages/console/src/Kernel.ts +1 -0
  60. package/packages/console/src/Musketeer.ts +4 -0
  61. package/packages/console/src/Providers/ConsoleServiceProvider.ts +16 -0
  62. package/packages/console/src/index.ts +10 -0
  63. package/packages/console/tests/.gitkeep +0 -0
  64. package/packages/console/tsconfig.json +8 -0
  65. package/packages/console/vite.config.ts +9 -0
  66. package/packages/core/node_modules/.bin/tsc +21 -0
  67. package/packages/core/node_modules/.bin/tsserver +21 -0
  68. package/packages/core/package.json +29 -0
  69. package/packages/core/src/Application.ts +164 -0
  70. package/packages/core/src/Container.ts +71 -0
  71. package/packages/core/src/Contracts/.gitkeep +0 -0
  72. package/packages/core/src/Contracts/BindingsContract.ts +37 -0
  73. package/packages/core/src/Controller.ts +20 -0
  74. package/packages/core/src/Exceptions/Handler.ts +1 -0
  75. package/packages/core/src/Http/Kernel.ts +47 -0
  76. package/packages/core/src/Providers/AppServiceProvider.ts +18 -0
  77. package/packages/core/src/Providers/ViewServiceProvider.ts +19 -0
  78. package/packages/core/src/ServiceProvider.ts +21 -0
  79. package/packages/core/src/Utils/PathLoader.ts +46 -0
  80. package/packages/core/src/index.ts +14 -0
  81. package/packages/core/tests/.gitkeep +0 -0
  82. package/packages/core/tsconfig.json +8 -0
  83. package/packages/core/vite.config.ts +9 -0
  84. package/packages/database/node_modules/.bin/tsc +21 -0
  85. package/packages/database/node_modules/.bin/tsserver +21 -0
  86. package/packages/database/package.json +26 -0
  87. package/packages/database/src/Contracts/.gitkeep +0 -0
  88. package/packages/database/src/Migrations/.gitkeep +0 -0
  89. package/packages/database/src/Model.ts +1 -0
  90. package/packages/database/src/Providers/DatabaseServiceProvider.ts +16 -0
  91. package/packages/database/src/Query/.gitkeep +0 -0
  92. package/packages/database/src/index.ts +6 -0
  93. package/packages/database/src/tests/.gitkeep +0 -0
  94. package/packages/database/tsconfig.json +8 -0
  95. package/packages/database/vite.config.ts +9 -0
  96. package/packages/http/node_modules/.bin/tsc +21 -0
  97. package/packages/http/node_modules/.bin/tsserver +21 -0
  98. package/packages/http/package.json +28 -0
  99. package/packages/http/src/Contracts/ControllerContracts.ts +13 -0
  100. package/packages/http/src/Contracts/HttpContract.ts +7 -0
  101. package/packages/http/src/Middleware/LogRequests.ts +9 -0
  102. package/packages/http/src/Middleware.ts +5 -0
  103. package/packages/http/src/Providers/HttpServiceProvider.ts +22 -0
  104. package/packages/http/src/Request.ts +59 -0
  105. package/packages/http/src/Resources/ApiResource.ts +39 -0
  106. package/packages/http/src/Resources/JsonResource.ts +201 -0
  107. package/packages/http/src/Response.ts +80 -0
  108. package/packages/http/src/index.ts +13 -0
  109. package/packages/http/tests/.gitkeep +0 -0
  110. package/packages/http/tsconfig.json +8 -0
  111. package/packages/http/vite.config.ts +9 -0
  112. package/packages/mail/node_modules/.bin/tsc +21 -0
  113. package/packages/mail/node_modules/.bin/tsserver +21 -0
  114. package/packages/mail/package.json +26 -0
  115. package/packages/mail/src/Contracts/.gitkeep +0 -0
  116. package/packages/mail/src/Drivers/SES.ts +1 -0
  117. package/packages/mail/src/Drivers/SMTP.ts +1 -0
  118. package/packages/mail/src/Helpers.ts +1 -0
  119. package/packages/mail/src/Mailable.ts +1 -0
  120. package/packages/mail/src/Mailer.ts +1 -0
  121. package/packages/mail/src/Providers/MailServiceProvider.ts +16 -0
  122. package/packages/mail/src/index.ts +10 -0
  123. package/packages/mail/tests/.gitkeep +0 -0
  124. package/packages/mail/tsconfig.json +8 -0
  125. package/packages/mail/vite.config.ts +9 -0
  126. package/packages/queue/node_modules/.bin/tsc +21 -0
  127. package/packages/queue/node_modules/.bin/tsserver +21 -0
  128. package/packages/queue/package.json +26 -0
  129. package/packages/queue/src/Contracts/.gitkeep +0 -0
  130. package/packages/queue/src/Drivers/MemoryDriver.ts +1 -0
  131. package/packages/queue/src/Drivers/RedisDriver.ts +1 -0
  132. package/packages/queue/src/Jobs/.gitkeep +0 -0
  133. package/packages/queue/src/Providers/QueueServiceProvider.ts +16 -0
  134. package/packages/queue/src/QueueManager.ts +1 -0
  135. package/packages/queue/src/Workers/.gitkeep +0 -0
  136. package/packages/queue/src/index.ts +8 -0
  137. package/packages/queue/tests/.gitkeep +0 -0
  138. package/packages/queue/tsconfig.json +8 -0
  139. package/packages/queue/vite.config.ts +9 -0
  140. package/packages/router/node_modules/.bin/tsc +21 -0
  141. package/packages/router/node_modules/.bin/tsserver +21 -0
  142. package/packages/router/package.json +27 -0
  143. package/packages/router/src/Contracts/.gitkeep +0 -0
  144. package/packages/router/src/Controller.ts +1 -0
  145. package/packages/router/src/Decorators/ApiResource.ts +1 -0
  146. package/packages/router/src/Decorators/Controller.ts +1 -0
  147. package/packages/router/src/Decorators/Get.ts +1 -0
  148. package/packages/router/src/Decorators/Middleware.ts +1 -0
  149. package/packages/router/src/Decorators/Post.ts +1 -0
  150. package/packages/router/src/Middleware/.gitkeep +0 -0
  151. package/packages/router/src/Providers/AssetsServiceProvider.ts +53 -0
  152. package/packages/router/src/Providers/RouteServiceProvider.ts +44 -0
  153. package/packages/router/src/Route.ts +1 -0
  154. package/packages/router/src/Router.ts +180 -0
  155. package/packages/router/src/index.ts +14 -0
  156. package/packages/router/tests/.gitkeep +0 -0
  157. package/packages/router/tsconfig.json +8 -0
  158. package/packages/router/vite.config.ts +9 -0
  159. package/packages/support/node_modules/.bin/tsc +21 -0
  160. package/packages/support/node_modules/.bin/tsserver +21 -0
  161. package/packages/support/package.json +26 -0
  162. package/packages/support/src/Contracts/ObjContract.ts +53 -0
  163. package/packages/support/src/Contracts/StrContract.ts +6 -0
  164. package/packages/support/src/Facades/.gitkeep +0 -0
  165. package/packages/support/src/Helpers/Arr.ts +33 -0
  166. package/packages/support/src/Helpers/Number.ts +194 -0
  167. package/packages/support/src/Helpers/Obj.ts +220 -0
  168. package/packages/support/src/Helpers/Str.ts +256 -0
  169. package/packages/support/src/index.ts +10 -0
  170. package/packages/support/tests/.gitkeep +0 -0
  171. package/packages/support/tsconfig.json +8 -0
  172. package/packages/support/vite.config.ts +9 -0
  173. package/pnpm-workspace.yaml +7 -0
  174. package/tsconfig.json +26 -0
  175. package/tsup.config.ts +15 -0
  176. package/vite.base.config.ts +12 -0
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@h3ravel/router",
3
+ "version": "0.1.1",
4
+ "description": "Route facade, decorators and controller system for H3ravel.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "scripts": {
12
+ "barrel": "barrelsby --directory src --delete --singleQuotes",
13
+ "build": "tsup",
14
+ "dev": "tsx watch src/index.ts",
15
+ "start": "node dist/index.js",
16
+ "lint": "eslint . --ext .ts",
17
+ "test": "vitest"
18
+ },
19
+ "dependencies": {
20
+ "@h3ravel/core": "workspace:*",
21
+ "@h3ravel/support": "workspace:*",
22
+ "h3": "^2.0.0-beta.1"
23
+ },
24
+ "devDependencies": {
25
+ "typescript": "^5.4.0"
26
+ }
27
+ }
File without changes
@@ -0,0 +1 @@
1
+ export default class { }
@@ -0,0 +1 @@
1
+ export default class { }
@@ -0,0 +1 @@
1
+ export default class { }
@@ -0,0 +1 @@
1
+ export default class { }
@@ -0,0 +1 @@
1
+ export default class { }
@@ -0,0 +1 @@
1
+ export default class { }
File without changes
@@ -0,0 +1,53 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+
3
+ import { ServiceProvider } from '@h3ravel/core'
4
+ import { before } from "@h3ravel/support";
5
+ import { join } from "node:path";
6
+ import { serveStatic } from 'h3'
7
+ import { statSync } from "node:fs";
8
+
9
+ /**
10
+ * Handles public assets loading
11
+ *
12
+ * Auto-Registered
13
+ */
14
+ export class AssetsServiceProvider extends ServiceProvider {
15
+ register () {
16
+ const app = this.app.make('router')
17
+ const config = this.app.make('config')
18
+ const fsconfig = config.get('filesystem')
19
+ const publicPath = this.app.getPath('public')
20
+
21
+ app.middleware(`/${fsconfig.public_mask}/**`, (event) => {
22
+ return serveStatic(event, {
23
+ indexNames: ["/index.html"],
24
+ getContents: (id) => {
25
+ const newId = id.replace(`/${fsconfig.public_mask}/`, '')
26
+ return readFile(join(before(publicPath, newId), newId))
27
+ },
28
+ getMeta: async (id) => {
29
+ const newId = id.replace(`/${fsconfig.public_mask}/`, '')
30
+ const stats = await stat(join(before(publicPath, newId), newId)).catch(() => { });
31
+ if (stats?.isFile()) {
32
+ return {
33
+ size: stats.size,
34
+ mtime: stats.mtimeMs,
35
+ };
36
+ }
37
+ },
38
+ });
39
+ })
40
+
41
+ this.app.singleton('asset', () => {
42
+ return (key: string, def = '') => {
43
+ try {
44
+ statSync(join(before(publicPath, key), key))
45
+ } catch {
46
+ key = def
47
+ }
48
+
49
+ return join(fsconfig.public_mask, key)
50
+ }
51
+ })
52
+ }
53
+ }
@@ -0,0 +1,44 @@
1
+ import { Router } from '../Router'
2
+ import { ServiceProvider } from '@h3ravel/core'
3
+ import path from 'node:path'
4
+ import { readdir } from 'node:fs/promises'
5
+
6
+ /**
7
+ * Handles routing registration
8
+ *
9
+ * Load route files (web.ts, api.ts).
10
+ * Map controllers to routes.
11
+ * Register route-related middleware.
12
+ *
13
+ * Auto-Registered
14
+ */
15
+ export class RouteServiceProvider extends ServiceProvider {
16
+ register () {
17
+ this.app.singleton('router', () => {
18
+ const h3App = this.app.make('http.app')
19
+ return new Router(h3App, this.app)
20
+ })
21
+ }
22
+
23
+ /**
24
+ * Load routes from src/routes
25
+ */
26
+ async boot () {
27
+ try {
28
+ const routePath = this.app.getPath('routes')
29
+
30
+ const files = await readdir(routePath);
31
+
32
+ for (let i = 0; i < files.length; i++) {
33
+ const routesModule = await import(path.join(routePath, files[i]))
34
+
35
+ if (typeof routesModule.default === 'function') {
36
+ const router = this.app.make('router')
37
+ routesModule.default(router)
38
+ }
39
+ }
40
+ } catch (e) {
41
+ console.warn('No web routes found or failed to load:', e)
42
+ }
43
+ }
44
+ }
@@ -0,0 +1 @@
1
+ export default class { }
@@ -0,0 +1,180 @@
1
+ import { H3Event, Middleware, MiddlewareOptions, type H3 } from 'h3'
2
+ import { Application, Controller, Kernel } from '@h3ravel/core'
3
+ import { Middleware as HttpMiddleware } from '@h3ravel/http'
4
+ import { HttpContext } from '@h3ravel/http'
5
+ import { afterLast } from '@h3ravel/support'
6
+
7
+ type EventHandler = (ctx: HttpContext) => unknown
8
+
9
+ interface RouteDefinition {
10
+ method: string
11
+ path: string
12
+ name?: string
13
+ handler: EventHandler
14
+ }
15
+
16
+ export class Router {
17
+ private routes: RouteDefinition[] = []
18
+ private groupPrefix = ''
19
+ private groupMiddleware: EventHandler[] = []
20
+
21
+ constructor(private h3App: H3, private app: Application) { }
22
+
23
+ /**
24
+ * Route Resolver
25
+ *
26
+ * @param handler
27
+ * @param middleware
28
+ * @returns
29
+ */
30
+ private resolveHandler (handler: EventHandler, middleware: HttpMiddleware[] = []) {
31
+ return async (event: H3Event) => {
32
+ const kernel = new Kernel(middleware)
33
+ return kernel.handle(event, (ctx) => Promise.resolve(handler(ctx)))
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Add a route to the stack
39
+ *
40
+ * @param method
41
+ * @param path
42
+ * @param handler
43
+ * @param name
44
+ * @param middleware
45
+ */
46
+ private addRoute (
47
+ method: string,
48
+ path: string,
49
+ handler: EventHandler,
50
+ name?: string,
51
+ middleware: HttpMiddleware[] = []
52
+ ) {
53
+ const fullPath = `${this.groupPrefix}${path}`.replace(/\/+/g, '/')
54
+ this.routes.push({ method, path: fullPath, name, handler })
55
+ this.h3App[method as 'get'](fullPath, this.resolveHandler(handler, middleware))
56
+ }
57
+
58
+ private resolveControllerOrHandler (
59
+ handler: EventHandler | (new (...args: any[]) => Controller),
60
+ methodName?: string
61
+ ): EventHandler {
62
+ if (typeof handler === 'function' && (handler as any).prototype instanceof Controller) {
63
+ return (ctx) => {
64
+ const controller = new (handler as new (...args: any[]) => Controller)(this.app)
65
+ const action = (methodName || 'index') as keyof Controller
66
+
67
+ if (typeof controller[action] !== 'function') {
68
+ throw new Error(`Method "${action}" not found on controller ${handler.name}`)
69
+ }
70
+
71
+ return controller[action](ctx)
72
+ }
73
+ }
74
+
75
+ return handler as EventHandler
76
+ }
77
+
78
+
79
+ get (
80
+ path: string,
81
+ handler: EventHandler | (new (...args: any[]) => Controller),
82
+ methodName?: string, name?: string, middleware: HttpMiddleware[] = []
83
+ ) {
84
+ this.addRoute('get', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)
85
+ }
86
+
87
+ post (
88
+ path: string,
89
+ handler: EventHandler | (new (...args: any[]) => Controller),
90
+ methodName?: string, name?: string, middleware: HttpMiddleware[] = []
91
+ ) {
92
+ this.addRoute('post', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)
93
+ }
94
+
95
+ put (
96
+ path: string,
97
+ handler: EventHandler | (new (...args: any[]) => Controller),
98
+ methodName?: string, name?: string, middleware: HttpMiddleware[] = []
99
+ ) {
100
+ this.addRoute('put', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)
101
+ }
102
+
103
+ delete (
104
+ path: string,
105
+ handler: EventHandler | (new (...args: any[]) => Controller),
106
+ methodName?: string, name?: string, middleware: HttpMiddleware[] = []
107
+ ) {
108
+ this.addRoute('delete', path, this.resolveControllerOrHandler(handler, methodName), name, middleware)
109
+ }
110
+
111
+ /**
112
+ * API Resource support
113
+ *
114
+ * @param path
115
+ * @param controller
116
+ */
117
+ apiResource (
118
+ path: string,
119
+ Controller: new (app: Application) => Controller,
120
+ middleware: HttpMiddleware[] = []
121
+ ) {
122
+ path = path.replace(/\//g, '/')
123
+
124
+ const name = afterLast(path, '/')
125
+ const basePath = `/${path}`.replace(/\/+/g, '/')
126
+
127
+ const controller = new Controller(this.app)
128
+
129
+ this.addRoute('get', basePath, controller.index.bind(controller), `${name}.index`, middleware)
130
+ this.addRoute('post', basePath, controller.store.bind(controller), `${name}.store`, middleware)
131
+ this.addRoute('get', `${basePath}/:id`, controller.show.bind(controller), `${name}.show`, middleware)
132
+ this.addRoute('put', `${basePath}/:id`, controller.update.bind(controller), `${name}.update`, middleware)
133
+ this.addRoute('patch', `${basePath}/:id`, controller.update.bind(controller), `${name}.update`, middleware)
134
+ this.addRoute('delete', `${basePath}/:id`, controller.destroy.bind(controller), `${name}.destroy`, middleware)
135
+ }
136
+
137
+ /**
138
+ * Named route URL generator
139
+ *
140
+ * @param name
141
+ * @param params
142
+ * @returns
143
+ */
144
+ route (name: string, params: Record<string, string> = {}): string | undefined {
145
+ const found = this.routes.find(r => r.name === name)
146
+ if (!found) return undefined
147
+
148
+ let url = found.path
149
+ for (const [key, value] of Object.entries(params)) {
150
+ url = url.replace(`:${key}`, value)
151
+ }
152
+ return url
153
+ }
154
+
155
+ /**
156
+ * Grouping
157
+ *
158
+ * @param options
159
+ * @param callback
160
+ */
161
+ group (options: { prefix?: string; middleware?: EventHandler[] }, callback: () => void) {
162
+ const prevPrefix = this.groupPrefix
163
+ const prevMiddleware = [...this.groupMiddleware]
164
+
165
+ this.groupPrefix += options.prefix || ''
166
+ this.groupMiddleware.push(...(options.middleware || []))
167
+
168
+ callback()
169
+
170
+ /**
171
+ * Restore state after group
172
+ */
173
+ this.groupPrefix = prevPrefix
174
+ this.groupMiddleware = prevMiddleware
175
+ }
176
+
177
+ middleware (path: string, handler: Middleware, opts?: MiddlewareOptions) {
178
+ this.h3App.use(path, handler, opts)
179
+ }
180
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @file Automatically generated by barrelsby.
3
+ */
4
+
5
+ export * from './Controller';
6
+ export * from './Route';
7
+ export * from './Router';
8
+ export * from './Decorators/ApiResource';
9
+ export * from './Decorators/Controller';
10
+ export * from './Decorators/Get';
11
+ export * from './Decorators/Middleware';
12
+ export * from './Decorators/Post';
13
+ export * from './Providers/AssetsServiceProvider';
14
+ export * from './Providers/RouteServiceProvider';
File without changes
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist"
5
+ },
6
+ "include": ["src"],
7
+ "exclude": ["dist", "node_modules"]
8
+ }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'tsup'
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['esm', 'cjs'],
6
+ dts: true,
7
+ sourcemap: true,
8
+ clean: true
9
+ })
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/node_modules:/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/node_modules:/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/typescript@5.8.3/node_modules:/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/node_modules:/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/node_modules:/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/typescript@5.8.3/node_modules:/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
19
+ else
20
+ exec node "$basedir/../typescript/bin/tsc" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/node_modules:/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/node_modules:/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/typescript@5.8.3/node_modules:/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/node_modules:/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/node_modules:/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/typescript@5.8.3/node_modules:/Users/ralph/Documents/Marx/Toneflix/OpenSource/H3ravel/framework/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
19
+ else
20
+ exec node "$basedir/../typescript/bin/tsserver" "$@"
21
+ fi
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@h3ravel/support",
3
+ "version": "0.1.1",
4
+ "description": "Shared helpers, facades and utilities for H3ravel.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "scripts": {
12
+ "barrel": "barrelsby --directory src --delete --singleQuotes",
13
+ "build": "tsup",
14
+ "dev": "tsx watch src/index.ts",
15
+ "start": "node dist/index.js",
16
+ "lint": "eslint . --ext .ts",
17
+ "test": "vitest"
18
+ },
19
+ "dependencies": {
20
+ "@h3ravel/core": "workspace:*",
21
+ "h3": "^2.0.0-beta.1"
22
+ },
23
+ "devDependencies": {
24
+ "typescript": "^5.4.0"
25
+ }
26
+ }
@@ -0,0 +1,53 @@
1
+ import { CamelToSnakeCase } from "./StrContract"
2
+
3
+ /**
4
+ * Adds a dot prefix to nested keys
5
+ */
6
+ type DotPrefix<T extends string, U extends string> =
7
+ T extends '' ? U : `${T}.${U}`
8
+
9
+ /**
10
+ * Converts a union of objects into a single merged object
11
+ */
12
+ type MergeUnion<T> =
13
+ (T extends any ? (k: T) => void : never) extends
14
+ (k: infer I) => void ? { [K in keyof I]: I[K] } : never
15
+
16
+ /**
17
+ * Flattens nested objects into dotted keys
18
+ */
19
+ export type DotFlatten<T, Prefix extends string = ''> = MergeUnion<{
20
+ [K in keyof T & string]:
21
+ T[K] extends Record<string, any>
22
+ ? DotFlatten<T[K], DotPrefix<Prefix, K>>
23
+ : { [P in DotPrefix<Prefix, K>]: T[K] }
24
+ }[keyof T & string]>
25
+
26
+ /**
27
+ * Builds "nested.key" paths for autocompletion
28
+ */
29
+ export type DotNestedKeys<T> = {
30
+ [K in keyof T & string]:
31
+ T[K] extends object
32
+ ? `${K}` | `${K}.${DotNestedKeys<T[K]>}`
33
+ : `${K}`
34
+ }[keyof T & string]
35
+
36
+ /**
37
+ * Retrieves type at a given dot-path
38
+ */
39
+ export type DotNestedValue<T, Path extends string> =
40
+ Path extends `${infer Key}.${infer Rest}`
41
+ ? Key extends keyof T
42
+ ? DotNestedValue<T[Key], Rest>
43
+ : never
44
+ : Path extends keyof T
45
+ ? T[Path]
46
+ : never
47
+
48
+ /**
49
+ * Convert CamelCased Object keys to snake_case
50
+ */
51
+ export type KeysToSnakeCase<T> = {
52
+ [K in keyof T as CamelToSnakeCase<string & K>]: T[K]
53
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Converts CamelCased strings to snake_case
3
+ */
4
+ export type CamelToSnakeCase<S extends string> = S extends `${infer T}${infer U}` ?
5
+ `${T extends Capitalize<T> ? '_' : ''}${Lowercase<T>}${CamelToSnakeCase<U>}` :
6
+ S
File without changes
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Splits an array into chunks of a specified size.
3
+ *
4
+ * @template T - Type of elements in the array
5
+ * @param arr - The input array
6
+ * @param size - Size of each chunk (default: 2)
7
+ * @returns An array of chunks (arrays)
8
+ */
9
+ export const chunk = <T> (arr: T[], size: number = 2): T[][] => {
10
+ if (size <= 0) throw new Error("Chunk size must be greater than 0")
11
+
12
+ const chunks: T[][] = []
13
+
14
+ for (let i = 0; i < arr.length; i += size) {
15
+ chunks.push(arr.slice(i, i + size))
16
+ }
17
+
18
+ return chunks
19
+ }
20
+
21
+
22
+ /**
23
+ * Generates an array of sequential numbers.
24
+ *
25
+ * @param size - Number of elements in the range
26
+ * @param startAt - Starting number (default: 0)
27
+ * @returns An array of numbers from startAt to startAt + size - 1
28
+ */
29
+ export const range = (size: number, startAt: number = 0): number[] => {
30
+ if (size <= 0 || !Number.isFinite(size)) return []
31
+
32
+ return Array.from({ length: size }, (_, i) => startAt + i)
33
+ }