From cccaac7ad935253265a170dba4fad61b9c1545a6 Mon Sep 17 00:00:00 2001 From: Thibault Le Ouay Ducasse Date: Thu, 27 Aug 2026 16:09:27 +0200 Subject: [PATCH] deps: upgrade to effect 4 --- apps/workflows/src/cron/checker.ts | 12 +- .../src/cron/external-incidents-prune.ts | 2 +- apps/workflows/src/cron/external-status.ts | 10 +- apps/workflows/src/cron/index.ts | 2 +- packages/emails/src/client.tsx | 4 +- .../status-fetcher/__tests__/fetch.test.ts | 2 +- packages/status-fetcher/__tests__/helpers.ts | 6 +- packages/status-fetcher/src/fetch.ts | 40 +++--- packages/subscriptions/src/channels/retry.ts | 8 +- pnpm-lock.yaml | 121 +++++++++++++++--- pnpm-workspace.yaml | 5 +- 11 files changed, 151 insertions(+), 61 deletions(-) diff --git a/apps/workflows/src/cron/checker.ts b/apps/workflows/src/cron/checker.ts index 30e226cd..b7a0a435 100644 --- a/apps/workflows/src/cron/checker.ts +++ b/apps/workflows/src/cron/checker.ts @@ -33,7 +33,7 @@ import { type tpcPayloadSchema, transformHeaders, } from "@openstatus/utils"; -import { Effect, Either, Schedule } from "effect"; +import { Effect, Result, Schedule } from "effect"; import { z } from "zod"; import { env } from "../env"; @@ -239,22 +239,22 @@ export async function sendCheckerTasks( times: 3, schedule: Schedule.exponential("1000 millis"), }), - Effect.either, + Effect.result, ), { concurrency: 100 }, ), ); for (const result of results) { - if (Either.isLeft(result)) { + if (Result.isFailure(result)) { logger.error("Task creation failed after retries", { - error_message: result.left.message, + error_message: result.failure.message, }); } } - const success = results.filter(Either.isRight).length; - const failed = results.filter(Either.isLeft).length; + const success = results.filter(Result.isSuccess).length; + const failed = results.filter(Result.isFailure).length; logger.info("Completed cron job", { periodicity, diff --git a/apps/workflows/src/cron/external-incidents-prune.ts b/apps/workflows/src/cron/external-incidents-prune.ts index c14b5b6a..a63b2803 100644 --- a/apps/workflows/src/cron/external-incidents-prune.ts +++ b/apps/workflows/src/cron/external-incidents-prune.ts @@ -38,7 +38,7 @@ export async function handleExternalIncidentsPruneCron(c: Context) { void cronCompleted(); }), ), - Effect.catchAll((e) => + Effect.catch((e) => Effect.sync(() => { logger.error("external-incidents-prune tick errored: {message}", { message: e.message, diff --git a/apps/workflows/src/cron/external-status.ts b/apps/workflows/src/cron/external-status.ts index 9ab070d7..56d7b613 100644 --- a/apps/workflows/src/cron/external-status.ts +++ b/apps/workflows/src/cron/external-status.ts @@ -183,7 +183,7 @@ function runStatusPhase( ), // Failure reporting is deferred: the detect step after this phase // either merges it into a detection story or reports it plain. - Effect.catchAll((err: FetchError) => + Effect.catch((err: FetchError) => Effect.succeed({ kind: "fail", slug: entry.id, @@ -237,7 +237,7 @@ function runIncidentPhase( ), ), ), - Effect.catchAll((err: FetchError) => + Effect.catch((err: FetchError) => Effect.sync(() => { reportFetchFailure({ phase: "incidents", @@ -307,7 +307,7 @@ function runComponentPhase( }), ), ), - Effect.catchAll((err: FetchError) => + Effect.catch((err: FetchError) => Effect.sync(() => { reportFetchFailure({ phase: "components", @@ -531,7 +531,7 @@ function applyDetection(args: { }); return { kind: outcome, slug: entry.id }; }), - Effect.catchAll((e) => + Effect.catch((e) => Effect.sync((): DetectOutcome => { logger.warn( "external-status detect: write failed for slug={slug}: {message}", @@ -734,7 +734,7 @@ export async function handleExternalStatusCron(c: Context) { void cronCompleted(); }), ), - Effect.catchAll((e) => + Effect.catch((e) => Effect.sync(() => { logger.error("external-status tick errored: {message}", { message: e.message, diff --git a/apps/workflows/src/cron/index.ts b/apps/workflows/src/cron/index.ts index c5096571..4b0df286 100644 --- a/apps/workflows/src/cron/index.ts +++ b/apps/workflows/src/cron/index.ts @@ -75,7 +75,7 @@ app.get("/checker/:period", async (c) => { void cronCompleted(); }), ), - Effect.catchAll((e) => + Effect.catch((e) => Effect.sync(() => { console.error(e); void reportBackgroundError(e.message); diff --git a/packages/emails/src/client.tsx b/packages/emails/src/client.tsx index 074709ec..9aca7527 100644 --- a/packages/emails/src/client.tsx +++ b/packages/emails/src/client.tsx @@ -56,9 +56,9 @@ export class EmailClient { public readonly client: Resend; // Base delay for the per-batch send retry. Overridable so tests can run the // retry path without the real ~1s exponential sleep. - private readonly retryBackoff: Duration.DurationInput; + private readonly retryBackoff: Duration.Input; - constructor(opts: { apiKey: string; retryBackoff?: Duration.DurationInput }) { + constructor(opts: { apiKey: string; retryBackoff?: Duration.Input }) { this.client = new Resend(opts.apiKey); this.retryBackoff = opts.retryBackoff ?? "1000 millis"; } diff --git a/packages/status-fetcher/__tests__/fetch.test.ts b/packages/status-fetcher/__tests__/fetch.test.ts index 5500645b..91e3ef53 100644 --- a/packages/status-fetcher/__tests__/fetch.test.ts +++ b/packages/status-fetcher/__tests__/fetch.test.ts @@ -52,7 +52,7 @@ const expectFailure = (exit: Exit.Exit): FetchError => { if (!Exit.isFailure(exit)) { throw new Error("expected Exit.Failure"); } - const failure = Cause.failureOption(exit.cause); + const failure = Cause.findErrorOption(exit.cause); if (Option.isNone(failure)) { throw new Error("expected Cause.Fail"); } diff --git a/packages/status-fetcher/__tests__/helpers.ts b/packages/status-fetcher/__tests__/helpers.ts index bcf6a527..9e0650a5 100644 --- a/packages/status-fetcher/__tests__/helpers.ts +++ b/packages/status-fetcher/__tests__/helpers.ts @@ -34,7 +34,7 @@ export const expectFetchError = ( if (!Exit.isFailure(exit)) { throw new Error("expected Exit.Failure, got Success"); } - const failure = Cause.failureOption(exit.cause); + const failure = Cause.findErrorOption(exit.cause); if (Option.isNone(failure)) { throw new Error("expected Cause.Fail, got defect"); } @@ -67,7 +67,7 @@ export const expectIncidentsFetchError = ( if (!Exit.isFailure(exit)) { throw new Error("expected Exit.Failure, got Success"); } - const failure = Cause.failureOption(exit.cause); + const failure = Cause.findErrorOption(exit.cause); if (Option.isNone(failure)) { throw new Error("expected Cause.Fail, got defect"); } @@ -100,7 +100,7 @@ export const expectComponentsFetchError = ( if (!Exit.isFailure(exit)) { throw new Error("expected Exit.Failure, got Success"); } - const failure = Cause.failureOption(exit.cause); + const failure = Cause.findErrorOption(exit.cause); if (Option.isNone(failure)) { throw new Error("expected Cause.Fail, got defect"); } diff --git a/packages/status-fetcher/src/fetch.ts b/packages/status-fetcher/src/fetch.ts index 80f25448..1750b334 100644 --- a/packages/status-fetcher/src/fetch.ts +++ b/packages/status-fetcher/src/fetch.ts @@ -37,14 +37,14 @@ export class FetchError extends Error { } } -const DEFAULT_TIMEOUT: Duration.DurationInput = "30000 millis"; +const DEFAULT_TIMEOUT: Duration.Input = "30000 millis"; export type FetchBaseOptions = { url: string; init?: Omit & { headers?: Record; }; - timeout?: Duration.DurationInput; + timeout?: Duration.Input; fetcherName?: string; entryId?: string; }; @@ -94,15 +94,17 @@ const doFetch = ( }), catch: failWith(opts, "network"), }).pipe( - Effect.timeoutFail({ + Effect.timeoutOrElse({ duration: opts.timeout ?? DEFAULT_TIMEOUT, - onTimeout: () => - buildFetchError(opts, { - kind: "timeout", - cause: new Error( - `timeout after ${String(opts.timeout ?? DEFAULT_TIMEOUT)}`, - ), - }), + orElse: () => + Effect.fail( + buildFetchError(opts, { + kind: "timeout", + cause: new Error( + `timeout after ${String(opts.timeout ?? DEFAULT_TIMEOUT)}`, + ), + }), + ), }), Effect.flatMap((response) => response.ok @@ -127,15 +129,17 @@ const fetchBody = ( Effect.retry(retryPolicy), Effect.flatMap((response) => read(response).pipe( - Effect.timeoutFail({ + Effect.timeoutOrElse({ duration: opts.timeout ?? DEFAULT_TIMEOUT, - onTimeout: () => - buildFetchError(opts, { - kind: "timeout", - cause: new Error( - `body read timeout after ${String(opts.timeout ?? DEFAULT_TIMEOUT)}`, - ), - }), + orElse: () => + Effect.fail( + buildFetchError(opts, { + kind: "timeout", + cause: new Error( + `body read timeout after ${String(opts.timeout ?? DEFAULT_TIMEOUT)}`, + ), + }), + ), }), ), ), diff --git a/packages/subscriptions/src/channels/retry.ts b/packages/subscriptions/src/channels/retry.ts index c720ea7f..41e37180 100644 --- a/packages/subscriptions/src/channels/retry.ts +++ b/packages/subscriptions/src/channels/retry.ts @@ -46,10 +46,12 @@ export function postWebhookWithRetry(opts: { }), catch: (cause) => new WebhookSendError("Webhook request failed", { cause }), }).pipe( - Effect.timeoutFail({ + Effect.timeoutOrElse({ duration: `${opts.timeoutMs} millis`, - onTimeout: () => - new WebhookSendError(`Webhook timed out after ${opts.timeoutMs}ms`), + orElse: () => + Effect.fail( + new WebhookSendError(`Webhook timed out after ${opts.timeoutMs}ms`), + ), }), Effect.flatMap((response) => response.ok diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4578fa97..24599a9a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -331,8 +331,8 @@ catalogs: specifier: 0.8.3 version: 0.8.3 effect: - specifier: 3.21.2 - version: 3.21.2 + specifier: 4.0.0-rc.112 + version: 4.0.0-rc.112 feed: specifier: 4.2.2 version: 4.2.2 @@ -1707,7 +1707,7 @@ importers: version: 0.45.2(@libsql/client@0.17.4)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(@upstash/redis@1.38.0)(bun-types@1.3.14) effect: specifier: 'catalog:' - version: 3.21.2 + version: 4.0.0-rc.112 hono: specifier: 'catalog:' version: 4.12.21 @@ -2022,7 +2022,7 @@ importers: version: 0.13.11(typescript@5.9.3)(zod@4.1.13) effect: specifier: 'catalog:' - version: 3.21.2 + version: 4.0.0-rc.112 react: specifier: 'catalog:' version: 19.2.6 @@ -2713,7 +2713,7 @@ importers: version: 10.8.0 effect: specifier: 'catalog:' - version: 3.21.2 + version: 4.0.0-rc.112 zod: specifier: 'catalog:' version: 4.1.13 @@ -2735,7 +2735,7 @@ importers: dependencies: effect: specifier: 'catalog:' - version: 3.21.2 + version: 4.0.0-rc.112 node-html-parser: specifier: 'catalog:' version: 6.1.13 @@ -2772,7 +2772,7 @@ importers: version: 1.38.0 effect: specifier: 'catalog:' - version: 3.21.2 + version: 4.0.0-rc.112 zod: specifier: 'catalog:' version: 4.1.13 @@ -4818,6 +4818,36 @@ packages: '@cfworker/json-schema': optional: true + '@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] + '@mswjs/interceptors@0.40.0': resolution: {integrity: sha512-EFd6cVbHsgLa6wa4RljGj6Wk75qoHxUSyc5asLyyPSyuhIcdS2Q3Phw6ImS1q+CkALthJRShiYfKANcQMuMqsQ==} engines: {node: '>=18'} @@ -8092,6 +8122,7 @@ packages: crypto-js@4.2.0: resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + deprecated: Active development of CryptoJS has been discontinued. This library is no longer maintained. css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} @@ -8452,8 +8483,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - effect@3.21.2: - resolution: {integrity: sha512-rXd2FGDM8KdjSIrc+mqEELo7ScW7xTVxEf1iInmPSpIde9/nyGuFM710cjTo7/EreGXiUX2MOonPpprbz2XHCg==} + effect@4.0.0-rc.112: + resolution: {integrity: sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A==} electron-to-chromium@1.5.267: resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} @@ -8680,9 +8711,9 @@ packages: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} - fast-check@3.23.2: - resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} - engines: {node: '>=8.0.0'} + fast-check@4.9.0: + resolution: {integrity: sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg==} + engines: {node: '>=12.17.0'} fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -9849,6 +9880,13 @@ 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.1.0: + resolution: {integrity: sha512-p/pBCVO63CsvvpkomUnNNag6+n38rULuDA6HHe70o2gtC8ODI52foF/4ko2qQcp6OiErJXTmrZeXmsGGHsIQNQ==} + msw@2.12.3: resolution: {integrity: sha512-/5rpGC0eK8LlFqsHaBmL19/PVKxu/CCt8pO1vzp9X6SDLsRDh/Ccudkf3Ur5lyaKxJz9ndAx+LaThdv0ySqB6A==} engines: {node: '>=18'} @@ -10020,6 +10058,10 @@ packages: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-gyp-build-optional-packages@5.2.2: + resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} + hasBin: true + node-html-parser@6.1.13: resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} @@ -10472,8 +10514,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.2: + resolution: {integrity: sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng==} qr-code-styling@1.9.2: resolution: {integrity: sha512-RgJaZJ1/RrXJ6N0j7a+pdw3zMBmzZU4VN2dtAZf8ZggCfRB5stEQ3IoDNGaNhYY3nnZKYlYSLl5YkfWN5dPutg==} @@ -13507,6 +13549,24 @@ snapshots: transitivePeerDependencies: - supports-color + '@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 + '@mswjs/interceptors@0.40.0': dependencies: '@open-draft/deferred-promise': 2.2.0 @@ -16854,10 +16914,10 @@ snapshots: ee-first@1.1.1: {} - effect@3.21.2: + effect@4.0.0-rc.112: dependencies: - '@standard-schema/spec': 1.1.0 - fast-check: 3.23.2 + fast-check: 4.9.0 + msgpackr: 2.1.0 electron-to-chromium@1.5.267: {} @@ -17191,9 +17251,9 @@ snapshots: iconv-lite: 0.4.24 tmp: 0.0.33 - fast-check@3.23.2: + fast-check@4.9.0: dependencies: - pure-rand: 6.1.0 + pure-rand: 8.4.2 fast-deep-equal@3.1.3: {} @@ -18682,6 +18742,22 @@ 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.1.0: + optionalDependencies: + msgpackr-extract: 3.0.4 + msw@2.12.3(@types/node@24.12.4)(typescript@5.9.3): dependencies: '@inquirer/confirm': 5.1.21(@types/node@24.12.4) @@ -18854,6 +18930,11 @@ snapshots: fetch-blob: 3.2.0 formdata-polyfill: 4.0.10 + node-gyp-build-optional-packages@5.2.2: + dependencies: + detect-libc: 2.1.2 + optional: true + node-html-parser@6.1.13: dependencies: css-select: 5.2.2 @@ -19363,7 +19444,7 @@ snapshots: punycode@2.3.1: {} - pure-rand@6.1.0: {} + pure-rand@8.4.2: {} qr-code-styling@1.9.2: dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 9c114121..9f4d8f5f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -12,6 +12,9 @@ allowBuilds: "@tailwindcss/oxide": true core-js-pure: true esbuild: true + # Optional native accelerator for msgpackr (pulled in by effect). msgpackr + # falls back to its pure-JS path without it, so skip the native build. + msgpackr-extract: false msw: true protobufjs: true sharp: true @@ -140,7 +143,7 @@ catalog: drizzle-kit: 0.31.10 drizzle-orm: 0.45.2 drizzle-zod: 0.8.3 - effect: 3.21.2 + effect: 4.0.0-rc.112 feed: 4.2.2 gray-matter: 4.0.3 hono: 4.12.21 -- 2.51.2