@effect-auth/core 0.1.0-alpha.0 → 0.1.0-alpha.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/README.md +774 -36
- package/dist/ApiKey.d.ts +207 -0
- package/dist/ApiKey.d.ts.map +1 -0
- package/dist/ApiKey.js +275 -0
- package/dist/ApiKey.js.map +1 -0
- package/dist/AuditLog.d.ts +278 -1
- package/dist/AuditLog.d.ts.map +1 -1
- package/dist/AuditLog.js +217 -2
- package/dist/AuditLog.js.map +1 -1
- package/dist/AuthConfig.d.ts +42 -0
- package/dist/AuthConfig.d.ts.map +1 -0
- package/dist/AuthConfig.js +43 -0
- package/dist/AuthConfig.js.map +1 -0
- package/dist/AuthFlow.d.ts +465 -36
- package/dist/AuthFlow.d.ts.map +1 -1
- package/dist/AuthFlow.js +660 -5
- package/dist/AuthFlow.js.map +1 -1
- package/dist/AuthKernel.d.ts +3 -0
- package/dist/AuthKernel.d.ts.map +1 -0
- package/dist/AuthKernel.js +9 -0
- package/dist/AuthKernel.js.map +1 -0
- package/dist/Challenge.d.ts +27 -4
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +170 -1
- package/dist/Challenge.js.map +1 -1
- package/dist/Client.d.ts +378 -0
- package/dist/Client.d.ts.map +1 -0
- package/dist/Client.js +768 -0
- package/dist/Client.js.map +1 -0
- package/dist/Crypto.d.ts +9 -1
- package/dist/Crypto.d.ts.map +1 -1
- package/dist/Crypto.js +65 -1
- package/dist/Crypto.js.map +1 -1
- package/dist/EffectQbSqliteStorage.d.ts +600 -0
- package/dist/EffectQbSqliteStorage.d.ts.map +1 -0
- package/dist/EffectQbSqliteStorage.js +1637 -0
- package/dist/EffectQbSqliteStorage.js.map +1 -0
- package/dist/EmailOtp.d.ts +120 -0
- package/dist/EmailOtp.d.ts.map +1 -0
- package/dist/EmailOtp.js +286 -0
- package/dist/EmailOtp.js.map +1 -0
- package/dist/EmailVerification.d.ts +121 -0
- package/dist/EmailVerification.d.ts.map +1 -0
- package/dist/EmailVerification.js +200 -0
- package/dist/EmailVerification.js.map +1 -0
- package/dist/HttpApi/Api.d.ts +1956 -0
- package/dist/HttpApi/Api.d.ts.map +1 -0
- package/dist/HttpApi/Api.js +2325 -0
- package/dist/HttpApi/Api.js.map +1 -0
- package/dist/HttpApi/Endpoints.d.ts +945 -0
- package/dist/HttpApi/Endpoints.d.ts.map +1 -0
- package/dist/HttpApi/Endpoints.js +373 -0
- package/dist/HttpApi/Endpoints.js.map +1 -0
- package/dist/HttpApi/Errors.d.ts +82 -0
- package/dist/HttpApi/Errors.d.ts.map +1 -0
- package/dist/HttpApi/Errors.js +184 -0
- package/dist/HttpApi/Errors.js.map +1 -0
- package/dist/HttpApi/Schemas.d.ts +1113 -0
- package/dist/HttpApi/Schemas.d.ts.map +1 -0
- package/dist/HttpApi/Schemas.js +734 -0
- package/dist/HttpApi/Schemas.js.map +1 -0
- package/dist/HttpApi/Security.d.ts +159 -0
- package/dist/HttpApi/Security.d.ts.map +1 -0
- package/dist/HttpApi/Security.js +530 -0
- package/dist/HttpApi/Security.js.map +1 -0
- package/dist/HttpApi/Transport.d.ts +65 -0
- package/dist/HttpApi/Transport.d.ts.map +1 -0
- package/dist/HttpApi/Transport.js +311 -0
- package/dist/HttpApi/Transport.js.map +1 -0
- package/dist/HttpApi/index.d.ts +8 -0
- package/dist/HttpApi/index.d.ts.map +1 -0
- package/dist/HttpApi/index.js +7 -0
- package/dist/HttpApi/index.js.map +1 -0
- package/dist/HttpApi.d.ts +2 -0
- package/dist/HttpApi.d.ts.map +1 -0
- package/dist/HttpApi.js +2 -0
- package/dist/HttpApi.js.map +1 -0
- package/dist/Identifiers.d.ts.map +1 -1
- package/dist/Identifiers.js.map +1 -1
- package/dist/Internal.d.ts +7 -0
- package/dist/Internal.d.ts.map +1 -0
- package/dist/Internal.js +12 -0
- package/dist/Internal.js.map +1 -0
- package/dist/Jwt.d.ts +271 -0
- package/dist/Jwt.d.ts.map +1 -0
- package/dist/Jwt.js +512 -0
- package/dist/Jwt.js.map +1 -0
- package/dist/LoginApproval.d.ts +314 -0
- package/dist/LoginApproval.d.ts.map +1 -0
- package/dist/LoginApproval.js +551 -0
- package/dist/LoginApproval.js.map +1 -0
- package/dist/LoginNotification.d.ts +183 -0
- package/dist/LoginNotification.d.ts.map +1 -0
- package/dist/LoginNotification.js +329 -0
- package/dist/LoginNotification.js.map +1 -0
- package/dist/LoginRisk.d.ts +73 -0
- package/dist/LoginRisk.d.ts.map +1 -0
- package/dist/LoginRisk.js +57 -0
- package/dist/LoginRisk.js.map +1 -0
- package/dist/MagicLink.d.ts +85 -0
- package/dist/MagicLink.d.ts.map +1 -0
- package/dist/MagicLink.js +206 -0
- package/dist/MagicLink.js.map +1 -0
- package/dist/Mailer.d.ts +147 -0
- package/dist/Mailer.d.ts.map +1 -0
- package/dist/Mailer.js +208 -0
- package/dist/Mailer.js.map +1 -0
- package/dist/OAuth.d.ts +934 -0
- package/dist/OAuth.d.ts.map +1 -0
- package/dist/OAuth.js +1661 -0
- package/dist/OAuth.js.map +1 -0
- package/dist/Passkey.d.ts +334 -0
- package/dist/Passkey.d.ts.map +1 -0
- package/dist/Passkey.js +422 -0
- package/dist/Passkey.js.map +1 -0
- package/dist/PasskeySimpleWebAuthn.d.ts +11 -0
- package/dist/PasskeySimpleWebAuthn.d.ts.map +1 -0
- package/dist/PasskeySimpleWebAuthn.js +181 -0
- package/dist/PasskeySimpleWebAuthn.js.map +1 -0
- package/dist/Password.d.ts +237 -0
- package/dist/Password.d.ts.map +1 -0
- package/dist/Password.js +641 -0
- package/dist/Password.js.map +1 -0
- package/dist/Policy.d.ts +7 -4
- package/dist/Policy.d.ts.map +1 -1
- package/dist/Policy.js +28 -5
- package/dist/Policy.js.map +1 -1
- package/dist/Privacy.d.ts +18 -0
- package/dist/Privacy.d.ts.map +1 -1
- package/dist/Privacy.js +63 -3
- package/dist/Privacy.js.map +1 -1
- package/dist/RateLimiter.d.ts +104 -0
- package/dist/RateLimiter.d.ts.map +1 -0
- package/dist/RateLimiter.js +118 -0
- package/dist/RateLimiter.js.map +1 -0
- package/dist/RecoveryCode.d.ts +169 -0
- package/dist/RecoveryCode.d.ts.map +1 -0
- package/dist/RecoveryCode.js +299 -0
- package/dist/RecoveryCode.js.map +1 -0
- package/dist/RefreshToken.d.ts +222 -0
- package/dist/RefreshToken.d.ts.map +1 -0
- package/dist/RefreshToken.js +342 -0
- package/dist/RefreshToken.js.map +1 -0
- package/dist/SecurityTimeline.d.ts +72 -0
- package/dist/SecurityTimeline.d.ts.map +1 -0
- package/dist/SecurityTimeline.js +386 -0
- package/dist/SecurityTimeline.js.map +1 -0
- package/dist/Sessions.d.ts +135 -11
- package/dist/Sessions.d.ts.map +1 -1
- package/dist/Sessions.js +546 -1
- package/dist/Sessions.js.map +1 -1
- package/dist/StepUp.d.ts +44 -0
- package/dist/StepUp.d.ts.map +1 -0
- package/dist/StepUp.js +82 -0
- package/dist/StepUp.js.map +1 -0
- package/dist/Storage.d.ts +175 -0
- package/dist/Storage.d.ts.map +1 -0
- package/dist/Storage.js +27 -0
- package/dist/Storage.js.map +1 -0
- package/dist/StorageMigrations.d.ts +19 -0
- package/dist/StorageMigrations.d.ts.map +1 -0
- package/dist/StorageMigrations.js +291 -0
- package/dist/StorageMigrations.js.map +1 -0
- package/dist/Testing.d.ts +9 -1
- package/dist/Testing.d.ts.map +1 -1
- package/dist/Testing.js +30 -2
- package/dist/Testing.js.map +1 -1
- package/dist/Totp.d.ts +220 -0
- package/dist/Totp.d.ts.map +1 -0
- package/dist/Totp.js +477 -0
- package/dist/Totp.js.map +1 -0
- package/dist/TrustedDevice.d.ts +127 -0
- package/dist/TrustedDevice.d.ts.map +1 -0
- package/dist/TrustedDevice.js +252 -0
- package/dist/TrustedDevice.js.map +1 -0
- package/dist/WaitUntil.d.ts +3 -0
- package/dist/WaitUntil.d.ts.map +1 -1
- package/dist/WaitUntil.js +6 -3
- package/dist/WaitUntil.js.map +1 -1
- package/dist/Webhook.d.ts +72 -0
- package/dist/Webhook.d.ts.map +1 -0
- package/dist/Webhook.js +82 -0
- package/dist/Webhook.js.map +1 -0
- package/dist/alchemy/cloudflare/Email.d.ts +25 -0
- package/dist/alchemy/cloudflare/Email.d.ts.map +1 -0
- package/dist/alchemy/cloudflare/Email.js +117 -0
- package/dist/alchemy/cloudflare/Email.js.map +1 -0
- package/dist/alchemy/cloudflare/RateLimitDurableObject.d.ts +34 -0
- package/dist/alchemy/cloudflare/RateLimitDurableObject.d.ts.map +1 -0
- package/dist/alchemy/cloudflare/RateLimitDurableObject.js +30 -0
- package/dist/alchemy/cloudflare/RateLimitDurableObject.js.map +1 -0
- package/dist/cloudflare/Email.d.ts +25 -0
- package/dist/cloudflare/Email.d.ts.map +1 -0
- package/dist/cloudflare/Email.js +153 -0
- package/dist/cloudflare/Email.js.map +1 -0
- package/dist/cloudflare/RateLimitDurableObject.d.ts +50 -0
- package/dist/cloudflare/RateLimitDurableObject.d.ts.map +1 -0
- package/dist/cloudflare/RateLimitDurableObject.js +51 -0
- package/dist/cloudflare/RateLimitDurableObject.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/RateLimitDurableObject.d.ts +32 -0
- package/dist/internal/RateLimitDurableObject.d.ts.map +1 -0
- package/dist/internal/RateLimitDurableObject.js +80 -0
- package/dist/internal/RateLimitDurableObject.js.map +1 -0
- package/migrations/0001_auth_storage.sql +32 -0
- package/migrations/0002_auth_password.sql +25 -0
- package/migrations/0003_auth_login_approval_review.sql +22 -0
- package/migrations/0004_auth_trusted_device.sql +12 -0
- package/migrations/0005_auth_passkey.sql +17 -0
- package/migrations/0006_auth_totp_factor.sql +17 -0
- package/migrations/0007_auth_recovery_code.sql +13 -0
- package/migrations/0008_auth_api_key.sql +17 -0
- package/migrations/0009_auth_refresh_token.sql +21 -0
- package/migrations/0010_auth_jwt_revocation.sql +8 -0
- package/migrations/0011_auth_oauth_account.sql +16 -0
- package/migrations/0012_auth_oauth_provider_token_vault.sql +20 -0
- package/migrations/0013_auth_security_timeline.sql +16 -0
- package/package.json +161 -16
- package/LICENSE +0 -21
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as Cloudflare from "alchemy/Cloudflare";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import * as Internal from "../../internal/RateLimitDurableObject.js";
|
|
4
|
+
export interface RateLimitDurableObjectFixedWindowInput {
|
|
5
|
+
readonly tokens: number;
|
|
6
|
+
readonly refillMillis: number;
|
|
7
|
+
readonly limit: number | undefined;
|
|
8
|
+
}
|
|
9
|
+
export interface RateLimitDurableObjectTokenBucketInput {
|
|
10
|
+
readonly tokens: number;
|
|
11
|
+
readonly limit: number;
|
|
12
|
+
readonly refillMillis: number;
|
|
13
|
+
readonly allowOverflow: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface RateLimitDurableObjectApi {
|
|
16
|
+
readonly fixedWindow: (input: RateLimitDurableObjectFixedWindowInput) => Effect.Effect<readonly [count: number, ttl: number], unknown>;
|
|
17
|
+
readonly tokenBucket: (input: RateLimitDurableObjectTokenBucketInput) => Effect.Effect<number, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface AlchemyRateLimitDurableObjectNamespace {
|
|
20
|
+
readonly getByName: (name: string) => RateLimitDurableObjectApi;
|
|
21
|
+
}
|
|
22
|
+
export interface RateLimitStoreDurableObjectLayerOptions {
|
|
23
|
+
readonly namespace: AlchemyRateLimitDurableObjectNamespace;
|
|
24
|
+
readonly prefix?: string;
|
|
25
|
+
}
|
|
26
|
+
declare const EffectAuthRateLimitDurableObject_base: Effect.Effect<Cloudflare.DurableObjectNamespace<EffectAuthRateLimitDurableObject>, never, Cloudflare.Worker> & (new (_: never) => Internal.RateLimitDurableObjectApi);
|
|
27
|
+
export declare class EffectAuthRateLimitDurableObject extends EffectAuthRateLimitDurableObject_base {
|
|
28
|
+
}
|
|
29
|
+
export declare const RateLimitDurableObject: Effect.Effect<AlchemyRateLimitDurableObjectNamespace>;
|
|
30
|
+
export declare const RateLimitStoreDurableObject: {
|
|
31
|
+
readonly layer: (options: RateLimitStoreDurableObjectLayerOptions) => import("effect/Layer").Layer<import("effect/unstable/persistence/RateLimiter").RateLimiterStore, never, never>;
|
|
32
|
+
};
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=RateLimitDurableObject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimitDurableObject.d.ts","sourceRoot":"","sources":["../../../src/alchemy/cloudflare/RateLimitDurableObject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,QAAQ,MAAM,0CAA0C,CAAC;AAErE,MAAM,WAAW,sCAAsC;IACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED,MAAM,WAAW,sCAAsC;IACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,WAAW,EAAE,CACpB,KAAK,EAAE,sCAAsC,KAC1C,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IACnE,QAAQ,CAAC,WAAW,EAAE,CACpB,KAAK,EAAE,sCAAsC,KAC1C,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,sCAAsC;IACrD,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,yBAAyB,CAAC;CACjE;AAED,MAAM,WAAW,uCAAuC;IACtD,QAAQ,CAAC,SAAS,EAAE,sCAAsC,CAAC;IAC3D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;;AAiCD,qBAAa,gCAAiC,SAAQ,qCAWrD;CAAG;AAEJ,eAAO,MAAM,sBAAsB,EACc,MAAM,CAAC,MAAM,CAAC,sCAAsC,CAAC,CAAC;AAEvG,eAAO,MAAM,2BAA2B;8BACrB,uCAAuC;CAKhD,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as Cloudflare from "alchemy/Cloudflare";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import * as Internal from "../../internal/RateLimitDurableObject.js";
|
|
4
|
+
const fromAlchemyStorageOperations = (operations) => {
|
|
5
|
+
const storage = {
|
|
6
|
+
get: (key) => operations.get(key),
|
|
7
|
+
put: (key, value) => operations.put(key, value),
|
|
8
|
+
transaction: (body) => body(storage),
|
|
9
|
+
};
|
|
10
|
+
return storage;
|
|
11
|
+
};
|
|
12
|
+
const fromAlchemyDurableObjectStorage = (durableObjectStorage) => ({
|
|
13
|
+
...fromAlchemyStorageOperations(durableObjectStorage),
|
|
14
|
+
transaction: (body) => durableObjectStorage.transaction((transaction) => body(fromAlchemyStorageOperations(transaction)).pipe(Effect.orDie)),
|
|
15
|
+
});
|
|
16
|
+
export class EffectAuthRateLimitDurableObject extends Cloudflare.DurableObjectNamespace()("EffectAuthRateLimitDurableObject", Effect.gen(function* () {
|
|
17
|
+
return Effect.gen(function* () {
|
|
18
|
+
const state = yield* Cloudflare.DurableObjectState;
|
|
19
|
+
return Internal.makeRateLimitDurableObjectApi(fromAlchemyDurableObjectStorage(state.storage));
|
|
20
|
+
});
|
|
21
|
+
})) {
|
|
22
|
+
}
|
|
23
|
+
export const RateLimitDurableObject = EffectAuthRateLimitDurableObject;
|
|
24
|
+
export const RateLimitStoreDurableObject = {
|
|
25
|
+
layer: (options) => Internal.makeRateLimitDurableObjectStoreLayer({
|
|
26
|
+
namespace: options.namespace,
|
|
27
|
+
prefix: options.prefix,
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=RateLimitDurableObject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimitDurableObject.js","sourceRoot":"","sources":["../../../src/alchemy/cloudflare/RateLimitDurableObject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,QAAQ,MAAM,0CAA0C,CAAC;AAsCrE,MAAM,4BAA4B,GAAG,CACnC,UAAiD,EACT,EAAE;IAC1C,MAAM,OAAO,GAA2C;QACtD,GAAG,EAAE,CAAc,GAAW,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAI,GAAG,CAAC;QACzD,GAAG,EAAE,CAAI,GAAW,EAAE,KAAQ,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC;QAC7D,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;KACrC,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,+BAA+B,GAAG,CACtC,oBAAqD,EACb,EAAE,CAAC,CAAC;IAC5C,GAAG,4BAA4B,CAAC,oBAAoB,CAAC;IACrD,WAAW,EAAE,CACX,IAE8B,EAC9B,EAAE,CACF,oBAAoB,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,EAAE,CAC/C,IAAI,CAAC,4BAA4B,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CACnE;CACJ,CAAC,CAAC;AAEH,MAAM,OAAO,gCAAiC,SAAQ,UAAU,CAAC,sBAAsB,EAAoC,CACzH,kCAAkC,EAClC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACzB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,kBAAkB,CAAC;QAEnD,OAAO,QAAQ,CAAC,6BAA6B,CAC3C,+BAA+B,CAAC,KAAK,CAAC,OAAO,CAAC,CAC/C,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CACH;CAAG;AAEJ,MAAM,CAAC,MAAM,sBAAsB,GACjC,gCAAoG,CAAC;AAEvG,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,KAAK,EAAE,CAAC,OAAgD,EAAE,EAAE,CAC1D,QAAQ,CAAC,oCAAoC,CAAC;QAC5C,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC;CACI,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Effect, Layer } from "effect";
|
|
2
|
+
import { EmailSendError, Mailer, type EmailAddress, type EmailMessage as AuthEmailMessage, type MailerService } from "../Mailer.js";
|
|
3
|
+
export type MaybePromise<A> = A | PromiseLike<A>;
|
|
4
|
+
export interface CloudflareSendEmailBinding<Message = unknown> {
|
|
5
|
+
readonly send: (message: Message) => MaybePromise<unknown>;
|
|
6
|
+
}
|
|
7
|
+
export type CloudflareEmailMessageConstructor<Message = unknown> = new (from: string, to: string, raw: string) => Message;
|
|
8
|
+
export interface CloudflareMailerOptions<Message = unknown> {
|
|
9
|
+
readonly binding: CloudflareSendEmailBinding<Message>;
|
|
10
|
+
readonly EmailMessage: CloudflareEmailMessageConstructor<Message>;
|
|
11
|
+
readonly from: EmailAddress;
|
|
12
|
+
readonly provider?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface CloudflareRenderedEmail {
|
|
15
|
+
readonly from: string;
|
|
16
|
+
readonly recipients: readonly string[];
|
|
17
|
+
readonly raw: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const renderCloudflareEmail: <Message>(options: CloudflareMailerOptions<Message>, message: AuthEmailMessage) => Effect.Effect<CloudflareRenderedEmail, EmailSendError>;
|
|
20
|
+
export declare const makeCloudflareMailer: <Message>(options: CloudflareMailerOptions<Message>) => MailerService;
|
|
21
|
+
export declare const CloudflareMailer: {
|
|
22
|
+
readonly make: <Message>(options: CloudflareMailerOptions<Message>) => MailerService;
|
|
23
|
+
readonly layer: <Message>(options: CloudflareMailerOptions<Message>) => Layer.Layer<Mailer, never, never>;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=Email.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Email.d.ts","sourceRoot":"","sources":["../../src/cloudflare/Email.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAY,KAAK,EAAE,MAAM,QAAQ,CAAC;AAGjD,OAAO,EACL,cAAc,EACd,MAAM,EACN,KAAK,YAAY,EACjB,KAAK,YAAY,IAAI,gBAAgB,EACrC,KAAK,aAAa,EACnB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;AAEjD,MAAM,WAAW,0BAA0B,CAAC,OAAO,GAAG,OAAO;IAC3D,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC;CAC5D;AAED,MAAM,MAAM,iCAAiC,CAAC,OAAO,GAAG,OAAO,IAAI,KACjE,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,KACR,OAAO,CAAC;AAEb,MAAM,WAAW,uBAAuB,CAAC,OAAO,GAAG,OAAO;IACxD,QAAQ,CAAC,OAAO,EAAE,0BAA0B,CAAC,OAAO,CAAC,CAAC;IACtD,QAAQ,CAAC,YAAY,EAAE,iCAAiC,CAAC,OAAO,CAAC,CAAC;IAClE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAwLD,eAAO,MAAM,qBAAqB,GAAI,OAAO,EAC3C,SAAS,uBAAuB,CAAC,OAAO,CAAC,EACzC,SAAS,gBAAgB,KACxB,MAAM,CAAC,MAAM,CAAC,uBAAuB,EAAE,cAAc,CAqEpD,CAAC;AAEL,eAAO,MAAM,oBAAoB,GAAI,OAAO,EAC1C,SAAS,uBAAuB,CAAC,OAAO,CAAC,KACxC,aAyBC,CAAC;AAEL,eAAO,MAAM,gBAAgB;oBA7BQ,OAAO,WACjC,uBAAuB,CAAC,OAAO,CAAC,KACxC,aAAa;qBA6BN,OAAO,WAAW,uBAAuB,CAAC,OAAO,CAAC;CAElD,CAAC"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Effect, Encoding, Layer } from "effect";
|
|
2
|
+
import { EmailSendError, Mailer, } from "../Mailer.js";
|
|
3
|
+
const crlf = "\r\n";
|
|
4
|
+
const multipartBoundary = "effect-auth-cloudflare-email-boundary";
|
|
5
|
+
const textEncoder = new TextEncoder();
|
|
6
|
+
const reservedHeaderNames = new Set([
|
|
7
|
+
"bcc",
|
|
8
|
+
"cc",
|
|
9
|
+
"content-transfer-encoding",
|
|
10
|
+
"content-type",
|
|
11
|
+
"from",
|
|
12
|
+
"mime-version",
|
|
13
|
+
"reply-to",
|
|
14
|
+
"subject",
|
|
15
|
+
"to",
|
|
16
|
+
]);
|
|
17
|
+
const sendError = (message, cause, provider = "cloudflare") => new EmailSendError({ provider, message, cause });
|
|
18
|
+
const addressEmail = (address) => typeof address === "string" ? address : address.email;
|
|
19
|
+
const escapeDisplayName = (name) => `"${name.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
|
|
20
|
+
const addressHeader = (address) => typeof address === "string"
|
|
21
|
+
? address
|
|
22
|
+
: address.name === undefined || address.name.length === 0
|
|
23
|
+
? address.email
|
|
24
|
+
: `${escapeDisplayName(address.name)} <${address.email}>`;
|
|
25
|
+
const addressList = (address) => {
|
|
26
|
+
if (address === undefined) {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
return Array.isArray(address) ? address : [address];
|
|
30
|
+
};
|
|
31
|
+
const uniqueStrings = (values) => [
|
|
32
|
+
...new Set(values),
|
|
33
|
+
];
|
|
34
|
+
const validateHeaderName = (name, provider) => {
|
|
35
|
+
if (!/^[A-Za-z0-9-]+$/.test(name)) {
|
|
36
|
+
return Effect.fail(sendError(`Invalid email header name: ${name}`, undefined, provider));
|
|
37
|
+
}
|
|
38
|
+
if (reservedHeaderNames.has(name.toLowerCase())) {
|
|
39
|
+
return Effect.fail(sendError(`Email header is managed by CloudflareMailer: ${name}`, undefined, provider));
|
|
40
|
+
}
|
|
41
|
+
return Effect.succeed(name);
|
|
42
|
+
};
|
|
43
|
+
const validateHeaderValue = (value, provider) => value.includes("\r") || value.includes("\n")
|
|
44
|
+
? Effect.fail(sendError("Email header values must not contain newlines", undefined, provider))
|
|
45
|
+
: Effect.succeed(value);
|
|
46
|
+
const headerLine = (name, value, provider) => Effect.gen(function* () {
|
|
47
|
+
const safeName = yield* validateHeaderName(name, provider);
|
|
48
|
+
const safeValue = yield* validateHeaderValue(value, provider);
|
|
49
|
+
return `${safeName}: ${safeValue}`;
|
|
50
|
+
});
|
|
51
|
+
const systemHeaderLine = (name, value, provider) => validateHeaderValue(value, provider).pipe(Effect.map((safeValue) => `${name}: ${safeValue}`));
|
|
52
|
+
const wrapBase64 = (value) => value.match(/.{1,76}/g)?.join(crlf) ?? "";
|
|
53
|
+
const base64Body = (content) => wrapBase64(Encoding.encodeBase64(textEncoder.encode(content)));
|
|
54
|
+
const contentPart = (contentType, content) => [
|
|
55
|
+
`Content-Type: ${contentType}; charset=utf-8`,
|
|
56
|
+
"Content-Transfer-Encoding: base64",
|
|
57
|
+
"",
|
|
58
|
+
base64Body(content),
|
|
59
|
+
].join(crlf);
|
|
60
|
+
const renderedBody = (message, provider) => {
|
|
61
|
+
if (message.text === undefined && message.html === undefined) {
|
|
62
|
+
return Effect.fail(sendError("Email message must include text or html content", undefined, provider));
|
|
63
|
+
}
|
|
64
|
+
if (message.text !== undefined && message.html !== undefined) {
|
|
65
|
+
return Effect.succeed([
|
|
66
|
+
[`Content-Type: multipart/alternative; boundary="${multipartBoundary}"`],
|
|
67
|
+
[
|
|
68
|
+
`--${multipartBoundary}`,
|
|
69
|
+
contentPart("text/plain", message.text),
|
|
70
|
+
`--${multipartBoundary}`,
|
|
71
|
+
contentPart("text/html", message.html),
|
|
72
|
+
`--${multipartBoundary}--`,
|
|
73
|
+
"",
|
|
74
|
+
].join(crlf),
|
|
75
|
+
]);
|
|
76
|
+
}
|
|
77
|
+
if (message.html !== undefined) {
|
|
78
|
+
return Effect.succeed([
|
|
79
|
+
[
|
|
80
|
+
"Content-Type: text/html; charset=utf-8",
|
|
81
|
+
"Content-Transfer-Encoding: base64",
|
|
82
|
+
],
|
|
83
|
+
base64Body(message.html),
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
return Effect.succeed([
|
|
87
|
+
[
|
|
88
|
+
"Content-Type: text/plain; charset=utf-8",
|
|
89
|
+
"Content-Transfer-Encoding: base64",
|
|
90
|
+
],
|
|
91
|
+
base64Body(message.text ?? ""),
|
|
92
|
+
]);
|
|
93
|
+
};
|
|
94
|
+
const recipientHeaders = (message) => [
|
|
95
|
+
addressList(message.to).map(addressHeader).join(", "),
|
|
96
|
+
...addressList(message.cc).map(addressHeader),
|
|
97
|
+
];
|
|
98
|
+
const envelopeRecipients = (message) => uniqueStrings([
|
|
99
|
+
...addressList(message.to),
|
|
100
|
+
...addressList(message.cc),
|
|
101
|
+
...addressList(message.bcc),
|
|
102
|
+
].map((address) => addressEmail(address)));
|
|
103
|
+
export const renderCloudflareEmail = (options, message) => Effect.gen(function* () {
|
|
104
|
+
const provider = options.provider ?? "cloudflare";
|
|
105
|
+
const from = yield* validateHeaderValue(addressEmail(message.from ?? options.from), provider);
|
|
106
|
+
const recipients = [];
|
|
107
|
+
for (const recipient of envelopeRecipients(message)) {
|
|
108
|
+
recipients.push(yield* validateHeaderValue(recipient, provider));
|
|
109
|
+
}
|
|
110
|
+
if (recipients.length === 0) {
|
|
111
|
+
return yield* sendError("Email message must include at least one recipient", undefined, provider);
|
|
112
|
+
}
|
|
113
|
+
const [toHeader] = recipientHeaders(message);
|
|
114
|
+
const headers = [];
|
|
115
|
+
const [contentHeaders, body] = yield* renderedBody(message, provider);
|
|
116
|
+
headers.push(yield* systemHeaderLine("From", addressHeader(message.from ?? options.from), provider));
|
|
117
|
+
headers.push(yield* systemHeaderLine("To", toHeader, provider));
|
|
118
|
+
const cc = addressList(message.cc);
|
|
119
|
+
if (cc.length > 0) {
|
|
120
|
+
headers.push(yield* systemHeaderLine("Cc", cc.map(addressHeader).join(", "), provider));
|
|
121
|
+
}
|
|
122
|
+
if (message.replyTo !== undefined) {
|
|
123
|
+
headers.push(yield* systemHeaderLine("Reply-To", addressHeader(message.replyTo), provider));
|
|
124
|
+
}
|
|
125
|
+
headers.push(yield* systemHeaderLine("Subject", message.subject, provider));
|
|
126
|
+
headers.push("MIME-Version: 1.0");
|
|
127
|
+
headers.push(...contentHeaders);
|
|
128
|
+
for (const [name, value] of Object.entries(message.headers ?? {})) {
|
|
129
|
+
headers.push(yield* headerLine(name, value, provider));
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
from,
|
|
133
|
+
recipients,
|
|
134
|
+
raw: `${headers.join(crlf)}${crlf}${crlf}${body}`,
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
export const makeCloudflareMailer = (options) => Mailer.make({
|
|
138
|
+
send: Effect.fn("auth.cloudflare_email.send")(function* (message) {
|
|
139
|
+
const rendered = yield* renderCloudflareEmail(options, message);
|
|
140
|
+
for (const recipient of rendered.recipients) {
|
|
141
|
+
const cloudflareMessage = new options.EmailMessage(rendered.from, recipient, rendered.raw);
|
|
142
|
+
yield* Effect.tryPromise({
|
|
143
|
+
try: () => Promise.resolve(options.binding.send(cloudflareMessage)),
|
|
144
|
+
catch: (cause) => sendError("Cloudflare failed to send email", cause, options.provider),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}),
|
|
148
|
+
});
|
|
149
|
+
export const CloudflareMailer = {
|
|
150
|
+
make: makeCloudflareMailer,
|
|
151
|
+
layer: (options) => Layer.succeed(Mailer, makeCloudflareMailer(options)),
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=Email.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Email.js","sourceRoot":"","sources":["../../src/cloudflare/Email.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
export interface RateLimitDurableObjectFixedWindowInput {
|
|
3
|
+
readonly tokens: number;
|
|
4
|
+
readonly refillMillis: number;
|
|
5
|
+
readonly limit: number | undefined;
|
|
6
|
+
}
|
|
7
|
+
export interface RateLimitDurableObjectTokenBucketInput {
|
|
8
|
+
readonly tokens: number;
|
|
9
|
+
readonly limit: number;
|
|
10
|
+
readonly refillMillis: number;
|
|
11
|
+
readonly allowOverflow: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface RateLimitDurableObjectApi {
|
|
14
|
+
readonly fixedWindow: (input: RateLimitDurableObjectFixedWindowInput) => Effect.Effect<readonly [count: number, ttl: number], unknown>;
|
|
15
|
+
readonly tokenBucket: (input: RateLimitDurableObjectTokenBucketInput) => Effect.Effect<number, unknown>;
|
|
16
|
+
}
|
|
17
|
+
export interface CloudflareRateLimitDurableObjectStorageOperations {
|
|
18
|
+
readonly get: <T = unknown>(key: string) => Promise<T | undefined>;
|
|
19
|
+
readonly put: <T>(key: string, value: T) => Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export interface CloudflareRateLimitDurableObjectStorage extends CloudflareRateLimitDurableObjectStorageOperations {
|
|
22
|
+
readonly transaction: <A>(body: (transaction: CloudflareRateLimitDurableObjectStorageOperations) => Promise<A>) => Promise<A>;
|
|
23
|
+
}
|
|
24
|
+
export type MaybePromise<T> = T | PromiseLike<T>;
|
|
25
|
+
export type CloudflareRateLimitDurableObjectFixedWindowOutput = readonly MaybePromise<number>[];
|
|
26
|
+
export interface CloudflareRateLimitDurableObjectStub {
|
|
27
|
+
readonly fixedWindow: (input: RateLimitDurableObjectFixedWindowInput) => MaybePromise<CloudflareRateLimitDurableObjectFixedWindowOutput>;
|
|
28
|
+
readonly tokenBucket: (input: RateLimitDurableObjectTokenBucketInput) => MaybePromise<number>;
|
|
29
|
+
}
|
|
30
|
+
export type CloudflareRateLimitDurableObjectNamespace<Id = unknown> = {
|
|
31
|
+
readonly getByName: (name: string) => CloudflareRateLimitDurableObjectStub;
|
|
32
|
+
} | {
|
|
33
|
+
readonly idFromName: (name: string) => Id;
|
|
34
|
+
readonly get: (id: Id) => CloudflareRateLimitDurableObjectStub;
|
|
35
|
+
};
|
|
36
|
+
export interface RateLimitStoreDurableObjectLayerOptions<Id = unknown> {
|
|
37
|
+
readonly namespace: CloudflareRateLimitDurableObjectNamespace<Id>;
|
|
38
|
+
readonly prefix?: string;
|
|
39
|
+
}
|
|
40
|
+
export type CloudflareDurableObjectBase = abstract new (...args: any[]) => object;
|
|
41
|
+
export declare const makeRateLimitDurableObjectApi: (storage: CloudflareRateLimitDurableObjectStorage) => RateLimitDurableObjectApi;
|
|
42
|
+
export declare const RateLimitDurableObject: <Base extends CloudflareDurableObjectBase>(Base: Base) => (abstract new (...args: any[]) => {
|
|
43
|
+
readonly "__#3@#api": RateLimitDurableObjectApi;
|
|
44
|
+
fixedWindow(input: RateLimitDurableObjectFixedWindowInput): Promise<readonly [count: number, ttl: number]>;
|
|
45
|
+
tokenBucket(input: RateLimitDurableObjectTokenBucketInput): Promise<number>;
|
|
46
|
+
}) & Base;
|
|
47
|
+
export declare const RateLimitStoreDurableObject: {
|
|
48
|
+
readonly layer: <Id>(options: RateLimitStoreDurableObjectLayerOptions<Id>) => import("effect/Layer").Layer<import("effect/unstable/persistence/RateLimiter").RateLimiterStore, never, never>;
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=RateLimitDurableObject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimitDurableObject.d.ts","sourceRoot":"","sources":["../../src/cloudflare/RateLimitDurableObject.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import * as Internal from "../internal/RateLimitDurableObject.js";
|
|
3
|
+
const fromCloudflareStorageOperations = (operations) => {
|
|
4
|
+
const storage = {
|
|
5
|
+
get: (key) => Effect.tryPromise(() => operations.get(key)),
|
|
6
|
+
put: (key, value) => Effect.tryPromise(() => operations.put(key, value)),
|
|
7
|
+
transaction: (body) => body(storage),
|
|
8
|
+
};
|
|
9
|
+
return storage;
|
|
10
|
+
};
|
|
11
|
+
const fromCloudflareDurableObjectStorage = (durableObjectStorage) => ({
|
|
12
|
+
...fromCloudflareStorageOperations(durableObjectStorage),
|
|
13
|
+
transaction: (body) => Effect.tryPromise(() => durableObjectStorage.transaction((transaction) => Effect.runPromise(body(fromCloudflareStorageOperations(transaction))))),
|
|
14
|
+
});
|
|
15
|
+
const getStubByName = (namespace, name) => "getByName" in namespace
|
|
16
|
+
? namespace.getByName(name)
|
|
17
|
+
: namespace.get(namespace.idFromName(name));
|
|
18
|
+
const fromCloudflareDurableObjectNamespace = (namespace) => ({
|
|
19
|
+
getByName: (name) => {
|
|
20
|
+
const stub = getStubByName(namespace, name);
|
|
21
|
+
return {
|
|
22
|
+
fixedWindow: (input) => Effect.tryPromise(async () => {
|
|
23
|
+
const result = await stub.fixedWindow(input);
|
|
24
|
+
const count = await result[0];
|
|
25
|
+
const ttl = await result[1];
|
|
26
|
+
return [count, ttl];
|
|
27
|
+
}),
|
|
28
|
+
tokenBucket: (input) => Effect.tryPromise(() => Promise.resolve(stub.tokenBucket(input))),
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
export const makeRateLimitDurableObjectApi = (storage) => Internal.makeRateLimitDurableObjectApi(fromCloudflareDurableObjectStorage(storage));
|
|
33
|
+
export const RateLimitDurableObject = (Base) => {
|
|
34
|
+
class EffectAuthRateLimitDurableObject extends Base {
|
|
35
|
+
#api = makeRateLimitDurableObjectApi(this.ctx.storage);
|
|
36
|
+
fixedWindow(input) {
|
|
37
|
+
return Effect.runPromise(this.#api.fixedWindow(input));
|
|
38
|
+
}
|
|
39
|
+
tokenBucket(input) {
|
|
40
|
+
return Effect.runPromise(this.#api.tokenBucket(input));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return EffectAuthRateLimitDurableObject;
|
|
44
|
+
};
|
|
45
|
+
export const RateLimitStoreDurableObject = {
|
|
46
|
+
layer: (options) => Internal.makeRateLimitDurableObjectStoreLayer({
|
|
47
|
+
namespace: fromCloudflareDurableObjectNamespace(options.namespace),
|
|
48
|
+
prefix: options.prefix,
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=RateLimitDurableObject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimitDurableObject.js","sourceRoot":"","sources":["../../src/cloudflare/RateLimitDurableObject.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
export declare const packageName: "@effect-auth/core";
|
|
2
|
+
export * from "./ApiKey.js";
|
|
2
3
|
export * from "./AuditLog.js";
|
|
4
|
+
export * from "./AuthConfig.js";
|
|
3
5
|
export * from "./AuthFlow.js";
|
|
6
|
+
export * from "./AuthKernel.js";
|
|
4
7
|
export * from "./Challenge.js";
|
|
5
8
|
export * from "./Crypto.js";
|
|
9
|
+
export * from "./EmailOtp.js";
|
|
10
|
+
export * from "./EmailVerification.js";
|
|
6
11
|
export * from "./Identifiers.js";
|
|
12
|
+
export * from "./Jwt.js";
|
|
13
|
+
export * from "./LoginApproval.js";
|
|
14
|
+
export * from "./LoginNotification.js";
|
|
15
|
+
export * from "./LoginRisk.js";
|
|
16
|
+
export * from "./Mailer.js";
|
|
17
|
+
export * from "./MagicLink.js";
|
|
18
|
+
export * from "./OAuth.js";
|
|
19
|
+
export * from "./Password.js";
|
|
20
|
+
export * from "./Passkey.js";
|
|
7
21
|
export * from "./Policy.js";
|
|
8
22
|
export * from "./Privacy.js";
|
|
23
|
+
export * from "./RecoveryCode.js";
|
|
24
|
+
export * from "./RefreshToken.js";
|
|
9
25
|
export * from "./Sessions.js";
|
|
26
|
+
export * from "./SecurityTimeline.js";
|
|
27
|
+
export * from "./Storage.js";
|
|
28
|
+
export * from "./StepUp.js";
|
|
29
|
+
export * from "./Totp.js";
|
|
30
|
+
export * from "./TrustedDevice.js";
|
|
10
31
|
export * from "./WaitUntil.js";
|
|
32
|
+
export * from "./Webhook.js";
|
|
11
33
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,EAAG,mBAA4B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,EAAG,mBAA4B,CAAC;AAExD,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
export const packageName = "@effect-auth/core";
|
|
2
|
+
export * from "./ApiKey.js";
|
|
2
3
|
export * from "./AuditLog.js";
|
|
4
|
+
export * from "./AuthConfig.js";
|
|
3
5
|
export * from "./AuthFlow.js";
|
|
6
|
+
export * from "./AuthKernel.js";
|
|
4
7
|
export * from "./Challenge.js";
|
|
5
8
|
export * from "./Crypto.js";
|
|
9
|
+
export * from "./EmailOtp.js";
|
|
10
|
+
export * from "./EmailVerification.js";
|
|
6
11
|
export * from "./Identifiers.js";
|
|
12
|
+
export * from "./Jwt.js";
|
|
13
|
+
export * from "./LoginApproval.js";
|
|
14
|
+
export * from "./LoginNotification.js";
|
|
15
|
+
export * from "./LoginRisk.js";
|
|
16
|
+
export * from "./Mailer.js";
|
|
17
|
+
export * from "./MagicLink.js";
|
|
18
|
+
export * from "./OAuth.js";
|
|
19
|
+
export * from "./Password.js";
|
|
20
|
+
export * from "./Passkey.js";
|
|
7
21
|
export * from "./Policy.js";
|
|
8
22
|
export * from "./Privacy.js";
|
|
23
|
+
export * from "./RecoveryCode.js";
|
|
24
|
+
export * from "./RefreshToken.js";
|
|
9
25
|
export * from "./Sessions.js";
|
|
26
|
+
export * from "./SecurityTimeline.js";
|
|
27
|
+
export * from "./Storage.js";
|
|
28
|
+
export * from "./StepUp.js";
|
|
29
|
+
export * from "./Totp.js";
|
|
30
|
+
export * from "./TrustedDevice.js";
|
|
10
31
|
export * from "./WaitUntil.js";
|
|
32
|
+
export * from "./Webhook.js";
|
|
11
33
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,mBAA4B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,mBAA4B,CAAC;AAExD,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Effect, Layer } from "effect";
|
|
2
|
+
import { RateLimiter as PersistenceRateLimiter } from "effect/unstable/persistence";
|
|
3
|
+
export interface RateLimitDurableObjectFixedWindowInput {
|
|
4
|
+
readonly tokens: number;
|
|
5
|
+
readonly refillMillis: number;
|
|
6
|
+
readonly limit: number | undefined;
|
|
7
|
+
}
|
|
8
|
+
export interface RateLimitDurableObjectTokenBucketInput {
|
|
9
|
+
readonly tokens: number;
|
|
10
|
+
readonly limit: number;
|
|
11
|
+
readonly refillMillis: number;
|
|
12
|
+
readonly allowOverflow: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface RateLimitDurableObjectStorage {
|
|
15
|
+
readonly get: <T = unknown>(key: string) => Effect.Effect<T | undefined, unknown>;
|
|
16
|
+
readonly put: <T>(key: string, value: T) => Effect.Effect<void, unknown>;
|
|
17
|
+
readonly transaction: <A>(body: (transaction: RateLimitDurableObjectStorage) => Effect.Effect<A, unknown>) => Effect.Effect<A, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface RateLimitDurableObjectApi {
|
|
20
|
+
readonly fixedWindow: (input: RateLimitDurableObjectFixedWindowInput) => Effect.Effect<readonly [count: number, ttl: number], unknown>;
|
|
21
|
+
readonly tokenBucket: (input: RateLimitDurableObjectTokenBucketInput) => Effect.Effect<number, unknown>;
|
|
22
|
+
}
|
|
23
|
+
export interface RateLimitDurableObjectNamespace {
|
|
24
|
+
readonly getByName: (name: string) => RateLimitDurableObjectApi;
|
|
25
|
+
}
|
|
26
|
+
export interface RateLimitDurableObjectStoreOptions {
|
|
27
|
+
readonly namespace: RateLimitDurableObjectNamespace;
|
|
28
|
+
readonly prefix?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare const makeRateLimitDurableObjectApi: (storage: RateLimitDurableObjectStorage) => RateLimitDurableObjectApi;
|
|
31
|
+
export declare const makeRateLimitDurableObjectStoreLayer: (options: RateLimitDurableObjectStoreOptions) => Layer.Layer<PersistenceRateLimiter.RateLimiterStore>;
|
|
32
|
+
//# sourceMappingURL=RateLimitDurableObject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimitDurableObject.d.ts","sourceRoot":"","sources":["../../src/internal/RateLimitDurableObject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACxD,OAAO,EAAE,WAAW,IAAI,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAEpF,MAAM,WAAW,sCAAsC;IACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED,MAAM,WAAW,sCAAsC;IACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,OAAO,EACxB,GAAG,EAAE,MAAM,KACR,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,EAAE,OAAO,CAAC,CAAC;IAC3C,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACzE,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,EACtB,IAAI,EAAE,CACJ,WAAW,EAAE,6BAA6B,KACvC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,KAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,WAAW,EAAE,CACpB,KAAK,EAAE,sCAAsC,KAC1C,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IACnE,QAAQ,CAAC,WAAW,EAAE,CACpB,KAAK,EAAE,sCAAsC,KAC1C,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,yBAAyB,CAAC;CACjE;AAED,MAAM,WAAW,kCAAkC;IACjD,QAAQ,CAAC,SAAS,EAAE,+BAA+B,CAAC;IACpD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AA4BD,eAAO,MAAM,6BAA6B,GACxC,SAAS,6BAA6B,KACrC,yBA+DD,CAAC;AAEH,eAAO,MAAM,oCAAoC,GAC/C,SAAS,kCAAkC,KAC1C,KAAK,CAAC,KAAK,CAAC,sBAAsB,CAAC,gBAAgB,CA2BrD,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Clock, Duration, Effect, Layer } from "effect";
|
|
2
|
+
import { RateLimiter as PersistenceRateLimiter } from "effect/unstable/persistence";
|
|
3
|
+
const fixedWindowKey = "fixed-window";
|
|
4
|
+
const tokenBucketKey = "token-bucket";
|
|
5
|
+
const nonZeroMillis = (millis) => Math.max(1, millis);
|
|
6
|
+
const storeError = (operation, cause) => new PersistenceRateLimiter.RateLimiterError({
|
|
7
|
+
reason: new PersistenceRateLimiter.RateLimitStoreError({
|
|
8
|
+
message: `Cloudflare Durable Object rate limit store failed during ${operation}`,
|
|
9
|
+
cause,
|
|
10
|
+
}),
|
|
11
|
+
});
|
|
12
|
+
export const makeRateLimitDurableObjectApi = (storage) => ({
|
|
13
|
+
fixedWindow: (input) => storage.transaction((transaction) => Effect.gen(function* () {
|
|
14
|
+
const now = yield* Clock.currentTimeMillis;
|
|
15
|
+
const refillMillis = nonZeroMillis(input.refillMillis);
|
|
16
|
+
let counter = yield* transaction.get(fixedWindowKey);
|
|
17
|
+
if (!counter || counter.expiresAt <= now) {
|
|
18
|
+
counter = { count: 0, expiresAt: now };
|
|
19
|
+
}
|
|
20
|
+
const nextCount = counter.count + input.tokens;
|
|
21
|
+
const currentTtl = Math.max(0, counter.expiresAt - now);
|
|
22
|
+
if (input.limit !== undefined && nextCount > input.limit) {
|
|
23
|
+
return [nextCount, currentTtl];
|
|
24
|
+
}
|
|
25
|
+
const next = {
|
|
26
|
+
count: nextCount,
|
|
27
|
+
expiresAt: counter.expiresAt + refillMillis * input.tokens,
|
|
28
|
+
};
|
|
29
|
+
yield* transaction.put(fixedWindowKey, next);
|
|
30
|
+
return [next.count, Math.max(0, next.expiresAt - now)];
|
|
31
|
+
})),
|
|
32
|
+
tokenBucket: (input) => storage.transaction((transaction) => Effect.gen(function* () {
|
|
33
|
+
const now = yield* Clock.currentTimeMillis;
|
|
34
|
+
const refillMillis = nonZeroMillis(input.refillMillis);
|
|
35
|
+
let bucket = yield* transaction.get(tokenBucketKey);
|
|
36
|
+
if (!bucket) {
|
|
37
|
+
bucket = { tokens: input.limit, lastRefill: now };
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const elapsed = now - bucket.lastRefill;
|
|
41
|
+
const tokensToAdd = Math.floor(elapsed / refillMillis);
|
|
42
|
+
if (tokensToAdd > 0) {
|
|
43
|
+
bucket = {
|
|
44
|
+
tokens: Math.min(input.limit, bucket.tokens + tokensToAdd),
|
|
45
|
+
lastRefill: bucket.lastRefill + tokensToAdd * refillMillis,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const remaining = bucket.tokens - input.tokens;
|
|
50
|
+
if (input.allowOverflow || remaining >= 0) {
|
|
51
|
+
yield* transaction.put(tokenBucketKey, {
|
|
52
|
+
tokens: remaining,
|
|
53
|
+
lastRefill: bucket.lastRefill,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return remaining;
|
|
57
|
+
})),
|
|
58
|
+
});
|
|
59
|
+
export const makeRateLimitDurableObjectStoreLayer = (options) => {
|
|
60
|
+
const prefix = options.prefix ?? "effect-auth:rate-limit:";
|
|
61
|
+
const object = (key) => options.namespace.getByName(`${prefix}${key}`);
|
|
62
|
+
return Layer.sync(PersistenceRateLimiter.RateLimiterStore, () => PersistenceRateLimiter.RateLimiterStore.of({
|
|
63
|
+
fixedWindow: (input) => object(input.key)
|
|
64
|
+
.fixedWindow({
|
|
65
|
+
tokens: input.tokens,
|
|
66
|
+
refillMillis: Duration.toMillis(input.refillRate),
|
|
67
|
+
limit: input.limit,
|
|
68
|
+
})
|
|
69
|
+
.pipe(Effect.mapError((cause) => storeError("fixedWindow", cause))),
|
|
70
|
+
tokenBucket: (input) => object(input.key)
|
|
71
|
+
.tokenBucket({
|
|
72
|
+
tokens: input.tokens,
|
|
73
|
+
limit: input.limit,
|
|
74
|
+
refillMillis: Duration.toMillis(input.refillRate),
|
|
75
|
+
allowOverflow: input.allowOverflow,
|
|
76
|
+
})
|
|
77
|
+
.pipe(Effect.mapError((cause) => storeError("tokenBucket", cause))),
|
|
78
|
+
}));
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=RateLimitDurableObject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimitDurableObject.js","sourceRoot":"","sources":["../../src/internal/RateLimitDurableObject.ts"],"names":[],"mappings":"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"}
|