@orpc/shared 0.0.0-next.346e220 → 0.0.0-next.347f023

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
@@ -31,7 +31,7 @@
31
31
  - **📘 First-Class OpenAPI**: Built-in support that fully adheres to the OpenAPI standard.
32
32
  - **📝 Contract-First Development**: Optionally define your API contract before implementation.
33
33
  - **🔍 First-Class OpenTelemetry**: Seamlessly integrate with OpenTelemetry for observability.
34
- - **⚙️ Framework Integrations**: Seamlessly integrate with TanStack Query (React, Vue, Solid, Svelte, Angular), Pinia Colada, and more.
34
+ - **⚙️ Framework Integrations**: Seamlessly integrate with TanStack Query (React, Vue, Solid, Svelte, Angular), SWR, Pinia Colada, and more.
35
35
  - **🚀 Server Actions**: Fully compatible with React Server Actions on Next.js, TanStack Start, and other platforms.
36
36
  - **🔠 Standard Schema Support**: Works out of the box with Zod, Valibot, ArkType, and other schema validators.
37
37
  - **🗃️ Native Types**: Supports native types like Date, File, Blob, BigInt, URL, and more.
@@ -54,6 +54,7 @@ You can find the full documentation [here](https://orpc.unnoq.com).
54
54
  - [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Deeply integrate oRPC with [NestJS](https://nestjs.com/).
55
55
  - [@orpc/react](https://www.npmjs.com/package/@orpc/react): Utilities for integrating oRPC with React and React Server Actions.
56
56
  - [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query): [TanStack Query](https://tanstack.com/query/latest) integration.
57
+ - [@orpc/experimental-react-swr](https://www.npmjs.com/package/@orpc/experimental-react-swr): [SWR](https://swr.vercel.app/) integration.
57
58
  - [@orpc/vue-colada](https://www.npmjs.com/package/@orpc/vue-colada): Integration with [Pinia Colada](https://pinia-colada.esm.dev/).
58
59
  - [@orpc/hey-api](https://www.npmjs.com/package/@orpc/hey-api): [Hey API](https://heyapi.dev/) integration.
59
60
  - [@orpc/zod](https://www.npmjs.com/package/@orpc/zod): More schemas that [Zod](https://zod.dev/) doesn't support yet.
package/dist/index.d.mts CHANGED
@@ -30,7 +30,7 @@ type OmitChainMethodDeep<T extends object, K extends keyof any> = {
30
30
 
31
31
  declare const ORPC_NAME = "orpc";
32
32
  declare const ORPC_SHARED_PACKAGE_NAME = "@orpc/shared";
33
- declare const ORPC_SHARED_PACKAGE_VERSION = "0.0.0-next.346e220";
33
+ declare const ORPC_SHARED_PACKAGE_VERSION = "0.0.0-next.347f023";
34
34
 
35
35
  /**
36
36
  * Error thrown when an operation is aborted.
@@ -121,6 +121,7 @@ interface Registry {
121
121
  type ThrowableError = Registry extends {
122
122
  throwableError: infer T;
123
123
  } ? T : Error;
124
+ type InferAsyncIterableYield<T> = T extends AsyncIterable<infer U> ? U : never;
124
125
 
125
126
  type InterceptableOptions = Record<string, any>;
126
127
  type InterceptorOptions<TOptions extends InterceptableOptions, TResult> = Omit<TOptions, 'next'> & {
@@ -277,15 +278,24 @@ declare const NullProtoObj: ({
277
278
  new <T extends Record<PropertyKey, unknown>>(): T;
278
279
  });
279
280
 
281
+ /**
282
+ * Prevents objects from being awaitable by intercepting the `then` method
283
+ * when called by the native await mechanism. This is useful for preventing
284
+ * accidental awaiting of objects that aren't meant to be promises.
285
+ */
286
+ declare function preventNativeAwait<T extends object>(target: T): T;
287
+
280
288
  interface AsyncIdQueueCloseOptions {
281
289
  id?: string;
282
290
  reason?: unknown;
283
291
  }
284
292
  declare class AsyncIdQueue<T> {
285
293
  private readonly openIds;
286
- private readonly items;
287
- private readonly pendingPulls;
294
+ private readonly queues;
295
+ private readonly waiters;
288
296
  get length(): number;
297
+ get waiterIds(): string[];
298
+ hasBufferedItems(id: string): boolean;
289
299
  open(id: string): void;
290
300
  isOpen(id: string): boolean;
291
301
  push(id: string, item: T): void;
@@ -302,5 +312,5 @@ declare function tryDecodeURIComponent(value: string): string;
302
312
  type Value<T, TArgs extends any[] = []> = T | ((...args: TArgs) => T);
303
313
  declare function value<T, TArgs extends any[]>(value: Value<T, TArgs>, ...args: NoInfer<TArgs>): T extends Value<infer U, any> ? U : never;
304
314
 
305
- export { AbortError, AsyncIdQueue, AsyncIteratorClass, EventPublisher, NullProtoObj, ORPC_NAME, ORPC_SHARED_PACKAGE_NAME, ORPC_SHARED_PACKAGE_VERSION, SequentialIdGenerator, asyncIteratorToStream, asyncIteratorWithSpan, clone, defer, findDeepMatches, get, getGlobalOtelConfig, intercept, isAsyncIteratorObject, isObject, isPropertyKey, isTypescriptObject, onError, onFinish, onStart, onSuccess, once, parseEmptyableJSON, readAsBuffer, replicateAsyncIterator, resolveMaybeOptionalOptions, runInSpanContext, runWithSpan, sequential, setGlobalOtelConfig, setSpanAttribute, setSpanError, splitInHalf, startSpan, streamToAsyncIteratorClass, stringifyJSON, toArray, toOtelException, toSpanAttributeValue, tryDecodeURIComponent, value };
306
- export type { AnyFunction, AsyncIdQueueCloseOptions, AsyncIteratorClassCleanupFn, AsyncIteratorClassNextFn, AsyncIteratorWithSpanOptions, EventPublisherOptions, EventPublisherSubscribeIteratorOptions, InterceptableOptions, Interceptor, InterceptorOptions, IntersectPick, MaybeOptionalOptions, OmitChainMethodDeep, OnFinishState, OtelConfig, PromiseWithError, Registry, RunWithSpanOptions, Segment, SetOptional, SetSpanErrorOptions, ThrowableError, Value };
315
+ export { AbortError, AsyncIdQueue, AsyncIteratorClass, EventPublisher, NullProtoObj, ORPC_NAME, ORPC_SHARED_PACKAGE_NAME, ORPC_SHARED_PACKAGE_VERSION, SequentialIdGenerator, asyncIteratorToStream, asyncIteratorWithSpan, clone, defer, findDeepMatches, get, getGlobalOtelConfig, intercept, isAsyncIteratorObject, isObject, isPropertyKey, isTypescriptObject, onError, onFinish, onStart, onSuccess, once, parseEmptyableJSON, preventNativeAwait, readAsBuffer, replicateAsyncIterator, resolveMaybeOptionalOptions, runInSpanContext, runWithSpan, sequential, setGlobalOtelConfig, setSpanAttribute, setSpanError, splitInHalf, startSpan, streamToAsyncIteratorClass, stringifyJSON, toArray, toOtelException, toSpanAttributeValue, tryDecodeURIComponent, value };
316
+ export type { AnyFunction, AsyncIdQueueCloseOptions, AsyncIteratorClassCleanupFn, AsyncIteratorClassNextFn, AsyncIteratorWithSpanOptions, EventPublisherOptions, EventPublisherSubscribeIteratorOptions, InferAsyncIterableYield, InterceptableOptions, Interceptor, InterceptorOptions, IntersectPick, MaybeOptionalOptions, OmitChainMethodDeep, OnFinishState, OtelConfig, PromiseWithError, Registry, RunWithSpanOptions, Segment, SetOptional, SetSpanErrorOptions, ThrowableError, Value };
package/dist/index.d.ts CHANGED
@@ -30,7 +30,7 @@ type OmitChainMethodDeep<T extends object, K extends keyof any> = {
30
30
 
31
31
  declare const ORPC_NAME = "orpc";
32
32
  declare const ORPC_SHARED_PACKAGE_NAME = "@orpc/shared";
33
- declare const ORPC_SHARED_PACKAGE_VERSION = "0.0.0-next.346e220";
33
+ declare const ORPC_SHARED_PACKAGE_VERSION = "0.0.0-next.347f023";
34
34
 
35
35
  /**
36
36
  * Error thrown when an operation is aborted.
@@ -121,6 +121,7 @@ interface Registry {
121
121
  type ThrowableError = Registry extends {
122
122
  throwableError: infer T;
123
123
  } ? T : Error;
124
+ type InferAsyncIterableYield<T> = T extends AsyncIterable<infer U> ? U : never;
124
125
 
125
126
  type InterceptableOptions = Record<string, any>;
126
127
  type InterceptorOptions<TOptions extends InterceptableOptions, TResult> = Omit<TOptions, 'next'> & {
@@ -277,15 +278,24 @@ declare const NullProtoObj: ({
277
278
  new <T extends Record<PropertyKey, unknown>>(): T;
278
279
  });
279
280
 
281
+ /**
282
+ * Prevents objects from being awaitable by intercepting the `then` method
283
+ * when called by the native await mechanism. This is useful for preventing
284
+ * accidental awaiting of objects that aren't meant to be promises.
285
+ */
286
+ declare function preventNativeAwait<T extends object>(target: T): T;
287
+
280
288
  interface AsyncIdQueueCloseOptions {
281
289
  id?: string;
282
290
  reason?: unknown;
283
291
  }
284
292
  declare class AsyncIdQueue<T> {
285
293
  private readonly openIds;
286
- private readonly items;
287
- private readonly pendingPulls;
294
+ private readonly queues;
295
+ private readonly waiters;
288
296
  get length(): number;
297
+ get waiterIds(): string[];
298
+ hasBufferedItems(id: string): boolean;
289
299
  open(id: string): void;
290
300
  isOpen(id: string): boolean;
291
301
  push(id: string, item: T): void;
@@ -302,5 +312,5 @@ declare function tryDecodeURIComponent(value: string): string;
302
312
  type Value<T, TArgs extends any[] = []> = T | ((...args: TArgs) => T);
303
313
  declare function value<T, TArgs extends any[]>(value: Value<T, TArgs>, ...args: NoInfer<TArgs>): T extends Value<infer U, any> ? U : never;
304
314
 
305
- export { AbortError, AsyncIdQueue, AsyncIteratorClass, EventPublisher, NullProtoObj, ORPC_NAME, ORPC_SHARED_PACKAGE_NAME, ORPC_SHARED_PACKAGE_VERSION, SequentialIdGenerator, asyncIteratorToStream, asyncIteratorWithSpan, clone, defer, findDeepMatches, get, getGlobalOtelConfig, intercept, isAsyncIteratorObject, isObject, isPropertyKey, isTypescriptObject, onError, onFinish, onStart, onSuccess, once, parseEmptyableJSON, readAsBuffer, replicateAsyncIterator, resolveMaybeOptionalOptions, runInSpanContext, runWithSpan, sequential, setGlobalOtelConfig, setSpanAttribute, setSpanError, splitInHalf, startSpan, streamToAsyncIteratorClass, stringifyJSON, toArray, toOtelException, toSpanAttributeValue, tryDecodeURIComponent, value };
306
- export type { AnyFunction, AsyncIdQueueCloseOptions, AsyncIteratorClassCleanupFn, AsyncIteratorClassNextFn, AsyncIteratorWithSpanOptions, EventPublisherOptions, EventPublisherSubscribeIteratorOptions, InterceptableOptions, Interceptor, InterceptorOptions, IntersectPick, MaybeOptionalOptions, OmitChainMethodDeep, OnFinishState, OtelConfig, PromiseWithError, Registry, RunWithSpanOptions, Segment, SetOptional, SetSpanErrorOptions, ThrowableError, Value };
315
+ export { AbortError, AsyncIdQueue, AsyncIteratorClass, EventPublisher, NullProtoObj, ORPC_NAME, ORPC_SHARED_PACKAGE_NAME, ORPC_SHARED_PACKAGE_VERSION, SequentialIdGenerator, asyncIteratorToStream, asyncIteratorWithSpan, clone, defer, findDeepMatches, get, getGlobalOtelConfig, intercept, isAsyncIteratorObject, isObject, isPropertyKey, isTypescriptObject, onError, onFinish, onStart, onSuccess, once, parseEmptyableJSON, preventNativeAwait, readAsBuffer, replicateAsyncIterator, resolveMaybeOptionalOptions, runInSpanContext, runWithSpan, sequential, setGlobalOtelConfig, setSpanAttribute, setSpanError, splitInHalf, startSpan, streamToAsyncIteratorClass, stringifyJSON, toArray, toOtelException, toSpanAttributeValue, tryDecodeURIComponent, value };
316
+ export type { AnyFunction, AsyncIdQueueCloseOptions, AsyncIteratorClassCleanupFn, AsyncIteratorClassNextFn, AsyncIteratorWithSpanOptions, EventPublisherOptions, EventPublisherSubscribeIteratorOptions, InferAsyncIterableYield, InterceptableOptions, Interceptor, InterceptorOptions, IntersectPick, MaybeOptionalOptions, OmitChainMethodDeep, OnFinishState, OtelConfig, PromiseWithError, Registry, RunWithSpanOptions, Segment, SetOptional, SetSpanErrorOptions, ThrowableError, Value };
package/dist/index.mjs CHANGED
@@ -21,7 +21,7 @@ function readAsBuffer(source) {
21
21
 
22
22
  const ORPC_NAME = "orpc";
23
23
  const ORPC_SHARED_PACKAGE_NAME = "@orpc/shared";
24
- const ORPC_SHARED_PACKAGE_VERSION = "0.0.0-next.346e220";
24
+ const ORPC_SHARED_PACKAGE_VERSION = "0.0.0-next.347f023";
25
25
 
26
26
  class AbortError extends Error {
27
27
  constructor(...rest) {
@@ -153,11 +153,17 @@ async function runInSpanContext(span, fn) {
153
153
 
154
154
  class AsyncIdQueue {
155
155
  openIds = /* @__PURE__ */ new Set();
156
- items = /* @__PURE__ */ new Map();
157
- pendingPulls = /* @__PURE__ */ new Map();
156
+ queues = /* @__PURE__ */ new Map();
157
+ waiters = /* @__PURE__ */ new Map();
158
158
  get length() {
159
159
  return this.openIds.size;
160
160
  }
161
+ get waiterIds() {
162
+ return Array.from(this.waiters.keys());
163
+ }
164
+ hasBufferedItems(id) {
165
+ return Boolean(this.queues.get(id)?.length);
166
+ }
161
167
  open(id) {
162
168
  this.openIds.add(id);
163
169
  }
@@ -166,59 +172,59 @@ class AsyncIdQueue {
166
172
  }
167
173
  push(id, item) {
168
174
  this.assertOpen(id);
169
- const pending = this.pendingPulls.get(id);
175
+ const pending = this.waiters.get(id);
170
176
  if (pending?.length) {
171
177
  pending.shift()[0](item);
172
178
  if (pending.length === 0) {
173
- this.pendingPulls.delete(id);
179
+ this.waiters.delete(id);
174
180
  }
175
181
  } else {
176
- const items = this.items.get(id);
182
+ const items = this.queues.get(id);
177
183
  if (items) {
178
184
  items.push(item);
179
185
  } else {
180
- this.items.set(id, [item]);
186
+ this.queues.set(id, [item]);
181
187
  }
182
188
  }
183
189
  }
184
190
  async pull(id) {
185
191
  this.assertOpen(id);
186
- const items = this.items.get(id);
192
+ const items = this.queues.get(id);
187
193
  if (items?.length) {
188
194
  const item = items.shift();
189
195
  if (items.length === 0) {
190
- this.items.delete(id);
196
+ this.queues.delete(id);
191
197
  }
192
198
  return item;
193
199
  }
194
200
  return new Promise((resolve, reject) => {
195
- const waitingPulls = this.pendingPulls.get(id);
201
+ const waitingPulls = this.waiters.get(id);
196
202
  const pending = [resolve, reject];
197
203
  if (waitingPulls) {
198
204
  waitingPulls.push(pending);
199
205
  } else {
200
- this.pendingPulls.set(id, [pending]);
206
+ this.waiters.set(id, [pending]);
201
207
  }
202
208
  });
203
209
  }
204
210
  close({ id, reason } = {}) {
205
211
  if (id === void 0) {
206
- this.pendingPulls.forEach((pendingPulls, id2) => {
212
+ this.waiters.forEach((pendingPulls, id2) => {
207
213
  pendingPulls.forEach(([, reject]) => {
208
214
  reject(reason ?? new Error(`[AsyncIdQueue] Queue[${id2}] was closed or aborted while waiting for pulling.`));
209
215
  });
210
216
  });
211
- this.pendingPulls.clear();
217
+ this.waiters.clear();
212
218
  this.openIds.clear();
213
- this.items.clear();
219
+ this.queues.clear();
214
220
  return;
215
221
  }
216
- this.pendingPulls.get(id)?.forEach(([, reject]) => {
222
+ this.waiters.get(id)?.forEach(([, reject]) => {
217
223
  reject(reason ?? new Error(`[AsyncIdQueue] Queue[${id}] was closed or aborted while waiting for pulling.`));
218
224
  });
219
- this.pendingPulls.delete(id);
225
+ this.waiters.delete(id);
220
226
  this.openIds.delete(id);
221
- this.items.delete(id);
227
+ this.queues.delete(id);
222
228
  }
223
229
  assertOpen(id) {
224
230
  if (!this.isOpen(id)) {
@@ -304,37 +310,41 @@ function replicateAsyncIterator(source, count) {
304
310
  try {
305
311
  while (true) {
306
312
  const item = await source.next();
307
- for (let id = 0; id < count; id++) {
308
- if (queue.isOpen(id.toString())) {
309
- queue.push(id.toString(), item);
313
+ for (let i = 0; i < count; i++) {
314
+ const id = i.toString();
315
+ if (queue.isOpen(id)) {
316
+ queue.push(id, item);
310
317
  }
311
318
  }
312
319
  if (item.done) {
313
320
  break;
314
321
  }
315
322
  }
316
- } catch (e) {
317
- error = { value: e };
323
+ } catch (reason) {
324
+ error = { value: reason };
325
+ queue.waiterIds.forEach((id) => {
326
+ queue.close({ id, reason });
327
+ });
318
328
  }
319
329
  });
320
- for (let id = 0; id < count; id++) {
321
- queue.open(id.toString());
330
+ for (let i = 0; i < count; i++) {
331
+ const id = i.toString();
332
+ queue.open(id);
322
333
  replicated.push(new AsyncIteratorClass(
323
334
  () => {
324
335
  start();
325
336
  return new Promise((resolve, reject) => {
326
- queue.pull(id.toString()).then(resolve).catch(reject);
327
- defer(() => {
328
- if (error) {
329
- reject(error.value);
330
- }
331
- });
337
+ if (!error || queue.hasBufferedItems(id)) {
338
+ queue.pull(id).then(resolve).catch(reject);
339
+ } else {
340
+ reject(error.value);
341
+ }
332
342
  });
333
343
  },
334
344
  async (reason) => {
335
- queue.close({ id: id.toString() });
345
+ queue.close({ id });
336
346
  if (reason !== "next") {
337
- if (replicated.every((_, id2) => !queue.isOpen(id2.toString()))) {
347
+ if (!queue.length) {
338
348
  await source?.return?.();
339
349
  }
340
350
  }
@@ -581,6 +591,38 @@ const NullProtoObj = /* @__PURE__ */ (() => {
581
591
  return e;
582
592
  })();
583
593
 
594
+ function preventNativeAwait(target) {
595
+ return new Proxy(target, {
596
+ get(target2, prop, receiver) {
597
+ const value = Reflect.get(target2, prop, receiver);
598
+ if (prop !== "then" || typeof value !== "function") {
599
+ return value;
600
+ }
601
+ return new Proxy(value, {
602
+ apply(targetFn, thisArg, args) {
603
+ if (args.length !== 2 || args.some((arg) => !isNativeFunction(arg))) {
604
+ return Reflect.apply(targetFn, thisArg, args);
605
+ }
606
+ let shouldOmit = true;
607
+ args[0].call(thisArg, preventNativeAwait(new Proxy(target2, {
608
+ get: (target3, prop2, receiver2) => {
609
+ if (shouldOmit && prop2 === "then") {
610
+ shouldOmit = false;
611
+ return void 0;
612
+ }
613
+ return Reflect.get(target3, prop2, receiver2);
614
+ }
615
+ })));
616
+ }
617
+ });
618
+ }
619
+ });
620
+ }
621
+ const NATIVE_FUNCTION_REGEX = /^\s*function\s*\(\)\s*\{\s*\[native code\]\s*\}\s*$/;
622
+ function isNativeFunction(fn) {
623
+ return typeof fn === "function" && NATIVE_FUNCTION_REGEX.test(fn.toString());
624
+ }
625
+
584
626
  function streamToAsyncIteratorClass(stream) {
585
627
  const reader = stream.getReader();
586
628
  return new AsyncIteratorClass(
@@ -623,4 +665,4 @@ function value(value2, ...args) {
623
665
  return value2;
624
666
  }
625
667
 
626
- export { AbortError, AsyncIdQueue, AsyncIteratorClass, EventPublisher, NullProtoObj, ORPC_NAME, ORPC_SHARED_PACKAGE_NAME, ORPC_SHARED_PACKAGE_VERSION, SequentialIdGenerator, asyncIteratorToStream, asyncIteratorWithSpan, clone, defer, findDeepMatches, get, getGlobalOtelConfig, intercept, isAsyncIteratorObject, isObject, isPropertyKey, isTypescriptObject, onError, onFinish, onStart, onSuccess, once, parseEmptyableJSON, readAsBuffer, replicateAsyncIterator, resolveMaybeOptionalOptions, runInSpanContext, runWithSpan, sequential, setGlobalOtelConfig, setSpanAttribute, setSpanError, splitInHalf, startSpan, streamToAsyncIteratorClass, stringifyJSON, toArray, toOtelException, toSpanAttributeValue, tryDecodeURIComponent, value };
668
+ export { AbortError, AsyncIdQueue, AsyncIteratorClass, EventPublisher, NullProtoObj, ORPC_NAME, ORPC_SHARED_PACKAGE_NAME, ORPC_SHARED_PACKAGE_VERSION, SequentialIdGenerator, asyncIteratorToStream, asyncIteratorWithSpan, clone, defer, findDeepMatches, get, getGlobalOtelConfig, intercept, isAsyncIteratorObject, isObject, isPropertyKey, isTypescriptObject, onError, onFinish, onStart, onSuccess, once, parseEmptyableJSON, preventNativeAwait, readAsBuffer, replicateAsyncIterator, resolveMaybeOptionalOptions, runInSpanContext, runWithSpan, sequential, setGlobalOtelConfig, setSpanAttribute, setSpanError, splitInHalf, startSpan, streamToAsyncIteratorClass, stringifyJSON, toArray, toOtelException, toSpanAttributeValue, tryDecodeURIComponent, value };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orpc/shared",
3
3
  "type": "module",
4
- "version": "0.0.0-next.346e220",
4
+ "version": "0.0.0-next.347f023",
5
5
  "license": "MIT",
6
6
  "homepage": "https://orpc.unnoq.com",
7
7
  "repository": {
@@ -39,7 +39,7 @@
39
39
  "@opentelemetry/api": "^1.9.0",
40
40
  "arktype": "2.1.20",
41
41
  "valibot": "^1.1.0",
42
- "zod": "^4.0.17"
42
+ "zod": "^4.1.1"
43
43
  },
44
44
  "scripts": {
45
45
  "build": "unbuild",