@typetron/framework 0.5.30 → 0.5.32

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 (128) hide show
  1. package/AGENTS.md +31 -0
  2. package/CLAUDE.md +1 -0
  3. package/Cache/Readme.md +63 -0
  4. package/Container/Readme.md +95 -0
  5. package/Database/Readme.md +139 -0
  6. package/Encryption/Readme.md +54 -0
  7. package/Forms/Readme.md +79 -0
  8. package/Framework/Readme.md +143 -0
  9. package/Frontend/Angular/Readme.md +68 -0
  10. package/Frontend/Websockets/Readme.md +96 -0
  11. package/Mail/Readme.md +99 -0
  12. package/Models/Readme.md +85 -0
  13. package/Router/Readme.md +145 -0
  14. package/Storage/Readme.md +188 -0
  15. package/Support/Readme.md +71 -0
  16. package/Testing/Readme.md +80 -0
  17. package/Validation/Readme.md +91 -0
  18. package/build/Cache/Stores/FileStore.d.ts +3 -3
  19. package/build/Cache/Stores/FileStore.d.ts.map +1 -1
  20. package/build/Cache/Stores/FileStore.js.map +1 -1
  21. package/build/Database/List.d.ts +1 -1
  22. package/build/Database/Migrations/Migrator.d.ts +3 -3
  23. package/build/Database/Migrations/Migrator.d.ts.map +1 -1
  24. package/build/Database/Migrations/Migrator.js.map +1 -1
  25. package/build/Database/Seeders/SeederManager.d.ts +3 -3
  26. package/build/Database/Seeders/SeederManager.d.ts.map +1 -1
  27. package/build/Database/Seeders/SeederManager.js +3 -3
  28. package/build/Database/Seeders/SeederManager.js.map +1 -1
  29. package/build/Framework/Application.js +1 -1
  30. package/build/Framework/Application.js.map +1 -1
  31. package/build/Framework/Config/StorageConfig.d.ts +7 -0
  32. package/build/Framework/Config/StorageConfig.d.ts.map +1 -0
  33. package/build/Framework/Config/StorageConfig.js +15 -0
  34. package/build/Framework/Config/StorageConfig.js.map +1 -0
  35. package/build/Framework/Config/index.d.ts +1 -0
  36. package/build/Framework/Config/index.d.ts.map +1 -1
  37. package/build/Framework/Config/index.js +1 -0
  38. package/build/Framework/Config/index.js.map +1 -1
  39. package/build/Framework/Middleware/StaticAssetsMiddleware.d.ts +2 -2
  40. package/build/Framework/Middleware/StaticAssetsMiddleware.d.ts.map +1 -1
  41. package/build/Framework/Middleware/StaticAssetsMiddleware.js +1 -1
  42. package/build/Framework/Middleware/StaticAssetsMiddleware.js.map +1 -1
  43. package/build/Framework/Providers/CacheProvider.js +1 -1
  44. package/build/Framework/Providers/CacheProvider.js.map +1 -1
  45. package/build/Framework/Providers/DatabaseProvider.d.ts +2 -2
  46. package/build/Framework/Providers/DatabaseProvider.d.ts.map +1 -1
  47. package/build/Framework/Providers/DatabaseProvider.js +1 -1
  48. package/build/Framework/Providers/DatabaseProvider.js.map +1 -1
  49. package/build/Framework/Providers/StorageProvider.d.ts +7 -0
  50. package/build/Framework/Providers/StorageProvider.d.ts.map +1 -0
  51. package/build/Framework/Providers/StorageProvider.js +28 -0
  52. package/build/Framework/Providers/StorageProvider.js.map +1 -0
  53. package/build/Framework/Providers/WebsocketsProvider.d.ts.map +1 -1
  54. package/build/Framework/Providers/WebsocketsProvider.js +13 -0
  55. package/build/Framework/Providers/WebsocketsProvider.js.map +1 -1
  56. package/build/Framework/index.d.ts +1 -0
  57. package/build/Framework/index.d.ts.map +1 -1
  58. package/build/Framework/index.js +1 -0
  59. package/build/Framework/index.js.map +1 -1
  60. package/build/Router/Http/Request.d.ts.map +1 -1
  61. package/build/Router/Http/Request.js +3 -4
  62. package/build/Router/Http/Request.js.map +1 -1
  63. package/build/Router/Router.js +1 -1
  64. package/build/Router/Router.js.map +1 -1
  65. package/build/Router/Servers/uNetworking.d.ts.map +1 -1
  66. package/build/Router/Servers/uNetworking.js +3 -4
  67. package/build/Router/Servers/uNetworking.js.map +1 -1
  68. package/build/Storage/Drivers/LocalDriver.d.ts +26 -0
  69. package/build/Storage/Drivers/LocalDriver.d.ts.map +1 -0
  70. package/build/Storage/Drivers/LocalDriver.js +209 -0
  71. package/build/Storage/Drivers/LocalDriver.js.map +1 -0
  72. package/build/Storage/Drivers/MemoryDriver.d.ts +25 -0
  73. package/build/Storage/Drivers/MemoryDriver.d.ts.map +1 -0
  74. package/build/Storage/Drivers/MemoryDriver.js +108 -0
  75. package/build/Storage/Drivers/MemoryDriver.js.map +1 -0
  76. package/build/Storage/Drivers/ReadOnlyDriver.d.ts +22 -0
  77. package/build/Storage/Drivers/ReadOnlyDriver.d.ts.map +1 -0
  78. package/build/Storage/Drivers/ReadOnlyDriver.js +38 -0
  79. package/build/Storage/Drivers/ReadOnlyDriver.js.map +1 -0
  80. package/build/Storage/Drivers/S3Driver.d.ts +32 -0
  81. package/build/Storage/Drivers/S3Driver.d.ts.map +1 -0
  82. package/build/Storage/Drivers/S3Driver.js +248 -0
  83. package/build/Storage/Drivers/S3Driver.js.map +1 -0
  84. package/build/Storage/Drivers/ScopedDriver.d.ts +24 -0
  85. package/build/Storage/Drivers/ScopedDriver.d.ts.map +1 -0
  86. package/build/Storage/Drivers/ScopedDriver.js +50 -0
  87. package/build/Storage/Drivers/ScopedDriver.js.map +1 -0
  88. package/build/Storage/File.d.ts +14 -4
  89. package/build/Storage/File.d.ts.map +1 -1
  90. package/build/Storage/File.js +29 -47
  91. package/build/Storage/File.js.map +1 -1
  92. package/build/Storage/Filesystem.d.ts +31 -0
  93. package/build/Storage/Filesystem.d.ts.map +1 -0
  94. package/build/Storage/Filesystem.js +121 -0
  95. package/build/Storage/Filesystem.js.map +1 -0
  96. package/build/Storage/PathPrefixer.d.ts +9 -0
  97. package/build/Storage/PathPrefixer.d.ts.map +1 -0
  98. package/build/Storage/PathPrefixer.js +53 -0
  99. package/build/Storage/PathPrefixer.js.map +1 -0
  100. package/build/Storage/Storage.d.ts +37 -9
  101. package/build/Storage/Storage.d.ts.map +1 -1
  102. package/build/Storage/Storage.js +85 -101
  103. package/build/Storage/Storage.js.map +1 -1
  104. package/build/Storage/StorageDisk.d.ts +34 -0
  105. package/build/Storage/StorageDisk.d.ts.map +1 -0
  106. package/build/Storage/StorageDisk.js +104 -0
  107. package/build/Storage/StorageDisk.js.map +1 -0
  108. package/build/Storage/StorageDriver.d.ts +19 -0
  109. package/build/Storage/StorageDriver.d.ts.map +1 -0
  110. package/build/Storage/StorageDriver.js +7 -0
  111. package/build/Storage/StorageDriver.js.map +1 -0
  112. package/build/Storage/UploadedFile.d.ts +9 -0
  113. package/build/Storage/UploadedFile.d.ts.map +1 -0
  114. package/build/Storage/UploadedFile.js +22 -0
  115. package/build/Storage/UploadedFile.js.map +1 -0
  116. package/build/Storage/errors.d.ts +21 -0
  117. package/build/Storage/errors.d.ts.map +1 -0
  118. package/build/Storage/errors.js +43 -0
  119. package/build/Storage/errors.js.map +1 -0
  120. package/build/Storage/index.d.ts +12 -0
  121. package/build/Storage/index.d.ts.map +1 -1
  122. package/build/Storage/index.js +12 -0
  123. package/build/Storage/index.js.map +1 -1
  124. package/build/Storage/types.d.ts +73 -0
  125. package/build/Storage/types.d.ts.map +1 -0
  126. package/build/Storage/types.js +3 -0
  127. package/build/Storage/types.js.map +1 -0
  128. package/package.json +35 -3
package/AGENTS.md ADDED
@@ -0,0 +1,31 @@
1
+ # Typetron Framework Guide
2
+
3
+ Read the documentation for the module you are changing before editing its source. Nested features are documented by their owning module; for
4
+ example, HTTP and WebSocket routing are covered by Router, while migrations and seeders are covered by Database.
5
+
6
+ ## Module Documentation
7
+
8
+ - [Cache](Cache/Readme.md) - cache contracts and memory, file, and database stores.
9
+ - [Container](Container/Readme.md) - dependency injection, bindings, resolvers, and scopes.
10
+ - [Database](Database/Readme.md) - connections, queries, entities, relationships, migrations, and seeders.
11
+ - [Encryption](Encryption/Readme.md) - password hashing and JSON Web Tokens.
12
+ - [Forms](Forms/Readme.md) - typed input objects and field validation.
13
+ - [Framework](Framework/Readme.md) - application bootstrap, configuration, providers, authentication, and middleware.
14
+ - [Mail](Mail/Readme.md) - mailables, recipients, and transports.
15
+ - [Models](Models/Readme.md) - explicit response and data projections.
16
+ - [Router](Router/Readme.md) - controllers, HTTP routes, WebSocket actions, middleware, and servers.
17
+ - [Storage](Storage/Readme.md) - files, directories, and image data.
18
+ - [Support](Support/Readme.md) - shared types, utilities, and prototype helpers.
19
+ - [Testing](Testing/Readme.md) - application-aware HTTP and WebSocket test helpers.
20
+ - [Validation](Validation/Readme.md) - built-in and custom validation rules.
21
+ - [Angular](Frontend/Angular/Readme.md) - Angular form integration.
22
+ - [Browser WebSockets](Frontend/Websockets/Readme.md) - the Typetron WebSocket browser client.
23
+
24
+ ## Working in This Repository
25
+
26
+ - Treat each capitalized source directory as a framework module.
27
+ - Use the nearest module barrel or the documented `@Typetron/<Module>` path for public imports.
28
+ - Look for corresponding behavior tests under `tests/<Module>` before changing an implementation.
29
+ - Do not edit `build/`; it is generated by `npm run build`.
30
+ - Keep module documentation aligned with public behavior. Update the relevant `Readme.md` when an API, default, error, or example changes.
31
+ - Keep documentation examples short and executable in shape. Do not document planned or commented-out features as available.
package/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ @AGENTS.md
@@ -0,0 +1,63 @@
1
+ # Cache
2
+
3
+ - [Introduction](#introduction)
4
+ - [Using a Cache Store](#using-a-cache-store)
5
+ - [Retrieving and Remembering Values](#retrieving-and-remembering-values)
6
+ - [Available Stores](#available-stores)
7
+ - [Removing Values](#removing-values)
8
+
9
+ ## Introduction
10
+
11
+ Typetron provides one cache contract for values stored in memory, on disk, or in the configured database. Each store supports the same
12
+ asynchronous operations, so application code may depend on `Cache` without knowing where values are kept.
13
+
14
+ ## Using a Cache Store
15
+
16
+ The `CacheProvider` binds the configured store to the `Cache` class. A store may also be constructed directly when no application container
17
+ is available:
18
+
19
+ ```ts
20
+ import { MemoryStore } from '@Typetron/Cache'
21
+
22
+ const cache = new MemoryStore()
23
+
24
+ await cache.set('user:1', {name: 'John'}, 60)
25
+ const user = await cache.get<{name: string}>('user:1')
26
+ ```
27
+
28
+ The optional duration passed to `set` is measured in seconds. Omitting it keeps the value until it is removed or the store is flushed.
29
+
30
+ ## Retrieving and Remembering Values
31
+
32
+ The `get` method accepts either a value or a function as its fallback. Use `remember` when the fallback should also be stored:
33
+
34
+ ```ts
35
+ const users = await cache.remember('users', async () => {
36
+ return [{id: 1, name: 'John'}]
37
+ }, 300)
38
+ ```
39
+
40
+ The fallback is evaluated only when the key is unavailable. `get` returns `undefined` when no cached value or fallback is provided.
41
+
42
+ ## Available Stores
43
+
44
+ `MemoryStore` keeps values in the current process. `FileStore` hashes each key and stores its serialized value below a configured directory.
45
+ `DatabaseStore` stores serialized values in a table and creates that table when it first writes a value.
46
+
47
+ The application-level `CacheConfig` supports the `memory`, `file`, and `database` drivers. The `CacheProvider` creates the selected
48
+ implementation.
49
+
50
+ > Note: Memory cache values disappear when the process exits. File and database stores persist values, but their values must be JSON
51
+ > serializable.
52
+
53
+ ## Removing Values
54
+
55
+ Use `delete` to remove one key or `flush` to clear the entire store:
56
+
57
+ ```ts
58
+ await cache.delete('user:1')
59
+ await cache.flush()
60
+ ```
61
+
62
+ Calling `has` checks whether a key is present. Expired memory values are removed during this check, while persisted stores enforce
63
+ expiration when values are read.
@@ -0,0 +1,95 @@
1
+ # Service Container
2
+
3
+ - [Introduction](#introduction)
4
+ - [Resolving Classes](#resolving-classes)
5
+ - [Binding Values](#binding-values)
6
+ - [Dependency Injection](#dependency-injection)
7
+ - [Scopes and Child Containers](#scopes-and-child-containers)
8
+ - [Custom Resolvers](#custom-resolvers)
9
+
10
+ ## Introduction
11
+
12
+ The service container constructs classes and resolves their dependencies. Typetron uses it for controllers, providers, middleware, and other
13
+ framework services, but it may also resolve application classes directly.
14
+
15
+ ## Resolving Classes
16
+
17
+ Concrete classes require no manual registration. Pass the constructor to `get` and the container will build it:
18
+
19
+ ```ts
20
+ import { Container } from '@Typetron/Container'
21
+
22
+ class UserRepository {}
23
+
24
+ const container = new Container()
25
+ const users = container.get(UserRepository)
26
+ ```
27
+
28
+ Classes use singleton scope by default, so subsequent calls return the same resolved instance.
29
+
30
+ ## Binding Values
31
+
32
+ Use `set` when an abstraction, symbol, or string should resolve to a particular value:
33
+
34
+ ```ts
35
+ abstract class StorageContract {}
36
+
37
+ class LocalStorage extends StorageContract {}
38
+
39
+ container.set(StorageContract, new LocalStorage())
40
+ container.set('appName', 'Typetron')
41
+
42
+ const storage = container.get(StorageContract)
43
+ ```
44
+
45
+ A missing string binding throws `No instance found for '<name>'`.
46
+
47
+ ## Dependency Injection
48
+
49
+ Constructor types are resolved automatically. The `@Inject` decorator provides property injection and may name an explicit binding:
50
+
51
+ ```ts
52
+ import { Inject, Injectable } from '@Typetron/Container'
53
+
54
+ @Injectable()
55
+ class UserService {
56
+ constructor(public users: UserRepository) {}
57
+ }
58
+
59
+ class UserController {
60
+ @Inject()
61
+ users: UserService
62
+
63
+ @Inject('appName')
64
+ appName: string
65
+ }
66
+
67
+ const controller = container.get(UserController)
68
+ ```
69
+
70
+ Decorator-based injection requires TypeScript decorator metadata to be enabled, as it is in this repository's `tsconfig.json`.
71
+
72
+ ## Scopes and Child Containers
73
+
74
+ Pass a `Scope` to `@Injectable` when the default singleton lifetime is not appropriate:
75
+
76
+ ```ts
77
+ import { Injectable, Scope } from '@Typetron/Container'
78
+
79
+ @Injectable(Scope.TRANSIENT)
80
+ class Operation {}
81
+
82
+ const first = container.get(Operation)
83
+ const second = container.get(Operation)
84
+ ```
85
+
86
+ `first` and `second` are different instances. `REQUEST` services are isolated to request containers, while `CONNECTION` services may live in
87
+ a connection container and be reused by its request children. Create those boundaries with `createChildContainer('connection')` and
88
+ `createChildContainer('request')`.
89
+
90
+ ## Custom Resolvers
91
+
92
+ Extend `BaseResolver` to resolve values the default class resolver cannot construct. Add the resolver near the beginning of
93
+ `container.resolvers` when it should take precedence, and implement `canResolve` and `resolve`.
94
+
95
+ > Note: A resolver may return a promise. In that case, callers must await the value returned by `container.get`.
@@ -0,0 +1,139 @@
1
+ # Database
2
+
3
+ - [Introduction](#introduction)
4
+ - [Configuration](#configuration)
5
+ - [Queries and Entities](#queries-and-entities)
6
+ - [Relationships](#relationships)
7
+ - [Migrations and Seeders](#migrations-and-seeders)
8
+
9
+ ## Introduction
10
+
11
+ The Database module contains Typetron's connection layer, SQL query builder, schema drivers, and entity ORM. SQLite and MySQL use the same
12
+ `Query` and `Entity` APIs.
13
+
14
+ ## Configuration
15
+
16
+ Applications configure the active driver through `DatabaseConfig` and register `DatabaseProvider`. Outside an application, assign
17
+ `Query.connection` before creating queries:
18
+
19
+ ```ts
20
+ import { Connection, Query, SqliteDriver } from '@Typetron/Database'
21
+ import { DatabaseConfig } from '@Typetron/Framework'
22
+
23
+ export const config = new DatabaseConfig({
24
+ driver: 'sqlite',
25
+ migrationsDirectory: 'Database/migrations',
26
+ seedersDirectory: 'Database/seeders',
27
+ })
28
+
29
+ Query.connection = new Connection(new SqliteDriver(':memory:'))
30
+ ```
31
+
32
+ The built-in SQLite driver reads `process.env.database` and otherwise uses `database.sqlite`. The MySQL driver reads the database host,
33
+ user, password, and database environment values. All queries and entities use the static `Query.connection`.
34
+
35
+ ## Queries and Entities
36
+
37
+ Start a query with `Query.table`, or extend `Entity` and decorate mapped properties. The following example defines an entity and exercises
38
+ both APIs:
39
+
40
+ ```ts
41
+ import {
42
+ Column,
43
+ CreatedAt,
44
+ Entity,
45
+ HasMany,
46
+ Options,
47
+ PrimaryColumn,
48
+ Query,
49
+ Relation,
50
+ UpdatedAt,
51
+ } from '@Typetron/Database'
52
+ import { Post } from '../Entities/Post'
53
+
54
+ @Options({table: 'users'})
55
+ class User extends Entity {
56
+ @PrimaryColumn()
57
+ id: number
58
+
59
+ @Column()
60
+ name: string
61
+
62
+ @Column()
63
+ email: string
64
+
65
+ @CreatedAt()
66
+ createdAt: Date
67
+
68
+ @UpdatedAt()
69
+ updatedAt: Date
70
+
71
+ @Relation(() => Post, 'author')
72
+ posts: HasMany<Post>
73
+ }
74
+
75
+ const id = await Query.table('users').insertOne({name: 'John'})
76
+ const user = await User.create({
77
+ name: 'Jane',
78
+ email: 'jane@example.com',
79
+ })
80
+
81
+ const users = await User
82
+ .whereLike('email', '%@example.com')
83
+ .orderBy('name', 'ASC')
84
+ .get()
85
+
86
+ user.name = 'Janet'
87
+ await user.save()
88
+ ```
89
+
90
+ The query builder supports selection, joins, grouping, ordering, limits, aggregates, subqueries, and common `where` variants. Use `first`,
91
+ `insert`, `insertOne`, `update`, and `delete` to execute work; `insertOne` resolves to the identifier supplied by the active driver.
92
+
93
+ Without `@Options`, an entity table defaults to the lowercase class name. `@Column('column_name')` maps another column name, while
94
+ `@JSONColumn` serializes objects as JSON. Use `find` or `first` when absence is expected; `findOrFail` throws `EntityNotFoundError`.
95
+ `firstOrNew` returns an unsaved entity, while `firstOrCreate` persists it.
96
+
97
+ ## Relationships
98
+
99
+ Typetron supports `BelongsTo`, `HasOne`, `HasMany`, and `BelongsToMany`. Declare both sides with `@Relation`, naming the inverse property:
100
+
101
+ The `User.posts` property above pairs with a `Post.author: BelongsTo<User>` relation whose inverse name is `posts`. Load the relation with
102
+ `User.with('posts').get()`, or use `User.withCount('posts').get()` to add a `postsCount` value.
103
+
104
+ `with` accepts nested relation paths and constrained relation queries. `withCount` places the loaded count on the corresponding
105
+ `<relation>Count` property.
106
+
107
+ ## Migrations and Seeders
108
+
109
+ Migration classes implement `up` and `down` with the provided connection. Seeders implement `run` against the active connection:
110
+
111
+ ```ts
112
+ import { Query } from '@Typetron/Database'
113
+ import { Migration } from '@Typetron/Database/Migrations'
114
+ import { Seeder } from '@Typetron/Database/Seeders'
115
+
116
+ export class CreateUsersTable extends Migration {
117
+ async up() {
118
+ await this.connection.runRaw(
119
+ 'CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)'
120
+ )
121
+ }
122
+
123
+ async down() {
124
+ await this.connection.runRaw('DROP TABLE users')
125
+ }
126
+ }
127
+
128
+ export class UserSeeder extends Seeder {
129
+ async run() {
130
+ await Query.table('users').insert({name: 'John'})
131
+ }
132
+ }
133
+ ```
134
+
135
+ `Migrator.migrate` discovers pending TypeScript files and records batches. `rollback(steps)` and `reset` invoke migration `down` methods.
136
+ `SeederManager.seed` discovers TypeScript seeder files and runs them.
137
+
138
+ > Warning: `reset` reverses migrations against the active database. `migrate({fresh: true})` clears only the migration history; it does not
139
+ > drop existing application tables before rerunning migrations.
@@ -0,0 +1,54 @@
1
+ # Encryption
2
+
3
+ - [Introduction](#introduction)
4
+ - [Hashing Passwords](#hashing-passwords)
5
+ - [Signing Tokens](#signing-tokens)
6
+ - [Verifying Tokens](#verifying-tokens)
7
+
8
+ ## Introduction
9
+
10
+ The Encryption module wraps password hashing and JSON Web Token operations in promise-based services that can be resolved through Typetron's
11
+ container.
12
+
13
+ ## Hashing Passwords
14
+
15
+ Use `Crypt.hash` before storing a password and `Crypt.compare` when checking a submitted value:
16
+
17
+ ```ts
18
+ import { Crypt } from '@Typetron/Encryption'
19
+
20
+ const crypt = new Crypt()
21
+ const password = await crypt.hash('secret', 12)
22
+ const matches = await crypt.compare('secret', password)
23
+ ```
24
+
25
+ The second argument to `hash` is the bcrypt salt-round count. Both operations reject when bcrypt cannot process the supplied value.
26
+
27
+ ## Signing Tokens
28
+
29
+ The `JWT` service exposes the asynchronous form of `jsonwebtoken.sign`:
30
+
31
+ ```ts
32
+ import { JWT } from '@Typetron/Encryption'
33
+
34
+ const jwt = new JWT()
35
+ const token = await jwt.sign(
36
+ {sub: 1},
37
+ process.env.APP_SECRET!,
38
+ {expiresIn: '1h'}
39
+ )
40
+ ```
41
+
42
+ Payload and signing options follow the `jsonwebtoken` package.
43
+
44
+ ## Verifying Tokens
45
+
46
+ Pass the token and the same public key or secret to `verify`:
47
+
48
+ ```ts
49
+ const payload = await jwt.verify<number>(token, process.env.APP_SECRET!)
50
+
51
+ console.log(payload.sub)
52
+ ```
53
+
54
+ The promise resolves to the decoded payload, including `sub`, `iat`, and `exp`, or rejects when the token is invalid or expired.
@@ -0,0 +1,79 @@
1
+ # Forms
2
+
3
+ - [Introduction](#introduction)
4
+ - [Defining Forms](#defining-forms)
5
+ - [Filling Forms](#filling-forms)
6
+ - [Validating Forms](#validating-forms)
7
+ - [Optional Fields](#optional-fields)
8
+
9
+ ## Introduction
10
+
11
+ Forms describe the input an application accepts. A form declares its fields, applies Validation module rules, and exposes only those fields
12
+ when it is filled or serialized.
13
+
14
+ ## Defining Forms
15
+
16
+ Extend `Form` and decorate each accepted property with `@Field`. Apply validation with `@Rules`:
17
+
18
+ ```ts
19
+ import { Field, Form, Rules } from '@Typetron/Forms'
20
+ import { Email, MinLength, Required } from '@Typetron/Validation'
21
+
22
+ class UserForm extends Form {
23
+ @Field()
24
+ @Rules(Required, MinLength(3))
25
+ name: string
26
+
27
+ @Field()
28
+ @Rules(Required, Email)
29
+ email: string
30
+ }
31
+ ```
32
+
33
+ `@Field('externalName')` may be used when the exposed field name differs from the property name.
34
+
35
+ ## Filling Forms
36
+
37
+ The `fill` method copies decorated fields from an input object and ignores other properties:
38
+
39
+ ```ts
40
+ const form = new UserForm()
41
+
42
+ form.fill({
43
+ name: 'John',
44
+ email: 'john@example.com',
45
+ })
46
+
47
+ const value = form.value()
48
+ ```
49
+
50
+ `value` and `toJSON` return an object containing all declared fields. `validated` returns the truthy fields that do not currently have
51
+ validation errors.
52
+
53
+ ## Validating Forms
54
+
55
+ Call `valid` after filling the form:
56
+
57
+ ```ts
58
+ if (!form.valid()) {
59
+ console.log(form.errors)
60
+ }
61
+ ```
62
+
63
+ Errors are grouped first by field name and then by rule identifier, such as `required` or `email`.
64
+
65
+ ## Optional Fields
66
+
67
+ Use `Optional` before other constraints when a missing value is allowed:
68
+
69
+ ```ts
70
+ import { MinLength, Optional } from '@Typetron/Validation'
71
+
72
+ class ProfileForm extends Form {
73
+ @Field()
74
+ @Rules(Optional, MinLength(10))
75
+ biography?: string
76
+ }
77
+ ```
78
+
79
+ A value of `undefined` or `null` skips all rules for an optional field. An empty string is still validated by the remaining rules.
@@ -0,0 +1,143 @@
1
+ # Application Framework
2
+
3
+ - [Introduction](#introduction)
4
+ - [Creating an Application](#creating-an-application)
5
+ - [Configuration](#configuration)
6
+ - [Providers and Middleware](#providers-and-middleware)
7
+ - [Authentication](#authentication)
8
+ - [Automatic Parameter Resolution](#automatic-parameter-resolution)
9
+ - [Accessing Services](#accessing-services)
10
+
11
+ ## Introduction
12
+
13
+ The Framework module bootstraps a Typetron application. It loads configuration, prepares the service container, registers providers and
14
+ parameter resolvers, and starts the selected HTTP and WebSocket servers.
15
+
16
+ ## Creating an Application
17
+
18
+ Use `Application.create` with the application's root directory, then start its server:
19
+
20
+ ```ts
21
+ import {
22
+ AppConfig,
23
+ Application,
24
+ AuthConfig,
25
+ CacheProvider,
26
+ DatabaseProvider,
27
+ MailProvider,
28
+ StorageProvider,
29
+ } from '@Typetron/Framework'
30
+ import { User } from './Entities/User'
31
+
32
+ export const appConfig = new AppConfig({
33
+ environment: 'development',
34
+ server: 'node',
35
+ port: 3000,
36
+ providers: [DatabaseProvider, CacheProvider, MailProvider, StorageProvider],
37
+ })
38
+
39
+ export const authConfig = new AuthConfig({
40
+ entity: User,
41
+ identityColumn: 'id',
42
+ signature: process.env.APP_SECRET!,
43
+ duration: 3600,
44
+ saltRounds: 12,
45
+ })
46
+
47
+ const app = await Application.create(process.cwd())
48
+ app.startServer()
49
+ ```
50
+
51
+ In a real application, each config instance is the default export of a TypeScript file in `config`. Configuration loads before
52
+ `Application.create` resolves. The second argument may select another config directory.
53
+
54
+ ## Configuration
55
+
56
+ The module includes `AppConfig`, `AuthConfig`, `CacheConfig`, `DatabaseConfig`, `MailConfig`, and `StorageConfig`. Constructor values
57
+ replace defaults when
58
+ the application loads each file.
59
+
60
+ `AppConfig.server` selects the Node or uWebSockets HTTP server. A configured `websocketsPort` starts the separate WebSocket provider. Static
61
+ assets are served when `staticAssets` entries are present.
62
+
63
+ Authentication configuration must provide a signing `signature`. If it is missing, application creation throws an error stating that
64
+ `APP_SECRET` is not set up.
65
+
66
+ ## Providers and Middleware
67
+
68
+ Providers bind application services. Middleware surrounds requests and may be global, HTTP-only, WebSocket-only, or attached by the Router:
69
+
70
+ ```ts
71
+ import { AppConfig, Provider } from '@Typetron/Framework'
72
+ import { RequestHandler } from '@Typetron/Router'
73
+ import { Request } from '@Typetron/Router/Http'
74
+ import { HttpMiddleware } from '@Typetron/Router/Http/Middleware'
75
+
76
+ class SearchService {}
77
+
78
+ class SearchProvider extends Provider {
79
+ register() {
80
+ this.app.set(SearchService, new SearchService())
81
+ }
82
+ }
83
+
84
+ class ResponseHeader extends HttpMiddleware {
85
+ async handle(request: Request, next: RequestHandler) {
86
+ const response = await next(request)
87
+ response.setHeader('x-powered-by', 'Typetron')
88
+ return response
89
+ }
90
+ }
91
+
92
+ export const config = new AppConfig({
93
+ port: 3000,
94
+ providers: [SearchProvider],
95
+ middleware: {
96
+ global: [],
97
+ http: [ResponseHeader],
98
+ websocket: [],
99
+ },
100
+ })
101
+ ```
102
+
103
+ Typetron includes providers for database, cache, mail, storage, and WebSockets, together with `AuthMiddleware`, `CorsMiddleware`, and
104
+ `StaticAssetsMiddleware`.
105
+
106
+ Framework bootstrap and source discovery use an internal host `Filesystem` before application storage configuration is available. This is
107
+ not the application storage API; application services should depend on `Storage` and select configured disks with `storage.disk(name)`.
108
+
109
+ ## Authentication
110
+
111
+ The `Auth` service signs and verifies user tokens. Your user may extend the provided `User` entity or implement `Authenticatable` by naming
112
+ its identity, username, and password columns.
113
+
114
+ Protect an HTTP controller with `AuthMiddleware`, then resolve the current user with `@AuthUser`:
115
+
116
+ ```ts
117
+ import { AuthUser, User } from '@Typetron/Framework/Auth'
118
+ import { AuthMiddleware } from '@Typetron/Framework/Middleware'
119
+ import { Controller, Get, Middleware } from '@Typetron/Router'
120
+
121
+ @Controller('account')
122
+ @Middleware(AuthMiddleware)
123
+ class AccountController {
124
+ @Get('me')
125
+ me(@AuthUser() user: User) {
126
+ return user
127
+ }
128
+ }
129
+ ```
130
+
131
+ The middleware accepts a bearer token from the `Authorization` header or a `token` field in the body. Invalid or expired tokens produce an
132
+ unauthenticated HTTP response.
133
+
134
+ ## Automatic Parameter Resolution
135
+
136
+ Application bootstrap registers resolvers for forms, entities, and authenticated users. A controller parameter extending `Form` is filled
137
+ from the request body and files, then validated; failure produces status `422`. An entity parameter is loaded from a route parameter named
138
+ after its class.
139
+
140
+ ## Accessing Services
141
+
142
+ An `Application` is also the root container. Resolve services with `app.get`, or use `App.get` after creation. For example, `App.get(Cache)`
143
+ returns the store registered by `CacheProvider`.
@@ -0,0 +1,68 @@
1
+ # Typetron Angular
2
+
3
+ - [Introduction](#introduction)
4
+ - [Installation](#installation)
5
+ - [Building Angular Forms](#building-angular-forms)
6
+ - [Validation](#validation)
7
+
8
+ ## Introduction
9
+
10
+ The `@typetron/angular` package turns a Typetron `Form` class into an Angular reactive `FormGroup`. Backend field names, initial values, and
11
+ validation rules can therefore be reused by an Angular application.
12
+
13
+ ## Installation
14
+
15
+ Install the package with Angular's reactive forms dependencies:
16
+
17
+ ```bash
18
+ npm install @typetron/angular @angular/forms
19
+ ```
20
+
21
+ The package expects compatible `@angular/core`, `@angular/common`, and `@angular/forms` packages, together with `@typetron/framework`.
22
+
23
+ ## Building Angular Forms
24
+
25
+ Define the form with Typetron decorators, then pass its class to `FormBuilder.build`:
26
+
27
+ ```ts
28
+ import { Component } from '@angular/core'
29
+ import { ReactiveFormsModule } from '@angular/forms'
30
+ import { FormBuilder } from '@typetron/angular'
31
+ import { Field, Form, Rules } from '@Typetron/Forms'
32
+ import { Email, Required } from '@Typetron/Validation'
33
+
34
+ class UserForm extends Form {
35
+ @Field()
36
+ @Rules(Required)
37
+ name: string
38
+
39
+ @Field()
40
+ @Rules(Required, Email)
41
+ email: string
42
+ }
43
+
44
+ @Component({
45
+ imports: [ReactiveFormsModule],
46
+ template: `<form [formGroup]="form"></form>`,
47
+ })
48
+ export class UserEditor {
49
+ form = FormBuilder.build(UserForm)
50
+ }
51
+ ```
52
+
53
+ The resulting `FormGroup` contains one control for every `@Field` in `UserForm`.
54
+
55
+ ## Validation
56
+
57
+ Each Angular control delegates validation to the corresponding Typetron `FormField`. Validation failures are returned using the Typetron
58
+ rule identifiers and messages.
59
+
60
+ ```ts
61
+ const email = this.form.controls.email
62
+
63
+ email.setValue('invalid')
64
+ console.log(email.errors?.email)
65
+ ```
66
+
67
+ > Note: The builder creates a new Typetron form to obtain default field values. Set defaults on the form class before calling
68
+ `FormBuilder.build`.