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.
100 lines
3.7 KiB
JavaScript
100 lines
3.7 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.safeToString = exports.objectToString = void 0;
|
|
exports.createPromiseCallback = createPromiseCallback;
|
|
exports.inOperator = inOperator;
|
|
/** Wrapped `Object.prototype.toString`, so that you don't need to remember to use `.call()`. */
|
|
const objectToString = (obj) => Object.prototype.toString.call(obj);
|
|
exports.objectToString = objectToString;
|
|
/**
|
|
* Converts an array to string, safely handling symbols, null prototype objects, and recursive arrays.
|
|
*/
|
|
const safeArrayToString = (arr, seenArrays) => {
|
|
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString#description
|
|
if (typeof arr.join !== 'function')
|
|
return (0, exports.objectToString)(arr);
|
|
seenArrays.add(arr);
|
|
const mapped = arr.map((val) => val === null || val === undefined || seenArrays.has(val)
|
|
? ''
|
|
: safeToStringImpl(val, seenArrays));
|
|
return mapped.join();
|
|
};
|
|
const safeToStringImpl = (val, seenArrays = new WeakSet()) => {
|
|
// Using .toString() fails for null/undefined and implicit conversion (val + "") fails for symbols
|
|
// and objects with null prototype
|
|
if (typeof val !== 'object' || val === null) {
|
|
return String(val);
|
|
}
|
|
else if (typeof val.toString === 'function') {
|
|
return Array.isArray(val)
|
|
? // Arrays have a weird custom toString that we need to replicate
|
|
safeArrayToString(val, seenArrays)
|
|
: // eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
String(val);
|
|
}
|
|
else {
|
|
// This case should just be objects with null prototype, so we can just use Object#toString
|
|
return (0, exports.objectToString)(val);
|
|
}
|
|
};
|
|
/** Safely converts any value to string, using the value's own `toString` when available. */
|
|
const safeToString = (val) => safeToStringImpl(val);
|
|
exports.safeToString = safeToString;
|
|
/** Converts a callback into a utility object where either a callback or a promise can be used. */
|
|
function createPromiseCallback(cb) {
|
|
let callback;
|
|
let resolve;
|
|
let reject;
|
|
const promise = new Promise((_resolve, _reject) => {
|
|
resolve = _resolve;
|
|
reject = _reject;
|
|
});
|
|
if (typeof cb === 'function') {
|
|
callback = (err, result) => {
|
|
try {
|
|
if (err)
|
|
cb(err);
|
|
// If `err` is null, we know `result` must be `T`
|
|
// The assertion isn't *strictly* correct, as `T` could be nullish, but, ehh, good enough...
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
else
|
|
cb(null, result);
|
|
}
|
|
catch (e) {
|
|
reject(e instanceof Error ? e : new Error());
|
|
}
|
|
};
|
|
}
|
|
else {
|
|
callback = (err, result) => {
|
|
try {
|
|
// If `err` is null, we know `result` must be `T`
|
|
// The assertion isn't *strictly* correct, as `T` could be nullish, but, ehh, good enough...
|
|
if (err)
|
|
reject(err);
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
else
|
|
resolve(result);
|
|
}
|
|
catch (e) {
|
|
reject(e instanceof Error ? e : new Error());
|
|
}
|
|
};
|
|
}
|
|
return {
|
|
promise,
|
|
callback,
|
|
resolve: (value) => {
|
|
callback(null, value);
|
|
return promise;
|
|
},
|
|
reject: (error) => {
|
|
callback(error);
|
|
return promise;
|
|
},
|
|
};
|
|
}
|
|
function inOperator(k, o) {
|
|
return k in o;
|
|
}
|