ff-effect 0.0.3 → 0.0.5

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.
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/for/orpc/index.ts
21
21
  var orpc_exports = {};
22
22
  __export(orpc_exports, {
23
+ FfOrpcCtx: () => FfOrpcCtx,
23
24
  createHandler: () => createHandler
24
25
  });
25
26
  module.exports = __toCommonJS(orpc_exports);
@@ -52,16 +53,33 @@ async function runPromiseUnwrapped(effect) {
52
53
  }
53
54
 
54
55
  // src/for/orpc/procedure.ts
56
+ var FfOrpcCtx;
57
+ ((FfOrpcCtx2) => {
58
+ const TAG = "ff-orpc";
59
+ function create(input) {
60
+ return {
61
+ _tag: TAG,
62
+ runEffect: input.runEffect
63
+ };
64
+ }
65
+ FfOrpcCtx2.create = create;
66
+ function is(ctx) {
67
+ return typeof ctx === "object" && ctx !== null && "_tag" in ctx && ctx._tag === TAG;
68
+ }
69
+ FfOrpcCtx2.is = is;
70
+ })(FfOrpcCtx || (FfOrpcCtx = {}));
55
71
  function createHandler(builder, handler) {
56
72
  return import_effect3.Effect.gen(function* () {
57
73
  const ext_handler = yield* extract(handler);
58
- return builder.handler(
59
- async (opt) => ext_handler(opt).pipe((e) => runPromiseUnwrapped(e))
60
- );
74
+ return builder.handler(async (opt) => {
75
+ const runEffect = FfOrpcCtx.is(opt.context.ff) ? opt.context.ff.runEffect : runPromiseUnwrapped;
76
+ return ext_handler(opt).pipe((e) => runEffect(e));
77
+ });
61
78
  });
62
79
  }
63
80
  // Annotate the CommonJS export names for ESM import in node:
64
81
  0 && (module.exports = {
82
+ FfOrpcCtx,
65
83
  createHandler
66
84
  });
67
85
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/for/orpc/index.ts","../../../src/for/orpc/procedure.ts","../../../src/extract.ts","../../../src/run-promise-unwrapped.ts"],"sourcesContent":["import { createHandler } from './procedure';\n\nexport { createHandler };\n","import { Effect } from 'effect';\nimport { extract } from '../../extract';\nimport { runPromiseUnwrapped } from '../../run-promise-unwrapped';\n\ntype SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER> = {\n\thandler: (handler: (_: INPUT) => Promise<OUTPUT>) => IMPLEMENTED_HANDLER;\n};\n\n/**\n * Create a Effect-based handler\n *\n * @example\n * ```ts\n * // Before - Plain oRPC\n * const procedure = os\n * .input(v.object({ hello: v.string() }))\n * .handler(({ input }) => 'world');\n *\n * // After\n * const procedure = createHandler(\n * os.input(v.object({ hello: v.string() })),\n * Effect.fn(function* ({ input }) {\n * return 'world'\n * }),\n * );\n * ```\n **/\nexport function createHandler<INPUT, OUTPUT, IMPLEMENTED_HANDLER, R>(\n\tbuilder: SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER>,\n\thandler: (opt: INPUT) => Effect.Effect<OUTPUT, unknown, R>,\n) {\n\treturn Effect.gen(function* () {\n\t\tconst ext_handler = yield* extract(handler);\n\t\treturn builder.handler(async (opt) =>\n\t\t\text_handler(opt).pipe((e) => runPromiseUnwrapped(e)),\n\t\t);\n\t});\n}\n","import { Context, Effect, pipe } from \"effect\";\n\ntype InferClass<T> = T extends new (...args: any[]) => infer R ? R : never;\n\n// biome-ignore lint/suspicious/noExplicitAny: intended\nexport function extract<\n\tP extends any[],\n\tA,\n\tE,\n\tR,\n\tINFERRED_EXCLUDED extends Context.Tag<any, any> = never,\n\tEXCLUDED = InferClass<INFERRED_EXCLUDED>,\n>(\n\teffect: (...params: P) => Effect.Effect<A, E, R>,\n\toptions?: { exclude?: Array<INFERRED_EXCLUDED> }\n): Effect.Effect<\n\t(...params: P) => Effect.Effect<A, E, Extract<R, EXCLUDED>>,\n\tnever,\n\tExclude<R, EXCLUDED>\n> {\n\t// @ts-expect-error quite hard to type, check unit test\n\treturn Effect.gen(function* () {\n\t\tconst runtime = yield* Effect.runtime();\n\n\t\tconst context = runtime.context.pipe(\n\t\t\toptions?.exclude ? Context.omit(...options.exclude) : (e) => e\n\t\t) as Context.Context<Exclude<R, EXCLUDED>>;\n\n\t\treturn (...params: P) =>\n\t\t\tpipe(effect(...params), Effect.provide(context));\n\t});\n}\n","import { Cause, Effect, Exit } from \"effect\";\n\n/**\n * A simple wrapper around Effect.runPromiseExit that throws the error if it's a failure\n **/\nexport async function runPromiseUnwrapped<A, E>(\n\teffect: Effect.Effect<A, E, never>\n) {\n\tconst exit = await Effect.runPromiseExit(effect);\n\treturn Exit.match(exit, {\n\t\tonSuccess: (value) => value,\n\t\tonFailure: (cause) => {\n\t\t\tthrow Cause.isFailType(cause) ? cause.error : cause;\n\t\t},\n\t});\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,iBAAuB;;;ACAvB,oBAAsC;AAK/B,SAAS,QAQf,QACA,SAKC;AAED,SAAO,qBAAO,IAAI,aAAa;AAC9B,UAAM,UAAU,OAAO,qBAAO,QAAQ;AAEtC,UAAM,UAAU,QAAQ,QAAQ;AAAA,MAC/B,SAAS,UAAU,sBAAQ,KAAK,GAAG,QAAQ,OAAO,IAAI,CAAC,MAAM;AAAA,IAC9D;AAEA,WAAO,IAAI,eACV,oBAAK,OAAO,GAAG,MAAM,GAAG,qBAAO,QAAQ,OAAO,CAAC;AAAA,EACjD,CAAC;AACF;;;AC/BA,IAAAC,iBAAoC;AAKpC,eAAsB,oBACrB,QACC;AACD,QAAM,OAAO,MAAM,sBAAO,eAAe,MAAM;AAC/C,SAAO,oBAAK,MAAM,MAAM;AAAA,IACvB,WAAW,CAAC,UAAU;AAAA,IACtB,WAAW,CAAC,UAAU;AACrB,YAAM,qBAAM,WAAW,KAAK,IAAI,MAAM,QAAQ;AAAA,IAC/C;AAAA,EACD,CAAC;AACF;;;AFYO,SAAS,cACf,SACA,SACC;AACD,SAAO,sBAAO,IAAI,aAAa;AAC9B,UAAM,cAAc,OAAO,QAAQ,OAAO;AAC1C,WAAO,QAAQ;AAAA,MAAQ,OAAO,QAC7B,YAAY,GAAG,EAAE,KAAK,CAAC,MAAM,oBAAoB,CAAC,CAAC;AAAA,IACpD;AAAA,EACD,CAAC;AACF;","names":["import_effect","import_effect"]}
1
+ {"version":3,"sources":["../../../src/for/orpc/index.ts","../../../src/for/orpc/procedure.ts","../../../src/extract.ts","../../../src/run-promise-unwrapped.ts"],"sourcesContent":["import { createHandler, FfOrpcCtx } from './procedure';\n\nexport { createHandler, FfOrpcCtx };\n","import { Effect } from 'effect';\nimport { extract } from '../../extract';\nimport { runPromiseUnwrapped } from '../../run-promise-unwrapped';\n\nexport namespace FfOrpcCtx {\n\tconst TAG = 'ff-orpc';\n\n\texport function create<R>(input: {\n\t\trunEffect: <A = unknown, E = unknown>(\n\t\t\teffect: Effect.Effect<A, E, R>,\n\t\t) => Promise<A>;\n\t}) {\n\t\treturn {\n\t\t\t_tag: TAG,\n\t\t\trunEffect: input.runEffect,\n\t\t};\n\t}\n\n\texport function is(ctx: unknown): ctx is FfOrpcCtx.Type<unknown> {\n\t\treturn (\n\t\t\ttypeof ctx === 'object' &&\n\t\t\tctx !== null &&\n\t\t\t'_tag' in ctx &&\n\t\t\tctx._tag === TAG\n\t\t);\n\t}\n\n\texport type Type<R> = ReturnType<typeof create<R>>;\n}\n\nexport type FfOrpcCtx<R> = FfOrpcCtx.Type<R>;\n\ntype SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER> = {\n\thandler: (handler: (_: INPUT) => Promise<OUTPUT>) => IMPLEMENTED_HANDLER;\n};\n\n/**\n * Create a Effect-based handler\n *\n * @example\n * ```ts\n * // Before - Plain oRPC\n * const procedure = os\n * .input(v.object({ hello: v.string() }))\n * .handler(({ input }) => 'world');\n *\n * // After\n * const procedure = createHandler(\n * os.input(v.object({ hello: v.string() })),\n * Effect.fn(function* ({ input }) {\n * return 'world'\n * }),\n * );\n * ```\n **/\nexport function createHandler<\n\tOPT extends { context: { ff?: FfOrpcCtx<never> } },\n\tOUTPUT,\n\tIMPLEMENTED_HANDLER,\n\tR,\n>(\n\tbuilder: SimpleBuilder<OPT, OUTPUT, IMPLEMENTED_HANDLER>,\n\thandler: (opt: OPT) => Effect.Effect<OUTPUT, unknown, R>,\n) {\n\treturn Effect.gen(function* () {\n\t\tconst ext_handler = yield* extract(handler);\n\t\treturn builder.handler(async (opt) => {\n\t\t\tconst runEffect = FfOrpcCtx.is(opt.context.ff)\n\t\t\t\t? opt.context.ff.runEffect\n\t\t\t\t: runPromiseUnwrapped;\n\t\t\treturn ext_handler(opt).pipe((e) => runEffect(e));\n\t\t});\n\t});\n}\n","import { Context, Effect, pipe } from \"effect\";\n\ntype InferClass<T> = T extends new (...args: any[]) => infer R ? R : never;\n\n// biome-ignore lint/suspicious/noExplicitAny: intended\nexport function extract<\n\tP extends any[],\n\tA,\n\tE,\n\tR,\n\tINFERRED_EXCLUDED extends Context.Tag<any, any> = never,\n\tEXCLUDED = InferClass<INFERRED_EXCLUDED>,\n>(\n\teffect: (...params: P) => Effect.Effect<A, E, R>,\n\toptions?: { exclude?: Array<INFERRED_EXCLUDED> }\n): Effect.Effect<\n\t(...params: P) => Effect.Effect<A, E, Extract<R, EXCLUDED>>,\n\tnever,\n\tExclude<R, EXCLUDED>\n> {\n\t// @ts-expect-error quite hard to type, check unit test\n\treturn Effect.gen(function* () {\n\t\tconst runtime = yield* Effect.runtime();\n\n\t\tconst context = runtime.context.pipe(\n\t\t\toptions?.exclude ? Context.omit(...options.exclude) : (e) => e\n\t\t) as Context.Context<Exclude<R, EXCLUDED>>;\n\n\t\treturn (...params: P) =>\n\t\t\tpipe(effect(...params), Effect.provide(context));\n\t});\n}\n","import { Cause, Effect, Exit } from \"effect\";\n\n/**\n * A simple wrapper around Effect.runPromiseExit that throws the error if it's a failure\n **/\nexport async function runPromiseUnwrapped<A, E>(\n\teffect: Effect.Effect<A, E, never>\n) {\n\tconst exit = await Effect.runPromiseExit(effect);\n\treturn Exit.match(exit, {\n\t\tonSuccess: (value) => value,\n\t\tonFailure: (cause) => {\n\t\t\tthrow Cause.isFailType(cause) ? cause.error : cause;\n\t\t},\n\t});\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,iBAAuB;;;ACAvB,oBAAsC;AAK/B,SAAS,QAQf,QACA,SAKC;AAED,SAAO,qBAAO,IAAI,aAAa;AAC9B,UAAM,UAAU,OAAO,qBAAO,QAAQ;AAEtC,UAAM,UAAU,QAAQ,QAAQ;AAAA,MAC/B,SAAS,UAAU,sBAAQ,KAAK,GAAG,QAAQ,OAAO,IAAI,CAAC,MAAM;AAAA,IAC9D;AAEA,WAAO,IAAI,eACV,oBAAK,OAAO,GAAG,MAAM,GAAG,qBAAO,QAAQ,OAAO,CAAC;AAAA,EACjD,CAAC;AACF;;;AC/BA,IAAAC,iBAAoC;AAKpC,eAAsB,oBACrB,QACC;AACD,QAAM,OAAO,MAAM,sBAAO,eAAe,MAAM;AAC/C,SAAO,oBAAK,MAAM,MAAM;AAAA,IACvB,WAAW,CAAC,UAAU;AAAA,IACtB,WAAW,CAAC,UAAU;AACrB,YAAM,qBAAM,WAAW,KAAK,IAAI,MAAM,QAAQ;AAAA,IAC/C;AAAA,EACD,CAAC;AACF;;;AFXO,IAAU;AAAA,CAAV,CAAUC,eAAV;AACN,QAAM,MAAM;AAEL,WAAS,OAAU,OAIvB;AACF,WAAO;AAAA,MACN,MAAM;AAAA,MACN,WAAW,MAAM;AAAA,IAClB;AAAA,EACD;AATO,EAAAA,WAAS;AAWT,WAAS,GAAG,KAA8C;AAChE,WACC,OAAO,QAAQ,YACf,QAAQ,QACR,UAAU,OACV,IAAI,SAAS;AAAA,EAEf;AAPO,EAAAA,WAAS;AAAA,GAdA;AAmDV,SAAS,cAMf,SACA,SACC;AACD,SAAO,sBAAO,IAAI,aAAa;AAC9B,UAAM,cAAc,OAAO,QAAQ,OAAO;AAC1C,WAAO,QAAQ,QAAQ,OAAO,QAAQ;AACrC,YAAM,YAAY,UAAU,GAAG,IAAI,QAAQ,EAAE,IAC1C,IAAI,QAAQ,GAAG,YACf;AACH,aAAO,YAAY,GAAG,EAAE,KAAK,CAAC,MAAM,UAAU,CAAC,CAAC;AAAA,IACjD,CAAC;AAAA,EACF,CAAC;AACF;","names":["import_effect","import_effect","FfOrpcCtx"]}
@@ -1,5 +1,16 @@
1
1
  import { Effect } from 'effect';
2
2
 
3
+ declare namespace FfOrpcCtx {
4
+ function create<R>(input: {
5
+ runEffect: <A = unknown, E = unknown>(effect: Effect.Effect<A, E, R>) => Promise<A>;
6
+ }): {
7
+ _tag: string;
8
+ runEffect: <A = unknown, E = unknown>(effect: Effect.Effect<A, E, R>) => Promise<A>;
9
+ };
10
+ function is(ctx: unknown): ctx is FfOrpcCtx.Type<unknown>;
11
+ type Type<R> = ReturnType<typeof create<R>>;
12
+ }
13
+ type FfOrpcCtx<R> = FfOrpcCtx.Type<R>;
3
14
  type SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER> = {
4
15
  handler: (handler: (_: INPUT) => Promise<OUTPUT>) => IMPLEMENTED_HANDLER;
5
16
  };
@@ -22,6 +33,10 @@ type SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER> = {
22
33
  * );
23
34
  * ```
24
35
  **/
25
- declare function createHandler<INPUT, OUTPUT, IMPLEMENTED_HANDLER, R>(builder: SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER>, handler: (opt: INPUT) => Effect.Effect<OUTPUT, unknown, R>): Effect.Effect<IMPLEMENTED_HANDLER, never, Exclude<R, never>>;
36
+ declare function createHandler<OPT extends {
37
+ context: {
38
+ ff?: FfOrpcCtx<never>;
39
+ };
40
+ }, OUTPUT, IMPLEMENTED_HANDLER, R>(builder: SimpleBuilder<OPT, OUTPUT, IMPLEMENTED_HANDLER>, handler: (opt: OPT) => Effect.Effect<OUTPUT, unknown, R>): Effect.Effect<IMPLEMENTED_HANDLER, never, Exclude<R, never>>;
26
41
 
27
- export { createHandler };
42
+ export { FfOrpcCtx, createHandler };
@@ -1,5 +1,16 @@
1
1
  import { Effect } from 'effect';
2
2
 
3
+ declare namespace FfOrpcCtx {
4
+ function create<R>(input: {
5
+ runEffect: <A = unknown, E = unknown>(effect: Effect.Effect<A, E, R>) => Promise<A>;
6
+ }): {
7
+ _tag: string;
8
+ runEffect: <A = unknown, E = unknown>(effect: Effect.Effect<A, E, R>) => Promise<A>;
9
+ };
10
+ function is(ctx: unknown): ctx is FfOrpcCtx.Type<unknown>;
11
+ type Type<R> = ReturnType<typeof create<R>>;
12
+ }
13
+ type FfOrpcCtx<R> = FfOrpcCtx.Type<R>;
3
14
  type SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER> = {
4
15
  handler: (handler: (_: INPUT) => Promise<OUTPUT>) => IMPLEMENTED_HANDLER;
5
16
  };
@@ -22,6 +33,10 @@ type SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER> = {
22
33
  * );
23
34
  * ```
24
35
  **/
25
- declare function createHandler<INPUT, OUTPUT, IMPLEMENTED_HANDLER, R>(builder: SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER>, handler: (opt: INPUT) => Effect.Effect<OUTPUT, unknown, R>): Effect.Effect<IMPLEMENTED_HANDLER, never, Exclude<R, never>>;
36
+ declare function createHandler<OPT extends {
37
+ context: {
38
+ ff?: FfOrpcCtx<never>;
39
+ };
40
+ }, OUTPUT, IMPLEMENTED_HANDLER, R>(builder: SimpleBuilder<OPT, OUTPUT, IMPLEMENTED_HANDLER>, handler: (opt: OPT) => Effect.Effect<OUTPUT, unknown, R>): Effect.Effect<IMPLEMENTED_HANDLER, never, Exclude<R, never>>;
26
41
 
27
- export { createHandler };
42
+ export { FfOrpcCtx, createHandler };
@@ -26,15 +26,32 @@ async function runPromiseUnwrapped(effect) {
26
26
  }
27
27
 
28
28
  // src/for/orpc/procedure.ts
29
+ var FfOrpcCtx;
30
+ ((FfOrpcCtx2) => {
31
+ const TAG = "ff-orpc";
32
+ function create(input) {
33
+ return {
34
+ _tag: TAG,
35
+ runEffect: input.runEffect
36
+ };
37
+ }
38
+ FfOrpcCtx2.create = create;
39
+ function is(ctx) {
40
+ return typeof ctx === "object" && ctx !== null && "_tag" in ctx && ctx._tag === TAG;
41
+ }
42
+ FfOrpcCtx2.is = is;
43
+ })(FfOrpcCtx || (FfOrpcCtx = {}));
29
44
  function createHandler(builder, handler) {
30
45
  return Effect3.gen(function* () {
31
46
  const ext_handler = yield* extract(handler);
32
- return builder.handler(
33
- async (opt) => ext_handler(opt).pipe((e) => runPromiseUnwrapped(e))
34
- );
47
+ return builder.handler(async (opt) => {
48
+ const runEffect = FfOrpcCtx.is(opt.context.ff) ? opt.context.ff.runEffect : runPromiseUnwrapped;
49
+ return ext_handler(opt).pipe((e) => runEffect(e));
50
+ });
35
51
  });
36
52
  }
37
53
  export {
54
+ FfOrpcCtx,
38
55
  createHandler
39
56
  };
40
57
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/for/orpc/procedure.ts","../../../src/extract.ts","../../../src/run-promise-unwrapped.ts"],"sourcesContent":["import { Effect } from 'effect';\nimport { extract } from '../../extract';\nimport { runPromiseUnwrapped } from '../../run-promise-unwrapped';\n\ntype SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER> = {\n\thandler: (handler: (_: INPUT) => Promise<OUTPUT>) => IMPLEMENTED_HANDLER;\n};\n\n/**\n * Create a Effect-based handler\n *\n * @example\n * ```ts\n * // Before - Plain oRPC\n * const procedure = os\n * .input(v.object({ hello: v.string() }))\n * .handler(({ input }) => 'world');\n *\n * // After\n * const procedure = createHandler(\n * os.input(v.object({ hello: v.string() })),\n * Effect.fn(function* ({ input }) {\n * return 'world'\n * }),\n * );\n * ```\n **/\nexport function createHandler<INPUT, OUTPUT, IMPLEMENTED_HANDLER, R>(\n\tbuilder: SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER>,\n\thandler: (opt: INPUT) => Effect.Effect<OUTPUT, unknown, R>,\n) {\n\treturn Effect.gen(function* () {\n\t\tconst ext_handler = yield* extract(handler);\n\t\treturn builder.handler(async (opt) =>\n\t\t\text_handler(opt).pipe((e) => runPromiseUnwrapped(e)),\n\t\t);\n\t});\n}\n","import { Context, Effect, pipe } from \"effect\";\n\ntype InferClass<T> = T extends new (...args: any[]) => infer R ? R : never;\n\n// biome-ignore lint/suspicious/noExplicitAny: intended\nexport function extract<\n\tP extends any[],\n\tA,\n\tE,\n\tR,\n\tINFERRED_EXCLUDED extends Context.Tag<any, any> = never,\n\tEXCLUDED = InferClass<INFERRED_EXCLUDED>,\n>(\n\teffect: (...params: P) => Effect.Effect<A, E, R>,\n\toptions?: { exclude?: Array<INFERRED_EXCLUDED> }\n): Effect.Effect<\n\t(...params: P) => Effect.Effect<A, E, Extract<R, EXCLUDED>>,\n\tnever,\n\tExclude<R, EXCLUDED>\n> {\n\t// @ts-expect-error quite hard to type, check unit test\n\treturn Effect.gen(function* () {\n\t\tconst runtime = yield* Effect.runtime();\n\n\t\tconst context = runtime.context.pipe(\n\t\t\toptions?.exclude ? Context.omit(...options.exclude) : (e) => e\n\t\t) as Context.Context<Exclude<R, EXCLUDED>>;\n\n\t\treturn (...params: P) =>\n\t\t\tpipe(effect(...params), Effect.provide(context));\n\t});\n}\n","import { Cause, Effect, Exit } from \"effect\";\n\n/**\n * A simple wrapper around Effect.runPromiseExit that throws the error if it's a failure\n **/\nexport async function runPromiseUnwrapped<A, E>(\n\teffect: Effect.Effect<A, E, never>\n) {\n\tconst exit = await Effect.runPromiseExit(effect);\n\treturn Exit.match(exit, {\n\t\tonSuccess: (value) => value,\n\t\tonFailure: (cause) => {\n\t\t\tthrow Cause.isFailType(cause) ? cause.error : cause;\n\t\t},\n\t});\n}\n"],"mappings":";AAAA,SAAS,UAAAA,eAAc;;;ACAvB,SAAS,SAAS,QAAQ,YAAY;AAK/B,SAAS,QAQf,QACA,SAKC;AAED,SAAO,OAAO,IAAI,aAAa;AAC9B,UAAM,UAAU,OAAO,OAAO,QAAQ;AAEtC,UAAM,UAAU,QAAQ,QAAQ;AAAA,MAC/B,SAAS,UAAU,QAAQ,KAAK,GAAG,QAAQ,OAAO,IAAI,CAAC,MAAM;AAAA,IAC9D;AAEA,WAAO,IAAI,WACV,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO,QAAQ,OAAO,CAAC;AAAA,EACjD,CAAC;AACF;;;AC/BA,SAAS,OAAO,UAAAC,SAAQ,YAAY;AAKpC,eAAsB,oBACrB,QACC;AACD,QAAM,OAAO,MAAMA,QAAO,eAAe,MAAM;AAC/C,SAAO,KAAK,MAAM,MAAM;AAAA,IACvB,WAAW,CAAC,UAAU;AAAA,IACtB,WAAW,CAAC,UAAU;AACrB,YAAM,MAAM,WAAW,KAAK,IAAI,MAAM,QAAQ;AAAA,IAC/C;AAAA,EACD,CAAC;AACF;;;AFYO,SAAS,cACf,SACA,SACC;AACD,SAAOC,QAAO,IAAI,aAAa;AAC9B,UAAM,cAAc,OAAO,QAAQ,OAAO;AAC1C,WAAO,QAAQ;AAAA,MAAQ,OAAO,QAC7B,YAAY,GAAG,EAAE,KAAK,CAAC,MAAM,oBAAoB,CAAC,CAAC;AAAA,IACpD;AAAA,EACD,CAAC;AACF;","names":["Effect","Effect","Effect"]}
1
+ {"version":3,"sources":["../../../src/for/orpc/procedure.ts","../../../src/extract.ts","../../../src/run-promise-unwrapped.ts"],"sourcesContent":["import { Effect } from 'effect';\nimport { extract } from '../../extract';\nimport { runPromiseUnwrapped } from '../../run-promise-unwrapped';\n\nexport namespace FfOrpcCtx {\n\tconst TAG = 'ff-orpc';\n\n\texport function create<R>(input: {\n\t\trunEffect: <A = unknown, E = unknown>(\n\t\t\teffect: Effect.Effect<A, E, R>,\n\t\t) => Promise<A>;\n\t}) {\n\t\treturn {\n\t\t\t_tag: TAG,\n\t\t\trunEffect: input.runEffect,\n\t\t};\n\t}\n\n\texport function is(ctx: unknown): ctx is FfOrpcCtx.Type<unknown> {\n\t\treturn (\n\t\t\ttypeof ctx === 'object' &&\n\t\t\tctx !== null &&\n\t\t\t'_tag' in ctx &&\n\t\t\tctx._tag === TAG\n\t\t);\n\t}\n\n\texport type Type<R> = ReturnType<typeof create<R>>;\n}\n\nexport type FfOrpcCtx<R> = FfOrpcCtx.Type<R>;\n\ntype SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER> = {\n\thandler: (handler: (_: INPUT) => Promise<OUTPUT>) => IMPLEMENTED_HANDLER;\n};\n\n/**\n * Create a Effect-based handler\n *\n * @example\n * ```ts\n * // Before - Plain oRPC\n * const procedure = os\n * .input(v.object({ hello: v.string() }))\n * .handler(({ input }) => 'world');\n *\n * // After\n * const procedure = createHandler(\n * os.input(v.object({ hello: v.string() })),\n * Effect.fn(function* ({ input }) {\n * return 'world'\n * }),\n * );\n * ```\n **/\nexport function createHandler<\n\tOPT extends { context: { ff?: FfOrpcCtx<never> } },\n\tOUTPUT,\n\tIMPLEMENTED_HANDLER,\n\tR,\n>(\n\tbuilder: SimpleBuilder<OPT, OUTPUT, IMPLEMENTED_HANDLER>,\n\thandler: (opt: OPT) => Effect.Effect<OUTPUT, unknown, R>,\n) {\n\treturn Effect.gen(function* () {\n\t\tconst ext_handler = yield* extract(handler);\n\t\treturn builder.handler(async (opt) => {\n\t\t\tconst runEffect = FfOrpcCtx.is(opt.context.ff)\n\t\t\t\t? opt.context.ff.runEffect\n\t\t\t\t: runPromiseUnwrapped;\n\t\t\treturn ext_handler(opt).pipe((e) => runEffect(e));\n\t\t});\n\t});\n}\n","import { Context, Effect, pipe } from \"effect\";\n\ntype InferClass<T> = T extends new (...args: any[]) => infer R ? R : never;\n\n// biome-ignore lint/suspicious/noExplicitAny: intended\nexport function extract<\n\tP extends any[],\n\tA,\n\tE,\n\tR,\n\tINFERRED_EXCLUDED extends Context.Tag<any, any> = never,\n\tEXCLUDED = InferClass<INFERRED_EXCLUDED>,\n>(\n\teffect: (...params: P) => Effect.Effect<A, E, R>,\n\toptions?: { exclude?: Array<INFERRED_EXCLUDED> }\n): Effect.Effect<\n\t(...params: P) => Effect.Effect<A, E, Extract<R, EXCLUDED>>,\n\tnever,\n\tExclude<R, EXCLUDED>\n> {\n\t// @ts-expect-error quite hard to type, check unit test\n\treturn Effect.gen(function* () {\n\t\tconst runtime = yield* Effect.runtime();\n\n\t\tconst context = runtime.context.pipe(\n\t\t\toptions?.exclude ? Context.omit(...options.exclude) : (e) => e\n\t\t) as Context.Context<Exclude<R, EXCLUDED>>;\n\n\t\treturn (...params: P) =>\n\t\t\tpipe(effect(...params), Effect.provide(context));\n\t});\n}\n","import { Cause, Effect, Exit } from \"effect\";\n\n/**\n * A simple wrapper around Effect.runPromiseExit that throws the error if it's a failure\n **/\nexport async function runPromiseUnwrapped<A, E>(\n\teffect: Effect.Effect<A, E, never>\n) {\n\tconst exit = await Effect.runPromiseExit(effect);\n\treturn Exit.match(exit, {\n\t\tonSuccess: (value) => value,\n\t\tonFailure: (cause) => {\n\t\t\tthrow Cause.isFailType(cause) ? cause.error : cause;\n\t\t},\n\t});\n}\n"],"mappings":";AAAA,SAAS,UAAAA,eAAc;;;ACAvB,SAAS,SAAS,QAAQ,YAAY;AAK/B,SAAS,QAQf,QACA,SAKC;AAED,SAAO,OAAO,IAAI,aAAa;AAC9B,UAAM,UAAU,OAAO,OAAO,QAAQ;AAEtC,UAAM,UAAU,QAAQ,QAAQ;AAAA,MAC/B,SAAS,UAAU,QAAQ,KAAK,GAAG,QAAQ,OAAO,IAAI,CAAC,MAAM;AAAA,IAC9D;AAEA,WAAO,IAAI,WACV,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO,QAAQ,OAAO,CAAC;AAAA,EACjD,CAAC;AACF;;;AC/BA,SAAS,OAAO,UAAAC,SAAQ,YAAY;AAKpC,eAAsB,oBACrB,QACC;AACD,QAAM,OAAO,MAAMA,QAAO,eAAe,MAAM;AAC/C,SAAO,KAAK,MAAM,MAAM;AAAA,IACvB,WAAW,CAAC,UAAU;AAAA,IACtB,WAAW,CAAC,UAAU;AACrB,YAAM,MAAM,WAAW,KAAK,IAAI,MAAM,QAAQ;AAAA,IAC/C;AAAA,EACD,CAAC;AACF;;;AFXO,IAAU;AAAA,CAAV,CAAUC,eAAV;AACN,QAAM,MAAM;AAEL,WAAS,OAAU,OAIvB;AACF,WAAO;AAAA,MACN,MAAM;AAAA,MACN,WAAW,MAAM;AAAA,IAClB;AAAA,EACD;AATO,EAAAA,WAAS;AAWT,WAAS,GAAG,KAA8C;AAChE,WACC,OAAO,QAAQ,YACf,QAAQ,QACR,UAAU,OACV,IAAI,SAAS;AAAA,EAEf;AAPO,EAAAA,WAAS;AAAA,GAdA;AAmDV,SAAS,cAMf,SACA,SACC;AACD,SAAOC,QAAO,IAAI,aAAa;AAC9B,UAAM,cAAc,OAAO,QAAQ,OAAO;AAC1C,WAAO,QAAQ,QAAQ,OAAO,QAAQ;AACrC,YAAM,YAAY,UAAU,GAAG,IAAI,QAAQ,EAAE,IAC1C,IAAI,QAAQ,GAAG,YACf;AACH,aAAO,YAAY,GAAG,EAAE,KAAK,CAAC,MAAM,UAAU,CAAC,CAAC;AAAA,IACjD,CAAC;AAAA,EACF,CAAC;AACF;","names":["Effect","Effect","FfOrpcCtx","Effect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ff-effect",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -1,3 +1,3 @@
1
- import { createHandler } from './procedure';
1
+ import { createHandler, FfOrpcCtx } from './procedure';
2
2
 
3
- export { createHandler };
3
+ export { createHandler, FfOrpcCtx };
@@ -2,17 +2,30 @@ import { layer } from '@effect/vitest';
2
2
  import { call, implement, os } from '@orpc/server';
3
3
  import { Effect } from 'effect';
4
4
  import * as v from 'valibot';
5
- import { expect, expectTypeOf } from 'vitest';
6
- import { createHandler } from './procedure.js';
5
+ import { expect, expectTypeOf, test } from 'vitest';
6
+ import { createHandler, FfOrpcCtx } from './procedure.js';
7
7
 
8
8
  class Deps extends Effect.Service<Deps>()('deps', {
9
9
  effect: Effect.gen(function* () {
10
- return {
10
+ return yield* Effect.succeed({
11
11
  value: 'world',
12
- };
12
+ });
13
13
  }),
14
14
  }) {}
15
15
 
16
+ test('FfOrpcCtx.is', () => {
17
+ const validCtx = {
18
+ _tag: 'ff-orpc',
19
+ runEffect: async () => {},
20
+ };
21
+ expect(FfOrpcCtx.is(validCtx)).toBe(true);
22
+
23
+ expect(FfOrpcCtx.is(null)).toBe(false);
24
+ expect(FfOrpcCtx.is(undefined)).toBe(false);
25
+ expect(FfOrpcCtx.is({})).toBe(false);
26
+ expect(FfOrpcCtx.is({ _tag: 'other' })).toBe(false);
27
+ });
28
+
16
29
  layer(Deps.Default)((it) => {
17
30
  it(
18
31
  'basic',
@@ -56,4 +69,67 @@ layer(Deps.Default)((it) => {
56
69
  >();
57
70
  }),
58
71
  );
72
+
73
+ it(
74
+ 'with custom runEffect',
75
+ Effect.fn(function* () {
76
+ let runEffectCalled = false;
77
+
78
+ const deps = yield* Deps;
79
+ const customRunEffect = async <A, E>(
80
+ effect: Effect.Effect<A, E, Deps>,
81
+ ): Promise<A> => {
82
+ runEffectCalled = true;
83
+ return Effect.runSync(effect.pipe(Effect.provideService(Deps, deps)));
84
+ };
85
+
86
+ const effectProcedure = createHandler(
87
+ os
88
+ .$context<{ ff: FfOrpcCtx<Deps> }>()
89
+ .input(v.object({ message: v.string() })),
90
+ Effect.fn(function* ({ input }) {
91
+ return `${input.message} ${(yield* Deps).value}`;
92
+ }),
93
+ );
94
+ const procedure = yield* effectProcedure;
95
+
96
+ const result = yield* Effect.promise(() =>
97
+ call(
98
+ procedure,
99
+ { message: 'hello' },
100
+ {
101
+ context: {
102
+ ff: FfOrpcCtx.create({
103
+ runEffect: customRunEffect,
104
+ }),
105
+ },
106
+ },
107
+ ),
108
+ );
109
+
110
+ expect(result).toBe('hello world');
111
+ expect(runEffectCalled).toBe(true);
112
+ }),
113
+ );
114
+
115
+ it(
116
+ 'fallback to runPromiseUnwrapped when no ff context',
117
+ Effect.fn(function* () {
118
+ const effectProcedure = createHandler(
119
+ os
120
+ .$context<{ ff?: FfOrpcCtx<Deps> }>()
121
+ .input(v.object({ message: v.string() })),
122
+ Effect.fn(function* ({ input }) {
123
+ return `${input.message} ${(yield* Deps).value}`;
124
+ }),
125
+ );
126
+ const procedure = yield* effectProcedure;
127
+
128
+ const result = yield* Effect.promise(() =>
129
+ call(procedure, { message: 'hello' }, { context: {} }),
130
+ );
131
+
132
+ expect(result).toBe('hello world');
133
+ }),
134
+ );
59
135
  });
@@ -2,6 +2,34 @@ import { Effect } from 'effect';
2
2
  import { extract } from '../../extract';
3
3
  import { runPromiseUnwrapped } from '../../run-promise-unwrapped';
4
4
 
5
+ export namespace FfOrpcCtx {
6
+ const TAG = 'ff-orpc';
7
+
8
+ export function create<R>(input: {
9
+ runEffect: <A = unknown, E = unknown>(
10
+ effect: Effect.Effect<A, E, R>,
11
+ ) => Promise<A>;
12
+ }) {
13
+ return {
14
+ _tag: TAG,
15
+ runEffect: input.runEffect,
16
+ };
17
+ }
18
+
19
+ export function is(ctx: unknown): ctx is FfOrpcCtx.Type<unknown> {
20
+ return (
21
+ typeof ctx === 'object' &&
22
+ ctx !== null &&
23
+ '_tag' in ctx &&
24
+ ctx._tag === TAG
25
+ );
26
+ }
27
+
28
+ export type Type<R> = ReturnType<typeof create<R>>;
29
+ }
30
+
31
+ export type FfOrpcCtx<R> = FfOrpcCtx.Type<R>;
32
+
5
33
  type SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER> = {
6
34
  handler: (handler: (_: INPUT) => Promise<OUTPUT>) => IMPLEMENTED_HANDLER;
7
35
  };
@@ -25,14 +53,22 @@ type SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER> = {
25
53
  * );
26
54
  * ```
27
55
  **/
28
- export function createHandler<INPUT, OUTPUT, IMPLEMENTED_HANDLER, R>(
29
- builder: SimpleBuilder<INPUT, OUTPUT, IMPLEMENTED_HANDLER>,
30
- handler: (opt: INPUT) => Effect.Effect<OUTPUT, unknown, R>,
56
+ export function createHandler<
57
+ OPT extends { context: { ff?: FfOrpcCtx<never> } },
58
+ OUTPUT,
59
+ IMPLEMENTED_HANDLER,
60
+ R,
61
+ >(
62
+ builder: SimpleBuilder<OPT, OUTPUT, IMPLEMENTED_HANDLER>,
63
+ handler: (opt: OPT) => Effect.Effect<OUTPUT, unknown, R>,
31
64
  ) {
32
65
  return Effect.gen(function* () {
33
66
  const ext_handler = yield* extract(handler);
34
- return builder.handler(async (opt) =>
35
- ext_handler(opt).pipe((e) => runPromiseUnwrapped(e)),
36
- );
67
+ return builder.handler(async (opt) => {
68
+ const runEffect = FfOrpcCtx.is(opt.context.ff)
69
+ ? opt.context.ff.runEffect
70
+ : runPromiseUnwrapped;
71
+ return ext_handler(opt).pipe((e) => runEffect(e));
72
+ });
37
73
  });
38
74
  }