feat: Phase 1 — extract the client (web SPA + desktop) to dtoro/oikos-web
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled

Problem: the hexagonal refactor churns the backend tree for nine more
phases; the UI delivery stack (web/ SPA, cmd/desktop Wails wrapper,
compose/web image) must move to its own repo first so doc/layout
rewrites land once on a backend-only tree.

Change:
- New repo git.hubris.network/dtoro/oikos-web (v0.33.0): web/, desktop/
  (updateURL repointed to oikos-web releases), compose/, own CI (web +
  desktop jobs), own deploy script (CI-green gate, TOCTOU guard,
  version-tagged images, prune-to-3), own webhook receiver on :9798 +
  launchd unit, own compose project publishing the same 8091:80.
- Cutover executed on mac-mini in order: oikos stack's web service
  stopped+removed, oikos-web project brought up on 8091; outer Caddy
  untouched (targets the published port) — serving + Authentik flow +
  /wails 404 quirk verified post-cutover.
- Stripped from oikos: web/, cmd/desktop/, compose/web/, desktop CI
  workflow, ci.yml web job, Makefile ui/desktop/desktop-package/install
  targets, the compose web service, oikos-web from deploy.sh's fallback
  prune list; wails + go-keyring dropped from go.mod, vendor synced.
- README / CONTRIBUTING / AGENTS.md / .agents dev+operations docs now
  point at the new repo; mbse + mascot design docs carry a path note.

Risk: production SPA serving depends on the new pipeline now; rollback
is versioned-image re-up of the old web service from a pre-split
checkout (port 8091). Desktop builds installed before the split still
check dtoro/oikos releases — one manual reinstall, noted in the
oikos-web release notes.

Verification: go vet, make test (race), make generate-check, golangci
(no new findings; baseline down 400→365); post-cutover curls —
localhost:8091 200, /wails/runtime.js 404, outer Caddy 302 Authentik.
This commit is contained in:
2026-08-15 22:27:52 +02:00
parent e074f04bdf
commit d4d99a7473
18854 changed files with 2615729 additions and 173735 deletions

View File

@@ -0,0 +1,19 @@
import { Attributes } from "graphology-types";
import { NodeHoverDrawingFunction, NodeLabelDrawingFunction, NodeProgramType } from "sigma/rendering";
import { TextureManagerOptions } from "./texture.js";
interface CreateNodeImageProgramOptions<N extends Attributes = Attributes, E extends Attributes = Attributes, G extends Attributes = Attributes> extends TextureManagerOptions {
drawingMode: "background" | "color";
keepWithinCircle: boolean;
drawLabel: NodeLabelDrawingFunction<N, E, G> | undefined;
drawHover: NodeHoverDrawingFunction<N, E, G> | undefined;
padding: number;
colorAttribute: string;
imageAttribute: string;
}
/**
* To share the texture between the program instances of the graph and the
* hovered nodes (to prevent some flickering, mostly), this program must be
* "built" for each sigma instance:
*/
export default function createNodeImageProgram<N extends Attributes = Attributes, E extends Attributes = Attributes, G extends Attributes = Attributes>(options?: Partial<CreateNodeImageProgramOptions<N, E, G>>): NodeProgramType<N, E, G>;
export {};

View File

@@ -0,0 +1,4 @@
import { NodeProgramType } from "sigma/rendering";
export { default as createNodeImageProgram } from "./factory.js";
export declare const NodeImageProgram: NodeProgramType;
export declare const NodePictogramProgram: NodeProgramType;

View File

@@ -0,0 +1,135 @@
import { EventEmitter } from "events";
import { Coordinates } from "sigma/types";
/**
* Useful types:
* *************
*/
export type TextureCursor = Coordinates & {
rowHeight: number;
maxRowWidth: number;
};
export type ImageLoading = {
status: "loading";
};
export type ImageError = {
status: "error";
};
export type ImageReady = {
status: "ready";
image: HTMLImageElement;
sourceX: number;
sourceY: number;
sourceSize: number;
destinationSize: number;
textureIndex?: number;
};
export type ImageType = ImageLoading | ImageError | ImageReady;
export type Atlas = Record<string, Coordinates & {
size: number;
textureIndex?: number;
}>;
export type TextureManagerOptions = {
size: {
mode: "auto";
} | {
mode: "max";
value: number;
} | {
mode: "force";
value: number;
};
objectFit: "contain" | "cover" | "fill";
correctCentering: boolean;
maxTextureSize: number;
debounceTimeout: number | null;
crossOrigin: CrossOrigin | null;
};
type CrossOrigin = "anonymous" | "use-credentials";
export declare const DEFAULT_TEXTURE_MANAGER_OPTIONS: TextureManagerOptions;
export declare const MARGIN_IN_TEXTURE = 1;
/**
* Helpers:
* ********
*/
/**
* This helper loads an image at a given URL, and returns an HTMLImageElement
* with it displayed once it's properly loaded, within a promise.
*/
export declare function loadRasterImage(imageSource: string, { crossOrigin }?: {
crossOrigin?: CrossOrigin;
}): Promise<HTMLImageElement>;
/**
* This helper loads an SVG image at a given URL, adjusts its size to a given
* size, and returns an HTMLImageElement with it displayed once it's properly
* loaded, within a promise.
*/
export declare function loadSVGImage(imageSource: string, { size, crossOrigin }?: {
size?: number;
crossOrigin?: CrossOrigin;
}): Promise<HTMLImageElement>;
/**
* This helper loads an image using the proper function.
*/
export declare function loadImage(imageSource: string, { size, crossOrigin }?: {
size?: number;
crossOrigin?: CrossOrigin;
}): Promise<HTMLImageElement>;
/**
* This helper computes exact coordinates to draw an image onto a texture.
*/
export declare function refineImage(image: HTMLImageElement, corrector: PictogramCenteringCorrector, { objectFit, size, correctCentering }: TextureManagerOptions): Omit<ImageReady, "status" | "image" | "textureIndex">;
/**
* This helper takes an array of ready-to-draw images, and draws as much as possible in a single texture.
* It then returns the atlas of the draw images, as well as the texture itself.
*/
export declare function drawTexture(images: (Omit<ImageReady, "status"> & {
key: string;
})[], ctx: CanvasRenderingContext2D, cursor: TextureCursor): {
atlas: Atlas;
texture: ImageData;
cursor: TextureCursor;
};
/**
* This helper takes a collection of image states and a context, draw all the
* images in the context, and returns an atlas to get where each image is drawn
* on the texture.
*/
export declare function drawTextures({ atlas: prevAtlas, textures: prevTextures, cursor: prevCursor, }: {
atlas: Atlas;
textures: ImageData[];
cursor: TextureCursor;
}, images: Record<string, ImageType>, ctx: CanvasRenderingContext2D): {
atlas: Atlas;
textures: ImageData[];
cursor: TextureCursor;
};
/**
* This class helps to "correct" the centering of an SVG pictogram by finding
* the "true" visually correct center through the barycenter of the pictogram's
* alpha layer in x and y dimension.
*/
export declare class PictogramCenteringCorrector {
canvas: HTMLCanvasElement;
context: CanvasRenderingContext2D;
constructor();
getCorrectionOffset(image: HTMLImageElement, size: number): Coordinates;
}
export declare class TextureManager extends EventEmitter {
static NEW_TEXTURE_EVENT: string;
private options;
private canvas;
private ctx;
private frameId?;
private corrector;
private imageStates;
private textures;
private lastTextureCursor;
private atlas;
constructor(options?: Partial<TextureManagerOptions>);
private scheduleGenerateTexture;
private generateTextures;
registerImage(source: string): Promise<void>;
getAtlas(): Atlas;
getTextures(): ImageData[];
}
export {};

View File

@@ -0,0 +1,2 @@
export * from "./declarations/src/index.js";
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbWEtbm9kZS1pbWFnZS5janMuZC5tdHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuL2RlY2xhcmF0aW9ucy9zcmMvaW5kZXguZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSJ9

View File

@@ -0,0 +1,2 @@
export * from "./declarations/src/index.js";
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbWEtbm9kZS1pbWFnZS5janMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4vZGVjbGFyYXRpb25zL3NyYy9pbmRleC5kLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBIn0=

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
'use strict';
if (process.env.NODE_ENV === "production") {
module.exports = require("./sigma-node-image.cjs.prod.js");
} else {
module.exports = require("./sigma-node-image.cjs.dev.js");
}

View File

@@ -0,0 +1,5 @@
export {
NodeImageProgram,
NodePictogramProgram,
createNodeImageProgram
} from "./sigma-node-image.cjs.js";

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff