@shivaedev/server 0.9.3 → 0.11.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 (77) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +24 -19
  3. package/dist/appDatabase.d.ts +14 -0
  4. package/dist/appDatabase.d.ts.map +1 -0
  5. package/dist/{databaseLayer.js → appDatabase.js} +6 -6
  6. package/dist/appDatabase.js.map +1 -0
  7. package/dist/appHost.d.ts +1 -14
  8. package/dist/appHost.d.ts.map +1 -1
  9. package/dist/appHost.js +5 -10
  10. package/dist/appHost.js.map +1 -1
  11. package/dist/appHostHttp.d.ts +29 -29
  12. package/dist/appHostHttp.d.ts.map +1 -1
  13. package/dist/appHostHttp.js +7 -7
  14. package/dist/appHostHttp.js.map +1 -1
  15. package/dist/bearerSocketRpc.d.ts +5 -0
  16. package/dist/bearerSocketRpc.d.ts.map +1 -0
  17. package/dist/bearerSocketRpc.js +69 -0
  18. package/dist/bearerSocketRpc.js.map +1 -0
  19. package/dist/hostChanges.d.ts +2 -3
  20. package/dist/hostChanges.d.ts.map +1 -1
  21. package/dist/hostChanges.js +9 -14
  22. package/dist/hostChanges.js.map +1 -1
  23. package/dist/hostRpcRoutes.d.ts +2 -3
  24. package/dist/hostRpcRoutes.d.ts.map +1 -1
  25. package/dist/hostRpcRoutes.js +4 -2
  26. package/dist/hostRpcRoutes.js.map +1 -1
  27. package/dist/otlpHttpClient.js +2 -2
  28. package/dist/otlpHttpClient.js.map +1 -1
  29. package/dist/redactingDiagnostics.d.ts +0 -2
  30. package/dist/redactingDiagnostics.d.ts.map +1 -1
  31. package/dist/redactingDiagnostics.js +1 -4
  32. package/dist/redactingDiagnostics.js.map +1 -1
  33. package/dist/redactingTracer.d.ts.map +1 -1
  34. package/dist/redactingTracer.js +6 -5
  35. package/dist/redactingTracer.js.map +1 -1
  36. package/dist/safeOtlpSerialization.d.ts +0 -2
  37. package/dist/safeOtlpSerialization.d.ts.map +1 -1
  38. package/dist/safeOtlpSerialization.js +5 -12
  39. package/dist/safeOtlpSerialization.js.map +1 -1
  40. package/dist/setupDatabases.d.ts +1 -1
  41. package/dist/setupDatabases.d.ts.map +1 -1
  42. package/dist/setupDatabases.js +1 -1
  43. package/dist/setupDatabases.js.map +1 -1
  44. package/dist/socketRpc.d.ts.map +1 -1
  45. package/dist/socketRpc.js +6 -4
  46. package/dist/socketRpc.js.map +1 -1
  47. package/package.json +11 -17
  48. package/src/{databaseLayer.ts → appDatabase.ts} +6 -6
  49. package/src/appHost.ts +5 -11
  50. package/src/appHostHttp.ts +8 -11
  51. package/src/bearerSocketRpc.ts +80 -0
  52. package/src/hostChanges.ts +12 -22
  53. package/src/hostRpcRoutes.ts +4 -6
  54. package/src/otlpHttpClient.ts +2 -2
  55. package/src/redactingDiagnostics.ts +1 -5
  56. package/src/redactingTracer.ts +7 -5
  57. package/src/safeOtlpSerialization.ts +5 -12
  58. package/src/setupDatabases.ts +1 -1
  59. package/src/socketRpc.ts +6 -6
  60. package/dist/databaseLayer.d.ts +0 -14
  61. package/dist/databaseLayer.d.ts.map +0 -1
  62. package/dist/databaseLayer.js.map +0 -1
  63. package/dist/redactOtlpUrl.d.ts +0 -2
  64. package/dist/redactOtlpUrl.d.ts.map +0 -1
  65. package/dist/redactOtlpUrl.js +0 -41
  66. package/dist/redactOtlpUrl.js.map +0 -1
  67. package/dist/schemaSensitiveAst.d.ts +0 -7
  68. package/dist/schemaSensitiveAst.d.ts.map +0 -1
  69. package/dist/schemaSensitiveAst.js +0 -102
  70. package/dist/schemaSensitiveAst.js.map +0 -1
  71. package/dist/schemaSensitiveKeys.d.ts +0 -6
  72. package/dist/schemaSensitiveKeys.d.ts.map +0 -1
  73. package/dist/schemaSensitiveKeys.js +0 -47
  74. package/dist/schemaSensitiveKeys.js.map +0 -1
  75. package/src/redactOtlpUrl.ts +0 -48
  76. package/src/schemaSensitiveAst.ts +0 -106
  77. package/src/schemaSensitiveKeys.ts +0 -49
package/src/appHost.ts CHANGED
@@ -1,25 +1,19 @@
1
1
  import * as NodeCrypto from "@effect/platform-node/NodeCrypto";
2
- import { Context, type Effect, Layer } from "effect";
2
+ import { Layer } from "effect";
3
3
  import type { Rpc } from "effect/rpc";
4
- import type { makeLiveServer } from "@shivaedev/contract/makeLiveServer.ts";
5
4
  import type { SessionPolicy, SessionShape } from "@shivaedev/identity/server/session.ts";
6
5
  import type { AppHostFactory } from "#AppHostFactory.ts";
7
6
  import type { AppHostInput, HostPreflight } from "#AppHostInput.ts";
7
+ import { appDatabase, type DatabaseConfig } from "#appDatabase.ts";
8
8
  import { appHostHttp, deferredHost, migratedHost } from "#appHostHttp.ts";
9
- import { type DatabaseConfig, databaseLayer } from "#databaseLayer.ts";
10
9
  import type { HostCoreOptions, HostPolicy, HostRouteRequirements, HostRoutes } from "#hostOptions.ts";
11
10
  import type { MigrationOptions } from "#MigrationOptions.ts";
12
11
 
13
- export class AppChanges extends Context.Service<AppChanges, Effect.Success<typeof makeLiveServer>>()("@shivaedev/server/AppChanges") {}
14
12
  export interface AppDatabaseOptions<R = never, E = never> {
15
13
  readonly config?: DatabaseConfig;
16
14
  readonly migrations: MigrationOptions<R, E>;
17
15
  }
18
16
 
19
- export function appDatabase<R, E = never>(options: AppDatabaseOptions<R, E>) {
20
- return databaseLayer(options, AppChanges);
21
- }
22
-
23
17
  export type AppHostOptions<
24
18
  TRpcs extends Rpc.Any,
25
19
  THandlers,
@@ -125,14 +119,14 @@ export const appHost: AppHostFactory = <
125
119
  >,
126
120
  ) => {
127
121
  if ("application" in options) {
128
- return deferredHost(options.application, appDatabase(options), AppChanges).pipe(
122
+ return deferredHost(options.application, appDatabase(options)).pipe(
129
123
  Layer.provideMerge(options.preflight ?? Layer.empty),
130
124
  Layer.provide(NodeCrypto.layer),
131
125
  );
132
126
  }
133
127
  return options.migrations === undefined
134
- ? appHostHttp(options, AppChanges).pipe(Layer.provideMerge(options.preflight ?? Layer.empty), Layer.provide(NodeCrypto.layer))
135
- : migratedHost({ ...options, migrations: options.migrations }, appDatabase({ ...options, migrations: options.migrations }), AppChanges).pipe(
128
+ ? appHostHttp(options).pipe(Layer.provideMerge(options.preflight ?? Layer.empty), Layer.provide(NodeCrypto.layer))
129
+ : migratedHost({ ...options, migrations: options.migrations }, appDatabase({ ...options, migrations: options.migrations })).pipe(
136
130
  Layer.provideMerge(options.preflight ?? Layer.empty),
137
131
  Layer.provide(NodeCrypto.layer),
138
132
  );
@@ -2,9 +2,10 @@ import * as NodeHttpServer from "@effect/platform-node/NodeHttpServer";
2
2
  import { Effect, Layer } from "effect";
3
3
  import { HttpRouter, HttpServer, HttpStaticServer } from "effect/http";
4
4
  import type { Rpc } from "effect/rpc";
5
+ import { schemaSensitiveKeys } from "@shivaedev/errors/schemaSensitiveKeys.ts";
5
6
  import type { SessionShape } from "@shivaedev/identity/server/session.ts";
6
- import type { AppChanges, AppHttpHostOptions } from "#appHost.ts";
7
- import type { databaseLayer } from "#databaseLayer.ts";
7
+ import type { appDatabase } from "#appDatabase.ts";
8
+ import type { AppHttpHostOptions } from "#appHost.ts";
8
9
  import { healthRoute } from "#healthRoute.ts";
9
10
  import { hostApplicationRoutes } from "#hostApplicationRoutes.ts";
10
11
  import type { HostOptions, HostPolicy, HostRouteRequirements } from "#hostOptions.ts";
@@ -16,7 +17,6 @@ import { nodeHttpServer } from "#nodeHttpServer.ts";
16
17
  import { otlpTracing } from "#otlpTracing.ts";
17
18
  import { RedactionPolicy } from "#RedactionPolicy.ts";
18
19
  import { redactingDiagnostics } from "#redactingDiagnostics.ts";
19
- import { schemaSensitiveKeys } from "#schemaSensitiveKeys.ts";
20
20
 
21
21
  export function appHostHttp<
22
22
  TRpcs extends Rpc.Any,
@@ -42,14 +42,13 @@ export function appHostHttp<
42
42
  TRouteRequirements
43
43
  > &
44
44
  HostPolicy<TSession>,
45
- changesService: typeof AppChanges,
46
45
  ) {
47
46
  const sensitive = schemaSensitiveKeys(options.group, options.config?.sensitiveKeys);
48
47
  return Layer.unwrap(
49
48
  Effect.gen(function* () {
50
49
  const transport = yield* hostTransport(options);
51
50
  const { bodySize, host, trustedProxy, nativeOrigins } = transport;
52
- const routes = hostRpcRoutes(options, changesService, transport, sensitive);
51
+ const routes = hostRpcRoutes(options, transport, sensitive);
53
52
  const assets =
54
53
  options.assets === undefined
55
54
  ? Layer.empty
@@ -98,11 +97,10 @@ export function migratedHost<
98
97
  HostPolicy<TSession> & {
99
98
  readonly migrations: MigrationOptions<TMigrations, TMigrationError>;
100
99
  },
101
- database: ReturnType<typeof databaseLayer<TMigrations, TMigrationError>>,
102
- changesService: typeof AppChanges,
100
+ database: ReturnType<typeof appDatabase<TMigrations, TMigrationError>>,
103
101
  ) {
104
102
  const services = Layer.mergeAll(options.services ?? Layer.empty);
105
- return appHostHttp({ ...options, services: services.pipe(Layer.provideMerge(database)) }, changesService);
103
+ return appHostHttp({ ...options, services: services.pipe(Layer.provideMerge(database)) });
106
104
  }
107
105
 
108
106
  export function deferredHost<
@@ -140,8 +138,7 @@ export function deferredHost<
140
138
  TApplicationError,
141
139
  TApplicationRequirements
142
140
  >,
143
- database: ReturnType<typeof databaseLayer<TMigrations, TMigrationError>>,
144
- changesService: typeof AppChanges,
141
+ database: ReturnType<typeof appDatabase<TMigrations, TMigrationError>>,
145
142
  ) {
146
- return Layer.unwrap(Effect.map(application, (options) => appHostHttp(options, changesService))).pipe(Layer.provideMerge(database));
143
+ return Layer.unwrap(Effect.map(application, (options) => appHostHttp(options))).pipe(Layer.provideMerge(database));
147
144
  }
@@ -0,0 +1,80 @@
1
+ import { Effect, Option, Schema, type Scope } from "effect";
2
+ import { Headers, HttpServerRequest, HttpServerResponse } from "effect/http";
3
+ import * as Socket from "effect/socket/Socket";
4
+ import { SocketAuthentication } from "@shivaedev/contract/socketAuthentication.ts";
5
+ import { Unauthorized } from "@shivaedev/errors/taxonomy.ts";
6
+ import { recheckSession } from "@shivaedev/identity/server/recheckSession.ts";
7
+ import { resolveSession, type SessionPolicy, type SessionShape } from "@shivaedev/identity/server/session.ts";
8
+ import { makeSocketSession, SocketSession } from "@shivaedev/identity/server/socketSession.ts";
9
+
10
+ export const bearerSocketRpc = Effect.fnUntraced(function* <TSession extends SessionShape>(
11
+ handler: Effect.Effect<HttpServerResponse.HttpServerResponse, never, HttpServerRequest.HttpServerRequest | Scope.Scope>,
12
+ policy: SessionPolicy<TSession>,
13
+ ) {
14
+ const request = yield* HttpServerRequest.HttpServerRequest;
15
+ const socket = yield* Effect.orDie(request.upgrade);
16
+ const reader = yield* Effect.orDie(socket.reader);
17
+ const writer = yield* socket.writer;
18
+ function close(code: number, reason: string) {
19
+ return writer.write(new Socket.CloseEvent(code, reason)).pipe(Effect.as(HttpServerResponse.empty()));
20
+ }
21
+ function unauthorized() {
22
+ return close(1008, "Authentication required");
23
+ }
24
+ function unavailable() {
25
+ return close(1011, "Authentication unavailable");
26
+ }
27
+ return yield* Effect.gen(function* () {
28
+ const frames = yield* reader.pull.pipe(Effect.timeout("5 seconds"));
29
+ const frame = frames[0];
30
+ const auth =
31
+ typeof frame === "string" && frame.length <= 8192
32
+ ? Schema.decodeUnknownOption(Schema.fromJsonString(SocketAuthentication))(frame)
33
+ : Option.none();
34
+ if (Option.isNone(auth)) {
35
+ return yield* new Unauthorized({ message: "Authentication required" });
36
+ }
37
+ const authenticated = request.modify({ headers: Headers.set(request.headers, "authorization", `Bearer ${auth.value.token}`) });
38
+ let buffered = frames.slice(1);
39
+ const authenticatedSocket: Socket.Socket = {
40
+ ...socket,
41
+ reader: Effect.succeed({
42
+ ...reader,
43
+ pull: Effect.suspend(() => {
44
+ if (buffered.length === 0) {
45
+ return reader.pull;
46
+ }
47
+ const [first, ...rest] = buffered;
48
+ buffered = [];
49
+ return first === undefined ? reader.pull : Effect.succeed([first, ...rest] as const);
50
+ }),
51
+ }),
52
+ };
53
+ const transport = new Proxy(authenticated, {
54
+ get: (target, key, receiver) => (key === "upgrade" ? Effect.succeed(authenticatedSocket) : Reflect.get(target, key, receiver)),
55
+ });
56
+ return yield* Effect.gen(function* () {
57
+ const initial = yield* resolveSession(policy, Headers.empty, "$connect");
58
+ if (Option.isNone(initial)) {
59
+ return yield* new Unauthorized({ message: "Authentication required" });
60
+ }
61
+ const session = yield* makeSocketSession(policy.streamRevalidationInterval ?? "30 seconds");
62
+ const check = recheckSession(policy, Headers.empty, "$connect").pipe(
63
+ Effect.flatMap((current) =>
64
+ Option.isSome(current) && current.value.user.id === initial.value.user.id
65
+ ? Effect.void
66
+ : Effect.fail(new Unauthorized({ message: "Authentication required" })),
67
+ ),
68
+ );
69
+ return yield* Effect.raceFirst(handler, session.monitor(check)).pipe(Effect.provideService(SocketSession, session));
70
+ }).pipe(Effect.provideService(HttpServerRequest.HttpServerRequest, transport));
71
+ }).pipe(
72
+ Effect.catchTags({
73
+ AuthUnavailable: unavailable,
74
+ Forbidden: unauthorized,
75
+ TimeoutError: unauthorized,
76
+ Unauthorized: unauthorized,
77
+ }),
78
+ Effect.catchTag("SocketError", () => Effect.succeed(HttpServerResponse.empty())),
79
+ );
80
+ });
@@ -1,44 +1,43 @@
1
1
  import { Context, Effect, Layer, Option, Stream } from "effect";
2
2
  import { Headers } from "effect/http";
3
- import type { Rpc, RpcGroup } from "effect/rpc";
3
+ import { Rpc, type RpcGroup } from "effect/rpc";
4
+ import { LiveServer } from "@shivaedev/contract/LiveServer.ts";
4
5
  import { CurrentViewer, type Viewer } from "@shivaedev/contract/readPolicy.ts";
5
6
  import type { QueryReference } from "@shivaedev/contract/serverMetadata.ts";
6
7
  import { Unauthorized } from "@shivaedev/errors/taxonomy.ts";
7
8
  import { recheckSession } from "@shivaedev/identity/server/recheckSession.ts";
9
+ import { revalidateStream } from "@shivaedev/identity/server/revalidateStream.ts";
8
10
  import type { SessionPolicy, SessionShape } from "@shivaedev/identity/server/session.ts";
9
11
  import { resolveChanges } from "@shivaedev/identity/server/sessionKeys.ts";
10
- import { revalidateSession } from "@shivaedev/identity/server/socketSession.ts";
11
- import type { AppChanges } from "#appHost.ts";
12
12
  import { rerunQuery } from "#rerunQuery.ts";
13
13
 
14
- export function hostChanges<R extends Rpc.Any, TSession extends SessionShape>(
15
- group: RpcGroup.RpcGroup<R>,
16
- changesService: typeof AppChanges,
17
- sessions?: SessionPolicy<TSession>,
18
- ) {
14
+ export function hostChanges<R extends Rpc.Any, TSession extends SessionShape>(group: RpcGroup.RpcGroup<R>, sessions?: SessionPolicy<TSession>) {
19
15
  return Layer.effectContext(
20
16
  Effect.gen(function* () {
21
- const changes = yield* Effect.serviceOption(changesService);
17
+ const changes = yield* Effect.serviceOption(LiveServer);
22
18
  const services = yield* Effect.context<never>();
23
19
  const handlers = new Map<string, unknown>();
24
- function subscribe(rpc: Rpc.Any, queries: readonly QueryReference[], options: Parameters<Rpc.Handler<string>["handler"]>[1]) {
20
+ function subscribe(rpc: Rpc.AnyWithProps, queries: readonly QueryReference[], options: Parameters<Rpc.Handler<string>["handler"]>[1]) {
25
21
  return Stream.unwrap(
26
22
  Effect.gen(function* () {
27
23
  const { subscription, context } = yield* resolveChanges(rpc, queries);
28
24
  const viewer = yield* CurrentViewer;
29
25
  const authorized = authorizeSession(sessions, rpc._tag, viewer, subscription.authorized);
30
26
  const stream = Option.isSome(changes)
31
- ? changes.value.subscribe({ ...subscription, authorized }, context, rerunQuery(group, options))
27
+ ? Stream.unwrap(changes.value.subscribe({ ...subscription, authorized }, context, rerunQuery(group, options)))
32
28
  : Stream.concat(Stream.succeed({ _tag: "Resync" } as const), Stream.never);
33
29
  if (sessions === undefined || Option.isNone(viewer)) {
34
30
  return stream;
35
31
  }
36
- return Stream.interruptWhen(stream, sessionRevoked(sessions, rpc._tag, viewer.value.id));
32
+ const revalidation = Effect.never.pipe(
33
+ revalidateStream(sessions, rpc, viewer.value.id, recheckSession(sessions, Headers.empty, rpc._tag)),
34
+ );
35
+ return Stream.interruptWhen(stream, revalidation);
37
36
  }),
38
37
  );
39
38
  }
40
39
  for (const rpc of group.requests.values()) {
41
- if (!rpc._tag.endsWith(".$changes")) {
40
+ if (!(Rpc.isRpc(rpc) && rpc._tag.endsWith(".$changes"))) {
42
41
  continue;
43
42
  }
44
43
  const provided = services.mapUnsafe.get(rpc.key);
@@ -75,12 +74,3 @@ function authorizeSession<TSession extends SessionShape, E, R>(
75
74
  ),
76
75
  );
77
76
  }
78
-
79
- function sessionRevoked<TSession extends SessionShape>(sessions: SessionPolicy<TSession>, tag: string, id: string) {
80
- return Effect.gen(function* () {
81
- const current = yield* recheckSession(sessions, Headers.empty, tag).pipe(Effect.catchTag("AuthUnavailable", () => Effect.succeed(undefined)));
82
- if (current !== undefined && (Option.isNone(current) || current.value.user.id !== id)) {
83
- return yield* new Unauthorized({ message: "Authentication required" });
84
- }
85
- }).pipe((check) => revalidateSession(check, sessions.streamRevalidationInterval ?? "30 seconds"));
86
- }
@@ -2,10 +2,11 @@ import { ByteSize, Effect, Layer } from "effect";
2
2
  import { HttpEffect, HttpIncomingMessage, HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/http";
3
3
  import * as HttpStatus from "effect/http/HttpStatus";
4
4
  import { type Rpc, type RpcGroup, RpcSerialization } from "effect/rpc";
5
+ import { validateReadPolicies } from "@shivaedev/contract/validateReadPolicies.ts";
6
+ import type { schemaSensitiveKeys } from "@shivaedev/errors/schemaSensitiveKeys.ts";
5
7
  import type { Authenticated, MaybeAuthenticated, RequestTracing } from "@shivaedev/identity/middleware.ts";
6
8
  import { localRpcGuard } from "@shivaedev/identity/server/local.ts";
7
9
  import { authenticatedLayer, maybeAuthenticatedLayer, type SessionShape } from "@shivaedev/identity/server/session.ts";
8
- import type { AppChanges } from "#appHost.ts";
9
10
  import { boundedRpcRequest } from "#boundedRpcRequest.ts";
10
11
  import { hostChanges } from "#hostChanges.ts";
11
12
  import type { HostPolicy } from "#hostOptions.ts";
@@ -13,7 +14,6 @@ import { hostRpc, rpcCacheControl } from "#hostRpc.ts";
13
14
  import type { hostTransport } from "#hostTransport.ts";
14
15
  import { redactingRpcSerialization } from "#redactingRpcSerialization.ts";
15
16
  import { rpcRequestTracing } from "#rpcRequestTracing.ts";
16
- import type { schemaSensitiveKeys } from "#schemaSensitiveKeys.ts";
17
17
  import { socketRpc } from "#socketRpc.ts";
18
18
 
19
19
  export function hostRpcRoutes<TRpcs extends Rpc.Any, THandlers, TError, TRequirements, TSession extends SessionShape>(
@@ -22,7 +22,6 @@ export function hostRpcRoutes<TRpcs extends Rpc.Any, THandlers, TError, TRequire
22
22
  readonly handlers: Layer.Layer<THandlers, TError, TRequirements>;
23
23
  readonly rpcPath?: HttpRouter.PathInput;
24
24
  } & HostPolicy<TSession>,
25
- changesService: typeof AppChanges,
26
25
  { bodySize, trustedProxy, nativeOrigins }: Effect.Success<ReturnType<typeof hostTransport>>,
27
26
  sensitive: ReturnType<typeof schemaSensitiveKeys>,
28
27
  ) {
@@ -32,6 +31,7 @@ export function hostRpcRoutes<TRpcs extends Rpc.Any, THandlers, TError, TRequire
32
31
  : Layer.mergeAll(authenticatedLayer(options.sessions), maybeAuthenticatedLayer(options.sessions), rpcRequestTracing(sensitive));
33
32
  return HttpRouter.use((router) =>
34
33
  Effect.gen(function* () {
34
+ yield* validateReadPolicies(options.group);
35
35
  const wire = redactingRpcSerialization(yield* RpcSerialization.RpcSerialization, sensitive, sensitive.maskFailure, sensitive.forRpc);
36
36
  const httpGroup = options.group.omit(...[...options.group.requests.keys()].filter((tag) => tag.endsWith(".$changes")));
37
37
  const handler = yield* hostRpc(httpGroup).pipe(Effect.provideService(RpcSerialization.RpcSerialization, wire));
@@ -62,9 +62,7 @@ export function hostRpcRoutes<TRpcs extends Rpc.Any, THandlers, TError, TRequire
62
62
  Layer.provide(
63
63
  Layer.merge(
64
64
  middleware,
65
- hostChanges(options.group, changesService, options.policy === "loopback" ? undefined : options.sessions).pipe(
66
- Layer.provideMerge(options.handlers),
67
- ),
65
+ hostChanges(options.group, options.policy === "loopback" ? undefined : options.sessions).pipe(Layer.provideMerge(options.handlers)),
68
66
  ),
69
67
  ),
70
68
  Layer.provide(RpcSerialization.layerNdjson),
@@ -1,8 +1,8 @@
1
1
  import { Effect, Layer } from "effect";
2
2
  import { FetchHttpClient, HttpClient, HttpClientError, type HttpClientRequest } from "effect/http";
3
3
  import * as HttpStatus from "effect/http/HttpStatus";
4
+ import { redactText } from "@shivaedev/errors/sensitive.ts";
4
5
  import { RedactionPolicy } from "#RedactionPolicy.ts";
5
- import { redactOtlpText } from "#safeOtlpSerialization.ts";
6
6
 
7
7
  function timeoutError(request: HttpClientRequest.HttpClientRequest) {
8
8
  return new HttpClientError.HttpClientError({
@@ -44,7 +44,7 @@ export function otlpHttpClient(timeout = 10_000) {
44
44
  return warnOnce(
45
45
  response.text.pipe(
46
46
  Effect.orElseSucceed(() => "Unable to read collector response"),
47
- Effect.map((body) => ({ "otlp.response": redactOtlpText(body, "", sensitive), "otlp.status": response.status })),
47
+ Effect.map((body) => ({ "otlp.response": redactText(body, sensitive), "otlp.status": response.status })),
48
48
  ),
49
49
  );
50
50
  }),
@@ -1,12 +1,8 @@
1
1
  import { Context, Effect, ErrorReporter, Layer, Logger, References } from "effect";
2
- import { redact } from "@shivaedev/errors/redact.ts";
2
+ import { redact, redactRecord } from "@shivaedev/errors/redact.ts";
3
3
  import { redactDiagnosticCause, redactingErrorReporter } from "@shivaedev/errors/redactCause.ts";
4
- import type { SensitiveKey } from "@shivaedev/errors/sensitive.ts";
5
4
  import { type HostRedactionPolicy, redactionForRpc } from "#RedactionPolicy.ts";
6
5
 
7
- export function redactRecord(values: Readonly<Record<string, unknown>>, sensitive: SensitiveKey): Record<string, unknown> {
8
- return Object.fromEntries(Object.entries(values).map(([key, value]) => [key, sensitive(key) ? "<redacted>" : redact(value, sensitive)]));
9
- }
10
6
  function requestErrorReporter(reporter: ErrorReporter.ErrorReporter, policy: HostRedactionPolicy): ErrorReporter.ErrorReporter {
11
7
  return {
12
8
  [ErrorReporter.TypeId]: ErrorReporter.TypeId,
@@ -1,9 +1,8 @@
1
1
  import { Effect, Exit, Layer, Option, Tracer } from "effect";
2
- import { redact } from "@shivaedev/errors/redact.ts";
2
+ import { redactRecord } from "@shivaedev/errors/redact.ts";
3
3
  import { redactDiagnosticCause } from "@shivaedev/errors/redactCause.ts";
4
- import { REDACTED, type SensitiveKey } from "@shivaedev/errors/sensitive.ts";
4
+ import type { SensitiveKey } from "@shivaedev/errors/sensitive.ts";
5
5
  import { type HostRedactionPolicy, redactionForRpc } from "#RedactionPolicy.ts";
6
- import { redactRecord } from "#redactingDiagnostics.ts";
7
6
 
8
7
  function redactLinks(values: readonly Tracer.SpanLink[], sensitive: SensitiveKey) {
9
8
  return values.map((link) => ({ ...link, attributes: redactRecord(link.attributes, sensitive) }));
@@ -11,6 +10,9 @@ function redactLinks(values: readonly Tracer.SpanLink[], sensitive: SensitiveKey
11
10
  function redactSpan(span: Tracer.Span, policy: HostRedactionPolicy) {
12
11
  const end = span.end.bind(span);
13
12
  const attribute = span.attribute.bind(span);
13
+ function safeAttribute(key: string, value: unknown) {
14
+ return attribute(key, redactRecord({ [key]: value }, sensitive)[key]);
15
+ }
14
16
  const event = span.event.bind(span);
15
17
  const addLinks = span.addLinks.bind(span);
16
18
  function sensitive(key: string) {
@@ -18,10 +20,10 @@ function redactSpan(span: Tracer.Span, policy: HostRedactionPolicy) {
18
20
  }
19
21
  return Object.assign(span, {
20
22
  addLinks: (values: readonly Tracer.SpanLink[]) => addLinks(redactLinks(values, sensitive)),
21
- attribute: (key: string, value: unknown) => attribute(key, sensitive(key) ? REDACTED : redact(value, sensitive)),
23
+ attribute: safeAttribute,
22
24
  end: (time: bigint, exit: Exit.Exit<unknown, unknown>) => {
23
25
  for (const [key, value] of span.attributes) {
24
- attribute(key, sensitive(key) ? REDACTED : redact(value, sensitive));
26
+ safeAttribute(key, value);
25
27
  }
26
28
  end(time, Exit.isFailure(exit) ? Exit.failCause(redactDiagnosticCause(exit.cause, sensitive)) : exit);
27
29
  },
@@ -1,20 +1,13 @@
1
1
  import { Effect, Layer } from "effect";
2
2
  import type { OtlpResource, OtlpTracer } from "effect/observability";
3
3
  import { OtlpSerialization } from "effect/observability";
4
- import { isSensitiveKey, REDACTED, redactText, type SensitiveKey } from "@shivaedev/errors/sensitive.ts";
4
+ import { REDACTED, redactText, type SensitiveKey } from "@shivaedev/errors/sensitive.ts";
5
5
  import { type HostRedactionPolicy, RedactionPolicy, redactionForRpc } from "#RedactionPolicy.ts";
6
- import { redactOtlpUrl } from "#redactOtlpUrl.ts";
7
6
 
8
- function otlpSensitive(sensitive: SensitiveKey): SensitiveKey {
9
- return (key) => sensitive(key) || ["db.user", "db.user.name", "db.connection_string"].includes(key.toLowerCase());
10
- }
11
- export function redactOtlpText(value: string, key = "", sensitive: SensitiveKey = isSensitiveKey) {
12
- return redactText(redactOtlpUrl(value, key), otlpSensitive(sensitive));
13
- }
14
7
  function attributeValue(value: OtlpResource.AnyValue, key: string, sensitive: SensitiveKey): OtlpResource.AnyValue {
15
8
  return {
16
9
  ...value,
17
- ...(typeof value.stringValue === "string" ? { stringValue: redactOtlpText(value.stringValue, key, sensitive) } : {}),
10
+ ...(typeof value.stringValue === "string" ? { stringValue: redactText(value.stringValue, sensitive, undefined, key) } : {}),
18
11
  ...(value.arrayValue ? { arrayValue: { values: value.arrayValue.values.map((item) => attributeValue(item, key, sensitive)) } } : {}),
19
12
  ...(value.kvlistValue ? { kvlistValue: { values: attributes(value.kvlistValue.values, sensitive) } } : {}),
20
13
  };
@@ -38,7 +31,7 @@ function spanName(span: { readonly name: string; readonly kind: number; readonly
38
31
  }
39
32
 
40
33
  function redactTraces(data: OtlpTracer.TraceData, policy: HostRedactionPolicy): OtlpTracer.TraceData {
41
- const resourceSensitive = otlpSensitive(policy);
34
+ const resourceSensitive = policy;
42
35
  return {
43
36
  ...data,
44
37
  resourceSpans: data.resourceSpans.map((resource) => ({
@@ -48,9 +41,9 @@ function redactTraces(data: OtlpTracer.TraceData, policy: HostRedactionPolicy):
48
41
  ...scope,
49
42
  spans: scope.spans.map((span) => {
50
43
  const method = span.attributes.find(({ key }) => key === "rpc.method")?.value.stringValue;
51
- const sensitive = otlpSensitive(redactionForRpc(policy, method));
44
+ const sensitive = redactionForRpc(policy, method);
52
45
  function text(value: string) {
53
- return redactOtlpText(value, "", sensitive);
46
+ return redactText(value, sensitive);
54
47
  }
55
48
  return {
56
49
  ...span,
@@ -8,5 +8,5 @@ export const setupDatabases = Effect.fn("Platform.setupDatabases")(function* ()
8
8
  "DOCKER_HOST": Config.String("DOCKER_HOST").pipe(Config.withDefault("")),
9
9
  "TEST_DATABASE_URL": Config.String("TEST_DATABASE_URL"),
10
10
  });
11
- yield* Effect.sync(() => localPostgres(config).prepareDatabases([config.DATABASE_URL, config.TEST_DATABASE_URL]));
11
+ yield* localPostgres(config).prepareDatabases([config.DATABASE_URL, config.TEST_DATABASE_URL]);
12
12
  });
package/src/socketRpc.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import { Effect, type Scope } from "effect";
2
2
  import { Headers, HttpServerRequest, HttpServerResponse } from "effect/http";
3
3
  import * as HttpStatus from "effect/http/HttpStatus";
4
+ import { isAuthUnavailable, isForbidden } from "@shivaedev/errors/taxonomy.ts";
4
5
  import { localTransport } from "@shivaedev/identity/server/local.ts";
5
6
  import { resolveSession, type SessionShape } from "@shivaedev/identity/server/session.ts";
6
7
  import { makeSocketSession, SocketSession } from "@shivaedev/identity/server/socketSession.ts";
8
+ import { bearerSocketRpc } from "#bearerSocketRpc.ts";
7
9
  import type { HostPolicy } from "#hostOptions.ts";
8
10
 
9
11
  export function socketRpc<TSession extends SessionShape>(
@@ -18,17 +20,15 @@ export function socketRpc<TSession extends SessionShape>(
18
20
  return HttpServerResponse.text("Local same-origin requests only", { status: HttpStatus.fromLiteral("Forbidden") });
19
21
  }
20
22
  if (policy.policy !== "loopback") {
23
+ if (new URL(request.url, "http://localhost").searchParams.get("auth") === "frame") {
24
+ return yield* bearerSocketRpc(handler, policy.sessions);
25
+ }
21
26
  yield* resolveSession(policy.sessions, Headers.empty, "$connect");
22
27
  const session = yield* makeSocketSession(policy.sessions.streamRevalidationInterval ?? "30 seconds");
23
28
  return yield* Effect.provideService(handler, SocketSession, session);
24
29
  }
25
30
  return yield* handler;
26
- }).pipe(
27
- Effect.catchTags({
28
- AuthUnavailable: authUnavailable,
29
- Forbidden: forbidden,
30
- }),
31
- );
31
+ }).pipe(Effect.catchIf(isAuthUnavailable, authUnavailable), Effect.catchIf(isForbidden, forbidden));
32
32
  }
33
33
 
34
34
  function authUnavailable() {
@@ -1,14 +0,0 @@
1
- import * as PgClient from "@effect/sql-pg/PgClient";
2
- import { Config, Layer, Redacted } from "effect";
3
- import * as Reactivity from "effect/reactivity/Reactivity";
4
- import { Migrator } from "effect/sql";
5
- import { type PostgresChangesOptions } from "@shivaedev/sql/postgresChanges.ts";
6
- import { type PostgresOptions } from "@shivaedev/sql/postgresLayer.ts";
7
- import type { AppChanges, AppDatabaseOptions } from "#appHost.ts";
8
- export interface DatabaseConfig extends PostgresOptions {
9
- readonly changes?: Partial<Omit<PostgresChangesOptions, "client" | "listenerClient" | "connectionSetting" | "resync">>;
10
- readonly databaseUrl?: Redacted.Redacted<string>;
11
- readonly listenDatabaseUrl?: Redacted.Redacted<string>;
12
- }
13
- export declare function databaseLayer<R, E>(options: AppDatabaseOptions<R, E>, changesService: typeof AppChanges): Layer.Layer<AppChanges | PgClient.PgClient | import("@effect/sql-pg/PgPool").PgPool | Reactivity.Reactivity | import("effect/sql/SqlClient").SqlClient, E | Config.ConfigError | Migrator.MigrationError | import("@shivaedev/sql/PostgresListenerError.ts").PostgresListenerError | import("effect/Schema").SchemaError | import("effect/sql/SqlError").SqlError, Exclude<Exclude<R, import("effect/Scope").Scope>, PgClient.PgClient | import("@effect/sql-pg/PgPool").PgPool | import("effect/sql/SqlClient").SqlClient>>;
14
- //# sourceMappingURL=databaseLayer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"databaseLayer.d.ts","sourceRoot":"","sources":["../src/databaseLayer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAoC,KAAK,EAAU,QAAQ,EAAY,MAAM,QAAQ,CAAC;AACrG,OAAO,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAMtC,OAAO,EAAE,KAAK,sBAAsB,EAAmB,MAAM,mCAAmC,CAAC;AACjG,OAAO,EAAE,KAAK,eAAe,EAAiB,MAAM,iCAAiC,CAAC;AAEtF,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAElE,MAAM,WAAW,cAAe,SAAQ,eAAe;IACtD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAAE,QAAQ,GAAG,gBAAgB,GAAG,mBAAmB,GAAG,QAAQ,CAAC,CAAC,CAAC;IACvH,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACjD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;CACvD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,UAAU,ggBAqCvG"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"databaseLayer.js","sourceRoot":"","sources":["../src/databaseLayer.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export declare function redactOtlpUrl(value: string, key?: string): string;
2
- //# sourceMappingURL=redactOtlpUrl.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"redactOtlpUrl.d.ts","sourceRoot":"","sources":["../src/redactOtlpUrl.ts"],"names":[],"mappings":"AA6BA,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAK,GAAG,MAAM,CAkB7D"}
@@ -1,41 +0,0 @@
1
- import { REDACTED } from "@shivaedev/errors/sensitive.ts";
2
- function query(value) {
3
- return value
4
- .split("&")
5
- .map((part) => (part === "" ? part : `${part.split("=", 1)[0]}=${REDACTED}`))
6
- .join("&");
7
- }
8
- function url(value) {
9
- const fragment = value.indexOf("#");
10
- const target = fragment === -1 ? value : value.slice(0, fragment);
11
- const separator = target.indexOf("?");
12
- return ((separator === -1 ? target : `${target.slice(0, separator + 1)}${query(target.slice(separator + 1))}`).replaceAll(/(?<authority>(?:\b[a-z][a-z0-9+.-]*:)?\/\/)[^/?#]*@/giu, `$<authority>${REDACTED}@`) + (fragment === -1 ? "" : `#${REDACTED}`));
13
- }
14
- function structured(value) {
15
- try {
16
- return JSON.stringify(JSON.parse(value, (key, item) => (typeof item === "string" ? redactOtlpUrl(item, key) : item)));
17
- }
18
- catch {
19
- return undefined;
20
- }
21
- }
22
- export function redactOtlpUrl(value, key = "") {
23
- if (/(?:^|[._-])(?:fragment|userinfo|username|password)$/iu.test(key)) {
24
- return REDACTED;
25
- }
26
- if (/(?:^|[._-])query$/iu.test(key)) {
27
- return url(`?${value}`).slice(1);
28
- }
29
- if (/(?:^|[._-])(?:url|uri|target)(?:$|[._-])/iu.test(key) || /(?:^|[._-])(?:referer|referrer|location|origin)$/iu.test(key)) {
30
- return url(value);
31
- }
32
- if (/^\s*[[{]/u.test(value)) {
33
- const redacted = structured(value);
34
- if (redacted !== undefined) {
35
- return redacted;
36
- }
37
- }
38
- // Quotes and whitespace can belong to secret values, so free text has no safe closing delimiter.
39
- return value.replaceAll(/(?:[a-z][a-z0-9+.-]*:\/\/|[/?#]).*/gisu, url);
40
- }
41
- //# sourceMappingURL=redactOtlpUrl.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"redactOtlpUrl.js","sourceRoot":"","sources":["../src/redactOtlpUrl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAE1D,SAAS,KAAK,CAAC,KAAa;IAC3B,OAAO,KAAK;SACV,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;SAC5E,IAAI,CAAC,GAAG,CAAC,CAAC;AACb,CAAC;AAED,SAAS,GAAG,CAAC,KAAa;IACzB,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACtC,OAAO,CACN,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAChH,wDAAwD,EACxD,eAAe,QAAQ,GAAG,CAC1B,GAAG,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC,CAC3C,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAChC,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAW,EAAE,IAAa,EAAE,EAAE,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxI,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,GAAG,GAAG,EAAE;IACpD,IAAI,uDAAuD,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACvE,OAAO,QAAQ,CAAC;IACjB,CAAC;IACD,IAAI,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,OAAO,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,IAAI,4CAA4C,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,oDAAoD,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9H,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;IACD,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO,QAAQ,CAAC;QACjB,CAAC;IACF,CAAC;IACD,iGAAiG;IACjG,OAAO,KAAK,CAAC,UAAU,CAAC,wCAAwC,EAAE,GAAG,CAAC,CAAC;AACxE,CAAC"}
@@ -1,7 +0,0 @@
1
- import { type SchemaAST } from "effect";
2
- export declare function marked(ast: SchemaAST.AST, seen?: Set<SchemaAST.AST>): boolean;
3
- export declare function collectEncodedKeys(ast: SchemaAST.AST, keys: Set<string>): void;
4
- export declare function maskedValue(ast: SchemaAST.AST, keys: ReadonlySet<string>, seen?: Set<SchemaAST.AST>): boolean;
5
- export declare function collect(ast: SchemaAST.AST, nodes: Set<SchemaAST.AST>, encodings?: boolean): void;
6
- export declare function collectFieldKeys(properties: SchemaAST.Objects["propertySignatures"], keys: Set<string>, sensitive: (ast: SchemaAST.AST) => boolean): void;
7
- //# sourceMappingURL=schemaSensitiveAst.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"schemaSensitiveAst.d.ts","sourceRoot":"","sources":["../src/schemaSensitiveAst.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAsBnD,wBAAgB,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,IAAI,qBAA2B,GAAG,OAAO,CAenF;AAOD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,QAcvE;AAOD,wBAAgB,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,qBAA2B,GAAG,OAAO,CAmBnH;AACD,wBAAgB,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,SAAS,UAAO,QAQtF;AAMD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,KAAK,OAAO,QAMlJ"}