chore(effect): update to beta.107 (#43109)

This commit is contained in:
Kit Langton
2026-08-17 17:54:08 -04:00
committed by GitHub
parent 8fc65b3038
commit d9b81d2233
91 changed files with 1332 additions and 1117 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
import { Schema } from "effect"
import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi"
export class Missing extends Schema.TaggedErrorClass<Missing>()("Missing", {
export class Missing extends Schema.TaggedError<Missing>()("Missing", {
message: Schema.String,
}) {}
+73 -10
View File
@@ -504,7 +504,7 @@ describe("HttpApiCodegen.generate", () => {
})
test("preserves optional keys in Promise error types", () => {
class OptionalError extends Schema.TaggedErrorClass<OptionalError>()(
class OptionalError extends Schema.TaggedError<OptionalError>()(
"OptionalError",
{ message: Schema.String, detail: Schema.String.pipe(Schema.optional) },
{ httpApiStatus: 400 },
@@ -519,7 +519,7 @@ describe("HttpApiCodegen.generate", () => {
})
test("supports name-discriminated Promise errors", () => {
class NamedError extends Schema.ErrorClass<NamedError>("NamedError")(
class NamedError extends Schema.Error<NamedError>("NamedError")(
{ name: Schema.Literal("NamedError"), message: Schema.String },
{ httpApiStatus: 400 },
) {}
@@ -535,7 +535,7 @@ describe("HttpApiCodegen.generate", () => {
})
test("preserves reflected default error statuses", () => {
class MissingStatus extends Schema.TaggedErrorClass<MissingStatus>()("MissingStatus", {
class MissingStatus extends Schema.TaggedError<MissingStatus>()("MissingStatus", {
message: Schema.String,
}) {}
const output = emitPromise(
@@ -579,10 +579,14 @@ describe("HttpApiCodegen.generate", () => {
const Referenced = Schema.Struct({ value: Schema.String }).annotate({ identifier: "Referenced" })
const output = emitPromise(
compileContract(
api(
HttpApiEndpoint.get("get", "/session", {
success: Schema.Struct({ data: Referenced }),
}),
HttpApi.make("test").add(
HttpApiGroup.make("session")
.add(HttpApiEndpoint.get("get", "/session", { success: Schema.Struct({ data: Referenced }) }))
.add(
HttpApiEndpoint.get("list", "/sessions", {
success: Schema.Struct({ data: Schema.Array(Referenced) }),
}),
),
),
),
)
@@ -590,6 +594,21 @@ describe("HttpApiCodegen.generate", () => {
const types = output.files.find((file) => file.path === "types.ts")?.content
expect(types).toContain('export type Referenced = { readonly "value": string }')
expect(types).toContain('export type SessionGetOutput = ({ readonly "data": Referenced })["data"]')
expect(types).not.toContain("Referenced1")
})
test("inlines shared anonymous Promise wire types", () => {
const Shared = Schema.Struct({ value: Schema.String })
const output = emitPromise(
compileContract(
api(HttpApiEndpoint.get("get", "/session", { success: Schema.Struct({ first: Shared, second: Shared }) })),
),
)
const types = output.files.find((file) => file.path === "types.ts")?.content
expect(types).toContain('readonly "first": ({ readonly "value": string })')
expect(types).toContain('readonly "second": ({ readonly "value": string })')
expect(types).not.toContain("export type Objects")
})
test("emits mutable Promise outputs without restricting inputs", () => {
@@ -647,6 +666,37 @@ describe("HttpApiCodegen.generate", () => {
expect(types).toContain("export type ExampleName2 = string")
})
test("keeps conflicting Promise reference identifiers distinct", () => {
const First = Schema.Struct({ value: Schema.String }).annotate({ identifier: "Shared" })
const Second = Schema.Struct({ value: Schema.Number }).annotate({ identifier: "Shared" })
const output = emitPromise(
compileContract(
api(HttpApiEndpoint.get("get", "/session", { success: Schema.Struct({ first: First, second: Second }) })),
),
)
const types = output.files.find((file) => file.path === "types.ts")?.content
expect(types).toContain('export type Shared = { readonly "value": string }')
expect(types).toContain('export type Shared1 = { readonly "value": number }')
expect(types).toContain('readonly "first": Shared, readonly "second": Shared1')
})
test("deduplicates equivalent Promise references with the same identifier", () => {
const First = Schema.String.annotate({ identifier: "Shared", description: "first" })
const Second = Schema.String.annotate({ identifier: "Shared", description: "second" })
const output = emitPromise(
compileContract(
api(HttpApiEndpoint.get("get", "/session", { success: Schema.Struct({ first: First, second: Second }) })),
),
)
const types = output.files.find((file) => file.path === "types.ts")?.content
expect(types).toContain("export type Shared = string")
expect(types).not.toContain("export type Shared1")
expect(types).toContain('readonly "first": Shared, readonly "second": Shared')
})
test("emits Effect Json schemas as standalone Promise types", () => {
const output = emitPromise(
compileContract(
@@ -1347,6 +1397,19 @@ describe("HttpApiCodegen.generate", () => {
).toThrow("Effect schema requires authoritative import: session.get")
})
test("rejects same-shape custom transformations", () => {
const Trimmed = Schema.String.pipe(
Schema.decodeTo(Schema.String, {
decode: SchemaGetter.transform((value) => value.trim()),
encode: SchemaGetter.transform((value) => value),
}),
)
expect(() => compile(api(HttpApiEndpoint.get("get", "/session", { success: Trimmed })))).toThrow(
"Effect schema requires authoritative import: session.get",
)
})
test("rejects custom validation checks without portable metadata", () => {
const Positive = Schema.Number.check(Schema.makeFilter((value) => (value > 0 ? undefined : "positive")))
@@ -1404,7 +1467,7 @@ describe("HttpApiCodegen.generate", () => {
})
test("preserves errors from server-only middleware", () => {
class Unauthorized extends Schema.TaggedErrorClass<Unauthorized>()("Unauthorized", {}) {}
class Unauthorized extends Schema.TaggedError<Unauthorized>()("Unauthorized", {}) {}
class Authorization extends HttpApiMiddleware.Service<Authorization>()("Authorization", {
error: Unauthorized,
}) {}
@@ -1415,12 +1478,12 @@ describe("HttpApiCodegen.generate", () => {
expect(output.operations[0]).toBeDefined()
expect(output.files.find((file) => file.path === "session.ts")?.content).toContain(
'extends Schema.TaggedErrorClass<Endpoint0Error0Class>("Unauthorized")',
'extends Schema.TaggedError<Endpoint0Error0Class>("Unauthorized")',
)
})
test("preserves tagged error response statuses", () => {
class Missing extends Schema.TaggedErrorClass<Missing>()("Missing", {}) {}
class Missing extends Schema.TaggedError<Missing>()("Missing", {}) {}
const output = compile(
api(
HttpApiEndpoint.get("get", "/session", {
@@ -1,5 +1,5 @@
import { Schema } from "effect"
export class ClientError extends Schema.TaggedErrorClass<ClientError>()("ClientError", {
export class ClientError extends Schema.TaggedError<ClientError>()("ClientError", {
cause: Schema.Defect(),
}) {}
@@ -15,7 +15,7 @@ const Endpoint2Params = Schema.Struct({ sessionID: Schema.String })
const Endpoint2Success = Schema.Struct({ data: Schema.String })
class Endpoint2Error0Class extends Schema.TaggedErrorClass<Endpoint2Error0Class>("Missing")("Missing", {
class Endpoint2Error0Class extends Schema.TaggedError<Endpoint2Error0Class>("Missing")("Missing", {
message: Schema.String,
}) {}
const Endpoint2Error0 = Endpoint2Error0Class.annotate({ httpApiStatus: 404 })