@funeste38/freeland
v0.2.2
Published
Typed normalization hub for heterogeneous values across prefixes, files, runtimes and platforms (json:, b64:, file:, exe:, zip:, nez:, ...).
Maintainers
Readme
freeland
Freeland is the neutral normalization layer of the Funesterie ecosystem.
v1 was a prefix decoder.
v2 keeps that compatibility, but upgrades Freeland into a typed hub:
heterogeneous input -> Freeland parse -> typed canonical object -> runtime adaptationThat means Freeland can now be the place where text, JSON, files, images, executables, archives, URLs and secrets all pass through the same language before they hit A11, Qflush, Spyder or deployment runtimes.
Install
npm install @funeste38/freelandThe unscoped freeland package is deprecated. Use the scoped package directly.
Legacy v1 API
The original API still works:
import { registerSystem, decodeSystemValue } from "@funeste38/freeland";
registerSystem("upper:", (raw) => raw.toUpperCase());
const shout = await decodeSystemValue("upper:funesterie");Built-in legacy prefixes:
json:b64:/base64:file:nez:
Typed v2 API
The new API resolves an input into a canonical object:
import { resolveFreelandValue } from "@funeste38/freeland";
const value = await resolveFreelandValue("b64:SGVsbG8=");Example result:
{
"kind": "text",
"format": "base64",
"encoding": "utf8",
"value": "Hello",
"state": "compatible",
"runtime": "node",
"platform": "linux"
}Main exported concepts
resolveFreelandValue(input, options)adaptFreelandValue(value, runtime)registerFormat(prefix, handler)registerAdapter(runtime, adapter)parseFreelandInput(input)toFreelandCube(value, runtime?)
Canonical value shape
type FreelandValue = {
kind:
| "text"
| "json"
| "binary"
| "image"
| "audio"
| "executable"
| "archive"
| "path"
| "url"
| "secret"
| "identifier"
| "unknown";
format?: string;
platform?: "windows" | "linux" | "mac" | "any";
runtime?: "windows" | "linux" | "mac" | "docker" | "railway" | "local" | "browser" | "node" | "any";
mime?: string;
encoding?: string;
value: unknown;
state?: "raw" | "decoded" | "normalized" | "resolved" | "compatible" | "incompatible";
meta?: Record<string, unknown>;
};Composition
Freeland supports nested prefixes:
b64:file:./hello.b64.txt
exe:json:{"windows":"path:./bin/piper.exe","linux":"path:./bin/piper"}
zip:file:./artifacts/release.zip
manifest:json:{"kind":"executable","variants":{"windows":"path:./bin/piper.exe","linux":"path:./bin/piper"}}Resolution happens from inside to outside:
file:first- then
b64: - then runtime adaptation if requested
Built-in format families
- text:
text: - structured:
json: - binary:
b64:,base64:,hex:,bin: - filesystem:
file:,path: - identity/transport:
url:,id:,secret:,nez: - assets:
img:,image:,audio: - containers:
zip:,tar:,archive: - runtime artifacts:
exe:
Runtime-aware executables
Freeland now has a first-class way to describe executables by target:
const ffmpeg = await resolveFreelandValue(
'exe:json:{"windows":"path:./bin/ffmpeg.exe","linux":"path:./bin/ffmpeg","default":"path:./bin/ffmpeg"}',
{ runtime: "railway" }
);Freeland will:
- pick the best variant for the runtime/platform
- mark the result
compatibleorincompatible - refuse browser execution targets for native executables
Manifests
Freeland now supports lightweight manifests for runtime-aware resources:
const runtimeTool = await resolveFreelandValue(
'manifest:json:{"kind":"executable","variants":{"windows":"path:./bin/piper.exe","linux":"path:./bin/piper"},"meta":{"name":"piper"}}',
{ runtime: "railway" }
);This is the cleanest way to describe:
- runtime-specific executables
- portable bundles
- future image/audio/archive variants
- metadata-rich resources without inventing more one-off prefixes
Zip and archive support
Yes: archives should be first-class.
Freeland should not treat zip as "just another string prefix". It should treat it as a container family:
zip:for zip-specific taggingarchive:as the neutral umbrella kind- later: optional unpack/list/inspect adapters without bloating the core
That gives you room for:
- release bundles
- embedded assets
- portable module packs
- hand-off between local, CI and Railway
RGBA / Rubik / Morphing
My recommendation:
- keep
freelandas the typed normalization core - keep
morphingas the low-level 4-byte transport primitive - keep RGBA / Rubik visualization as a separate layer above the core
In practice:
freelandanswers: "what is this value?"morphinganswers: "how do I pack or move this compactly?"freeland-brosor another addon can answer: "how do I visualize or solve compatibility as RGBA / cube rotations?"
That is why v2 exports toFreelandCube() already: it gives you a stable bridge toward the Rubik/RGBA idea without forcing the core to depend on image semantics too early.
CLI
Freeland now ships a real CLI:
freeland --pretty "b64:SGVsbG8="
freeland --runtime railway --pretty "exe:json:{\"windows\":\"path:./bin/piper.exe\",\"linux\":\"path:./bin/piper\"}"
freeland --legacy "file:./.env"Suggestions for the next step
The best next upgrade is not "more prefixes". It is:
freeland-corefreeland-adaptersfreeland-bros
Concretely:
- Keep
freelandsmall, typed and deterministic. - Put heavy or optional adapters behind opt-in packages.
- Build RGBA / cube solving on top of the canonical object, not inside the parser.
Development
npm install
npm run build
npm testLicense
MIT
