mirror of
https://github.com/Blah-IM/typescript-core.git
synced 2025-06-23 16:31:08 +00:00
refactor: migrate to zod v4
This commit is contained in:
parent
fdcb07be23
commit
a1b0d889bd
16 changed files with 37 additions and 39 deletions
|
@ -1,4 +1,4 @@
|
|||
import type z from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
import {
|
||||
type BlahSignedPayload,
|
||||
blahSignedPayloadSchemaOf,
|
||||
|
@ -22,9 +22,7 @@ export class BlahPublicKey {
|
|||
this.name = id.slice(0, 4) + "..." + id.slice(-4);
|
||||
}
|
||||
|
||||
static async fromPublicKey(
|
||||
publicKey: CryptoKey,
|
||||
): Promise<BlahPublicKey> {
|
||||
static async fromPublicKey(publicKey: CryptoKey): Promise<BlahPublicKey> {
|
||||
const rawKey = await crypto.subtle.exportKey("raw", publicKey);
|
||||
const id = bufToHex(rawKey);
|
||||
return new BlahPublicKey(publicKey, id);
|
||||
|
@ -67,7 +65,9 @@ export class BlahPublicKey {
|
|||
options: SignOrVerifyOptions = {},
|
||||
): Promise<{ payload: z.infer<P>; key: BlahPublicKey }> {
|
||||
const signedPayloadSchema = blahSignedPayloadSchemaOf(schema);
|
||||
const parsed = signedPayloadSchema.parse(signedPayload) as z.infer<P>;
|
||||
const parsed = signedPayloadSchema.parse(
|
||||
signedPayload,
|
||||
) as BlahSignedPayload<z.infer<P>>;
|
||||
return await BlahPublicKey.verifyPayload(parsed, options);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { expect, test } from "vitest";
|
||||
|
||||
import { BlahKeyPair } from "./keypair.ts";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
import { BlahPublicKey } from "./publicKey.ts";
|
||||
import type { SignOrVerifyOptions } from "./signAndVerify.ts";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { expectTypeOf, test } from "vitest";
|
||||
|
||||
import z from "zod";
|
||||
import { z } from "zod/v4";
|
||||
import type { BlahSignedPayload } from "./mod.ts";
|
||||
import {
|
||||
type BlahPayloadSignee,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import z from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export function blahPayloadSigneeSchemaOf<P extends z.ZodTypeAny>(schema: P) {
|
||||
return z.object({
|
||||
nonce: z.number().int(),
|
||||
nonce: z.int(),
|
||||
payload: schema,
|
||||
timestamp: z.number().int(),
|
||||
timestamp: z.int(),
|
||||
id_key: z.string(),
|
||||
act_key: z.string(),
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { expectTypeOf, test } from "vitest";
|
||||
|
||||
import { type BlahActKeyRecord, blahActKeyRecordSchema } from "./actKey.ts";
|
||||
import z from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
test("BlahActKeyRecord typed correctly", () => {
|
||||
expectTypeOf<
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import z from "zod";
|
||||
import { z } from "zod/v4";
|
||||
import { BlahPublicKey } from "../crypto/publicKey.ts";
|
||||
import { BlahKeyPair } from "../crypto/keypair.ts";
|
||||
import type { BlahSignedPayload } from "../crypto/signedPayload.ts";
|
||||
|
@ -7,7 +7,7 @@ import type { SignOrVerifyOptions } from "../crypto/signAndVerify.ts";
|
|||
export const blahActKeyRecordSchema = z.object({
|
||||
typ: z.literal("user_act_key"),
|
||||
act_key: z.string(),
|
||||
expire_time: z.number().int(),
|
||||
expire_time: z.int(),
|
||||
comment: z.string(),
|
||||
});
|
||||
|
||||
|
@ -61,8 +61,8 @@ export class BlahActKey {
|
|||
sigValid = false;
|
||||
}
|
||||
|
||||
const key: BlahPublicKey | BlahKeyPair = keypair ??
|
||||
await BlahPublicKey.fromID(record.act_key);
|
||||
const key: BlahPublicKey | BlahKeyPair =
|
||||
keypair ?? (await BlahPublicKey.fromID(record.act_key));
|
||||
const fullConfig: Required<ActKeyUpdate> = {
|
||||
expiresAt: new Date(record.expire_time * 1000),
|
||||
comment: record.comment,
|
||||
|
@ -142,10 +142,10 @@ export class BlahActKey {
|
|||
): Promise<BlahSignedPayload<P>> {
|
||||
if (!this.canSign) throw new Error("Cannot sign without a private key");
|
||||
|
||||
return await (this.internalKey as BlahKeyPair).signPayload(
|
||||
payload,
|
||||
{ ...options, identityKeyId: this.internalIdKeyPublic.id },
|
||||
);
|
||||
return await (this.internalKey as BlahKeyPair).signPayload(payload, {
|
||||
...options,
|
||||
identityKeyId: this.internalIdKeyPublic.id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,9 +156,7 @@ export class BlahActKey {
|
|||
*
|
||||
* @param payload The signed payload to verify.
|
||||
*/
|
||||
async verifyPayload<P>(
|
||||
payload: BlahSignedPayload<P>,
|
||||
): Promise<P> {
|
||||
async verifyPayload<P>(payload: BlahSignedPayload<P>): Promise<P> {
|
||||
if (new Date(payload.signee.timestamp * 1000) > this.internalExpiresAt) {
|
||||
throw new Error("Key was expired at the time of signing");
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
getIdentityDescriptionFileURL,
|
||||
identityDescriptionFilePath,
|
||||
} from "./identityDescription.ts";
|
||||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
test("BlahIdentityDescription typed correctly", () => {
|
||||
expectTypeOf<
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
import { blahSignedPayloadSchemaOf } from "../crypto/signedPayload.ts";
|
||||
import { type BlahActKeyRecord, blahActKeyRecordSchema } from "./actKey.ts";
|
||||
import {
|
||||
|
@ -32,9 +32,7 @@ export const identityDescriptionFilePath = "/.well-known/blah/identity.json";
|
|||
* @returns The full URL to the identity description file.
|
||||
* @throws Error if the ID URL format is invalid.
|
||||
*/
|
||||
export function getIdentityDescriptionFileURL(
|
||||
idURL: string,
|
||||
): string {
|
||||
export function getIdentityDescriptionFileURL(idURL: string): string {
|
||||
if (!validateIDURLFormat(idURL)) throw new Error("Invalid ID URL format");
|
||||
const url = new URL(idURL);
|
||||
url.pathname = identityDescriptionFilePath;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type z from "zod";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
export * from "./identity.ts";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { expect, test, expectTypeOf } from "vitest";
|
||||
|
||||
import z from "zod";
|
||||
import { z } from "zod/v4";
|
||||
import {
|
||||
type BlahProfile,
|
||||
blahProfileSchema,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import z from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
/** Schema for Blah user profile. */
|
||||
export const blahProfileSchema = z.object({
|
||||
typ: z.literal("profile"),
|
||||
preferred_chat_server_urls: z.array(z.string().url()),
|
||||
preferred_chat_server_urls: z.array(z.url()),
|
||||
id_urls: z.array(z.string().refine(validateIDURLFormat)).min(1),
|
||||
name: z.string(),
|
||||
bio: z.string().optional(),
|
||||
|
@ -22,14 +22,16 @@ export type BlahProfile = {
|
|||
export function validateIDURLFormat(url: string): boolean {
|
||||
try {
|
||||
const idURL = new URL(url);
|
||||
return !!idURL &&
|
||||
return (
|
||||
!!idURL &&
|
||||
idURL.protocol === "https:" &&
|
||||
idURL.pathname === "/" &&
|
||||
!url.endsWith("/") &&
|
||||
!idURL.search &&
|
||||
!idURL.hash &&
|
||||
!idURL.username &&
|
||||
!idURL.password;
|
||||
!idURL.password
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* @module
|
||||
*/
|
||||
|
||||
import type z from "zod";
|
||||
import type z from "zod/v4";
|
||||
|
||||
import {
|
||||
type BlahRichTextSpan,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { expectTypeOf, test } from "vitest";
|
||||
|
||||
import { type BlahRichText, blahRichTextSchema } from "./richText.ts";
|
||||
import z from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
test("BlahRichText typed correctly", () => {
|
||||
expectTypeOf<
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
import { type BlahRichTextSpan, blahRichTextSpanSchema } from "./span.ts";
|
||||
|
||||
export const blahRichTextSchema = z.array(blahRichTextSpanSchema);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { expectTypeOf, test } from "vitest";
|
||||
|
||||
import { type BlahRichTextSpan, blahRichTextSpanSchema } from "./span.ts";
|
||||
import z from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
test("BlahRichTextSpan typed correctly", () => {
|
||||
expectTypeOf<BlahRichTextSpan>().toEqualTypeOf<
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { z } from "zod";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const blahRichTextSpanAttributesSchema = z.object({
|
||||
b: z.boolean().default(false),
|
||||
|
@ -8,7 +8,7 @@ export const blahRichTextSpanAttributesSchema = z.object({
|
|||
m: z.boolean().default(false),
|
||||
tag: z.boolean().default(false),
|
||||
spoiler: z.boolean().default(false),
|
||||
link: z.string().url().optional(),
|
||||
link: z.url().optional(),
|
||||
});
|
||||
|
||||
export type BlahRichTextSpanAttributes = {
|
||||
|
|
Loading…
Add table
Reference in a new issue