@orieljs/framework 0.1.0-alpha.5 → 0.1.0-alpha.7

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 (87) hide show
  1. package/NOTICE +7 -0
  2. package/README.md +10 -1
  3. package/TRADEMARKS.md +33 -0
  4. package/dist/{chunk-WNJP46B7.js → chunk-4MWG3B7G.js} +1785 -626
  5. package/dist/chunk-4MWG3B7G.js.map +1 -0
  6. package/dist/chunk-7ZQZYDOC.js +3253 -0
  7. package/dist/chunk-7ZQZYDOC.js.map +1 -0
  8. package/dist/{chunk-BSQKOLSK.js → chunk-GVNLZZTN.js} +1 -1
  9. package/dist/chunk-GVNLZZTN.js.map +1 -0
  10. package/dist/{chunk-A5XRLEWM.js → chunk-VOYW3R5J.js} +4 -4
  11. package/dist/chunk-VOYW3R5J.js.map +1 -0
  12. package/dist/contracts.d.ts +535 -17
  13. package/dist/contracts.js +1 -1
  14. package/dist/index.d-WQpfdIbG.d.ts +630 -0
  15. package/dist/index.d.ts +2202 -5952
  16. package/dist/index.js +4900 -944
  17. package/dist/index.js.map +1 -1
  18. package/dist/{jsx-runtime-WKTl3EEw.d.ts → jsx-runtime-6um4Mwfb.d.ts} +97 -51
  19. package/dist/jsx-runtime.d.ts +2 -2
  20. package/dist/jsx-runtime.js +3 -3
  21. package/dist/{testing-BErengYY.d.ts → testing-CKwfWJGn.d.ts} +313 -994
  22. package/dist/testing.d.ts +2 -2
  23. package/dist/testing.js +19 -5
  24. package/docs/authentication.md +487 -0
  25. package/docs/authorization.md +435 -0
  26. package/docs/cache.md +647 -0
  27. package/docs/collections.md +2270 -0
  28. package/docs/configuration.md +334 -0
  29. package/docs/console.md +651 -0
  30. package/docs/container.md +430 -0
  31. package/docs/controllers.md +406 -0
  32. package/docs/csrf.md +126 -0
  33. package/docs/database-testing.md +144 -0
  34. package/docs/database.md +236 -0
  35. package/docs/deployment.md +276 -0
  36. package/docs/eloquent-collections.md +218 -0
  37. package/docs/eloquent-factories.md +255 -0
  38. package/docs/eloquent-mutators.md +254 -0
  39. package/docs/eloquent-observers.md +145 -0
  40. package/docs/eloquent-relationships.md +557 -0
  41. package/docs/eloquent.md +494 -0
  42. package/docs/encryption.md +104 -0
  43. package/docs/errors.md +318 -0
  44. package/docs/events.md +336 -0
  45. package/docs/facades.md +278 -0
  46. package/docs/hashing.md +118 -0
  47. package/docs/helpers.md +1281 -0
  48. package/docs/http-tests.md +386 -0
  49. package/docs/inertia.md +485 -0
  50. package/docs/installation.md +209 -0
  51. package/docs/lifecycle.md +234 -0
  52. package/docs/live-tests.md +226 -0
  53. package/docs/live.md +910 -0
  54. package/docs/logging.md +255 -0
  55. package/docs/mail.md +619 -0
  56. package/docs/middleware.md +384 -0
  57. package/docs/migrations.md +416 -0
  58. package/docs/mocking.md +264 -0
  59. package/docs/navigation.json +273 -0
  60. package/docs/notifications.md +225 -0
  61. package/docs/pagination.md +247 -0
  62. package/docs/passwords.md +207 -0
  63. package/docs/providers.md +187 -0
  64. package/docs/queries.md +600 -0
  65. package/docs/queues.md +330 -0
  66. package/docs/requests.md +533 -0
  67. package/docs/responses.md +444 -0
  68. package/docs/routing.md +738 -0
  69. package/docs/scheduling.md +277 -0
  70. package/docs/seeding.md +122 -0
  71. package/docs/session.md +409 -0
  72. package/docs/starter-kits.md +396 -0
  73. package/docs/storage.md +192 -0
  74. package/docs/structure.md +264 -0
  75. package/docs/testing.md +165 -0
  76. package/docs/time-travel.md +138 -0
  77. package/docs/validation.md +1792 -0
  78. package/docs/verification.md +152 -0
  79. package/docs/views.md +566 -0
  80. package/docs/vite.md +322 -0
  81. package/package.json +34 -32
  82. package/dist/chunk-A5XRLEWM.js.map +0 -1
  83. package/dist/chunk-BSQKOLSK.js.map +0 -1
  84. package/dist/chunk-PM5YTG57.js +0 -880
  85. package/dist/chunk-PM5YTG57.js.map +0 -1
  86. package/dist/chunk-WNJP46B7.js.map +0 -1
  87. package/dist/index.d-DOlTeG-8.d.ts +0 -99
@@ -0,0 +1,334 @@
1
+ # Configuration
2
+
3
+ Your app's settings live in the `config` folder, one TypeScript file per part of the framework, with the values that
4
+ differ per machine in `.env`.
5
+
6
+ ## Introduction
7
+
8
+ Each file in `config` is a TypeScript module whose default export is an object. The file's name is the first part of
9
+ every key it holds: `name` in `config/app.ts` is `app.name`. A new app has `app`, `auth`, `cache`, `database`,
10
+ `filesystems`, `hashing`, `http`, `logging`, `mail`, `queue`, `services`, `session` and `view`, and the Inertia kits
11
+ add `inertia`:
12
+
13
+ ```ts title="config/app.ts"
14
+ import { env } from '@orieljs/framework'
15
+
16
+ export default {
17
+ name: env('APP_NAME', 'Oriel'),
18
+ env: env('APP_ENV', 'production'),
19
+ debug: env('APP_DEBUG', false),
20
+ url: env('APP_URL', 'http://localhost'),
21
+ timezone: 'UTC',
22
+ locale: env('APP_LOCALE', 'en'),
23
+ cipher: 'AES-256-GCM',
24
+ key: env('APP_KEY'),
25
+ previous_keys: String(env('APP_PREVIOUS_KEYS', '')).split(',').filter(Boolean),
26
+ }
27
+ ```
28
+
29
+ Oriel imports every `.ts`, `.js` and `.mjs` file directly in `config` when it creates your app, before any service
30
+ provider registers. A file is plain code, so it can compute a value, as `previous_keys` does, or build a path from
31
+ `import.meta.dirname`, as `config/database.ts` does for the SQLite file. Each app gets its own copy of the values, so
32
+ a value you change in one test never reaches the next.
33
+
34
+ A file runs once per process. A change to it, or to `.env`, applies when the process starts again, which
35
+ `node oriel serve --watch` does for you.
36
+
37
+ #### The `about` command
38
+
39
+ `about` shows an overview of your app: its name, the Oriel and Node versions, the environment, whether debug mode is
40
+ on, and its URL:
41
+
42
+ ```sh
43
+ node oriel about
44
+ ```
45
+
46
+ Laravel's `--only` option and `config:show` command aren't in Oriel.
47
+
48
+ ## Environment configuration
49
+
50
+ Some values differ between your machine and your servers: the database's password, the mail server, the debug mode.
51
+ They go in the `.env` file at the root of your app, and the config files read them with `env()`. A new app has a
52
+ `.env.example` file listing the variables it uses, and the installer copies it to `.env` for you.
53
+
54
+ If you work in a team, keep `.env.example` in your repository with placeholder values, so the others see which
55
+ variables your app needs.
56
+
57
+ > [!NOTE]
58
+ > A variable already set in the environment, by your shell, your server or your container, is never overwritten:
59
+ > its value wins over the one in `.env`.
60
+
61
+ #### Environment file security
62
+
63
+ `.env` is ignored by git in a new app, and should stay out of your repository: each machine has its own, and its
64
+ secrets would be exposed to anyone who can read the repository. Laravel can encrypt an environment file so that it can
65
+ be committed (`env:encrypt`); Oriel can't, so give your servers their values through their environment or their own
66
+ `.env`.
67
+
68
+ #### Additional environment files
69
+
70
+ When `APP_ENV` is set in the environment before your app starts, and a `.env.<APP_ENV>` file exists, Oriel loads that
71
+ file instead of `.env`, not as well: with `APP_ENV=staging`, a variable that is only in `.env` isn't set. When the
72
+ file doesn't exist, `.env` is loaded. `APP_ENV` inside `.env` doesn't choose a file, and there is no `--env` option.
73
+
74
+ Your tests run with `APP_ENV=testing`, so a `.env.testing` file, when you add one, replaces `.env` in your tests.
75
+
76
+ > [!WARNING]
77
+ > Bun loads `.env`, and its own files such as `.env.local`, into the environment itself, before your app starts. As
78
+ > Oriel never overwrites a variable, on Bun the values in `.env` win over those in `.env.<APP_ENV>`, which only adds
79
+ > the variables `.env` doesn't have. On Bun, keep one `.env` per machine, or set the variables in the environment.
80
+
81
+ ### Environment variable types
82
+
83
+ The values in `.env` are text. `env()` turns a few words into other values, whatever their case:
84
+
85
+ | `.env` value | `env()` value |
86
+ | --- | --- |
87
+ | `true`, `(true)` | `true` |
88
+ | `false`, `(false)` | `false` |
89
+ | `empty`, `(empty)` | `''` |
90
+ | `null`, `(null)` | `null` |
91
+
92
+ Nothing else is converted. A number stays text: with `SESSION_LIFETIME=120` in `.env`, `env('SESSION_LIFETIME', 120)` is
93
+ the string `'120'`, and only the default, used when the variable isn't set, is the number. Wrap the call where you need
94
+ a number, as a new app's config files do: `Number(env('SESSION_LIFETIME', 120))`. In the same way, debug mode is on only
95
+ for `APP_DEBUG=true`: `APP_DEBUG=1` is the string `'1'`.
96
+
97
+ A value with spaces goes in double quotes:
98
+
99
+ ```dotenv
100
+ APP_NAME="My Application"
101
+ ```
102
+
103
+ A value can use another variable, set earlier in the file or in the environment, as `${NAME}`. Single quotes keep a
104
+ value as written on Node; Bun, which reads `.env` itself, replaces `${NAME}` in single quotes too:
105
+
106
+ ```dotenv
107
+ MAIL_FROM_NAME="${APP_NAME}"
108
+ PASSWORD_HINT='${not a variable}'
109
+ ```
110
+
111
+ ### Retrieving environment configuration
112
+
113
+ `env()` reads a variable, with a default for when it isn't set. The config files call it for most of their values:
114
+
115
+ ```ts
116
+ const debug = env('APP_DEBUG', false)
117
+ ```
118
+
119
+ A function as the default is called only when the variable isn't set. The result is typed as the default's type, a
120
+ string, a boolean or `null`, since the variable could hold any of them.
121
+
122
+ Call `env()` in your config files, and read `config()` everywhere else. A config value can be changed while your app
123
+ runs, in a test for one, and every part of your app then reads the same value.
124
+
125
+ ### Determining the current environment
126
+
127
+ The current environment is `app.env` in your config, which `config/app.ts` reads from `APP_ENV`. A new app's `.env`
128
+ says `local`; without the variable, the environment is `production`. `app().environment()` returns it, and with names
129
+ it tells you whether it is one of them:
130
+
131
+ ```ts
132
+ const environment = app().environment()
133
+
134
+ if (app().environment('local')) {
135
+ // The environment is local
136
+ }
137
+
138
+ if (app().environment('local', 'staging')) {
139
+ // The environment is either local OR staging...
140
+ }
141
+ ```
142
+
143
+ A name may use `*` as a wildcard: `app().environment('stag*')`. Where Laravel takes a list, pass the names as separate
144
+ arguments. The application has shortcuts too:
145
+
146
+ | Method | Is `true` when |
147
+ | --- | --- |
148
+ | `app().isLocal()` | The environment is `local` |
149
+ | `app().isProduction()` | The environment is `production` |
150
+ | `app().runningUnitTests()` | The environment is `testing`, as in your tests |
151
+ | `app().runningInConsole()` | The app was started by an `oriel` command, `oriel serve` included, or by your tests |
152
+
153
+ Since a variable set in the environment wins over `.env`, your server can set `APP_ENV=production` even when its
154
+ `.env` says `local`.
155
+
156
+ ## Accessing configuration values
157
+
158
+ Read a value with `config()`, anywhere in your app. A key is the file's name, then the keys inside it, with dots. A
159
+ second argument is the default, returned when the key doesn't exist:
160
+
161
+ ```ts
162
+ const timezone = config('app.timezone')
163
+
164
+ // Retrieve a default value if the configuration value does not exist...
165
+ const fallback = config('app.timezone', 'Asia/Seoul')
166
+ ```
167
+
168
+ A value is typed `unknown`, unless you give it a type, which TypeScript takes on trust, `config<string>('app.name')`, or
169
+ a default, whose type it takes: `config('app.name', 'Oriel')`.
170
+
171
+ To set values while your app runs, pass an object to `config()`. A value you set lasts as long as the app:
172
+
173
+ ```ts
174
+ config({ 'app.timezone': 'America/Chicago' })
175
+ ```
176
+
177
+ With no arguments, `config()` returns the configuration itself, with `get()`, `set()`, `has()`, `push()` and `all()`.
178
+
179
+ ### The `Config` facade
180
+
181
+ The `Config` [facade](facades.md) reaches the same values:
182
+
183
+ ```ts
184
+ const timezone = Config.get('app.timezone')
185
+
186
+ Config.set('app.timezone', 'America/Chicago')
187
+
188
+ if (Config.has('services.stripe')) {
189
+ // ...
190
+ }
191
+ ```
192
+
193
+ It also has `getMany()`, which reads several keys at once, `push()` and `prepend()`, which add a value at the end or
194
+ the start of a list, and typed getters. A typed getter returns the value as its type, or throws a `TypeError` when the
195
+ value isn't of that type:
196
+
197
+ ```ts
198
+ const name = Config.string('app.name')
199
+ const debug = Config.boolean('app.debug')
200
+ const maxBodySize = Config.integer('http.max_body_size')
201
+ const proxies = Config.array('http.trusted_proxies')
202
+ ```
203
+
204
+ `float()` takes any number, as JavaScript has one number type, and `array()` takes a list or an object, such as a
205
+ config section. Each typed getter takes a default for a missing key. Laravel's `collection()` getter isn't in Oriel.
206
+
207
+ A typed getter checks the value it reads: `Config.integer()` on a value read from `.env` as text throws "Configuration
208
+ value for key [session.lifetime] must be an integer, string given.". A new app's config files wrap their numeric
209
+ settings in `Number()`, as Laravel's cast them, so its own values read as numbers; do the same for a setting of yours.
210
+
211
+ ### Third-party services
212
+
213
+ `config/services.ts` holds the credentials of the services your app talks to, such as a payment gateway or a mail
214
+ provider, so your code and your packages find them in one place. A new app's file is empty. Add a section per
215
+ service, with its values from `.env`:
216
+
217
+ ```ts title="config/services.ts"
218
+ import { env } from '@orieljs/framework'
219
+
220
+ export default {
221
+ stripe: { key: env('STRIPE_KEY'), secret: env('STRIPE_SECRET') },
222
+ }
223
+ ```
224
+
225
+ Read them as any other value: `config('services.stripe.key')`, or `Config.string('services.stripe.key')`, which throws
226
+ when the variable isn't set.
227
+
228
+ ### The HTTP settings
229
+
230
+ `config/http.ts` holds settings of the HTTP layer that Laravel sets in `bootstrap/app.php` or in PHP's own
231
+ configuration:
232
+
233
+ ```ts title="config/http.ts"
234
+ export default {
235
+ trusted_proxies: [],
236
+ csrf_except: [],
237
+ redirect_guests_to: '/login',
238
+ max_body_size: 8 * 1024 * 1024,
239
+ }
240
+ ```
241
+
242
+ - `trusted_proxies`: the proxies whose `X-Forwarded-*` headers your app believes (see
243
+ [Configuring trusted proxies](requests.md#configuring-trusted-proxies)).
244
+ - `csrf_except`: the URIs the CSRF check skips (see
245
+ [Excluding URIs from CSRF protection](csrf.md#excluding-uris-from-csrf-protection)).
246
+ - `redirect_guests_to`: where the `auth` middleware sends a guest (see
247
+ [Redirecting guests and signed-in users](middleware.md#redirecting-guests-and-signed-in-users)).
248
+ - `max_body_size`: the largest request body your app reads, in bytes, or `null` for no limit. A larger body gets a
249
+ 413 (see [Body size limits](requests.md#body-size-limits)).
250
+
251
+ The limit is 8 MB, and it holds for every route, uploads included. A Live component accepts uploads of up to 12 MB,
252
+ so to take a file larger than 8 MB, raise `max_body_size` above the largest file you accept, with room for the rest of
253
+ the form:
254
+
255
+ ```ts title="config/http.ts"
256
+ export default {
257
+ trusted_proxies: [],
258
+ csrf_except: [],
259
+ redirect_guests_to: '/login',
260
+ max_body_size: 16 * 1024 * 1024,
261
+ }
262
+ ```
263
+
264
+ With the default limit, a Live upload of 9 MB gets a 413, and the field shows "The photo failed to upload.", with your
265
+ property's name in place of `photo`.
266
+
267
+ ## Configuration caching
268
+
269
+ > [!NOTE]
270
+ > Laravel caches the config files into one file with `config:cache`, and `.env` isn't read once they are cached.
271
+ > Oriel has no `config:cache`: it imports your config files each time a process starts, which takes a moment, and
272
+ > there is no cache to clear after a deploy. `env()` works anywhere, but the advice to call it only in config files
273
+ > still holds.
274
+
275
+ ## Configuration publishing
276
+
277
+ The framework's packages merge their defaults with your config files, so a key you leave out still has its value:
278
+ `config/http.ts` has no `max_json_depth`, and `config('http.max_json_depth')` is 512. A package of your own does the
279
+ same with `mergeConfigFrom()`, in its [service provider](providers.md)'s `register()`:
280
+
281
+ ```ts title="app/Providers/CourierServiceProvider.ts"
282
+ import { ServiceProvider } from '@orieljs/framework'
283
+
284
+ export class CourierServiceProvider extends ServiceProvider {
285
+ override register(): void {
286
+ this.mergeConfigFrom({ channel: 'mail', timeout: 30, options: { retries: 3 } }, 'courier')
287
+ }
288
+ }
289
+ ```
290
+
291
+ The merge is shallow, as in Laravel: each top-level key of the app's `config/courier.ts` wins over the default, and an
292
+ object such as `options` is replaced whole, not merged key by key.
293
+
294
+ > [!NOTE]
295
+ > Laravel's `mergeConfigFrom()` takes the path of the package's config file, and `config:publish` copies a file into
296
+ > your app. Oriel's takes the defaults as an object, and has no `config:publish`: to change a package's settings,
297
+ > write the file in `config` yourself, with the keys you change.
298
+
299
+ ## Debug mode
300
+
301
+ `debug` in `config/app.ts` decides how much an error response shows. It reads `APP_DEBUG`, which a new app's `.env`
302
+ sets to `true`: a server error then shows the debug page, with your code around the error and its stack.
303
+ [Error handling](errors.md#configuration) describes what it shows.
304
+
305
+ > [!WARNING]
306
+ > In production, `APP_DEBUG` must be `false`. The debug page shows your source code and your error messages, which
307
+ > can hold secrets, to anyone who triggers an error.
308
+
309
+ ## The application key
310
+
311
+ `APP_KEY` in `.env` is your app's secret key. It encrypts your cookies, your sessions when `session.encrypt` is on and
312
+ what you encrypt with [`Crypt`](encryption.md), and it signs signed URLs, such as the email verification links, and the
313
+ state of your Live components. The installer sets it. To set a new one, run `key:generate`:
314
+
315
+ ```sh
316
+ node oriel key:generate
317
+ ```
318
+
319
+ It writes a random key for the cipher in `config/app.ts`, AES-256-GCM, into the `APP_KEY=` line of `.env`, as
320
+ `base64:` and the key's bytes. `.env` needs that line: without it, the command stops with "Unable to set application
321
+ key. No APP_KEY variable was found in the .env file.". `--show` prints a key and changes nothing. In production, the
322
+ command refuses to replace a key that is set, unless you pass `--force`.
323
+
324
+ A new key can't decrypt what the old one encrypted, so signed-in users are signed out. To keep reading the old values,
325
+ list the old keys in `APP_PREVIOUS_KEYS`, separated by commas: Oriel then decrypts with them too, and accepts the
326
+ signed URLs they signed, but encrypts and signs with the new key only. An app with no key fails the first time it
327
+ needs one, with "No application encryption key has been specified.".
328
+
329
+ ## Maintenance mode
330
+
331
+ > [!NOTE]
332
+ > Laravel's maintenance mode, the `down` and `up` commands with their 503 page, isn't in Oriel. To update an app
333
+ > without stopping it, start the new version beside the old one and switch your load balancer or proxy over to it.
334
+ > [Deployment](deployment.md) covers running your app in production.