effect-orpc 0.1.3 → 0.2.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/dist/index.js CHANGED
@@ -2,14 +2,12 @@ import {
2
2
  getCurrentFiberRefs
3
3
  } from "./chunk-VOWRLWZZ.js";
4
4
 
5
+ // src/contract.ts
6
+ import { isContractProcedure as isContractProcedure2 } from "@orpc/contract";
7
+ import { implement } from "@orpc/server";
8
+
5
9
  // src/effect-builder.ts
6
- import {
7
- mergeMeta as mergeMeta2,
8
- mergePrefix as mergePrefix2,
9
- mergeRoute as mergeRoute2,
10
- mergeTags,
11
- ORPCError as ORPCError2
12
- } from "@orpc/contract";
10
+ import { mergeMeta as mergeMeta2, mergePrefix as mergePrefix2, mergeRoute as mergeRoute2, mergeTags } from "@orpc/contract";
13
11
  import {
14
12
  addMiddleware as addMiddleware2,
15
13
  Builder,
@@ -17,7 +15,6 @@ import {
17
15
  fallbackConfig,
18
16
  lazy as lazy2
19
17
  } from "@orpc/server";
20
- import { Cause as Cause2, Effect, Exit, FiberRefs } from "effect";
21
18
 
22
19
  // src/effect-enhance-router.ts
23
20
  import {
@@ -323,6 +320,86 @@ function enhanceEffectRouter(router, options) {
323
320
  return enhanced;
324
321
  }
325
322
 
323
+ // src/effect-runtime.ts
324
+ import { ORPCError as ORPCError2 } from "@orpc/contract";
325
+ import { Cause as Cause2, Effect, Exit, FiberRefs } from "effect";
326
+ function toORPCErrorFromCause(cause) {
327
+ return Cause2.match(cause, {
328
+ onDie(defect) {
329
+ return new ORPCError2("INTERNAL_SERVER_ERROR", {
330
+ cause: defect
331
+ });
332
+ },
333
+ onFail(error) {
334
+ if (isORPCTaggedError(error)) {
335
+ return error.toORPCError();
336
+ }
337
+ if (error instanceof ORPCError2) {
338
+ return error;
339
+ }
340
+ return new ORPCError2("INTERNAL_SERVER_ERROR", {
341
+ cause: error
342
+ });
343
+ },
344
+ onInterrupt(fiberId) {
345
+ return new ORPCError2("INTERNAL_SERVER_ERROR", {
346
+ cause: new Error(`${fiberId} Interrupted`)
347
+ });
348
+ },
349
+ onSequential(left) {
350
+ return left;
351
+ },
352
+ onEmpty: new ORPCError2("INTERNAL_SERVER_ERROR", {
353
+ cause: new Error("Unknown error")
354
+ }),
355
+ onParallel(left) {
356
+ return left;
357
+ }
358
+ });
359
+ }
360
+ function createEffectProcedureHandler(options) {
361
+ const {
362
+ runtime,
363
+ effectErrorMap,
364
+ effectFn,
365
+ spanConfig,
366
+ defaultCaptureStackTrace
367
+ } = options;
368
+ return async (opts) => {
369
+ const effectOpts = {
370
+ context: opts.context,
371
+ input: opts.input,
372
+ path: opts.path,
373
+ procedure: opts.procedure,
374
+ signal: opts.signal,
375
+ lastEventId: opts.lastEventId,
376
+ errors: createEffectErrorConstructorMap(effectErrorMap)
377
+ };
378
+ const spanName = spanConfig?.name ?? opts.path.join(".");
379
+ const captureStackTrace = spanConfig?.captureStackTrace ?? defaultCaptureStackTrace;
380
+ const resolver = Effect.fnUntraced(effectFn);
381
+ const tracedEffect = Effect.withSpan(resolver(effectOpts), spanName, {
382
+ captureStackTrace
383
+ });
384
+ const parentFiberRefs = getCurrentFiberRefs();
385
+ const effectWithRefs = parentFiberRefs ? Effect.fiberIdWith(
386
+ (fiberId) => Effect.flatMap(
387
+ Effect.getFiberRefs,
388
+ (fiberRefs) => Effect.setFiberRefs(
389
+ FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs)
390
+ ).pipe(Effect.andThen(tracedEffect))
391
+ )
392
+ ) : tracedEffect;
393
+ const exit = await runtime.runPromiseExit(effectWithRefs, {
394
+ signal: opts.signal
395
+ });
396
+ if (Exit.isFailure(exit)) {
397
+ throw toORPCErrorFromCause(exit.cause);
398
+ }
399
+ return exit.value;
400
+ };
401
+ }
402
+
326
403
  // src/effect-builder.ts
327
404
  function addSpanStackTrace() {
328
405
  const ErrorConstructor = Error;
@@ -436,6 +513,14 @@ var EffectBuilder = class _EffectBuilder {
436
513
  inputSchema: initialInputSchema
437
514
  });
438
515
  }
516
+ /**
517
+ * Creates a middleware.
518
+ *
519
+ * @see {@link https://orpc.dev/docs/middleware Middleware Docs}
520
+ */
521
+ middleware(middleware) {
522
+ return decorateMiddleware2(middleware);
523
+ }
439
524
  /**
440
525
  * Adds type-safe custom errors.
441
526
  * Supports both traditional oRPC error definitions and ORPCTaggedError classes.
@@ -583,70 +668,13 @@ var EffectBuilder = class _EffectBuilder {
583
668
  return new EffectDecoratedProcedure({
584
669
  ...this["~effect"],
585
670
  handler: async (opts) => {
586
- const effectOpts = {
587
- context: opts.context,
588
- input: opts.input,
589
- path: opts.path,
590
- procedure: opts.procedure,
591
- signal: opts.signal,
592
- lastEventId: opts.lastEventId,
593
- errors: createEffectErrorConstructorMap(
594
- this["~effect"].effectErrorMap
595
- )
596
- };
597
- const spanName = spanConfig?.name ?? opts.path.join(".");
598
- const captureStackTrace = spanConfig?.captureStackTrace ?? defaultCaptureStackTrace;
599
- const resolver = Effect.fnUntraced(effectFn);
600
- const tracedEffect = Effect.withSpan(resolver(effectOpts), spanName, {
601
- captureStackTrace
602
- });
603
- const parentFiberRefs = getCurrentFiberRefs();
604
- const effectWithRefs = parentFiberRefs ? Effect.fiberIdWith(
605
- (fiberId) => Effect.flatMap(
606
- Effect.getFiberRefs,
607
- (fiberRefs) => Effect.setFiberRefs(
608
- FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs)
609
- ).pipe(Effect.andThen(tracedEffect))
610
- )
611
- ) : tracedEffect;
612
- const exit = await runtime.runPromiseExit(effectWithRefs, {
613
- signal: opts.signal
614
- });
615
- if (Exit.isFailure(exit)) {
616
- throw Cause2.match(exit.cause, {
617
- onDie(defect) {
618
- return new ORPCError2("INTERNAL_SERVER_ERROR", {
619
- cause: defect
620
- });
621
- },
622
- onFail(error) {
623
- if (isORPCTaggedError(error)) {
624
- return error.toORPCError();
625
- }
626
- if (error instanceof ORPCError2) {
627
- return error;
628
- }
629
- return new ORPCError2("INTERNAL_SERVER_ERROR", {
630
- cause: error
631
- });
632
- },
633
- onInterrupt(fiberId) {
634
- return new ORPCError2("INTERNAL_SERVER_ERROR", {
635
- cause: new Error(`${fiberId} Interrupted`)
636
- });
637
- },
638
- onSequential(left) {
639
- return left;
640
- },
641
- onEmpty: new ORPCError2("INTERNAL_SERVER_ERROR", {
642
- cause: new Error("Unknown error")
643
- }),
644
- onParallel(left) {
645
- return left;
646
- }
647
- });
648
- }
649
- return exit.value;
671
+ return createEffectProcedureHandler({
672
+ runtime,
673
+ effectErrorMap: this["~effect"].effectErrorMap,
674
+ effectFn,
675
+ spanConfig,
676
+ defaultCaptureStackTrace
677
+ })(opts);
650
678
  }
651
679
  });
652
680
  }
@@ -719,6 +747,256 @@ function emptyBuilder() {
719
747
  dedupeLeadingMiddlewares: true
720
748
  });
721
749
  }
750
+
751
+ // src/eoc.ts
752
+ import { isContractProcedure, oc } from "@orpc/contract";
753
+ var effectContractSymbol = /* @__PURE__ */ Symbol.for(
754
+ "@orpc/effect/contract"
755
+ );
756
+ function isWrappableContractBuilder(value) {
757
+ return typeof value === "object" && value !== null && "~orpc" in value;
758
+ }
759
+ function mergeEffectErrorMaps(left, right) {
760
+ if (!left) {
761
+ return right;
762
+ }
763
+ if (!right) {
764
+ return left;
765
+ }
766
+ return {
767
+ ...left,
768
+ ...right
769
+ };
770
+ }
771
+ function setEffectContractErrorMap(value, effectErrorMap) {
772
+ if (!effectErrorMap) {
773
+ return;
774
+ }
775
+ Object.defineProperty(value, effectContractSymbol, {
776
+ value: { errorMap: effectErrorMap },
777
+ enumerable: false,
778
+ configurable: true
779
+ });
780
+ }
781
+ function getEffectContractErrorMap(value) {
782
+ if (typeof value !== "object" || value === null) {
783
+ return void 0;
784
+ }
785
+ return value[effectContractSymbol]?.errorMap;
786
+ }
787
+ function applyEffectContractErrorMapToRouter(router, source, inheritedEffectErrorMap) {
788
+ const routerRecord = router;
789
+ const sourceRecord = source;
790
+ for (const key of Object.keys(routerRecord)) {
791
+ const routerValue = routerRecord[key];
792
+ const sourceValue = sourceRecord && typeof sourceRecord === "object" ? sourceRecord[key] : void 0;
793
+ if (!routerValue) {
794
+ continue;
795
+ }
796
+ if (isContractProcedure(routerValue)) {
797
+ const sourceEffectErrorMap = getEffectContractErrorMap(sourceValue);
798
+ setEffectContractErrorMap(
799
+ routerValue,
800
+ mergeEffectErrorMaps(inheritedEffectErrorMap, sourceEffectErrorMap)
801
+ );
802
+ continue;
803
+ }
804
+ if (typeof routerValue === "object") {
805
+ applyEffectContractErrorMapToRouter(
806
+ routerValue,
807
+ sourceValue,
808
+ inheritedEffectErrorMap
809
+ );
810
+ }
811
+ }
812
+ }
813
+ function wrapEffectContractBuilder(builder, inheritedEffectErrorMap) {
814
+ const currentEffectErrorMap = inheritedEffectErrorMap ?? getEffectContractErrorMap(builder);
815
+ if (typeof builder === "object" && builder !== null) {
816
+ setEffectContractErrorMap(builder, currentEffectErrorMap);
817
+ }
818
+ const proxy = new Proxy(builder, {
819
+ get(target, prop, receiver) {
820
+ if (prop === effectContractSymbol) {
821
+ return currentEffectErrorMap ? { errorMap: currentEffectErrorMap } : void 0;
822
+ }
823
+ if (prop === "errors") {
824
+ return (errors) => {
825
+ const nextEffectErrorMap = mergeEffectErrorMaps(
826
+ currentEffectErrorMap,
827
+ errors
828
+ );
829
+ return wrapEffectContractBuilder(
830
+ Reflect.apply(Reflect.get(target, prop, receiver), target, [
831
+ effectErrorMapToErrorMap(errors)
832
+ ]),
833
+ nextEffectErrorMap
834
+ );
835
+ };
836
+ }
837
+ if (prop === "router") {
838
+ return (router) => {
839
+ const result = Reflect.apply(
840
+ Reflect.get(target, prop, receiver),
841
+ target,
842
+ [router]
843
+ );
844
+ applyEffectContractErrorMapToRouter(
845
+ result,
846
+ router,
847
+ currentEffectErrorMap
848
+ );
849
+ return result;
850
+ };
851
+ }
852
+ const value = Reflect.get(target, prop, receiver);
853
+ if (typeof value !== "function") {
854
+ return value;
855
+ }
856
+ return (...args) => {
857
+ const result = Reflect.apply(value, target, args);
858
+ return isWrappableContractBuilder(result) ? wrapEffectContractBuilder(result, currentEffectErrorMap) : result;
859
+ };
860
+ }
861
+ });
862
+ setEffectContractErrorMap(proxy, currentEffectErrorMap);
863
+ return proxy;
864
+ }
865
+ var eoc = wrapEffectContractBuilder(
866
+ oc,
867
+ {}
868
+ );
869
+
870
+ // src/contract.ts
871
+ var CONTRACT_HIDDEN_METHODS = /* @__PURE__ */ new Set([
872
+ "$config",
873
+ "$context",
874
+ "$input",
875
+ "$meta",
876
+ "$route",
877
+ "errors",
878
+ "input",
879
+ "lazy",
880
+ "meta",
881
+ "middleware",
882
+ "output",
883
+ "prefix",
884
+ "route",
885
+ "router",
886
+ "tag"
887
+ ]);
888
+ function makeEnhanceOptions(runtime) {
889
+ return {
890
+ middlewares: [],
891
+ errorMap: {},
892
+ dedupeLeadingMiddlewares: true,
893
+ runtime
894
+ };
895
+ }
896
+ function wrapContractNode(contract, target, runtime) {
897
+ const cache = /* @__PURE__ */ new Map();
898
+ return new Proxy(target, {
899
+ get(currentTarget, prop, receiver) {
900
+ if (cache.has(prop)) {
901
+ return cache.get(prop);
902
+ }
903
+ if (isContractProcedure2(contract)) {
904
+ if (prop === "effect") {
905
+ const effect = (effectFn) => {
906
+ const effectErrorMap = getEffectContractErrorMap(contract) ?? currentTarget["~orpc"].errorMap;
907
+ return new EffectDecoratedProcedure({
908
+ ...currentTarget["~orpc"],
909
+ errorMap: effectErrorMapToErrorMap(effectErrorMap),
910
+ effectErrorMap,
911
+ runtime,
912
+ handler: createEffectProcedureHandler({
913
+ runtime,
914
+ effectErrorMap,
915
+ effectFn,
916
+ defaultCaptureStackTrace: addSpanStackTrace()
917
+ })
918
+ });
919
+ };
920
+ cache.set(prop, effect);
921
+ return effect;
922
+ }
923
+ if (prop === "use") {
924
+ const use = (...args) => wrapContractNode(
925
+ contract,
926
+ Reflect.apply(
927
+ Reflect.get(currentTarget, prop, currentTarget),
928
+ currentTarget,
929
+ args
930
+ ),
931
+ runtime
932
+ );
933
+ cache.set(prop, use);
934
+ return use;
935
+ }
936
+ if (CONTRACT_HIDDEN_METHODS.has(String(prop))) {
937
+ return void 0;
938
+ }
939
+ } else {
940
+ if (prop === "$context" || prop === "$config" || prop === "use") {
941
+ const wrappedMethod = (...args) => wrapContractNode(
942
+ contract,
943
+ Reflect.apply(
944
+ Reflect.get(currentTarget, prop, currentTarget),
945
+ currentTarget,
946
+ args
947
+ ),
948
+ runtime
949
+ );
950
+ cache.set(prop, wrappedMethod);
951
+ return wrappedMethod;
952
+ }
953
+ if (prop === "router" || prop === "lazy") {
954
+ const wrappedMethod = (...args) => enhanceEffectRouter(
955
+ Reflect.apply(
956
+ Reflect.get(currentTarget, prop, currentTarget),
957
+ currentTarget,
958
+ args
959
+ ),
960
+ makeEnhanceOptions(runtime)
961
+ );
962
+ cache.set(prop, wrappedMethod);
963
+ return wrappedMethod;
964
+ }
965
+ if (typeof prop === "string" && prop in contract) {
966
+ const child = wrapContractNode(
967
+ contract[prop],
968
+ Reflect.get(currentTarget, prop, receiver),
969
+ runtime
970
+ );
971
+ cache.set(prop, child);
972
+ return child;
973
+ }
974
+ }
975
+ const value = Reflect.get(currentTarget, prop, receiver);
976
+ return typeof value === "function" ? value.bind(currentTarget) : value;
977
+ },
978
+ has(currentTarget, prop) {
979
+ if (isContractProcedure2(contract)) {
980
+ if (prop === "effect") {
981
+ return true;
982
+ }
983
+ if (CONTRACT_HIDDEN_METHODS.has(String(prop))) {
984
+ return false;
985
+ }
986
+ } else if (typeof prop === "string" && prop in contract) {
987
+ return true;
988
+ }
989
+ return Reflect.has(currentTarget, prop);
990
+ }
991
+ });
992
+ }
993
+ function implementEffect(contract, runtime) {
994
+ return wrapContractNode(
995
+ contract,
996
+ implement(contract),
997
+ runtime
998
+ );
999
+ }
722
1000
  export {
723
1001
  EffectBuilder,
724
1002
  EffectDecoratedProcedure,
@@ -727,6 +1005,8 @@ export {
727
1005
  addSpanStackTrace,
728
1006
  createEffectErrorConstructorMap,
729
1007
  effectErrorMapToErrorMap,
1008
+ eoc,
1009
+ implementEffect,
730
1010
  isORPCTaggedError,
731
1011
  isORPCTaggedErrorClass,
732
1012
  makeEffectORPC,