chore(release): version packages - #3
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or setup this action to publish automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@bedrock-core/db@0.1.0
Minor Changes
#2
d75b88eThanks @drav0011! - Add@bedrock-core/db: typed documents persisted on whatever dynamic properties a target canhold.
The host resolver probes a target for where its documents can live — its own dynamic
properties through the engine's six-method or component ABI, or a world property keyed by its
identity when it holds nothing — behind one adapter over both ABIs, with a capability record per
host, refusals by name for an
ItemStackand a stackable slot, and a per-type cache that nevercaches a throw.
Collections key documents by target on the host the resolver finds. One JSON envelope per
document carries its version; migrations run lazily per document;
defaultsfill deep on read anda
normalizeruns on every write;patchmerges plain objects recursively and replaces arrays andscalars, with
undefineddeleting a key. A document that cannot be read is quarantined under<key>#badrather than deleted. A budget check runs before the engine, with chunking on the directABI,
acceptandrequireare checked at compile time against what the target type can do, and avalidity gate re-resolves the target on every operation.
The chunked index has a resumable
all()that heals a replaced block, ablockCleanupcustomcomponent for
onBreak, andcoalescewrite-behind that parks onentityLoadand flushes onplayerLeave— wired to the engine only when a coalescing collection exists.A collection is local. Nothing here is reachable from another realm: what crosses is what the
owning addon puts on one of the runtime's channels.
Tuned for the engine throughout: hosts, resolutions, document stores and handles are classes with
prototype methods, a handle resolves its target once per tick, the resolver trusts a cached type
decision, index chunks are written behind, and a single value skips the batch write.
Patch Changes
d75b88e]:@bedrock-core/i18n@0.2.0
Minor Changes
#2
d75b88eThanks @drav0011! - A library's strings can be overridden by the world it runs in.A library that draws UI ships its own bundle, keyed under a namespace it shares with the rest of
its family. A running realm has more than that: every addon present has announced a bundle, and
one of them may carry the very same key — deliberately, to rename what the library calls something
("Addons" becomes "Mods"), or simply because it ships a locale the library does not.
overlay(bound, published, bundle)is that precedence, as verbs.t()prefers the published valuewherever it carries the key, so an override and an unshipped locale reach the strings a script
renders rather than only the keys a client paints.
resolve()anddisplay()become the world's,so a key from any addon's bundle resolves — which is what a screen showing another addon's display
fields needs.
A realm with no published bundles gets the bound instance back untouched and allocates nothing.
@bedrock-core/observable@0.1.0
Minor Changes
d75b88eThanks @drav0011! - Add@bedrock-core/observable, the reactive primitive the stack notifies through:observablewith
get/set/subscribe,computed,effectandbatch, delivering synchronously withlisteners isolated from each other.
last(signal)turns anything withsubscribe— a Minecraft eventsignal included — into an observable of its most recent payload,
undefineduntil the first onearrives, released with
dispose(). The/minecraftentry bridges one of ours to a data-driven UIobservable with
toNative, keeping the native in step for a form's lifetime and writing back onlywhen the control is client-writable.
@bedrock-core/server-runtime@0.2.0
Minor Changes
#2
d75b88eThanks @drav0011! - Who is present is a value, not a stream: discovery, the registry and the host election areobservables.
Breaking.
discovery.peersanddiscovery.incompatiblePeersareReadonlyObservablelistsrather than array getters, so they read
.get(), watch with.subscribe(), and compose withcomputed()like a config leaf or a shared value:The lists republish only when the world actually changes. A heartbeat that repeats what a peer
already said refreshes its liveness and notifies nobody, which is what lets a listener sit on the
list without waking every five seconds per peer.
lastSeentherefore leftPeerInfoandIncompatiblePeer— a tick that moves on every heartbeat cannot live inside an observable value —and is asked for by id instead:
onPeerUp/onPeerDown/onRegister/onUnregisterstay: an arrival is a delta, and acaller that wants the one peer that changed still wants an event. A TTL sweep publishes the list
once for the whole sweep, before any listener runs, so a handler never sees a half-swept world.
Registrykeeps no directory of its own —all(),get()andhas()readaddons, so a cachedanswer can no longer disagree with the live one — and
HostElectioniscomputedover that list,which retires its
start().core.host.hostIdis nowcore.host.id, an observable;HostListenertakes a
previousHostId: string, since a derived value always has one.#2
d75b88eThanks @drav0011! - Breaking. Guides left the runtime: theguideandguideReferenceoptions ofregister(),core.guides,core.guides.manifest,GuidesRegistry,GuideReferenceandGuideManifestare removed. A guide is a set of compiled screens from@bedrock-core/guides, reached by navigating to its key, and the screens an addon publishes are read throughscreens(core)from@bedrock-core/navigation.#2
d75b88eThanks @drav0011! - Everything an addon owns is declared inregister(), and everything that crosses a realm goes overone of three channels.
Breaking.
register()installs declarations, not plain objects:shared: registerShared(keys),events: registerEvents(tree), and one field per app, such asconfig: registerConfig(definition)from
@bedrock-core/config. Config and guides are no longer part of the runtime. They are the@bedrock-core/configand@bedrock-core/guidesapps, which keep their state in aRuntimeSlotsslot the runtime fills and hands back (
core.fill/core.slot);core.config,core.guidesandcore.pagesare gone.core.shared— a flatsharedshape comes back as a typed tree, one observable per key withget/set/subscribeand the usual(next, prev)listener. Peers readcore.shared.of<Def>(ns), materialized from the key names the owner announces undercore-shared/shape, and never write: a peer's tree has noset, in the type and at runtime. Thebackend subscription is attached with the first listener and released with the last. The mirror
stores nothing — a value that must survive a restart is a db document the owner maps onto a key.
core.events— aneventsshape comes back as a typed tree withemitandsubscribe, thepayload type declared by
event<T>(). A peer readscore.events.of<Def>(ns), which hassubscribealone and answers before the owning addon exists, so a listener attached early hearsthe first event announced. Nothing is replayed.
core.rpc— a question the owner answers.authorize(target, actorId, operation)is the onerule such a handler applies: an operator reaches anything, anyone else only their own entity, and a
request with no acting player is an addon acting for itself.
core.dbis this addon's@bedrock-core/db, keyed under its namespace, with the declarationAPI (
schema, the acceptors and combinators, the errors) re-exported so a collection is declaredfrom the runtime import alone. It is local: a peer reaches a document only through a method the
owner wrote.
Every cross-addon feed is an
Announcement— one value under acore-key in the owner'snamespace, with
provide/own/of(ns)/namespaces/subscribeand a guard on read.core.translationsis one over the bundle, its verbs ati18n(ns);core.features.flagsannounces every flag as one record under
core-feature/flags; the shared shape sits atcore.shared.shape.provideManifest,provideReference,referenceOf,bundleOf,addonsWithGuidesandhasare gone with it.The package exports what an addon writes against. Registries are exported as types — the
runtime constructs them — and the schema, document and wire helpers (
flattenSchema,defaultsOf,normalizeAgainst,coerce,CONFIG_COLLECTIONS,configMethod,SHARED_SHAPE_KEY,validateManifest,addonNamespace,compareVersions,PROTOCOL_MIN/PROTOCOL_MAX) are no longer exported.core.stateandScopedStateare removed. A shared key covers every call they had; the rawnamespace, framework keys included, stays reachable at
core.node.state.#2
d75b88eThanks @drav0011! - Breaking. A node writes one namespace, the one named by its id.ownedNamespacesandstrictOwnershipare removed fromcreateSync/SyncNode, andStateOptionsfrom the exports: every mirror only ever applied a namespace's writes from the node whose id it is, so the options could not widen that. A write to another node's namespace is dropped by every mirror and counted indroppedForeign, and a node answers snapshot requests for its own namespace.#2
d75b88eThanks @drav0011! - Rework the script-event wire format, and negotiate the protocol per peer instead of demanding amatch.
A message now opens with a tag saying which shape follows: one envelope, a batch of envelopes, or
one frame of a chunked envelope. An envelope that fits in a message is sent whole instead of nested
inside a frame's
pfield, so it is no longer JSON-escaped to sit inside a JSON string — a smallmessage loses about a third of its length, and a round trip costs roughly half the CPU.
The outbound queue packs consecutive envelopes into one message up to the size cap. The engine
bounds script events per tick by count rather than by size, so a node that sends a burst in a single
tick — a run of
State.setcalls, a snapshot broadcast, an RPC fan-out — now spends a few of itsper-tick slots instead of one per envelope. Each addon has its own queue, so this packs one node's
own traffic and never several nodes' together.
Framing charges each character what JSON actually spends escaping it, rather than reserving two
characters for every one. Real payloads fill a frame instead of half of it: a 16KB envelope splits
into 10 frames where it previously took 18.
PROTOCOL_VERSIONis replaced byPROTOCOL_MINandPROTOCOL_MAX. A node advertises therange it speaks in every announce and talks to each peer at the newest version both know, so a
world may hold addons built against different releases without partitioning. Gating on one exact
version would have made this bump — and every later one — a silent split: two meshes on a single
channel, each listing only its own half, each electing its own UI host, each timing out every RPC
to the other.
Consequently:
whoisarepinned to
PROTOCOL_MINso the message that establishes a version never assumes one.that predates the batch tag is present. Both recover on their own once that peer expires.
PeerInfogainsprotocolandcaps. Capabilities are advertised per node and narrowed by thenegotiated version, so a later addition can appear or degrade without a version bump.
Discovery.onIncompatible/Registry.onIncompatibleand listed byRegistry.incompatible(),with a warning naming both ranges. It is named rather than silently absent.
negotiateProtocolandcapsForare exported for anyone writing an interoperatingimplementation.
The support window is two versions wide. Raising
PROTOCOL_MINdrops everything below it and is abreaking change.
MAX_MESSAGE, the default per-message character budget, is now exported alongside the existingBusOptions.maxMessageoverride.Patch Changes
d75b88e,d75b88e,d75b88e,d75b88e,d75b88e,d75b88e,d75b88e]:@bedrock-core/sync@0.2.0
Minor Changes
#2
d75b88eThanks @drav0011! - Who is present is a value, not a stream: discovery, the registry and the host election areobservables.
Breaking.
discovery.peersanddiscovery.incompatiblePeersareReadonlyObservablelistsrather than array getters, so they read
.get(), watch with.subscribe(), and compose withcomputed()like a config leaf or a shared value:The lists republish only when the world actually changes. A heartbeat that repeats what a peer
already said refreshes its liveness and notifies nobody, which is what lets a listener sit on the
list without waking every five seconds per peer.
lastSeentherefore leftPeerInfoandIncompatiblePeer— a tick that moves on every heartbeat cannot live inside an observable value —and is asked for by id instead:
onPeerUp/onPeerDown/onRegister/onUnregisterstay: an arrival is a delta, and acaller that wants the one peer that changed still wants an event. A TTL sweep publishes the list
once for the whole sweep, before any listener runs, so a handler never sees a half-swept world.
Registrykeeps no directory of its own —all(),get()andhas()readaddons, so a cachedanswer can no longer disagree with the live one — and
HostElectioniscomputedover that list,which retires its
start().core.host.hostIdis nowcore.host.id, an observable;HostListenertakes a
previousHostId: string, since a derived value always has one.#2
d75b88eThanks @drav0011! - Breaking. A node writes one namespace, the one named by its id.ownedNamespacesandstrictOwnershipare removed fromcreateSync/SyncNode, andStateOptionsfrom the exports: every mirror only ever applied a namespace's writes from the node whose id it is, so the options could not widen that. A write to another node's namespace is dropped by every mirror and counted indroppedForeign, and a node answers snapshot requests for its own namespace.#2
d75b88eThanks @drav0011! - Owner-only state. A mirror applies an entry for a namespace only from the namespace's owner —the sending node for a delta, the recorded writer for a snapshot entry, so a snapshot relayed by a
third party still names the original writer. Anything else is dropped and counted in
droppedForeign. The rule holds for a node's own writes too, so a foreign write is visible locallyexactly when it is visible everywhere, which is never.
Events, the subsystem for a happening.node.events.emit(name, payload)broadcasts onemessage;
on(namespace, name, handler)subscribes to one sender's name. The namespace a handlermatches is the envelope's
src, read from the transport rather than the payload, so a messagecannot claim to come from a node that did not send it. The sender dispatches to its own handlers
first, synchronously, before the message leaves; a handler that throws is caught and the others
still run. Nothing is stored and nothing is replayed.
#2
d75b88eThanks @drav0011! - Rework the script-event wire format, and negotiate the protocol per peer instead of demanding amatch.
A message now opens with a tag saying which shape follows: one envelope, a batch of envelopes, or
one frame of a chunked envelope. An envelope that fits in a message is sent whole instead of nested
inside a frame's
pfield, so it is no longer JSON-escaped to sit inside a JSON string — a smallmessage loses about a third of its length, and a round trip costs roughly half the CPU.
The outbound queue packs consecutive envelopes into one message up to the size cap. The engine
bounds script events per tick by count rather than by size, so a node that sends a burst in a single
tick — a run of
State.setcalls, a snapshot broadcast, an RPC fan-out — now spends a few of itsper-tick slots instead of one per envelope. Each addon has its own queue, so this packs one node's
own traffic and never several nodes' together.
Framing charges each character what JSON actually spends escaping it, rather than reserving two
characters for every one. Real payloads fill a frame instead of half of it: a 16KB envelope splits
into 10 frames where it previously took 18.
PROTOCOL_VERSIONis replaced byPROTOCOL_MINandPROTOCOL_MAX. A node advertises therange it speaks in every announce and talks to each peer at the newest version both know, so a
world may hold addons built against different releases without partitioning. Gating on one exact
version would have made this bump — and every later one — a silent split: two meshes on a single
channel, each listing only its own half, each electing its own UI host, each timing out every RPC
to the other.
Consequently:
whoisarepinned to
PROTOCOL_MINso the message that establishes a version never assumes one.that predates the batch tag is present. Both recover on their own once that peer expires.
PeerInfogainsprotocolandcaps. Capabilities are advertised per node and narrowed by thenegotiated version, so a later addition can appear or degrade without a version bump.
Discovery.onIncompatible/Registry.onIncompatibleand listed byRegistry.incompatible(),with a warning naming both ranges. It is named rather than silently absent.
negotiateProtocolandcapsForare exported for anyone writing an interoperatingimplementation.
The support window is two versions wide. Raising
PROTOCOL_MINdrops everything below it and is abreaking change.
MAX_MESSAGE, the default per-message character budget, is now exported alongside the existingBusOptions.maxMessageoverride.Patch Changes
d75b88e]: