alepha 0.13.1 → 0.13.2
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 +1 -1
- package/dist/api-files/index.d.ts +28 -91
- package/dist/api-files/index.js +10 -755
- package/dist/api-files/index.js.map +1 -1
- package/dist/api-jobs/index.d.ts +46 -46
- package/dist/api-jobs/index.js +13 -13
- package/dist/api-jobs/index.js.map +1 -1
- package/dist/api-notifications/index.d.ts +129 -146
- package/dist/api-notifications/index.js +17 -39
- package/dist/api-notifications/index.js.map +1 -1
- package/dist/api-parameters/index.d.ts +21 -22
- package/dist/api-parameters/index.js +22 -22
- package/dist/api-parameters/index.js.map +1 -1
- package/dist/api-users/index.d.ts +223 -2000
- package/dist/api-users/index.js +914 -4787
- package/dist/api-users/index.js.map +1 -1
- package/dist/api-verifications/index.d.ts +96 -96
- package/dist/batch/index.d.ts +13 -13
- package/dist/batch/index.js +8 -8
- package/dist/batch/index.js.map +1 -1
- package/dist/bucket/index.d.ts +14 -14
- package/dist/bucket/index.js +12 -12
- package/dist/bucket/index.js.map +1 -1
- package/dist/cache/index.d.ts +11 -11
- package/dist/cache/index.js +9 -9
- package/dist/cache/index.js.map +1 -1
- package/dist/cli/index.d.ts +28 -26
- package/dist/cli/index.js +50 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +19 -19
- package/dist/command/index.js +25 -25
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +218 -218
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +232 -232
- package/dist/core/index.js +218 -218
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +2113 -0
- package/dist/core/index.native.js.map +1 -0
- package/dist/datetime/index.d.ts +9 -9
- package/dist/datetime/index.js +7 -7
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/index.d.ts +16 -16
- package/dist/email/index.js +9 -9
- package/dist/email/index.js.map +1 -1
- package/dist/file/index.js +1 -1
- package/dist/file/index.js.map +1 -1
- package/dist/lock/index.d.ts +9 -9
- package/dist/lock/index.js +8 -8
- package/dist/lock/index.js.map +1 -1
- package/dist/lock-redis/index.js +3 -66
- package/dist/lock-redis/index.js.map +1 -1
- package/dist/logger/index.d.ts +5 -5
- package/dist/logger/index.js +8 -8
- package/dist/logger/index.js.map +1 -1
- package/dist/orm/index.browser.js +114 -114
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.d.ts +218 -218
- package/dist/orm/index.js +46 -46
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/index.d.ts +29 -29
- package/dist/queue/index.js +20 -20
- package/dist/queue/index.js.map +1 -1
- package/dist/queue-redis/index.d.ts +2 -2
- package/dist/redis/index.d.ts +10 -10
- package/dist/retry/index.d.ts +19 -19
- package/dist/retry/index.js +7 -7
- package/dist/retry/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +16 -16
- package/dist/scheduler/index.js +9 -9
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.d.ts +80 -80
- package/dist/security/index.js +32 -32
- package/dist/security/index.js.map +1 -1
- package/dist/server/index.browser.js +1 -1
- package/dist/server/index.browser.js.map +1 -1
- package/dist/server/index.d.ts +101 -101
- package/dist/server/index.js +16 -16
- package/dist/server/index.js.map +1 -1
- package/dist/server-auth/index.browser.js +4 -982
- package/dist/server-auth/index.browser.js.map +1 -1
- package/dist/server-auth/index.d.ts +204 -785
- package/dist/server-auth/index.js +47 -1239
- package/dist/server-auth/index.js.map +1 -1
- package/dist/server-cache/index.d.ts +10 -10
- package/dist/server-cache/index.js +2 -2
- package/dist/server-cache/index.js.map +1 -1
- package/dist/server-compress/index.d.ts +4 -4
- package/dist/server-compress/index.js +1 -1
- package/dist/server-compress/index.js.map +1 -1
- package/dist/server-cookies/index.browser.js +8 -8
- package/dist/server-cookies/index.browser.js.map +1 -1
- package/dist/server-cookies/index.d.ts +17 -17
- package/dist/server-cookies/index.js +10 -10
- package/dist/server-cookies/index.js.map +1 -1
- package/dist/server-cors/index.d.ts +17 -17
- package/dist/server-cors/index.js +9 -9
- package/dist/server-cors/index.js.map +1 -1
- package/dist/server-health/index.d.ts +19 -19
- package/dist/server-helmet/index.d.ts +1 -1
- package/dist/server-links/index.browser.js +12 -12
- package/dist/server-links/index.browser.js.map +1 -1
- package/dist/server-links/index.d.ts +59 -251
- package/dist/server-links/index.js +23 -502
- package/dist/server-links/index.js.map +1 -1
- package/dist/server-metrics/index.d.ts +4 -4
- package/dist/server-multipart/index.d.ts +2 -2
- package/dist/server-proxy/index.d.ts +12 -12
- package/dist/server-proxy/index.js +10 -10
- package/dist/server-proxy/index.js.map +1 -1
- package/dist/server-rate-limit/index.d.ts +22 -22
- package/dist/server-rate-limit/index.js +12 -12
- package/dist/server-rate-limit/index.js.map +1 -1
- package/dist/server-security/index.d.ts +22 -22
- package/dist/server-security/index.js +15 -15
- package/dist/server-security/index.js.map +1 -1
- package/dist/server-static/index.d.ts +14 -14
- package/dist/server-static/index.js +8 -8
- package/dist/server-static/index.js.map +1 -1
- package/dist/server-swagger/index.d.ts +25 -184
- package/dist/server-swagger/index.js +21 -724
- package/dist/server-swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +14 -14
- package/dist/sms/index.js +9 -9
- package/dist/sms/index.js.map +1 -1
- package/dist/thread/index.d.ts +11 -11
- package/dist/thread/index.js +17 -17
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/index.d.ts +26 -26
- package/dist/topic/index.js +16 -16
- package/dist/topic/index.js.map +1 -1
- package/dist/topic-redis/index.d.ts +1 -1
- package/dist/vite/index.d.ts +3 -3
- package/dist/vite/index.js +8 -8
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js +11 -11
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +58 -58
- package/dist/websocket/index.js +13 -13
- package/dist/websocket/index.js.map +1 -1
- package/package.json +113 -52
- package/src/api-files/services/FileService.ts +5 -7
- package/src/api-jobs/index.ts +1 -1
- package/src/api-jobs/{descriptors → primitives}/$job.ts +8 -8
- package/src/api-jobs/providers/JobProvider.ts +9 -9
- package/src/api-jobs/services/JobService.ts +5 -5
- package/src/api-notifications/index.ts +5 -15
- package/src/api-notifications/{descriptors → primitives}/$notification.ts +10 -10
- package/src/api-notifications/services/NotificationSenderService.ts +3 -3
- package/src/api-parameters/index.ts +1 -1
- package/src/api-parameters/{descriptors → primitives}/$config.ts +7 -12
- package/src/api-users/index.ts +1 -1
- package/src/api-users/{descriptors → primitives}/$userRealm.ts +8 -8
- package/src/api-users/providers/UserRealmProvider.ts +1 -1
- package/src/batch/index.ts +3 -3
- package/src/batch/{descriptors → primitives}/$batch.ts +13 -16
- package/src/bucket/index.ts +8 -8
- package/src/bucket/{descriptors → primitives}/$bucket.ts +8 -8
- package/src/bucket/providers/LocalFileStorageProvider.ts +3 -3
- package/src/cache/index.ts +4 -4
- package/src/cache/{descriptors → primitives}/$cache.ts +15 -15
- package/src/cli/apps/AlephaPackageBuilderCli.ts +24 -2
- package/src/cli/commands/DrizzleCommands.ts +6 -6
- package/src/cli/commands/VerifyCommands.ts +1 -1
- package/src/cli/commands/ViteCommands.ts +6 -1
- package/src/cli/services/ProjectUtils.ts +34 -3
- package/src/command/index.ts +5 -5
- package/src/command/{descriptors → primitives}/$command.ts +9 -12
- package/src/command/providers/CliProvider.ts +10 -10
- package/src/core/Alepha.ts +30 -33
- package/src/core/constants/KIND.ts +1 -1
- package/src/core/constants/OPTIONS.ts +1 -1
- package/src/core/helpers/{descriptor.ts → primitive.ts} +18 -18
- package/src/core/helpers/ref.ts +1 -1
- package/src/core/index.shared.ts +8 -8
- package/src/core/{descriptors → primitives}/$context.ts +5 -5
- package/src/core/{descriptors → primitives}/$hook.ts +4 -4
- package/src/core/{descriptors → primitives}/$inject.ts +2 -2
- package/src/core/{descriptors → primitives}/$module.ts +9 -9
- package/src/core/{descriptors → primitives}/$use.ts +2 -2
- package/src/core/providers/CodecManager.ts +1 -1
- package/src/core/providers/JsonSchemaCodec.ts +1 -1
- package/src/core/providers/StateManager.ts +2 -2
- package/src/datetime/index.ts +3 -3
- package/src/datetime/{descriptors → primitives}/$interval.ts +6 -6
- package/src/email/index.ts +4 -4
- package/src/email/{descriptors → primitives}/$email.ts +8 -8
- package/src/file/index.ts +1 -1
- package/src/lock/index.ts +3 -3
- package/src/lock/{descriptors → primitives}/$lock.ts +10 -10
- package/src/logger/index.ts +8 -8
- package/src/logger/{descriptors → primitives}/$logger.ts +2 -2
- package/src/logger/services/Logger.ts +1 -1
- package/src/orm/constants/PG_SYMBOLS.ts +2 -2
- package/src/orm/index.browser.ts +2 -2
- package/src/orm/index.ts +8 -8
- package/src/orm/{descriptors → primitives}/$entity.ts +11 -11
- package/src/orm/{descriptors → primitives}/$repository.ts +2 -2
- package/src/orm/{descriptors → primitives}/$sequence.ts +8 -8
- package/src/orm/{descriptors → primitives}/$transaction.ts +4 -4
- package/src/orm/providers/PostgresTypeProvider.ts +3 -3
- package/src/orm/providers/RepositoryProvider.ts +4 -4
- package/src/orm/providers/drivers/DatabaseProvider.ts +7 -7
- package/src/orm/services/ModelBuilder.ts +9 -9
- package/src/orm/services/PgRelationManager.ts +2 -2
- package/src/orm/services/PostgresModelBuilder.ts +5 -5
- package/src/orm/services/Repository.ts +7 -7
- package/src/orm/services/SqliteModelBuilder.ts +5 -5
- package/src/queue/index.ts +7 -7
- package/src/queue/{descriptors → primitives}/$consumer.ts +15 -15
- package/src/queue/{descriptors → primitives}/$queue.ts +12 -12
- package/src/queue/providers/WorkerProvider.ts +7 -7
- package/src/retry/index.ts +3 -3
- package/src/retry/{descriptors → primitives}/$retry.ts +14 -14
- package/src/scheduler/index.ts +3 -3
- package/src/scheduler/{descriptors → primitives}/$scheduler.ts +9 -9
- package/src/scheduler/providers/CronProvider.ts +1 -1
- package/src/security/index.ts +9 -9
- package/src/security/{descriptors → primitives}/$permission.ts +7 -7
- package/src/security/{descriptors → primitives}/$realm.ts +6 -12
- package/src/security/{descriptors → primitives}/$role.ts +12 -12
- package/src/security/{descriptors → primitives}/$serviceAccount.ts +8 -8
- package/src/server/index.browser.ts +1 -1
- package/src/server/index.ts +14 -14
- package/src/server/{descriptors → primitives}/$action.ts +13 -13
- package/src/server/{descriptors → primitives}/$route.ts +9 -9
- package/src/server/providers/NodeHttpServerProvider.ts +1 -1
- package/src/server/services/HttpClient.ts +1 -1
- package/src/server-auth/index.browser.ts +1 -1
- package/src/server-auth/index.ts +6 -6
- package/src/server-auth/{descriptors → primitives}/$auth.ts +10 -10
- package/src/server-auth/{descriptors → primitives}/$authCredentials.ts +4 -4
- package/src/server-auth/{descriptors → primitives}/$authGithub.ts +4 -4
- package/src/server-auth/{descriptors → primitives}/$authGoogle.ts +4 -4
- package/src/server-auth/providers/ServerAuthProvider.ts +4 -4
- package/src/server-cache/providers/ServerCacheProvider.ts +7 -7
- package/src/server-compress/providers/ServerCompressProvider.ts +3 -3
- package/src/server-cookies/index.browser.ts +2 -2
- package/src/server-cookies/index.ts +5 -5
- package/src/server-cookies/{descriptors → primitives}/$cookie.browser.ts +12 -12
- package/src/server-cookies/{descriptors → primitives}/$cookie.ts +13 -13
- package/src/server-cookies/providers/ServerCookiesProvider.ts +4 -4
- package/src/server-cookies/services/CookieParser.ts +1 -1
- package/src/server-cors/index.ts +3 -3
- package/src/server-cors/{descriptors → primitives}/$cors.ts +11 -13
- package/src/server-cors/providers/ServerCorsProvider.ts +5 -5
- package/src/server-links/index.browser.ts +5 -5
- package/src/server-links/index.ts +9 -9
- package/src/server-links/{descriptors → primitives}/$remote.ts +11 -11
- package/src/server-links/providers/LinkProvider.ts +7 -7
- package/src/server-links/providers/{RemoteDescriptorProvider.ts → RemotePrimitiveProvider.ts} +6 -6
- package/src/server-links/providers/ServerLinksProvider.ts +3 -3
- package/src/server-proxy/index.ts +3 -3
- package/src/server-proxy/{descriptors → primitives}/$proxy.ts +8 -8
- package/src/server-proxy/providers/ServerProxyProvider.ts +4 -4
- package/src/server-rate-limit/index.ts +6 -6
- package/src/server-rate-limit/{descriptors → primitives}/$rateLimit.ts +13 -13
- package/src/server-rate-limit/providers/ServerRateLimitProvider.ts +5 -5
- package/src/server-security/index.ts +3 -3
- package/src/server-security/{descriptors → primitives}/$basicAuth.ts +13 -13
- package/src/server-security/providers/ServerBasicAuthProvider.ts +5 -5
- package/src/server-security/providers/ServerSecurityProvider.ts +4 -4
- package/src/server-static/index.ts +3 -3
- package/src/server-static/{descriptors → primitives}/$serve.ts +8 -10
- package/src/server-static/providers/ServerStaticProvider.ts +6 -6
- package/src/server-swagger/index.ts +5 -5
- package/src/server-swagger/{descriptors → primitives}/$swagger.ts +9 -9
- package/src/server-swagger/providers/ServerSwaggerProvider.ts +11 -10
- package/src/sms/index.ts +4 -4
- package/src/sms/{descriptors → primitives}/$sms.ts +8 -8
- package/src/thread/index.ts +3 -3
- package/src/thread/{descriptors → primitives}/$thread.ts +13 -13
- package/src/thread/providers/ThreadProvider.ts +7 -9
- package/src/topic/index.ts +5 -5
- package/src/topic/{descriptors → primitives}/$subscriber.ts +14 -14
- package/src/topic/{descriptors → primitives}/$topic.ts +10 -10
- package/src/topic/providers/TopicProvider.ts +4 -4
- package/src/vite/tasks/copyAssets.ts +1 -1
- package/src/vite/tasks/generateSitemap.ts +3 -3
- package/src/vite/tasks/prerenderPages.ts +2 -2
- package/src/vite/tasks/runAlepha.ts +2 -2
- package/src/websocket/index.browser.ts +3 -3
- package/src/websocket/index.shared.ts +2 -2
- package/src/websocket/index.ts +4 -4
- package/src/websocket/interfaces/WebSocketInterfaces.ts +3 -3
- package/src/websocket/{descriptors → primitives}/$channel.ts +10 -10
- package/src/websocket/{descriptors → primitives}/$websocket.ts +8 -8
- package/src/websocket/providers/NodeWebSocketServerProvider.ts +7 -7
- package/src/websocket/providers/WebSocketServerProvider.ts +3 -3
- package/src/websocket/services/WebSocketClient.ts +5 -5
- package/src/api-notifications/providers/MemorySmsProvider.ts +0 -20
- package/src/api-notifications/providers/SmsProvider.ts +0 -8
- /package/src/core/{descriptors → primitives}/$atom.ts +0 -0
- /package/src/core/{descriptors → primitives}/$env.ts +0 -0
- /package/src/server-auth/{descriptors → primitives}/$authApple.ts +0 -0
- /package/src/server-links/{descriptors → primitives}/$client.ts +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as alepha76 from "alepha";
|
|
2
2
|
import { Static } from "alepha";
|
|
3
3
|
import * as alepha_server0 from "alepha/server";
|
|
4
4
|
import { DateTimeProvider } from "alepha/datetime";
|
|
@@ -6,35 +6,35 @@ import * as alepha_logger0 from "alepha/logger";
|
|
|
6
6
|
import * as alepha_orm56 from "alepha/orm";
|
|
7
7
|
|
|
8
8
|
//#region src/api-verifications/entities/verifications.d.ts
|
|
9
|
-
declare const verifications: alepha_orm56.
|
|
10
|
-
id: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
11
|
-
createdAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
12
|
-
updatedAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
13
|
-
version: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
14
|
-
type:
|
|
15
|
-
target:
|
|
16
|
-
code:
|
|
17
|
-
verifiedAt:
|
|
18
|
-
attempts: alepha_orm56.PgAttr<
|
|
9
|
+
declare const verifications: alepha_orm56.EntityPrimitive<alepha76.TObject<{
|
|
10
|
+
id: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TString, typeof alepha_orm56.PG_PRIMARY_KEY>, typeof alepha_orm56.PG_DEFAULT>;
|
|
11
|
+
createdAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TString, typeof alepha_orm56.PG_CREATED_AT>, typeof alepha_orm56.PG_DEFAULT>;
|
|
12
|
+
updatedAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TString, typeof alepha_orm56.PG_UPDATED_AT>, typeof alepha_orm56.PG_DEFAULT>;
|
|
13
|
+
version: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TInteger, typeof alepha_orm56.PG_VERSION>, typeof alepha_orm56.PG_DEFAULT>;
|
|
14
|
+
type: alepha76.TUnsafe<"link" | "code">;
|
|
15
|
+
target: alepha76.TString;
|
|
16
|
+
code: alepha76.TString;
|
|
17
|
+
verifiedAt: alepha76.TOptional<alepha76.TString>;
|
|
18
|
+
attempts: alepha_orm56.PgAttr<alepha76.TInteger, typeof alepha_orm56.PG_DEFAULT>;
|
|
19
19
|
}>>;
|
|
20
20
|
type VerificationEntity = Static<typeof verifications.schema>;
|
|
21
21
|
//#endregion
|
|
22
22
|
//#region src/api-verifications/schemas/verificationSettingsSchema.d.ts
|
|
23
|
-
declare const verificationSettingsSchema:
|
|
24
|
-
code:
|
|
25
|
-
maxAttempts:
|
|
26
|
-
codeLength:
|
|
27
|
-
codeExpiration:
|
|
28
|
-
verificationCooldown:
|
|
29
|
-
limitPerDay:
|
|
23
|
+
declare const verificationSettingsSchema: alepha76.TObject<{
|
|
24
|
+
code: alepha76.TObject<{
|
|
25
|
+
maxAttempts: alepha76.TInteger;
|
|
26
|
+
codeLength: alepha76.TInteger;
|
|
27
|
+
codeExpiration: alepha76.TInteger;
|
|
28
|
+
verificationCooldown: alepha76.TInteger;
|
|
29
|
+
limitPerDay: alepha76.TInteger;
|
|
30
30
|
}>;
|
|
31
|
-
link:
|
|
32
|
-
maxAttempts:
|
|
33
|
-
codeExpiration:
|
|
34
|
-
verificationCooldown:
|
|
35
|
-
limitPerDay:
|
|
31
|
+
link: alepha76.TObject<{
|
|
32
|
+
maxAttempts: alepha76.TInteger;
|
|
33
|
+
codeExpiration: alepha76.TInteger;
|
|
34
|
+
verificationCooldown: alepha76.TInteger;
|
|
35
|
+
limitPerDay: alepha76.TInteger;
|
|
36
36
|
}>;
|
|
37
|
-
purgeDays:
|
|
37
|
+
purgeDays: alepha76.TInteger;
|
|
38
38
|
}>;
|
|
39
39
|
type VerificationSettings = Static<typeof verificationSettingsSchema>;
|
|
40
40
|
//#endregion
|
|
@@ -42,21 +42,21 @@ type VerificationSettings = Static<typeof verificationSettingsSchema>;
|
|
|
42
42
|
/**
|
|
43
43
|
* Verification settings configuration atom
|
|
44
44
|
*/
|
|
45
|
-
declare const verificationOptions:
|
|
46
|
-
code:
|
|
47
|
-
maxAttempts:
|
|
48
|
-
codeLength:
|
|
49
|
-
codeExpiration:
|
|
50
|
-
verificationCooldown:
|
|
51
|
-
limitPerDay:
|
|
45
|
+
declare const verificationOptions: alepha76.Atom<alepha76.TObject<{
|
|
46
|
+
code: alepha76.TObject<{
|
|
47
|
+
maxAttempts: alepha76.TInteger;
|
|
48
|
+
codeLength: alepha76.TInteger;
|
|
49
|
+
codeExpiration: alepha76.TInteger;
|
|
50
|
+
verificationCooldown: alepha76.TInteger;
|
|
51
|
+
limitPerDay: alepha76.TInteger;
|
|
52
52
|
}>;
|
|
53
|
-
link:
|
|
54
|
-
maxAttempts:
|
|
55
|
-
codeExpiration:
|
|
56
|
-
verificationCooldown:
|
|
57
|
-
limitPerDay:
|
|
53
|
+
link: alepha76.TObject<{
|
|
54
|
+
maxAttempts: alepha76.TInteger;
|
|
55
|
+
codeExpiration: alepha76.TInteger;
|
|
56
|
+
verificationCooldown: alepha76.TInteger;
|
|
57
|
+
limitPerDay: alepha76.TInteger;
|
|
58
58
|
}>;
|
|
59
|
-
purgeDays:
|
|
59
|
+
purgeDays: alepha76.TInteger;
|
|
60
60
|
}>, "alepha.api.verifications.options">;
|
|
61
61
|
type VerificationOptions = Static<typeof verificationOptions.schema>;
|
|
62
62
|
declare module "alepha" {
|
|
@@ -85,23 +85,23 @@ declare class VerificationParameters {
|
|
|
85
85
|
}
|
|
86
86
|
//#endregion
|
|
87
87
|
//#region src/api-verifications/schemas/requestVerificationCodeResponseSchema.d.ts
|
|
88
|
-
declare const requestVerificationCodeResponseSchema:
|
|
89
|
-
token:
|
|
90
|
-
codeExpiration:
|
|
91
|
-
verificationCooldown:
|
|
92
|
-
maxVerificationAttempts:
|
|
88
|
+
declare const requestVerificationCodeResponseSchema: alepha76.TObject<{
|
|
89
|
+
token: alepha76.TString;
|
|
90
|
+
codeExpiration: alepha76.TInteger;
|
|
91
|
+
verificationCooldown: alepha76.TInteger;
|
|
92
|
+
maxVerificationAttempts: alepha76.TInteger;
|
|
93
93
|
}>;
|
|
94
94
|
type RequestVerificationResponse = Static<typeof requestVerificationCodeResponseSchema>;
|
|
95
95
|
//#endregion
|
|
96
96
|
//#region src/api-verifications/schemas/validateVerificationCodeResponseSchema.d.ts
|
|
97
|
-
declare const validateVerificationCodeResponseSchema:
|
|
98
|
-
ok:
|
|
99
|
-
alreadyVerified:
|
|
97
|
+
declare const validateVerificationCodeResponseSchema: alepha76.TObject<{
|
|
98
|
+
ok: alepha76.TBoolean;
|
|
99
|
+
alreadyVerified: alepha76.TOptional<alepha76.TBoolean>;
|
|
100
100
|
}>;
|
|
101
101
|
type ValidateVerificationCodeResponse = Static<typeof validateVerificationCodeResponseSchema>;
|
|
102
102
|
//#endregion
|
|
103
103
|
//#region src/api-verifications/schemas/verificationTypeEnumSchema.d.ts
|
|
104
|
-
declare const verificationTypeEnumSchema:
|
|
104
|
+
declare const verificationTypeEnumSchema: alepha76.TUnsafe<"link" | "code">;
|
|
105
105
|
type VerificationTypeEnum = Static<typeof verificationTypeEnumSchema>;
|
|
106
106
|
//#endregion
|
|
107
107
|
//#region src/api-verifications/services/VerificationService.d.ts
|
|
@@ -109,38 +109,38 @@ declare class VerificationService {
|
|
|
109
109
|
protected readonly log: alepha_logger0.Logger;
|
|
110
110
|
protected readonly dateTimeProvider: DateTimeProvider;
|
|
111
111
|
protected readonly verificationParameters: VerificationParameters;
|
|
112
|
-
protected readonly verificationRepository: alepha_orm56.Repository<
|
|
113
|
-
id: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
114
|
-
createdAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
115
|
-
updatedAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
116
|
-
version: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
117
|
-
type:
|
|
118
|
-
target:
|
|
119
|
-
code:
|
|
120
|
-
verifiedAt:
|
|
121
|
-
attempts: alepha_orm56.PgAttr<
|
|
112
|
+
protected readonly verificationRepository: alepha_orm56.Repository<alepha76.TObject<{
|
|
113
|
+
id: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TString, typeof alepha_orm56.PG_PRIMARY_KEY>, typeof alepha_orm56.PG_DEFAULT>;
|
|
114
|
+
createdAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TString, typeof alepha_orm56.PG_CREATED_AT>, typeof alepha_orm56.PG_DEFAULT>;
|
|
115
|
+
updatedAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TString, typeof alepha_orm56.PG_UPDATED_AT>, typeof alepha_orm56.PG_DEFAULT>;
|
|
116
|
+
version: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TInteger, typeof alepha_orm56.PG_VERSION>, typeof alepha_orm56.PG_DEFAULT>;
|
|
117
|
+
type: alepha76.TUnsafe<"link" | "code">;
|
|
118
|
+
target: alepha76.TString;
|
|
119
|
+
code: alepha76.TString;
|
|
120
|
+
verifiedAt: alepha76.TOptional<alepha76.TString>;
|
|
121
|
+
attempts: alepha_orm56.PgAttr<alepha76.TInteger, typeof alepha_orm56.PG_DEFAULT>;
|
|
122
122
|
}>>;
|
|
123
123
|
findByEntry(entry: VerificationEntry): Promise<VerificationEntity>;
|
|
124
|
-
findRecentsByEntry(entry: VerificationEntry): Promise<alepha_orm56.PgStatic<
|
|
125
|
-
id: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
126
|
-
createdAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
127
|
-
updatedAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
128
|
-
version: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
129
|
-
type:
|
|
130
|
-
target:
|
|
131
|
-
code:
|
|
132
|
-
verifiedAt:
|
|
133
|
-
attempts: alepha_orm56.PgAttr<
|
|
134
|
-
}>, alepha_orm56.PgRelationMap<
|
|
135
|
-
id: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
136
|
-
createdAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
137
|
-
updatedAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
138
|
-
version: alepha_orm56.PgAttr<alepha_orm56.PgAttr<
|
|
139
|
-
type:
|
|
140
|
-
target:
|
|
141
|
-
code:
|
|
142
|
-
verifiedAt:
|
|
143
|
-
attempts: alepha_orm56.PgAttr<
|
|
124
|
+
findRecentsByEntry(entry: VerificationEntry): Promise<alepha_orm56.PgStatic<alepha76.TObject<{
|
|
125
|
+
id: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TString, typeof alepha_orm56.PG_PRIMARY_KEY>, typeof alepha_orm56.PG_DEFAULT>;
|
|
126
|
+
createdAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TString, typeof alepha_orm56.PG_CREATED_AT>, typeof alepha_orm56.PG_DEFAULT>;
|
|
127
|
+
updatedAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TString, typeof alepha_orm56.PG_UPDATED_AT>, typeof alepha_orm56.PG_DEFAULT>;
|
|
128
|
+
version: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TInteger, typeof alepha_orm56.PG_VERSION>, typeof alepha_orm56.PG_DEFAULT>;
|
|
129
|
+
type: alepha76.TUnsafe<"link" | "code">;
|
|
130
|
+
target: alepha76.TString;
|
|
131
|
+
code: alepha76.TString;
|
|
132
|
+
verifiedAt: alepha76.TOptional<alepha76.TString>;
|
|
133
|
+
attempts: alepha_orm56.PgAttr<alepha76.TInteger, typeof alepha_orm56.PG_DEFAULT>;
|
|
134
|
+
}>, alepha_orm56.PgRelationMap<alepha76.TObject<{
|
|
135
|
+
id: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TString, typeof alepha_orm56.PG_PRIMARY_KEY>, typeof alepha_orm56.PG_DEFAULT>;
|
|
136
|
+
createdAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TString, typeof alepha_orm56.PG_CREATED_AT>, typeof alepha_orm56.PG_DEFAULT>;
|
|
137
|
+
updatedAt: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TString, typeof alepha_orm56.PG_UPDATED_AT>, typeof alepha_orm56.PG_DEFAULT>;
|
|
138
|
+
version: alepha_orm56.PgAttr<alepha_orm56.PgAttr<alepha76.TInteger, typeof alepha_orm56.PG_VERSION>, typeof alepha_orm56.PG_DEFAULT>;
|
|
139
|
+
type: alepha76.TUnsafe<"link" | "code">;
|
|
140
|
+
target: alepha76.TString;
|
|
141
|
+
code: alepha76.TString;
|
|
142
|
+
verifiedAt: alepha76.TOptional<alepha76.TString>;
|
|
143
|
+
attempts: alepha_orm56.PgAttr<alepha76.TInteger, typeof alepha_orm56.PG_DEFAULT>;
|
|
144
144
|
}>>>[]>;
|
|
145
145
|
/**
|
|
146
146
|
* Creates a verification entry and returns the token.
|
|
@@ -162,31 +162,31 @@ declare class VerificationController {
|
|
|
162
162
|
protected readonly verificationService: VerificationService;
|
|
163
163
|
readonly url = "/verifications";
|
|
164
164
|
readonly group = "verifications";
|
|
165
|
-
readonly requestVerificationCode: alepha_server0.
|
|
166
|
-
params:
|
|
167
|
-
type:
|
|
165
|
+
readonly requestVerificationCode: alepha_server0.ActionPrimitiveFn<{
|
|
166
|
+
params: alepha76.TObject<{
|
|
167
|
+
type: alepha76.TUnsafe<"link" | "code">;
|
|
168
168
|
}>;
|
|
169
|
-
body:
|
|
170
|
-
target:
|
|
169
|
+
body: alepha76.TObject<{
|
|
170
|
+
target: alepha76.TString;
|
|
171
171
|
}>;
|
|
172
|
-
response:
|
|
173
|
-
token:
|
|
174
|
-
codeExpiration:
|
|
175
|
-
verificationCooldown:
|
|
176
|
-
maxVerificationAttempts:
|
|
172
|
+
response: alepha76.TObject<{
|
|
173
|
+
token: alepha76.TString;
|
|
174
|
+
codeExpiration: alepha76.TInteger;
|
|
175
|
+
verificationCooldown: alepha76.TInteger;
|
|
176
|
+
maxVerificationAttempts: alepha76.TInteger;
|
|
177
177
|
}>;
|
|
178
178
|
}>;
|
|
179
|
-
readonly validateVerificationCode: alepha_server0.
|
|
180
|
-
params:
|
|
181
|
-
type:
|
|
179
|
+
readonly validateVerificationCode: alepha_server0.ActionPrimitiveFn<{
|
|
180
|
+
params: alepha76.TObject<{
|
|
181
|
+
type: alepha76.TUnsafe<"link" | "code">;
|
|
182
182
|
}>;
|
|
183
|
-
body:
|
|
184
|
-
target:
|
|
185
|
-
token:
|
|
183
|
+
body: alepha76.TObject<{
|
|
184
|
+
target: alepha76.TString;
|
|
185
|
+
token: alepha76.TString;
|
|
186
186
|
}>;
|
|
187
|
-
response:
|
|
188
|
-
ok:
|
|
189
|
-
alreadyVerified:
|
|
187
|
+
response: alepha76.TObject<{
|
|
188
|
+
ok: alepha76.TBoolean;
|
|
189
|
+
alreadyVerified: alepha76.TOptional<alepha76.TBoolean>;
|
|
190
190
|
}>;
|
|
191
191
|
}>;
|
|
192
192
|
}
|
|
@@ -201,7 +201,7 @@ declare class VerificationController {
|
|
|
201
201
|
*
|
|
202
202
|
* @module alepha.api.verifications
|
|
203
203
|
*/
|
|
204
|
-
declare const AlephaApiVerification:
|
|
204
|
+
declare const AlephaApiVerification: alepha76.Service<alepha76.Module>;
|
|
205
205
|
//#endregion
|
|
206
206
|
export { AlephaApiVerification, RequestVerificationResponse, ValidateVerificationCodeResponse, VerificationController, VerificationEntry, VerificationService, VerificationTypeEnum, requestVerificationCodeResponseSchema, validateVerificationCodeResponseSchema, verificationTypeEnumSchema };
|
|
207
207
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/batch/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as alepha1 from "alepha";
|
|
2
|
-
import { Alepha,
|
|
2
|
+
import { Alepha, KIND, Primitive, Static, TSchema } from "alepha";
|
|
3
3
|
import { DateTimeProvider, DurationLike } from "alepha/datetime";
|
|
4
4
|
import * as alepha_logger0 from "alepha/logger";
|
|
5
|
-
import { RetryBackoffOptions,
|
|
5
|
+
import { RetryBackoffOptions, RetryPrimitiveOptions, RetryProvider } from "alepha/retry";
|
|
6
6
|
|
|
7
7
|
//#region src/batch/providers/BatchProvider.d.ts
|
|
8
8
|
interface BatchOptions<TItem, TResponse = any> {
|
|
@@ -191,15 +191,15 @@ declare class BatchProvider {
|
|
|
191
191
|
protected startProcessing<TItem, TResponse>(context: BatchContext<TItem, TResponse>): Promise<void>;
|
|
192
192
|
}
|
|
193
193
|
//#endregion
|
|
194
|
-
//#region src/batch/
|
|
194
|
+
//#region src/batch/primitives/$batch.d.ts
|
|
195
195
|
/**
|
|
196
|
-
* Creates a batch processing
|
|
196
|
+
* Creates a batch processing primitive for efficient grouping and processing of multiple operations.
|
|
197
197
|
*/
|
|
198
198
|
declare const $batch: {
|
|
199
|
-
<TItem extends TSchema, TResponse>(options:
|
|
200
|
-
[KIND]: typeof
|
|
199
|
+
<TItem extends TSchema, TResponse>(options: BatchPrimitiveOptions<TItem, TResponse>): BatchPrimitive<TItem, TResponse>;
|
|
200
|
+
[KIND]: typeof BatchPrimitive;
|
|
201
201
|
};
|
|
202
|
-
interface
|
|
202
|
+
interface BatchPrimitiveOptions<TItem extends TSchema, TResponse = any> {
|
|
203
203
|
/**
|
|
204
204
|
* TypeBox schema for validating each item added to the batch.
|
|
205
205
|
*/
|
|
@@ -232,12 +232,12 @@ interface BatchDescriptorOptions<TItem extends TSchema, TResponse = any> {
|
|
|
232
232
|
/**
|
|
233
233
|
* Retry configuration for failed batch processing operations.
|
|
234
234
|
*/
|
|
235
|
-
retry?: Omit<
|
|
235
|
+
retry?: Omit<RetryPrimitiveOptions<() => Array<Static<TItem>>>, "handler">;
|
|
236
236
|
}
|
|
237
|
-
declare class
|
|
237
|
+
declare class BatchPrimitive<TItem extends TSchema, TResponse = any> extends Primitive<BatchPrimitiveOptions<TItem, TResponse>> {
|
|
238
238
|
protected readonly batchProvider: BatchProvider;
|
|
239
239
|
protected readonly context: BatchContext<Static<TItem>, TResponse>;
|
|
240
|
-
constructor(...args: ConstructorParameters<typeof
|
|
240
|
+
constructor(...args: ConstructorParameters<typeof Primitive<BatchPrimitiveOptions<TItem, TResponse>>>);
|
|
241
241
|
/**
|
|
242
242
|
* Pushes an item into the batch and returns immediately with a unique ID.
|
|
243
243
|
* The item will be processed asynchronously with other items when the batch is flushed.
|
|
@@ -277,8 +277,8 @@ declare class BatchDescriptor<TItem extends TSchema, TResponse = any> extends De
|
|
|
277
277
|
* @returns The number of items cleared
|
|
278
278
|
*/
|
|
279
279
|
clearCompleted(status?: "completed" | "failed"): number;
|
|
280
|
-
protected readonly onReady: alepha1.
|
|
281
|
-
protected readonly dispose: alepha1.
|
|
280
|
+
protected readonly onReady: alepha1.HookPrimitive<"ready">;
|
|
281
|
+
protected readonly dispose: alepha1.HookPrimitive<"stop">;
|
|
282
282
|
}
|
|
283
283
|
//#endregion
|
|
284
284
|
//#region src/batch/index.d.ts
|
|
@@ -326,5 +326,5 @@ declare class BatchDescriptor<TItem extends TSchema, TResponse = any> extends De
|
|
|
326
326
|
*/
|
|
327
327
|
declare const AlephaBatch: alepha1.Service<alepha1.Module>;
|
|
328
328
|
//#endregion
|
|
329
|
-
export { $batch, AlephaBatch, BatchContext,
|
|
329
|
+
export { $batch, AlephaBatch, BatchContext, type BatchItemState, type BatchItemStatus, BatchOptions, BatchPrimitive, BatchPrimitiveOptions, BatchProvider, PartitionState };
|
|
330
330
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/batch/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $hook, $inject, $module,
|
|
1
|
+
import { $hook, $inject, $module, KIND, Primitive, createPrimitive } from "alepha";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { DateTimeProvider } from "alepha/datetime";
|
|
4
4
|
import { $logger } from "alepha/logger";
|
|
@@ -272,12 +272,12 @@ var BatchProvider = class {
|
|
|
272
272
|
};
|
|
273
273
|
|
|
274
274
|
//#endregion
|
|
275
|
-
//#region src/batch/
|
|
275
|
+
//#region src/batch/primitives/$batch.ts
|
|
276
276
|
/**
|
|
277
|
-
* Creates a batch processing
|
|
277
|
+
* Creates a batch processing primitive for efficient grouping and processing of multiple operations.
|
|
278
278
|
*/
|
|
279
|
-
const $batch = (options) =>
|
|
280
|
-
var
|
|
279
|
+
const $batch = (options) => createPrimitive(BatchPrimitive, options);
|
|
280
|
+
var BatchPrimitive = class extends Primitive {
|
|
281
281
|
batchProvider = $inject(BatchProvider);
|
|
282
282
|
context;
|
|
283
283
|
constructor(...args) {
|
|
@@ -348,7 +348,7 @@ var BatchDescriptor = class extends Descriptor {
|
|
|
348
348
|
}
|
|
349
349
|
});
|
|
350
350
|
};
|
|
351
|
-
$batch[KIND] =
|
|
351
|
+
$batch[KIND] = BatchPrimitive;
|
|
352
352
|
|
|
353
353
|
//#endregion
|
|
354
354
|
//#region src/batch/index.ts
|
|
@@ -396,10 +396,10 @@ $batch[KIND] = BatchDescriptor;
|
|
|
396
396
|
*/
|
|
397
397
|
const AlephaBatch = $module({
|
|
398
398
|
name: "alepha.batch",
|
|
399
|
-
|
|
399
|
+
primitives: [$batch],
|
|
400
400
|
services: [BatchProvider]
|
|
401
401
|
});
|
|
402
402
|
|
|
403
403
|
//#endregion
|
|
404
|
-
export { $batch, AlephaBatch,
|
|
404
|
+
export { $batch, AlephaBatch, BatchPrimitive, BatchProvider };
|
|
405
405
|
//# sourceMappingURL=index.js.map
|
package/dist/batch/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["partitionKey: string","itemState: BatchItemState<TItem, TResponse>","promises: Promise<void>[]","itemsToProcess: TItem[]","result: any"],"sources":["../../src/batch/providers/BatchProvider.ts","../../src/batch/descriptors/$batch.ts","../../src/batch/index.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { $inject, type Alepha } from \"alepha\";\nimport { DateTimeProvider, type DurationLike } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\nimport { type RetryBackoffOptions, RetryProvider } from \"alepha/retry\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface BatchOptions<TItem, TResponse = any> {\n /**\n * The batch processing handler function that processes arrays of validated items.\n */\n handler: (items: TItem[]) => TResponse;\n\n /**\n * Maximum number of items to collect before automatically flushing the batch.\n *\n * @default 10\n */\n maxSize?: number;\n\n /**\n * Maximum number of items that can be queued in a single partition.\n * If exceeded, push() will throw an error.\n */\n maxQueueSize?: number;\n\n /**\n * Maximum time to wait before flushing a batch, even if it hasn't reached maxSize.\n *\n * @default [1, \"second\"]\n */\n maxDuration?: DurationLike;\n\n /**\n * Function to determine partition keys for grouping items into separate batches.\n */\n partitionBy?: (item: TItem) => string;\n\n /**\n * Maximum number of batch handlers that can execute simultaneously.\n *\n * @default 1\n */\n concurrency?: number;\n\n /**\n * Retry configuration for failed batch processing operations.\n */\n retry?: {\n /**\n * The maximum number of attempts.\n *\n * @default 3\n */\n max?: number;\n\n /**\n * The backoff strategy for delays between retries.\n * Can be a fixed number (in ms) or a configuration object for exponential backoff.\n *\n * @default { initial: 200, factor: 2, jitter: true }\n */\n backoff?: number | RetryBackoffOptions;\n\n /**\n * An overall time limit for all retry attempts combined.\n *\n * e.g., `[5, 'seconds']`\n */\n maxDuration?: DurationLike;\n\n /**\n * A function that determines if a retry should be attempted based on the error.\n *\n * @default (error) => true (retries on any error)\n */\n when?: (error: Error) => boolean;\n\n /**\n * A custom callback for when a retry attempt fails.\n * This is called before the delay.\n */\n onError?: (error: Error, attempt: number) => void;\n };\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport type BatchItemStatus = \"pending\" | \"processing\" | \"completed\" | \"failed\";\n\nexport interface BatchItemState<TItem, TResponse> {\n id: string;\n item: TItem;\n partitionKey: string;\n status: BatchItemStatus;\n result?: TResponse;\n error?: Error;\n promise?: Promise<TResponse>;\n resolve?: (value: TResponse) => void;\n reject?: (error: Error) => void;\n}\n\nexport interface PartitionState {\n itemIds: string[];\n timeout?: { clear: () => void };\n flushing: boolean;\n}\n\n/**\n * Context object that holds all state for a batch processor instance.\n */\nexport interface BatchContext<TItem, TResponse> {\n options: BatchOptions<TItem, TResponse>;\n itemStates: Map<string, BatchItemState<TItem, TResponse>>;\n partitions: Map<string, PartitionState>;\n activeHandlers: PromiseWithResolvers<void>[];\n isShuttingDown: boolean;\n isReady: boolean;\n alepha: Alepha;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Service for batch processing operations.\n * Provides methods to manage batches of items with automatic flushing based on size or time.\n */\nexport class BatchProvider {\n protected readonly log = $logger();\n protected readonly dateTime = $inject(DateTimeProvider);\n protected readonly retryProvider = $inject(RetryProvider);\n\n /**\n * Creates a new batch context with the given options.\n */\n createContext<TItem, TResponse>(\n alepha: Alepha,\n options: BatchOptions<TItem, TResponse>,\n ): BatchContext<TItem, TResponse> {\n return {\n options,\n itemStates: new Map(),\n partitions: new Map(),\n activeHandlers: [],\n isShuttingDown: false,\n isReady: false,\n alepha,\n };\n }\n\n /**\n * Get the effective maxSize for a context.\n */\n protected getMaxSize<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n ): number {\n return context.options.maxSize ?? 10;\n }\n\n /**\n * Get the effective concurrency for a context.\n */\n protected getConcurrency<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n ): number {\n return context.options.concurrency ?? 1;\n }\n\n /**\n * Get the effective maxDuration for a context.\n */\n protected getMaxDuration<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n ): DurationLike {\n return context.options.maxDuration ?? [1, \"second\"];\n }\n\n /**\n * Pushes an item into the batch and returns immediately with a unique ID.\n * The item will be processed asynchronously with other items when the batch is flushed.\n * Use wait(id) to get the processing result.\n *\n * @throws Error if maxQueueSize is exceeded\n */\n push<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n item: TItem,\n ): string {\n // 1. Generate unique ID\n const id = randomUUID();\n\n // 2. Determine the partition key (with error handling)\n let partitionKey: string;\n try {\n partitionKey = context.options.partitionBy\n ? context.options.partitionBy(item)\n : \"default\";\n } catch (error) {\n this.log.warn(\n \"partitionBy function threw an error, using 'default' partition\",\n { error },\n );\n partitionKey = \"default\";\n }\n\n // 3. Create item state\n const itemState: BatchItemState<TItem, TResponse> = {\n id,\n item,\n partitionKey,\n status: \"pending\",\n };\n\n // CAUTION: Do not log.debug/info here as it may cause infinite loops if logging is batched\n // log.trace is safe\n\n this.log.trace(\"Pushing item to batch\", {\n id,\n partitionKey,\n item,\n });\n\n context.itemStates.set(id, itemState);\n\n // 4. Get or create the partition state\n if (!context.partitions.has(partitionKey)) {\n context.partitions.set(partitionKey, {\n itemIds: [],\n flushing: false,\n });\n }\n const partition = context.partitions.get(partitionKey)!;\n\n // 5. Check maxQueueSize before adding\n if (\n context.options.maxQueueSize !== undefined &&\n partition.itemIds.length >= context.options.maxQueueSize\n ) {\n throw new Error(\n `Batch queue size exceeded for partition '${partitionKey}' (max: ${context.options.maxQueueSize})`,\n );\n }\n\n // 6. Add item ID to partition\n partition.itemIds.push(id);\n\n const maxSize = this.getMaxSize(context);\n const maxDuration = this.getMaxDuration(context);\n\n // 7. Only start processing if the app is ready (after \"ready\" hook)\n // During startup, items are just buffered in memory\n if (context.isReady) {\n // Check if the batch is full\n if (partition.itemIds.length >= maxSize) {\n this.log.trace(\n `Batch partition '${partitionKey}' is full, flushing...`,\n );\n this.flushPartition(context, partitionKey).catch((error) =>\n this.log.error(\n `Failed to flush batch partition '${partitionKey}' on max size`,\n error,\n ),\n );\n } else if (!partition.timeout && !partition.flushing) {\n // 8. Start the timeout if it's not already running for this partition and not currently flushing\n partition.timeout = this.dateTime.createTimeout(() => {\n this.log.trace(\n `Batch partition '${partitionKey}' timed out, flushing...`,\n );\n this.flushPartition(context, partitionKey).catch((error) =>\n this.log.error(\n `Failed to flush batch partition '${partitionKey}' on timeout`,\n error,\n ),\n );\n }, maxDuration);\n }\n } else {\n // Not ready yet - just buffer items, no size checks or timeouts\n this.log.trace(\n `Buffering item in partition '${partitionKey}' (app not ready yet, ${partition.itemIds.length} items buffered)`,\n );\n }\n\n // 9. Return ID immediately\n return id;\n }\n\n /**\n * Wait for a specific item to be processed and get its result.\n * @param id The item ID returned from push()\n * @returns The processing result\n * @throws If the item doesn't exist or processing failed\n */\n async wait<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n id: string,\n ): Promise<TResponse> {\n const itemState = context.itemStates.get(id);\n if (!itemState) {\n throw new Error(`Item with id '${id}' not found`);\n }\n\n // If already completed or failed, return immediately\n if (itemState.status === \"completed\") {\n return itemState.result!;\n }\n if (itemState.status === \"failed\") {\n throw itemState.error!;\n }\n\n // Create promise on-demand if not already created\n if (!itemState.promise) {\n itemState.promise = new Promise<TResponse>((resolve, reject) => {\n itemState.resolve = resolve;\n itemState.reject = reject;\n });\n }\n\n return itemState.promise;\n }\n\n /**\n * Get the current status of an item.\n * @param id The item ID returned from push()\n * @returns Status information or undefined if item doesn't exist\n */\n status<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n id: string,\n ):\n | { status: \"pending\" | \"processing\" }\n | { status: \"completed\"; result: TResponse }\n | { status: \"failed\"; error: Error }\n | undefined {\n const itemState = context.itemStates.get(id);\n if (!itemState) {\n return undefined;\n }\n\n if (itemState.status === \"completed\") {\n return { status: \"completed\", result: itemState.result! };\n }\n if (itemState.status === \"failed\") {\n return { status: \"failed\", error: itemState.error! };\n }\n return { status: itemState.status };\n }\n\n /**\n * Clears completed and failed items from the context to free memory.\n * Returns the number of items cleared.\n *\n * @param context The batch context\n * @param status Optional: only clear items with this specific status ('completed' or 'failed')\n * @returns The number of items cleared\n */\n clearCompleted<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n status?: \"completed\" | \"failed\",\n ): number {\n let count = 0;\n for (const [id, state] of context.itemStates) {\n if (status) {\n if (state.status === status) {\n context.itemStates.delete(id);\n count++;\n }\n } else if (state.status === \"completed\" || state.status === \"failed\") {\n context.itemStates.delete(id);\n count++;\n }\n }\n return count;\n }\n\n /**\n * Flush all partitions or a specific partition.\n */\n async flush<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n partitionKey?: string,\n ): Promise<void> {\n const promises: Promise<void>[] = [];\n if (partitionKey) {\n if (context.partitions.has(partitionKey)) {\n promises.push(this.flushPartition(context, partitionKey));\n }\n } else {\n for (const key of context.partitions.keys()) {\n promises.push(this.flushPartition(context, key));\n }\n }\n await Promise.all(promises);\n }\n\n /**\n * Flush a specific partition.\n */\n protected async flushPartition<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n partitionKey: string,\n limit?: number,\n ): Promise<void> {\n const partition = context.partitions.get(partitionKey);\n if (!partition || partition.itemIds.length === 0) {\n context.partitions.delete(partitionKey);\n return;\n }\n\n // Clear the timeout and grab the item IDs (up to limit if specified)\n partition.timeout?.clear();\n partition.timeout = undefined;\n const itemsToTake =\n limit !== undefined\n ? Math.min(limit, partition.itemIds.length)\n : partition.itemIds.length;\n const itemIdsToProcess = partition.itemIds.splice(0, itemsToTake);\n\n // Mark partition as flushing to prevent race conditions\n partition.flushing = true;\n\n // Get the items and mark them as processing\n const itemsToProcess: TItem[] = [];\n for (const id of itemIdsToProcess) {\n const itemState = context.itemStates.get(id);\n if (itemState) {\n itemState.status = \"processing\";\n itemsToProcess.push(itemState.item);\n }\n }\n\n const concurrency = this.getConcurrency(context);\n const maxDuration = this.getMaxDuration(context);\n\n // Wait until there's a free slot (if at concurrency limit)\n while (context.activeHandlers.length >= concurrency) {\n this.log.trace(\n `Batch handler is at concurrency limit, waiting for a slot...`,\n );\n // Wait for any single handler to complete, not all of them\n await Promise.race(context.activeHandlers.map((it) => it.promise));\n }\n\n const promise = Promise.withResolvers<void>();\n context.activeHandlers.push(promise);\n let result: any;\n try {\n result = await context.alepha.context.run(() =>\n // during shutdown, call handler directly to avoid retry cancellation\n context.isShuttingDown\n ? context.options.handler(itemsToProcess)\n : this.retryProvider.retry(\n {\n ...context.options.retry,\n handler: context.options.handler,\n },\n itemsToProcess,\n ),\n );\n\n // Mark all items as completed and resolve their promises\n for (const id of itemIdsToProcess) {\n const itemState = context.itemStates.get(id);\n if (itemState) {\n itemState.status = \"completed\";\n itemState.result = result;\n // Only resolve if someone is waiting\n itemState.resolve?.(result);\n }\n }\n } catch (error) {\n this.log.error(`Batch handler failed`, error);\n\n // Mark all items as failed and reject their promises\n for (const id of itemIdsToProcess) {\n const itemState = context.itemStates.get(id);\n if (itemState) {\n itemState.status = \"failed\";\n itemState.error = error as Error;\n // Only reject if someone is waiting (promise was created)\n itemState.reject?.(error as Error);\n }\n }\n } finally {\n promise.resolve();\n context.activeHandlers = context.activeHandlers.filter(\n (it) => it !== promise,\n );\n\n // Only delete partition if no new items arrived during processing\n const currentPartition = context.partitions.get(partitionKey);\n if (currentPartition?.flushing && currentPartition.itemIds.length === 0) {\n context.partitions.delete(partitionKey);\n } else if (currentPartition) {\n // Reset flushing flag if partition still exists with items\n currentPartition.flushing = false;\n\n // Restart timeout for items that arrived during flush\n if (currentPartition.itemIds.length > 0 && !currentPartition.timeout) {\n currentPartition.timeout = this.dateTime.createTimeout(() => {\n this.log.trace(\n `Batch partition '${partitionKey}' timed out, flushing...`,\n );\n this.flushPartition(context, partitionKey).catch((error) =>\n this.log.error(\n `Failed to flush batch partition '${partitionKey}' on timeout`,\n error,\n ),\n );\n }, maxDuration);\n }\n }\n }\n }\n\n /**\n * Mark the context as ready and start processing buffered items.\n * Called after the \"ready\" hook.\n */\n async markReady<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n ): Promise<void> {\n this.log.debug(\n \"Batch processor is now ready, starting to process buffered items...\",\n );\n context.isReady = true;\n await this.startProcessing(context);\n }\n\n /**\n * Mark the context as shutting down and flush all remaining items.\n */\n async shutdown<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n ): Promise<void> {\n this.log.debug(\"Flushing all remaining batch partitions on shutdown...\");\n context.isShuttingDown = true;\n await this.flush(context);\n this.log.debug(\"All batch partitions flushed\");\n }\n\n /**\n * Called after the \"ready\" hook to start processing buffered items that were\n * pushed during startup. This checks all partitions and starts timeouts/flushes\n * for items that were accumulated before the app was ready.\n */\n protected async startProcessing<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n ): Promise<void> {\n const maxSize = this.getMaxSize(context);\n const maxDuration = this.getMaxDuration(context);\n\n for (const [partitionKey, partition] of context.partitions.entries()) {\n if (partition.itemIds.length === 0) {\n continue;\n }\n\n this.log.trace(\n `Starting processing for partition '${partitionKey}' with ${partition.itemIds.length} buffered items`,\n );\n\n // Flush batches of maxSize while we have items >= maxSize\n while (partition.itemIds.length >= maxSize) {\n this.log.trace(\n `Partition '${partitionKey}' has ${partition.itemIds.length} items, flushing batch of ${maxSize}...`,\n );\n await this.flushPartition(context, partitionKey, maxSize);\n }\n\n // After flushing full batches, start timeout for any remaining items\n if (\n partition.itemIds.length > 0 &&\n !partition.timeout &&\n !partition.flushing\n ) {\n this.log.trace(\n `Starting timeout for partition '${partitionKey}' with ${partition.itemIds.length} remaining items`,\n );\n partition.timeout = this.dateTime.createTimeout(() => {\n this.log.trace(\n `Batch partition '${partitionKey}' timed out, flushing...`,\n );\n this.flushPartition(context, partitionKey).catch((error) =>\n this.log.error(\n `Failed to flush partition '${partitionKey}' on timeout after startup`,\n error,\n ),\n );\n }, maxDuration);\n }\n }\n }\n}\n","import {\n $hook,\n $inject,\n createDescriptor,\n Descriptor,\n KIND,\n type Static,\n type TSchema,\n} from \"alepha\";\nimport type { DurationLike } from \"alepha/datetime\";\nimport type { RetryDescriptorOptions } from \"alepha/retry\";\nimport {\n type BatchContext,\n type BatchItemState,\n type BatchItemStatus,\n BatchProvider,\n} from \"../providers/BatchProvider.ts\";\n\n/**\n * Creates a batch processing descriptor for efficient grouping and processing of multiple operations.\n */\nexport const $batch = <TItem extends TSchema, TResponse>(\n options: BatchDescriptorOptions<TItem, TResponse>,\n): BatchDescriptor<TItem, TResponse> =>\n createDescriptor(BatchDescriptor<TItem, TResponse>, options);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface BatchDescriptorOptions<\n TItem extends TSchema,\n TResponse = any,\n> {\n /**\n * TypeBox schema for validating each item added to the batch.\n */\n schema: TItem;\n\n /**\n * The batch processing handler function that processes arrays of validated items.\n */\n handler: (items: Static<TItem>[]) => TResponse;\n\n /**\n * Maximum number of items to collect before automatically flushing the batch.\n */\n maxSize?: number;\n\n /**\n * Maximum number of items that can be queued in a single partition.\n * If exceeded, push() will throw an error.\n */\n maxQueueSize?: number;\n\n /**\n * Maximum time to wait before flushing a batch, even if it hasn't reached maxSize.\n */\n maxDuration?: DurationLike;\n\n /**\n * Function to determine partition keys for grouping items into separate batches.\n */\n partitionBy?: (item: Static<TItem>) => string;\n\n /**\n * Maximum number of batch handlers that can execute simultaneously.\n */\n concurrency?: number;\n\n /**\n * Retry configuration for failed batch processing operations.\n */\n retry?: Omit<RetryDescriptorOptions<() => Array<Static<TItem>>>, \"handler\">;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport type { BatchItemState, BatchItemStatus };\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class BatchDescriptor<\n TItem extends TSchema,\n TResponse = any,\n> extends Descriptor<BatchDescriptorOptions<TItem, TResponse>> {\n protected readonly batchProvider = $inject(BatchProvider);\n protected readonly context: BatchContext<Static<TItem>, TResponse>;\n\n constructor(\n ...args: ConstructorParameters<\n typeof Descriptor<BatchDescriptorOptions<TItem, TResponse>>\n >\n ) {\n super(...args);\n this.context = this.batchProvider.createContext(this.alepha, {\n handler: this.options.handler,\n maxSize: this.options.maxSize,\n maxQueueSize: this.options.maxQueueSize,\n maxDuration: this.options.maxDuration,\n partitionBy: this.options.partitionBy,\n concurrency: this.options.concurrency,\n retry: this.options.retry,\n });\n }\n\n /**\n * Pushes an item into the batch and returns immediately with a unique ID.\n * The item will be processed asynchronously with other items when the batch is flushed.\n * Use wait(id) to get the processing result.\n */\n public async push(item: Static<TItem>): Promise<string> {\n // Validate the item against the schema\n const validatedItem = this.alepha.codec.validate(this.options.schema, item);\n return this.batchProvider.push(this.context, validatedItem);\n }\n\n /**\n * Wait for a specific item to be processed and get its result.\n * @param id The item ID returned from push()\n * @returns The processing result\n * @throws If the item doesn't exist or processing failed\n */\n public async wait(id: string): Promise<TResponse> {\n return this.batchProvider.wait(this.context, id);\n }\n\n /**\n * Get the current status of an item.\n * @param id The item ID returned from push()\n * @returns Status information or undefined if item doesn't exist\n */\n public status(\n id: string,\n ):\n | { status: \"pending\" | \"processing\" }\n | { status: \"completed\"; result: TResponse }\n | { status: \"failed\"; error: Error }\n | undefined {\n return this.batchProvider.status(this.context, id);\n }\n\n /**\n * Flush all partitions or a specific partition.\n */\n public async flush(partitionKey?: string): Promise<void> {\n return this.batchProvider.flush(this.context, partitionKey);\n }\n\n /**\n * Clears completed and failed items from memory.\n * Call this periodically in long-running applications to prevent memory leaks.\n *\n * @param status Optional: only clear items with this specific status ('completed' or 'failed')\n * @returns The number of items cleared\n */\n public clearCompleted(status?: \"completed\" | \"failed\"): number {\n return this.batchProvider.clearCompleted(this.context, status);\n }\n\n protected readonly onReady = $hook({\n on: \"ready\",\n handler: async () => {\n await this.batchProvider.markReady(this.context);\n },\n });\n\n protected readonly dispose = $hook({\n on: \"stop\",\n priority: \"first\",\n handler: async () => {\n await this.batchProvider.shutdown(this.context);\n },\n });\n}\n\n$batch[KIND] = BatchDescriptor;\n","import { $module } from \"alepha\";\nimport { $batch } from \"./descriptors/$batch.ts\";\nimport { BatchProvider } from \"./providers/BatchProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./descriptors/$batch.ts\";\nexport * from \"./providers/BatchProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * This module allows you to group multiple asynchronous operations into a single \"batch,\" which is then processed together.\n * This is an essential pattern for improving performance, reducing I/O, and interacting efficiently with rate-limited APIs or databases.\n *\n * ```ts\n * import { Alepha, $hook, run, t } from \"alepha\";\n * import { $batch } from \"alepha/batch\";\n *\n * class LoggingService {\n * // define the batch processor\n * logBatch = $batch({\n * schema: t.text(),\n * maxSize: 10,\n * maxDuration: [5, \"seconds\"],\n * handler: async (items) => {\n * console.log(`[BATCH LOG] Processing ${items.length} events:`, items);\n * },\n * });\n *\n * // example of how to use it\n * onReady = $hook({\n * on: \"ready\",\n * handler: async () => {\n * // push() returns an ID immediately\n * const id1 = await this.logBatch.push(\"Application started.\");\n * const id2 = await this.logBatch.push(\"User authenticated.\");\n *\n * // optionally wait for processing to complete\n * await this.logBatch.wait(id1);\n *\n * // or check the status\n * const status = this.logBatch.status(id2);\n * console.log(status?.status); // \"pending\" | \"processing\" | \"completed\" | \"failed\"\n * },\n * });\n * }\n * ```\n *\n * @see {@link $batch}\n * @see {@link BatchProvider}\n * @module alepha.batch\n */\nexport const AlephaBatch = $module({\n name: \"alepha.batch\",\n descriptors: [$batch],\n services: [BatchProvider],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["partitionKey: string","itemState: BatchItemState<TItem, TResponse>","promises: Promise<void>[]","itemsToProcess: TItem[]","result: any"],"sources":["../../src/batch/providers/BatchProvider.ts","../../src/batch/primitives/$batch.ts","../../src/batch/index.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { $inject, type Alepha } from \"alepha\";\nimport { DateTimeProvider, type DurationLike } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\nimport { type RetryBackoffOptions, RetryProvider } from \"alepha/retry\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface BatchOptions<TItem, TResponse = any> {\n /**\n * The batch processing handler function that processes arrays of validated items.\n */\n handler: (items: TItem[]) => TResponse;\n\n /**\n * Maximum number of items to collect before automatically flushing the batch.\n *\n * @default 10\n */\n maxSize?: number;\n\n /**\n * Maximum number of items that can be queued in a single partition.\n * If exceeded, push() will throw an error.\n */\n maxQueueSize?: number;\n\n /**\n * Maximum time to wait before flushing a batch, even if it hasn't reached maxSize.\n *\n * @default [1, \"second\"]\n */\n maxDuration?: DurationLike;\n\n /**\n * Function to determine partition keys for grouping items into separate batches.\n */\n partitionBy?: (item: TItem) => string;\n\n /**\n * Maximum number of batch handlers that can execute simultaneously.\n *\n * @default 1\n */\n concurrency?: number;\n\n /**\n * Retry configuration for failed batch processing operations.\n */\n retry?: {\n /**\n * The maximum number of attempts.\n *\n * @default 3\n */\n max?: number;\n\n /**\n * The backoff strategy for delays between retries.\n * Can be a fixed number (in ms) or a configuration object for exponential backoff.\n *\n * @default { initial: 200, factor: 2, jitter: true }\n */\n backoff?: number | RetryBackoffOptions;\n\n /**\n * An overall time limit for all retry attempts combined.\n *\n * e.g., `[5, 'seconds']`\n */\n maxDuration?: DurationLike;\n\n /**\n * A function that determines if a retry should be attempted based on the error.\n *\n * @default (error) => true (retries on any error)\n */\n when?: (error: Error) => boolean;\n\n /**\n * A custom callback for when a retry attempt fails.\n * This is called before the delay.\n */\n onError?: (error: Error, attempt: number) => void;\n };\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport type BatchItemStatus = \"pending\" | \"processing\" | \"completed\" | \"failed\";\n\nexport interface BatchItemState<TItem, TResponse> {\n id: string;\n item: TItem;\n partitionKey: string;\n status: BatchItemStatus;\n result?: TResponse;\n error?: Error;\n promise?: Promise<TResponse>;\n resolve?: (value: TResponse) => void;\n reject?: (error: Error) => void;\n}\n\nexport interface PartitionState {\n itemIds: string[];\n timeout?: { clear: () => void };\n flushing: boolean;\n}\n\n/**\n * Context object that holds all state for a batch processor instance.\n */\nexport interface BatchContext<TItem, TResponse> {\n options: BatchOptions<TItem, TResponse>;\n itemStates: Map<string, BatchItemState<TItem, TResponse>>;\n partitions: Map<string, PartitionState>;\n activeHandlers: PromiseWithResolvers<void>[];\n isShuttingDown: boolean;\n isReady: boolean;\n alepha: Alepha;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Service for batch processing operations.\n * Provides methods to manage batches of items with automatic flushing based on size or time.\n */\nexport class BatchProvider {\n protected readonly log = $logger();\n protected readonly dateTime = $inject(DateTimeProvider);\n protected readonly retryProvider = $inject(RetryProvider);\n\n /**\n * Creates a new batch context with the given options.\n */\n createContext<TItem, TResponse>(\n alepha: Alepha,\n options: BatchOptions<TItem, TResponse>,\n ): BatchContext<TItem, TResponse> {\n return {\n options,\n itemStates: new Map(),\n partitions: new Map(),\n activeHandlers: [],\n isShuttingDown: false,\n isReady: false,\n alepha,\n };\n }\n\n /**\n * Get the effective maxSize for a context.\n */\n protected getMaxSize<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n ): number {\n return context.options.maxSize ?? 10;\n }\n\n /**\n * Get the effective concurrency for a context.\n */\n protected getConcurrency<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n ): number {\n return context.options.concurrency ?? 1;\n }\n\n /**\n * Get the effective maxDuration for a context.\n */\n protected getMaxDuration<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n ): DurationLike {\n return context.options.maxDuration ?? [1, \"second\"];\n }\n\n /**\n * Pushes an item into the batch and returns immediately with a unique ID.\n * The item will be processed asynchronously with other items when the batch is flushed.\n * Use wait(id) to get the processing result.\n *\n * @throws Error if maxQueueSize is exceeded\n */\n push<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n item: TItem,\n ): string {\n // 1. Generate unique ID\n const id = randomUUID();\n\n // 2. Determine the partition key (with error handling)\n let partitionKey: string;\n try {\n partitionKey = context.options.partitionBy\n ? context.options.partitionBy(item)\n : \"default\";\n } catch (error) {\n this.log.warn(\n \"partitionBy function threw an error, using 'default' partition\",\n { error },\n );\n partitionKey = \"default\";\n }\n\n // 3. Create item state\n const itemState: BatchItemState<TItem, TResponse> = {\n id,\n item,\n partitionKey,\n status: \"pending\",\n };\n\n // CAUTION: Do not log.debug/info here as it may cause infinite loops if logging is batched\n // log.trace is safe\n\n this.log.trace(\"Pushing item to batch\", {\n id,\n partitionKey,\n item,\n });\n\n context.itemStates.set(id, itemState);\n\n // 4. Get or create the partition state\n if (!context.partitions.has(partitionKey)) {\n context.partitions.set(partitionKey, {\n itemIds: [],\n flushing: false,\n });\n }\n const partition = context.partitions.get(partitionKey)!;\n\n // 5. Check maxQueueSize before adding\n if (\n context.options.maxQueueSize !== undefined &&\n partition.itemIds.length >= context.options.maxQueueSize\n ) {\n throw new Error(\n `Batch queue size exceeded for partition '${partitionKey}' (max: ${context.options.maxQueueSize})`,\n );\n }\n\n // 6. Add item ID to partition\n partition.itemIds.push(id);\n\n const maxSize = this.getMaxSize(context);\n const maxDuration = this.getMaxDuration(context);\n\n // 7. Only start processing if the app is ready (after \"ready\" hook)\n // During startup, items are just buffered in memory\n if (context.isReady) {\n // Check if the batch is full\n if (partition.itemIds.length >= maxSize) {\n this.log.trace(\n `Batch partition '${partitionKey}' is full, flushing...`,\n );\n this.flushPartition(context, partitionKey).catch((error) =>\n this.log.error(\n `Failed to flush batch partition '${partitionKey}' on max size`,\n error,\n ),\n );\n } else if (!partition.timeout && !partition.flushing) {\n // 8. Start the timeout if it's not already running for this partition and not currently flushing\n partition.timeout = this.dateTime.createTimeout(() => {\n this.log.trace(\n `Batch partition '${partitionKey}' timed out, flushing...`,\n );\n this.flushPartition(context, partitionKey).catch((error) =>\n this.log.error(\n `Failed to flush batch partition '${partitionKey}' on timeout`,\n error,\n ),\n );\n }, maxDuration);\n }\n } else {\n // Not ready yet - just buffer items, no size checks or timeouts\n this.log.trace(\n `Buffering item in partition '${partitionKey}' (app not ready yet, ${partition.itemIds.length} items buffered)`,\n );\n }\n\n // 9. Return ID immediately\n return id;\n }\n\n /**\n * Wait for a specific item to be processed and get its result.\n * @param id The item ID returned from push()\n * @returns The processing result\n * @throws If the item doesn't exist or processing failed\n */\n async wait<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n id: string,\n ): Promise<TResponse> {\n const itemState = context.itemStates.get(id);\n if (!itemState) {\n throw new Error(`Item with id '${id}' not found`);\n }\n\n // If already completed or failed, return immediately\n if (itemState.status === \"completed\") {\n return itemState.result!;\n }\n if (itemState.status === \"failed\") {\n throw itemState.error!;\n }\n\n // Create promise on-demand if not already created\n if (!itemState.promise) {\n itemState.promise = new Promise<TResponse>((resolve, reject) => {\n itemState.resolve = resolve;\n itemState.reject = reject;\n });\n }\n\n return itemState.promise;\n }\n\n /**\n * Get the current status of an item.\n * @param id The item ID returned from push()\n * @returns Status information or undefined if item doesn't exist\n */\n status<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n id: string,\n ):\n | { status: \"pending\" | \"processing\" }\n | { status: \"completed\"; result: TResponse }\n | { status: \"failed\"; error: Error }\n | undefined {\n const itemState = context.itemStates.get(id);\n if (!itemState) {\n return undefined;\n }\n\n if (itemState.status === \"completed\") {\n return { status: \"completed\", result: itemState.result! };\n }\n if (itemState.status === \"failed\") {\n return { status: \"failed\", error: itemState.error! };\n }\n return { status: itemState.status };\n }\n\n /**\n * Clears completed and failed items from the context to free memory.\n * Returns the number of items cleared.\n *\n * @param context The batch context\n * @param status Optional: only clear items with this specific status ('completed' or 'failed')\n * @returns The number of items cleared\n */\n clearCompleted<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n status?: \"completed\" | \"failed\",\n ): number {\n let count = 0;\n for (const [id, state] of context.itemStates) {\n if (status) {\n if (state.status === status) {\n context.itemStates.delete(id);\n count++;\n }\n } else if (state.status === \"completed\" || state.status === \"failed\") {\n context.itemStates.delete(id);\n count++;\n }\n }\n return count;\n }\n\n /**\n * Flush all partitions or a specific partition.\n */\n async flush<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n partitionKey?: string,\n ): Promise<void> {\n const promises: Promise<void>[] = [];\n if (partitionKey) {\n if (context.partitions.has(partitionKey)) {\n promises.push(this.flushPartition(context, partitionKey));\n }\n } else {\n for (const key of context.partitions.keys()) {\n promises.push(this.flushPartition(context, key));\n }\n }\n await Promise.all(promises);\n }\n\n /**\n * Flush a specific partition.\n */\n protected async flushPartition<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n partitionKey: string,\n limit?: number,\n ): Promise<void> {\n const partition = context.partitions.get(partitionKey);\n if (!partition || partition.itemIds.length === 0) {\n context.partitions.delete(partitionKey);\n return;\n }\n\n // Clear the timeout and grab the item IDs (up to limit if specified)\n partition.timeout?.clear();\n partition.timeout = undefined;\n const itemsToTake =\n limit !== undefined\n ? Math.min(limit, partition.itemIds.length)\n : partition.itemIds.length;\n const itemIdsToProcess = partition.itemIds.splice(0, itemsToTake);\n\n // Mark partition as flushing to prevent race conditions\n partition.flushing = true;\n\n // Get the items and mark them as processing\n const itemsToProcess: TItem[] = [];\n for (const id of itemIdsToProcess) {\n const itemState = context.itemStates.get(id);\n if (itemState) {\n itemState.status = \"processing\";\n itemsToProcess.push(itemState.item);\n }\n }\n\n const concurrency = this.getConcurrency(context);\n const maxDuration = this.getMaxDuration(context);\n\n // Wait until there's a free slot (if at concurrency limit)\n while (context.activeHandlers.length >= concurrency) {\n this.log.trace(\n `Batch handler is at concurrency limit, waiting for a slot...`,\n );\n // Wait for any single handler to complete, not all of them\n await Promise.race(context.activeHandlers.map((it) => it.promise));\n }\n\n const promise = Promise.withResolvers<void>();\n context.activeHandlers.push(promise);\n let result: any;\n try {\n result = await context.alepha.context.run(() =>\n // during shutdown, call handler directly to avoid retry cancellation\n context.isShuttingDown\n ? context.options.handler(itemsToProcess)\n : this.retryProvider.retry(\n {\n ...context.options.retry,\n handler: context.options.handler,\n },\n itemsToProcess,\n ),\n );\n\n // Mark all items as completed and resolve their promises\n for (const id of itemIdsToProcess) {\n const itemState = context.itemStates.get(id);\n if (itemState) {\n itemState.status = \"completed\";\n itemState.result = result;\n // Only resolve if someone is waiting\n itemState.resolve?.(result);\n }\n }\n } catch (error) {\n this.log.error(`Batch handler failed`, error);\n\n // Mark all items as failed and reject their promises\n for (const id of itemIdsToProcess) {\n const itemState = context.itemStates.get(id);\n if (itemState) {\n itemState.status = \"failed\";\n itemState.error = error as Error;\n // Only reject if someone is waiting (promise was created)\n itemState.reject?.(error as Error);\n }\n }\n } finally {\n promise.resolve();\n context.activeHandlers = context.activeHandlers.filter(\n (it) => it !== promise,\n );\n\n // Only delete partition if no new items arrived during processing\n const currentPartition = context.partitions.get(partitionKey);\n if (currentPartition?.flushing && currentPartition.itemIds.length === 0) {\n context.partitions.delete(partitionKey);\n } else if (currentPartition) {\n // Reset flushing flag if partition still exists with items\n currentPartition.flushing = false;\n\n // Restart timeout for items that arrived during flush\n if (currentPartition.itemIds.length > 0 && !currentPartition.timeout) {\n currentPartition.timeout = this.dateTime.createTimeout(() => {\n this.log.trace(\n `Batch partition '${partitionKey}' timed out, flushing...`,\n );\n this.flushPartition(context, partitionKey).catch((error) =>\n this.log.error(\n `Failed to flush batch partition '${partitionKey}' on timeout`,\n error,\n ),\n );\n }, maxDuration);\n }\n }\n }\n }\n\n /**\n * Mark the context as ready and start processing buffered items.\n * Called after the \"ready\" hook.\n */\n async markReady<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n ): Promise<void> {\n this.log.debug(\n \"Batch processor is now ready, starting to process buffered items...\",\n );\n context.isReady = true;\n await this.startProcessing(context);\n }\n\n /**\n * Mark the context as shutting down and flush all remaining items.\n */\n async shutdown<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n ): Promise<void> {\n this.log.debug(\"Flushing all remaining batch partitions on shutdown...\");\n context.isShuttingDown = true;\n await this.flush(context);\n this.log.debug(\"All batch partitions flushed\");\n }\n\n /**\n * Called after the \"ready\" hook to start processing buffered items that were\n * pushed during startup. This checks all partitions and starts timeouts/flushes\n * for items that were accumulated before the app was ready.\n */\n protected async startProcessing<TItem, TResponse>(\n context: BatchContext<TItem, TResponse>,\n ): Promise<void> {\n const maxSize = this.getMaxSize(context);\n const maxDuration = this.getMaxDuration(context);\n\n for (const [partitionKey, partition] of context.partitions.entries()) {\n if (partition.itemIds.length === 0) {\n continue;\n }\n\n this.log.trace(\n `Starting processing for partition '${partitionKey}' with ${partition.itemIds.length} buffered items`,\n );\n\n // Flush batches of maxSize while we have items >= maxSize\n while (partition.itemIds.length >= maxSize) {\n this.log.trace(\n `Partition '${partitionKey}' has ${partition.itemIds.length} items, flushing batch of ${maxSize}...`,\n );\n await this.flushPartition(context, partitionKey, maxSize);\n }\n\n // After flushing full batches, start timeout for any remaining items\n if (\n partition.itemIds.length > 0 &&\n !partition.timeout &&\n !partition.flushing\n ) {\n this.log.trace(\n `Starting timeout for partition '${partitionKey}' with ${partition.itemIds.length} remaining items`,\n );\n partition.timeout = this.dateTime.createTimeout(() => {\n this.log.trace(\n `Batch partition '${partitionKey}' timed out, flushing...`,\n );\n this.flushPartition(context, partitionKey).catch((error) =>\n this.log.error(\n `Failed to flush partition '${partitionKey}' on timeout after startup`,\n error,\n ),\n );\n }, maxDuration);\n }\n }\n }\n}\n","import {\n $hook,\n $inject,\n createPrimitive,\n KIND,\n Primitive,\n type Static,\n type TSchema,\n} from \"alepha\";\nimport type { DurationLike } from \"alepha/datetime\";\nimport type { RetryPrimitiveOptions } from \"alepha/retry\";\nimport {\n type BatchContext,\n type BatchItemState,\n type BatchItemStatus,\n BatchProvider,\n} from \"../providers/BatchProvider.ts\";\n\n/**\n * Creates a batch processing primitive for efficient grouping and processing of multiple operations.\n */\nexport const $batch = <TItem extends TSchema, TResponse>(\n options: BatchPrimitiveOptions<TItem, TResponse>,\n): BatchPrimitive<TItem, TResponse> =>\n createPrimitive(BatchPrimitive<TItem, TResponse>, options);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface BatchPrimitiveOptions<TItem extends TSchema, TResponse = any> {\n /**\n * TypeBox schema for validating each item added to the batch.\n */\n schema: TItem;\n\n /**\n * The batch processing handler function that processes arrays of validated items.\n */\n handler: (items: Static<TItem>[]) => TResponse;\n\n /**\n * Maximum number of items to collect before automatically flushing the batch.\n */\n maxSize?: number;\n\n /**\n * Maximum number of items that can be queued in a single partition.\n * If exceeded, push() will throw an error.\n */\n maxQueueSize?: number;\n\n /**\n * Maximum time to wait before flushing a batch, even if it hasn't reached maxSize.\n */\n maxDuration?: DurationLike;\n\n /**\n * Function to determine partition keys for grouping items into separate batches.\n */\n partitionBy?: (item: Static<TItem>) => string;\n\n /**\n * Maximum number of batch handlers that can execute simultaneously.\n */\n concurrency?: number;\n\n /**\n * Retry configuration for failed batch processing operations.\n */\n retry?: Omit<RetryPrimitiveOptions<() => Array<Static<TItem>>>, \"handler\">;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport type { BatchItemState, BatchItemStatus };\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class BatchPrimitive<\n TItem extends TSchema,\n TResponse = any,\n> extends Primitive<BatchPrimitiveOptions<TItem, TResponse>> {\n protected readonly batchProvider = $inject(BatchProvider);\n protected readonly context: BatchContext<Static<TItem>, TResponse>;\n\n constructor(\n ...args: ConstructorParameters<\n typeof Primitive<BatchPrimitiveOptions<TItem, TResponse>>\n >\n ) {\n super(...args);\n this.context = this.batchProvider.createContext(this.alepha, {\n handler: this.options.handler,\n maxSize: this.options.maxSize,\n maxQueueSize: this.options.maxQueueSize,\n maxDuration: this.options.maxDuration,\n partitionBy: this.options.partitionBy,\n concurrency: this.options.concurrency,\n retry: this.options.retry,\n });\n }\n\n /**\n * Pushes an item into the batch and returns immediately with a unique ID.\n * The item will be processed asynchronously with other items when the batch is flushed.\n * Use wait(id) to get the processing result.\n */\n public async push(item: Static<TItem>): Promise<string> {\n // Validate the item against the schema\n const validatedItem = this.alepha.codec.validate(this.options.schema, item);\n return this.batchProvider.push(this.context, validatedItem);\n }\n\n /**\n * Wait for a specific item to be processed and get its result.\n * @param id The item ID returned from push()\n * @returns The processing result\n * @throws If the item doesn't exist or processing failed\n */\n public async wait(id: string): Promise<TResponse> {\n return this.batchProvider.wait(this.context, id);\n }\n\n /**\n * Get the current status of an item.\n * @param id The item ID returned from push()\n * @returns Status information or undefined if item doesn't exist\n */\n public status(\n id: string,\n ):\n | { status: \"pending\" | \"processing\" }\n | { status: \"completed\"; result: TResponse }\n | { status: \"failed\"; error: Error }\n | undefined {\n return this.batchProvider.status(this.context, id);\n }\n\n /**\n * Flush all partitions or a specific partition.\n */\n public async flush(partitionKey?: string): Promise<void> {\n return this.batchProvider.flush(this.context, partitionKey);\n }\n\n /**\n * Clears completed and failed items from memory.\n * Call this periodically in long-running applications to prevent memory leaks.\n *\n * @param status Optional: only clear items with this specific status ('completed' or 'failed')\n * @returns The number of items cleared\n */\n public clearCompleted(status?: \"completed\" | \"failed\"): number {\n return this.batchProvider.clearCompleted(this.context, status);\n }\n\n protected readonly onReady = $hook({\n on: \"ready\",\n handler: async () => {\n await this.batchProvider.markReady(this.context);\n },\n });\n\n protected readonly dispose = $hook({\n on: \"stop\",\n priority: \"first\",\n handler: async () => {\n await this.batchProvider.shutdown(this.context);\n },\n });\n}\n\n$batch[KIND] = BatchPrimitive;\n","import { $module } from \"alepha\";\nimport { $batch } from \"./primitives/$batch.ts\";\nimport { BatchProvider } from \"./providers/BatchProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./primitives/$batch.ts\";\nexport * from \"./providers/BatchProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * This module allows you to group multiple asynchronous operations into a single \"batch,\" which is then processed together.\n * This is an essential pattern for improving performance, reducing I/O, and interacting efficiently with rate-limited APIs or databases.\n *\n * ```ts\n * import { Alepha, $hook, run, t } from \"alepha\";\n * import { $batch } from \"alepha/batch\";\n *\n * class LoggingService {\n * // define the batch processor\n * logBatch = $batch({\n * schema: t.text(),\n * maxSize: 10,\n * maxDuration: [5, \"seconds\"],\n * handler: async (items) => {\n * console.log(`[BATCH LOG] Processing ${items.length} events:`, items);\n * },\n * });\n *\n * // example of how to use it\n * onReady = $hook({\n * on: \"ready\",\n * handler: async () => {\n * // push() returns an ID immediately\n * const id1 = await this.logBatch.push(\"Application started.\");\n * const id2 = await this.logBatch.push(\"User authenticated.\");\n *\n * // optionally wait for processing to complete\n * await this.logBatch.wait(id1);\n *\n * // or check the status\n * const status = this.logBatch.status(id2);\n * console.log(status?.status); // \"pending\" | \"processing\" | \"completed\" | \"failed\"\n * },\n * });\n * }\n * ```\n *\n * @see {@link $batch}\n * @see {@link BatchProvider}\n * @module alepha.batch\n */\nexport const AlephaBatch = $module({\n name: \"alepha.batch\",\n primitives: [$batch],\n services: [BatchProvider],\n});\n"],"mappings":"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"}
|
package/dist/bucket/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as alepha1 from "alepha";
|
|
2
|
-
import { Alepha, AlephaError,
|
|
2
|
+
import { Alepha, AlephaError, FileLike, KIND, Primitive, Service, Static } from "alepha";
|
|
3
3
|
import { FileDetector, FileSystemProvider } from "alepha/file";
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
5
|
import * as alepha_logger0 from "alepha/logger";
|
|
@@ -52,9 +52,9 @@ declare class MemoryFileStorageProvider implements FileStorageProvider {
|
|
|
52
52
|
protected createId(): string;
|
|
53
53
|
}
|
|
54
54
|
//#endregion
|
|
55
|
-
//#region src/bucket/
|
|
55
|
+
//#region src/bucket/primitives/$bucket.d.ts
|
|
56
56
|
/**
|
|
57
|
-
* Creates a bucket
|
|
57
|
+
* Creates a bucket primitive for file storage and management with configurable validation.
|
|
58
58
|
*
|
|
59
59
|
* Provides a comprehensive file storage system that handles uploads, downloads, validation,
|
|
60
60
|
* and management across multiple storage backends with MIME type and size limit controls.
|
|
@@ -103,10 +103,10 @@ declare class MemoryFileStorageProvider implements FileStorageProvider {
|
|
|
103
103
|
* ```
|
|
104
104
|
*/
|
|
105
105
|
declare const $bucket: {
|
|
106
|
-
(options:
|
|
107
|
-
[KIND]: typeof
|
|
106
|
+
(options: BucketPrimitiveOptions): BucketPrimitive;
|
|
107
|
+
[KIND]: typeof BucketPrimitive;
|
|
108
108
|
};
|
|
109
|
-
interface
|
|
109
|
+
interface BucketPrimitiveOptions extends BucketFileOptions {
|
|
110
110
|
/**
|
|
111
111
|
* File storage provider configuration for the bucket.
|
|
112
112
|
*
|
|
@@ -238,7 +238,7 @@ interface BucketFileOptions {
|
|
|
238
238
|
*/
|
|
239
239
|
maxSize?: number;
|
|
240
240
|
}
|
|
241
|
-
declare class
|
|
241
|
+
declare class BucketPrimitive extends Primitive<BucketPrimitiveOptions> {
|
|
242
242
|
readonly provider: FileStorageProvider | MemoryFileStorageProvider;
|
|
243
243
|
private readonly fileSystem;
|
|
244
244
|
get name(): string;
|
|
@@ -304,8 +304,8 @@ declare class LocalFileStorageProvider implements FileStorageProvider {
|
|
|
304
304
|
storagePath: string;
|
|
305
305
|
}>;
|
|
306
306
|
protected get storagePath(): string;
|
|
307
|
-
protected readonly onConfigure: alepha1.
|
|
308
|
-
protected readonly onStart: alepha1.
|
|
307
|
+
protected readonly onConfigure: alepha1.HookPrimitive<"configure">;
|
|
308
|
+
protected readonly onStart: alepha1.HookPrimitive<"start">;
|
|
309
309
|
upload(bucketName: string, file: FileLike, fileId?: string): Promise<string>;
|
|
310
310
|
download(bucketName: string, fileId: string): Promise<FileLike>;
|
|
311
311
|
exists(bucketName: string, fileId: string): Promise<boolean>;
|
|
@@ -326,7 +326,7 @@ declare module "alepha" {
|
|
|
326
326
|
"bucket:file:uploaded": {
|
|
327
327
|
id: string;
|
|
328
328
|
file: FileLike;
|
|
329
|
-
bucket:
|
|
329
|
+
bucket: BucketPrimitive;
|
|
330
330
|
options: BucketFileOptions;
|
|
331
331
|
};
|
|
332
332
|
/**
|
|
@@ -334,14 +334,14 @@ declare module "alepha" {
|
|
|
334
334
|
*/
|
|
335
335
|
"bucket:file:deleted": {
|
|
336
336
|
id: string;
|
|
337
|
-
bucket:
|
|
337
|
+
bucket: BucketPrimitive;
|
|
338
338
|
};
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
341
|
/**
|
|
342
|
-
* Provides file storage capabilities through declarative bucket
|
|
342
|
+
* Provides file storage capabilities through declarative bucket primitives with support for multiple storage backends.
|
|
343
343
|
*
|
|
344
|
-
* The bucket module enables unified file operations across different storage systems using the `$bucket`
|
|
344
|
+
* The bucket module enables unified file operations across different storage systems using the `$bucket` primitive
|
|
345
345
|
* on class properties. It abstracts storage provider differences, offering consistent APIs for local filesystem,
|
|
346
346
|
* cloud storage, or in-memory storage for testing environments.
|
|
347
347
|
*
|
|
@@ -351,5 +351,5 @@ declare module "alepha" {
|
|
|
351
351
|
*/
|
|
352
352
|
declare const AlephaBucket: alepha1.Service<alepha1.Module>;
|
|
353
353
|
//#endregion
|
|
354
|
-
export { $bucket, AlephaBucket,
|
|
354
|
+
export { $bucket, AlephaBucket, BucketFileOptions, BucketPrimitive, BucketPrimitiveOptions, FileNotFoundError, FileStorageProvider, LocalFileStorageProvider, LocalFileStorageProviderOptions, MemoryFileStorageProvider, localFileStorageOptions };
|
|
355
355
|
//# sourceMappingURL=index.d.ts.map
|