@shivaedev/platform 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +130 -12
  3. package/dist/rpc/identity.d.ts +8 -2
  4. package/dist/rpc/identity.d.ts.map +1 -1
  5. package/dist/rpc/identity.js +2 -0
  6. package/dist/rpc/identity.js.map +1 -1
  7. package/dist/rpc/middleware.d.ts +4 -1
  8. package/dist/rpc/middleware.d.ts.map +1 -1
  9. package/dist/rpc/middleware.js +4 -0
  10. package/dist/rpc/middleware.js.map +1 -1
  11. package/dist/rpc/publicConfig.d.ts +3 -0
  12. package/dist/rpc/publicConfig.d.ts.map +1 -0
  13. package/dist/rpc/publicConfig.js +8 -0
  14. package/dist/rpc/publicConfig.js.map +1 -0
  15. package/dist/server/better-auth/mount.d.ts +61 -0
  16. package/dist/server/better-auth/mount.d.ts.map +1 -0
  17. package/dist/server/better-auth/mount.js +59 -0
  18. package/dist/server/better-auth/mount.js.map +1 -0
  19. package/dist/server/better-auth/testing.d.ts +50 -0
  20. package/dist/server/better-auth/testing.d.ts.map +1 -0
  21. package/dist/server/better-auth/testing.js +18 -0
  22. package/dist/server/better-auth/testing.js.map +1 -0
  23. package/dist/server/databaseLayer.d.ts +2 -1
  24. package/dist/server/databaseLayer.d.ts.map +1 -1
  25. package/dist/server/databaseLayer.js +2 -0
  26. package/dist/server/databaseLayer.js.map +1 -1
  27. package/dist/server/rpc-server/adapters/betterAuthSessions.d.ts +3 -1
  28. package/dist/server/rpc-server/adapters/betterAuthSessions.d.ts.map +1 -1
  29. package/dist/server/rpc-server/adapters/betterAuthSessions.js +13 -22
  30. package/dist/server/rpc-server/adapters/betterAuthSessions.js.map +1 -1
  31. package/dist/server/rpc-server/publicConfigLayer.d.ts +4 -0
  32. package/dist/server/rpc-server/publicConfigLayer.d.ts.map +1 -0
  33. package/dist/server/rpc-server/publicConfigLayer.js +8 -0
  34. package/dist/server/rpc-server/publicConfigLayer.js.map +1 -0
  35. package/dist/server/rpc-server/session.d.ts +6 -2
  36. package/dist/server/rpc-server/session.d.ts.map +1 -1
  37. package/dist/server/rpc-server/session.js +16 -6
  38. package/dist/server/rpc-server/session.js.map +1 -1
  39. package/package.json +10 -6
  40. package/src/rpc/identity.ts +8 -2
  41. package/src/rpc/middleware.ts +7 -1
  42. package/src/rpc/publicConfig.ts +9 -0
  43. package/src/server/better-auth/mount.ts +68 -0
  44. package/src/server/better-auth/testing.ts +21 -0
  45. package/src/server/databaseLayer.ts +4 -1
  46. package/src/server/rpc-server/adapters/betterAuthSessions.ts +19 -23
  47. package/src/server/rpc-server/publicConfigLayer.ts +11 -0
  48. package/src/server/rpc-server/session.ts +38 -6
@@ -1 +1 @@
1
- {"version":3,"file":"databaseLayer.js","sourceRoot":"","sources":["../../src/server/databaseLayer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"databaseLayer.js","sourceRoot":"","sources":["../../src/server/databaseLayer.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,12 @@
1
+ import { Effect } from "effect";
2
+ import { AuthUnavailable, Unauthorized } from "#errors/taxonomy.ts";
1
3
  import type { ProviderAccountValue } from "#rpc/identity.ts";
2
4
  import type { SessionProvider, SessionShape } from "#server/rpc-server/session.ts";
3
5
  export type GetSession<TSession extends SessionShape> = (headers: globalThis.Headers) => Promise<TSession | null>;
4
6
  export type GetProviderAccounts = (headers: globalThis.Headers) => Promise<readonly ProviderAccountValue[]>;
5
7
  export type SessionWithProviderAccounts<TSession extends SessionShape> = TSession & {
6
8
  readonly user: TSession["user"] & {
7
- readonly providerAccounts: readonly ProviderAccountValue[];
9
+ readonly providerAccounts: Effect.Effect<readonly ProviderAccountValue[], AuthUnavailable | Unauthorized>;
8
10
  };
9
11
  };
10
12
  export declare function betterAuthSessions<TSession extends SessionShape>(getSession: GetSession<TSession>): SessionProvider<TSession>;
@@ -1 +1 @@
1
- {"version":3,"file":"betterAuthSessions.d.ts","sourceRoot":"","sources":["../../../../src/server/rpc-server/adapters/betterAuthSessions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AACnF,MAAM,MAAM,UAAU,CAAC,QAAQ,SAAS,YAAY,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAClH,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,KAAK,OAAO,CAAC,SAAS,oBAAoB,EAAE,CAAC,CAAC;AAC5G,MAAM,MAAM,2BAA2B,CAAC,QAAQ,SAAS,YAAY,IAAI,QAAQ,GAAG;IACnF,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG;QAAE,QAAQ,CAAC,gBAAgB,EAAE,SAAS,oBAAoB,EAAE,CAAA;KAAE,CAAC;CACjG,CAAC;AAOF,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,YAAY,EAAE,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;AAC/H,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,YAAY,EAC/D,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,EAChC,mBAAmB,EAAE,mBAAmB,GACtC,eAAe,CAAC,2BAA2B,CAAC,QAAQ,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"betterAuthSessions.d.ts","sourceRoot":"","sources":["../../../../src/server/rpc-server/adapters/betterAuthSessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,QAAQ,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AACnF,MAAM,MAAM,UAAU,CAAC,QAAQ,SAAS,YAAY,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAClH,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,KAAK,OAAO,CAAC,SAAS,oBAAoB,EAAE,CAAC,CAAC;AAC5G,MAAM,MAAM,2BAA2B,CAAC,QAAQ,SAAS,YAAY,IAAI,QAAQ,GAAG;IACnF,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG;QAAE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,oBAAoB,EAAE,EAAE,eAAe,GAAG,YAAY,CAAC,CAAA;KAAE,CAAC;CAChJ,CAAC;AAOF,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,YAAY,EAAE,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;AAC/H,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,YAAY,EAC/D,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,EAChC,mBAAmB,EAAE,mBAAmB,GACtC,eAAe,CAAC,2BAA2B,CAAC,QAAQ,CAAC,CAAC,CAAC"}
@@ -1,32 +1,23 @@
1
1
  import { Effect, Option, Predicate } from "effect";
2
- import { AuthUnavailable } from "#errors/taxonomy.ts";
2
+ import { AuthUnavailable, Unauthorized } from "#errors/taxonomy.ts";
3
3
  import { redact } from "#server/rpc-server/redact.ts";
4
4
  function unavailable(cause) {
5
5
  return Effect.andThen(Effect.logError("Authentication provider failed", redact(cause)), Effect.fail(new AuthUnavailable({ message: "Authentication is temporarily unavailable" })));
6
6
  }
7
7
  export function betterAuthSessions(getSession, getProviderAccounts) {
8
8
  const betterAuthSession = Effect.fn("PlatformRpc.betterAuthSession")(function* (headers) {
9
- const session = yield* Effect.tryPromise(async () => {
10
- const transport = new globalThis.Headers(headers);
11
- const resolved = await getSession(transport);
12
- if (resolved === null || getProviderAccounts === undefined) {
13
- return resolved;
14
- }
15
- const accounts = await getProviderAccounts(transport).catch((cause) => {
16
- if (Predicate.hasProperty(cause, "statusCode") && cause.statusCode === 401) {
17
- return null;
18
- }
19
- throw cause;
20
- });
21
- if (accounts === null) {
22
- return null;
23
- }
24
- return {
25
- ...resolved,
26
- user: { ...resolved.user, providerAccounts: accounts },
27
- };
28
- }).pipe(Effect.catch((error) => unavailable(error.cause)));
29
- return Option.fromNullishOr(session);
9
+ const transport = new globalThis.Headers(headers);
10
+ const session = yield* Effect.tryPromise(() => getSession(transport)).pipe(Effect.catch((error) => unavailable(error.cause)));
11
+ if (session === null || getProviderAccounts === undefined) {
12
+ return Option.fromNullishOr(session);
13
+ }
14
+ const providerAccounts = Effect.tryPromise({
15
+ catch: (cause) => cause,
16
+ try: () => getProviderAccounts(transport),
17
+ }).pipe(Effect.catch((cause) => Predicate.hasProperty(cause, "statusCode") && cause.statusCode === 401
18
+ ? Effect.fail(new Unauthorized({ message: "Authentication required" }))
19
+ : unavailable(cause)));
20
+ return Option.some({ ...session, user: { ...session.user, providerAccounts } });
30
21
  });
31
22
  return { get: betterAuthSession };
32
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"betterAuthSessions.js","sourceRoot":"","sources":["../../../../src/server/rpc-server/adapters/betterAuthSessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAOtD,SAAS,WAAW,CAAC,KAAc;IAClC,OAAO,MAAM,CAAC,OAAO,CACpB,MAAM,CAAC,QAAQ,CAAC,gCAAgC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAChE,MAAM,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,2CAA2C,EAAE,CAAC,CAAC,CAC1F,CAAC;AACH,CAAC;AAMD,MAAM,UAAU,kBAAkB,CAAgC,UAAgC,EAAE,mBAAyC;IAC5I,MAAM,iBAAiB,GAAG,MAAM,CAAC,EAAE,CAAC,+BAA+B,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAwB;QACvG,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,IAAI,EAAE;YACnD,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAClD,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,CAAC;YAC7C,IAAI,QAAQ,KAAK,IAAI,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;gBAC5D,OAAO,QAAQ,CAAC;YACjB,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBAC9E,IAAI,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,YAAY,CAAC,IAAI,KAAK,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;oBAC5E,OAAO,IAAI,CAAC;gBACb,CAAC;gBACD,MAAM,KAAK,CAAC;YACb,CAAC,CAAC,CAAC;YACH,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACvB,OAAO,IAAI,CAAC;YACb,CAAC;YACD,OAAO;gBACN,GAAG,QAAQ;gBACX,IAAI,EAAE,EAAE,GAAG,QAAQ,CAAC,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE;aACtD,CAAC;QACH,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3D,OAAO,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,CAAC;AACnC,CAAC"}
1
+ {"version":3,"file":"betterAuthSessions.js","sourceRoot":"","sources":["../../../../src/server/rpc-server/adapters/betterAuthSessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEpE,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAOtD,SAAS,WAAW,CAAC,KAAc;IAClC,OAAO,MAAM,CAAC,OAAO,CACpB,MAAM,CAAC,QAAQ,CAAC,gCAAgC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAChE,MAAM,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,2CAA2C,EAAE,CAAC,CAAC,CAC1F,CAAC;AACH,CAAC;AAMD,MAAM,UAAU,kBAAkB,CAAgC,UAAgC,EAAE,mBAAyC;IAC5I,MAAM,iBAAiB,GAAG,MAAM,CAAC,EAAE,CAAC,+BAA+B,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAwB;QACvG,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9H,IAAI,OAAO,KAAK,IAAI,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;YAC3D,OAAO,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;QACD,MAAM,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC;YAC1C,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;YACvB,GAAG,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC;SACzC,CAAC,CAAC,IAAI,CACN,MAAM,CAAC,KAAK,CACX,CAAC,KAAK,EAAwD,EAAE,CAC/D,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,YAAY,CAAC,IAAI,KAAK,CAAC,UAAU,KAAK,GAAG;YACrE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC,CAAC;YACvE,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CACtB,CACD,CAAC;QACF,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,CAAC;AACnC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Config, type ConfigProvider } from "effect";
2
+ import type { publicConfig } from "#rpc/publicConfig.ts";
3
+ export declare function publicConfigLayer<T, E>(declaration: ReturnType<typeof publicConfig<T, E>>, path?: string | ConfigProvider.Path): import("effect/Layer").Layer<import("effect/rpc/Rpc").Handler<"platform.publicConfig.get">, Config.ConfigError, never>;
4
+ //# sourceMappingURL=publicConfigLayer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicConfigLayer.d.ts","sourceRoot":"","sources":["../../../src/server/rpc-server/publicConfigLayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,cAAc,EAAU,MAAM,QAAQ,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,IAAI,0HAO9H"}
@@ -0,0 +1,8 @@
1
+ import { Config, Effect } from "effect";
2
+ export function publicConfigLayer(declaration, path) {
3
+ return declaration.toLayer(Effect.gen(function* () {
4
+ const value = yield* Config.schema(declaration.declaration.queries[0].success, path);
5
+ return declaration.of({ "platform.publicConfig.get": () => Effect.succeed(value) });
6
+ }));
7
+ }
8
+ //# sourceMappingURL=publicConfigLayer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicConfigLayer.js","sourceRoot":"","sources":["../../../src/server/rpc-server/publicConfigLayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAuB,MAAM,EAAE,MAAM,QAAQ,CAAC;AAG7D,MAAM,UAAU,iBAAiB,CAAO,WAAkD,EAAE,IAAmC;IAC9H,OAAO,WAAW,CAAC,OAAO,CACzB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACrF,OAAO,WAAW,CAAC,EAAE,CAAC,EAAE,2BAA2B,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACrF,CAAC,CAAC,CACF,CAAC;AACH,CAAC"}
@@ -1,8 +1,8 @@
1
1
  import { Effect, Layer, Option } from "effect";
2
2
  import type { Headers } from "effect/http";
3
3
  import { type AuthUnavailable, Forbidden, Unauthorized } from "#errors/taxonomy.ts";
4
- import { Identity, SessionUser, type SessionUserValue } from "#rpc/identity.ts";
5
- import { Authenticated, AuthenticatedUser, MaybeAuthenticated } from "#rpc/middleware.ts";
4
+ import { Identity, SessionUser, type SessionUserValue, type SessionUserWithProviderAccountsValue } from "#rpc/identity.ts";
5
+ import { Authenticated, AuthenticatedUser, AuthenticatedUserWithProviderAccounts, MaybeAuthenticated } from "#rpc/middleware.ts";
6
6
  import { type OriginPolicy } from "./origin.ts";
7
7
  export interface SessionShape {
8
8
  readonly user: {
@@ -24,4 +24,8 @@ export interface UserSessionShape extends SessionShape {
24
24
  }
25
25
  export declare function withSessionUser<TSession extends UserSessionShape>(policy: SessionPolicy<TSession>, headers: Headers.Headers, operation: string): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E | AuthUnavailable | Forbidden | Unauthorized, Exclude<Exclude<R, Identity>, SessionUser>>;
26
26
  export declare function authenticatedUserLayer<TSession extends UserSessionShape>(policy: SessionPolicy<TSession>): Layer.Layer<AuthenticatedUser>;
27
+ export interface ProviderAccountsSessionShape extends UserSessionShape {
28
+ readonly user: SessionUserWithProviderAccountsValue;
29
+ }
30
+ export declare function authenticatedUserWithProviderAccountsLayer<TSession extends ProviderAccountsSessionShape>(policy: SessionPolicy<TSession>): Layer.Layer<AuthenticatedUserWithProviderAccounts>;
27
31
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/server/rpc-server/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,KAAK,eAAe,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,QAAQ,EAAoB,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAClG,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,KAAK,YAAY,EAAiB,MAAM,aAAa,CAAC;AAE/D,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE;QACd,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;KACpB,CAAC;CACF;AACD,MAAM,WAAW,eAAe,CAAC,QAAQ,SAAS,YAAY;IAC7D,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC,CAAC;CACpG;AACD,MAAM,WAAW,aAAa,CAAC,QAAQ,SAAS,YAAY;IAC3D,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;CAC7C;AACD,eAAO,MAAM,cAAc,EAAE,CAAC,QAAQ,SAAS,YAAY,EAC1D,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,EAC/B,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,GAAG,EAAE,MAAM,KACP,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,SAAS,CAQrE,CAAC;AAIH,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,YAAY,EAAE,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAW7H;AACD,wBAAgB,uBAAuB,CAAC,QAAQ,SAAS,YAAY,EAAE,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAWvI;AACD,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACrD,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;CAChC;AACD,wBAAgB,eAAe,CAAC,QAAQ,SAAS,gBAAgB,EAAE,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,IACtI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,kHAsB/C;AACD,wBAAgB,sBAAsB,CAAC,QAAQ,SAAS,gBAAgB,EAAE,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAEzI"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/server/rpc-server/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,KAAK,eAAe,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,EACN,QAAQ,EAER,WAAW,EACX,KAAK,gBAAgB,EAErB,KAAK,oCAAoC,EACzC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,qCAAqC,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACjI,OAAO,EAAE,KAAK,YAAY,EAAiB,MAAM,aAAa,CAAC;AAE/D,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE;QACd,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;KACpB,CAAC;CACF;AACD,MAAM,WAAW,eAAe,CAAC,QAAQ,SAAS,YAAY;IAC7D,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC,CAAC;CACpG;AACD,MAAM,WAAW,aAAa,CAAC,QAAQ,SAAS,YAAY;IAC3D,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;CAC7C;AACD,eAAO,MAAM,cAAc,EAAE,CAAC,QAAQ,SAAS,YAAY,EAC1D,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,EAC/B,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,GAAG,EAAE,MAAM,KACP,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,SAAS,CAQrE,CAAC;AAIH,wBAAgB,kBAAkB,CAAC,QAAQ,SAAS,YAAY,EAAE,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAW7H;AACD,wBAAgB,uBAAuB,CAAC,QAAQ,SAAS,YAAY,EAAE,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAWvI;AACD,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACrD,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;CAChC;AACD,wBAAgB,eAAe,CAAC,QAAQ,SAAS,gBAAgB,EAAE,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,IACtI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,kHAmB/C;AACD,wBAAgB,sBAAsB,CAAC,QAAQ,SAAS,gBAAgB,EAAE,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAEzI;AAED,MAAM,WAAW,4BAA6B,SAAQ,gBAAgB;IACrE,QAAQ,CAAC,IAAI,EAAE,oCAAoC,CAAC;CACpD;AACD,wBAAgB,0CAA0C,CAAC,QAAQ,SAAS,4BAA4B,EACvG,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,GAC7B,KAAK,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAqBpD"}
@@ -1,7 +1,7 @@
1
1
  import { Effect, Layer, Option } from "effect";
2
2
  import { Forbidden, Unauthorized } from "#errors/taxonomy.ts";
3
- import { Identity, OptionalIdentity, SessionUser } from "#rpc/identity.ts";
4
- import { Authenticated, AuthenticatedUser, MaybeAuthenticated } from "#rpc/middleware.ts";
3
+ import { Identity, OptionalIdentity, SessionUser, SessionUserWithProviderAccounts, } from "#rpc/identity.ts";
4
+ import { Authenticated, AuthenticatedUser, AuthenticatedUserWithProviderAccounts, MaybeAuthenticated } from "#rpc/middleware.ts";
5
5
  import { originRequest } from "./origin.js";
6
6
  import { transportHeaders } from "./transportHeaders.js";
7
7
  export const resolveSession = Effect.fn("PlatformRpc.resolveSession")(function* (policy, headers, rpc) {
@@ -40,20 +40,30 @@ export function withSessionUser(policy, headers, operation) {
40
40
  if (Option.isNone(session)) {
41
41
  return yield* new Unauthorized({ message: "Authentication required" });
42
42
  }
43
- const { name, email, role, providerAccounts } = session.value.user;
43
+ const { name, email, role } = session.value.user;
44
44
  const id = yield* identified(session.value.user.id);
45
45
  return yield* effect.pipe(Effect.provideService(Identity, { id }), Effect.provideService(SessionUser, {
46
46
  email,
47
47
  id,
48
48
  name,
49
49
  ...(role === undefined ? {} : { role }),
50
- ...(providerAccounts === undefined
51
- ? {}
52
- : { providerAccounts: providerAccounts.map(({ accountId, providerId }) => ({ accountId, providerId })) }),
53
50
  }), Effect.annotateLogs({ userId: id }));
54
51
  });
55
52
  }
56
53
  export function authenticatedUserLayer(policy) {
57
54
  return Layer.succeed(AuthenticatedUser, (effect, { headers, rpc }) => effect.pipe(withSessionUser(policy, headers, rpc._tag)));
58
55
  }
56
+ export function authenticatedUserWithProviderAccountsLayer(policy) {
57
+ return Layer.succeed(AuthenticatedUserWithProviderAccounts, (effect, { headers, rpc }) => Effect.gen(function* () {
58
+ const session = yield* resolveSession(policy, headers, rpc._tag);
59
+ if (Option.isNone(session)) {
60
+ return yield* new Unauthorized({ message: "Authentication required" });
61
+ }
62
+ const { id, name, email, role, providerAccounts } = session.value.user;
63
+ const accounts = yield* Effect.cached(Effect.map(providerAccounts, (values) => values.map(({ accountId, providerId }) => ({ accountId, providerId }))));
64
+ const user = { email, id, name, ...(role === undefined ? {} : { role }) };
65
+ yield* identified(id);
66
+ return yield* effect.pipe(Effect.provideService(Identity, { id }), Effect.provideService(SessionUser, user), Effect.provideService(SessionUserWithProviderAccounts, { ...user, providerAccounts: accounts }), Effect.annotateLogs({ userId: id }));
67
+ }));
68
+ }
59
69
  //# sourceMappingURL=session.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/server/rpc-server/session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/server/rpc-server/session.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/platform",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "Opinionated Effect application infrastructure for ShivaeDev services",
5
5
  "homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/platform#readme",
6
6
  "bugs": {
@@ -41,7 +41,7 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "@shivaedev/effect-contract": "0.5.1",
44
- "@shivaedev/effect-sql": "0.5.2",
44
+ "@shivaedev/effect-sql": "0.6.0",
45
45
  "@shivaedev/types": "0.2.1"
46
46
  },
47
47
  "devDependencies": {
@@ -55,10 +55,10 @@
55
55
  "@prisma-next/sql-orm-client": "0.16.0",
56
56
  "@prisma-next/target-postgres": "0.16.0",
57
57
  "@shivaedev/effect-prisma": "0.10.0",
58
- "@shivaedev/effect-test-sql": "0.5.5",
58
+ "@shivaedev/effect-test-sql": "0.6.0",
59
59
  "@shivaedev/effect-trpc": "0.8.0",
60
- "@shivaedev/quality": "0.27.0",
61
- "@shivaedev/test-story": "0.9.0",
60
+ "@shivaedev/quality": "0.27.1",
61
+ "@shivaedev/test-story": "0.10.0",
62
62
  "@trpc/client": "11.19.0",
63
63
  "@trpc/server": "11.19.0",
64
64
  "@types/node": "24.19.2",
@@ -79,7 +79,8 @@
79
79
  "@shivaedev/effect-trpc": "0.8.0",
80
80
  "@trpc/server": "11.19.0",
81
81
  "better-auth": "1.7.7",
82
- "effect": "4.0.4"
82
+ "effect": "4.0.4",
83
+ "pg": "8.23.0"
83
84
  },
84
85
  "peerDependenciesMeta": {
85
86
  "@effect/platform-node": {
@@ -105,6 +106,9 @@
105
106
  },
106
107
  "better-auth": {
107
108
  "optional": true
109
+ },
110
+ "pg": {
111
+ "optional": true
108
112
  }
109
113
  },
110
114
  "engines": {
@@ -1,4 +1,5 @@
1
- import { Context, type Option } from "effect";
1
+ import { Context, type Effect, type Option } from "effect";
2
+ import type { AuthUnavailable, Unauthorized } from "#errors/taxonomy.ts";
2
3
  export class RequestId extends Context.Service<RequestId, string>()("@shivaedev/platform/rpc/RequestId") {}
3
4
  export interface IdentityValue {
4
5
  readonly id: string;
@@ -12,7 +13,12 @@ export interface ProviderAccountValue {
12
13
  export interface SessionUserValue extends IdentityValue {
13
14
  readonly email: string;
14
15
  readonly name: string;
15
- readonly providerAccounts?: readonly ProviderAccountValue[];
16
16
  readonly role?: string | null | undefined;
17
17
  }
18
18
  export class SessionUser extends Context.Service<SessionUser, SessionUserValue>()("@shivaedev/platform/rpc/SessionUser") {}
19
+ export interface SessionUserWithProviderAccountsValue extends SessionUserValue {
20
+ readonly providerAccounts: Effect.Effect<readonly ProviderAccountValue[], AuthUnavailable | Unauthorized>;
21
+ }
22
+ export class SessionUserWithProviderAccounts extends Context.Service<SessionUserWithProviderAccounts, SessionUserWithProviderAccountsValue>()(
23
+ "@shivaedev/platform/rpc/SessionUserWithProviderAccounts",
24
+ ) {}
@@ -1,7 +1,7 @@
1
1
  import { Schema } from "effect";
2
2
  import { RpcMiddleware } from "effect/rpc";
3
3
  import { AuthUnavailable, Forbidden, Unauthorized } from "#errors/taxonomy.ts";
4
- import type { Identity, OptionalIdentity, RequestId, SessionUser } from "./identity.ts";
4
+ import type { Identity, OptionalIdentity, RequestId, SessionUser, SessionUserWithProviderAccounts } from "./identity.ts";
5
5
  export class RequestTracing extends RpcMiddleware.Service<
6
6
  RequestTracing,
7
7
  {
@@ -30,3 +30,9 @@ export class AuthenticatedUser extends RpcMiddleware.Service<
30
30
  >()("@shivaedev/platform/rpc/AuthenticatedUser", {
31
31
  error: Schema.Union([Unauthorized, AuthUnavailable, Forbidden]),
32
32
  }) {}
33
+ export class AuthenticatedUserWithProviderAccounts extends RpcMiddleware.Service<
34
+ AuthenticatedUserWithProviderAccounts,
35
+ { provides: Identity | SessionUser | SessionUserWithProviderAccounts }
36
+ >()("@shivaedev/platform/rpc/AuthenticatedUserWithProviderAccounts", {
37
+ error: Schema.Union([Unauthorized, AuthUnavailable, Forbidden]),
38
+ }) {}
@@ -0,0 +1,9 @@
1
+ import type { Schema } from "effect";
2
+ import { contract } from "@shivaedev/effect-contract/contract.ts";
3
+ import { query } from "@shivaedev/effect-contract/operation.ts";
4
+
5
+ export function publicConfig<T, E>(schema: Schema.Codec<T, E>) {
6
+ return contract("platform.publicConfig", {
7
+ queries: [query("get", { reads: () => [], success: schema })],
8
+ });
9
+ }
@@ -0,0 +1,68 @@
1
+ import { type BetterAuthOptions, betterAuth } from "better-auth";
2
+ import { Config, Effect, Option, Redacted } from "effect";
3
+ import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/http";
4
+ import { Pool, type PoolClient } from "pg";
5
+ import { trustedProxyPeer, trustedProxyRanges } from "#server/rpc-server/local.ts";
6
+
7
+ export const betterAuthMount = Effect.fn("Platform.betterAuthMount")(function* <const TOptions extends BetterAuthOptions>(options: TOptions) {
8
+ const secret = options.secret ?? Redacted.value(yield* Config.Redacted("BETTER_AUTH_SECRET"));
9
+ const publicUrl = yield* Config.URL("PUBLIC_URL").pipe(Config.option);
10
+ const origin = Option.map(publicUrl, (url) => url.origin);
11
+ const trustedProxy = Option.getOrUndefined(yield* Config.String("TRUSTED_PROXY").pipe(Config.option));
12
+ const clientIpHeader = yield* Config.String("AUTH_CLIENT_IP_HEADER").pipe(Config.withDefault("x-forwarded-for"));
13
+ const rateLimitEnabled = yield* Config.Boolean("AUTH_RATE_LIMIT_ENABLED").pipe(Config.withDefault(true));
14
+ const isTrustedProxy = trustedProxyPeer(trustedProxy);
15
+ const trustedProxies = trustedProxyRanges(trustedProxy);
16
+ const auth = betterAuth({
17
+ ...options,
18
+ advanced: {
19
+ useSecureCookies: Option.isSome(publicUrl) && publicUrl.value.protocol === "https:",
20
+ ...options.advanced,
21
+ ipAddress: {
22
+ ...options.advanced?.ipAddress,
23
+ ipAddressHeaders: trustedProxies.length === 0 ? [] : [clientIpHeader],
24
+ trustedProxies,
25
+ },
26
+ },
27
+ "baseURL": options.baseURL ?? Option.getOrElse(origin, () => ({ allowedHosts: ["127.0.0.1:*"], protocol: "http" as const })),
28
+ rateLimit: { ...options.rateLimit, enabled: rateLimitEnabled },
29
+ secret,
30
+ trustedOrigins: options.trustedOrigins ?? [Option.getOrElse(origin, () => "http://127.0.0.1:*")],
31
+ });
32
+ const routes = HttpRouter.use((router) =>
33
+ router.add("*", "/api/auth/*", (request) =>
34
+ Effect.gen(function* () {
35
+ const web = yield* HttpServerRequest.toWeb(request);
36
+ if (!Option.exists(request.remoteAddress, isTrustedProxy)) {
37
+ web.headers.delete("x-forwarded-for");
38
+ web.headers.delete(clientIpHeader);
39
+ }
40
+ return HttpServerResponse.fromWeb(yield* Effect.tryPromise(() => auth.handler(web)));
41
+ }).pipe(Effect.catch(() => Effect.succeed(HttpServerResponse.text("Authentication is temporarily unavailable", { status: 503 })))),
42
+ ),
43
+ );
44
+ return { auth, routes };
45
+ });
46
+
47
+ export const authDatabase = Effect.fn("Platform.authDatabase")(function* (url: Redacted.Redacted<string>) {
48
+ const clients = new Set<PoolClient>();
49
+ const run = Effect.runForkWith(yield* Effect.context<never>());
50
+ return yield* Effect.acquireRelease(
51
+ Effect.sync(() => {
52
+ const pool = new Pool({ connectionString: Redacted.value(url) });
53
+ pool.on("connect", (client) => clients.add(client));
54
+ pool.on("remove", (client) => clients.delete(client));
55
+ pool.on("error", (error) => {
56
+ run(Effect.logDebug({ event: "auth_database_idle_client_failed", message: error.message }));
57
+ });
58
+ return pool;
59
+ }),
60
+ (pool) =>
61
+ Effect.promise(async () => {
62
+ // pg-pool resolves end before its clients finish disconnecting.
63
+ const disconnected = [...clients].map((client) => new Promise<void>((resolve) => client.once("end", resolve)));
64
+ await pool.end();
65
+ await Promise.all(disconnected);
66
+ }),
67
+ );
68
+ });
@@ -0,0 +1,21 @@
1
+ import { testUtils } from "better-auth/plugins";
2
+
3
+ export function authTestUtils(options?: Parameters<typeof testUtils>[0]) {
4
+ const plugin = testUtils(options);
5
+ return {
6
+ ...plugin,
7
+ init(context: Parameters<typeof plugin.init>[0]) {
8
+ const result = plugin.init(context);
9
+ // Remove this wrapper once Better Auth's testUtils omits undefined options.
10
+ return result.options === undefined ? { context: result.context } : { context: result.context, options: result.options };
11
+ },
12
+ };
13
+ }
14
+
15
+ type TestContext = ReturnType<ReturnType<typeof authTestUtils>["init"]>["context"];
16
+
17
+ export async function signedInUser(auth: { readonly $context: Promise<TestContext> }, fields: Parameters<TestContext["test"]["createUser"]>[0]) {
18
+ const { test } = await auth.$context;
19
+ const user = await test.saveUser(test.createUser(fields));
20
+ return test.login({ userId: user.id });
21
+ }
@@ -3,12 +3,13 @@ import { Config, Effect, Layer, type Redacted, Schedule } from "effect";
3
3
  import * as Reactivity from "effect/reactivity/Reactivity";
4
4
  import { makeLiveServer } from "@shivaedev/effect-contract/makeLiveServer.ts";
5
5
  import { assertPostgresMigrations } from "@shivaedev/effect-sql/assertPostgresMigrations.ts";
6
+ import type { SqlNameTransforms } from "@shivaedev/effect-sql/clientOptions.ts";
6
7
  import { migratePostgres } from "@shivaedev/effect-sql/migrations.ts";
7
8
  import { type PostgresChangesOptions, postgresChanges } from "@shivaedev/effect-sql/postgresChanges.ts";
8
9
  import type { AppChanges, AppDatabaseOptions } from "#server/appHost.ts";
9
10
  import { databaseAddress } from "./databaseAddress.ts";
10
11
 
11
- export interface DatabaseConfig {
12
+ export interface DatabaseConfig extends SqlNameTransforms {
12
13
  readonly applicationName?: string;
13
14
  readonly changes?: Omit<PostgresChangesOptions, "client" | "resync">;
14
15
  readonly databaseUrl?: Redacted.Redacted<string>;
@@ -20,6 +21,8 @@ export function databaseLayer<R>(options: AppDatabaseOptions<R>, changesService:
20
21
  Effect.gen(function* () {
21
22
  const url = options.config?.databaseUrl ?? (yield* Config.Redacted("DATABASE_URL"));
22
23
  return PgClient.layer({
24
+ transformQueryNames: options.config?.transformQueryNames,
25
+ transformResultNames: options.config?.transformResultNames,
23
26
  url,
24
27
  ...databaseAddress(url),
25
28
  ...(options.config?.maxConnections === undefined ? {} : { maxConnections: options.config.maxConnections }),
@@ -1,13 +1,13 @@
1
1
  import { Effect, Option, Predicate } from "effect";
2
2
  import type { Headers } from "effect/http";
3
- import { AuthUnavailable } from "#errors/taxonomy.ts";
3
+ import { AuthUnavailable, Unauthorized } from "#errors/taxonomy.ts";
4
4
  import type { ProviderAccountValue } from "#rpc/identity.ts";
5
5
  import { redact } from "#server/rpc-server/redact.ts";
6
6
  import type { SessionProvider, SessionShape } from "#server/rpc-server/session.ts";
7
7
  export type GetSession<TSession extends SessionShape> = (headers: globalThis.Headers) => Promise<TSession | null>;
8
8
  export type GetProviderAccounts = (headers: globalThis.Headers) => Promise<readonly ProviderAccountValue[]>;
9
9
  export type SessionWithProviderAccounts<TSession extends SessionShape> = TSession & {
10
- readonly user: TSession["user"] & { readonly providerAccounts: readonly ProviderAccountValue[] };
10
+ readonly user: TSession["user"] & { readonly providerAccounts: Effect.Effect<readonly ProviderAccountValue[], AuthUnavailable | Unauthorized> };
11
11
  };
12
12
  function unavailable(cause: unknown) {
13
13
  return Effect.andThen(
@@ -22,27 +22,23 @@ export function betterAuthSessions<TSession extends SessionShape>(
22
22
  ): SessionProvider<SessionWithProviderAccounts<TSession>>;
23
23
  export function betterAuthSessions<TSession extends SessionShape>(getSession: GetSession<TSession>, getProviderAccounts?: GetProviderAccounts) {
24
24
  const betterAuthSession = Effect.fn("PlatformRpc.betterAuthSession")(function* (headers: Headers.Headers) {
25
- const session = yield* Effect.tryPromise(async () => {
26
- const transport = new globalThis.Headers(headers);
27
- const resolved = await getSession(transport);
28
- if (resolved === null || getProviderAccounts === undefined) {
29
- return resolved;
30
- }
31
- const accounts = await getProviderAccounts(transport).catch((cause: unknown) => {
32
- if (Predicate.hasProperty(cause, "statusCode") && cause.statusCode === 401) {
33
- return null;
34
- }
35
- throw cause;
36
- });
37
- if (accounts === null) {
38
- return null;
39
- }
40
- return {
41
- ...resolved,
42
- user: { ...resolved.user, providerAccounts: accounts },
43
- };
44
- }).pipe(Effect.catch((error) => unavailable(error.cause)));
45
- return Option.fromNullishOr(session);
25
+ const transport = new globalThis.Headers(headers);
26
+ const session = yield* Effect.tryPromise(() => getSession(transport)).pipe(Effect.catch((error) => unavailable(error.cause)));
27
+ if (session === null || getProviderAccounts === undefined) {
28
+ return Option.fromNullishOr(session);
29
+ }
30
+ const providerAccounts = Effect.tryPromise({
31
+ catch: (cause) => cause,
32
+ try: () => getProviderAccounts(transport),
33
+ }).pipe(
34
+ Effect.catch(
35
+ (cause): Effect.Effect<never, AuthUnavailable | Unauthorized> =>
36
+ Predicate.hasProperty(cause, "statusCode") && cause.statusCode === 401
37
+ ? Effect.fail(new Unauthorized({ message: "Authentication required" }))
38
+ : unavailable(cause),
39
+ ),
40
+ );
41
+ return Option.some({ ...session, user: { ...session.user, providerAccounts } });
46
42
  });
47
43
  return { get: betterAuthSession };
48
44
  }
@@ -0,0 +1,11 @@
1
+ import { Config, type ConfigProvider, Effect } from "effect";
2
+ import type { publicConfig } from "#rpc/publicConfig.ts";
3
+
4
+ export function publicConfigLayer<T, E>(declaration: ReturnType<typeof publicConfig<T, E>>, path?: string | ConfigProvider.Path) {
5
+ return declaration.toLayer(
6
+ Effect.gen(function* () {
7
+ const value = yield* Config.schema(declaration.declaration.queries[0].success, path);
8
+ return declaration.of({ "platform.publicConfig.get": () => Effect.succeed(value) });
9
+ }),
10
+ );
11
+ }
@@ -1,8 +1,15 @@
1
1
  import { Effect, Layer, Option } from "effect";
2
2
  import type { Headers } from "effect/http";
3
3
  import { type AuthUnavailable, Forbidden, Unauthorized } from "#errors/taxonomy.ts";
4
- import { Identity, OptionalIdentity, SessionUser, type SessionUserValue } from "#rpc/identity.ts";
5
- import { Authenticated, AuthenticatedUser, MaybeAuthenticated } from "#rpc/middleware.ts";
4
+ import {
5
+ Identity,
6
+ OptionalIdentity,
7
+ SessionUser,
8
+ type SessionUserValue,
9
+ SessionUserWithProviderAccounts,
10
+ type SessionUserWithProviderAccountsValue,
11
+ } from "#rpc/identity.ts";
12
+ import { Authenticated, AuthenticatedUser, AuthenticatedUserWithProviderAccounts, MaybeAuthenticated } from "#rpc/middleware.ts";
6
13
  import { type OriginPolicy, originRequest } from "./origin.ts";
7
14
  import { transportHeaders } from "./transportHeaders.ts";
8
15
  export interface SessionShape {
@@ -67,7 +74,7 @@ export function withSessionUser<TSession extends UserSessionShape>(policy: Sessi
67
74
  if (Option.isNone(session)) {
68
75
  return yield* new Unauthorized({ message: "Authentication required" });
69
76
  }
70
- const { name, email, role, providerAccounts } = session.value.user;
77
+ const { name, email, role } = session.value.user;
71
78
  const id = yield* identified(session.value.user.id);
72
79
  return yield* effect.pipe(
73
80
  Effect.provideService(Identity, { id }),
@@ -76,9 +83,6 @@ export function withSessionUser<TSession extends UserSessionShape>(policy: Sessi
76
83
  id,
77
84
  name,
78
85
  ...(role === undefined ? {} : { role }),
79
- ...(providerAccounts === undefined
80
- ? {}
81
- : { providerAccounts: providerAccounts.map(({ accountId, providerId }) => ({ accountId, providerId })) }),
82
86
  }),
83
87
  Effect.annotateLogs({ userId: id }),
84
88
  );
@@ -87,3 +91,31 @@ export function withSessionUser<TSession extends UserSessionShape>(policy: Sessi
87
91
  export function authenticatedUserLayer<TSession extends UserSessionShape>(policy: SessionPolicy<TSession>): Layer.Layer<AuthenticatedUser> {
88
92
  return Layer.succeed(AuthenticatedUser, (effect, { headers, rpc }) => effect.pipe(withSessionUser(policy, headers, rpc._tag)));
89
93
  }
94
+
95
+ export interface ProviderAccountsSessionShape extends UserSessionShape {
96
+ readonly user: SessionUserWithProviderAccountsValue;
97
+ }
98
+ export function authenticatedUserWithProviderAccountsLayer<TSession extends ProviderAccountsSessionShape>(
99
+ policy: SessionPolicy<TSession>,
100
+ ): Layer.Layer<AuthenticatedUserWithProviderAccounts> {
101
+ return Layer.succeed(AuthenticatedUserWithProviderAccounts, (effect, { headers, rpc }) =>
102
+ Effect.gen(function* () {
103
+ const session = yield* resolveSession(policy, headers, rpc._tag);
104
+ if (Option.isNone(session)) {
105
+ return yield* new Unauthorized({ message: "Authentication required" });
106
+ }
107
+ const { id, name, email, role, providerAccounts } = session.value.user;
108
+ const accounts = yield* Effect.cached(
109
+ Effect.map(providerAccounts, (values) => values.map(({ accountId, providerId }) => ({ accountId, providerId }))),
110
+ );
111
+ const user = { email, id, name, ...(role === undefined ? {} : { role }) };
112
+ yield* identified(id);
113
+ return yield* effect.pipe(
114
+ Effect.provideService(Identity, { id }),
115
+ Effect.provideService(SessionUser, user),
116
+ Effect.provideService(SessionUserWithProviderAccounts, { ...user, providerAccounts: accounts }),
117
+ Effect.annotateLogs({ userId: id }),
118
+ );
119
+ }),
120
+ );
121
+ }