alepha 0.9.5 → 0.10.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.
- package/README.md +77 -38
- package/batch.d.ts +2 -3
- package/bucket.d.ts +7 -7
- package/command.d.ts +77 -16
- package/core.d.ts +374 -329
- package/datetime.d.ts +2 -1
- package/email.d.ts +105 -23
- package/logger.d.ts +45 -12
- package/package.json +56 -45
- package/postgres.d.ts +104 -133
- package/queue/redis.d.ts +3 -3
- package/queue.d.ts +105 -171
- package/react/auth.d.ts +99 -107
- package/react/form.d.ts +4 -1
- package/react/i18n.d.ts +8 -3
- package/react.d.ts +123 -30
- package/redis.d.ts +5 -5
- package/security.d.ts +24 -24
- package/server/cache.d.ts +1 -0
- package/server/compress.d.ts +4 -4
- package/server/health.d.ts +6 -6
- package/server/links.d.ts +29 -29
- package/server.d.ts +58 -73
- package/topic.d.ts +0 -1
- package/vite.d.ts +24 -0
package/README.md
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
Alepha
|
|
11
11
|
</h1>
|
|
12
12
|
<p style="max-width: 512px">
|
|
13
|
-
🚧
|
|
14
13
|
</p>
|
|
15
14
|
<a href="https://www.npmjs.com/package/alepha"><img src="https://img.shields.io/npm/v/alepha.svg" alt="npm"/></a>
|
|
16
15
|
<a href="https://www.npmjs.com/package/alepha"><img src="https://img.shields.io/npm/l/alepha.svg" alt="npm"/></a>
|
|
@@ -19,17 +18,23 @@ Alepha
|
|
|
19
18
|
<a href="https://github.com/feunard/alepha"><img src="https://img.shields.io/github/stars/feunard/alepha.svg?style=social" alt="GitHub stars"/></a>
|
|
20
19
|
</div>
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
A convention-driven TypeScript framework for building type-safe full-stack applications.
|
|
23
22
|
|
|
24
|
-
##
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx @alepha/cli create my-app
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or manually:
|
|
25
30
|
|
|
26
31
|
```bash
|
|
27
32
|
npm install alepha
|
|
28
33
|
```
|
|
29
34
|
|
|
30
|
-
##
|
|
35
|
+
## What is this?
|
|
31
36
|
|
|
32
|
-
|
|
37
|
+
Alepha is an opinionated framework that handles everything from database to frontend. It uses a descriptor-based architecture (`$action`, `$page`, `$repository`, etc.) and enforces type safety across the entire stack.
|
|
33
38
|
|
|
34
39
|
```ts
|
|
35
40
|
import { run } from "alepha";
|
|
@@ -44,50 +49,84 @@ class App {
|
|
|
44
49
|
run(App);
|
|
45
50
|
```
|
|
46
51
|
|
|
47
|
-
|
|
52
|
+
## Examples
|
|
48
53
|
|
|
49
|
-
|
|
54
|
+
### Type-safe API endpoint
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
```ts
|
|
57
|
+
import { $action } from "alepha/server";
|
|
58
|
+
import { t } from "alepha/core";
|
|
59
|
+
|
|
60
|
+
class UserController {
|
|
61
|
+
getUser = $action({
|
|
62
|
+
schema: {
|
|
63
|
+
params: t.object({ id: t.string() }),
|
|
64
|
+
response: t.object({
|
|
65
|
+
name: t.string(),
|
|
66
|
+
email: t.string()
|
|
67
|
+
})
|
|
68
|
+
},
|
|
69
|
+
handler: async ({ params }) => {
|
|
70
|
+
return { name: "John", email: "john@example.com" };
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
```
|
|
52
75
|
|
|
53
|
-
###
|
|
76
|
+
### Database with Drizzle ORM
|
|
54
77
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
* **React ([@alepha/react](https://feunard.github.io/alepha/docs/alepha-react)) ⚛️:** Build full-stack, server-side rendered React applications with a file-based routing system (`$page`) that handles data fetching, hydration, and type-safe props.
|
|
78
|
+
```ts
|
|
79
|
+
import {$entity, $repository, pg} from "alepha/postgres";
|
|
80
|
+
import {t, Static} from "alepha";
|
|
59
81
|
|
|
60
|
-
|
|
82
|
+
export const users = $entity({
|
|
83
|
+
id: pg.primaryKey(),
|
|
84
|
+
name: t.string(),
|
|
85
|
+
email: t.string()
|
|
86
|
+
});
|
|
61
87
|
|
|
62
|
-
|
|
63
|
-
* **Queue ([@alepha/queue](https://feunard.github.io/alepha/docs/alepha-queue)) ⏳:** A simple and robust interface for background job processing. Define workers with the `$queue` descriptor and integrate with backends like Redis.
|
|
64
|
-
* **Cache ([@alepha/cache](https://feunard.github.io/alepha/docs/alepha-cache)) ⚡:** A flexible caching layer with support for TTL, automatic function caching (`$cache`), and multiple backends like in-memory or Redis.
|
|
65
|
-
* **Bucket ([@alepha/bucket](https://feunard.github.io/alepha/docs/alepha-bucket)) ☁️:** A unified API for file and object storage. Abstract away the details of local, in-memory, or cloud storage providers like Azure Blob Storage.
|
|
66
|
-
* **Scheduler ([@alepha/scheduler](https://feunard.github.io/alepha/docs/alepha-scheduler)) ⏰:** Schedule recurring tasks using cron expressions or fixed intervals with the `$scheduler` descriptor, with built-in support for distributed locking.
|
|
67
|
-
* **Topic ([@alepha/topic](https://feunard.github.io/alepha/docs/alepha-topic)) 📢:** A publish-subscribe (pub/sub) messaging interface for building event-driven architectures with `$topic` and `$subscriber`.
|
|
68
|
-
* **Lock ([@alepha/lock](https://feunard.github.io/alepha/docs/alepha-lock)) 🔒:** A distributed locking mechanism to ensure safe concurrent access to shared resources, using Redis or other backends.
|
|
88
|
+
type CreateUser = Static<typeof users.$insertSchema>;
|
|
69
89
|
|
|
70
|
-
|
|
90
|
+
class UserService {
|
|
91
|
+
users = $repository(users);
|
|
71
92
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
93
|
+
async create(data: CreateUser) {
|
|
94
|
+
return await this.users.create(data);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### React SSR Page
|
|
78
100
|
|
|
79
|
-
|
|
101
|
+
```tsx
|
|
102
|
+
import { $page } from "alepha/react";
|
|
80
103
|
|
|
81
|
-
|
|
104
|
+
class HomePage {
|
|
105
|
+
index = $page({
|
|
106
|
+
component: () => <div>Hello from React SSR!</div>
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
```
|
|
82
110
|
|
|
83
|
-
|
|
84
|
-
* **Head ([@alepha/react-head](https://feunard.github.io/alepha/docs/alepha-react-head)) SEO:** Manage your document's `<head>` for SEO and metadata. Control titles, meta tags, and more, both on the server and client.
|
|
85
|
-
* **i18n ([@alepha/react-i18n](https://feunard.github.io/alepha/docs/alepha-react-i18n)) 🌍:** A complete internationalization solution for your React applications, with support for lazy-loaded translation files and the `useI18n` hook.
|
|
86
|
-
* **Form ([@alepha/react-form](https://feunard.github.io/alepha/docs/alepha-react-form)) 📝:** Create powerful, type-safe forms with automatic validation using the `useForm` hook, powered by your TypeBox schemas.
|
|
111
|
+
## Core Concepts
|
|
87
112
|
|
|
88
|
-
|
|
113
|
+
- **Descriptors**: Define your app logic with `$action`, `$page`, `$repository`, `$cache`, `$email`, etc.
|
|
114
|
+
- **Type Safety**: TypeBox schemas validate data from DB to API to frontend
|
|
115
|
+
- **DI Container**: Built-in dependency injection using `$inject()`
|
|
116
|
+
- **Convention over Config**: Minimal boilerplate, sensible defaults
|
|
117
|
+
- **Full-Stack**: React SSR, Vite, class-based router with type-safe routing
|
|
118
|
+
|
|
119
|
+
## Stack
|
|
120
|
+
|
|
121
|
+
- Node.js 22+
|
|
122
|
+
- TypeScript
|
|
123
|
+
- React (SSR)
|
|
124
|
+
- Vite
|
|
125
|
+
- Drizzle ORM
|
|
126
|
+
- PostgreSQL
|
|
127
|
+
|
|
128
|
+
👉 For more information, please visit the [documentation](https://feunard.github.io/alepha/).
|
|
89
129
|
|
|
90
|
-
|
|
91
|
-
* **Command ([@alepha/command](https://feunard.github.io/alepha/docs/alepha-command)) ⌨️:** Build powerful, type-safe command-line interfaces and scripts directly within your application using the `$command` descriptor.
|
|
92
|
-
* **Retry ([@alepha/retry](https://feunard.github.io/alepha/docs/alepha-retry)) 🔄:** A declarative and powerful decorator (`$retry`) for automatically retrying failed operations with exponential backoff.
|
|
130
|
+
## License
|
|
93
131
|
|
|
132
|
+
MIT
|
package/batch.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { DateTimeProvider, DurationLike } from "alepha/datetime";
|
|
|
4
4
|
import * as _alepha_logger0 from "alepha/logger";
|
|
5
5
|
import * as _alepha_retry0 from "alepha/retry";
|
|
6
6
|
import { RetryDescriptorOptions } from "alepha/retry";
|
|
7
|
+
import * as typebox0 from "typebox";
|
|
7
8
|
|
|
8
9
|
//#region src/descriptors/$batch.d.ts
|
|
9
10
|
|
|
@@ -532,9 +533,7 @@ declare class BatchDescriptor<TItem extends TSchema, TResponse = any> extends De
|
|
|
532
533
|
protected readonly dateTime: DateTimeProvider;
|
|
533
534
|
protected readonly partitions: Map<any, any>;
|
|
534
535
|
protected activeHandlers: PromiseWithResolvers<void>[];
|
|
535
|
-
protected retry: _alepha_retry0.RetryDescriptorFn<(items:
|
|
536
|
-
params: [];
|
|
537
|
-
})["static"][]) => TResponse>;
|
|
536
|
+
protected retry: _alepha_retry0.RetryDescriptorFn<(items: typebox0.StaticType<[], "Encode", {}, {}, TItem>[]) => TResponse>;
|
|
538
537
|
/**
|
|
539
538
|
* Pushes an item into the batch. The item will be processed
|
|
540
539
|
* asynchronously with other items when the batch is flushed.
|
package/bucket.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as _alepha_core1 from "alepha";
|
|
|
2
2
|
import { Alepha, AlephaError, Descriptor, FileLike, KIND, Service } from "alepha";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as _alepha_logger0 from "alepha/logger";
|
|
5
|
-
import * as
|
|
5
|
+
import * as typebox0 from "typebox";
|
|
6
6
|
|
|
7
7
|
//#region src/providers/FileStorageProvider.d.ts
|
|
8
8
|
declare abstract class FileStorageProvider {
|
|
@@ -519,7 +519,7 @@ interface BucketFileOptions {
|
|
|
519
519
|
maxSize?: number;
|
|
520
520
|
}
|
|
521
521
|
declare class BucketDescriptor extends Descriptor<BucketDescriptorOptions> {
|
|
522
|
-
readonly provider:
|
|
522
|
+
readonly provider: FileStorageProvider | MemoryFileStorageProvider;
|
|
523
523
|
get name(): string;
|
|
524
524
|
/**
|
|
525
525
|
* Uploads a file to the bucket.
|
|
@@ -537,7 +537,7 @@ declare class BucketDescriptor extends Descriptor<BucketDescriptorOptions> {
|
|
|
537
537
|
* Downloads a file from the bucket.
|
|
538
538
|
*/
|
|
539
539
|
download(fileId: string): Promise<FileLike>;
|
|
540
|
-
protected $provider():
|
|
540
|
+
protected $provider(): FileStorageProvider | MemoryFileStorageProvider;
|
|
541
541
|
}
|
|
542
542
|
interface BucketFileOptions {
|
|
543
543
|
/**
|
|
@@ -579,10 +579,10 @@ declare class LocalFileStorageProvider implements FileStorageProvider {
|
|
|
579
579
|
protected path(container: string, fileId?: string): string;
|
|
580
580
|
protected isErrorNoEntry(error: unknown): boolean;
|
|
581
581
|
}
|
|
582
|
-
declare const fileMetadataSchema:
|
|
583
|
-
name:
|
|
584
|
-
type:
|
|
585
|
-
size:
|
|
582
|
+
declare const fileMetadataSchema: typebox0.TObject<{
|
|
583
|
+
name: typebox0.TString;
|
|
584
|
+
type: typebox0.TString;
|
|
585
|
+
size: typebox0.TNumber;
|
|
586
586
|
}>;
|
|
587
587
|
//#endregion
|
|
588
588
|
//#region src/index.d.ts
|
package/command.d.ts
CHANGED
|
@@ -1,10 +1,51 @@
|
|
|
1
1
|
import * as _alepha_core1 from "alepha";
|
|
2
|
-
import { Alepha, AlephaError, Async, Descriptor, KIND, Static, TObject, TSchema } from "alepha";
|
|
2
|
+
import { Alepha, AlephaError, Async, Descriptor, KIND, Static, TObject, TSchema, TString } from "alepha";
|
|
3
|
+
import * as _alepha_logger0 from "alepha/logger";
|
|
3
4
|
import * as fs from "node:fs/promises";
|
|
4
5
|
import { glob } from "node:fs/promises";
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
6
|
+
import * as readline_promises0 from "readline/promises";
|
|
7
|
+
import * as typebox0 from "typebox";
|
|
7
8
|
|
|
9
|
+
//#region src/helpers/Asker.d.ts
|
|
10
|
+
interface AskOptions<T extends TSchema = TString> {
|
|
11
|
+
/**
|
|
12
|
+
* Response schema expected.
|
|
13
|
+
*
|
|
14
|
+
* Recommended schemas:
|
|
15
|
+
* - t.string() - for free text input
|
|
16
|
+
* - t.number() - for numeric input
|
|
17
|
+
* - t.boolean() - for yes/no input (accepts "true", "false", "1", "0")
|
|
18
|
+
* - t.enum(["option1", "option2"]) - for predefined options
|
|
19
|
+
*
|
|
20
|
+
* You can use schema.default to provide a default value.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* ask("What is your name?", { schema: t.string({ default: "John Doe" }) })
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @default TString
|
|
28
|
+
*/
|
|
29
|
+
schema?: T;
|
|
30
|
+
/**
|
|
31
|
+
* Custom validation function.
|
|
32
|
+
* Throws an AlephaError in case of validation failure.
|
|
33
|
+
*/
|
|
34
|
+
validate?: (value: Static<T>) => void;
|
|
35
|
+
}
|
|
36
|
+
interface AskMethod {
|
|
37
|
+
<T extends TSchema = TString>(question: string, options?: AskOptions<T>): Promise<Static<T>>;
|
|
38
|
+
}
|
|
39
|
+
declare class Asker {
|
|
40
|
+
protected readonly log: _alepha_logger0.Logger;
|
|
41
|
+
readonly ask: AskMethod;
|
|
42
|
+
protected readonly alepha: Alepha;
|
|
43
|
+
constructor();
|
|
44
|
+
protected createAskMethod(): AskMethod;
|
|
45
|
+
protected prompt<T extends TSchema = TString>(question: string, options: AskOptions<T>): Promise<Static<T>>;
|
|
46
|
+
protected createPromptInterface(): readline_promises0.Interface;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
8
49
|
//#region src/helpers/Runner.d.ts
|
|
9
50
|
type Task = {
|
|
10
51
|
name: string;
|
|
@@ -19,13 +60,9 @@ interface RunOptions {
|
|
|
19
60
|
* Rename the command for logging purposes.
|
|
20
61
|
*/
|
|
21
62
|
alias?: string;
|
|
22
|
-
/**
|
|
23
|
-
* If true, the command will not be logged.
|
|
24
|
-
*/
|
|
25
|
-
silent?: boolean;
|
|
26
63
|
}
|
|
27
64
|
interface RunnerMethod {
|
|
28
|
-
(cmd: string | Array<string | Task>,
|
|
65
|
+
(cmd: string | Task | Array<string | Task>, options?: RunOptions | (() => any)): Promise<string>;
|
|
29
66
|
rm: (glob: string | string[], options?: RunOptions) => Promise<string>;
|
|
30
67
|
cp: (source: string, dest: string, options?: RunOptions) => Promise<string>;
|
|
31
68
|
}
|
|
@@ -59,14 +96,14 @@ declare class Runner {
|
|
|
59
96
|
* within your Alepha application structure.
|
|
60
97
|
*/
|
|
61
98
|
declare const $command: {
|
|
62
|
-
<T extends TObject>(options: CommandDescriptorOptions<T>): CommandDescriptor<T>;
|
|
99
|
+
<T extends TObject, A extends TSchema>(options: CommandDescriptorOptions<T, A>): CommandDescriptor<T, A>;
|
|
63
100
|
[KIND]: typeof CommandDescriptor;
|
|
64
101
|
};
|
|
65
|
-
interface CommandDescriptorOptions<T extends TObject> {
|
|
102
|
+
interface CommandDescriptorOptions<T extends TObject, A extends TSchema> {
|
|
66
103
|
/**
|
|
67
104
|
* The handler function to execute when the command is matched.
|
|
68
105
|
*/
|
|
69
|
-
handler: (args: CommandHandlerArgs<T>) => Async<void>;
|
|
106
|
+
handler: (args: CommandHandlerArgs<T, A>) => Async<void>;
|
|
70
107
|
/**
|
|
71
108
|
* The name of the command. If omitted, the property key is used.
|
|
72
109
|
*
|
|
@@ -85,19 +122,38 @@ interface CommandDescriptorOptions<T extends TObject> {
|
|
|
85
122
|
* A TypeBox object schema defining the flags for the command.
|
|
86
123
|
*/
|
|
87
124
|
flags?: T;
|
|
125
|
+
/**
|
|
126
|
+
* An optional TypeBox schema defining the arguments for the command.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* args: t.string()
|
|
130
|
+
* my-cli command <arg1: string>
|
|
131
|
+
*
|
|
132
|
+
* args: t.optional(t.string())
|
|
133
|
+
* my-cli command [arg1: string]
|
|
134
|
+
*
|
|
135
|
+
* args: t.tuple([t.string(), t.number()])
|
|
136
|
+
* my-cli command <arg1: string> <arg2: number>
|
|
137
|
+
*
|
|
138
|
+
* args: t.tuple([t.string(), t.optional(t.number())])
|
|
139
|
+
* my-cli command <arg1: string> [arg2: number]
|
|
140
|
+
*/
|
|
141
|
+
args?: A;
|
|
88
142
|
/**
|
|
89
143
|
* If false, skip summary message at the end of the command execution.
|
|
90
144
|
*/
|
|
91
145
|
summary?: boolean;
|
|
92
146
|
}
|
|
93
|
-
declare class CommandDescriptor<T extends TObject = TObject> extends Descriptor<CommandDescriptorOptions<T>> {
|
|
147
|
+
declare class CommandDescriptor<T extends TObject = TObject, A extends TSchema = TSchema> extends Descriptor<CommandDescriptorOptions<T, A>> {
|
|
94
148
|
readonly flags: TObject<{}>;
|
|
95
149
|
readonly aliases: string[];
|
|
96
150
|
get name(): string;
|
|
97
151
|
}
|
|
98
|
-
interface CommandHandlerArgs<T extends TObject> {
|
|
152
|
+
interface CommandHandlerArgs<T extends TObject, A extends TSchema = TSchema> {
|
|
99
153
|
flags: Static<T>;
|
|
154
|
+
args: A extends TSchema ? Static<A> : undefined;
|
|
100
155
|
run: RunnerMethod;
|
|
156
|
+
ask: AskMethod;
|
|
101
157
|
glob: typeof glob;
|
|
102
158
|
fs: typeof fs;
|
|
103
159
|
}
|
|
@@ -123,6 +179,7 @@ declare class CliProvider {
|
|
|
123
179
|
protected readonly alepha: Alepha;
|
|
124
180
|
protected readonly log: _alepha_logger0.Logger;
|
|
125
181
|
protected readonly runner: Runner;
|
|
182
|
+
protected readonly asker: Asker;
|
|
126
183
|
options: {
|
|
127
184
|
name: string;
|
|
128
185
|
description: string;
|
|
@@ -132,7 +189,7 @@ declare class CliProvider {
|
|
|
132
189
|
help: {
|
|
133
190
|
aliases: string[];
|
|
134
191
|
description: string;
|
|
135
|
-
schema:
|
|
192
|
+
schema: typebox0.TBoolean;
|
|
136
193
|
};
|
|
137
194
|
};
|
|
138
195
|
protected readonly onReady: _alepha_core1.HookDescriptor<"ready">;
|
|
@@ -144,6 +201,10 @@ declare class CliProvider {
|
|
|
144
201
|
aliases: string[];
|
|
145
202
|
schema: TSchema;
|
|
146
203
|
}[]): Record<string, any>;
|
|
204
|
+
protected parseCommandArgs(argv: string[], schema?: TSchema): any;
|
|
205
|
+
protected parseArgumentValue(value: string, schema: TSchema): any;
|
|
206
|
+
protected generateArgsUsage(schema?: TSchema): string;
|
|
207
|
+
protected getTypeName(schema: TSchema): string;
|
|
147
208
|
printHelp(command?: CommandDescriptor<any>): void;
|
|
148
209
|
private getMaxCmdLength;
|
|
149
210
|
private getMaxFlagLength;
|
|
@@ -160,7 +221,7 @@ declare class CliProvider {
|
|
|
160
221
|
* @module alepha.command
|
|
161
222
|
*/
|
|
162
223
|
declare const AlephaCommand: _alepha_core1.Service<_alepha_core1.Module>;
|
|
163
|
-
declare module "
|
|
224
|
+
declare module "typebox" {
|
|
164
225
|
interface StringOptions {
|
|
165
226
|
/**
|
|
166
227
|
* Additional aliases for the flags.
|
|
@@ -173,5 +234,5 @@ declare module "@sinclair/typebox" {
|
|
|
173
234
|
//# sourceMappingURL=index.d.ts.map
|
|
174
235
|
|
|
175
236
|
//#endregion
|
|
176
|
-
export { $command, AlephaCommand, CliProvider, CommandDescriptor, CommandDescriptorOptions, CommandError, CommandHandlerArgs, RunOptions, Runner, RunnerMethod, Task };
|
|
237
|
+
export { $command, AlephaCommand, AskMethod, AskOptions, Asker, CliProvider, CommandDescriptor, CommandDescriptorOptions, CommandError, CommandHandlerArgs, RunOptions, Runner, RunnerMethod, Task };
|
|
177
238
|
//# sourceMappingURL=index.d.ts.map
|