galbe 0.1.6 → 0.1.8

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.
@@ -16,5 +16,5 @@ jobs:
16
16
  -H "Accept: application/vnd.github+json" \
17
17
  -H "Authorization: Bearer ${{ secrets.GH_WEBSITE_TOKEN }}" \
18
18
  -H "X-GitHub-Api-Version: 2022-11-28" \
19
- https://api.github.com/repos/pierre-cm/galbe-website/actions/workflows/ci.yml/dispatches \
19
+ https://api.github.com/repos/pierre-cm/galbe-website/actions/workflows/deploy.yml/dispatches \
20
20
  -d '{"ref":"main"}'
package/README.md CHANGED
@@ -12,7 +12,9 @@ Galbe is a fast, lightweight and highly customizable JavaScript web framework ba
12
12
  ## Getting started
13
13
 
14
14
  ```bash
15
- bun create galbe
15
+ bun create galbe app
16
+ cd app
17
+ bun install && bun dev
16
18
  ```
17
19
 
18
20
  ## Documentation
package/bin/cli.ts CHANGED
@@ -5,7 +5,7 @@ import type { RouteMeta } from '../src/routes'
5
5
  import { program } from 'commander'
6
6
  import { relative, resolve } from 'path'
7
7
  import { mkdir, readdir, lstat, rm } from 'fs/promises'
8
- import { metaAnalysis } from '../src/routes'
8
+ import { DEFAULT_ROUTE_PATTERN, metaAnalysis } from '../src/routes'
9
9
  import { randomUUID } from 'crypto'
10
10
  import { Galbe } from '../src'
11
11
 
@@ -14,7 +14,8 @@ const BUILD_ID = randomUUID()
14
14
 
15
15
  Bun.env.FORCE_COLOR = '1'
16
16
 
17
- const parseRoutes = async (routes?: string | string[]): Promise<{ path: string; meta: RouteMeta }[]> => {
17
+ const parseRoutes = async (routes?: boolean | string | string[]): Promise<{ path: string; meta: RouteMeta }[]> => {
18
+ routes = routes === true ? DEFAULT_ROUTE_PATTERN : routes
18
19
  if (!routes) return []
19
20
  let files: { path: string; meta: RouteMeta }[] = []
20
21
  if (typeof routes === 'string') {
@@ -61,11 +62,12 @@ program.name('galbe').description('CLI to execute galbe utilities').version('0.1
61
62
 
62
63
  program
63
64
  .command('dev')
64
- .description('Run a dev server running your galbe API')
65
+ .description('Start a dev server running your Galbe application')
65
66
  .argument('<string>', 'filename')
66
67
  .option('-p, --port <number>', 'port number', '')
68
+ .option('-w, --watch', 'watch file changes', 'true')
67
69
  .action(async (fileName, props) => {
68
- const { port } = props
70
+ const { port, watch } = props
69
71
  const devRoot = resolve(ROOT, '.galbe', 'dev')
70
72
  await mkdir(devRoot, { recursive: true })
71
73
  await Bun.write(
@@ -76,15 +78,15 @@ program
76
78
  await rm(resolve(ROOT, '.galbe', 'dev'), { recursive: true })
77
79
  })
78
80
 
79
- await $`BUN_ENV=development bun run --watch ${resolve(devRoot, 'index.ts')}`.cwd(ROOT)
81
+ await $`BUN_ENV=development bun run ${watch ? '--watch' : ''} ${resolve(devRoot, 'index.ts')}`.cwd(ROOT)
80
82
  })
81
83
 
82
84
  program
83
85
  .command('build')
84
- .description('Build your galbe API')
86
+ .description('undle your Galbe application')
85
87
  .argument('<string>', 'filename')
86
- .option('-o, --out <string>', 'output file', '')
87
- .option('-c, --compile', 'standalone executable', false)
88
+ .option('-o, --out <string>', 'output file/directory', '')
89
+ .option('-c, --compile', 'create a standalone executable', false)
88
90
  .action(async (fileName, props) => {
89
91
  const { out, compile } = props
90
92
  const g: Galbe = (await import(resolve(ROOT, fileName))).default
@@ -97,7 +99,7 @@ program
97
99
  buildIndex,
98
100
  '--target',
99
101
  'bun',
100
- ...(compile ? ['--compile', '--outfile', out ? out : 'api'] : ['--outdir', out ? out : 'dist'])
102
+ ...(compile ? ['--compile', '--outfile', out ? out : 'app'] : ['--outdir', out ? out : 'dist'])
101
103
  ].filter(c => c)
102
104
  Bun.spawn(cmds, {
103
105
  cwd: ROOT,
package/bun.lockb CHANGED
Binary file
@@ -1,5 +1,223 @@
1
- ### Create a project
1
+ # Getting started
2
2
 
3
- ```shell
4
- bun create pierre-cm/create-galbe
3
+ Galbe is a Javascript web framework for building fast and versatile backend servers with Bun.
4
+
5
+ Designed with simplicity in mind, Galbe allows you to quickly create and set up a project. In addition to its ease of use, Galbe also offers a range of useful features that help you focus on the core logic of your application.
6
+
7
+ ## Requirements
8
+
9
+ To start developing your Galbe project, you first need to install [Bun](https://bun.sh).
10
+
11
+ ## Automatic Installation
12
+
13
+ This is the recommended way of setting up a Galbe project.
14
+
15
+ ```bash
16
+ bun create galbe app
17
+ cd app
18
+ bun install
5
19
  ```
20
+
21
+ This will create a new project under `app` directory and install it.
22
+
23
+ Now you can start the dev server by running:
24
+
25
+ ```bash
26
+ bun dev
27
+ ```
28
+
29
+ This will start a web server on `localhost:3000`.
30
+
31
+ To verify that the project was setup correctly and is running, try to reach `localhost:3000/hello` endpoint, this should return following greeting message:
32
+
33
+ ```bash
34
+ curl localhost:3000/hello
35
+ Hello from Galbe!
36
+ ```
37
+
38
+ > [!TIP]
39
+ > By default, the dev server automatically reloads on every file change.
40
+
41
+ ## Manual Installation
42
+
43
+ Init a new Bun project and add Galbe as dependency:
44
+
45
+ ```bash
46
+ bun init
47
+ bun add galbe
48
+ ```
49
+
50
+ Open `package.json` file and add the following scripts:
51
+
52
+ ```json
53
+ {
54
+ "scripts": {
55
+ "dev": "galbe dev index.ts",
56
+ "build": "galbe build index.ts",
57
+ "test": "bun test"
58
+ }
59
+ }
60
+ ```
61
+
62
+ As you can see, those scripts rely on Galbe CLI to run and build the application. You will find more info about Galbe CLI available options in the next section [Galbe CLI](#galbe-cli).
63
+
64
+ This require your `index.ts` to export a default Galbe instance in order to work. As in the following example:
65
+
66
+ ```ts
67
+ import { Galbe } from 'galbe'
68
+
69
+ const g = new Galbe({ port: 3000 })
70
+ g.get('/hello', () => 'Hello Mom!')
71
+
72
+ export default galbe
73
+ ```
74
+
75
+ This is the recommended way to proceed but it is not mandatory. Galbe instances also provide a `listen` method that will allow you to manually start your server instance from the code.
76
+
77
+ > [!WARNING]
78
+ > In the case you decide to not rely on Galbe CLI to run/build your app, you will not have access to [Automatic Route Analyzer](routes.md#automatic-route-analyzer) feature.
79
+
80
+ ### Galbe CLI
81
+
82
+ ```bash
83
+ galbe <command> <argument> [options]
84
+ ```
85
+
86
+ Here are the available commands:
87
+
88
+ **dev**
89
+
90
+ Start a dev server running your Galbe application.
91
+
92
+ _argument_
93
+
94
+ The path of the file exporting your Galbe instance
95
+
96
+ _options_
97
+
98
+ - `--port` or `-p`: port number (default: 3000)
99
+ - `--watch` or `-w`: watch file changes (default: true)
100
+
101
+ **build**
102
+
103
+ Bundle your Galbe application.
104
+
105
+ _argument_
106
+
107
+ The path of the file exporting your Galbe instance
108
+
109
+ _options_
110
+
111
+ - `--out` or `-o`: output file | directory (default: app | dist )
112
+ - `--compile` or `-c`: create a standalone executable (default: false)
113
+
114
+ ## Configuration
115
+
116
+ To configure your Galbe server, you should pass your configuration to the Galbe constructor when you instanciate it.
117
+
118
+ ```ts
119
+ const galbe = new Galbe(configuration)
120
+ ```
121
+
122
+ ### Properties
123
+
124
+ **port**
125
+
126
+ The port number that the server will be listening on. Default is `3000`.
127
+
128
+ **basePath**
129
+
130
+ The base path is added as a prefix to all the routes created.
131
+
132
+ **routes**
133
+
134
+ A Glob Pattern or a list of Glob patterns defining the route files to be analyzed by the [Automatic Route Analyzer](routes.md#automatic-route-analyzer). Default is `src/**/*.route.{js,ts}`.
135
+
136
+ **plugin**
137
+
138
+ A property that can be used by plugins to add plugin's specific configuration. Every key should correspond to a [Unique Plugin Identifier](plugins.md).
139
+
140
+ ### Examples
141
+
142
+ A common way to handle server configuration is to create new file `galbe.config.(js|ts|json)` at the root of your project directory and import it in your code. Here is an example:
143
+
144
+ galbe.config.js
145
+
146
+ ```js
147
+ export default {
148
+ port: Bun.env.GALBE_PORT
149
+ routes: 'src/**/*.route.ts',
150
+ }
151
+ ```
152
+
153
+ index.js
154
+
155
+ ```js
156
+ import { Galbe } from 'galbe'
157
+ import config from './galbe.config'
158
+
159
+ export default new Galbe(config)
160
+ ```
161
+
162
+ > [!TIP]
163
+ > If you are using Typescript, you can import `GalbeConfig` type from galbe package to ensure type consistency for your configuration. Here is an example:
164
+ >
165
+ > ```ts
166
+ > import type { GalbeConfig } from 'galbe'
167
+ > const config: GalbeConfig = {
168
+ > port: Number(Bun.env.GALBE_PORT),
169
+ > routes: 'routes/*.route.ts'
170
+ > }
171
+ > export default config
172
+ > ```
173
+
174
+ ## Project Structure
175
+
176
+ One key aspect of Galbe, is its versatility in terms of project structure. This is partly allowed by the [Automatic Route Analyzer](routes.md#automatic-route-analyzer) and the `routes` config property which defaults to `src/**/*.route.{js,ts}`.
177
+
178
+ Here are two examples of valid project structures by default:
179
+
180
+ **Example 1**
181
+
182
+ ```txt
183
+ ┌── src
184
+ │ ├── hooks
185
+ │ │   └── log.hook.ts
186
+ │ ├── routes
187
+ │ │   ├── foo.route.ts
188
+ │ │   └── foo.route.ts
189
+ │ └── schemas
190
+ │ ├── bar.schema.ts
191
+ │ └── bar.schema.ts
192
+ ├── galbe.config.ts
193
+ ├── index.ts
194
+ ├── package.json
195
+ ├── README.md
196
+ └── tsconfig.json
197
+ ```
198
+
199
+ **Example 2**
200
+
201
+ ```txt
202
+ ┌── src
203
+ │ ├── hooks
204
+ │ │   └── log.hook.ts
205
+ │ ├── foo
206
+ │ │   ├── foo.route.ts
207
+ │ │   └── foo.schema.ts
208
+ │ └── bar
209
+ │ ├── bar.route.ts
210
+ │ └── bar.schema.ts
211
+ ├── galbe.config.ts
212
+ ├── index.ts
213
+ ├── package.json
214
+ ├── README.md
215
+ └── tsconfig.json
216
+ ```
217
+
218
+ In both cases, the [Automatic Route Analyzer](routes.md#automatic-route-analyzer) will analyze `foo.route.ts` and `bar.route.ts` Route Files to find route definitions.
219
+
220
+ You can find more info about Route Files definition in the [Routes Files](routes.md#route-files) section.
221
+
222
+ > [!NOTE]
223
+ > The examples provided above will work with the default configuration, but you can easily customize the routes property to fit your own project structure. Simply redefine the `routes` property with your own pattern(s) to to fit your own project structure.
@@ -0,0 +1 @@
1
+ # Handler
package/docs/hooks.md ADDED
@@ -0,0 +1,88 @@
1
+ # Hooks
2
+
3
+ Hooks provide a simple way to perform specific actions before and/or after reaching a specific route endpoint.
4
+
5
+ ## Hook Definition
6
+
7
+ ```ts
8
+ const hook = (context, next) => {
9
+ context.state['foo'] = 'bar'
10
+ await next()
11
+ console.log('Hook end')
12
+ }
13
+ ```
14
+
15
+ The hook takes only two arguments, a `context` object and a `next` function.
16
+
17
+ **context**
18
+
19
+ The `context` object contains the request information along with a state property that is modifiable and preserved across all hooks and the handler. It is useful for sharing information or objects across hooks and handler. You can find more information about it in the [Context]() section.
20
+
21
+ **next**
22
+
23
+ The `next` function calls the next hook in the hook list or the handler if the current hook is the last one declared. The `next` function should be called at most once. If it is omitted, Galbe will call it automatically at the end of the execution of the current hook.
24
+
25
+ > [!TIP]
26
+ > Hooks are interruptible objects, meaning they can return a response at any moment. This provides a powerful mechanism for implementing custom logic, such as authentication, authorization, caching, and more."
27
+
28
+ ## Hooks Declaration
29
+
30
+ Hooks should be declared just before the handler method in the [Route Definition]() method as a list of Hooks.
31
+
32
+ ```ts
33
+ galbe.get('foo', [ hook1, hook2, ... ], ctx => {})
34
+ ```
35
+
36
+ Hooks are called just before the [Handler]() in the order that they have been declared in the hook list of the [Route Definition](). To get a better understanding of hooks execution during the request lifecycle, you can refer to the [Lifecycle]() section.
37
+
38
+ ### Examples
39
+
40
+ Linear hooks declaration:
41
+
42
+ ```ts
43
+ const hook1 = context => {
44
+ console.log('hook1 called')
45
+ }
46
+ const hook2 = context => {
47
+ console.log('hook2 called')
48
+ }
49
+
50
+ galbe.get('example', [hook1, hook2], ctx => {
51
+ console.log('handler')
52
+ })
53
+ ```
54
+
55
+ ```bash
56
+ curl http://localhost:3000/example
57
+ hook1
58
+ hook2
59
+ handler
60
+ ```
61
+
62
+ Nested hooks declaration:
63
+
64
+ ```ts
65
+ const hook1 = (context, next) => {
66
+ console.log('hook1 start')
67
+ await next()
68
+ console.log('hook1 end')
69
+ }
70
+ const hook2 = context => {
71
+ console.log('hook2 start')
72
+ await next()
73
+ console.log('hook2 end')
74
+ }
75
+
76
+ galbe.get('example', [hook1, hook2], ctx => {
77
+ console.log('handler')
78
+ })
79
+ ```
80
+
81
+ ```bash
82
+ curl http://localhost:3000/example
83
+ hook1 start
84
+ hook2 start
85
+ handler
86
+ hook2 end
87
+ hook1 end
88
+ ```
@@ -0,0 +1 @@
1
+ # Plugins
package/docs/router.md ADDED
@@ -0,0 +1 @@
1
+ # Router
package/docs/routes.md ADDED
@@ -0,0 +1,124 @@
1
+ # Routes
2
+
3
+ Routes are the entry points for handling client requests in a Galbe application. In this section, we'll cover how to define routes, the various options available for route definitions, and how to use the Automatic Route Analyzer to simplify route setup.
4
+
5
+ ## Route Definition
6
+
7
+ Here is how to define routes in Galbe.
8
+
9
+ ```ts
10
+ galbe.[method](path: string, schema?: Schema, hooks?: Hooks[], handler: Handler)
11
+ ```
12
+
13
+ **method** ( get | post | put | delete | patch | options )
14
+
15
+ The [HTTP Request Method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) for the defined route.
16
+
17
+ **path** (string)
18
+
19
+ The path of the route. It should be composed of a sequence of segments separated by `/`. Each segment can be composed alphanumeric characters and dashes, but should not start or end with a dash.
20
+
21
+ There are two special segments:
22
+
23
+ - `:param` Any segment starting with `:` indicates a parameter segment.
24
+ - `*` To indicate a wildcard segment. This will match any segment or sequence of segments.
25
+
26
+ **schema** (Schema) _Optional_
27
+
28
+ See [Schemas](schemas.md) section.
29
+
30
+ **hooks** (Hook[]) _Optional_
31
+
32
+ See [Hooks](hooks.md) section.
33
+
34
+ **handler** (Handler)
35
+
36
+ See [Handler](handler.md) section.
37
+
38
+ ### Examples
39
+
40
+ **Basic route**
41
+
42
+ ```js
43
+ galbe.get('/foo', ctx => 'Hello World!')
44
+ ```
45
+
46
+ **Route with Schema**
47
+
48
+ <!-- prettier-ignore -->
49
+ ```js
50
+ galbe.get(
51
+ '/foo/:bar',
52
+ { params: { bar: $T.string() } },
53
+ ctx => `Hello ${ctx.params.bar} !`
54
+ )
55
+ ```
56
+
57
+ **Route with Hooks**
58
+
59
+ <!-- prettier-ignore -->
60
+ ```js
61
+ galbe.get(
62
+ '/foo/:bar',
63
+ [() => console.log('Hook1'), () => console.log('Hook2')],
64
+ ctx => `Hello ${ctx.params.bar} !`
65
+ )
66
+ ```
67
+
68
+ **Route with Schemas and Hooks**
69
+
70
+ <!-- prettier-ignore -->
71
+ ```js
72
+ galbe.get(
73
+ '/foo/:bar',
74
+ { params: { bar: $T.string() } },
75
+ [() => console.log('Hook')],
76
+ ctx => `Hello ${ctx.params.bar} !`
77
+ )
78
+ ```
79
+
80
+ ## Automatic Route Analyzer
81
+
82
+ > [!NOTE]
83
+ > This feature is only available if you run/build the app via the [Galbe CLI](getting-started.md#galbe-cli), which is the case by default if you created your app following the [Automatic Installation](getting-started.md#automatic-installation) step or if you configured your package.json to do so.
84
+
85
+ The Automatic Route Analyzer is responsible for analyzing all the Route Files of your project and setting up the route definitions for your Galbe server automatically. By default, the analyzer will search for Route Files matching paths like `src/**/*.route.{js,ts}`. This can be configured by modifying the value of `routes` property of your Galbe configuration. A value of `false` will disable the analyzer.
86
+
87
+ ### Route Files
88
+
89
+ In order to be properly analyzed, Route Files must export a default function that takes a Galbe instance as unique argument. Your routes should be defined using that Galbe instance. Here's a basic example in JavaScript:
90
+
91
+ ```ts
92
+ export default g => {
93
+ g.get('/foo/:bar', ctx => ctx.params.bar)
94
+ }
95
+ ```
96
+
97
+ The same example in Typescript:
98
+
99
+ ```ts
100
+ import type { Galbe } from 'galbe'
101
+ export default (g: Galbe) => {
102
+ g.get('/foo/:bar', ctx => ctx.params.bar)
103
+ }
104
+ ```
105
+
106
+ The Automatic Route Analyzer can also collect metadata about your Route File and your routes by analyzing multiline comments. This can be used by some plugins to perform specific tasks. Here's an example of a Route File with multiline comment metadata:
107
+
108
+ ```js
109
+ /**
110
+ * This is the header's head comment
111
+ * @annotation example of header's annotation
112
+ */
113
+ export default g => {
114
+ /**
115
+ * This is a route head comment
116
+ * @deprecated
117
+ * @tag tag1
118
+ * @tag tag2
119
+ */
120
+ g.get('/foo/:bar', ctx => ctx.params.bar)
121
+ }
122
+ ```
123
+
124
+ You will find more information about comment metadata and how to use them along with examples in the [Plugin](plugins.md) section.