17 Commits

Author SHA1 Message Date
09d85c8f22 lalalalal 2026-02-02 19:06:47 -05:00
a0ce5183b2 dkkdkdkdkd 2026-02-02 19:02:40 -05:00
c83202b681 fafafafa 2026-02-02 18:59:54 -05:00
2c1d297be1 fda 2026-02-02 18:55:31 -05:00
2d697c1e61 Move package.json files around 2026-02-02 18:47:54 -05:00
410bb671f1 fads 2026-02-02 18:41:26 -05:00
0ae197f939 fdas 2026-02-02 18:39:49 -05:00
370bea5d98 asdf 2026-02-02 18:37:09 -05:00
9d34768051 Add file list 2026-02-02 18:35:37 -05:00
b752eb5080 Make shfmt happier 2026-02-02 18:32:53 -05:00
1ed5aa4b33 Reorder some imports 2026-02-02 18:32:39 -05:00
4d1c30b874 Fix some stragglers 2026-02-02 18:31:03 -05:00
02edf259f0 Rename framework/ to diachron/ and update all references
Update paths in .gitignore, cmd, develop, mgmt, sync.sh, check.sh,
fixup.sh, CLAUDE.md, docs/new-project.md, and backend/*.sh scripts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 18:10:32 -05:00
db1f2151de Rename express/ to backend/ and update references
Update paths in sync.sh, master/main.go, and CLAUDE.md to reflect
the directory rename.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 17:54:44 -05:00
6e669d025a Move many files to diachron subdir 2026-02-02 17:22:08 -05:00
a1dbf71de4 Rename directory 2026-02-02 16:53:22 -05:00
0afc3efa5d Fix test script to work on macOS default bash
Replace globstar (bash 4.0+) with find for portability.
macOS ships with bash 3.2 which doesn't support globstar.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 12:25:26 -05:00
120 changed files with 292 additions and 85 deletions

8
.gitignore vendored
View File

@@ -1,5 +1,5 @@
**/node_modules
framework/downloads
framework/binaries
framework/.nodejs
framework/.nodejs-config
diachron/downloads
diachron/binaries
diachron/.nodejs
diachron/.nodejs-config

View File

@@ -38,7 +38,7 @@ master process. Key design principles:
**Format TypeScript code:**
```bash
cd express && ../cmd pnpm biome check --write .
cd backend && ../cmd pnpm biome check --write .
```
**Build Go master process:**
@@ -54,9 +54,9 @@ cd master && go build
### Components
- **express/** - TypeScript/Express.js backend application
- **backend/** - TypeScript/Express.js backend application
- **master/** - Go-based master process for file watching and process management
- **framework/** - Managed binaries (Node.js, pnpm), command wrappers, and
- **diachron/** - Managed binaries (Node.js, pnpm), command wrappers, and
framework-specific library code
- **monitor/** - Go file watcher that triggers rebuilds (experimental)
@@ -68,7 +68,7 @@ Responsibilities:
- Proxy web requests to backend workers
- Behaves identically in all environments (no dev/prod distinction)
### Express App Structure
### Backend App Structure
- `app.ts` - Main Express application setup with route matching
- `routes.ts` - Route definitions
@@ -78,7 +78,7 @@ Responsibilities:
### Framework Command System
Commands flow through: `./cmd``framework/cmd.d/*``framework/shims/*` → managed binaries in `framework/binaries/`
Commands flow through: `./cmd``diachron/cmd.d/*``diachron/shims/*` → managed binaries in `diachron/binaries/`
This ensures consistent tooling versions across the team without system-wide installations.

View File

@@ -3,15 +3,13 @@ import express, {
type Response as ExpressResponse,
} from "express";
import { match } from "path-to-regexp";
import { Session } from "./auth";
import { cli } from "./cli";
import { contentTypes } from "./content-types";
import { runWithContext } from "./context";
import { core } from "./core";
import { httpCodes } from "./http-codes";
import { request } from "./request";
import { routes } from "./routes";
import { Session } from "./diachron/auth";
import { cli } from "./diachron/cli";
import { contentTypes } from "./diachron/content-types";
import { runWithContext } from "./diachron/context";
import { core } from "./diachron/core";
import { httpCodes } from "./diachron/http-codes";
import { request } from "./diachron/request";
// import { URLPattern } from 'node:url';
import {
AuthenticationRequired,
@@ -25,7 +23,8 @@ import {
type ProcessedRoute,
type Result,
type Route,
} from "./types";
} from "./diachron/types";
import { routes } from "./routes";
const app = express();

View File

@@ -8,7 +8,7 @@ check_dir="$DIR"
out_dir="$check_dir/out"
source "$check_dir"/../framework/shims/common
source "$check_dir"/../framework/shims/node.common
source "$check_dir"/../diachron/shims/common
source "$check_dir"/../diachron/shims/node.common
$ROOT/cmd pnpm tsc --outDir "$out_dir"

View File

@@ -1,5 +1,5 @@
import { DateTime } from "ts-luxon";
import { get, User } from "../framework/hydrators/user";
import { get, User } from "../hydrators/user";
import { request } from "../request";
import { html, render } from "../request/util";
import type { Call, Result, Route } from "../types";

View File

@@ -113,7 +113,7 @@ async function raw<T = unknown>(
//
// Migrations directory: express/migrations/
const FRAMEWORK_MIGRATIONS_DIR = path.join(__dirname, "framework/migrations");
const FRAMEWORK_MIGRATIONS_DIR = path.join(__dirname, "diachron/migrations");
const APP_MIGRATIONS_DIR = path.join(__dirname, "migrations");
const MIGRATIONS_TABLE = "_migrations";

View File

@@ -1,7 +1,7 @@
import { Kysely, PostgresDialect } from "kysely";
import { Pool } from "pg";
import { connectionConfig } from "../../database";
import type { DB } from "../../generated/db";
import { connectionConfig } from "../database";
const db = new Kysely<DB>({
dialect: new PostgresDialect({

View File

@@ -0,0 +1 @@
export type Hydrators = {};

View File

@@ -2,7 +2,7 @@
// Run: DB_PORT=5433 DB_USER=diachron_test DB_PASSWORD=diachron_test DB_NAME=diachron_test npx tsx --test tests/*.test.ts
import { Pool } from "pg";
import { connectionConfig, migrate } from "../../../database";
import { connectionConfig, migrate } from "../../database";
const pool = new Pool(connectionConfig);

View File

@@ -1,5 +1,5 @@
// Tests for user hydrator
// Run with: cd express && DB_PORT=5433 DB_USER=diachron_test DB_PASSWORD=diachron_test DB_NAME=diachron_test ../cmd npx tsx --test framework/hydrators/tests/user.test.ts
// Run with: cd express && DB_PORT=5433 DB_USER=diachron_test DB_PASSWORD=diachron_test DB_NAME=diachron_test ../cmd npx tsx --test diachron/hydrators/tests/user.test.ts
import assert from "node:assert/strict";
import { after, before, beforeEach, describe, it } from "node:test";

View File

@@ -0,0 +1,59 @@
import {
ColumnType,
Generated,
Insertable,
JSONColumnType,
Selectable,
Updateable,
} from "kysely";
import type { TypeID } from "typeid-js";
import { z } from "zod";
import { db, Hydrator } from "./hydrator";
const parser = z.object({
// id: z.uuidv7(),
id: z.uuid(),
display_name: z.string(),
// FIXME: status is duplicated elsewhere
status: z.union([
z.literal("active"),
z.literal("suspended"),
z.literal("pending"),
]),
email: z.email(),
});
const tp = parser.parse({
id: "cfae0a19-6515-4813-bc2d-1e032b72b203",
display_name: "foo",
status: "active",
email: "mw@philologue.net",
});
export type User = z.infer<typeof parser>;
const get = async (id: string): Promise<null | User> => {
const ret = await db
.selectFrom("users")
.where("users.id", "=", id)
.innerJoin("user_emails", "user_emails.user_id", "users.id")
.select([
"users.id",
"users.status",
"users.display_name",
"user_emails.email",
])
.executeTakeFirst();
if (ret === undefined) {
return null;
}
console.dir(ret);
const parsed = parser.parse(ret);
return parsed;
};
export { get };

109
backend/generated/db.d.ts vendored Normal file
View File

@@ -0,0 +1,109 @@
/**
* This file was generated by kysely-codegen.
* Please do not edit it manually.
*/
import type { ColumnType } from "kysely";
export type Generated<T> =
T extends ColumnType<infer S, infer I, infer U>
? ColumnType<S, I | undefined, U>
: ColumnType<T, T | undefined, T>;
export type Timestamp = ColumnType<Date, Date | string, Date | string>;
export interface _Migrations {
applied_at: Generated<Timestamp>;
id: Generated<number>;
name: string;
}
export interface Capabilities {
description: string | null;
id: string;
name: string;
}
export interface Groups {
created_at: Generated<Timestamp>;
id: string;
name: string;
}
export interface RoleCapabilities {
capability_id: string;
granted_at: Generated<Timestamp>;
revoked_at: Timestamp | null;
role_id: string;
}
export interface Roles {
description: string | null;
id: string;
name: string;
}
export interface Sessions {
auth_method: string;
created_at: Generated<Timestamp>;
expires_at: Timestamp;
id: Generated<string>;
ip_address: string | null;
is_used: Generated<boolean | null>;
revoked_at: Timestamp | null;
token_hash: string;
token_type: string;
user_agent: string | null;
user_email_id: string | null;
user_id: string;
}
export interface UserCredentials {
created_at: Generated<Timestamp>;
credential_type: Generated<string>;
id: string;
password_hash: string | null;
updated_at: Generated<Timestamp>;
user_id: string;
}
export interface UserEmails {
created_at: Generated<Timestamp>;
email: string;
id: string;
is_primary: Generated<boolean>;
is_verified: Generated<boolean>;
normalized_email: string;
revoked_at: Timestamp | null;
user_id: string;
verified_at: Timestamp | null;
}
export interface UserGroupRoles {
granted_at: Generated<Timestamp>;
group_id: string;
revoked_at: Timestamp | null;
role_id: string;
user_id: string;
}
export interface Users {
created_at: Generated<Timestamp>;
display_name: string | null;
id: string;
status: Generated<string>;
updated_at: Generated<Timestamp>;
}
export interface DB {
_migrations: _Migrations;
capabilities: Capabilities;
groups: Groups;
role_capabilities: RoleCapabilities;
roles: Roles;
sessions: Sessions;
user_credentials: UserCredentials;
user_emails: UserEmails;
user_group_roles: UserGroupRoles;
users: Users;
}

View File

@@ -0,0 +1 @@
CREATE TABLE test_application_table ();

View File

@@ -0,0 +1 @@
CREATE TABLE test_application_table ();

20
backend/package.json Normal file
View File

@@ -0,0 +1,20 @@
{
"name": "my app",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "DB_PORT=5433 DB_USER=diachron_test DB_PASSWORD=diachron_test DB_NAME=diachron_test tsx --test '**/*.{test,spec}.ts'",
"test:watch": "DB_PORT=5433 DB_USER=diachron_test DB_PASSWORD=diachron_test DB_NAME=diachron_test tsx --test --watch '**/*.{test,spec}.ts'",
"nodemon": "nodemon dist/index.js",
"kysely-codegen": "kysely-codegen"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.12.4",
"dependencies": {
},
"devDependencies": {
}
}

View File

@@ -0,0 +1,2 @@
packages:
- 'diachron'

View File

@@ -2,13 +2,13 @@
import nunjucks from "nunjucks";
import { DateTime } from "ts-luxon";
import { authRoutes } from "./auth/routes";
import { routes as basicRoutes } from "./basic/routes";
import { contentTypes } from "./content-types";
import { core } from "./core";
import { multiHandler } from "./handlers";
import { httpCodes } from "./http-codes";
import type { Call, Result, Route } from "./types";
import { authRoutes } from "./diachron/auth/routes";
import { routes as basicRoutes } from "./diachron/basic/routes";
import { contentTypes } from "./diachron/content-types";
import { core } from "./diachron/core";
import { multiHandler } from "./diachron/handlers";
import { httpCodes } from "./diachron/http-codes";
import type { Call, Result, Route } from "./diachron/types";
// FIXME: Obviously put this somewhere else
const okText = (result: string): Result => {

View File

@@ -6,7 +6,7 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
check_dir="$DIR"
source "$check_dir"/../framework/shims/common
source "$check_dir"/../framework/shims/node.common
source "$check_dir"/../diachron/shims/common
source "$check_dir"/../diachron/shims/node.common
$ROOT/cmd pnpm tsc --showConfig

View File

@@ -9,5 +9,6 @@
"strict": true,
"types": ["node"],
"outDir": "out"
}
},
"exclude": ["**/*.spec.ts", "**/*.test.ts"]
}

View File

@@ -6,8 +6,8 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
check_dir="$DIR"
source "$check_dir"/../framework/shims/common
source "$check_dir"/../framework/shims/node.common
source "$check_dir"/../diachron/shims/common
source "$check_dir"/../diachron/shims/node.common
# $ROOT/cmd pnpm tsc --lib ES2023 --esModuleInterop -w $check_dir/app.ts
# $ROOT/cmd pnpm tsc -w $check_dir/app.ts

View File

@@ -10,7 +10,7 @@ cd "$DIR"
#
exclusions="SC2002"
source "$DIR/framework/versions"
source "$DIR/diachron/versions"
if [[ $# -ne 0 ]]; then
shellcheck --exclude="$exclusions" "$@"
@@ -20,10 +20,10 @@ fi
shell_scripts="$(fd .sh | xargs)"
# The files we need to check all either end in .sh or else they're the files
# in framework/cmd.d and framework/shims. -x instructs shellcheck to also
# in diachron/cmd.d and diachron/shims. -x instructs shellcheck to also
# check `source`d files.
shellcheck -x --exclude="$exclusions" "$DIR/cmd" "$DIR"/framework/cmd.d/* "$DIR"/framework/shims/* "$shell_scripts"
shellcheck -x --exclude="$exclusions" "$DIR/cmd" "$DIR"/diachron/cmd.d/* "$DIR"/diachron/shims/* "$shell_scripts"
pushd "$DIR/master"
docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:$golangci_lint golangci-lint run

4
cmd
View File

@@ -13,7 +13,7 @@ if [ $# -lt 1 ]; then
echo "Usage: ./cmd <command> [args...]"
echo ""
echo "Available commands:"
for cmd in "$DIR"/framework/cmd.d/*; do
for cmd in "$DIR"/diachron/cmd.d/*; do
if [ -x "$cmd" ]; then
basename "$cmd"
fi
@@ -24,4 +24,4 @@ fi
subcmd="$1"
shift
exec "$DIR"/framework/cmd.d/"$subcmd" "$@"
exec "$DIR"/diachron/cmd.d/"$subcmd" "$@"

View File

@@ -13,7 +13,7 @@ if [ $# -lt 1 ]; then
echo "Usage: ./develop <command> [args...]"
echo ""
echo "Available commands:"
for cmd in "$DIR"/framework/develop.d/*; do
for cmd in "$DIR"/diachron/develop.d/*; do
if [ -x "$cmd" ]; then
basename "$cmd"
fi
@@ -24,4 +24,4 @@ fi
subcmd="$1"
shift
exec "$DIR"/framework/develop.d/"$subcmd" "$@"
exec "$DIR"/diachron/develop.d/"$subcmd" "$@"

0
diachron/.nodejs/.gitignore vendored Normal file
View File

0
diachron/binaries/.gitignore vendored Normal file
View File

15
diachron/cmd.d/test Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
set -eu
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$DIR/../../backend"
if [ $# -eq 0 ]; then
# Find all test files - use -print0/xargs to handle filenames safely
find . -type f \( -name '*.spec.ts' -o -name '*.test.ts' \) -print0 |
xargs -0 "$DIR"/../shims/pnpm tsx --test
else
"$DIR"/../shims/pnpm tsx --test "$@"
fi

View File

@@ -5,5 +5,5 @@ set -eu
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$DIR/../.."
cd "$ROOT/express"
cd "$ROOT/backend"
"$DIR"/tsx migrate.ts "$@"

Some files were not shown because too many files have changed in this diff Show More