@shivaedev/server 0.9.3 → 0.10.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.10.0 - 2026-10-31
4
+
5
+ ### Fixed
6
+
7
+ - End open authenticated streams with `AuthUnavailable` when a session revalidation cannot reach the auth provider. Revoked sessions still end with `Unauthorized`, and live-change subscriptions use identity's shared stream revalidation.
8
+ - Generated applications provide Node services when running database setup, so setup commands participate in Effect interruption and typed failure handling.
9
+
10
+ ### Breaking
11
+
12
+ - `@shivaedev/local-postgres`: `assertLocalDatabase`, `sql`, `startPostgres`, `prepareDatabases` and lower-level command helpers return Effects. Yield them in an Effect program and provide `ChildProcessSpawner` for commands, for example with `NodeServices.layer` at a Node entry point. Replace synchronous try/catch with Effect error handling. Command failures use `PostgresCommandError`; local-target and image refusals use `LocalPostgresError`. Construct the Schema tagged errors as `new PostgresVersionMismatch({ expectedVersion: "18.6", observedVersion })` or `new PostgresSettingError({ container: "development-postgres", setting: "max_connections", cause })`. Exhausted readiness checks retain their final failure instead of reporting an unobserved version mismatch.
13
+ - `@shivaedev/server`: `setupDatabases()` requires `ChildProcessSpawner` and exposes local PostgreSQL failures in its typed error channel. Provide `NodeServices.layer` at the setup entry point instead of relying on synchronous commands hidden inside the host.
14
+
3
15
  ## 0.9.3 - 2026-10-31
4
16
 
5
17
  ### Fixed
package/README.md CHANGED
@@ -29,7 +29,7 @@ The optional modules solve different boundaries. `runtime/` carries Effect servi
29
29
 
30
30
  ### Prepare local development
31
31
 
32
- `setupDatabases()` from `@shivaedev/server/setupDatabases.ts` reads `DATABASE_URL` and `TEST_DATABASE_URL` through Effect Config and prepares both local databases with `@shivaedev/local-postgres`. Database names come from those URLs. `DOCKER_HOST` and `DOCKER_CONTEXT` are optional. Missing database URLs fail with a typed Config error; migrations remain the application's responsibility.
32
+ `setupDatabases()` from `@shivaedev/server/setupDatabases.ts` reads `DATABASE_URL` and `TEST_DATABASE_URL` through Effect Config and prepares both local databases with `@shivaedev/local-postgres`. Database names come from those URLs. `DOCKER_HOST` and `DOCKER_CONTEXT` are optional. Missing database URLs fail with a typed Config error; setup command failures retain their local-postgres error tags. Provide `ChildProcessSpawner` at the setup entry point, for example with `Effect.provide(NodeServices.layer)` before `NodeRuntime.runMain`. Migrations remain the application's responsibility.
33
33
 
34
34
  `development({ server, worker, conditions? })` from `@shivaedev/server/development.ts` starts the two application entry points with Node's watch mode and runs `pnpm exec vite`. Supply paths relative to the application directory and any export conditions its code needs. Provide `NodeServices.layer` to run it. When a process exits, the other processes stop and the Effect returns the first exit code, which the entry point can assign to `process.exitCode`. Use `runDevelopment(options)` from the same module for the Node entry point with that runtime wiring included.
35
35
 
@@ -1,5 +1,5 @@
1
1
  import { Layer } from "effect";
2
- import type { Rpc, RpcGroup } from "effect/rpc";
2
+ import { Rpc, type RpcGroup } from "effect/rpc";
3
3
  import type { SessionPolicy, SessionShape } from "@shivaedev/identity/server/session.ts";
4
4
  import type { AppChanges } from "#appHost.ts";
5
5
  export declare function hostChanges<R extends Rpc.Any, TSession extends SessionShape>(group: RpcGroup.RpcGroup<R>, changesService: typeof AppChanges, sessions?: SessionPolicy<TSession>): Layer.Layer<Rpc.ToHandler<Extract<R, {
@@ -1 +1 @@
1
- {"version":3,"file":"hostChanges.d.ts","sourceRoot":"","sources":["../src/hostChanges.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,EAAkB,MAAM,QAAQ,CAAC;AAEhE,OAAO,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKhD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAGzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,wBAAgB,WAAW,CAAC,CAAC,SAAS,GAAG,CAAC,GAAG,EAAE,QAAQ,SAAS,YAAY,EAC3E,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAC3B,cAAc,EAAE,OAAO,UAAU,EACjC,QAAQ,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;mBAuCoC,GAAG,MAAM,WAAW;mBAG1F"}
1
+ {"version":3,"file":"hostChanges.d.ts","sourceRoot":"","sources":["../src/hostChanges.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,EAAkB,MAAM,QAAQ,CAAC;AAEhE,OAAO,EAAE,GAAG,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAMhD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAEzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,wBAAgB,WAAW,CAAC,CAAC,SAAS,GAAG,CAAC,GAAG,EAAE,QAAQ,SAAS,YAAY,EAC3E,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAC3B,cAAc,EAAE,OAAO,UAAU,EACjC,QAAQ,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;mBA0CoC,GAAG,MAAM,WAAW;mBAG1F"}
@@ -1,10 +1,11 @@
1
1
  import { Context, Effect, Layer, Option, Stream } from "effect";
2
2
  import { Headers } from "effect/http";
3
+ import { Rpc } from "effect/rpc";
3
4
  import { CurrentViewer } from "@shivaedev/contract/readPolicy.ts";
4
5
  import { Unauthorized } from "@shivaedev/errors/taxonomy.ts";
5
6
  import { recheckSession } from "@shivaedev/identity/server/recheckSession.ts";
7
+ import { revalidateStream } from "@shivaedev/identity/server/revalidateStream.ts";
6
8
  import { resolveChanges } from "@shivaedev/identity/server/sessionKeys.ts";
7
- import { revalidateSession } from "@shivaedev/identity/server/socketSession.ts";
8
9
  import { rerunQuery } from "#rerunQuery.ts";
9
10
  export function hostChanges(group, changesService, sessions) {
10
11
  return Layer.effectContext(Effect.gen(function* () {
@@ -22,11 +23,12 @@ export function hostChanges(group, changesService, sessions) {
22
23
  if (sessions === undefined || Option.isNone(viewer)) {
23
24
  return stream;
24
25
  }
25
- return Stream.interruptWhen(stream, sessionRevoked(sessions, rpc._tag, viewer.value.id));
26
+ const revalidation = Effect.never.pipe(revalidateStream(sessions, rpc, viewer.value.id, recheckSession(sessions, Headers.empty, rpc._tag)));
27
+ return Stream.interruptWhen(stream, revalidation);
26
28
  }));
27
29
  }
28
30
  for (const rpc of group.requests.values()) {
29
- if (!rpc._tag.endsWith(".$changes")) {
31
+ if (!(Rpc.isRpc(rpc) && rpc._tag.endsWith(".$changes"))) {
30
32
  continue;
31
33
  }
32
34
  const provided = services.mapUnsafe.get(rpc.key);
@@ -49,12 +51,4 @@ function authorizeSession(sessions, tag, viewer, policy) {
49
51
  }
50
52
  return recheckSession(sessions, Headers.empty, tag).pipe(Effect.map((current) => Option.isNone(viewer) || (Option.isSome(current) && current.value.user.id === viewer.value.id)), Effect.flatMap((allowed) => allowed ? policy : Effect.fail(new Unauthorized({ message: "Authentication required" }))));
51
53
  }
52
- function sessionRevoked(sessions, tag, id) {
53
- return Effect.gen(function* () {
54
- const current = yield* recheckSession(sessions, Headers.empty, tag).pipe(Effect.catchTag("AuthUnavailable", () => Effect.succeed(undefined)));
55
- if (current !== undefined && (Option.isNone(current) || current.value.user.id !== id)) {
56
- return yield* new Unauthorized({ message: "Authentication required" });
57
- }
58
- }).pipe((check) => revalidateSession(check, sessions.streamRevalidationInterval ?? "30 seconds"));
59
- }
60
54
  //# sourceMappingURL=hostChanges.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hostChanges.js","sourceRoot":"","sources":["../src/hostChanges.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hostChanges.js","sourceRoot":"","sources":["../src/hostChanges.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  import { Config, Effect } from "effect";
2
- export declare const setupDatabases: () => Effect.Effect<void, Config.ConfigError, never>;
2
+ export declare const setupDatabases: () => Effect.Effect<void, Config.ConfigError | import("@shivaedev/local-postgres/server/LocalPostgresError.ts").LocalPostgresError | import("@shivaedev/local-postgres/server/PostgresCommandError.ts").PostgresCommandError | import("@shivaedev/local-postgres/server/localConnections.ts").PostgresSettingError | import("@shivaedev/local-postgres/server/PostgresVersionMismatch.ts").PostgresVersionMismatch, import("effect/process/ChildProcessSpawner").ChildProcessSpawner>;
3
3
  //# sourceMappingURL=setupDatabases.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"setupDatabases.d.ts","sourceRoot":"","sources":["../src/setupDatabases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGxC,eAAO,MAAM,cAAc,sDAQzB,CAAC"}
1
+ {"version":3,"file":"setupDatabases.d.ts","sourceRoot":"","sources":["../src/setupDatabases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGxC,eAAO,MAAM,cAAc,udAQzB,CAAC"}
@@ -7,6 +7,6 @@ export const setupDatabases = Effect.fn("Platform.setupDatabases")(function* ()
7
7
  "DOCKER_HOST": Config.String("DOCKER_HOST").pipe(Config.withDefault("")),
8
8
  "TEST_DATABASE_URL": Config.String("TEST_DATABASE_URL"),
9
9
  });
10
- yield* Effect.sync(() => localPostgres(config).prepareDatabases([config.DATABASE_URL, config.TEST_DATABASE_URL]));
10
+ yield* localPostgres(config).prepareDatabases([config.DATABASE_URL, config.TEST_DATABASE_URL]);
11
11
  });
12
12
  //# sourceMappingURL=setupDatabases.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"setupDatabases.js","sourceRoot":"","sources":["../src/setupDatabases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,mDAAmD,CAAC;AAElF,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,QAAQ,CAAC;IAC3E,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QAChC,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC;QAC7C,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC9E,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACxE,mBAAmB,EAAE,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC;KACvD,CAAC,CAAC;IACH,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;AACnH,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"setupDatabases.js","sourceRoot":"","sources":["../src/setupDatabases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,mDAAmD,CAAC;AAElF,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,QAAQ,CAAC;IAC3E,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QAChC,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC;QAC7C,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC9E,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACxE,mBAAmB,EAAE,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC;KACvD,CAAC,CAAC;IACH,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAChG,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/server",
3
- "version": "0.9.3",
3
+ "version": "0.10.0",
4
4
  "description": "The Effect application host: HTTP and RPC serving, health, OTLP export, database and migrations, and development mode",
5
5
  "keywords": [
6
6
  "effect"
@@ -46,11 +46,11 @@
46
46
  ],
47
47
  "dependencies": {
48
48
  "@shivaedev/changes": "0.6.0",
49
- "@shivaedev/contract": "0.26.0",
49
+ "@shivaedev/contract": "0.27.0",
50
50
  "@shivaedev/errors": "0.1.3",
51
51
  "@shivaedev/http": "0.3.1",
52
- "@shivaedev/identity": "0.10.0",
53
- "@shivaedev/local-postgres": "0.7.0",
52
+ "@shivaedev/identity": "0.10.1",
53
+ "@shivaedev/local-postgres": "0.8.0",
54
54
  "@shivaedev/sql": "0.27.0"
55
55
  },
56
56
  "devDependencies": {
@@ -58,17 +58,15 @@
58
58
  "@effect/sql-pg": "4.0.6",
59
59
  "@effect/vitest": "4.0.6",
60
60
  "@shivaedev/access": "0.3.1",
61
- "@shivaedev/admin": "0.12.2",
62
- "@shivaedev/jobs": "0.24.0",
63
- "@shivaedev/quality": "0.48.1",
61
+ "@shivaedev/admin": "0.12.3",
62
+ "@shivaedev/jobs": "0.25.0",
63
+ "@shivaedev/quality": "0.48.2",
64
64
  "@shivaedev/test": "0.12.0",
65
65
  "@shivaedev/test-sql": "0.15.0",
66
- "@shivaedev/test-story": "0.27.0",
66
+ "@shivaedev/test-story": "0.28.0",
67
67
  "@types/node": "24.19.2",
68
- "@types/pg": "8.20.0",
69
68
  "better-auth": "1.7.12",
70
69
  "effect": "4.0.6",
71
- "pg": "8.23.0",
72
70
  "pg-boss": "12.38.0",
73
71
  "typescript": "7.0.2",
74
72
  "vitest": "5.0.5"
@@ -78,8 +76,7 @@
78
76
  "@effect/sql-pg": "4.0.6",
79
77
  "@effect/vitest": "4.0.6",
80
78
  "better-auth": "1.7.12",
81
- "effect": "4.0.6",
82
- "pg": "8.23.0"
79
+ "effect": "4.0.6"
83
80
  },
84
81
  "peerDependenciesMeta": {
85
82
  "@effect/platform-node": {
@@ -93,9 +90,6 @@
93
90
  },
94
91
  "better-auth": {
95
92
  "optional": true
96
- },
97
- "pg": {
98
- "optional": true
99
93
  }
100
94
  },
101
95
  "engines": {
@@ -1,13 +1,13 @@
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
4
  import { CurrentViewer, type Viewer } from "@shivaedev/contract/readPolicy.ts";
5
5
  import type { QueryReference } from "@shivaedev/contract/serverMetadata.ts";
6
6
  import { Unauthorized } from "@shivaedev/errors/taxonomy.ts";
7
7
  import { recheckSession } from "@shivaedev/identity/server/recheckSession.ts";
8
+ import { revalidateStream } from "@shivaedev/identity/server/revalidateStream.ts";
8
9
  import type { SessionPolicy, SessionShape } from "@shivaedev/identity/server/session.ts";
9
10
  import { resolveChanges } from "@shivaedev/identity/server/sessionKeys.ts";
10
- import { revalidateSession } from "@shivaedev/identity/server/socketSession.ts";
11
11
  import type { AppChanges } from "#appHost.ts";
12
12
  import { rerunQuery } from "#rerunQuery.ts";
13
13
 
@@ -21,7 +21,7 @@ export function hostChanges<R extends Rpc.Any, TSession extends SessionShape>(
21
21
  const changes = yield* Effect.serviceOption(changesService);
22
22
  const services = yield* Effect.context<never>();
23
23
  const handlers = new Map<string, unknown>();
24
- function subscribe(rpc: Rpc.Any, queries: readonly QueryReference[], options: Parameters<Rpc.Handler<string>["handler"]>[1]) {
24
+ function subscribe(rpc: Rpc.AnyWithProps, queries: readonly QueryReference[], options: Parameters<Rpc.Handler<string>["handler"]>[1]) {
25
25
  return Stream.unwrap(
26
26
  Effect.gen(function* () {
27
27
  const { subscription, context } = yield* resolveChanges(rpc, queries);
@@ -33,12 +33,15 @@ export function hostChanges<R extends Rpc.Any, TSession extends SessionShape>(
33
33
  if (sessions === undefined || Option.isNone(viewer)) {
34
34
  return stream;
35
35
  }
36
- return Stream.interruptWhen(stream, sessionRevoked(sessions, rpc._tag, viewer.value.id));
36
+ const revalidation = Effect.never.pipe(
37
+ revalidateStream(sessions, rpc, viewer.value.id, recheckSession(sessions, Headers.empty, rpc._tag)),
38
+ );
39
+ return Stream.interruptWhen(stream, revalidation);
37
40
  }),
38
41
  );
39
42
  }
40
43
  for (const rpc of group.requests.values()) {
41
- if (!rpc._tag.endsWith(".$changes")) {
44
+ if (!(Rpc.isRpc(rpc) && rpc._tag.endsWith(".$changes"))) {
42
45
  continue;
43
46
  }
44
47
  const provided = services.mapUnsafe.get(rpc.key);
@@ -75,12 +78,3 @@ function authorizeSession<TSession extends SessionShape, E, R>(
75
78
  ),
76
79
  );
77
80
  }
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
- }
@@ -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
  });