1.0.0 — Extracted into a package of its own
The first release of @bayudwiyansatria/core. The kernel that lived inside an application as src/core/system/ is now
a package, so every service that wants this architecture shares one copy rather than forking it.
The extraction was anticipated. That directory's own module documentation said it was "meant to be liftable into a package the other services can share", and an ESLint boundary rule had been enforcing the constraint. It held: across all 45 files, the only import pointing outward was the one documented exception.
This repository previously held the Node.js library template. Its scaffolding was replaced with the newer generation —
flat ESLint config, four Rollup outputs with an exports map, the TypeDoc gate — and its placeholder source removed.
What this package provides
| Category | Exports |
|---|---|
| Contracts | Service, APIResponse |
| Capabilities | Capability, the ten interfaces over it, RequestMetadata, their shapes, the Noop* four |
| Configuration | configure, resolve, systemDefaults, the settings shapes |
| Observability | Logger, LogContext |
| Security | timingSafeEqual |
| Errors | MissingCapabilityError, ConfigurationError |
| Utilities | Signature, Text, Time |
42 names in all, from a single entry point. The exports map exposes . and ./package.json and nothing else, so
there are no deep import paths to depend on — src/ may be rearranged in a patch release without it being a breaking
change.
What changed in the move
configure() replaces the import of src/config/
resolve() used to import the application's configuration directly. That is fine inside one repository and impossible
across a package boundary — a package cannot reach into its consumer's source tree.
The application now assembles the surface and hands it over:
configure({ ...systemDefaults, ...platformDefaults }, overrides)
The merge semantics carry over exactly: per field rather than per module, and an override set explicitly to undefined
is ignored.
ConfigurationError is new
resolve() throws it for a module registered nowhere, and the message names both ways that happens: configure() has
not run yet, or two copies of this package are loaded. The second is the nastier one — the registry is module state, so
a duplicate copy means one registry gets seeded and another gets read — and nothing about the stack trace would
otherwise suggest a packaging problem.
Returning undefined instead would push the fault downstream to whichever binding first dereferenced the settings,
where the message would name the cache rather than the actual cause.
Logger.fromEnv no longer names a platform
It took Env, an ambient global from the runtime it was written for. It now takes
{ LOG_LEVEL?: string } | null | undefined, which is all it ever needed — and which an environment object, a
process.env, or a bare object literal all satisfy. This was the only real reference to a platform type in the whole
kernel; every other match was prose in a doc comment.
Signature derives its key type from the runtime
CryptoKey is only an ambient global when a runtime-specific lib (DOM, WebWorker) is in scope, and this package
deliberately compiles with neither so anything runtime-specific fails the build. WebCrypto itself is part of the minimum
API every target runtime provides, so the value is always there — only the type name is not. The alias is derived from
crypto.subtle and never reaches the public surface.
systemDefaults.logging.service
Was the name of the application this came from, now 'app'. An application-specific value had no business being a
library default; the placeholder is deliberately generic so an un-overridden deployment reads as unconfigured rather
than as some other project.
Kernel purity
An ESLint rule now forbids importing @cloudflare/*, hono, or cloudflare:* anywhere in src/. The boundary that
made this extraction possible is worth keeping enforced now that the code has somewhere to be extracted to.
Tests
85 specs: the configure/resolve merge contract including both ConfigurationError paths, timingSafeEqual over the
cases an early return would get wrong, Signature sign/verify with a case per forgeable input, Logger threshold and
context handling, Service envelopes, the four Noop* capabilities, and MissingCapabilityError including the
cross-package instanceof a subclass depends on.
Upgrading
Nothing to upgrade — this is the first release. A service moving off a vendored src/core/ should follow the migration
guide published by its adapter package.