@replit/river 0.208.3 → 0.209.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 (59) hide show
  1. package/README.md +36 -1
  2. package/dist/{adapter-ChksXKVN.d.ts → adapter-Cp7_gIVA.d.ts} +1 -1
  3. package/dist/{adapter-Cuc4JtfV.d.cts → adapter-DjiEwOYi.d.cts} +1 -1
  4. package/dist/{chunk-M2B4PVR5.js → chunk-LPWARXI3.js} +2 -2
  5. package/dist/{chunk-JC4XN6NC.js → chunk-RATCBAZE.js} +199 -170
  6. package/dist/chunk-RATCBAZE.js.map +1 -0
  7. package/dist/{chunk-3WYK5ZRT.js → chunk-TVN2TB6X.js} +2 -2
  8. package/dist/{chunk-3WYK5ZRT.js.map → chunk-TVN2TB6X.js.map} +1 -1
  9. package/dist/client-BzJwq-hg.d.ts +54 -0
  10. package/dist/client-aETS93z1.d.cts +54 -0
  11. package/dist/codec/index.d.cts +3 -3
  12. package/dist/codec/index.d.ts +3 -3
  13. package/dist/codec/index.js +2 -2
  14. package/dist/{connection-Donr3JRB.d.ts → connection-b1wd5XrC.d.ts} +3 -3
  15. package/dist/{connection-BF4zg6Qv.d.cts → connection-hUWlS-hg.d.cts} +3 -3
  16. package/dist/{index-D8IOd3LG.d.ts → index-CSM8soK7.d.ts} +1 -1
  17. package/dist/{index-C9tpZjBN.d.cts → index-D9R6UTMl.d.cts} +1 -1
  18. package/dist/logging/index.d.cts +2 -2
  19. package/dist/logging/index.d.ts +2 -2
  20. package/dist/{message-Di94OL80.d.cts → message-Dlsh5WDF.d.cts} +1 -1
  21. package/dist/{message-Di94OL80.d.ts → message-Dlsh5WDF.d.ts} +1 -1
  22. package/dist/router/index.cjs +199 -170
  23. package/dist/router/index.cjs.map +1 -1
  24. package/dist/router/index.d.cts +21 -18
  25. package/dist/router/index.d.ts +21 -18
  26. package/dist/router/index.js +3 -3
  27. package/dist/server-BBgDVOzk.d.cts +72 -0
  28. package/dist/server-DZ0Yzmpf.d.ts +72 -0
  29. package/dist/services-DBvjc-Mq.d.ts +1010 -0
  30. package/dist/services-DC_uol9A.d.cts +1010 -0
  31. package/dist/testUtil/index.cjs +1 -1
  32. package/dist/testUtil/index.cjs.map +1 -1
  33. package/dist/testUtil/index.d.cts +9 -7
  34. package/dist/testUtil/index.d.ts +9 -7
  35. package/dist/testUtil/index.js +2 -2
  36. package/dist/testUtil/index.js.map +1 -1
  37. package/dist/transport/impls/ws/client.cjs +1 -1
  38. package/dist/transport/impls/ws/client.cjs.map +1 -1
  39. package/dist/transport/impls/ws/client.d.cts +6 -5
  40. package/dist/transport/impls/ws/client.d.ts +6 -5
  41. package/dist/transport/impls/ws/client.js +3 -3
  42. package/dist/transport/impls/ws/server.cjs +1 -1
  43. package/dist/transport/impls/ws/server.cjs.map +1 -1
  44. package/dist/transport/impls/ws/server.d.cts +8 -8
  45. package/dist/transport/impls/ws/server.d.ts +8 -8
  46. package/dist/transport/impls/ws/server.js +3 -3
  47. package/dist/transport/impls/ws/server.js.map +1 -1
  48. package/dist/transport/index.cjs +1 -1
  49. package/dist/transport/index.cjs.map +1 -1
  50. package/dist/transport/index.d.cts +7 -74
  51. package/dist/transport/index.d.ts +7 -74
  52. package/dist/transport/index.js +2 -2
  53. package/dist/transport-CxjUaGhi.d.cts +577 -0
  54. package/dist/transport-DwEB67zY.d.ts +577 -0
  55. package/package.json +1 -1
  56. package/dist/chunk-JC4XN6NC.js.map +0 -1
  57. package/dist/transport-CCaWx1Rb.d.cts +0 -1566
  58. package/dist/transport-CZb3vdB4.d.ts +0 -1566
  59. /package/dist/{chunk-M2B4PVR5.js.map → chunk-LPWARXI3.js.map} +0 -0
package/README.md CHANGED
@@ -272,4 +272,39 @@ You can find more service examples in the [E2E test fixtures](https://github.com
272
272
  - `npm run check` -- lint
273
273
  - `npm run format` -- format
274
274
  - `npm run test` -- run tests
275
- - `npm run publish` -- cut a new release (should bump version in package.json first)
275
+ - `npm run release` -- cut a new release (should bump version in package.json first)
276
+
277
+ ## Releasing
278
+
279
+ River uses an automated release process with [Release Drafter](https://github.com/release-drafter/release-drafter) for version management and NPM publishing.
280
+
281
+ ### Automated Release Process (Recommended)
282
+
283
+ 1. **Merge PRs to main** - Release Drafter automatically:
284
+
285
+ - Updates the draft release notes with PR titles
286
+ - You can view the draft at [GitHub Releases](../../releases)
287
+
288
+ 2. **When ready to release, create a version bump PR**:
289
+
290
+ - Create a PR that bumps the version in `package.json` and `package-lock.json`. You can run `pnpm version --no-git-tag-version <version>` to bump the version.
291
+ - Use semantic versioning:
292
+ - `patch` - Bug fixes, small improvements (e.g., 0.208.4 → 0.208.5)
293
+ - `minor` - New features, backwards compatible (e.g., 0.208.4 → 0.209.0)
294
+ - `major` - Breaking changes (e.g., 0.208.4 → 1.0.0)
295
+ - Merge the PR to main
296
+
297
+ 3. **Publish the GitHub release**:
298
+
299
+ - Go to [GitHub Releases](../../releases)
300
+ - Find the draft release and click "Edit"
301
+ - Update the tag to match your new version (e.g., `v0.209.0`)
302
+ - Click "Publish release"
303
+
304
+ 4. **Automation takes over**:
305
+
306
+ - Publishing the release automatically triggers the "Build and Publish" workflow
307
+ - The `river` package is published to NPM
308
+
309
+ 5. **Manual npm release**:
310
+ - If the auto-publish workflow failed, you can run `npm run release` locally
@@ -1,4 +1,4 @@
1
- import { O as OpaqueTransportMessage } from './message-Di94OL80.js';
1
+ import { b as OpaqueTransportMessage } from './message-Dlsh5WDF.js';
2
2
 
3
3
  /**
4
4
  * Codec interface for encoding and decoding objects to and from Uint8 buffers.
@@ -1,4 +1,4 @@
1
- import { O as OpaqueTransportMessage } from './message-Di94OL80.cjs';
1
+ import { b as OpaqueTransportMessage } from './message-Dlsh5WDF.cjs';
2
2
 
3
3
  /**
4
4
  * Codec interface for encoding and decoding objects to and from Uint8 buffers.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Connection
3
- } from "./chunk-3WYK5ZRT.js";
3
+ } from "./chunk-TVN2TB6X.js";
4
4
 
5
5
  // transport/impls/ws/connection.ts
6
6
  var WS_HEALTHY_CLOSE_CODE = 1e3;
@@ -52,4 +52,4 @@ var WebSocketConnection = class extends Connection {
52
52
  export {
53
53
  WebSocketConnection
54
54
  };
55
- //# sourceMappingURL=chunk-M2B4PVR5.js.map
55
+ //# sourceMappingURL=chunk-LPWARXI3.js.map
@@ -107,182 +107,184 @@ function serializeSchema(services, handshakeSchema) {
107
107
  }
108
108
  return schema;
109
109
  }
110
- var ServiceSchema = class _ServiceSchema {
111
- /**
112
- * Factory function for creating a fresh state.
113
- */
114
- initializeState;
115
- /**
116
- * The procedures for this service.
117
- */
118
- procedures;
119
- /**
120
- * @param config - The configuration for this service.
121
- * @param procedures - The procedures for this service.
122
- */
123
- constructor(config, procedures) {
124
- this.initializeState = config.initializeState;
125
- this.procedures = procedures;
126
- }
127
- /**
128
- * Creates a {@link ServiceScaffold}, which can be used to define procedures
129
- * that can then be merged into a {@link ServiceSchema}, via the scaffold's
130
- * `finalize` method.
131
- *
132
- * There are two patterns that work well with this method. The first is using
133
- * it to separate the definition of procedures from the definition of the
134
- * service's configuration:
135
- * ```ts
136
- * const MyServiceScaffold = ServiceSchema.scaffold({
137
- * initializeState: () => ({ count: 0 }),
138
- * });
139
- *
140
- * const incrementProcedures = MyServiceScaffold.procedures({
141
- * increment: Procedure.rpc({
142
- * requestInit: Type.Object({ amount: Type.Number() }),
143
- * responseData: Type.Object({ current: Type.Number() }),
144
- * async handler(ctx, init) {
145
- * ctx.state.count += init.amount;
146
- * return Ok({ current: ctx.state.count });
147
- * }
148
- * }),
149
- * })
150
- *
151
- * const MyService = MyServiceScaffold.finalize({
152
- * ...incrementProcedures,
153
- * // you can also directly define procedures here
154
- * });
155
- * ```
156
- * This might be really handy if you have a very large service and you're
157
- * wanting to split it over multiple files. You can define the scaffold
158
- * in one file, and then import that scaffold in other files where you
159
- * define procedures - and then finally import the scaffolds and your
160
- * procedure objects in a final file where you finalize the scaffold into
161
- * a service schema.
162
- *
163
- * The other way is to use it like in a builder pattern:
164
- * ```ts
165
- * const MyService = ServiceSchema
166
- * .scaffold({ initializeState: () => ({ count: 0 }) })
167
- * .finalize({
168
- * increment: Procedure.rpc({
169
- * requestInit: Type.Object({ amount: Type.Number() }),
170
- * responseData: Type.Object({ current: Type.Number() }),
171
- * async handler(ctx, init) {
172
- * ctx.state.count += init.amount;
173
- * return Ok({ current: ctx.state.count });
174
- * }
175
- * }),
176
- * })
177
- * ```
178
- * Depending on your preferences, this may be a more appealing way to define
179
- * a schema versus using the {@link ServiceSchema.define} method.
180
- */
181
- static scaffold(config) {
182
- return new ServiceScaffold(config);
183
- }
184
- // actual implementation
185
- static define(configOrProcedures, maybeProcedures) {
186
- let config;
187
- let procedures;
188
- if ("initializeState" in configOrProcedures && typeof configOrProcedures.initializeState === "function") {
189
- if (!maybeProcedures) {
190
- throw new Error("Expected procedures to be defined");
110
+ function createServiceSchema() {
111
+ return class ServiceSchema {
112
+ /**
113
+ * Factory function for creating a fresh state.
114
+ */
115
+ initializeState;
116
+ /**
117
+ * The procedures for this service.
118
+ */
119
+ procedures;
120
+ /**
121
+ * @param config - The configuration for this service.
122
+ * @param procedures - The procedures for this service.
123
+ */
124
+ constructor(config, procedures) {
125
+ this.initializeState = config.initializeState;
126
+ this.procedures = procedures;
127
+ }
128
+ /**
129
+ * Creates a {@link ServiceScaffold}, which can be used to define procedures
130
+ * that can then be merged into a {@link ServiceSchema}, via the scaffold's
131
+ * `finalize` method.
132
+ *
133
+ * There are two patterns that work well with this method. The first is using
134
+ * it to separate the definition of procedures from the definition of the
135
+ * service's configuration:
136
+ * ```ts
137
+ * const MyServiceScaffold = ServiceSchema.scaffold({
138
+ * initializeState: () => ({ count: 0 }),
139
+ * });
140
+ *
141
+ * const incrementProcedures = MyServiceScaffold.procedures({
142
+ * increment: Procedure.rpc({
143
+ * requestInit: Type.Object({ amount: Type.Number() }),
144
+ * responseData: Type.Object({ current: Type.Number() }),
145
+ * async handler(ctx, init) {
146
+ * ctx.state.count += init.amount;
147
+ * return Ok({ current: ctx.state.count });
148
+ * }
149
+ * }),
150
+ * })
151
+ *
152
+ * const MyService = MyServiceScaffold.finalize({
153
+ * ...incrementProcedures,
154
+ * // you can also directly define procedures here
155
+ * });
156
+ * ```
157
+ * This might be really handy if you have a very large service and you're
158
+ * wanting to split it over multiple files. You can define the scaffold
159
+ * in one file, and then import that scaffold in other files where you
160
+ * define procedures - and then finally import the scaffolds and your
161
+ * procedure objects in a final file where you finalize the scaffold into
162
+ * a service schema.
163
+ *
164
+ * The other way is to use it like in a builder pattern:
165
+ * ```ts
166
+ * const MyService = ServiceSchema
167
+ * .scaffold({ initializeState: () => ({ count: 0 }) })
168
+ * .finalize({
169
+ * increment: Procedure.rpc({
170
+ * requestInit: Type.Object({ amount: Type.Number() }),
171
+ * responseData: Type.Object({ current: Type.Number() }),
172
+ * async handler(ctx, init) {
173
+ * ctx.state.count += init.amount;
174
+ * return Ok({ current: ctx.state.count });
175
+ * }
176
+ * }),
177
+ * })
178
+ * ```
179
+ * Depending on your preferences, this may be a more appealing way to define
180
+ * a schema versus using the {@link ServiceSchema.define} method.
181
+ */
182
+ static scaffold(config) {
183
+ return new ServiceScaffold(config);
184
+ }
185
+ // actual implementation
186
+ static define(configOrProcedures, maybeProcedures) {
187
+ let config;
188
+ let procedures;
189
+ if ("initializeState" in configOrProcedures && typeof configOrProcedures.initializeState === "function") {
190
+ if (!maybeProcedures) {
191
+ throw new Error("Expected procedures to be defined");
192
+ }
193
+ config = configOrProcedures;
194
+ procedures = maybeProcedures;
195
+ } else {
196
+ config = { initializeState: () => ({}) };
197
+ procedures = configOrProcedures;
191
198
  }
192
- config = configOrProcedures;
193
- procedures = maybeProcedures;
194
- } else {
195
- config = { initializeState: () => ({}) };
196
- procedures = configOrProcedures;
199
+ return new ServiceSchema(config, procedures);
197
200
  }
198
- return new _ServiceSchema(config, procedures);
199
- }
200
- /**
201
- * Serializes this schema's procedures into a plain object that is JSON compatible.
202
- */
203
- serialize() {
204
- return {
205
- procedures: Object.fromEntries(
206
- Object.entries(this.procedures).map(([procName, procDef]) => [
207
- procName,
208
- {
209
- init: Strict(procDef.requestInit),
210
- output: Strict(procDef.responseData),
211
- errors: getSerializedProcErrors(procDef),
212
- // Only add `description` field if the type declares it.
213
- ..."description" in procDef ? { description: procDef.description } : {},
214
- type: procDef.type,
215
- // Only add the `input` field if the type declares it.
216
- ..."requestData" in procDef ? {
217
- input: Strict(procDef.requestData)
218
- } : {}
219
- }
220
- ])
221
- )
222
- };
223
- }
224
- // TODO remove once clients migrate to v2
225
- /**
226
- * Same as {@link ServiceSchema.serialize}, but with a format that is compatible with
227
- * protocol v1. This is useful to be able to continue to generate schemas for older
228
- * clients as they are still supported.
229
- */
230
- serializeV1Compat() {
231
- return {
232
- procedures: Object.fromEntries(
233
- Object.entries(this.procedures).map(
234
- ([procName, procDef]) => {
235
- if (procDef.type === "rpc" || procDef.type === "subscription") {
201
+ /**
202
+ * Serializes this schema's procedures into a plain object that is JSON compatible.
203
+ */
204
+ serialize() {
205
+ return {
206
+ procedures: Object.fromEntries(
207
+ Object.entries(this.procedures).map(([procName, procDef]) => [
208
+ procName,
209
+ {
210
+ init: Strict(procDef.requestInit),
211
+ output: Strict(procDef.responseData),
212
+ errors: getSerializedProcErrors(procDef),
213
+ // Only add `description` field if the type declares it.
214
+ ..."description" in procDef ? { description: procDef.description } : {},
215
+ type: procDef.type,
216
+ // Only add the `input` field if the type declares it.
217
+ ..."requestData" in procDef ? {
218
+ input: Strict(procDef.requestData)
219
+ } : {}
220
+ }
221
+ ])
222
+ )
223
+ };
224
+ }
225
+ // TODO remove once clients migrate to v2
226
+ /**
227
+ * Same as {@link ServiceSchema.serialize}, but with a format that is compatible with
228
+ * protocol v1. This is useful to be able to continue to generate schemas for older
229
+ * clients as they are still supported.
230
+ */
231
+ serializeV1Compat() {
232
+ return {
233
+ procedures: Object.fromEntries(
234
+ Object.entries(this.procedures).map(
235
+ ([procName, procDef]) => {
236
+ if (procDef.type === "rpc" || procDef.type === "subscription") {
237
+ return [
238
+ procName,
239
+ {
240
+ // BACKWARDS COMPAT: map init to input for protocolv1
241
+ // this is the only change needed to make it compatible.
242
+ input: Strict(procDef.requestInit),
243
+ output: Strict(procDef.responseData),
244
+ errors: getSerializedProcErrors(procDef),
245
+ // Only add `description` field if the type declares it.
246
+ ..."description" in procDef ? { description: procDef.description } : {},
247
+ type: procDef.type
248
+ }
249
+ ];
250
+ }
236
251
  return [
237
252
  procName,
238
253
  {
239
- // BACKWARDS COMPAT: map init to input for protocolv1
240
- // this is the only change needed to make it compatible.
241
- input: Strict(procDef.requestInit),
254
+ init: Strict(procDef.requestInit),
242
255
  output: Strict(procDef.responseData),
243
256
  errors: getSerializedProcErrors(procDef),
244
257
  // Only add `description` field if the type declares it.
245
258
  ..."description" in procDef ? { description: procDef.description } : {},
246
- type: procDef.type
259
+ type: procDef.type,
260
+ input: Strict(procDef.requestData)
247
261
  }
248
262
  ];
249
263
  }
250
- return [
251
- procName,
252
- {
253
- init: Strict(procDef.requestInit),
254
- output: Strict(procDef.responseData),
255
- errors: getSerializedProcErrors(procDef),
256
- // Only add `description` field if the type declares it.
257
- ..."description" in procDef ? { description: procDef.description } : {},
258
- type: procDef.type,
259
- input: Strict(procDef.requestData)
260
- }
261
- ];
262
- }
264
+ )
263
265
  )
264
- )
265
- };
266
- }
267
- /**
268
- * Instantiates this schema into a {@link Service} object.
269
- *
270
- * You probably don't need this, usually the River server will handle this
271
- * for you.
272
- */
273
- instantiate(extendedContext) {
274
- const state = this.initializeState(extendedContext);
275
- const dispose = async () => {
276
- await state[Symbol.asyncDispose]?.();
277
- state[Symbol.dispose]?.();
278
- };
279
- return Object.freeze({
280
- state,
281
- procedures: this.procedures,
282
- [Symbol.asyncDispose]: dispose
283
- });
284
- }
285
- };
266
+ };
267
+ }
268
+ /**
269
+ * Instantiates this schema into a {@link Service} object.
270
+ *
271
+ * You probably don't need this, usually the River server will handle this
272
+ * for you.
273
+ */
274
+ instantiate(extendedContext) {
275
+ const state = this.initializeState(extendedContext);
276
+ const dispose = async () => {
277
+ await state[Symbol.asyncDispose]?.();
278
+ state[Symbol.dispose]?.();
279
+ };
280
+ return Object.freeze({
281
+ state,
282
+ procedures: this.procedures,
283
+ [Symbol.asyncDispose]: dispose
284
+ });
285
+ }
286
+ };
287
+ }
286
288
  function getSerializedProcErrors(procDef) {
287
289
  if (!("responseError" in procDef) || procDef.responseError[Kind2] === "Never") {
288
290
  return Strict(ReaderErrorSchema);
@@ -345,7 +347,10 @@ var ServiceScaffold = class {
345
347
  * ```
346
348
  */
347
349
  finalize(procedures) {
348
- return ServiceSchema.define(this.config, procedures);
350
+ return createServiceSchema().define(
351
+ this.config,
352
+ procedures
353
+ );
349
354
  }
350
355
  };
351
356
 
@@ -1019,6 +1024,9 @@ function createClient(transport, serverId, providedClientOptions = {}) {
1019
1024
  }, []);
1020
1025
  }
1021
1026
  function handleProc(procType, transport, serverId, init, serviceName, procedureName, abortSignal) {
1027
+ if (transport.getStatus() === "closed") {
1028
+ return getPreClosedReturnForProc(procType);
1029
+ }
1022
1030
  const session = transport.sessions.get(serverId) ?? transport.createUnconnectedSession(serverId);
1023
1031
  const sessionScopedSend = transport.getSessionBoundSendFn(
1024
1032
  serverId,
@@ -1195,13 +1203,33 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
1195
1203
  if (procClosesWithInit) {
1196
1204
  reqWritable.close();
1197
1205
  }
1206
+ return getReturnForProc(procType, resReadable, reqWritable, transport.log);
1207
+ }
1208
+ function getPreClosedReturnForProc(procType) {
1209
+ const readable = new ReadableImpl();
1210
+ const err = Err({
1211
+ code: UNEXPECTED_DISCONNECT_CODE,
1212
+ message: `transport is closed`
1213
+ });
1214
+ readable._pushValue(err);
1215
+ readable._triggerClose();
1216
+ const writable = new WritableImpl({
1217
+ writeCb: () => {
1218
+ },
1219
+ closeCb: () => {
1220
+ }
1221
+ });
1222
+ writable.close();
1223
+ return getReturnForProc(procType, readable, writable);
1224
+ }
1225
+ function getReturnForProc(procType, resReadable, reqWritable, log) {
1198
1226
  if (procType === "subscription") {
1199
1227
  return {
1200
1228
  resReadable
1201
1229
  };
1202
1230
  }
1203
1231
  if (procType === "rpc") {
1204
- return getSingleMessage(resReadable, transport.log);
1232
+ return getSingleMessage(resReadable, log);
1205
1233
  }
1206
1234
  if (procType === "upload") {
1207
1235
  let didFinalize = false;
@@ -1215,7 +1243,7 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
1215
1243
  if (!reqWritable.isClosed()) {
1216
1244
  reqWritable.close();
1217
1245
  }
1218
- return getSingleMessage(resReadable, transport.log);
1246
+ return getSingleMessage(resReadable, log);
1219
1247
  }
1220
1248
  };
1221
1249
  }
@@ -1266,8 +1294,9 @@ var RiverServer = class {
1266
1294
  this.middlewares = middlewares;
1267
1295
  this.services = instances;
1268
1296
  this.contextMap = /* @__PURE__ */ new Map();
1297
+ extendedContext = extendedContext ?? {};
1269
1298
  for (const [name, service] of Object.entries(services)) {
1270
- const instance = service.instantiate(extendedContext ?? {});
1299
+ const instance = service.instantiate(extendedContext);
1271
1300
  instances[name] = instance;
1272
1301
  this.contextMap.set(instance, {
1273
1302
  ...extendedContext,
@@ -1950,7 +1979,7 @@ function createServerHandshakeOptions(schema, validate) {
1950
1979
  }
1951
1980
 
1952
1981
  // package.json
1953
- var version = "0.208.3";
1982
+ var version = "0.209.0";
1954
1983
 
1955
1984
  export {
1956
1985
  generateId,
@@ -1974,7 +2003,7 @@ export {
1974
2003
  flattenErrorType,
1975
2004
  serializeSchemaV1Compat,
1976
2005
  serializeSchema,
1977
- ServiceSchema,
2006
+ createServiceSchema,
1978
2007
  Procedure,
1979
2008
  Ok,
1980
2009
  Err,
@@ -1989,4 +2018,4 @@ export {
1989
2018
  createConnectionTelemetryInfo,
1990
2019
  getTracer
1991
2020
  };
1992
- //# sourceMappingURL=chunk-JC4XN6NC.js.map
2021
+ //# sourceMappingURL=chunk-RATCBAZE.js.map