@shivaedev/server 0.3.0 → 0.4.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/README.md CHANGED
@@ -13,7 +13,7 @@ import { appHost } from "@shivaedev/server/appHost.ts";
13
13
  import { Api, Handlers, Services, migrations, sessions } from "./app.ts";
14
14
 
15
15
  NodeRuntime.runMain(
16
- Layer.launch(appHost({ group: Api, handlers: Handlers, services: Services, migrations: { loader: migrations }, sessions, assets: "./public" })),
16
+ Layer.launch(appHost({ group: Api, handlers: Handlers, services: Services, migrations: { loader: migrations }, sessions, assets: "./public" })),
17
17
  );
18
18
  ```
19
19
 
@@ -35,7 +35,7 @@ The optional modules solve different boundaries. `runtime/` carries Effect servi
35
35
 
36
36
  ### Host the application
37
37
 
38
- `appHost` is the server entry point for an Effect app. For a PostgreSQL app, supply the native RPC group, handler and service Layers, migration loader, session policy and static asset directory. The host completes migrations before acquiring application services, starts Node HTTP with NDJSON RPC at `/rpc`, and provides SQL, Reactivity and `AppChanges` to those Layers.
38
+ `appHost` is the server entry point for an Effect app. For a PostgreSQL app, supply the native RPC group, handler and service Layers, migration loader, session policy and static asset directory. The host completes migrations before acquiring application services, starts Node HTTP with native Effect RPC over a WebSocket upgrade at `/rpc`, and provides SQL, Reactivity and `AppChanges` to those Layers.
39
39
 
40
40
  ```ts
41
41
  import { NodeRuntime } from "@effect/platform-node";
@@ -44,12 +44,12 @@ import { appHost } from "@shivaedev/server/appHost.ts";
44
44
  import { Api, Handlers, Services, migrations, sessions } from "./app.ts";
45
45
 
46
46
  const Server = appHost({
47
- group: Api,
48
- handlers: Handlers,
49
- services: Services,
50
- migrations: { loader: migrations },
51
- sessions,
52
- assets: "./public",
47
+ group: Api,
48
+ handlers: Handlers,
49
+ services: Services,
50
+ migrations: { loader: migrations },
51
+ sessions,
52
+ assets: "./public",
53
53
  });
54
54
 
55
55
  NodeRuntime.runMain(Layer.launch(Server));
@@ -65,15 +65,15 @@ Pass application HTTP endpoints through `routes`, including routes that read app
65
65
  import { Effect, Layer } from "effect";
66
66
  import { HttpMiddleware, HttpRouter, HttpServerResponse } from "effect/http";
67
67
 
68
- const Routes = HttpRouter.add(
69
- "*",
70
- "/.well-known/app",
71
- AppMetadata.pipe(Effect.map(HttpServerResponse.text)),
72
- ).pipe(
73
- Layer.provide(HttpRouter.middleware(HttpMiddleware.cors({
74
- allowedOrigins: ["*"],
75
- allowedMethods: ["GET"],
76
- })).layer),
68
+ const Routes = HttpRouter.add("*", "/.well-known/app", AppMetadata.pipe(Effect.map(HttpServerResponse.text))).pipe(
69
+ Layer.provide(
70
+ HttpRouter.middleware(
71
+ HttpMiddleware.cors({
72
+ allowedOrigins: ["*"],
73
+ allowedMethods: ["GET"],
74
+ }),
75
+ ).layer,
76
+ ),
77
77
  );
78
78
 
79
79
  const Server = appHost({ group: Api, handlers: Handlers, services: Services, routes: Routes, sessions });
@@ -89,7 +89,7 @@ RPC request bodies are limited to 1 MiB by default. Set `MAX_BODY_SIZE` to a byt
89
89
 
90
90
  For a native Node HTTP route outside RPC, read the request body with `readBoundedBody` from [`@shivaedev/http`](https://github.com/ShivaeDev/platform/tree/main/packages/http#readme), which rejects oversized bodies with a typed 413 failure.
91
91
 
92
- RPC uses the existing `localRpcGuard`: it requires a loopback peer and Host, same-origin or absent Origin, and the NDJSON content type. Session lookup uses transport headers. The host applies `RequestTracing` last to every served RPC, including loopback RPC, so it wraps authentication and handlers without a per-contract tracing declaration. Existing tracing declarations run once at that outermost boundary. With a session policy, contracts declare `Authenticated` and `MaybeAuthenticated` as needed; the host supplies their implementations. For `AuthenticatedUser`, merge `authenticatedUserLayer(sessions)` beside the handlers as shown below. Declared errors retain their Schema types. Applications still own resource authorization and use `rpcBoundary` when they need to map unexpected failures.
92
+ Ordinary POST RPC uses `localRpcGuard` from `@shivaedev/identity/server/local.ts`: it requires a loopback peer and Host, same-origin or absent Origin, and the NDJSON content type. The WebSocket upgrade uses the same loopback, origin and trusted-proxy checks without an HTTP body content type. Session lookup uses the upgrade's transport headers; RPC message headers cannot replace its cookie or Origin. Session middleware revalidates authenticated streams at `streamRevalidationInterval` and ends revoked subscriptions with typed `Unauthorized`. The shared socket remains open; later protected calls use the same session checks. Automatic live subscriptions also recheck the session and query policy before each hint. POST RPC has no `$changes` stream. The host applies `RequestTracing` last to every served RPC, including loopback RPC, so it wraps authentication and handlers without a per-contract tracing declaration. Existing tracing declarations run once at that outermost boundary. With a session policy, contracts declare `Authenticated` and `MaybeAuthenticated` as needed; the host supplies their implementations. For `AuthenticatedUser`, merge `authenticatedUserLayer(sessions)` from `@shivaedev/identity/server/session.ts` beside the handlers. Declared errors retain their Schema types. Applications still own resource authorization and use `rpcBoundary` when they need to map unexpected failures.
93
93
 
94
94
  Every response from the host's native RPC endpoint carries `Cache-Control: private, no-store`, including mixed public and authenticated batches, typed failures, transport rejections, body-read failures and streams. The host sets this at the outer response boundary without inspecting batch contents.
95
95
 
@@ -103,7 +103,7 @@ Set `migrations.mode: "check"` on `appDatabase` or a database-backed `appHost` w
103
103
 
104
104
  Pass `migrations.components` beside `loader` for storage managed by another engine. For pg-boss, register `pgBossSchema({ schema: "app_jobs" })` from `@shivaedev/jobs/server/schema.ts`, then start every jobs Layer with `migrate: false`. `check` and `wait` use the same `MigrationError` readout for pending ledger IDs and component names and details, including pg-boss’s installed and required versions.
105
105
 
106
- The host provides Effect's native `Crypto` service (`effect/Crypto`) to preflight, deferred application construction, application services and handlers. Generate invite codes and tokens through that service; see the [secure invite code example](../../docs/framework/README.md#secure-invite-codes-and-tokens). Use `Random` for non-secure choices.
106
+ The host provides Effect's native `Crypto` service (`effect/Crypto`) to preflight, deferred application construction, application services and handlers. Generate invite codes and tokens through that service; see the [secure invite code example](https://github.com/ShivaeDev/platform/blob/main/docs/framework/README.md#secure-invite-codes-and-tokens). Use `Random` for non-secure choices.
107
107
 
108
108
  Supply `preflight: AppConfigLive` to `appHost` to build a native Layer before checking or applying migrations, or constructing the application. Use it to validate configuration such as app IDs, keys and invite lists. Its errors stay in the returned Layer's typed error channel, its requirements other than `Crypto` remain external requirements, and its services are available to migrations, application construction, services and RPC handlers as well as callers of the host Layer. Preflight resources close with the host scope. The option also works without migrations.
109
109
 
@@ -111,13 +111,13 @@ When construction itself touches the schema, use `appHost({ migrations, config,
111
111
 
112
112
  ```ts
113
113
  const host = appHost({
114
- config: { databaseUrl },
115
- migrations: { loader: migrations, mode: "check" },
116
- preflight: AppConfigLive,
117
- application: Effect.gen(function* () {
118
- const { routes, sessions } = yield* makeAuth();
119
- return { group: Api, handlers: Handlers, services: Services, routes, sessions };
120
- }),
114
+ config: { databaseUrl },
115
+ migrations: { loader: migrations, mode: "check" },
116
+ preflight: AppConfigLive,
117
+ application: Effect.gen(function* () {
118
+ const { routes, sessions } = yield* makeAuth();
119
+ return { group: Api, handlers: Handlers, services: Services, routes, sessions };
120
+ }),
121
121
  });
122
122
  ```
123
123
 
@@ -127,27 +127,27 @@ Set `OTEL_EXPORTER_OTLP_ENDPOINT` or `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` to exp
127
127
 
128
128
  The supported tracing variables and defaults are:
129
129
 
130
- | Variable | Default | Meaning |
131
- | --- | --- | --- |
132
- | `OTEL_EXPORTER_OTLP_ENDPOINT` | Unset | Collector base URL. |
133
- | `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | Base URL plus `/v1/traces` | Complete traces URL; takes precedence. |
134
- | `OTEL_EXPORTER_OTLP_PROTOCOL` | `http/protobuf` | `http/protobuf` or `http/json`. |
135
- | `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` | General protocol | Overrides the protocol for traces. |
136
- | `OTEL_EXPORTER_OTLP_HEADERS` | Empty | Comma-separated exporter headers. |
137
- | `OTEL_SERVICE_NAME` | Resource `service.name`, then `unknown_service` | Service name. |
138
- | `OTEL_SERVICE_VERSION` | Resource `service.version`, otherwise unset | Service version. |
139
- | `OTEL_RESOURCE_ATTRIBUTES` | Empty | Comma-separated resource attributes. |
140
- | `OTEL_EXPORTER_OTLP_TIMEOUT` | `10000` ms | Timeout for each HTTP export attempt, including its response body. |
141
- | `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT` | General timeout | Overrides the request timeout for traces. |
142
- | `OTEL_BSP_SCHEDULE_DELAY` | `5000` ms | Effect tracer's batch export interval. |
143
- | `OTEL_BSP_MAX_EXPORT_BATCH_SIZE` | `1000` spans | Effect tracer's batch-size trigger. |
144
- | `OTEL_BSP_EXPORT_TIMEOUT` | `3000` ms | Effect tracer's shutdown flush bound, capped at the request timeout. |
130
+ | Variable | Default | Meaning |
131
+ | ------------------------------------ | ----------------------------------------------- | -------------------------------------------------------------------- |
132
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | Unset | Collector base URL. |
133
+ | `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | Base URL plus `/v1/traces` | Complete traces URL; takes precedence. |
134
+ | `OTEL_EXPORTER_OTLP_PROTOCOL` | `http/protobuf` | `http/protobuf` or `http/json`. |
135
+ | `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` | General protocol | Overrides the protocol for traces. |
136
+ | `OTEL_EXPORTER_OTLP_HEADERS` | Empty | Comma-separated exporter headers. |
137
+ | `OTEL_SERVICE_NAME` | Resource `service.name`, then `unknown_service` | Service name. |
138
+ | `OTEL_SERVICE_VERSION` | Resource `service.version`, otherwise unset | Service version. |
139
+ | `OTEL_RESOURCE_ATTRIBUTES` | Empty | Comma-separated resource attributes. |
140
+ | `OTEL_EXPORTER_OTLP_TIMEOUT` | `10000` ms | Timeout for each HTTP export attempt, including its response body. |
141
+ | `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT` | General timeout | Overrides the request timeout for traces. |
142
+ | `OTEL_BSP_SCHEDULE_DELAY` | `5000` ms | Effect tracer's batch export interval. |
143
+ | `OTEL_BSP_MAX_EXPORT_BATCH_SIZE` | `1000` spans | Effect tracer's batch-size trigger. |
144
+ | `OTEL_BSP_EXPORT_TIMEOUT` | `3000` ms | Effect tracer's shutdown flush bound, capped at the request timeout. |
145
145
 
146
146
  Timeouts fail through the HTTP client's typed transport-error channel and use the same warning path as other transport failures. Effect retains its native retry policy; the request timeout applies to each attempt. The batch defaults follow Effect's `OtlpTracer.layer`. Its options cannot express a separate batch-operation deadline or a queue capacity, so `OTEL_BSP_EXPORT_TIMEOUT` controls shutdown only and `OTEL_BSP_MAX_QUEUE_SIZE` is unsupported. Other `OTEL_BSP_*` variables are unsupported.
147
147
 
148
148
  On Railway, enable the per-service tracing setting separately for the web service and worker, and leave both exporter endpoint variables unset in your app's configuration. Railway documents that it injects the `OTEL_*` variables, including `OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf`, only when the app sets no endpoint of its own. The framework exports through Effect's own `effect/observability` OTLP tracer; eBPF auto-instrumentation is outside this path. For a worker, provide `otlpTracing` from `@shivaedev/server/otlpTracing.ts` to its application Layer. It batches ended Effect spans and flushes during scoped shutdown with a three-second bound by default. The first failed export logs a warning with the collector status and redacted response body, or the transport failure kind when no response arrives. Repeated failures stay quiet until a successful export. Collector connection failures and HTTP errors leave requests, jobs and shutdown successful.
149
149
 
150
- Exported HTTP server spans use `{method} {route}` with `http.route` for matched RPC and router paths, including parameter templates; unmatched requests use the method alone. The production host continues incoming W3C `traceparent` context, including one sent by an edge proxy.
150
+ Exported HTTP server spans use `{method} {route}` with `http.route` for matched RPC and router paths, including parameter templates; unmatched requests use the method alone. `appHost` continues incoming W3C `traceparent` context in RPC handling, including one sent by an edge proxy, whether or not an exporter is configured.
151
151
 
152
152
  Both JSON and protobuf export serialization apply sensitive-key and credential-text redaction to span attributes, events, links, error details and resource attributes. Credential text includes JWTs, Bearer/Basic credentials, sensitive assignments including bare `sig=...` anywhere in text (with or without `?`), and complete PEM private-key blocks through their matching END marker, including RSA, EC, OPENSSH and encrypted private keys. Matches become `<redacted>`. `sig` uses the shared sensitive-key policy for attributes and text. URL query values, fragments and user information are also redacted. Exporter headers stay in the collector request, outside the spans. Applications must still avoid placing secrets in span names, free text or custom attributes.
153
153
 
@@ -167,11 +167,7 @@ Use one `publicConfig` declaration per application as the one path for server co
167
167
  import { Schema } from "effect";
168
168
  import { publicConfig } from "@shivaedev/contract/publicConfig.ts";
169
169
 
170
- export const PublicConfig = publicConfig(
171
- Schema.Struct({ installUrl: Schema.URL }).pipe(
172
- Schema.encodeKeys({ installUrl: "INSTALL_URL" }),
173
- ),
174
- );
170
+ export const PublicConfig = publicConfig(Schema.Struct({ installUrl: Schema.URL }).pipe(Schema.encodeKeys({ installUrl: "INSTALL_URL" })));
175
171
  ```
176
172
 
177
173
  On the server, merge the declaration into the application's group and its generated handler Layer into the handlers:
@@ -184,35 +180,27 @@ import { Api, Handlers, sessions } from "./app.ts";
184
180
  import { PublicConfig } from "./public-config.ts";
185
181
 
186
182
  export const Server = appHost({
187
- group: Api.merge(PublicConfig),
188
- handlers: Layer.merge(Handlers, publicConfigLayer(PublicConfig)),
189
- sessions,
183
+ group: Api.merge(PublicConfig),
184
+ handlers: Layer.merge(Handlers, publicConfigLayer(PublicConfig)),
185
+ sessions,
190
186
  });
191
187
  ```
192
188
 
193
189
  `publicConfigLayer` reads `Config.schema` from the host's native ConfigProvider when the handler Layer builds. Missing or invalid required fields fail startup with a typed `ConfigError`. An optional second argument supplies a native Config path: `publicConfigLayer(PublicConfig, "PUBLIC")` reads `PUBLIC_INSTALL_URL` with the default environment provider. Only schema-declared fields are loaded and serialized; other server values never enter this response. The generated query has no session middleware, so it can supply public configuration before sign-in. Merge it alongside authenticated contracts rather than applying authentication to the merged group.
194
190
 
195
- On the client, use the same native `AtomRpc.Service`, NDJSON HTTP protocol and contract `bind` as other queries:
191
+ On the client, use the same contract `makeClient` and shared WebSocket as other queries:
196
192
 
197
193
  ```ts
198
- import { Layer } from "effect";
199
- import { FetchHttpClient } from "effect/http";
200
- import * as AtomRpc from "effect/reactivity/AtomRpc";
201
- import { RpcClient, RpcSerialization } from "effect/rpc";
202
- import { bind } from "@shivaedev/contract/bind.ts";
194
+ import { makeClient } from "@shivaedev/contract/bind.ts";
203
195
  import { useQuery } from "@shivaedev/react/client/resultState.ts";
204
196
  import { PublicConfig } from "./public-config.ts";
205
197
 
206
- class ConfigClient extends AtomRpc.Service<ConfigClient>()("app/ConfigClient", {
207
- group: PublicConfig,
208
- protocol: RpcClient.layerProtocolHttp({ url: "/rpc" }).pipe(
209
- Layer.provide([FetchHttpClient.layer, RpcSerialization.layerNdjson]),
210
- ),
211
- }) {}
212
- const config = bind(PublicConfig, ConfigClient);
198
+ const { api: config } = makeClient(PublicConfig, {
199
+ url: new URL("/rpc", window.location.href).href,
200
+ });
213
201
 
214
202
  export function usePublicConfig() {
215
- return useQuery(config.get.query());
203
+ return useQuery(config.get.query());
216
204
  }
217
205
  ```
218
206
 
@@ -228,15 +216,15 @@ Tracing logs declared failures with `RPC failure` and their tag, and defects wit
228
216
  import { Schema } from "effect";
229
217
 
230
218
  const Contact = Schema.Struct({
231
- deliveryAddress: Schema.String.annotate({ sensitive: true }),
232
- recoveryCode: Schema.RedactedFromValue(Schema.String),
219
+ deliveryAddress: Schema.String.annotate({ sensitive: true }),
220
+ recoveryCode: Schema.RedactedFromValue(Schema.String),
233
221
  });
234
222
 
235
223
  const Server = appHost({
236
- group: Api,
237
- handlers: Handlers,
238
- sessions,
239
- config: { sensitiveKeys: ["customerReference"] },
224
+ group: Api,
225
+ handlers: Handlers,
226
+ sessions,
227
+ config: { sensitiveKeys: ["customerReference"] },
240
228
  });
241
229
  ```
242
230
 
@@ -252,7 +240,7 @@ For native RPC serialization, `schemaSensitiveKeys(group, extraKeys?)` returns a
252
240
 
253
241
  The masking primitives, `redact`, `redactWire`, `redactText`, `redactCause` and `isSensitiveKey`, live in [`@shivaedev/errors`](https://github.com/ShivaeDev/platform/tree/main/packages/errors#readme).
254
242
 
255
- For a native RPC server composed without `appHost`, `requestTracingLayer({ sensitive })` accepts a key predicate; `isSensitiveKey` from `@shivaedev/errors/sensitive.ts` supplies the default credential rules. `redactingErrorReporter(reporter, sensitive?)` from `@shivaedev/errors/redactCause.ts` wraps an Effect error reporter and passes it redacted failure and defect causes while preserving reporting hints such as severity and redacted attributes.
243
+ For a native RPC server composed without `appHost`, `requestTracingLayer({ sensitive })` from `@shivaedev/identity/server/tracing.ts` accepts a key predicate; `isSensitiveKey` from `@shivaedev/errors/sensitive.ts` supplies the default credential rules. `redactingErrorReporter(reporter, sensitive?)` from `@shivaedev/errors/redactCause.ts` wraps an Effect error reporter and passes it redacted failure and defect causes while preserving reporting hints such as severity and redacted attributes.
256
244
 
257
245
  ### Calling outside APIs
258
246
 
@@ -270,13 +258,10 @@ class Greeting extends Context.Service<Greeting, string>()("app/Greeting") {}
270
258
 
271
259
  const runtime = makePlatformRuntime(Layer.succeed(Greeting, "application"));
272
260
  const base = await runtime.runPromise(Greeting);
273
- const request = await runtime.runWithServices(
274
- Context.make(Greeting, "request"),
275
- async () => {
276
- await Promise.resolve();
277
- return runtime.runPromise(Greeting);
278
- },
279
- );
261
+ const request = await runtime.runWithServices(Context.make(Greeting, "request"), async () => {
262
+ await Promise.resolve();
263
+ return runtime.runPromise(Greeting);
264
+ });
280
265
  await runtime.dispose();
281
266
  ```
282
267
 
@@ -293,21 +278,21 @@ import type { IncomingMessage } from "node:http";
293
278
  import { nodeSubscriptionSignal } from "@shivaedev/server/node-http/subscriptionSignal.ts";
294
279
 
295
280
  export async function consumeSubscription(
296
- request: Request,
297
- nodeRequest: IncomingMessage,
298
- procedureSignal: AbortSignal,
299
- consume: (signal: AbortSignal) => Promise<void>,
281
+ request: Request,
282
+ nodeRequest: IncomingMessage,
283
+ procedureSignal: AbortSignal,
284
+ consume: (signal: AbortSignal) => Promise<void>,
300
285
  ) {
301
- const subscription = nodeSubscriptionSignal({
302
- nodeRequest,
303
- request,
304
- signals: [procedureSignal],
305
- });
306
- try {
307
- await consume(subscription.signal);
308
- } finally {
309
- subscription.dispose();
310
- }
286
+ const subscription = nodeSubscriptionSignal({
287
+ nodeRequest,
288
+ request,
289
+ signals: [procedureSignal],
290
+ });
291
+ try {
292
+ await consume(subscription.signal);
293
+ } finally {
294
+ subscription.dispose();
295
+ }
311
296
  }
312
297
  ```
313
298
 
@@ -317,29 +302,32 @@ The signal aborts on an additional signal, socket close, incomplete request clos
317
302
 
318
303
  Import the module that defines the name; there is no package-root entry. Paths below follow `@shivaedev/server/`.
319
304
 
320
- | Module | Names and purpose |
321
- | --- | --- |
322
- | `appHost.ts` | `appHost`, `appDatabase`, `AppChanges`: scoped HTTP and PostgreSQL composition with loopback defaults and optional proxy trust. |
323
- | `otlpTracing.ts` | `otlpTracing`: opt-in Effect OTLP trace export for worker Layers. |
324
- | `schemaSensitiveKeys.ts`, `RedactionPolicy.ts` | `schemaSensitiveKeys(group, extraKeys?)`, `RedactionPolicy`: derive and provide an app's diagnostic key predicate. |
325
- | `redactingDiagnostics.ts`, `redactingTracer.ts`, `redactingRpcSerialization.ts` | `redactingDiagnostics(sensitive)`, `redactRecord(values, sensitive)`, `redactingTracer(sensitive)`, `redactingRpcSerialization(wire, sensitive)`: compose native diagnostic and NDJSON boundaries. |
326
- | `runtime/makePlatform.ts` | `makePlatformRuntime(layer, { developmentCacheKey? })`. |
327
- | `node-http/subscriptionSignal.ts` | `nodeSubscriptionSignal({ nodeRequest?, request?, signals? })`, returning `{ signal, dispose }`. |
305
+ | Module | Names and purpose |
306
+ | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
307
+ | `appHost.ts` | `appHost`, `appDatabase`, `AppChanges`: scoped HTTP and PostgreSQL composition with loopback defaults and optional proxy trust. |
308
+ | `setupDatabases.ts` | `setupDatabases()`: prepare the local development and test databases. |
309
+ | `development.ts` | `development({ server, worker, conditions? })`, `runDevelopment(options)`: run the server, worker and Vite in watch mode. |
310
+ | `rpc-server/publicConfigLayer.ts` | `publicConfigLayer(declaration, path?)`: serve a `publicConfig` declaration from native Config. |
311
+ | `otlpTracing.ts` | `otlpTracing`: opt-in Effect OTLP trace export for worker Layers. |
312
+ | `schemaSensitiveKeys.ts`, `RedactionPolicy.ts` | `schemaSensitiveKeys(group, extraKeys?)`, `RedactionPolicy`: derive and provide an app's diagnostic key predicate. |
313
+ | `redactingDiagnostics.ts`, `redactingTracer.ts`, `redactingRpcSerialization.ts` | `redactingDiagnostics(sensitive)`, `redactRecord(values, sensitive)`, `redactingTracer(sensitive)`, `redactingRpcSerialization(wire, sensitive, maskFailure?)`: compose native diagnostic and NDJSON boundaries. |
314
+ | `runtime/makePlatform.ts` | `makePlatformRuntime(layer, { developmentCacheKey? })`. |
315
+ | `node-http/subscriptionSignal.ts` | `nodeSubscriptionSignal({ nodeRequest?, request?, signals? })`, returning `{ signal, dispose }`. |
328
316
 
329
317
  ### Install, setup and limits
330
318
 
331
319
  ```sh
332
- pnpm add @shivaedev/server effect@4.0.5
320
+ pnpm add @shivaedev/server effect
333
321
  ```
334
322
 
335
323
  Effect is the only required peer. The `node-http/`, `rpc-server/` and `runtime/` modules work without the optional peers; a module's import path is its path under `src/`. Every module is server code: the runtime uses Node's `AsyncLocalStorage`, and browser code imports contracts from `@shivaedev/contract`, identity declarations from `@shivaedev/identity` and error schemas from `@shivaedev/errors` instead.
336
324
 
337
325
  Install the optional peers for the selected integration:
338
326
 
339
- | Integration | Additional peers |
340
- | --- | --- |
341
- | `appHost.ts` | `@effect/platform-node`, `@effect/sql-pg` |
342
-
327
+ | Integration | Additional peers |
328
+ | ---------------- | ----------------------------------------- |
329
+ | `appHost.ts` | `@effect/platform-node`, `@effect/sql-pg` |
330
+ | `development.ts` | `@effect/platform-node` |
343
331
  - The package needs Node 24 or newer.
344
332
  - `appHost` adds tracing last on its server-side copy of the group. When composing a native RPC server directly, add `RequestTracing` last on the group so it wraps authentication too; see the [native-server example](https://github.com/ShivaeDev/platform/blob/main/docs/framework/request-context.md#request-id-identity-and-logging). Middleware outside that tracing boundary is responsible for its own diagnostics.
345
333
  - Redaction recognizes declared field names and common credential shapes. Mark sensitive fields in RPC schemas and configure extra names once with `config.sensitiveKeys`. Keep sensitive values out of ordinary prose.
package/dist/appHost.js CHANGED
@@ -1,4 +1,4 @@
1
- import { NodeCrypto } from "@effect/platform-node";
1
+ import * as NodeCrypto from "@effect/platform-node/NodeCrypto";
2
2
  import { Context, Layer } from "effect";
3
3
  import { appHostHttp, deferredHost, migratedHost } from "#appHostHttp.ts";
4
4
  import { databaseLayer } from "#databaseLayer.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"appHost.js","sourceRoot":"","sources":["../src/appHost.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAe,KAAK,EAAE,MAAM,QAAQ,CAAC;AAMrD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAuB,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAIvE,MAAM,OAAO,UAAW,SAAQ,OAAO,CAAC,OAAO,EAAqD,CAAC,8BAA8B,CAAC;CAAG;AAMvI,MAAM,UAAU,WAAW,CAAI,OAA8B;IAC5D,OAAO,aAAa,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAC3C,CAAC;AAiED,MAAM,CAAC,MAAM,OAAO,GAAmB,CAkBtC,OAiBC,EACA,EAAE;IACH,IAAI,aAAa,IAAI,OAAO,EAAE,CAAC;QAC9B,OAAO,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAC9E,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,EACpD,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAC/B,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC,UAAU,KAAK,SAAS;QACtC,CAAC,CAAC,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAC9H,CAAC,CAAC,YAAY,CAAC,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,WAAW,CAAC,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAC1I,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,EACpD,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAC/B,CAAC;AACL,CAAC,CAAC"}
1
+ {"version":3,"file":"appHost.js","sourceRoot":"","sources":["../src/appHost.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAe,KAAK,EAAE,MAAM,QAAQ,CAAC;AAMrD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAuB,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAIvE,MAAM,OAAO,UAAW,SAAQ,OAAO,CAAC,OAAO,EAAqD,CAAC,8BAA8B,CAAC;CAAG;AAMvI,MAAM,UAAU,WAAW,CAAI,OAA8B;IAC5D,OAAO,aAAa,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAC3C,CAAC;AAiED,MAAM,CAAC,MAAM,OAAO,GAAmB,CAkBtC,OAiBC,EACA,EAAE;IACH,IAAI,aAAa,IAAI,OAAO,EAAE,CAAC;QAC9B,OAAO,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAC9E,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,EACpD,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAC/B,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC,UAAU,KAAK,SAAS;QACtC,CAAC,CAAC,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAC9H,CAAC,CAAC,YAAY,CAAC,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,WAAW,CAAC,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAC1I,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,EACpD,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAC/B,CAAC;AACL,CAAC,CAAC"}