Replaces the legacy Bureau CMS stack (@bureaudouble/bureau, deno-sqlite-blob, Fresh-style RSC) with the fleet layout: a defineProgram schema over the legacy tables (rows carry over by id), the timeline-selected blob database (autokit.sqlite), the operator CLI and mf predeploy, the package-shipped admin with a plugin per table, and the /api rpc/mcp/openapi door. The pages still render as server components, wired like wtfutures: one Autokit session per process, the request's db minted once in a createStart request middleware, read as context.db by each page's server function and handed to the server components as a db prop; the rsc graph never imports the session module (tests/one-session.test.ts). French stays at / and English at /en, now through Autokit's locales: the *_en columns became the translationsJson bag beside their French base text. The integer order columns of persons, roles and resources became order keys (drag-to-reorder in the admin); media columns are stored-media lists resolved through autokit-media. The age gate is the same shared page for every visitor: a head script marks a visitor who already answered, before the first paint.
103 lines
4.2 KiB
TypeScript
103 lines
4.2 KiB
TypeScript
import { describe, expect, it } from "vite-plus/test";
|
|
|
|
import { parseConversation } from "#/utils/conversation-parser.ts";
|
|
import { localizePath } from "#/utils/locale.ts";
|
|
import { resourcesFilterUrl } from "#/utils/resources-url.ts";
|
|
import { byNewsDate, parseEntityId } from "#/utils/route-input.ts";
|
|
import { parseSearch, stringifySearch } from "#/utils/search.ts";
|
|
import { matchesQuery, normalizeQuery } from "#/utils/search-text.ts";
|
|
|
|
describe("the legacy addresses", () => {
|
|
it("keeps French at the root and English under /en", () => {
|
|
expect(localizePath("/", "en")).toBe("/en");
|
|
expect(localizePath("/en", "fr")).toBe("/");
|
|
expect(localizePath("/resources?author_id=72", "en")).toBe("/en/resources?author_id=72");
|
|
expect(localizePath("/en/news/3-x", "fr")).toBe("/news/3-x");
|
|
expect(localizePath("/en/news", "en")).toBe("/en/news");
|
|
});
|
|
|
|
it("reads a record's id off its slugged address", () => {
|
|
expect(parseEntityId("179-ai-girlfriend")).toBe(179);
|
|
expect(parseEntityId("12")).toBe(12);
|
|
expect(() => parseEntityId("nope")).toThrow();
|
|
});
|
|
|
|
it("round-trips repeated query parameters in address order", () => {
|
|
const search = parseSearch("?tag_id=2&tag_id=1&q=sex%20bots");
|
|
expect(search).toEqual({ tag_id: ["2", "1"], q: ["sex bots"] });
|
|
expect(stringifySearch(search)).toBe("?tag_id=2&tag_id=1&q=sex+bots");
|
|
expect(stringifySearch({})).toBe("");
|
|
});
|
|
|
|
it("changes one resources filter, drops the page and spells the address canonically", () => {
|
|
const url = new URL("https://fuckingtech.ch/resources?type_id=13&page=2&tag_id=5&tag_id=3");
|
|
expect(resourcesFilterUrl(url, { author_id: [72] })).toBe(
|
|
"/resources?author_id=72&tag_id=3&tag_id=5&type_id=13",
|
|
);
|
|
expect(resourcesFilterUrl(url, { display_mode: "table" })).toBe(
|
|
"/resources?tag_id=3&tag_id=5&type_id=13",
|
|
);
|
|
expect(resourcesFilterUrl(url, { page: "2" })).toBe(
|
|
"/resources?page=2&tag_id=3&tag_id=5&type_id=13",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("the field notes", () => {
|
|
it("sort by publication, else creation, newest first", () => {
|
|
const items = [
|
|
{ id: 1, publishedAt: null, createdAt: "2025-03-17T17:28:49" },
|
|
{ id: 2, publishedAt: "2025-04-02T09:31", createdAt: "2025-01-01T00:00:00" },
|
|
{ id: 3, publishedAt: null, createdAt: null },
|
|
];
|
|
expect(byNewsDate(items).map((item) => item.id)).toEqual([2, 1, 3]);
|
|
});
|
|
|
|
it("search as the legacy SQL did: accents of the query dropped, a few of the text's", () => {
|
|
expect(matchesQuery("Conférence à Montréal", normalizeQuery("MONTREAL"))).toBe(false);
|
|
expect(matchesQuery("Conférence à Genève", normalizeQuery("a gen"))).toBe(true);
|
|
expect(matchesQuery(null, "x")).toBe(false);
|
|
});
|
|
|
|
it("read both chat exports as one message list", () => {
|
|
expect(
|
|
parseConversation({
|
|
preset: "erebus",
|
|
systemPrompt: "You are a storyteller.",
|
|
messages: [
|
|
{ versions: [{ type: "singleStep", role: "user", content: [{ text: "Hi" }] }] },
|
|
{
|
|
versions: [
|
|
{
|
|
type: "multiStep",
|
|
role: "assistant",
|
|
senderInfo: { senderName: "mistral" },
|
|
steps: [{ content: [{ text: "Once" }] }, { content: [{ text: "upon" }] }],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
}).messages,
|
|
).toEqual([
|
|
{ role: "system", model: "erebus", content: "You are a storyteller.", type: "text" },
|
|
{ role: "user", model: undefined, content: "Hi", type: "text" },
|
|
{ role: "assistant", model: "mistral", content: "Once\n\nupon", type: "text" },
|
|
]);
|
|
expect(
|
|
parseConversation([
|
|
{ role: "user", metadata: {}, parts: [{ type: "text", text: "Bonjour" }] },
|
|
{
|
|
role: "assistant",
|
|
metadata: { model: { id: "gpt" } },
|
|
parts: [
|
|
{ type: "step-start" },
|
|
{ type: "text", text: JSON.stringify({ aiMessagesArrayToUser: ["Bienvenue", "Ici"] }) },
|
|
],
|
|
},
|
|
]).messages,
|
|
).toEqual([
|
|
{ role: "user", model: "unknown", content: "Bonjour", type: "text" },
|
|
{ role: "assistant", model: "gpt", content: "Bienvenue\n\nIci", type: "text" },
|
|
]);
|
|
});
|
|
});
|