diff --git a/apps/content/docs/integrations/effect.md b/apps/content/docs/integrations/effect.md index 19c3a3f55..305199c2d 100644 --- a/apps/content/docs/integrations/effect.md +++ b/apps/content/docs/integrations/effect.md @@ -83,12 +83,12 @@ import { call, os } from '@orpc/server' import { handlerGen, WithEffectContext } from '@orpc/experimental-effect' import { Context, Effect } from 'effect' -class Random extends Context.Tag('MyRandomService')< +class Random extends Context.Service< Random, { readonly next: Effect.Effect } ->() {} +>()('MyRandomService') {} interface ServerContext extends WithEffectContext {} @@ -149,7 +149,7 @@ export async function fetch(request: Request) { context: { '~effect/context': Context.empty(), '~effect/wrap': (effect, opts) => effect.pipe( - Effect.catchAllCause((cause) => { + Effect.catchCause((cause) => { }) ), @@ -192,13 +192,13 @@ if (isInferableError(error)) { ## Effect Schema -oRPC natively supports [Standard Schema](https://standardschema.dev/schema#what-schema-libraries-implement-the-spec), and [Effect Schema](https://effect.website/docs/schema/introduction/) implements that spec through [Schema.standardSchemaV1](https://effect.website/docs/schema/standard-schema/): +oRPC natively supports [Standard Schema](https://standardschema.dev/schema#what-schema-libraries-implement-the-spec), and [Effect Schema](https://effect.website/docs/schema/introduction/) implements that spec through [Schema.toStandardSchemaV1](https://effect.website/docs/schema/standard-schema/): ```ts import { Schema } from 'effect' const procedure = os - .input(Schema.standardSchemaV1(Schema.Struct({ name: Schema.String }))) + .input(Schema.toStandardSchemaV1(Schema.Struct({ name: Schema.String }))) .handler(handlerGen(function* ({ input, context }) { return `Hello ${input.name}!` })) diff --git a/apps/content/package.json b/apps/content/package.json index a0634e5db..997351f7c 100644 --- a/apps/content/package.json +++ b/apps/content/package.json @@ -30,7 +30,7 @@ "@tanstack/svelte-query": "^6.1.34", "@tanstack/vue-query": "^5.101.0", "@types/node": "^26.0.0", - "effect": "^3.21.3", + "effect": "4.0.0-beta.90", "markdown-it-task-lists": "^2.1.1", "mermaid": "^11.15.0", "openai": "^6.44.0", diff --git a/packages/effect/package.json b/packages/effect/package.json index ab7e83ee5..ea4b8c750 100644 --- a/packages/effect/package.json +++ b/packages/effect/package.json @@ -51,7 +51,7 @@ "type:check": "tsc -b" }, "peerDependencies": { - "effect": ">=3.21.2" + "effect": ">=4.0.0-beta.90" }, "dependencies": { "@orpc/contract": "workspace:*", @@ -60,6 +60,6 @@ "@orpc/shared": "workspace:*" }, "devDependencies": { - "effect": "^3.21.3" + "effect": "4.0.0-beta.90" } } diff --git a/packages/effect/src/converter.test.ts b/packages/effect/src/converter.test.ts index 5f358741b..0fb71de07 100644 --- a/packages/effect/src/converter.test.ts +++ b/packages/effect/src/converter.test.ts @@ -33,6 +33,22 @@ describe('effectSchemaToJsonSchemaConverter', () => { expect(optional).toBe(false) }) + it('uses standard json schema input and output generators', () => { + const schema = toStandardSchema(Effect.Schema.NumberFromString) + expect(converter.convert(schema, 'input')).toEqual([ + expect.objectContaining({ type: 'string' }), + false, + ]) + expect(converter.convert(schema, 'output')).toEqual([ + expect.objectContaining({ + anyOf: expect.arrayContaining([ + expect.objectContaining({ type: 'number' }), + ]), + }), + false, + ]) + }) + it('marks as optional if direction is input and schema accept undefined', () => { const [, optional1] = converter.convert(toStandardSchema(Effect.Schema.Unknown), 'input') expect(optional1).toBe(true) @@ -43,12 +59,13 @@ describe('effectSchemaToJsonSchemaConverter', () => { expect(optional1).toBe(true) }) - it('marks as required if validation throw', () => { + it('keeps converting and marks as required if standard validation throws', () => { const schema = toStandardSchema(Effect.Schema.Unknown) ;(schema as any)['~standard'].validate = () => { throw new Error('test') } - const [, optional] = converter.convert(schema, 'input') + const [jsonSchema, optional] = converter.convert(schema, 'input') + expect(jsonSchema).toEqual(expect.any(Object)) expect(optional).toBe(false) }) }) diff --git a/packages/effect/src/converter.ts b/packages/effect/src/converter.ts index a58ac82c1..04de6efdd 100644 --- a/packages/effect/src/converter.ts +++ b/packages/effect/src/converter.ts @@ -1,26 +1,18 @@ import type { AnySchema } from '@orpc/contract' import type { JsonSchema, JsonSchemaConverter, JsonSchemaConverterDirection } from '@orpc/json-schema' -import type { Schema as EffectSchema } from 'effect' -import { JSONSchema } from 'effect' +import { StandardJsonSchemaConverter } from '@orpc/json-schema' +import { Schema as EffectSchema } from 'effect' export class EffectSchemaToJsonSchemaConverter implements JsonSchemaConverter { + private readonly converter = new StandardJsonSchemaConverter() + condition(schema: AnySchema | undefined, _direction: JsonSchemaConverterDirection): boolean { return schema?.['~standard'].vendor === 'effect' } convert(schema: AnySchema | undefined, direction: JsonSchemaConverterDirection): [jsonSchema: JsonSchema, optional: boolean] { - const effectSchema = schema as unknown as EffectSchema.Schema & AnySchema - const jsonSchema = JSONSchema.make(effectSchema, { target: 'jsonSchema2020-12' }) - - let optional = false - try { - const result = effectSchema['~standard'].validate(undefined) - if (!(result instanceof Promise) && !result.issues) { - optional = direction === 'input' ? true : result.value === undefined - } - } - catch {} - - return [jsonSchema as JsonSchema, optional] + const effectSchema = schema as EffectSchema.Constraint & AnySchema + const standardJsonSchema = EffectSchema.toStandardJSONSchemaV1(effectSchema) + return this.converter.convert(standardJsonSchema, direction) } } diff --git a/packages/effect/src/extensions/effect.ts b/packages/effect/src/extensions/effect.ts index e9135d16a..affd31be6 100644 --- a/packages/effect/src/extensions/effect.ts +++ b/packages/effect/src/extensions/effect.ts @@ -1,7 +1,6 @@ import type { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, InitialInputSchema, Schema } from '@orpc/contract' import type { AnyORPCError, Context, DecoratedProcedure, ImplementedProcedure, MergedContext, ORPCErrorConstructorMap } from '@orpc/server' import type { Effect } from 'effect' -import type { YieldWrap } from 'effect/Utils' import type { WithEffectContext } from '../context' import type { HandlerGen, InferYieldError } from '../handler' import { Builder, ProcedureImplementer } from '@orpc/server' @@ -13,11 +12,11 @@ declare module '@orpc/server' { TErrorMap extends ErrorMap, > { effect< - TYield extends YieldWrap ? S : never - >>, + >, TReturn, >( handler: HandlerGen< @@ -43,11 +42,11 @@ declare module '@orpc/server' { TErrorMap extends ErrorMap, > { effect< - TYield extends YieldWrap extends WithEffectContext ? S : never - >>, + >, TReturn, >( handler: HandlerGen< @@ -74,11 +73,11 @@ declare module '@orpc/server' { TErrorMap extends ErrorMap, > { effect< - TYield extends YieldWrap extends WithEffectContext ? S : never - >>, + >, TReturn, >( handler: HandlerGen< @@ -105,11 +104,11 @@ declare module '@orpc/server' { TErrorMap extends ErrorMap, > { effect< - TYield extends YieldWrap extends WithEffectContext ? S : never - >>, + >, TReturn extends InferSchemaInput | AnyORPCError, >( handler: HandlerGen< @@ -137,11 +136,11 @@ declare module '@orpc/server' { TErrorMap extends ErrorMap, > { effect< - TYield extends YieldWrap extends WithEffectContext ? S : never - >>, + >, TReturn extends InferSchemaInput | AnyORPCError, >( handler: HandlerGen< @@ -172,11 +171,11 @@ declare module '@orpc/server' { handler: HandlerGen< MergedContext, InferSchemaOutput, - YieldWrap extends WithEffectContext ? S : never - >>, + >, AnyORPCError | InferSchemaInput, ORPCErrorConstructorMap >, diff --git a/packages/effect/src/extensions/input-output.test-d.ts b/packages/effect/src/extensions/input-output.test-d.ts index f7f86d25a..34291f78e 100644 --- a/packages/effect/src/extensions/input-output.test-d.ts +++ b/packages/effect/src/extensions/input-output.test-d.ts @@ -14,15 +14,7 @@ const errorMap = { const schema1 = z.object({ schema1: z.number().transform(n => `${n}`) }) const schema2 = z.object({ schema2: z.number().transform(n => `${n}`) }) -const NumberFromString = EffectSchema.transform( - EffectSchema.String, - EffectSchema.JsonNumber, - { - strict: true, - decode: literal => Number(literal), - encode: number => number.toString(), - }, -) +const NumberFromString = EffectSchema.NumberFromString it('adds .input .output into ContractBuilder', async () => { const builder = {} as ContractBuilder diff --git a/packages/effect/src/extensions/input-output.ts b/packages/effect/src/extensions/input-output.ts index 74563f88e..f69142ac4 100644 --- a/packages/effect/src/extensions/input-output.ts +++ b/packages/effect/src/extensions/input-output.ts @@ -5,43 +5,49 @@ import { Builder } from '@orpc/server' import { Schema as EffectSchema } from 'effect' import { toStandardSchema } from '../schema' +function isEffectConstraintDecoder( + schema: AnySchema | EffectSchema.ConstraintDecoder, +): schema is EffectSchema.ConstraintDecoder { + return EffectSchema.isSchema(schema) +} + declare module '@orpc/contract' { interface ContractBuilder< TErrorMap extends ErrorMap, > { - input( - schema: EffectSchema.Schema, - ): ProcedureContractBuilderWithInput, TErrorMap> + input>( + schema: S, + ): ProcedureContractBuilderWithInput, TErrorMap> - output( - schema: EffectSchema.Schema, - ): ProcedureContractBuilderWithOutput, TErrorMap> + output>( + schema: S, + ): ProcedureContractBuilderWithOutput, TErrorMap> } interface ProcedureContractBuilderWithInput< TInputSchema extends AnySchema, TErrorMap extends ErrorMap, > { - input( - schema: EffectSchema.Schema, - ): ProcedureContractBuilderWithInput, TInputSchema>, TErrorMap> + input>( + schema: S, + ): ProcedureContractBuilderWithInput, TInputSchema>, TErrorMap> - output( - schema: EffectSchema.Schema, - ): ProcedureContractBuilderWithInputOutput, TErrorMap> + output>( + schema: S, + ): ProcedureContractBuilderWithInputOutput, TErrorMap> } interface ProcedureContractBuilderWithOutput< TOutputSchema extends AnySchema, TErrorMap extends ErrorMap, > { - input( - schema: EffectSchema.Schema, - ): ProcedureContractBuilderWithInputOutput, TOutputSchema, TErrorMap> + input>( + schema: S, + ): ProcedureContractBuilderWithInputOutput, TOutputSchema, TErrorMap> - output( - schema: EffectSchema.Schema, - ): ProcedureContractBuilderWithOutput, TOutputSchema>, TErrorMap> + output>( + schema: S, + ): ProcedureContractBuilderWithOutput, TOutputSchema>, TErrorMap> } interface ProcedureContractBuilderWithInputOutput< @@ -49,24 +55,24 @@ declare module '@orpc/contract' { TOutputSchema extends AnySchema, TErrorMap extends ErrorMap, > { - input( - schema: EffectSchema.Schema, - ): ProcedureContractBuilderWithInputOutput, TInputSchema>, TOutputSchema, TErrorMap> + input>( + schema: S, + ): ProcedureContractBuilderWithInputOutput, TInputSchema>, TOutputSchema, TErrorMap> - output( - schema: EffectSchema.Schema, - ): ProcedureContractBuilderWithInputOutput, TOutputSchema>, TErrorMap> + output>( + schema: S, + ): ProcedureContractBuilderWithInputOutput, TOutputSchema>, TErrorMap> } } const OriginalContractBuilderInput = ContractBuilder.prototype.input -ContractBuilder.prototype.input = function input(schema: AnySchema | EffectSchema.Schema) { - return OriginalContractBuilderInput.bind(this)(EffectSchema.isSchema(schema) ? toStandardSchema(schema) : schema) +ContractBuilder.prototype.input = function input(schema: AnySchema | EffectSchema.ConstraintDecoder) { + return OriginalContractBuilderInput.bind(this)(isEffectConstraintDecoder(schema) ? toStandardSchema(schema) : schema) } const OriginalContractBuilderOutput = ContractBuilder.prototype.output -ContractBuilder.prototype.output = function output(schema: AnySchema | EffectSchema.Schema) { - return OriginalContractBuilderOutput.bind(this)(EffectSchema.isSchema(schema) ? toStandardSchema(schema) : schema) +ContractBuilder.prototype.output = function output(schema: AnySchema | EffectSchema.ConstraintDecoder) { + return OriginalContractBuilderOutput.bind(this)(isEffectConstraintDecoder(schema) ? toStandardSchema(schema) : schema) } declare module '@orpc/server' { @@ -74,13 +80,13 @@ declare module '@orpc/server' { TInitialContext extends Context, TErrorMap extends ErrorMap, > { - input( - schema: EffectSchema.Schema, - ): BuilderWithInput, TErrorMap> + input>( + schema: S, + ): BuilderWithInput, TErrorMap> - output( - schema: EffectSchema.Schema, - ): BuilderWithOutput, TErrorMap> + output>( + schema: S, + ): BuilderWithOutput, TErrorMap> } interface BuilderWithMiddlewares< @@ -88,13 +94,13 @@ declare module '@orpc/server' { TInjectedContext extends Context, TErrorMap extends ErrorMap, > { - input( - schema: EffectSchema.Schema, - ): BuilderWithInput, TErrorMap> + input>( + schema: S, + ): BuilderWithInput, TErrorMap> - output( - schema: EffectSchema.Schema, - ): BuilderWithOutput, TErrorMap> + output>( + schema: S, + ): BuilderWithOutput, TErrorMap> } interface BuilderWithInput< @@ -103,13 +109,13 @@ declare module '@orpc/server' { TInputSchema extends AnySchema, TErrorMap extends ErrorMap, > { - input( - schema: EffectSchema.Schema, - ): BuilderWithInput, TInputSchema>, TErrorMap> + input>( + schema: S, + ): BuilderWithInput, TInputSchema>, TErrorMap> - output( - schema: EffectSchema.Schema, - ): BuilderWithInputOutput, TErrorMap> + output>( + schema: S, + ): BuilderWithInputOutput, TErrorMap> } interface BuilderWithOutput< @@ -118,13 +124,13 @@ declare module '@orpc/server' { TOutputSchema extends AnySchema, TErrorMap extends ErrorMap, > { - input( - schema: EffectSchema.Schema, - ): BuilderWithInputOutput, TOutputSchema, TErrorMap> + input>( + schema: S, + ): BuilderWithInputOutput, TOutputSchema, TErrorMap> - output( - schema: EffectSchema.Schema, - ): BuilderWithOutput, TOutputSchema>, TErrorMap> + output>( + schema: S, + ): BuilderWithOutput, TOutputSchema>, TErrorMap> } interface BuilderWithInputOutput< @@ -134,23 +140,23 @@ declare module '@orpc/server' { TOutputSchema extends AnySchema, TErrorMap extends ErrorMap, > { - input( - schema: EffectSchema.Schema, - ): BuilderWithInputOutput, TInputSchema>, TOutputSchema, TErrorMap> + input>( + schema: S, + ): BuilderWithInputOutput, TInputSchema>, TOutputSchema, TErrorMap> - output( - schema: EffectSchema.Schema, - ): BuilderWithInputOutput, TOutputSchema>, TErrorMap> + output>( + schema: S, + ): BuilderWithInputOutput, TOutputSchema>, TErrorMap> } } const OriginalBuilderInput = Builder.prototype.input -Builder.prototype.input = function input(schema: AnySchema | EffectSchema.Schema) { - return OriginalBuilderInput.bind(this)(EffectSchema.isSchema(schema) ? toStandardSchema(schema) : schema) +Builder.prototype.input = function input(schema: AnySchema | EffectSchema.ConstraintDecoder) { + return OriginalBuilderInput.bind(this)(isEffectConstraintDecoder(schema) ? toStandardSchema(schema) : schema) } const OriginalBuilderOutput = Builder.prototype.output -Builder.prototype.output = function output(schema: AnySchema | EffectSchema.Schema) { - return OriginalBuilderOutput.bind(this)(EffectSchema.isSchema(schema) ? toStandardSchema(schema) : schema) +Builder.prototype.output = function output(schema: AnySchema | EffectSchema.ConstraintDecoder) { + return OriginalBuilderOutput.bind(this)(isEffectConstraintDecoder(schema) ? toStandardSchema(schema) : schema) } diff --git a/packages/effect/src/handler.test-d.ts b/packages/effect/src/handler.test-d.ts index fcf376551..bb9c46979 100644 --- a/packages/effect/src/handler.test-d.ts +++ b/packages/effect/src/handler.test-d.ts @@ -6,19 +6,19 @@ import { Context, Effect } from 'effect' import { z } from 'zod' import { handlerGen } from './handler' -class Service1 extends Context.Tag('Service1')< +class Service1 extends Context.Service< Service1, { readonly id: 'Service1' } ->() {} +>()('Service1') {} -class Service2 extends Context.Tag('Service2')< +class Service2 extends Context.Service< Service2, { readonly id: 'Service2' } ->() {} +>()('Service2') {} const errorMap = { BASE: { diff --git a/packages/effect/src/handler.test.ts b/packages/effect/src/handler.test.ts index 8e7695852..8b8c118d2 100644 --- a/packages/effect/src/handler.test.ts +++ b/packages/effect/src/handler.test.ts @@ -10,19 +10,19 @@ beforeEach(() => { vi.clearAllMocks() }) -class Service1 extends Context.Tag('Service1')< +class Service1 extends Context.Service< Service1, { readonly id: 'Service1' } ->() {} +>()('Service1') {} -class Service2 extends Context.Tag('Service2')< +class Service2 extends Context.Service< Service2, { readonly id: 'Service2' } ->() {} +>()('Service2') {} describe('handlerGen', () => { it('works with native Effect syntax, and treat return/yield ORPCError as inferable', async () => { diff --git a/packages/effect/src/handler.ts b/packages/effect/src/handler.ts index b97fef1ff..8d50bf4c4 100644 --- a/packages/effect/src/handler.ts +++ b/packages/effect/src/handler.ts @@ -1,20 +1,19 @@ import type { AnyORPCError, Context, ORPCErrorConstructorMap, ProcedureHandler, ProcedureHandlerOptions } from '@orpc/server' -import type { YieldWrap } from 'effect/Utils' import type { WithEffectContext } from './context' import { ORPCError } from '@orpc/server' import { Effect, Context as EffectContext } from 'effect' import { runPromise } from './runtime' -export type InferYieldError = [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never +export type InferYieldError = [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? E : never export interface HandlerGen< TCurrentContext extends Context, TInput, - TYield extends YieldWrap ? S : never - >>, + >, TReturn, TErrorConstructorMap extends ORPCErrorConstructorMap, > { @@ -28,17 +27,17 @@ export interface HandlerGen< > } -const succeedOnORPCError = Effect.catchAll(error => error instanceof ORPCError ? Effect.succeed(error) : Effect.fail(error)) +const succeedOnORPCError = Effect.catch(error => error instanceof ORPCError ? Effect.succeed(error) : Effect.fail(error)) export function handlerGen< TCurrentContext extends Context, TInput, TErrorConstructorMap extends ORPCErrorConstructorMap, - TYield extends YieldWrap ? S : never - >>, + >, TReturn, >( handler: HandlerGen, diff --git a/packages/effect/src/runtime.test.ts b/packages/effect/src/runtime.test.ts index 7fc59df25..9b64b8f77 100644 --- a/packages/effect/src/runtime.test.ts +++ b/packages/effect/src/runtime.test.ts @@ -1,3 +1,4 @@ +import { AbortError } from '@orpc/shared' import { Cause, Effect } from 'effect' import { describe, expect, it } from 'vitest' import { runPromise } from './runtime' @@ -17,21 +18,28 @@ describe('runPromise & extractErrorFromCause', () => { }) describe('failure - throws original error without FiberFailure wrapper', () => { - it('interrupts the effect when the provided signal aborts', async () => { + it('throws signal reason when interrupted with signal', async () => { + const signal = AbortSignal.timeout(0) await expect( - runPromise(Effect.never, { signal: AbortSignal.timeout(0) }), - ).rejects.toThrow(/Fiber interrupted/) + runPromise(Effect.never, { signal }), + ).rejects.toSatisfy(e => e === signal.reason) + }) + + it('throws a generic AbortError when interrupted without signal', async () => { + const effect = Effect.gen(function* () { + yield* Effect.interrupt + }) + + await expect(runPromise(effect)).rejects.toThrow(new AbortError('All fibers interrupted without error')) }) it('throws the original Error instance from Effect.fail', async () => { const original = new TypeError('typed domain error') - await expect(runPromise(Effect.fail(original))).rejects.toThrow(original) }) it('throws the original defect from Effect.die', async () => { const defect = new RangeError('unexpected defect') - await expect(runPromise(Effect.die(defect))).rejects.toThrow(defect) }) @@ -44,14 +52,6 @@ describe('runPromise & extractErrorFromCause', () => { await expect(runPromise(effect)).rejects.toThrow(defect) }) - it('throws a synthesized Error on interrupt', async () => { - const effect = Effect.gen(function* () { - yield* Effect.interrupt - }) - - await expect(runPromise(effect)).rejects.toThrow(/Fiber interrupted/) - }) - it('throws the finalizer error on sequential cause (mirrors try/finally)', async () => { const finalizerError = new Error('finalizer also failed') @@ -81,12 +81,12 @@ describe('runPromise & extractErrorFromCause', () => { await expect(runPromise(Effect.fail(original))).rejects.toBe(original) }) - it('throws a sentinel Error when cause is empty', async () => { + it('throws a empty Error when cause is empty', async () => { const effect = Effect.failCause(Cause.empty) await expect( runPromise(effect), - ).rejects.toThrow(new Error('Effect failed with no error information')) + ).rejects.toThrow(new Error('Empty cause')) }) }) }) diff --git a/packages/effect/src/runtime.ts b/packages/effect/src/runtime.ts index c6f3824f1..dd2d63665 100644 --- a/packages/effect/src/runtime.ts +++ b/packages/effect/src/runtime.ts @@ -1,31 +1,12 @@ import { AbortError } from '@orpc/shared' -import { Cause, Effect, Exit, FiberId } from 'effect' - -/** - * Extracts the most meaningful original error from an Effect Cause, - * preserving the original error instance wherever possible. - */ -export function extractErrorFromCause(cause: Cause.Cause): unknown { - return Cause.match(cause, { - onFail: error => error, - onDie: defect => defect, - onInterrupt: fiberId => new AbortError(`Fiber interrupted: ${FiberId.threadName(fiberId)}`), - onEmpty: new Error('Effect failed with no error information'), - - // Mirrors native try/finally: if the finalizer (right) also throws, - // it overwrites the original (left) — same behaviour as JS would produce - onSequential: (_left, right) => right, - onParallel: (left, _right) => left, - }) -} +import { Cause, Effect, Exit } from 'effect' export interface RunPromiseOptions { signal?: undefined | AbortSignal } /** - * Runs an Effect as a Promise while re-throwing the original error directly, - * bypassing Effect.runPromise's FiberFailure wrapper. + * Runs an Effect as a Promise and throws the most meaningful errors. */ export async function runPromise(effect: Effect.Effect, options: RunPromiseOptions = {}): Promise { const exit = await Effect.runPromiseExit(effect, options) @@ -34,5 +15,16 @@ export async function runPromise(effect: Effect.Effect, options: return exit.value } - throw extractErrorFromCause(exit.cause) + // Use AbortError for interruption-only failures. + // This is more meaningful than the generic + // `Error("All fibers interrupted without error")` from Cause.squash. + if (Cause.hasInterruptsOnly(exit.cause)) { + if (options.signal?.aborted) { + throw options.signal.reason + } + + throw new AbortError('All fibers interrupted without error') + } + + throw Cause.squash(exit.cause) } diff --git a/packages/effect/src/schema.ts b/packages/effect/src/schema.ts index e559bd8fb..4ad1393a7 100644 --- a/packages/effect/src/schema.ts +++ b/packages/effect/src/schema.ts @@ -2,10 +2,10 @@ import type { Schema } from '@orpc/contract' import { getHiddenMetaPlugins, setHiddenMetaPlugins } from '@orpc/contract' import { Schema as EffectSchema } from 'effect' -export function toStandardSchema( - schema: EffectSchema.Schema, -): Schema { - const converted = EffectSchema.standardSchemaV1(schema) +export function toStandardSchema>( + schema: S, +): Schema & S { + const converted = EffectSchema.toStandardSchemaV1(schema) const metaPlugins = getHiddenMetaPlugins(schema) if (metaPlugins) { setHiddenMetaPlugins(converted, metaPlugins) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f2eacd659..0e3b34c9d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -147,8 +147,8 @@ importers: specifier: ^26.0.0 version: 26.0.0 effect: - specifier: ^3.21.3 - version: 3.21.4 + specifier: 4.0.0-beta.90 + version: 4.0.0-beta.90 markdown-it-task-lists: specifier: ^2.1.1 version: 2.1.1 @@ -256,8 +256,8 @@ importers: version: link:../shared devDependencies: effect: - specifier: ^3.21.3 - version: 3.21.4 + specifier: 4.0.0-beta.90 + version: 4.0.0-beta.90 packages/evlog: dependencies: @@ -1758,6 +1758,36 @@ packages: '@mermaid-js/parser@1.1.1': resolution: {integrity: sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==} + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4': + resolution: {integrity: sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==} + cpu: [arm64] + os: [darwin] + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4': + resolution: {integrity: sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==} + cpu: [x64] + os: [darwin] + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4': + resolution: {integrity: sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==} + cpu: [arm64] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4': + resolution: {integrity: sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==} + cpu: [arm] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4': + resolution: {integrity: sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==} + cpu: [x64] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4': + resolution: {integrity: sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==} + cpu: [x64] + os: [win32] + '@napi-rs/wasm-runtime@1.1.5': resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} peerDependencies: @@ -4294,8 +4324,8 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - effect@3.21.4: - resolution: {integrity: sha512-B89v/xSgPbl1J2Ai2u18jxq3odpFauU1rC6/eSs4FeNHi72kwKdJp12VGigvRV2lK+kRnx+OOz41XV8guZd4gQ==} + effect@4.0.0-beta.90: + resolution: {integrity: sha512-A0U3OE+2oyK/iFG6VYbFj9gwjJ7rFXjgP7qV+m7n/4lOREp9Lfk1///SlGCpX7HRueOCZO1l7aW0KByXuJeiPA==} electron-to-chromium@1.5.376: resolution: {integrity: sha512-cUVA7/RvbFTEuw/i3obUwDTRIXojaxkResf+ibByPFxjc6XK3VNtcQXV0NSbAlJ0FMjcJGgftVVB4Qo184EXvA==} @@ -4704,9 +4734,9 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - fast-check@3.23.2: - resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} - engines: {node: '>=8.0.0'} + fast-check@4.8.0: + resolution: {integrity: sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg==} + engines: {node: '>=12.17.0'} fast-decode-uri-component@1.0.1: resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} @@ -4784,6 +4814,9 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + find-my-way-ts@0.1.6: + resolution: {integrity: sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==} + find-my-way@9.6.0: resolution: {integrity: sha512-Zf4Xve4RymLl7NgaavNebZ01joJ8MfVerOG43wy7SHLO+r+K0C6d/SE0BiR7AV5V1VOCFlOP7ecdo+I4qmiHrQ==} engines: {node: '>=20'} @@ -5096,6 +5129,10 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ini@7.0.0: + resolution: {integrity: sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} + internmap@1.0.1: resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} @@ -5345,6 +5382,9 @@ packages: knitwork@1.3.0: resolution: {integrity: sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw==} + kubernetes-types@1.30.0: + resolution: {integrity: sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==} + layout-base@1.0.2: resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} @@ -5795,9 +5835,19 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + msgpackr-extract@3.0.4: + resolution: {integrity: sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==} + hasBin: true + + msgpackr@2.0.4: + resolution: {integrity: sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA==} + muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + multipasta@0.2.7: + resolution: {integrity: sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==} + nanoid@3.3.14: resolution: {integrity: sha512-U9kYi5bpVMEI31yC8iw4bJJp0avcHXA0W8/wNfLfnvJYzihQo2ZRPYPvpAAd570HAcCBjCTN7vnr+v4StKl1IQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -5857,6 +5907,10 @@ packages: node-fetch-native@1.6.7: resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + node-gyp-build-optional-packages@5.2.2: + resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} + hasBin: true + node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true @@ -6333,8 +6387,8 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + pure-rand@8.4.0: + resolution: {integrity: sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==} qs@6.15.2: resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} @@ -7106,6 +7160,10 @@ packages: resolution: {integrity: sha512-A5F0cM6+mDleacLIEUkmfpkBbnHJFV1d2rprHU2MXNk7mlxHq2zGojA+SRvQD1RoMo9gqjZPWEaKG4v1BQ48lw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + toml@4.1.1: + resolution: {integrity: sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==} + engines: {node: '>=20'} + tough-cookie@6.0.1: resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} engines: {node: '>=16'} @@ -8678,6 +8736,24 @@ snapshots: dependencies: '@chevrotain/types': 11.1.2 + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4': + optional: true + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4': + optional: true + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4': + optional: true + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 @@ -11766,10 +11842,18 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - effect@3.21.4: + effect@4.0.0-beta.90: dependencies: '@standard-schema/spec': 1.1.0 - fast-check: 3.23.2 + fast-check: 4.8.0 + find-my-way-ts: 0.1.6 + ini: 7.0.0 + kubernetes-types: 1.30.0 + msgpackr: 2.0.4 + multipasta: 0.2.7 + toml: 4.1.1 + uuid: 14.0.0 + yaml: 2.9.0 electron-to-chromium@1.5.376: {} @@ -12228,9 +12312,9 @@ snapshots: extend@3.0.2: {} - fast-check@3.23.2: + fast-check@4.8.0: dependencies: - pure-rand: 6.1.0 + pure-rand: 8.4.0 fast-decode-uri-component@1.0.1: {} @@ -12319,6 +12403,8 @@ snapshots: dependencies: to-regex-range: 5.0.1 + find-my-way-ts@0.1.6: {} + find-my-way@9.6.0: dependencies: fast-deep-equal: 3.1.3 @@ -12682,6 +12768,8 @@ snapshots: inherits@2.0.4: {} + ini@7.0.0: {} + internmap@1.0.1: {} internmap@2.0.3: {} @@ -12902,6 +12990,8 @@ snapshots: knitwork@1.3.0: {} + kubernetes-types@1.30.0: {} + layout-base@1.0.2: {} layout-base@2.0.1: {} @@ -13543,8 +13633,26 @@ snapshots: ms@2.1.3: {} + msgpackr-extract@3.0.4: + dependencies: + node-gyp-build-optional-packages: 5.2.2 + optionalDependencies: + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.4 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.4 + '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.4 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.4 + '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.4 + '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.4 + optional: true + + msgpackr@2.0.4: + optionalDependencies: + msgpackr-extract: 3.0.4 + muggle-string@0.4.1: {} + multipasta@0.2.7: {} + nanoid@3.3.14: {} nanoid@5.1.14: {} @@ -13591,6 +13699,11 @@ snapshots: node-fetch-native@1.6.7: {} + node-gyp-build-optional-packages@5.2.2: + dependencies: + detect-libc: 2.1.2 + optional: true + node-gyp-build@4.8.4: optional: true @@ -14068,7 +14181,7 @@ snapshots: punycode@2.3.1: {} - pure-rand@6.1.0: {} + pure-rand@8.4.0: {} qs@6.15.2: dependencies: @@ -15035,6 +15148,8 @@ snapshots: dependencies: eslint-visitor-keys: 5.0.1 + toml@4.1.1: {} + tough-cookie@6.0.1: dependencies: tldts: 7.4.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c06038768..44e79bd2d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -27,6 +27,7 @@ minimumReleaseAgeExclude: - '@standardserver/node@0.0.24' - '@standardserver/peer@0.0.24' - '@standardserver/shared@0.0.24' + - effect@4.0.0-beta.90 allowBuilds: '@parcel/watcher': false '@scarf/scarf': false @@ -34,6 +35,7 @@ allowBuilds: '@tree-sitter-grammars/tree-sitter-yaml': false core-js-pure: false esbuild: false + msgpackr-extract: false msw: true protobufjs: false sharp: false