feat: biome check
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
14
.prettierrc
14
.prettierrc
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 2,
|
||||
"printWidth": 120,
|
||||
"singleQuote": false,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.ts",
|
||||
"options": {
|
||||
"parser": "typescript"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
20
.vscode/settings.json
vendored
20
.vscode/settings.json
vendored
@@ -1,23 +1,11 @@
|
||||
{
|
||||
"biome.enabled": true,
|
||||
"deno.enable": true,
|
||||
"deno.lint": false,
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
},
|
||||
"[markdown]": {
|
||||
"editor.defaultFormatter": null,
|
||||
"editor.wordWrap": "off"
|
||||
},
|
||||
"eslint.options": {
|
||||
"ignorePatterns": ["**/*.md"]
|
||||
"source.organizeImports.biome": "explicit",
|
||||
"source.fixAll.biome": "explicit"
|
||||
},
|
||||
"files.exclude": {
|
||||
"**/.git": true,
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export const config = {
|
||||
mongodb: "mongo:8.0.3",
|
||||
postgres: "postgres:17",
|
||||
};
|
||||
@@ -1,154 +0,0 @@
|
||||
import { getAvailablePort } from "@std/net";
|
||||
import cookie from "cookie";
|
||||
|
||||
import { auth, Session } from "~libraries/auth/mod.ts";
|
||||
import { Code } from "~libraries/code/aggregates/code.ts";
|
||||
import { handler } from "~libraries/server/handler.ts";
|
||||
|
||||
import { Api, QueryMethod } from "../.generated/api.ts";
|
||||
|
||||
export class ApiTestContainer {
|
||||
#server?: Deno.HttpServer;
|
||||
#client?: Api;
|
||||
#cookie?: string;
|
||||
#session?: Session;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Accessors
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
get accountId(): string | undefined {
|
||||
if (this.#session?.valid === true) {
|
||||
return this.#session.accountId;
|
||||
}
|
||||
}
|
||||
|
||||
get client() {
|
||||
if (this.#client === undefined) {
|
||||
throw new Error("ApiContainer > .start() has not been executed.");
|
||||
}
|
||||
return this.#client;
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Lifecycle
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
async start(): Promise<this> {
|
||||
const port = await getAvailablePort();
|
||||
this.#server = await Deno.serve({ port, hostname: "127.0.0.1" }, handler);
|
||||
this.#client = makeApiClient(port, {
|
||||
onBeforeRequest: (headers: Headers) => {
|
||||
if (this.#cookie !== undefined) {
|
||||
headers.set("cookie", this.#cookie);
|
||||
}
|
||||
},
|
||||
onAfterResponse: (response) => {
|
||||
const cookie = response.headers.get("set-cookie");
|
||||
if (cookie !== null) {
|
||||
this.#cookie = cookie;
|
||||
}
|
||||
},
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
async stop() {
|
||||
await this.#server?.shutdown();
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Utilities
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
async authorize(accountId: string): Promise<void> {
|
||||
const code = await Code.create({ identity: { type: "admin", accountId } }).save();
|
||||
await this.client.auth.code(accountId, code.id, code.value, {});
|
||||
this.#session = await this.getSession();
|
||||
}
|
||||
|
||||
async getSession(): Promise<Session | undefined> {
|
||||
const token = cookie.parse(this.#cookie ?? "").token;
|
||||
if (token !== undefined) {
|
||||
const session = await auth.resolve(token);
|
||||
if (session.valid === true) {
|
||||
return session;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unauthorize(): void {
|
||||
this.#cookie = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function makeApiClient(
|
||||
port: number,
|
||||
{
|
||||
onBeforeRequest,
|
||||
onAfterResponse,
|
||||
}: {
|
||||
onBeforeRequest: (headers: Headers) => void;
|
||||
onAfterResponse: (response: Response) => void;
|
||||
},
|
||||
): Api {
|
||||
return new Api({
|
||||
async command(payload) {
|
||||
const headers = new Headers();
|
||||
onBeforeRequest(headers);
|
||||
headers.set("content-type", "application/json");
|
||||
const response = await fetch(`http://127.0.0.1:${port}/api/v1/command`, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
const text = await response.text();
|
||||
if (response.status >= 300) {
|
||||
console.error(
|
||||
`Command '${payload.method}' responded with error status '${response.status} ${response.statusText}'.`,
|
||||
);
|
||||
}
|
||||
if (response.headers.get("content-type")?.includes("json") === true) {
|
||||
return JSON.parse(text);
|
||||
}
|
||||
},
|
||||
async query(method: QueryMethod, path: string, query: Record<string, unknown>, body: any = {}) {
|
||||
const headers = new Headers();
|
||||
onBeforeRequest(headers);
|
||||
if (method !== "GET") {
|
||||
headers.set("content-type", "application/json");
|
||||
}
|
||||
const response = await fetch(`http://127.0.0.1:${port}${path}${getSearchQuery(query)}`, {
|
||||
method,
|
||||
headers,
|
||||
body: method === "GET" ? undefined : JSON.stringify(body),
|
||||
});
|
||||
onAfterResponse(response);
|
||||
const text = await response.text();
|
||||
if (response.status >= 300) {
|
||||
console.error(`Query '${path}' responded with error status '${response.status} ${response.statusText}'.`);
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
if (response.headers.get("content-type")?.includes("json") === true) {
|
||||
return JSON.parse(text);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function getSearchQuery(query: Record<string, unknown>): string {
|
||||
const search: string[] = [];
|
||||
for (const key in query) {
|
||||
search.push(`${key}=${query[key]}`);
|
||||
}
|
||||
if (search.length === 0) {
|
||||
return "";
|
||||
}
|
||||
return `?${search.join("&")}`;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import { MongoTestContainer } from "@valkyr/testcontainers/mongodb";
|
||||
|
||||
import { container } from "~database/container.ts";
|
||||
import { logger } from "~libraries/logger/mod.ts";
|
||||
import { bootstrap } from "~libraries/utilities/bootstrap.ts";
|
||||
import { API_DOMAINS_DIR, API_PACKAGES_DIR } from "~paths";
|
||||
|
||||
export class DatabaseTestContainer {
|
||||
constructor(readonly mongo: MongoTestContainer) {
|
||||
container.set("client", mongo.client);
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Lifecycle
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
async start(): Promise<this> {
|
||||
logger.prefix("Database").info("DatabaseTestContainer Started");
|
||||
|
||||
await bootstrap(API_DOMAINS_DIR);
|
||||
await bootstrap(API_PACKAGES_DIR);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
async truncate() {
|
||||
const promises: Promise<any>[] = [];
|
||||
for (const dbName of ["balto:auth", "balto:code", "balto:consultant", "balto:task"]) {
|
||||
const db = this.mongo.client.db(dbName);
|
||||
const collections = await db.listCollections().toArray();
|
||||
promises.push(...collections.map(({ name }) => db.collection(name).deleteMany({})));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
async stop() {
|
||||
logger.prefix("Database").info("DatabaseTestContainer stopped");
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
import { MongoTestContainer } from "@valkyr/testcontainers/mongodb";
|
||||
|
||||
import { config } from "../config.ts";
|
||||
import { ApiTestContainer } from "./api-container.ts";
|
||||
import { DatabaseTestContainer } from "./database-container.ts";
|
||||
|
||||
export class TestContainer {
|
||||
readonly id = crypto.randomUUID();
|
||||
|
||||
// ### Enablers
|
||||
// A map of services to enable when the TestContainer is started. These toggles
|
||||
// must be toggled before the container is started.
|
||||
|
||||
#with: With = {
|
||||
mongodb: false,
|
||||
database: false,
|
||||
api: false,
|
||||
};
|
||||
|
||||
// ### Needs
|
||||
|
||||
#needs: Needs = {
|
||||
mongodb: [],
|
||||
database: ["mongodb"],
|
||||
api: ["mongodb", "database"],
|
||||
};
|
||||
|
||||
// ### Services
|
||||
// Any services that has been enabled will be running under the following
|
||||
// assignments. Make sure to .stop any running services to avoid shutdown
|
||||
// leaks.
|
||||
|
||||
#mongodb?: MongoTestContainer;
|
||||
#database?: DatabaseTestContainer;
|
||||
#api?: ApiTestContainer;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Accessors
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
get accountId() {
|
||||
if (this.#api === undefined) {
|
||||
throw new Error("TestContainer > .withApi() must be called before starting the TestContainer.");
|
||||
}
|
||||
return this.#api.accountId;
|
||||
}
|
||||
|
||||
get mongodb(): MongoTestContainer {
|
||||
if (this.#mongodb === undefined) {
|
||||
throw new Error("TestContainer > .withMongo() must be called before starting the TestContainer.");
|
||||
}
|
||||
return this.#mongodb;
|
||||
}
|
||||
|
||||
get database(): DatabaseTestContainer {
|
||||
if (this.#database === undefined) {
|
||||
throw new Error("TestContainer > .withDatabase() must be called before starting the TestContainer.");
|
||||
}
|
||||
return this.#database;
|
||||
}
|
||||
|
||||
get api() {
|
||||
if (this.#api === undefined) {
|
||||
throw new Error("TestContainer > .withApi() must be called before starting the TestContainer.");
|
||||
}
|
||||
return this.#api.client;
|
||||
}
|
||||
|
||||
get authorize() {
|
||||
if (this.#api === undefined) {
|
||||
throw new Error("TestContainer > .withApi() must be called before starting the TestContainer.");
|
||||
}
|
||||
return this.#api.authorize.bind(this.#api);
|
||||
}
|
||||
|
||||
get unauthorize() {
|
||||
if (this.#api === undefined) {
|
||||
throw new Error("TestContainer > .withApi() must be called before starting the TestContainer.");
|
||||
}
|
||||
return this.#api.unauthorize.bind(this.#api);
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Builder
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
withMongo(): this {
|
||||
this.#with.mongodb = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
withDatabase(): this {
|
||||
this.#with.database = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
withApi(): this {
|
||||
this.#with.api = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Lifecycle
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
async start(): Promise<this> {
|
||||
const promises: Promise<void>[] = [];
|
||||
if (this.#isNeeded("mongodb") === true) {
|
||||
promises.push(
|
||||
(async () => {
|
||||
this.#mongodb = await MongoTestContainer.start(config.mongodb);
|
||||
if (this.#isNeeded("database") === true) {
|
||||
this.#database = await new DatabaseTestContainer(this.mongodb).start();
|
||||
}
|
||||
})(),
|
||||
);
|
||||
}
|
||||
if (this.#isNeeded("api") === true) {
|
||||
promises.push(
|
||||
(async () => {
|
||||
this.#api = await new ApiTestContainer().start();
|
||||
})(),
|
||||
);
|
||||
}
|
||||
await Promise.all(promises);
|
||||
return this;
|
||||
}
|
||||
|
||||
async stop(): Promise<this> {
|
||||
await this.#api?.stop();
|
||||
await this.#database?.stop();
|
||||
await this.#mongodb?.stop();
|
||||
|
||||
this.#api = undefined;
|
||||
this.#database = undefined;
|
||||
this.#mongodb = undefined;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Helpers
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#isNeeded(target: keyof With): boolean {
|
||||
if (this.#with[target] !== false) {
|
||||
return true;
|
||||
}
|
||||
for (const key in this.#needs) {
|
||||
if (this.#with[key as keyof With] !== false && this.#needs[key as keyof With].includes(target) === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Types
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
type Needs = Record<keyof With, (keyof With)[]>;
|
||||
|
||||
type With = {
|
||||
mongodb: boolean;
|
||||
database: boolean;
|
||||
api: boolean;
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
import * as assertSuite from "@std/assert";
|
||||
import * as bddSuite from "@std/testing/bdd";
|
||||
|
||||
import type { TestContainer } from "~libraries/testing/containers/test-container.ts";
|
||||
|
||||
import { authorize } from "./utilities/account.ts";
|
||||
|
||||
export function describe(name: string, runner: TestRunner): (container: TestContainer) => void {
|
||||
return (container: TestContainer) =>
|
||||
bddSuite.describe(name, () => runner(container, bddSuite, assertSuite, { authorize: authorize(container) }));
|
||||
}
|
||||
|
||||
export type TestRunner = (
|
||||
container: TestContainer,
|
||||
bdd: {
|
||||
[key in keyof typeof bddSuite]: (typeof bddSuite)[key];
|
||||
},
|
||||
assert: {
|
||||
[key in keyof typeof assertSuite]: (typeof assertSuite)[key];
|
||||
},
|
||||
utils: {
|
||||
authorize: ReturnType<typeof authorize>;
|
||||
},
|
||||
) => void;
|
||||
@@ -1,68 +0,0 @@
|
||||
import type { EventData } from "@valkyr/event-store";
|
||||
|
||||
import { AccountCreated, AccountEmailAdded } from "~libraries/auth/.generated/events.ts";
|
||||
import { Account } from "~libraries/auth/aggregates/account.ts";
|
||||
import { Role } from "~libraries/auth/aggregates/role.ts";
|
||||
import type { TestContainer } from "~libraries/testing/containers/test-container.ts";
|
||||
|
||||
type AuthorizationOptions = {
|
||||
name?: { family?: string; given?: string };
|
||||
email?: Partial<EventData<AccountEmailAdded>>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a function which provides the ability to create a new account which
|
||||
* is authorized and ready to use for testing authorized requests.
|
||||
*
|
||||
* @param container - Container to authorize against.
|
||||
*/
|
||||
export function authorize(container: TestContainer): AuthorizeFn {
|
||||
return async (data: EventData<AccountCreated>, { name = {}, email = {} }: AuthorizationOptions = {}) => {
|
||||
const role = await makeRole(data.type).save();
|
||||
const account = await Account.create(data, "test")
|
||||
.addName(name?.family ?? "Doe", name?.given ?? "John", "test")
|
||||
.addEmail({ value: "john.doe@fixture.none", type: "work", primary: true, verified: true, ...email }, "test")
|
||||
.addRole(role.id, "test")
|
||||
.save();
|
||||
await container.authorize(account.id);
|
||||
return account;
|
||||
};
|
||||
}
|
||||
|
||||
function makeRole(type: "admin" | "consultant" | "organization"): Role {
|
||||
switch (type) {
|
||||
case "admin": {
|
||||
return Role.create(
|
||||
{
|
||||
name: "Admin",
|
||||
permissions: [
|
||||
{ resource: "admin", actions: ["create", "update", "delete"] },
|
||||
{ resource: "consultant", actions: ["create", "update", "delete"] },
|
||||
{ resource: "organization", actions: ["create", "update", "delete"] },
|
||||
],
|
||||
},
|
||||
"test",
|
||||
);
|
||||
}
|
||||
case "consultant": {
|
||||
return Role.create(
|
||||
{
|
||||
name: "Consultant",
|
||||
permissions: [{ resource: "consultant", actions: ["create", "update", "delete"] }],
|
||||
},
|
||||
"test",
|
||||
);
|
||||
}
|
||||
case "organization": {
|
||||
return Role.create(
|
||||
{
|
||||
name: "Organization",
|
||||
permissions: [{ resource: "organization", actions: ["create", "update", "delete"] }],
|
||||
},
|
||||
"test",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type AuthorizeFn = (data: EventData<AccountCreated>, optional?: AuthorizationOptions) => Promise<Account>;
|
||||
@@ -1,62 +0,0 @@
|
||||
/**
|
||||
* Removes excess indentation caused by using multiline template strings.
|
||||
*
|
||||
* Ported from `dedent-js` solution.
|
||||
*
|
||||
* @see https://github.com/MartinKolarik/dedent-js
|
||||
*
|
||||
* @param templateStrings - Template strings to dedent.
|
||||
*
|
||||
* @example
|
||||
* {
|
||||
* nested: {
|
||||
* examples: [
|
||||
* dedent(`
|
||||
* I am 8 spaces off from the beginning of this file.
|
||||
* But I will be 2 spaces based on the trimmed distance
|
||||
* of the first line.
|
||||
* `),
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
export function dedent(templateStrings: TemplateStringsArray | string, ...values: any[]) {
|
||||
const matches = [];
|
||||
const strings = typeof templateStrings === "string" ? [templateStrings] : templateStrings.slice();
|
||||
|
||||
// Remove trailing whitespace.
|
||||
|
||||
strings[strings.length - 1] = strings[strings.length - 1].replace(/\r?\n([\t ]*)$/, "");
|
||||
|
||||
// Find all line breaks to determine the highest common indentation level.
|
||||
|
||||
for (let i = 0; i < strings.length; i++) {
|
||||
const match = strings[i].match(/\n[\t ]+/g);
|
||||
if (match) {
|
||||
matches.push(...match);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the common indentation from all strings.
|
||||
|
||||
if (matches.length) {
|
||||
const size = Math.min(...matches.map((value) => value.length - 1));
|
||||
const pattern = new RegExp(`\n[\t ]{${size}}`, "g");
|
||||
for (let i = 0; i < strings.length; i++) {
|
||||
strings[i] = strings[i].replace(pattern, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Remove leading whitespace.
|
||||
|
||||
strings[0] = strings[0].replace(/^\r?\n/, "");
|
||||
|
||||
// Perform interpolation.
|
||||
|
||||
let string = strings[0];
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
string += values[i] + strings[i + 1];
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* Traverse path and look for a `generate.ts` file in each folder found under
|
||||
* the given path. If a `generate.ts` file is found it is imported so its content
|
||||
* is executed.
|
||||
*
|
||||
* @param path - Path to resolve `generate.ts` files.
|
||||
* @param filter - Which folders found under the given path to ignore.
|
||||
*/
|
||||
export async function generate(path: string, filter: string[] = []): Promise<void> {
|
||||
const generate: string[] = [];
|
||||
for await (const entry of Deno.readDir(path)) {
|
||||
if (entry.isDirectory === true) {
|
||||
const moduleName = path.split("/").pop();
|
||||
if (moduleName === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (filter.length > 0 && filter.includes(moduleName) === false) {
|
||||
continue;
|
||||
}
|
||||
const filePath = `${path}/${entry.name}/.tasks/generate.ts`;
|
||||
if (await hasFile(filePath)) {
|
||||
generate.push(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const filePath of generate) {
|
||||
await import(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
async function hasFile(filePath: string) {
|
||||
try {
|
||||
await Deno.lstat(filePath);
|
||||
} catch (err) {
|
||||
if (!(err instanceof Deno.errors.NotFound)) {
|
||||
throw err;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { procedure } from "@platform/relay";
|
||||
import z from "zod";
|
||||
|
||||
const EventSchema = z.object({
|
||||
id: z.uuid(),
|
||||
stream: z.uuid(),
|
||||
type: z.string(),
|
||||
data: z.any(),
|
||||
meta: z.any(),
|
||||
recorded: z.string(),
|
||||
created: z.string(),
|
||||
});
|
||||
|
||||
export default procedure
|
||||
.method("event")
|
||||
.access("public")
|
||||
.params(EventSchema)
|
||||
.response(z.uuid())
|
||||
.handle(async (event) => {
|
||||
console.log(event);
|
||||
return crypto.randomUUID();
|
||||
});
|
||||
@@ -8,7 +8,7 @@ import socket from "@platform/socket/server.ts";
|
||||
import { storage } from "@platform/storage";
|
||||
|
||||
import { config } from "./config.ts";
|
||||
import session from "./services/session.ts";
|
||||
import session from "./session.ts";
|
||||
|
||||
const log = logger.prefix("Server");
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ export class Controller<TState extends Unknown = Empty, TProps extends Unknown =
|
||||
component: ReactComponent<TProps, TController>,
|
||||
setView: any,
|
||||
): InstanceType<TController> {
|
||||
return new this(component, setView);
|
||||
return new Controller(component, setView);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { type FunctionComponent } from "react";
|
||||
import type React from "react";
|
||||
import type { FunctionComponent } from "react";
|
||||
|
||||
import { ControllerRefs } from "./refs.ts";
|
||||
import type { ControllerRefs } from "./refs.ts";
|
||||
|
||||
export type ReactComponent<TProps extends Unknown, TController extends ControllerClass> = FunctionComponent<{
|
||||
props: TProps;
|
||||
|
||||
@@ -82,7 +82,7 @@ function useController(controller: ControllerClass, component: any, props: any,
|
||||
return () => {
|
||||
instance.$destroy();
|
||||
};
|
||||
}, []);
|
||||
}, [component, controller, setView]);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { TodosController } from "./todos.controller.ts";
|
||||
|
||||
export const TodosView = makeControllerView(
|
||||
TodosController,
|
||||
({ state: { form, todos }, actions: { remove, stress } }) => {
|
||||
({ state: { form, todos }, actions: { remove } }) => {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 flex flex-col items-center py-10 px-4 font-sans">
|
||||
<div className="w-full max-w-2xl space-y-8">
|
||||
|
||||
@@ -2,8 +2,8 @@ module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'sans-serif'],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sans: ["Inter", "sans-serif"],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
"references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
|
||||
45
biome.json
Normal file
45
biome.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"formatWithErrors": false,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineEnding": "lf",
|
||||
"lineWidth": 120,
|
||||
"attributePosition": "auto"
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"suspicious": {
|
||||
"noConfusingVoidType": "off",
|
||||
"noExplicitAny": "off"
|
||||
},
|
||||
"complexity": {
|
||||
"noBannedTypes": "off"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assist": {
|
||||
"enabled": true,
|
||||
"actions": {
|
||||
"source": {
|
||||
"organizeImports": {
|
||||
"level": "on",
|
||||
"options": {
|
||||
"groups": [
|
||||
[":BUN:", ":NODE:"],
|
||||
":BLANK_LINE:",
|
||||
":PACKAGE:",
|
||||
":BLANK_LINE:",
|
||||
[":ALIAS:"],
|
||||
":BLANK_LINE:",
|
||||
":PATH:"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
deno.json
12
deno.json
@@ -43,16 +43,8 @@
|
||||
"description": "Start react application instance."
|
||||
},
|
||||
"check": {
|
||||
"command": "deno check ./api/server.ts ./platform",
|
||||
"description": "Runs a check on all the projects main entry files."
|
||||
},
|
||||
"lint": {
|
||||
"command": "npx eslint -c eslint.config.mjs .",
|
||||
"description": "Runs eslint across the entire project."
|
||||
},
|
||||
"fmt": {
|
||||
"command": "npx prettier --write .",
|
||||
"description": "Runs prettier formatting across the entire project."
|
||||
"command": "deno run -A npm:@biomejs/biome check --write ./api ./modules ./platform",
|
||||
"description": "Format, lint, and organize imports of the entire project."
|
||||
},
|
||||
"test": {
|
||||
"command": "deno test --allow-all",
|
||||
|
||||
75
deno.lock
generated
75
deno.lock
generated
@@ -1,6 +1,8 @@
|
||||
{
|
||||
"version": "5",
|
||||
"specifiers": {
|
||||
"npm:@biomejs/biome@*": "2.2.4",
|
||||
"npm:@biomejs/biome@2.2.4": "2.2.4",
|
||||
"npm:@cerbos/http@0.23.1": "0.23.1",
|
||||
"npm:@eslint/js@9.35.0": "9.35.0",
|
||||
"npm:@jsr/std__assert@1.0.14": "1.0.14",
|
||||
@@ -23,7 +25,6 @@
|
||||
"npm:cookie@1.0.2": "1.0.2",
|
||||
"npm:eslint-plugin-react-hooks@5.2.0": "5.2.0_eslint@9.35.0",
|
||||
"npm:eslint-plugin-react-refresh@0.4.20": "0.4.20_eslint@9.35.0",
|
||||
"npm:eslint-plugin-simple-import-sort@12.1.1": "12.1.1_eslint@9.35.0",
|
||||
"npm:eslint@9.35.0": "9.35.0",
|
||||
"npm:fast-equals@5.2.2": "5.2.2",
|
||||
"npm:globals@16.4.0": "16.4.0",
|
||||
@@ -31,7 +32,6 @@
|
||||
"npm:mongodb@6.20.0": "6.20.0",
|
||||
"npm:nanoid@5.1.5": "5.1.5",
|
||||
"npm:path-to-regexp@8": "8.3.0",
|
||||
"npm:prettier@3.6.2": "3.6.2",
|
||||
"npm:react-dom@19.1.1": "19.1.1_react@19.1.1",
|
||||
"npm:react@19.1.1": "19.1.1",
|
||||
"npm:tailwindcss@4.1.13": "4.1.13",
|
||||
@@ -184,6 +184,60 @@
|
||||
"@better-fetch/fetch@1.1.18": {
|
||||
"integrity": "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA=="
|
||||
},
|
||||
"@biomejs/biome@2.2.4": {
|
||||
"integrity": "sha512-TBHU5bUy/Ok6m8c0y3pZiuO/BZoY/OcGxoLlrfQof5s8ISVwbVBdFINPQZyFfKwil8XibYWb7JMwnT8wT4WVPg==",
|
||||
"optionalDependencies": [
|
||||
"@biomejs/cli-darwin-arm64",
|
||||
"@biomejs/cli-darwin-x64",
|
||||
"@biomejs/cli-linux-arm64",
|
||||
"@biomejs/cli-linux-arm64-musl",
|
||||
"@biomejs/cli-linux-x64",
|
||||
"@biomejs/cli-linux-x64-musl",
|
||||
"@biomejs/cli-win32-arm64",
|
||||
"@biomejs/cli-win32-x64"
|
||||
],
|
||||
"bin": true
|
||||
},
|
||||
"@biomejs/cli-darwin-arm64@2.2.4": {
|
||||
"integrity": "sha512-RJe2uiyaloN4hne4d2+qVj3d3gFJFbmrr5PYtkkjei1O9c+BjGXgpUPVbi8Pl8syumhzJjFsSIYkcLt2VlVLMA==",
|
||||
"os": ["darwin"],
|
||||
"cpu": ["arm64"]
|
||||
},
|
||||
"@biomejs/cli-darwin-x64@2.2.4": {
|
||||
"integrity": "sha512-cFsdB4ePanVWfTnPVaUX+yr8qV8ifxjBKMkZwN7gKb20qXPxd/PmwqUH8mY5wnM9+U0QwM76CxFyBRJhC9tQwg==",
|
||||
"os": ["darwin"],
|
||||
"cpu": ["x64"]
|
||||
},
|
||||
"@biomejs/cli-linux-arm64-musl@2.2.4": {
|
||||
"integrity": "sha512-7TNPkMQEWfjvJDaZRSkDCPT/2r5ESFPKx+TEev+I2BXDGIjfCZk2+b88FOhnJNHtksbOZv8ZWnxrA5gyTYhSsQ==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["arm64"]
|
||||
},
|
||||
"@biomejs/cli-linux-arm64@2.2.4": {
|
||||
"integrity": "sha512-M/Iz48p4NAzMXOuH+tsn5BvG/Jb07KOMTdSVwJpicmhN309BeEyRyQX+n1XDF0JVSlu28+hiTQ2L4rZPvu7nMw==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["arm64"]
|
||||
},
|
||||
"@biomejs/cli-linux-x64-musl@2.2.4": {
|
||||
"integrity": "sha512-m41nFDS0ksXK2gwXL6W6yZTYPMH0LughqbsxInSKetoH6morVj43szqKx79Iudkp8WRT5SxSh7qVb8KCUiewGg==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["x64"]
|
||||
},
|
||||
"@biomejs/cli-linux-x64@2.2.4": {
|
||||
"integrity": "sha512-orr3nnf2Dpb2ssl6aihQtvcKtLySLta4E2UcXdp7+RTa7mfJjBgIsbS0B9GC8gVu0hjOu021aU8b3/I1tn+pVQ==",
|
||||
"os": ["linux"],
|
||||
"cpu": ["x64"]
|
||||
},
|
||||
"@biomejs/cli-win32-arm64@2.2.4": {
|
||||
"integrity": "sha512-NXnfTeKHDFUWfxAefa57DiGmu9VyKi0cDqFpdI+1hJWQjGJhJutHPX0b5m+eXvTKOaf+brU+P0JrQAZMb5yYaQ==",
|
||||
"os": ["win32"],
|
||||
"cpu": ["arm64"]
|
||||
},
|
||||
"@biomejs/cli-win32-x64@2.2.4": {
|
||||
"integrity": "sha512-3Y4V4zVRarVh/B/eSHczR4LYoSVyv3Dfuvm3cWs5w/HScccS0+Wt/lHOcDTRYeHjQmMYVC3rIRWqyN2EI52+zg==",
|
||||
"os": ["win32"],
|
||||
"cpu": ["x64"]
|
||||
},
|
||||
"@cerbos/core@0.24.1": {
|
||||
"integrity": "sha512-Gt9ETQR3WDVcPlxN+HiGUDtNgWFulwS5ZjBgzJFsdb7e2GCw0tOPE9Ex1qHNZvG/0JHpFWJWIiYaSKyXcp35YQ==",
|
||||
"dependencies": [
|
||||
@@ -1379,12 +1433,6 @@
|
||||
"eslint"
|
||||
]
|
||||
},
|
||||
"eslint-plugin-simple-import-sort@12.1.1_eslint@9.35.0": {
|
||||
"integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==",
|
||||
"dependencies": [
|
||||
"eslint"
|
||||
]
|
||||
},
|
||||
"eslint-scope@8.4.0": {
|
||||
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
|
||||
"dependencies": [
|
||||
@@ -1927,10 +1975,6 @@
|
||||
"prelude-ls@1.2.1": {
|
||||
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
|
||||
},
|
||||
"prettier@3.6.2": {
|
||||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||
"bin": true
|
||||
},
|
||||
"punycode@2.3.1": {
|
||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="
|
||||
},
|
||||
@@ -2284,12 +2328,9 @@
|
||||
"workspace": {
|
||||
"packageJson": {
|
||||
"dependencies": [
|
||||
"npm:@biomejs/biome@2.2.4",
|
||||
"npm:@jsr/std__assert@1.0.14",
|
||||
"npm:@jsr/std__testing@1.0.15",
|
||||
"npm:eslint-plugin-simple-import-sort@12.1.1",
|
||||
"npm:eslint@9.35.0",
|
||||
"npm:prettier@3.6.2",
|
||||
"npm:typescript-eslint@8.44.0"
|
||||
"npm:@jsr/std__testing@1.0.15"
|
||||
]
|
||||
},
|
||||
"members": {
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import simpleImportSort from "eslint-plugin-simple-import-sort";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default [
|
||||
...tseslint.configs.recommended,
|
||||
{
|
||||
plugins: {
|
||||
"simple-import-sort": simpleImportSort,
|
||||
},
|
||||
rules: {
|
||||
"simple-import-sort/imports": "error",
|
||||
"simple-import-sort/exports": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["**/*.ts"],
|
||||
rules: {
|
||||
"@typescript-eslint/ban-ts-comment": [
|
||||
"error",
|
||||
{
|
||||
"ts-expect-error": "allow-with-description",
|
||||
minimumDescriptionLength: 10,
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
argsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getEnvironmentVariable } from "@platform/config/environment.ts";
|
||||
import { SerializeOptions } from "cookie";
|
||||
import type { SerializeOptions } from "cookie";
|
||||
import z from "zod";
|
||||
|
||||
export const config = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import route from "./spec.ts";
|
||||
|
||||
export default route.access("session").handle(async ({ params: { id } }, { session, principal, access }) => {
|
||||
export default route.access("session").handle(async () => {
|
||||
// const user = await getUserById(id);
|
||||
// if (user === undefined) {
|
||||
// return new NotFoundError("Identity does not exist, or has been removed.");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import route from "./spec.ts";
|
||||
|
||||
export default route.access("public").handle(async ({ body: { email } }) => {
|
||||
export default route.access("public").handle(async () => {
|
||||
// const code = await Passwordless.createCode({ tenantId: "public", email });
|
||||
// if (code.status !== "OK") {
|
||||
// return logger.info({
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ForbiddenError } from "@platform/relay";
|
||||
import { NotFoundError } from "@platform/relay";
|
||||
import { ForbiddenError, NotFoundError } from "@platform/relay";
|
||||
|
||||
import { getPrincipalById, setPrincipalRolesById } from "../../services/database.ts";
|
||||
import route from "./spec.ts";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { cerbos } from "@platform/cerbos";
|
||||
|
||||
import { Principal } from "../models/principal.ts";
|
||||
import type { Principal } from "../models/principal.ts";
|
||||
|
||||
export function getAccessControlMethods(principal: Principal) {
|
||||
return {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { getDatabaseAccessor } from "@platform/database/accessor.ts";
|
||||
|
||||
import {
|
||||
parsePrincipal,
|
||||
type Principal,
|
||||
PRINCIPAL_TYPE_NAMES,
|
||||
type Principal,
|
||||
PrincipalSchema,
|
||||
PrincipalTypeId,
|
||||
parsePrincipal,
|
||||
} from "../models/principal.ts";
|
||||
|
||||
export const db = getDatabaseAccessor<{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { AuditActor, auditors } from "@platform/spec/audit/actor.ts";
|
||||
import { type AuditActor, auditors } from "@platform/spec/audit/actor.ts";
|
||||
import { AggregateRoot, getDate } from "@valkyr/event-store";
|
||||
|
||||
import { db } from "../database.ts";
|
||||
import { EventRecord, EventStoreFactory, projector } from "../event-store.ts";
|
||||
import { type EventRecord, type EventStoreFactory, projector } from "../event-store.ts";
|
||||
|
||||
export class WorkspaceUser extends AggregateRoot<EventStoreFactory> {
|
||||
static override readonly name = "workspace:user";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { AuditActor, auditors } from "@platform/spec/audit/actor.ts";
|
||||
import { type AuditActor, auditors } from "@platform/spec/audit/actor.ts";
|
||||
import { AggregateRoot, getDate } from "@valkyr/event-store";
|
||||
|
||||
import { db } from "../database.ts";
|
||||
import { EventRecord, EventStoreFactory, projector } from "../event-store.ts";
|
||||
import { type EventRecord, type EventStoreFactory, projector } from "../event-store.ts";
|
||||
|
||||
export class Workspace extends AggregateRoot<EventStoreFactory> {
|
||||
static override readonly name = "workspace";
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import z from "zod";
|
||||
|
||||
/*
|
||||
export const resources = new ResourceRegistry([
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { getDatabaseAccessor } from "@platform/database/accessor.ts";
|
||||
|
||||
import { parseWorkspace, type Workspace } from "./models/workspace.ts";
|
||||
import { WorkspaceUser } from "./models/workspace-user.ts";
|
||||
import type { WorkspaceUser } from "./models/workspace-user.ts";
|
||||
|
||||
export const db = getDatabaseAccessor<{
|
||||
workspaces: Workspace;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { mongo } from "@platform/database/client.ts";
|
||||
import { EventFactory, EventStore, Prettify, Projector } from "@valkyr/event-store";
|
||||
import { EventFactory, EventStore, type Prettify, Projector } from "@valkyr/event-store";
|
||||
import { MongoAdapter } from "@valkyr/event-store/mongo";
|
||||
|
||||
/*
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
"devDependencies": {
|
||||
"@std/assert": "npm:@jsr/std__assert@1.0.14",
|
||||
"@std/testing": "npm:@jsr/std__testing@1.0.15",
|
||||
"eslint": "9.35.0",
|
||||
"eslint-plugin-simple-import-sort": "12.1.1",
|
||||
"prettier": "3.6.2",
|
||||
"typescript-eslint": "8.44.0"
|
||||
"@biomejs/biome": "2.2.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { load } from "@std/dotenv";
|
||||
import { z, type ZodType } from "zod";
|
||||
import type { ZodType, z } from "zod";
|
||||
|
||||
import { InvalidEnvironmentKeyError } from "./errors.ts";
|
||||
import { getServiceEnvironment, type ServiceEnvironment } from "./service.ts";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Collection, type CollectionOptions, type Db, type Document, type MongoClient } from "mongodb";
|
||||
import type { Collection, CollectionOptions, Db, Document, MongoClient } from "mongodb";
|
||||
|
||||
import { mongo } from "./client.ts";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Db } from "mongodb";
|
||||
import z, { type ZodObject, type ZodType } from "zod";
|
||||
import type { ZodObject, ZodType, z } from "zod";
|
||||
|
||||
/**
|
||||
* TODO ...
|
||||
@@ -29,7 +29,7 @@ export function makeDocumentParser<TSchema extends ZodObject>(schema: TSchema):
|
||||
export function toParsedDocuments<TSchema extends ZodType>(
|
||||
schema: TSchema,
|
||||
): (documents: unknown[]) => Promise<z.infer<TSchema>[]> {
|
||||
return async function (documents: unknown[]) {
|
||||
return async (documents: unknown[]) => {
|
||||
const parsed = [];
|
||||
for (const document of documents) {
|
||||
parsed.push(await schema.parseAsync(document));
|
||||
@@ -44,7 +44,7 @@ export function toParsedDocuments<TSchema extends ZodType>(
|
||||
export function toParsedDocument<TSchema extends ZodType>(
|
||||
schema: TSchema,
|
||||
): (document?: unknown) => Promise<z.infer<TSchema> | undefined> {
|
||||
return async function (document: unknown) {
|
||||
return async (document: unknown) => {
|
||||
if (document === undefined || document === null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HexValue } from "./color/hex.ts";
|
||||
import type { HexValue } from "./color/hex.ts";
|
||||
import { type BGColor, type Color, hexToBgColor, hexToColor, type Modifier, styles } from "./color/styles.ts";
|
||||
|
||||
export const chalk = {
|
||||
@@ -13,21 +13,15 @@ export const chalk = {
|
||||
} as Chalk;
|
||||
|
||||
for (const key in styles.modifier) {
|
||||
chalk[key as Modifier] = function (value: string) {
|
||||
return toModifiedValue(key as Modifier, value);
|
||||
};
|
||||
chalk[key as Modifier] = (value: string) => toModifiedValue(key as Modifier, value);
|
||||
}
|
||||
|
||||
for (const key in styles.color) {
|
||||
chalk[key as Color] = function (value: string) {
|
||||
return toColorValue(key as Color, value);
|
||||
};
|
||||
chalk[key as Color] = (value: string) => toColorValue(key as Color, value);
|
||||
}
|
||||
|
||||
for (const key in styles.bgColor) {
|
||||
chalk[key as BGColor] = function (value: string) {
|
||||
return toBGColorValue(key as BGColor, value);
|
||||
};
|
||||
chalk[key as BGColor] = (value: string) => toBGColorValue(key as BGColor, value);
|
||||
}
|
||||
|
||||
function toModifiedValue(key: Modifier, value: string): string {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { hexToAnsi256, HexValue } from "./hex.ts";
|
||||
import { type HexValue, hexToAnsi256 } from "./hex.ts";
|
||||
import { toEscapeSequence } from "./utilities.ts";
|
||||
|
||||
export const styles = {
|
||||
|
||||
@@ -2,12 +2,12 @@ import { encrypt } from "@platform/vault";
|
||||
|
||||
import {
|
||||
assertServerErrorResponse,
|
||||
RelayAdapter,
|
||||
RelayInput,
|
||||
RelayResponse,
|
||||
ServerErrorResponse,
|
||||
type RelayAdapter,
|
||||
type RelayInput,
|
||||
type RelayResponse,
|
||||
type ServerErrorResponse,
|
||||
} from "../libraries/adapter.ts";
|
||||
import { ServerError, ServerErrorType } from "../libraries/errors.ts";
|
||||
import { ServerError, type ServerErrorType } from "../libraries/errors.ts";
|
||||
|
||||
/**
|
||||
* HttpAdapter provides a unified transport layer for Relay.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
export interface ServerContext {}
|
||||
export type ServerContext = {};
|
||||
|
||||
export const context: ServerContext = {} as any;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ZodError } from "zod";
|
||||
import type { ZodError } from "zod";
|
||||
|
||||
export abstract class ServerError<TData = unknown> extends Error {
|
||||
abstract readonly code: string;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import z, { ZodType } from "zod";
|
||||
import type z from "zod";
|
||||
import type { ZodType } from "zod";
|
||||
|
||||
import { ServerContext } from "./context.ts";
|
||||
import { ServerError, ServerErrorClass } from "./errors.ts";
|
||||
import { RouteAccess } from "./route.ts";
|
||||
import type { ServerContext } from "./context.ts";
|
||||
import type { ServerError, ServerErrorClass } from "./errors.ts";
|
||||
import type { RouteAccess } from "./route.ts";
|
||||
|
||||
export class Procedure<const TState extends State = State> {
|
||||
readonly type = "procedure" as const;
|
||||
@@ -234,7 +235,8 @@ type HandleFn<TArgs extends Array<any> = any[], TResponse = any> = (
|
||||
? Promise<z.infer<TResponse> | Response | ServerError>
|
||||
: Promise<Response | ServerError | void>;
|
||||
|
||||
type ServerArgs<TState extends State> =
|
||||
HasInputArgs<TState> extends true ? [z.output<TState["params"]>, ServerContext] : [ServerContext];
|
||||
type ServerArgs<TState extends State> = HasInputArgs<TState> extends true
|
||||
? [z.output<TState["params"]>, ServerContext]
|
||||
: [ServerContext];
|
||||
|
||||
type HasInputArgs<TState extends State> = TState["params"] extends ZodType ? true : false;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { match, type MatchFunction } from "path-to-regexp";
|
||||
import z, { ZodObject, ZodRawShape, ZodType } from "zod";
|
||||
import { type MatchFunction, match } from "path-to-regexp";
|
||||
import z, { type ZodObject, type ZodRawShape, type ZodType } from "zod";
|
||||
|
||||
import { ServerContext } from "./context.ts";
|
||||
import { ServerError, ServerErrorClass } from "./errors.ts";
|
||||
import { Hooks } from "./hooks.ts";
|
||||
import type { ServerContext } from "./context.ts";
|
||||
import { ServerError, type ServerErrorClass } from "./errors.ts";
|
||||
import type { Hooks } from "./hooks.ts";
|
||||
|
||||
export class Route<const TState extends RouteState = RouteState> {
|
||||
readonly type = "route" as const;
|
||||
@@ -480,8 +480,7 @@ type HandleFn<TArgs extends Array<any> = any[], TResponse = any> = (
|
||||
? Promise<z.infer<TResponse> | Response | ServerError>
|
||||
: Promise<Response | ServerError | void>;
|
||||
|
||||
type ServerArgs<TState extends RouteState> =
|
||||
HasInputArgs<TState> extends true
|
||||
type ServerArgs<TState extends RouteState> = HasInputArgs<TState> extends true
|
||||
? [
|
||||
(TState["params"] extends ZodObject ? { params: z.output<TState["params"]> } : unknown) &
|
||||
(TState["query"] extends ZodObject ? { query: z.output<TState["query"]> } : unknown) &
|
||||
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
InternalServerError,
|
||||
NotFoundError,
|
||||
NotImplementedError,
|
||||
Route,
|
||||
RouteMethod,
|
||||
type Route,
|
||||
type RouteMethod,
|
||||
ServerError,
|
||||
type ServerErrorResponse,
|
||||
UnauthorizedError,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import "./types.ts";
|
||||
|
||||
import { context } from "@platform/relay";
|
||||
import { InternalServerError } from "@platform/relay";
|
||||
import { storage } from "@platform/storage";
|
||||
import { getStorageContext } from "@platform/storage";
|
||||
import { context, InternalServerError } from "@platform/relay";
|
||||
import { getStorageContext, storage } from "@platform/storage";
|
||||
|
||||
export default {
|
||||
/**
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { Api } from "./api.ts";
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
export function upgradeWebSocket(request: Request, api: Api) {
|
||||
export function upgradeWebSocket(request: Request, _api: Api) {
|
||||
const { socket, response } = Deno.upgradeWebSocket(request);
|
||||
|
||||
socket.addEventListener("open", () => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import "./types.d.ts";
|
||||
|
||||
import { InternalServerError } from "@platform/relay";
|
||||
import { context } from "@platform/relay";
|
||||
import { context, InternalServerError } from "@platform/relay";
|
||||
import { getStorageContext, storage } from "@platform/storage";
|
||||
|
||||
import { SocketRegistry } from "./sockets.ts";
|
||||
|
||||
@@ -41,7 +41,9 @@ export class SocketRegistry {
|
||||
* @param data - Data to send to each connected socket.
|
||||
*/
|
||||
send(data: string | ArrayBufferLike | Blob | ArrayBufferView): this {
|
||||
this.#sockets.forEach((socket) => socket.send(data));
|
||||
this.#sockets.forEach((socket) => {
|
||||
socket.send(data);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,4 @@ export function getStorageContext(): StorageContext {
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
export interface StorageContext {}
|
||||
export type StorageContext = {};
|
||||
|
||||
@@ -46,6 +46,9 @@ function bufferToHex(buffer: ArrayBuffer): string {
|
||||
}
|
||||
|
||||
function hexToBuffer(hex: string): ArrayBuffer {
|
||||
const bytes = new Uint8Array(hex.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16)));
|
||||
return bytes.buffer;
|
||||
const match = hex.match(/.{1,2}/g);
|
||||
if (match === null) {
|
||||
return new Uint8Array().buffer;
|
||||
}
|
||||
return new Uint8Array(match.map((byte) => parseInt(byte, 16))).buffer;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import * as Jose from "jose";
|
||||
|
||||
import { createKeyPair, ExportedKeyPair, importPrivateKey, importPublicKey, KeyPair, loadKeyPair } from "./key-pair.ts";
|
||||
import {
|
||||
createKeyPair,
|
||||
type ExportedKeyPair,
|
||||
importPrivateKey,
|
||||
importPublicKey,
|
||||
type KeyPair,
|
||||
loadKeyPair,
|
||||
} from "./key-pair.ts";
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user