Content-Length: 759310 | pFad | http://github.com/PHS-TSA/webmaster-23-24/pull/59/files

1D Effect.TS by lishaduck · Pull Request #59 · PHS-TSA/webmaster-23-24 · GitHub
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Effect.TS #59

Merged
merged 12 commits into from
Nov 7, 2024
6 changes: 3 additions & 3 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@
"@preact/signals": "npm:@preact/signals@1.3.0",
"@preact/signals-core": "npm:@preact/signals-core@1.8.0",
"@std/assert": "jsr:@std/assert@1.0.6",
"@std/fs": "jsr:@std/fs@1.0.4",
"@std/path": "jsr:@std/path@1.0.6",
"@tabler/icons-preact": "npm:@tabler/icons-preact@3.19.0",
"@tailwindcss/forms": "npm:@tailwindcss/forms@0.5.9",
"@tailwindcss/typography": "npm:@tailwindcss/typography@0.5.15",
"@types/hast": "npm:@types/hast@3.0.4",
"@vendor/": "./vendor/",
"clsx": "npm:clsx@2.1.1",
"effect": "npm:effect@3.10.12",
"idb-keyval": "npm:idb-keyval@6.2.1",
"openai": "https://deno.land/x/openai@v4.50.0/mod.ts",
"openai/": "https://deno.land/x/openai@v4.50.0/",
Expand Down Expand Up @@ -64,8 +66,7 @@
"unified": "npm:unified@11.0.5",
"vfile": "npm:vfile@6.0.3",
"vfile-matter": "npm:vfile-matter@5.0.0",
"vfile-reporter": "npm:vfile-reporter@8.1.1",
"zod": "https://deno.land/x/zod@v3.23.8/mod.ts"
"vfile-reporter": "npm:vfile-reporter@8.1.1"
},
"scopes": {
"https://esm.sh/v135/": {
Expand Down Expand Up @@ -117,7 +118,6 @@
"tags": ["fresh", "recommended"],
"include": [
"ban-untagged-todo",
"explicit-function-return-type",
"explicit-module-boundary-types",
"guard-for-in",
"no-await-in-loop",
Expand Down
2 changes: 1 addition & 1 deletion src/components/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { css } from "../utils/tags.ts";
import type { HeroProps } from "./Cover.tsx";

export interface CarouselProps extends HeroProps {
heros: string[];
heros: readonly string[];
scrollDown?: boolean;
}

Expand Down
11 changes: 5 additions & 6 deletions src/routes/calculator/results.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { Head } from "$fresh/runtime.ts";
import type { Handlers, PageProps, RouteConfig } from "$fresh/server.ts";
import { IconCheck } from "@tabler/icons-preact";
import { Either, Schema } from "effect";
import type { ComponentChildren, JSX } from "preact";
import CalculatorScaffold from "../../components/CalculatorScaffold.tsx";
import { Cover } from "../../components/Cover.tsx";
import { Meta } from "../../components/Meta.tsx";
import {
type GeoCostBreakdown,
geothermalLoopType,
} from "../../utils/calc/geo.ts";
import {
GeothermalLoopTypeSchema,
calculatePricing,
calculatePricingFromType,
calculatePricingIfHardInstallation,
Expand Down Expand Up @@ -67,14 +66,14 @@ function parseData(
const region = data.get("region[value]")?.toString();
const isHilly = data.get("hills")?.toString() ?? "";
const renovations = data.get("renovations")?.toString() ?? "";
const geoType = geothermalLoopType.safeParse(
const geoType = Schema.decodeUnknownEither(GeothermalLoopTypeSchema)(
data.get("geo-type[value]")?.toString(),
);
const squareFootage = data.get("area")?.toString();
const requiresPermit = data.get("permit")?.toString() ?? "";

if (
geoType.success &&
Either.isRight(geoType) &&
region !== undefined &&
Object.hasOwn(stateData, region)
) {
Expand All @@ -87,7 +86,7 @@ function parseData(
geoCostData: {
isHilly: Boolean(isHilly),
needsRenovations: Boolean(renovations),
type: geoType.data,
type: geoType.right,
squareFootage: Number(squareFootage),
requiresPermit: Boolean(requiresPermit),
},
Expand Down
38 changes: 20 additions & 18 deletions src/routes/solutions/[category]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Head } from "$fresh/runtime.ts";
import type { Handlers, PageProps, RouteConfig } from "$fresh/server.ts";
import { IconBolt, IconLink } from "@tabler/icons-preact";
import { Schema } from "effect";
import type { ComponentType, JSX } from "preact";
import { Fragment } from "preact";
import { z } from "zod";
import { Carousel } from "../../../components/Carousel.tsx";
import { Content } from "../../../components/Content.tsx";
import { Cover, type HeroProps } from "../../../components/Cover.tsx";
Expand All @@ -17,25 +17,27 @@ export const config = {
csp: true,
} as const satisfies RouteConfig;

export type CategoryProps = z.infer<typeof categoryProps>;
export type CategoryPages = z.infer<typeof categoryPropsPages>;
export type CategoryData = z.infer<typeof categoryPropsPageData>;
export type CategoryProps = typeof CategoryProps.Type;
export type CategoryPages = typeof CategoryPropsPages.Type;
export type CategoryData = typeof CategoryPropsPageData.Type;

export const categoryPropsPageData = z.object({
short: z.string(),
linkText: z.string(),
title: z.string(),
linkTo: z.string(),
picture: z.string(),
export const CategoryPropsPageData = Schema.Struct({
short: Schema.String,
linkText: Schema.String,
title: Schema.String,
linkTo: Schema.String,
picture: Schema.String,
});

export const categoryPropsPages = categoryPropsPageData.array();
export const CategoryPropsPages = CategoryPropsPageData.pipe(Schema.Array);

export const categoryProps = z.object({
pages: categoryPropsPages,
title: z.string(),
description: z.string().refine((value) => !value.endsWith(".")),
heros: z.string().array(),
export const CategoryProps = Schema.Struct({
pages: CategoryPropsPages,
title: Schema.String,
description: Schema.String.pipe(
Schema.filter((value) => !value.endsWith(".")),
),
heros: Schema.String.pipe(Schema.Array),
});

/**
Expand Down Expand Up @@ -83,7 +85,7 @@ export const handler: Handlers<CategoryProps> = {
];

return await ctx.render({
pages: categoryPropsPages.parse(data),
pages: Schema.decodeSync(CategoryPropsPages)(data),
title: metadata.title,
description: metadata.description,
heros: data.map((page) => page.picture),
Expand Down Expand Up @@ -184,6 +186,6 @@ export default function Category({
);
}

function CategoryCarousel(heros: string[]): ComponentType<HeroProps> {
function CategoryCarousel(heros: readonly string[]): ComponentType<HeroProps> {
return ({ children }) => <Carousel heros={heros}>{children}</Carousel>;
}
5 changes: 3 additions & 2 deletions src/sdk/chat/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Schema } from "effect";
import {
type ChatThread,
chatThreadSchema,
ChatThreadSchema,
} from "../../utils/openai/schemas.ts";

export async function chat(
Expand All @@ -15,7 +16,7 @@ export async function chat(
);
const json = await res.json();

return chatThreadSchema.parse(json);
return Schema.decodeUnknownSync(ChatThreadSchema)(json);
} catch {
return undefined;
}
Expand Down
5 changes: 3 additions & 2 deletions src/sdk/chat/references.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Schema } from "effect";
import {
type FileObject,
fileObjectSchema,
FileObjectSchema,
} from "../../utils/openai/schemas.ts";

export async function getFileData(
Expand All @@ -12,7 +13,7 @@ export async function getFileData(
);
const json = await res.json();

return fileObjectSchema.parse(json);
return Schema.decodeUnknownSync(FileObjectSchema)(json);
} catch {
return undefined;
}
Expand Down
5 changes: 3 additions & 2 deletions src/sdk/chat/thread.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { type Thread, threadSchema } from "../../utils/openai/schemas.ts";
import { Schema } from "effect";
import { type Thread, ThreadSchema } from "../../utils/openai/schemas.ts";

export async function getThread(): Promise<Thread | undefined> {
try {
const res = await fetch("/api/chat/thread/");
const json = await res.json();

return threadSchema.parse(json);
return Schema.decodeUnknownSync(ThreadSchema)(json);
} catch {
return undefined;
}
Expand Down
16 changes: 8 additions & 8 deletions src/utils/calc/geo.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { z } from "zod";
import { Schema } from "effect";

export type GeoType = z.infer<typeof geothermalLoopType>;
export type GeoType = typeof GeothermalLoopTypeSchema.Type;

export const geothermalLoopType = z.union([
z.literal("horizontal"),
z.literal("vertical"),
z.literal("open"),
z.literal("closed"),
]);
export const GeothermalLoopTypeSchema = Schema.Literal(
"horizontal",
"vertical",
"open",
"closed",
);

export interface GeoCostBreakdown {
/** +$2000 */
Expand Down
21 changes: 12 additions & 9 deletions src/utils/calc/solar.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { z } from "zod";
import { Schema } from "effect";

export interface StateData {
/** In years */
Expand All @@ -12,7 +12,7 @@ export interface StateData {
readonly emissions: number;
}

export type State = z.infer<typeof regionSchema>;
export type State = typeof RegionSchema.Type;

export const stateData = {
Alabama: {
Expand Down Expand Up @@ -377,11 +377,14 @@ export const stateData = {
// @ts-expect-error: Typescript types the core JS libs awfully ;).
export const states: (keyof typeof stateData)[] = Object.keys(stateData);

export const regionSchema = z.custom<keyof typeof stateData>(
(region) =>
z
.string()
// @ts-expect-error: And, of course, the stricter states typing breaks this ;).
.refine((region2) => states.includes(region2))
.safeParse(region).success,
export const RegionSchema = Schema.declare<keyof typeof stateData>(
(region): region is keyof typeof stateData =>
Schema.is(
Schema.String.pipe(
Schema.filter(
// @ts-expect-error: And, of course, the stricter states typing breaks this ;).
(region) => states.includes(region),
),
),
)(region),
);
29 changes: 14 additions & 15 deletions src/utils/ip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
*/

import { join } from "@std/path";
import { z } from "zod";
import { regionSchema } from "./calc/solar.ts";
import type { ZodTypeUnknown } from "./zod.ts";
import { Schema } from "effect";
import { RegionSchema } from "./calc/solar.ts";

export type Geo = z.infer<typeof geoSchema>;
type Ip = z.infer<typeof ipSchema>;
export type Geo = typeof GeoSchema.Type;
type Ip = typeof IpSchema.Type;

export const geoSchema = z.object({ region: regionSchema });
const ipSchema = z.object({ ip: z.string() });
export const GeoSchema = Schema.Struct({ region: RegionSchema });
const IpSchema = Schema.Struct({ ip: Schema.String });

const ipEndpoint = "https://api.ipify.org";
const geoEndpoint = "https://ipapi.co";
Expand All @@ -36,7 +35,7 @@ export async function getIpLocation(ip?: string): Promise<Geo | undefined> {

return await makeRequest(
join(geoEndpoint, currentIP ?? "", "json"),
geoSchema,
GeoSchema,
);
} catch {
return undefined;
Expand All @@ -47,24 +46,24 @@ export async function getIpLocation(ip?: string): Promise<Geo | undefined> {
* Query a JSON API and validate the response.
*
* @param endpoint - The API to query (GET).
* @param schema - The Zod schema to validate the data against.
* @param schema - The schema to validate the data against.
* @returns - The validated API content.
*/
async function makeRequest<T extends ZodTypeUnknown>(
endpoint: string,
schema: T,
): Promise<z.infer<T>> {
async function makeRequest<
T extends Schema.Schema<A>,
A = Schema.Schema.Type<T>,
>(endpoint: string, schema: T): Promise<NoInfer<A>> {
// Send the request.
const res = await fetch(endpoint);

// Validate the response.
return schema.parse(await res.json());
return Schema.decodeUnknownSync(schema)(await res.json());
}

/**
* Get the current device's IP from the https://ipify.org API.
*/
function getIp(): Promise<Ip> {
// make http request and return the IP as json
return makeRequest(`${ipEndpoint}?format=json`, ipSchema);
return makeRequest(`${ipEndpoint}?format=json`, IpSchema);
}
41 changes: 26 additions & 15 deletions src/utils/openai/schemas.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,50 @@
import { Schema } from "effect";
import type { Message } from "openai/resources/beta/threads/messages.ts";
import type { Thread as OThread } from "openai/resources/beta/threads/threads.ts";
import type { FileObject as OFileObject } from "openai/resources/mod.ts";
import { z } from "zod";

export type FileObject = z.infer<typeof fileObjectSchema>;
export type Thread = z.infer<typeof threadSchema>;
export type ChatThread = z.infer<typeof chatThreadSchema>;
export type FileObject = typeof FileObjectSchema.Type;
export type Thread = typeof ThreadSchema.Type;
export type ChatThread = typeof ChatThreadSchema.Type;
export type ChatMessage = typeof MessageSchema.Type;

/**
* @remarks
* This is very basic, and doesn't check anything beyond that it's an object.
* This is a very unsafe stub.
* It does zero validation.
*
* @see {@link OFileObject}
*/
export const fileObjectSchema = z.custom<OFileObject>(
(val) => z.object({}).safeParse(val).success,
export const FileObjectSchema = Schema.declare<OFileObject>(
(_): _ is OFileObject => true,
);

/**
* @remarks
* This is very basic, and doesn't check anything beyond that it's an object.
* This is a very unsafe stub.
* It does zero validation.
*
* @see {@link OThread}
*/
export const threadSchema = z.custom<OThread>(
(val) => z.object({}).safeParse(val).success,
);
export const ThreadSchema = Schema.declare<OThread>((_): _ is OThread => true);

/**
* @remarks
* This is very basic, and doesn't check anything beyond that it's an array of objects.
* This is a very unsafe stub.
* It does zero validation.
*
* @see {@link Message}
*/
export const chatThreadSchema = z.custom<Message[]>(
(val) => z.object({}).array().safeParse(val).success,
);
export const MessageSchema = Schema.declare<Message>((_): _ is Message => true);

/**
* @remarks
* This is a very unsafe stub.
* It does zero validation.
*
* @see {@link MessageSchema}
*/
export const ChatThreadSchema = Schema.Array(MessageSchema);

export type {
Message,
Expand Down
Loading








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/PHS-TSA/webmaster-23-24/pull/59/files

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy