SDK surface
@meridian/shared (libs/shared/package.json) is the one package a plugin compiles
against. It is browser-safe: no filesystem access, no host internals, no dependency on
apps/api. A plugin's runtime code imports it as import type wherever possible, so the
import is erased at compile/bundle time — see
Bundling and distribution.
This page is the exhaustive map of what the package exports, file by file. It does not explain how to author a manifest, a behavior, or a workflow — see Plugin manifest, Autonomy and packaging, and the how-to guides linked from each section below.
Package identity
| Name | @meridian/shared |
| Version | version in libs/shared/package.json, released with the other @meridian/* libraries |
| Runtime dependencies | @opentelemetry/api, croner, zod |
exports (dev) |
"./*": "./src/*.ts" — every subpath resolves 1:1 to a .ts source file |
exports (publishConfig, published) |
"./*": { "types": "./dist/*.d.ts", "default": "./dist/*.js" } |
| Build | npm run build → tsc -p tsconfig.build.json (declaration, declarationMap, sourceMap, outDir: dist, rootDir: src) |
Two resolution paths coexist:
- The repository's plugins (
external-plugins/<name>/) resolve@meridian/shared/*via the path alias"@meridian/shared/*": ["../libs/shared/src/*"](external-plugins/tsconfig.json) — straight to source, no build step. - Out-of-repo plugins resolve the published npm package, whose
exportsonly take effect throughpublishConfig— a fieldpnpm publish/pnpm packapply andnpmignores. See Bundling and distribution.
PLUGIN_CONTRACT_VERSION (below) is a hand-maintained constant that is decoupled
from the @meridian/shared package version: it moves when the plugin-facing contract
does (see version), not on every library release.
Directory layout
libs/shared/src/
version.ts PLUGIN_CONTRACT_VERSION
plugin/ the plugin-authoring contract
behavior.ts
source.ts
mapping.ts
assist.ts
inbound.ts
manifest.ts
manifest-keys.ts
dependencies.ts
declared-events.ts
node-contribution.ts
agent-contribution.ts
instance.ts
i18n.ts
domain/ shared platform vocabulary
types.ts
object-types.ts
value-sets.ts
dimensions.ts
context-kinds.ts
event-types.ts
event-routing.ts
trigger-filter.ts
trigger-facts.ts
validation.ts
terminology.ts
agent-spec.ts
agent-tools.ts
memory.ts
ports.ts
workflow-spec.ts
engine/ type-system & catalog helpers
type-system.ts
conversions.ts
catalog-metadata.ts
event-contract.ts
dynamic-ports.ts
derived-ports.ts
template.ts
effects.ts
agent-tool-eligibility.ts
memory.ts
schedule.ts
observability/
trace.ts
Every file above is a real, committed source file (git ls-files libs/shared/src); there
is no generated or build-manifest step involved in producing this list.
plugin/* — the plugin-authoring contract
| Import | Exports | Purpose |
|---|---|---|
@meridian/shared/plugin/behavior |
NodeBehavior<I,O,C>, RunArgs<I,C>, Proposal<O>, NodeBehaviorFactory<I,O>, PluginNodeContext, ValidationResolution, PortSandboxFactory, WorkflowToolFactory |
The node behavior contract — what a behavior.module (and a portSandboxes module) exports. Full contract at Behavior contract. |
@meridian/shared/plugin/source |
SourceFactory, SourceFactoryOpts, SourceFeed, SourceHandle |
The event-source mechanism contract (polling). The host starts the factory for each inbound connection of the source: config holds the connection's parameters, declared defaults applied, without connection; connection the outbound connection that parameter names, else the default connection of the type; feeds one feed per binding enabled on the connection. emit resolves once the host's reception has stored the record, and rejects when it could not store it — see Contribute an event source and binding. |
@meridian/shared/plugin/connections |
AUTH_SCHEMES/AuthScheme, SCHEME_CREDENTIAL_KIND, CONNECTION_NAME, CONNECTIONS_MIN_SDK, ConnectionTypeContribSchema, ConnectionRequirementSchema, InstanceConnectionSchema, StoredConnectionConfigSchema, INBOUND_AUTH_SCHEMES, connectionIssues(), instanceAuthIssues(), paramIssues(), paramValues(), effectiveParams(), ConnectionHandle, ConnectionAccessor |
Connections: the contribution of a connection type, the requirement of an adapter, a source or a node, and the handle the host passes them (PluginNodeContext.connection, SourceFactoryOpts.connection, the second argument of an adapter factory). The handle's fetch adds the authentication, the timeout and the trace. See Connection types. |
@meridian/shared/plugin/mapping |
MapExprSchema (zod), MapExpr |
Raw-record → event field projection grammar, used by eventBindings.map. Full grammar at MapExpr. |
@meridian/shared/plugin/assist |
NodeAssist, AssistSuggestion |
Host-side configuration assistance of a node (assist in the manifest): checks beyond the schema, suggestions taken from a sample, preview. See Declared configuration and ports. |
@meridian/shared/plugin/inbound |
InboundReceiverFactory, InboundReceiverOptions (the receiver of an inbound connection type: the connection's params, encoding, onMessage, onError), InboundProtocol, InboundIdentity, INBOUND_ENCODINGS/InboundEncoding (the encodings a connection accepts), HOST_TRANSPORTS/HostTransport/isHostTransport() (http and directory, offered to every protocol), InboundTransport (a protocol's own transport as its manifest describes it: name, defaultPort?, hint?), LISTENER_PORTS (the ports a connection with a protocol transport listens on, 1024–65535), DEFAULT_MEDIA_TYPES (text/plain, application/octet-stream: the media types of an HTTP connection when the protocol declares none), InboundReceiver, ReceiverOptions, ListenerOptions, TransportFactory, ValidationProfile, ValidationReport, MessageBinding, MessageBindingContext, MessageBindingOption, InboundRejection, message encoding and bounded-reception helpers |
Protocol-owned inbound reception, safe validation reports, and raw-message projection. The host retains the inbox and generic transports. See Connect an EAI. |
@meridian/shared/plugin/manifest |
TypeRefSchema, PluginManifest (zod schema + type), ManifestShorthand, MANIFEST_SHORTHANDS (the shorthands the schema admits, by place: an agent's input/output for inputs/outputs), NodeContribution, TypeContribution, ConversionContribution, AgentContribution, AdapterContribution, ContextKindContribution, EventContribution, EventFieldContribution, EventContextContribution, PortSandboxContribution, EventSourceContribution, EventBindingContribution, MessageBindingContribution, ReceiveContribution (a pinned trigger's receive, transports normalized to InboundTransport) |
The plugin.yaml schema. Full field reference at Plugin manifest. |
@meridian/shared/plugin/manifest-keys |
StrippedKey, strippedKeys(), keyPath(), manifestKeyIssues() |
The keys of a YAML document that a schema drops. strippedKeys(written, parsed) compares the document (the parsed YAML, before the schema) with what the schema returns and lists each key absent from it at the same path, at any depth, arrays index by index; a value the schema keeps whole (z.record, z.unknown()) is open. keyPath(path, key) writes a key's path (contributes.nodes[3].config[0].option). manifestKeyIssues(document, manifest) turns the keys a plugin manifest's schema dropped into load problems of kind key (a declared shorthand that does not apply gets a message that says why), shared by the host and meridian-plugin validate/build/publish; the host also logs the keys dropped from the instance manifest with strippedKeys. See Load checks. |
@meridian/shared/plugin/dependencies |
DependencySemver, RangeKind, rangeKind(), RangeState, rangeState(), testedRange(), DependencyState, DependencyCheck, DependencyReport, dependencyIssues() |
The dependsOn ranges of a set of manifests checked against the versions found, shared by the host and meridian-plugin validate/build/deps. dependencyIssues(manifests, refused, semver) takes the manifests whose contract is accepted, those refused for their contract, and the caller's semver operations (validRange, satisfies, gtr, valid; the SDK does not depend on semver): an entry that names the plugin itself, an invalid range or a version found outside the range refuses the plugin (refused), a dependency absent or refused with a version in the range is a problem and the plugin loads; problems of kind dependency named after the dependency, in dependency order, and the state of each dependency (checks). DependencyState is ok, unconstrained (*), out-of-range, invalid-range, absent, refused or self; rangeState(range, version, semver) gives the first four, and the registry resolution uses it. testedRange(version, semver) gives ^<version>, the range a message proposes. See Load checks. |
@meridian/shared/plugin/declared-events |
DECLARED_EVENTS_MIN_SDK, EVENT_DEFAULT_SELECTOR_MIN_SDK, RECEIVE_PRESENTATION_MIN_SDK, RESERVED_EVENT_FIELDS, EVENT_TYPE_PATTERN, EVENT_FIELD_PATTERN, PluginLoadIssue, isLoadNote(), usesDeclaredEvents(), usesReceivePresentation(), dependsOnClosure(), eventDeclarationIssues(), declareEvent(), TriggerDerivation, triggerFromEvent(), strayFromIssues(), eventBindingIssues(), messageBindingIssues(), declaredEventUsageIssues(), pluginContractIssue(), sdkFloorIssue(), portDimensionIssues() |
The load checks of a plugin, shared by the host and meridian-plugin validate/build: contract (pluginContractIssue(manifest, accepts): a range that does not accept the host's contract refuses the plugin), declarations and examples, derivation of an event: trigger, dimensions of event fields and node ports resolved in the dependsOn closure (portDimensionIssues(node, closure) for the ports), bindings (declaredEventUsageIssues, once every plugin is applied), sdk floor (sdkFloorIssue(manifest, rangeCovers): 0.1.1 for declared events, 0.1.3 with an event defaultSelector, 0.1.4 when a node describes its reception, 0.1.5 for conditional port rules, 0.1.6 with connections, one problem for the highest floor). PluginLoadIssue.kind is one of contract, event, example, trigger, node, filter, binding, sdk, module, key and dependency. The registration of a manifest's events lives in @meridian/engine-core/engine/plugin-events, because the default filter is a jexl expression: registerPluginEvents sets aside a type already declared, then declarePluginEvent declares each event, refuses a type equal to a pinned address and checks the default filter. See contributes.events. |
@meridian/shared/plugin/node-contribution |
ContributedNode, contributedNodeMeta(), nodeIssues(), PinnedAddress, pinnedAddresses() |
The projection of a node contribution onto its NodeTypeMeta, shared by the host and meridian-plugin validate/build: the flat trigger keys of the manifest become receives, a node the projection refuses comes with its problems, and a node-level defaultSelector is ignored with a problem; nodeIssues gives them kind trigger on a trigger, node on another node. pinnedAddresses(manifests) lists the addresses no declared event may take, each with its triggers and their plugin: the core's pinned triggers (CORE_CATALOG_META) and the pinned triggers of the manifests whose contribution projects. See Load checks. |
@meridian/shared/plugin/agent-contribution |
agentSlug(), contributedAgentNodeId(), contributedAgent() |
The projection of an agent contribution onto its AgentDef, shared by the host and meridian-plugin validate/build: the agent's node type is agent.<slug>, and an agent that breaks the rules of AgentSpec (an empty provider or model, no input or no output) comes with its problems, of kind node, instead of a definition. See contributes.agents. |
@meridian/shared/plugin/instance |
InstanceManifest (zod schema + type), PortBinding, PluginRequirement, EMPTY_INSTANCE |
The instance manifest schema (deployment configuration, not a plugin contribution). Full field reference at Instance manifest. |
@meridian/shared/plugin/i18n |
I18nEntry, I18nBundle, PluginBundles, manifestI18nEntries(), bundleLookup(), interpolate(), resolveRuntimeKey(), localizeManifest(), receiveTransportHintPath() (the key of a transport's hint under its trigger, receive.transports.<name>.hint) |
The key-derivation walker shared by the host (resolution) and the CLI (i18n extract/i18n check) — see Translate a plugin. |
domain/* — shared platform vocabulary
| Import | Exports | Purpose |
|---|---|---|
@meridian/shared/domain/types |
PrimitiveName, TypeRef (union), t (TypeRef builder helpers), typeLabel(), ContextKey, ContextEnvelope |
The TypeRef vocabulary every port type is expressed in. Full kind-by-kind reference at TypeRef. |
@meridian/shared/domain/object-types |
FieldDescriptor, TypeDescriptor, ObjectTypeName, OBJECT_TYPES, registerType(), getType(), isObjectType() |
The open registry of object-kind types ({ kind: "object", name }). Starts empty — the core contributes no domain type; plugins populate it via registerType. |
@meridian/shared/domain/value-sets |
ValueSetConcept, ValueSetDef, VALUE_SETS, registerValueSet(), hasValueSet(), isExternalValueSet(), valueSetConcepts(), codeInValueSet(), displayOfCode(), subsumes() |
The open registry backing coded types. Starts empty; external: true value-sets are not enumerated here (resolved by a terminology port instead). |
@meridian/shared/domain/dimensions |
Dimension (string, a registered dimension name), UnitDef, DimensionDef (with its source plugin), DIMENSIONS, registerDimension(), getDimension(), dimensionOfUnit(), unitInDimension(), convertUnit(), unknownDimensionReason() |
The open registry backing quantity types (unit checking + conversion by multiplicative factor). Starts empty — the core declares no dimension; plugins contribute them via contributes.dimensions (@posos/common contributes the common physical dimensions). A registered dimension cannot be redefined by another plugin or differently. |
@meridian/shared/domain/context-kinds |
ContextKindDescriptor, CONTEXT_KINDS, registerContextKind(), getContextKind(), isContextKind(), contextIdField(), listContextKinds(), contextKindForEntity() |
The open registry of ambient-context kinds (context:/establishes: keys, ref entities, subject id fields). Starts empty — the core knows no kind; plugins contribute them via contributes.contextKinds (@posos/common contributes patient/encounter/order/document). |
@meridian/shared/domain/event-types |
EventContextKind, EventFieldDescriptor, EventTypeDescriptor, duplicateEventMessage(), registerEventType(), getEventType(), listEventTypes(), replaceEventTypes() |
The open registry of declared events (contract of each event type: context kinds, typed fields, example, default filter, declaring plugin). Starts empty; plugins contribute via contributes.events. registerEventType returns a problem instead of throwing when another plugin already declared the type. |
@meridian/shared/domain/memory |
MEMORY_SCOPES, MEMORY_TTL_DEFAULT, MemoryAddress, MemoryEntry, MemoryListing, MemoryWrite, MemoryWriteResult, MemoryStore, MemoryRef, NodeMemory, MemorySeedEntry, the zod schemas MemoryAddressSchema/MemoryWriteSchema/MemorySeedEntrySchema, workflowSlug(), memoryTypeName() |
The workflow-memory contract: the address of an item (scope, workflow, subject, key), what the store returns (value, stored type, version, provenance, expiry), the result of a write ({ written: true, entry } or { written: false, currentVersion } for a refused conditional write), and the store interface the host implements. Behaviors of plugins do not reach the memory; the core memory nodes do. See Remember values between runs. |
@meridian/shared/domain/validation |
PendingValidationRecord, ValidationClosure, ValidationClosureOutcome |
The platform human-in-the-loop concept, as a pair: the request published to a subject's record when a run suspends (runId/pendingId correlate and resume the run), and its closing when the validation ends outside the record (outcome: accepted, rejected, expired, withdrawn; by?, at, comment?). See Port contracts. |
@meridian/shared/domain/terminology |
TerminologyPort (interface), InternalTerminology, RoutingTerminology |
The terminology port and its two implementations: the in-registry resolver, and a per-value-set router over the terminology adapters contributed by plugins (used when several plugins each own a code system). |
@meridian/shared/domain/agent-spec |
LLM_PROVIDERS, DEFAULT_LLM_PROVIDER, DEFAULT_LLM_MODEL, AgentPortSchema/AgentPort, AgentSpec (zod, with legacy input/output → inputs/outputs coercion), AgentDef, coerceLegacyAgentIo(), resolveTypeName(), agentPortType(), agentPortTypeLabel(), selectableTypeNames() |
The agent specification schema (apiVersion: meridian/agent-v1) and its TypeRef resolution helpers. See Author an agent. |
@meridian/shared/domain/ports |
AgentToolHandle, AgentRunRequest, AgentRunnerPort, SubjectRecordPort, Ports (open bag, [pluginPort: string]: unknown), requirePort() |
The hexagonal port bundle a behavior reaches through ctx.ports. The SDK types only the ports the core calls (agent, terminology) plus the SubjectRecordPort platform capability; business port contracts live with their owning plugin, which augments Ports via declare module. requirePort<T>(ports, name) is the common runtime guard. Full contract at Port contracts. |
@meridian/shared/domain/agent-tools |
AgentToolResolution, AgentToolSource, ResolvedAgentTools, resolveAgentTools() |
The shared resolution loop turning an agent's tools references into invocable handles, composed from per-executor sources. |
@meridian/shared/domain/workflow-spec |
NodePosition, WorkflowNodeInstance, Connection, WorkflowSpec (zod, apiVersion: meridian/v3), parsePortRef(), withSpecReplaced(); routing: SelectorEvaluator, RouteSelection, RouteMatch, RouteHit, RouteResult, RoutedWorkflow, selectorMatches(), hasNoSelector(), routeEvent() |
The workflow DSL schema, and the routing of an event to the published workflows: routeEvent returns { hits, candidates } — every workflow whose trigger receives the type and whose filter keeps the event (or that has none), with its reason (selector, unfiltered, targeted, pinned). Full grammar at Workflow DSL. |
@meridian/shared/domain/event-routing |
IngestEventResponse<V>, DeliveredRun, DeliveryFailure, RunRouting, RecentEvent, RecentEventOutcome, RecentEventsResponse, AlsoReceivedFile, AlsoReceivedNotice, RoutingNotice, SelectorSample, PublishResponse, RollbackResponse, PublishRefusal |
Types only: the HTTP shapes of routing shared by the API and the console — the POST /api/events response, the routing fields of a run, the recent-arrivals trace, and the publication notes about other receivers. See Event ingestion API. |
@meridian/shared/domain/trigger-filter |
SelectorRole, FilterOp, FilterLiteral, FilterRow, FilterModel, EventFieldType, EventField, FILTER_OPS_BY_TYPE, isFilterPath(), quoteString(), renderLiteral(), FilterBuildError, buildSelector() |
The trigger filter (trigger.selector) helpers shared by the API and the console: the filter's role (route, filter, ignored, computed by triggerFacts), the guided model (rows of field, operator, value), the operators allowed per field type, and the JEXL it produces. |
@meridian/shared/domain/trigger-facts |
TriggerFamily, TriggerProblem, TriggerFacts, TriggerInstance, TriggerMeta, triggerFacts(), declaredEventOf(), eventConfigField(), TriggerRoute, triggerRoute(), EventClaim, eventClaims(), EventAdmission, eventAdmission(), triggerKey(), contractEstablishes(), exampleEvent() |
The only resolution of what a trigger instance receives (node type and spec.trigger.config): family, type received (for a configurable trigger, the event of its configuration field), selector role, contract read in the event registry, context established, example, default filter and problem (trigger-unknown, event-absent, event-unknown). Also the routing key of a workflow (triggerRoute), the triggers that can receive a type (eventClaims: a configurable trigger claims every declared event, with the configuration that makes it receive it), whether a type is routed to every matching workflow (eventAdmission: routable, addressed, unclaimed), the console identity of an instance (triggerKey) and the pre-filled event of a trigger (exampleEvent). Browser-safe. |
Terminology port
TerminologyPort is the one domain contract with more than a data shape: has,
validateCode, expand, display, subsumes — each implementation may answer
synchronously (InternalTerminology) or asynchronously (a terminology adapter,
reached through RoutingTerminology). A terminology server is plugged in by a plugin
that contributes a terminology adapter. See Configure terminology.
engine/* — type-system & catalog helpers
| Import | Exports | Purpose |
|---|---|---|
@meridian/shared/engine/type-system |
objectFields(), isAssignable(), validateValue(), exampleValue(), describeCatalogTypes() |
Structural connection compatibility (design-time) and value validation (runtime, port boundaries), crossing TypeRef against the OBJECT_TYPES/VALUE_SETS/DIMENSIONS registries. |
@meridian/shared/engine/event-contract |
ownValue(), OCCURRED_AT_TYPE, CONTEXT_ID_TYPE, isAbsent(), ContextIdState, contextIdState(), EventContractKey, eventContractKeys(), EventContractIssue, EventContractOptions, eventContractIssues(), invalidReason(), projectDeclaredEvent(), ResolvedTriggerOutput, contractOutputs(), contractOutputPorts() |
Conformity of a payload to a declared event (validity without conversion, required fields, context ids; messages never quote the value), the defensive projection behind the declarative trigger, and the default outputs of a trigger on a declared event: one output per field of the contract, in declaration order (contractOutputs for the projection, contractOutputPorts for the ports). |
@meridian/shared/engine/conversions |
Conversion (interface), CONVERSIONS, registerConversion(), findConversion(), listConversions() |
The From/Into conversion registry backing the transform.convert node and the editor's auto-insert. Starts empty — the core knows no conversion; plugins contribute declarative entries via contributes.conversions (JEXL over value). |
@meridian/shared/engine/catalog-metadata |
NodeKind, PortDef, ConfigFieldDef, NodeTypeMeta, TriggerReceives, CATALOG_META, CORE_CATALOG_META, triggerMetaIssues(), registerNodeMeta() |
The node-type registry (kind, ports, category). Seeded with only the core primitives (value.*, transform.*, flow.*, memory.*, the core triggers, sub-workflow and agent nodes); every domain node is registered by a plugin via registerNodeMeta. CORE_CATALOG_META is a copy of the core entries taken before any plugin registers. For a trigger, NodeTypeMeta carries receives (pinned, dedicated or configurable, see What a trigger receives); registerNodeMeta throws when triggerMetaIssues reports a problem. |
@meridian/shared/engine/effects |
effectSummary() |
The effect node types of a workflow (writes and notifications, human tasks, agent calls, sub-workflows), listed side by side for the workflows that start on the same event: publication notes, the filter panel, the assistant's digest, the routing audit. |
@meridian/shared/engine/template |
TEMPLATE_CONTEXT_ROOT, TemplatePart, ParsedTemplate, parseTemplate(), hasTemplate(), templateVariables(), templateContextKinds(), templateFields(), templateTexts() |
Templates in the text fields of a node's config ({name}, {context.patient.id}): parsing and the list of template fields; the evaluation lives in @meridian/engine-core. |
@meridian/shared/engine/dynamic-ports |
DynamicKind, templateVariables(), resolveDynamicPorts(), nodePorts(), nodeRequiredContext() |
Resolves ports from node config: core flow/transform/memory nodes, plugin nodes that declare derivedPorts, and a configurable trigger (the fields of the chosen event's contract, then done); nodeRequiredContext adds a memory node's subject kind to its catalog context. |
@meridian/shared/engine/derived-ports |
DerivedPorts, PortRule, TypeTemplate, ValueRef, resolveDerivedPorts() |
Evaluates the port rules a plugin node declares (derivedPorts): one port or one port per config list item, types read in the config, chosen by a value, or built as records; returns the ports and what could not become one. |
@meridian/shared/engine/memory |
MEMORY_DYNAMICS, isMemoryDynamic(), isConditionalWrite(), memoryConfigErrors(), memoryWriteMismatch(), memoryReadValue(), memoryValueType(), memoryTtlMs() |
The rules of the core memory nodes, shared by static validation, the editor and the node behaviors: configuration checks, the retention (30 days by default), the type check run on write, and the read of a stored value against the declared type, converted through the conversion registry when the stored type differs. |
@meridian/shared/engine/agent-tool-eligibility |
AgentToolEligibility, agentToolEligibility() |
Whether a catalog node may be exposed as a tool of an out-of-workflow agent — judged from its meta (kind, dynamic, agentTool opt-in) and the composability of its context against the context-kind registry (a kind with an idField is composable by the caller). |
@meridian/shared/engine/schedule |
ScheduleRuleSchema/ScheduleRule, ScheduleConfigSchema/ScheduleConfig, MIN_PERIOD_SECONDS, helpers |
The trigger.schedule rule grammar (cron/period) and its validation helpers. |
observability/trace
| Export | Purpose |
|---|---|
tracer |
The single OpenTelemetry tracer instance (meridian), shared by proxy, engine and plugins so spans assemble into one end-to-end trace. |
TraceCarrier |
Record<string, string> — a W3C traceparent/tracestate carrier for out-of-band propagation (e.g. a Restate invocation payload). |
withSpan() |
Runs a function inside an active span; records exceptions and sets ERROR status on throw. |
injectTraceContext() |
Captures the active trace context into a serializable carrier. |
runWithRemoteContext() |
Restores a carrier's trace context and runs a function under it. |
Depends only on @opentelemetry/api — a no-op API when no SDK is registered, so this
module costs nothing unless observability is enabled. See
Enable observability and
Observability signals.
Shared expression and configuration validation
@meridian/shared/engine/expression exports the existing JEXL evaluator
(evalExpression, compiledExpression, expressionAst, TRANSFORM_NAMES).
@meridian/shared/engine/expression-check exports expressionProblems for the
standard expression kinds or an explicit array of allowed root names.
@meridian/shared/engine/config-schema exposes configSchemaError and
configValueErrors, the same JSON Schema checks used by the engine.
@meridian/shared/engine/text-value exposes the shared value formatter.
The engine-core paths re-export these implementations. Metadata and port
resolution do not import the evaluator; plugin behaviors and host-side assistance
can opt into it without bringing plugin code into the browser.
version
| Export | Value |
|---|---|
PLUGIN_CONTRACT_VERSION |
"0.1.6" (libs/shared/src/version.ts) |
A plugin declares the contract range it needs in its manifest (sdk: "^0.1.1"). At plugin
discovery the host (apps/api/src/plugins.ts) checks that range against PLUGIN_CONTRACT_VERSION
using satisfies() from the npm semver package (no hand-rolled semver comparison); a
plugin whose range does not match is logged and skipped, the others still load. See the
sdk field in Plugin manifest.
The version follows its own doctrine:
- patch (
0.1.0→0.1.1): a new manifest key that an older host would strip (the schema drops a key it does not know: a host that reports unknown keys, kindkey, logs it at load; an earlier host drops it silently) and that changes what gets loaded. A plugin using it declaressdk: "^0.1.<patch>", so an older host refuses it instead of loading it by halves, while existing plugins (^0.1.0) stay accepted.0.1.1adds declared events (contributes.events, a trigger'sevent, an output'sfrom);meridian-plugin validate/buildfail on a manifest that uses them with a lower range, and the host warns.0.1.2addsresolve.pendingon an event binding (the validation a decision is about); no load check covers its range.0.1.3adds the default filter of a declared event (events[].defaultSelector), checked like0.1.1.0.1.4adds the description of a protocol's reception (receive.mediaTypes,receive.example, a transport written{ name, defaultPort?, hint? }), checked like0.1.1.0.1.5adds thederivedPortsrulewhen, checked the same way.0.1.6adds connections (contributes.connectionTypes,connectionon an adapter, an event source or a node), checked like0.1.1; - minor: a real break of the plugin-facing surface (a type, port, helper or manifest form removed or renamed) — plugins must be republished with a widened range;
- nothing: an addition an older host can ignore without consequence, such as
SubjectRecordPort.closeValidationRequest: an optional adapter method, with no manifest key, that a host which does not know it never calls, orlabelandparamson an event source, which an older host drops at load (« clé ignorée »).
0.1.3 also removes two manifest forms, the node-level defaultSelector and the trigger
without pinnedRouting and without event, which the rule above puts in a minor. It
stays a patch by a decision specific to this release: only @posos/common used one of
these forms in the repository, and each removal is reported at load, never dropped
silently. A plugin in ^0.1.x stays accepted and shows the problem.
A host of contract 0.1.3 refuses a plugin in ^0.1.4: with a contract problem when
its schema reads the manifest (it would drop the two keys), with « manifeste invalide »
when a transport is written as an object, since its schema reads a transport as a name
and parses the manifest before the sdk range. A transport written by its name stays
valid, and plugins in ^0.1.x stay accepted.
A host of contract 0.1.5 refuses a plugin in ^0.1.6 with a contract problem; plugins
in ^0.1.x stay accepted.
The check of the dependsOn ranges (kind dependency) has no contract version of its
own: it adds no manifest key, and a host that predates it ignores the ranges, as every host
did before. Requiring a higher sdk floor to get the check would make a rolled-back
image refuse the plugins.
What is not exported
The SDK exposes contracts and pure/registry helpers only. It has no CLI (that is
@meridian/plugin-cli, see meridian-plugin CLI), no plugin loader or
filesystem discovery (that is the API host's PluginHost), and no bundler (plugins are
built with meridian-plugin build, an esbuild bundle — see
Bundling and distribution and
Build and bundle). Publishing and registry resolution
(meridian-plugin publish, the instance manifest's registry:/plugins: fields, the
MERIDIAN_REGISTRY environment variable) are documented in
Publish to the registry and
Set up a plugin registry.