alepha 0.6.8 → 0.6.10

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/cache.d.ts CHANGED
@@ -92,6 +92,7 @@ interface TSchema extends TKind, SchemaOptions {
92
92
  }
93
93
 
94
94
  declare class CacheProvider {
95
+ constructor();
95
96
  /**
96
97
  * Get the value of a key.
97
98
  *
package/core.d.ts CHANGED
@@ -8,6 +8,7 @@ import { ValueError } from '@sinclair/typebox/errors';
8
8
  import { ReadableStream as ReadableStream$1 } from 'node:stream/web';
9
9
  import * as TypeBoxValue from '@sinclair/typebox/value';
10
10
  export { TypeBoxValue };
11
+ import { Readable } from 'node:stream';
11
12
 
12
13
  /**
13
14
  * Used for identifying descriptors.
@@ -16,6 +17,13 @@ export { TypeBoxValue };
16
17
  */
17
18
  declare const KIND: unique symbol;
18
19
 
20
+ /**
21
+ * Used for identifying descriptors.
22
+ *
23
+ * @internal
24
+ */
25
+ declare const OPTIONS: unique symbol;
26
+
19
27
  /**
20
28
  * Represents a value that can be either a value or a promise.
21
29
  */
@@ -83,42 +91,7 @@ interface ClassProvider<T extends object = any> {
83
91
  parents: Array<Class | null>;
84
92
  }
85
93
 
86
- /**
87
- * Used for identifying descriptors.
88
- *
89
- * @internal
90
- */
91
- declare const OPTIONS: unique symbol;
92
-
93
94
  declare const KEY = "HOOK";
94
- interface Hooks {
95
- /**
96
- * Triggered during the configuration phase. Before the start phase.
97
- *
98
- * - Configuration should technically be called many times without any side effects.
99
- * - Spamming Alepha#configure() should not cause any issues.
100
- */
101
- configure: Alepha;
102
- /**
103
- * Triggered during the start phase. When `Alepha#start()` is called.
104
- *
105
- * - Start is called only once. It should not be called multiple times.
106
- */
107
- start: Alepha;
108
- /**
109
- * Triggered during the ready phase. After the start phase.
110
- *
111
- * - Ready is called only once. It should not be called multiple times.
112
- */
113
- ready: Alepha;
114
- /**
115
- * Triggered during the stop phase.
116
- *
117
- * - Stop is called only once. It should not be called multiple times.
118
- * - Stop should be called after a SIGINT or SIGTERM signal in order to gracefully shutdown the application.
119
- */
120
- stop: Alepha;
121
- }
122
95
  interface HookOptions<T extends keyof Hooks> {
123
96
  /**
124
97
  * The name of the hook. "configure", "start", "ready", "stop", ...
@@ -441,6 +414,35 @@ interface State {
441
414
  afterEach?: (run: any) => any;
442
415
  onTestFinished?: (run: any) => any;
443
416
  }
417
+ interface Hooks {
418
+ echo: any;
419
+ /**
420
+ * Triggered during the configuration phase. Before the start phase.
421
+ *
422
+ * - Configuration should technically be called many times without any side effects.
423
+ * - Spamming Alepha#configure() should not cause any issues.
424
+ */
425
+ configure: Alepha;
426
+ /**
427
+ * Triggered during the start phase. When `Alepha#start()` is called.
428
+ *
429
+ * - Start is called only once. It should not be called multiple times.
430
+ */
431
+ start: Alepha;
432
+ /**
433
+ * Triggered during the ready phase. After the start phase.
434
+ *
435
+ * - Ready is called only once. It should not be called multiple times.
436
+ */
437
+ ready: Alepha;
438
+ /**
439
+ * Triggered during the stop phase.
440
+ *
441
+ * - Stop is called only once. It should not be called multiple times.
442
+ * - Stop should be called after a SIGINT or SIGTERM signal in order to gracefully shutdown the application.
443
+ */
444
+ stop: Alepha;
445
+ }
444
446
  /**
445
447
  *
446
448
  *
@@ -622,10 +624,11 @@ declare class Alepha {
622
624
  skipRegistration?: boolean;
623
625
  args?: any[];
624
626
  }): T;
625
- on<T extends keyof Hooks>(event: T, hook: Hook<T>): () => void;
627
+ on<T extends keyof Hooks>(event: T, hookOrFunc: Hook<T> | ((payload: Hooks[T]) => Async<void>)): () => void;
626
628
  emit<T extends keyof Hooks>(func: keyof Hooks, payload: Hooks[T], options?: {
627
629
  reverse?: boolean;
628
630
  log?: boolean;
631
+ catch?: boolean;
629
632
  }): Promise<void>;
630
633
  /**
631
634
  * Casts the given value to the specified schema.
@@ -733,11 +736,15 @@ declare const $logger: (name?: string) => Logger;
733
736
  */
734
737
  interface RetryDescriptorOptions<T extends (...args: any[]) => any> {
735
738
  /**
739
+ * Maximum number of attempts.
736
740
  *
741
+ * @default 3
737
742
  */
738
743
  max?: number;
739
744
  /**
745
+ * Delay in milliseconds.
740
746
  *
747
+ * @default 0
741
748
  */
742
749
  delay?: number;
743
750
  /**
@@ -778,26 +785,6 @@ declare class TypeBoxError extends Error {
778
785
  constructor(value: ValueError);
779
786
  }
780
787
 
781
- interface EventEmitterItem<T extends object> {
782
- name: keyof T;
783
- handler: (arg: any) => Async<void>;
784
- }
785
- declare class EventEmitter<T extends object> {
786
- protected events: EventEmitterItem<T>[];
787
- /**
788
- *
789
- * @param name
790
- * @param handler
791
- */
792
- on<Key extends keyof T>(name: Key, handler: (arg: T[Key]) => void): () => void;
793
- /**
794
- *
795
- * @param name
796
- * @param data
797
- */
798
- emit<Key extends keyof T>(name: Key, data: T[Key]): Promise<void>;
799
- }
800
-
801
788
  declare class TypeProvider {
802
789
  static DEFAULT_STRING_MAX_LENGTH: number;
803
790
  static DEFAULT_LONG_STRING_MAX_LENGTH: number;
@@ -963,19 +950,25 @@ declare class TypeProvider {
963
950
  file: (options?: {
964
951
  max?: number;
965
952
  }) => TFile;
953
+ stream: () => TStream;
966
954
  }
967
955
  interface FileLike {
968
956
  name: string;
969
957
  type: string;
970
958
  size: number;
971
959
  lastModified: number;
972
- stream(): ReadableStream | ReadableStream$1;
960
+ stream(): StreamLike;
973
961
  arrayBuffer(): Promise<ArrayBuffer>;
974
962
  text(): Promise<string>;
963
+ filepath?: string;
975
964
  }
976
- declare const t: TypeProvider;
977
965
  type TFile = TUnsafe<FileLike>;
966
+ type StreamLike = ReadableStream | ReadableStream$1 | Readable;
967
+ type TStream = TUnsafe<StreamLike>;
968
+ declare const t: TypeProvider;
978
969
  declare const isTypeFile: (value: TSchema) => value is TFile;
970
+ declare const isFileLike: (value: any) => value is FileLike;
971
+ declare const isTypeStream: (value: TSchema) => value is TStream;
979
972
  type TextLength = "short" | "long" | "rich";
980
973
  interface AlephaStringOptions extends StringOptions {
981
974
  size?: TextLength;
@@ -988,4 +981,4 @@ declare const run: (arg: Alepha | Class | ((env?: Env) => Alepha), opts?: {
988
981
  ready?: (alepha: Alepha) => Async<void>;
989
982
  }) => Alepha;
990
983
 
991
- export { $cursor, $hook, $inject, $logger, $retry, Alepha, type AlephaStringOptions, AppNotStartedError, type Async, type AsyncFn, type AsyncLocalStorageData, AsyncLocalStorageProvider, COLORS, CircularDependencyError, type Class, type ClassEntry, type ClassProvider, type ClassSwap, ContainerLockedError, type CursorDescriptor, type Descriptor, type DescriptorIdentifier, type DescriptorItem, type Env, EventEmitter, type EventEmitterItem, EventEmitterLike, type FileLike, type Hook, type HookDescriptor, type HookOptions, type Hooks, KIND, LEVEL_COLORS, type LogLevel, Logger, type LoggerEnv, type LoggerOptions, MockLogger, type MockLoggerStore, NotImplementedError, OPTIONS, PROVIDER, type PromiseFn, type RetryDescriptorOptions, type State, type TFile, type TextLength, TypeBoxError, TypeProvider, __alephaRef, __bind, __descriptor, descriptorEvents, isDescriptorValue, isTypeFile, isUUID, run, t };
984
+ export { $cursor, $hook, $inject, $logger, $retry, Alepha, type AlephaStringOptions, AppNotStartedError, type Async, type AsyncFn, type AsyncLocalStorageData, AsyncLocalStorageProvider, COLORS, CircularDependencyError, type Class, type ClassEntry, type ClassProvider, type ClassSwap, ContainerLockedError, type CursorDescriptor, type Descriptor, type DescriptorIdentifier, type DescriptorItem, type Env, EventEmitterLike, type FileLike, type Hook, type HookDescriptor, type HookOptions, type Hooks, KIND, LEVEL_COLORS, type LogLevel, Logger, type LoggerEnv, type LoggerOptions, MockLogger, type MockLoggerStore, NotImplementedError, OPTIONS, PROVIDER, type PromiseFn, type RetryDescriptorOptions, type State, type StreamLike, type TFile, type TStream, type TextLength, TypeBoxError, TypeProvider, __alephaRef, __bind, __descriptor, descriptorEvents, isDescriptorValue, isFileLike, isTypeFile, isTypeStream, isUUID, run, t };
package/lock.d.ts CHANGED
@@ -123,6 +123,7 @@ declare const $lock: {
123
123
  * Store Provider Interface
124
124
  */
125
125
  declare class LockProvider {
126
+ constructor();
126
127
  /**
127
128
  * Set the string value of a key.
128
129
  *
@@ -238,7 +239,7 @@ declare class MemoryLockProvider implements LockProvider {
238
239
  /**
239
240
  * A store provider that uses Redis.
240
241
  */
241
- declare class RedisLockProvider extends LockProvider {
242
+ declare class RedisLockProvider implements LockProvider {
242
243
  protected readonly log: _alepha_core.Logger;
243
244
  protected readonly redisProvider: RedisProvider;
244
245
  /**
package/package.json CHANGED
@@ -1,31 +1,37 @@
1
1
  {
2
2
  "name": "alepha",
3
- "version": "0.6.8",
3
+ "version": "0.6.10",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
+ "description": "TypeScript framework for building full-stack apps with strict conventions, custom schemas, and React-based SPA or SSR without filesystem-based routing.",
7
+ "homepage": "https://github.com/feunard/alepha",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/feunard/alepha.git"
11
+ },
6
12
  "main": "./core.js",
7
13
  "types": "./core.d.ts",
8
14
  "dependencies": {
9
- "@alepha/cache": "0.6.8",
10
- "@alepha/core": "0.6.8",
11
- "@alepha/datetime": "0.6.8",
12
- "@alepha/lock": "0.6.8",
13
- "@alepha/postgres": "0.6.8",
14
- "@alepha/queue": "0.6.8",
15
- "@alepha/react": "0.6.8",
16
- "@alepha/react-auth": "0.6.8",
17
- "@alepha/redis": "0.6.8",
18
- "@alepha/scheduler": "0.6.8",
19
- "@alepha/security": "0.6.8",
20
- "@alepha/server": "0.6.8",
21
- "@alepha/server-cookies": "0.6.8",
22
- "@alepha/server-metrics": "0.6.8",
23
- "@alepha/server-proxy": "0.6.8",
24
- "@alepha/server-static": "0.6.8",
25
- "@alepha/server-swagger": "0.6.8",
26
- "@alepha/testing": "0.6.8",
27
- "@alepha/topic": "0.6.8",
28
- "@alepha/vite": "0.6.8"
15
+ "@alepha/cache": "0.6.10",
16
+ "@alepha/core": "0.6.10",
17
+ "@alepha/datetime": "0.6.10",
18
+ "@alepha/lock": "0.6.10",
19
+ "@alepha/postgres": "0.6.10",
20
+ "@alepha/queue": "0.6.10",
21
+ "@alepha/react": "0.6.10",
22
+ "@alepha/react-auth": "0.6.10",
23
+ "@alepha/redis": "0.6.10",
24
+ "@alepha/scheduler": "0.6.10",
25
+ "@alepha/security": "0.6.10",
26
+ "@alepha/server": "0.6.10",
27
+ "@alepha/server-cookies": "0.6.10",
28
+ "@alepha/server-metrics": "0.6.10",
29
+ "@alepha/server-proxy": "0.6.10",
30
+ "@alepha/server-static": "0.6.10",
31
+ "@alepha/server-swagger": "0.6.10",
32
+ "@alepha/testing": "0.6.10",
33
+ "@alepha/topic": "0.6.10",
34
+ "@alepha/vite": "0.6.10"
29
35
  },
30
36
  "peerDependencies": {
31
37
  "@types/react": "^19",
@@ -159,5 +165,19 @@
159
165
  "require": "./server/swagger.cjs",
160
166
  "types": "./server/swagger.d.ts"
161
167
  }
162
- }
168
+ },
169
+ "keywords": [
170
+ "alepha",
171
+ "cache",
172
+ "datetime",
173
+ "lock",
174
+ "postgres",
175
+ "queue",
176
+ "react",
177
+ "redis",
178
+ "scheduler",
179
+ "security",
180
+ "server",
181
+ "topic"
182
+ ]
163
183
  }
package/postgres.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _alepha_core from '@alepha/core';
2
2
  import { TObject as TObject$1, Static as Static$1, Alepha, KIND, OPTIONS } from '@alepha/core';
3
3
  import * as _sinclair_typebox from '@sinclair/typebox';
4
- import { TObject, Static, TSchema, ObjectOptions, Kind, TProperties, Evaluate, TReadonly, TOptional, TAdditionalProperties, OptionalKind, TArray, TIntersect, TBoolean, TInteger, IntegerOptions, StringOptions, TOptionalWithFlag } from '@sinclair/typebox';
4
+ import { TObject, Static, TSchema, ObjectOptions, Kind, TProperties, Evaluate, TReadonly, TOptional, TAdditionalProperties, OptionalKind, TArray, TIntersect, TRecord, TBoolean, TInteger, IntegerOptions, StringOptions, TOptionalWithFlag } from '@sinclair/typebox';
5
5
  import * as drizzle_orm from 'drizzle-orm';
6
6
  import { TableConfig, SQLWrapper, SQL, BuildColumns } from 'drizzle-orm';
7
7
  export { sql } from 'drizzle-orm';
@@ -114,6 +114,7 @@ type PgTableWithColumnsAndSchema<T extends TableConfig, R extends TObject$1> = P
114
114
 
115
115
  type SQLLike = SQLWrapper | string;
116
116
  declare class PostgresProvider {
117
+ constructor();
117
118
  /**
118
119
  * Get the database instance
119
120
  */
@@ -662,11 +663,11 @@ type PageQuery = Static$1<typeof pageQuerySchema>;
662
663
  * @param objectSchema
663
664
  * @param options
664
665
  */
665
- declare const pageSchema: <T extends TObject | TIntersect>(objectSchema: T, options?: ObjectOptions) => TPage<T>;
666
+ declare const pageSchema: <T extends TObject | TIntersect | TRecord>(objectSchema: T, options?: ObjectOptions) => TPage<T>;
666
667
  /**
667
668
  *
668
669
  */
669
- type TPage<T extends TObject | TIntersect> = TObject<{
670
+ type TPage<T extends TObject | TIntersect | TRecord> = TObject<{
670
671
  content: TArray<T>;
671
672
  can: TObject<{
672
673
  next: TBoolean;
@@ -696,10 +697,6 @@ type Page<T> = {
696
697
  *
697
698
  */
698
699
  declare class Repository<TTable extends PgTableWithColumns<TableConfig$1>, TTableSchema extends TObject> {
699
- readonly options: {
700
- table: TTable;
701
- schema: TTableSchema;
702
- };
703
700
  readonly provider: PostgresProvider;
704
701
  protected readonly alepha: Alepha;
705
702
  static of: <TEntity extends TableConfig$1, TSchema extends TObject>(table: PgTableWithColumnsAndSchema<TEntity, TSchema>) => (new () => Repository<PgTableWithColumnsAndSchema<TEntity, TSchema>, TSchema>);
@@ -724,6 +721,10 @@ declare class Repository<TTable extends PgTableWithColumns<TableConfig$1>, TTabl
724
721
  table: TTable;
725
722
  schema: TTableSchema;
726
723
  };
724
+ readonly options: {
725
+ table: TTable;
726
+ schema: TTableSchema;
727
+ };
727
728
  constructor(options: {
728
729
  table: TTable;
729
730
  schema: TTableSchema;
package/queue.d.ts CHANGED
@@ -60,6 +60,7 @@ interface TSchema extends TKind, SchemaOptions {
60
60
  }
61
61
 
62
62
  declare class QueueProvider {
63
+ constructor();
63
64
  /**
64
65
  * Push a message to the queue.
65
66
  *
package/redis.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _alepha_core from '@alepha/core';
2
2
  import { Static, Alepha } from '@alepha/core';
3
3
  import * as Redis from 'ioredis';
4
- import Redis__default from 'ioredis';
4
+ import Redis__default, { RedisOptions } from 'ioredis';
5
5
 
6
6
  /** Symbol key applied to readonly types */
7
7
  declare const ReadonlyKind: unique symbol;
@@ -110,6 +110,7 @@ declare class RedisProvider {
110
110
  * Close the connection to the Redis server.
111
111
  */
112
112
  close(): Promise<void>;
113
+ duplicate(options?: Partial<RedisOptions>): RedisClient;
113
114
  /**
114
115
  * Redis subscriber client factory method.
115
116
  */
package/security.d.ts CHANGED
@@ -2,6 +2,28 @@ import * as _alepha_core from '@alepha/core';
2
2
  import { Static as Static$1, KIND, OPTIONS, Alepha } from '@alepha/core';
3
3
  import { JWSHeaderParameters, FlattenedJWSInput, CryptoKey, KeyObject, JSONWebKeySet, JWTVerifyResult, JWTPayload, JWTHeaderParameters } from 'jose';
4
4
 
5
+ /**
6
+ * Represents a User Account extracted from JWT.
7
+ */
8
+ interface UserAccountInfo {
9
+ /**
10
+ * ID of user account. Based on JWT.sub.
11
+ */
12
+ id: string;
13
+ /**
14
+ * Represents the roles assigned to a user.
15
+ */
16
+ roles?: string[];
17
+ /**
18
+ * User full name, if available.
19
+ */
20
+ name?: string;
21
+ /**
22
+ * Organization ID, if available.
23
+ */
24
+ organization?: string;
25
+ }
26
+
5
27
  /** Symbol key applied to readonly types */
6
28
  declare const ReadonlyKind: unique symbol;
7
29
  /** Symbol key applied to optional types */
@@ -142,39 +164,6 @@ interface TSchema extends TKind, SchemaOptions {
142
164
  static: unknown;
143
165
  }
144
166
 
145
- declare const roleSchema: TObject<{
146
- name: TString;
147
- description: TOptional<TString>;
148
- default: TOptional<TBoolean>;
149
- permissions: TArray<TObject<{
150
- name: TString;
151
- ownership: TOptional<TBoolean>;
152
- }>>;
153
- }>;
154
- type Role = Static$1<typeof roleSchema>;
155
-
156
- /**
157
- * Represents a User Account extracted from JWT.
158
- */
159
- interface UserAccountInfo {
160
- /**
161
- * ID of user account. Based on JWT.sub.
162
- */
163
- id: string;
164
- /**
165
- * Represents the roles assigned to a user.
166
- */
167
- roles?: Role[];
168
- /**
169
- * User full name, if available.
170
- */
171
- name?: string;
172
- /**
173
- * Organization ID, if available.
174
- */
175
- organization?: string;
176
- }
177
-
178
167
  declare const permissionSchema: TObject<{
179
168
  name: TString;
180
169
  group: TOptional<TString>;
@@ -241,6 +230,17 @@ interface UserAccountToken extends UserAccountInfo {
241
230
  ownership?: string | boolean;
242
231
  }
243
232
 
233
+ declare const roleSchema: TObject<{
234
+ name: TString;
235
+ description: TOptional<TString>;
236
+ default: TOptional<TBoolean>;
237
+ permissions: TArray<TObject<{
238
+ name: TString;
239
+ ownership: TOptional<TBoolean>;
240
+ }>>;
241
+ }>;
242
+ type Role = Static$1<typeof roleSchema>;
243
+
244
244
  /**
245
245
  * Provides utilities for working with JSON Web Tokens (JWT).
246
246
  */
@@ -406,9 +406,9 @@ declare class SecurityProvider {
406
406
  * Bonus: we check also if the user has "ownership" flag.
407
407
  *
408
408
  * @param permissionLike - The permission to check for.
409
- * @param roles - The roles to check for the permission.
409
+ * @param roleEntries - The roles to check for the permission.
410
410
  */
411
- checkPermission(permissionLike: string | Permission, ...roles: Role[]): SecurityCheckResult;
411
+ checkPermission(permissionLike: string | Permission, ...roleEntries: string[]): SecurityCheckResult;
412
412
  /**
413
413
  * Creates a user account from the provided payload.
414
414
  *
@@ -423,7 +423,7 @@ declare class SecurityProvider {
423
423
  * @param permission - The permission to check for.
424
424
  * @returns True if the user has the role, false otherwise.
425
425
  */
426
- can(roleName: string, permission: string | Permission): boolean;
426
+ can(role: string, permission: string | Permission): boolean;
427
427
  /**
428
428
  * Converts a permission object to a string.
429
429
  *
@@ -550,6 +550,10 @@ interface RealmDescriptor {
550
550
  * Set all roles in the realm.
551
551
  */
552
552
  setRoles(roles: Role[]): Promise<void>;
553
+ /**
554
+ * Get a role by name, throws an error if not found.
555
+ */
556
+ getRoleByName(name: string): Role;
553
557
  /**
554
558
  * Create a token for the subject.
555
559
  */
package/server/proxy.d.ts CHANGED
@@ -5,9 +5,10 @@ import { ServerRequest, ServerRouterProvider } from '@alepha/server';
5
5
  type ProxyDescriptorOptions = {
6
6
  path: string;
7
7
  target: string;
8
+ disabled?: boolean;
8
9
  beforeRequest?: (request: ServerRequest, proxyRequest: RequestInit) => Async<void>;
9
10
  afterResponse?: (request: ServerRequest, proxyResponse: Response) => Async<void>;
10
- disabled?: boolean;
11
+ rewrite?: (url: URL) => void;
11
12
  };
12
13
  interface ProxyDescriptor {
13
14
  [KIND]: "PROXY";
package/server.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import * as _alepha_core from '@alepha/core';
2
- import { Static as Static$1, TSchema as TSchema$1, Async, Alepha, OPTIONS, KIND, FileLike } from '@alepha/core';
2
+ import { Static as Static$1, TObject as TObject$1, TSchema as TSchema$1, Async, StreamLike, Alepha, OPTIONS, KIND, FileLike } from '@alepha/core';
3
3
  export { KIND } from '@alepha/core';
4
- import { UserAccountToken, Permission, SecurityProvider } from '@alepha/security';
4
+ import { UserAccountToken, Permission, SecurityProvider, JwtProvider } from '@alepha/security';
5
5
  import { IncomingMessage, ServerResponse as ServerResponse$1 } from 'node:http';
6
6
  import { Readable } from 'node:stream';
7
- import { ReadableStream as ReadableStream$1 } from 'node:stream/web';
7
+ import { ReadableStream } from 'node:stream/web';
8
8
  import { Route, RouterProvider } from '@alepha/router';
9
9
  import * as _alepha_cache from '@alepha/cache';
10
10
  import { DurationLike } from '@alepha/datetime';
@@ -189,7 +189,7 @@ interface TSchema extends TKind, SchemaOptions {
189
189
  declare const routeMethods: readonly ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS", "CONNECT", "TRACE"];
190
190
  type RouteMethod = (typeof routeMethods)[number];
191
191
 
192
- declare const envSchema$4: _alepha_core.TObject<{
192
+ declare const envSchema$4: TObject$1<{
193
193
  SERVER_ALS_ENABLED: TBoolean;
194
194
  }>;
195
195
  declare module "alepha" {
@@ -211,7 +211,7 @@ declare class ServerRouterProvider extends RouterProvider<ServerRouteWithHandler
211
211
  };
212
212
  body: any;
213
213
  }>;
214
- protected doRequestHandler(route: ServerRoute, request: ServerRequest, responseType: ResponseType, withAls: boolean): Promise<void>;
214
+ protected tryRequestProcessing(route: ServerRoute, request: ServerRequest, responseType: ResponseType, withAls: boolean): Promise<void>;
215
215
  protected getResponseType(schema?: RequestConfigSchema): ResponseType;
216
216
  protected errorHandler(route: ServerRoute, request: ServerRequest, error: Error): Promise<void>;
217
217
  validateRequest(route: {
@@ -221,16 +221,16 @@ declare class ServerRouterProvider extends RouterProvider<ServerRouteWithHandler
221
221
  }
222
222
  interface RequestConfigSchema {
223
223
  body?: TSchema$1;
224
- params?: TSchema$1;
225
- query?: TSchema$1;
226
- headers?: TSchema$1;
224
+ params?: TObject$1;
225
+ query?: TObject$1;
226
+ headers?: TObject$1;
227
227
  response?: TSchema$1;
228
228
  }
229
229
  interface ServerRequestConfig<TConfig extends RequestConfigSchema = RequestConfigSchema> {
230
230
  body: TConfig["body"] extends TSchema$1 ? Static$1<TConfig["body"]> : any;
231
- headers: TConfig["headers"] extends TSchema$1 ? Static$1<TConfig["headers"]> : Record<string, string>;
232
- params: TConfig["params"] extends TSchema$1 ? Static$1<TConfig["params"]> : Record<string, string>;
233
- query: TConfig["query"] extends TSchema$1 ? Static$1<TConfig["query"]> : Record<string, string>;
231
+ headers: TConfig["headers"] extends TObject$1 ? Static$1<TConfig["headers"]> : Record<string, string>;
232
+ params: TConfig["params"] extends TObject$1 ? Static$1<TConfig["params"]> : Record<string, string>;
233
+ query: TConfig["query"] extends TObject$1 ? Static$1<TConfig["query"]> : Record<string, string>;
234
234
  }
235
235
  type ServerRequestConfigEntry<TConfig extends RequestConfigSchema = RequestConfigSchema> = Partial<ServerRequestConfig<TConfig>>;
236
236
  interface ServerRequest<TConfig extends RequestConfigSchema = RequestConfigSchema> extends ServerRequestConfig<TConfig> {
@@ -244,7 +244,7 @@ interface ServerRequest<TConfig extends RequestConfigSchema = RequestConfigSchem
244
244
  res: ServerResponse$1;
245
245
  };
246
246
  };
247
- user?: UserAccountToken;
247
+ user: UserAccountToken;
248
248
  }
249
249
  interface ServerRoute<TConfig extends RequestConfigSchema = RequestConfigSchema> extends Route {
250
250
  method?: RouteMethod;
@@ -253,19 +253,19 @@ interface ServerRoute<TConfig extends RequestConfigSchema = RequestConfigSchema>
253
253
  schema?: TConfig;
254
254
  }
255
255
  type ServerResponseBody<TConfig extends RequestConfigSchema = RequestConfigSchema> = TConfig["response"] extends TSchema$1 ? Static$1<TConfig["response"]> : ResponseBodyType;
256
- type ResponseType = "json" | "text" | "void" | "stream" | "buffer" | "file";
257
- type ResponseBodyType = string | ArrayBuffer | Readable | ReadableStream$1 | ReadableStream | undefined | null | void;
256
+ type ResponseType = "json" | "text" | "void" | "file" | "any";
257
+ type ResponseBodyType = string | Buffer | StreamLike | undefined | null | void;
258
258
  type ServerHandler<TConfig extends RequestConfigSchema = RequestConfigSchema> = (request: ServerRequest<TConfig>) => Async<ServerResponseBody<TConfig>>;
259
259
  interface ServerReply {
260
260
  headers: Record<string, string> & {
261
261
  "set-cookie"?: string[];
262
262
  };
263
263
  status?: number;
264
- body?: ResponseBodyType;
264
+ body?: any;
265
265
  redirect(url: string): void;
266
266
  }
267
267
  interface ServerResponse {
268
- body: string | ArrayBuffer | Readable | ReadableStream$1;
268
+ body: string | ArrayBuffer | Readable | ReadableStream;
269
269
  headers: Record<string, string>;
270
270
  status: number;
271
271
  }
@@ -426,7 +426,12 @@ declare class HttpError extends Error {
426
426
  cause: {
427
427
  name: string;
428
428
  message: string;
429
- } | undefined;
429
+ };
430
+ } | {
431
+ status: number;
432
+ error: string | undefined;
433
+ message: string;
434
+ cause?: undefined;
430
435
  };
431
436
  readonly status: number;
432
437
  readonly error?: string;
@@ -446,23 +451,41 @@ declare class HttpError extends Error {
446
451
  }
447
452
  declare const errorNameByStatus: Record<number, string>;
448
453
 
454
+ declare class RouteDescriptorHelper {
455
+ name(options: RouteDescriptorOptions, instance: any, key: string): string;
456
+ path(options: RouteDescriptorOptions, instance: any, key: string, prefix?: string): string;
457
+ link(options: RouteDescriptorOptions, instance: any, key: string, prefix?: string): HttpClientLink;
458
+ method(options: {
459
+ method?: string;
460
+ schema?: any;
461
+ }): RouteMethod;
462
+ permission(options: RouteDescriptorOptions, instance: any, key: string, prefix?: string): Permission;
463
+ group(options: RouteDescriptorOptions, instance: any): string;
464
+ isMultipart(options: {
465
+ schema?: RequestConfigSchema;
466
+ }): boolean;
467
+ bodyContentType(options: RouteDescriptorOptions): string | undefined;
468
+ protected short(name: string): string;
469
+ }
470
+
449
471
  declare class HttpClient {
450
472
  protected readonly alepha: Alepha;
451
473
  protected readonly env: {
452
474
  SERVER_API_URL: string;
475
+ CLIENT_API_PREFIX: string;
453
476
  };
477
+ protected readonly helper: RouteDescriptorHelper;
454
478
  readonly URL_LINKS = "/_links";
455
479
  readonly cache: _alepha_cache.CacheDescriptor<any, any[]>;
456
480
  links?: Array<HttpClientLink>;
457
481
  protected readonly pendingRequests: HttpClientPendingRequests;
458
- protected host: string;
459
482
  json<T = any>(url: string, options?: RequestInit): Promise<T>;
460
483
  clear(): Promise<void>;
461
- createFetchFunction(link: HttpClientLink, options?: FetchFactoryAdditionalOptions): (config?: Partial<ClientRequestEntry>, fetchOptions?: ClientRequestOptions) => Promise<any>;
484
+ createFetchFunction(link: HttpClientLink, options?: FetchFactoryAdditionalOptions): (config?: Partial<ClientRequestEntry>, request?: ClientRequestOptions) => Promise<any>;
462
485
  request(args: {
463
- link: HttpClientLink;
464
- fetch?: ClientRequestOptions;
465
486
  config?: ServerRequestConfigEntry;
487
+ link: HttpClientLink;
488
+ request?: ClientRequestOptions;
466
489
  host?: string;
467
490
  }): Promise<any>;
468
491
  protected url(host: string, link: HttpClientLink, args: ServerRequestConfigEntry): string;
@@ -476,12 +499,23 @@ declare class HttpClient {
476
499
  * @protected
477
500
  */
478
501
  protected response(response: Response, options: FetchRunOptions): Promise<Response | any>;
502
+ protected isMaybeFile(response: Response): boolean;
503
+ protected getFileLike(response: Response, defaultFileName?: string): FileLike;
479
504
  protected pathVariables(url: string, action: HttpClientLink, args?: ServerRequestConfigEntry): string;
480
- protected queryParams(url: string, action: HttpClientLink, args?: ServerRequestConfigEntry): string;
505
+ queryParams(url: string, action: {
506
+ schema?: {
507
+ query?: TObject$1;
508
+ };
509
+ }, args?: ServerRequestConfigEntry): string;
481
510
  of<T extends object>(options?: {
482
511
  group?: string;
483
512
  host?: string | (() => string);
484
513
  }): HttpVirtualClient<T>;
514
+ follow(name: string, config?: any, options?: {
515
+ request?: ClientRequestOptions;
516
+ group?: string;
517
+ host?: string | (() => string);
518
+ }): Promise<any>;
485
519
  can(name: string): boolean;
486
520
  getLinks(opts?: {
487
521
  force?: boolean;
@@ -506,6 +540,8 @@ interface HttpClientLink {
506
540
  protected?: boolean;
507
541
  schema?: RequestConfigSchema;
508
542
  handler?: ServerHandler;
543
+ host?: string;
544
+ proxy?: boolean;
509
545
  }
510
546
  type HttpVirtualClient<T> = {
511
547
  [K in keyof T as T[K] extends RouteDescriptor ? K : never]: T[K] & {
@@ -519,11 +555,23 @@ interface RemoteDescriptorOptions {
519
555
  * The URL of the remote service.
520
556
  */
521
557
  url: string | (() => string);
558
+ /**
559
+ * @default "/api/_links"
560
+ */
561
+ linkPath?: string;
562
+ /**
563
+ * If true, all methods of the remote service will be exposed as actions.
564
+ */
565
+ proxy?: boolean | {
566
+ beforeRequest?: (request: ServerRequest, proxyRequest: RequestInit) => Async<void>;
567
+ afterResponse?: (request: ServerRequest, proxyResponse: Response) => Async<void>;
568
+ rewrite?: (url: URL) => void;
569
+ };
522
570
  /**
523
571
  * One or many instance of classes to be registered as remote services.
524
572
  * Services must contain some $action() descriptors.
525
573
  */
526
- services: object | Array<object>;
574
+ services?: object | Array<object>;
527
575
  /**
528
576
  * The name of the remote service.
529
577
  *
@@ -540,24 +588,8 @@ declare const $remote: {
540
588
  [KIND]: string;
541
589
  };
542
590
 
543
- declare class RouteDescriptorHelper {
544
- name(options: RouteDescriptorOptions, instance: any, key: string): string;
545
- path(options: RouteDescriptorOptions, instance: any, key: string, prefix?: string): string;
546
- link(options: RouteDescriptorOptions, instance: any, key: string, prefix?: string): HttpClientLink;
547
- method(options: {
548
- method?: string;
549
- schema?: any;
550
- }): RouteMethod;
551
- permission(options: RouteDescriptorOptions, instance: any, key: string, prefix?: string): Permission;
552
- group(options: RouteDescriptorOptions, instance: any): string;
553
- isMultipart(options: {
554
- schema?: RequestConfigSchema;
555
- }): boolean;
556
- bodyContentType(options: RouteDescriptorOptions): string | undefined;
557
- protected short(name: string): string;
558
- }
559
-
560
591
  declare class ServerProvider {
592
+ constructor();
561
593
  get hostname(): string;
562
594
  }
563
595
 
@@ -584,7 +616,14 @@ declare class ServerActionDescriptorProvider {
584
616
  protected readonly actions: ServerRouteAction[];
585
617
  getActions(): ServerRouteAction<RequestConfigSchema>[];
586
618
  readonly configure: _alepha_core.HookDescriptor<"configure">;
587
- registerRemote(value: RemoteDescriptor, key: string): void;
619
+ registerRemote(value: RemoteDescriptor, key: string): Promise<void>;
620
+ loadRemoteLinks: (options: RemoteDescriptorOptions) => Promise<Promise<void>>;
621
+ proxy(url: string, link: HttpClientLink, options: {
622
+ beforeRequest?: (request: ServerRequest, proxyRequest: RequestInit) => Async<void>;
623
+ afterResponse?: (request: ServerRequest, proxyResponse: Response) => Async<void>;
624
+ rewrite?: (url: URL) => void;
625
+ }): Promise<void>;
626
+ private getRawRequestBody;
588
627
  registerAction(value: RouteDescriptor, key: string, instance: any, prefix?: string): Promise<void>;
589
628
  /**
590
629
  * When your action has no handler, it's considered as an 'API'.
@@ -642,6 +681,7 @@ interface ServerRemote {
642
681
  url: string;
643
682
  services: object[];
644
683
  name: string;
684
+ proxy: boolean;
645
685
  }
646
686
  interface ServerRouteAction<TConfig extends RequestConfigSchema = RequestConfigSchema> extends ServerRoute<TConfig> {
647
687
  method: RouteMethod;
@@ -667,13 +707,16 @@ declare class BrowserActionDescriptorProvider {
667
707
  };
668
708
  protected readonly helper: RouteDescriptorHelper;
669
709
  readonly configure: _alepha_core.HookDescriptor<"configure">;
710
+ configureActions(): void;
670
711
  registerAction(value: RouteDescriptor, instance: any, key: string): void;
671
712
  }
672
713
 
673
714
  declare class ServerSecurityProvider {
674
715
  protected readonly log: _alepha_core.Logger;
675
716
  protected readonly securityProvider: SecurityProvider;
717
+ protected readonly jwtProvider: JwtProvider;
676
718
  protected readonly alepha: Alepha;
719
+ readonly onClientRequest: _alepha_core.HookDescriptor<"client:onRequest">;
677
720
  protected readonly onRequest: _alepha_core.HookDescriptor<"server:onRequest">;
678
721
  protected readonly onRoute: _alepha_core.HookDescriptor<"server:onRoute">;
679
722
  }
@@ -705,7 +748,7 @@ declare class ServerMultipartProvider {
705
748
  protected readonly helper: RouteDescriptorHelper;
706
749
  protected readonly alepha: Alepha;
707
750
  readonly onRequest: _alepha_core.HookDescriptor<"server:onRequest">;
708
- readonly onSend: _alepha_core.HookDescriptor<"server:onSend">;
751
+ readonly onSend: _alepha_core.HookDescriptor<"server:onResponse">;
709
752
  handleMultipartBodyFromNode(route: ServerRoute, stream: IncomingMessage): Promise<{
710
753
  body: Record<string, any>;
711
754
  cleanup: () => Promise<void>;
@@ -727,12 +770,13 @@ interface HybridFile extends FileLike {
727
770
  /**
728
771
  * Create a file-like object from various sources.
729
772
  */
730
- declare const file: (source: string | Buffer | ArrayBuffer, // TODO: FileLike, Blob, WebStream, NodeStream
731
- options?: {
773
+ declare const file: (source: string | Buffer | ArrayBuffer | StreamLike, options?: {
732
774
  type?: string;
733
775
  name?: string;
734
- }) => Promise<FileLike>;
735
- declare const isFileLike: (value: any) => value is FileLike;
776
+ }) => FileLike;
777
+ declare const bufferToStream: (buffer: Buffer) => Readable;
778
+ declare const streamToBuffer: (stream: Readable) => Promise<Buffer>;
779
+ declare const bufferToArrayBuffer: (buffer: Buffer) => ArrayBuffer;
736
780
  declare const getContentType: (filename: string) => string;
737
781
 
738
782
  declare const envSchema$1: _alepha_core.TObject<{
@@ -837,6 +881,11 @@ declare module "@alepha/core" {
837
881
  headers: Record<string, string>;
838
882
  request: RequestInit;
839
883
  };
884
+ "client:beforeFetch": {
885
+ url: string;
886
+ options: FetchRunOptions;
887
+ request: RequestInit;
888
+ };
840
889
  "client:onError": {
841
890
  route?: HttpClientLink;
842
891
  error: HttpError;
@@ -855,4 +904,4 @@ declare class ServerModule {
855
904
  constructor();
856
905
  }
857
906
 
858
- export { $action, $remote, $route, BadRequestError, BrowserActionDescriptorProvider, type ClientRequestEntry, type ClientRequestEntryContainer, type ClientRequestOptions, type ClientRequestResponse, ConflictError, type FetchFactoryAdditionalOptions, type FetchRunOptions, ForbiddenError, HttpClient, type HttpClientLink, type HttpClientPendingRequests, HttpError, type HttpVirtualClient, NodeHttpServerProvider, NotFoundError, type Ok, REMOTE_DESCRIPTOR_KEY, type RemoteDescriptor, type RemoteDescriptorOptions, type RequestConfigSchema, type ResponseBodyType, type ResponseType, type RouteDescriptor, type RouteDescriptorOptions, type RouteMethod, ServerActionDescriptorProvider, type ServerHandler, ServerLinksProvider, ServerLoggerProvider, ServerModule, ServerMultipartProvider, ServerProvider, type ServerRawRequest, type ServerRemote, type ServerReply, type ServerRequest, type ServerRequestConfig, type ServerRequestConfigEntry, type ServerResponse, type ServerResponseBody, type ServerRoute, type ServerRouteAction, type ServerRouteWithHandler, ServerRouterProvider, ServerSecurityProvider, UnauthorizedError, ValidationError, errorNameByStatus, errorSchema, file, getContentType, isFileLike, isServerAction, okSchema, routeMethods };
907
+ export { $action, $remote, $route, BadRequestError, BrowserActionDescriptorProvider, type ClientRequestEntry, type ClientRequestEntryContainer, type ClientRequestOptions, type ClientRequestResponse, ConflictError, type FetchFactoryAdditionalOptions, type FetchRunOptions, ForbiddenError, HttpClient, type HttpClientLink, type HttpClientPendingRequests, HttpError, type HttpVirtualClient, NodeHttpServerProvider, NotFoundError, type Ok, REMOTE_DESCRIPTOR_KEY, type RemoteDescriptor, type RemoteDescriptorOptions, type RequestConfigSchema, type ResponseBodyType, type ResponseType, type RouteDescriptor, type RouteDescriptorOptions, type RouteMethod, ServerActionDescriptorProvider, type ServerHandler, ServerLinksProvider, ServerLoggerProvider, ServerModule, ServerMultipartProvider, ServerProvider, type ServerRawRequest, type ServerRemote, type ServerReply, type ServerRequest, type ServerRequestConfig, type ServerRequestConfigEntry, type ServerResponse, type ServerResponseBody, type ServerRoute, type ServerRouteAction, type ServerRouteWithHandler, ServerRouterProvider, ServerSecurityProvider, UnauthorizedError, ValidationError, bufferToArrayBuffer, bufferToStream, errorNameByStatus, errorSchema, file, getContentType, isServerAction, okSchema, routeMethods, streamToBuffer };
package/topic.d.ts CHANGED
@@ -47,6 +47,7 @@ interface TSchema extends TKind, SchemaOptions {
47
47
  }
48
48
 
49
49
  declare class TopicProvider {
50
+ constructor();
50
51
  /**
51
52
  * Publish a message to a topic.
52
53
  *