Port to node.js

This commit is contained in:
2026-07-30 00:45:46 +02:00
parent 988025bfac
commit 1249781204
22 changed files with 1461 additions and 1768 deletions

View File

@@ -8,8 +8,8 @@
"./*": { "import": "./src/*.ts" }
},
"devDependencies": {
"@types/bun": "catalog:",
"typescript": "catalog:"
"typescript": "catalog:",
"vitest": "catalog:"
},
"dependencies": {
"cbor2": "catalog:",

View File

@@ -1,8 +1,6 @@
/// <reference types="bun" />
import { describe, expect, test } from "bun:test";
import { HashMap, Schema } from "effect";
import * as Api from "./Api";
import { describe, expect, test } from "vitest";
import * as Api from "./Api.ts";
describe("bundle", () => {
test("constructs a HashMap", () => {
@@ -29,7 +27,7 @@ describe("bundle", () => {
bar: Api.make(Schema.Void, Schema.Number, Schema.String),
});
expect(Object.isFrozen(bundle)).toBeTrue();
expect(Object.isFrozen(bundle)).toBe(true);
});
test("freezes the record", () => {
@@ -38,7 +36,7 @@ describe("bundle", () => {
bar: Api.make(Schema.Void, Schema.Number, Schema.String),
});
expect(Object.isFrozen(bundle.record)).toBeTrue();
expect(Object.isFrozen(bundle.record)).toBe(true);
});
});
@@ -62,6 +60,6 @@ describe("make", () => {
const api = Api.make(request, response, error);
expect(Object.isFrozen(api)).toBeTrue();
expect(Object.isFrozen(api)).toBe(true);
})
});

View File

@@ -1,9 +1,7 @@
/// <reference types="bun" />
import { describe, test } from "bun:test";
import { Cause, Effect } from "effect";
import * as Body from "./Body";
import * as Test from "./Test";
import { describe, test } from "vitest";
import * as Body from "./Body.ts";
import * as Test from "./Test.ts";
describe("arrayBuffer", () => {
test("succeeds", async () => {

View File

@@ -1,4 +1,4 @@
import { Update } from "common";
import { type Update } from "common";
import { Data, Deferred, Effect, Exit, Option } from "effect";
import { dual, identity } from "effect/Function";

View File

@@ -1,11 +1,9 @@
/// <reference types="bun" />
import { describe, test } from "bun:test";
import * as cbor from "cbor2";
import { Uint8ArrayArrayBufferFromSelf } from "common";
import { Effect, Schema } from "effect";
import * as Cbor from "./Cbor";
import * as Test from "./Test";
import { describe, test } from "vitest";
import * as Cbor from "./Cbor.ts";
import * as Test from "./Test.ts";
describe("encode", () => {
test("succeeds", async () => {

View File

@@ -1,5 +1,5 @@
import * as cbor from "cbor2";
import { Data, Effect, pipe, Schema } from "effect";
import { Console, Data, Effect, ParseResult, pipe, Schema } from "effect";
export class CborDecodeError extends Data.TaggedError("CborDecodeError")<{ cause: unknown }> { }
export class CborEncodeError extends Data.TaggedError("CborEncodeError")<{ cause: unknown }> { }
@@ -31,5 +31,10 @@ export const decodeSchema = <A>(schema: Schema.Schema<A, any>) => {
return (u: Uint8Array<ArrayBuffer>) => pipe(
decode(u),
Effect.flatMap((u) => schemaDecoder(u)),
Effect.tapErrorTag("ParseError", (error) => pipe(
error,
ParseResult.TreeFormatter.formatError,
Effect.flatMap(Console.error),
)),
);
};

View File

@@ -1,9 +1,9 @@
import { Data, Effect, Option, pipe, Record, Schema } from "effect";
import { Console, Data, Effect, Option, ParseResult, pipe, Record, Schema } from "effect";
import { constant } from "effect/Function";
import * as Api from "./Api";
import * as Body from "./Body";
import * as Cbor from "./Cbor";
import { fetch, FetchError } from "./Fetch";
import * as Api from "./Api.ts";
import * as Body from "./Body.ts";
import * as Cbor from "./Cbor.ts";
import { fetch, FetchError } from "./Fetch.ts";
export class ServerDie extends Data.TaggedError("ServerDie")<{ cause: unknown }> { }
export class UnexpectedStatus extends Data.TaggedError("UnexpectedStatusCode")<{ status: number }> { }
@@ -61,7 +61,7 @@ export const client = <const Record extends { readonly [_: string]: Api.ApiAny }
})) as { readonly [K in keyof Record]: (request: Record[K]["request"]["Type"]) => Effect.Effect<Record[K]["response"]["Type"], Record[K]["error"]["Type"] | FetchError, never> };
};
export const readBody = (body: Body) => pipe(
export const readBody = (body: { bytes(): Promise<Uint8Array<ArrayBuffer>> }) => pipe(
body,
Body.bytes,
Effect.map((bytes) => bytes.byteLength > 0 ? Option.some(bytes) : Option.none()),
@@ -74,7 +74,15 @@ export const readBody = (body: Body) => pipe(
export const decodeBody = <A>(schema: Schema.Schema<A, any>) => {
const decoder = Schema.decodeUnknown(schema);
return (body: Body) => Effect.flatMap(readBody(body), decoder);
return (body: { bytes(): Promise<Uint8Array<ArrayBuffer>> }) => pipe(
readBody(body),
Effect.flatMap(decoder),
Effect.tapErrorTag("ParseError", (error) => pipe(
error,
ParseResult.TreeFormatter.formatError,
Effect.flatMap(Console.error),
)),
);
};
export interface BodyData {

View File

@@ -1,7 +1,5 @@
/// <reference types="bun" />
import { expect } from "bun:test";
import { Cause, Exit, Predicate } from "effect";
import { assert, expect } from "vitest";
export function expectSuccess<A, E>(
actual: Exit.Exit<A, E>,
@@ -22,19 +20,15 @@ export function expectFailureTag<A, E, Tag extends string>(
tag: Tag,
): asserts actual is Exit.Failure<never, E & { readonly _tag: Tag }> {
if (!Exit.isFailure(actual)) {
expect(actual).fail("Expected Exit to be a Failure");
throw new Error("Unreachable");
assert.fail("Expected Exit to be a Failure");
}
const { cause } = actual;
if (!Cause.isFailType(cause)) {
expect(cause).fail("Expected Cause to be a Fail");
throw new Error("Unreachable");
assert.fail("Expected Cause to be a Fail");
}
const { error } = cause;
if (!Predicate.isTagged(tag)) {
expect(error).fail(`Expected error to be tagged with ${JSON.stringify(tag)}`);
throw new Error("Unreachable");
assert.fail(`Expected error to be tagged with ${JSON.stringify(tag)}`);
}
}

View File

@@ -1,7 +1,7 @@
import { AttachmentId, PieceId, RepertoireId, Sha256, Uint8ArrayArrayBufferFromSelf, UserId } from "common";
import { pipe, Schema } from "effect";
import { constant } from "effect/Function";
import * as Api from "./Api";
import * as Api from "./Api.ts";
// --- MARK: COMMON TYPES ------------------------------------------------------