@vendure/cloud
v0.3.2
Published
The package a Vendure Cloud application installs. Re-exports the Cloud Config interface and the platform-supplied plugins.
Readme
@vendure/cloud
The package a Vendure Cloud application installs as a development dependency. It exports the Cloud Config interface and a local runner; the managed image replaces its local substitutes with the private Cloud Runtime implementation.
import { defineCloudConfig, defineVendureExtension } from "@vendure/cloud";The Cloud Config surface is re-exported from @vendure/cloud-config. The four wrapped plugins ADR-0044
lists — CloudAssetServerPlugin, CloudDashboardPlugin, CloudEmailPlugin and
CloudAdvancedSearchPlugin — arrive with the wrappers they hold, in CLO-399, CLO-400,
CLO-401 and CLO-402, and each is added here as another exact-pinned dependency re-exported
from src/index.ts.
Local development
This package declares a Vendure CLI plugin in package.json#vendure.cliPlugin, which a project
turns on once with vendure plugins add @vendure/cloud. The plugin extends the dev command
through the host's ordered command-extension API rather than replacing it, so Core keeps supervising
the processes and a wrapper another plugin already applied still runs. What it adds before calling
the next action is the two servers below, the migration chain, and the two entry points Core would
otherwise have looked for in the customer's repository — which a Cloud Config application does not
have (ADR-0043). test/dev-e2e/run.sh drives all of that from a registry install.
vendure dev generates the Dashboard's Vite configuration under .cache from the same Cloud
Config. A standard Cloud project therefore owns no vite.config.*. The generated configuration
resolves the handle, derives the Dashboard route, exposes customer-authored Vendure plugins to
Dashboard extension discovery and delegates compilation to @vendure/dashboard/vite.
Projects that need custom Vite behaviour can pass --vite-config and use the Cloud-aware wrapper:
import { vendureCloudDashboardPlugin } from "@vendure/cloud/vite";
vendureCloudDashboardPlugin({
vendureConfigPath: new URL("./src/vendure-config.ts", import.meta.url),
api: { host: "http://localhost", port: 3000 },
gqlOutputPath: "./src/gql",
});Production-only platform plugin declarations are not composed inside the Vite process.
vendure dev provisions the local PostgreSQL database and the local Valkey cache, and runs the
included runner against them. The runner itself provisions nothing: composeLocalConfig takes each
connection as LocalRuntimeOptions.database and LocalRuntimeOptions.cache, or reads
VENDURE_LOCAL_DATABASE_URL and VENDURE_LOCAL_CACHE_URL when it was started as a child process,
and refuses to compose without either.
It supplies one substitute for every capability in the shared inventory @vendure/cloud-config
holds: PostgreSQL, a Valkey the server and the worker share, the job queue inside the database, the
default scheduler, the upstream Dashboard plugin against a Vite development server, and the upstream
asset server against a project-local directory. It prints a startup warning naming each of them.
The cache is a Valkey rather than DefaultCachePlugin because that plugin declares CacheItem and
CacheTag, and a customer's migrations are generated from this composition: two tables the managed
runtime never reads would reach their deployed database (CLO-645).
packages/cloud-runtime/test/entity-set.test.ts compares the two entity sets whole, with nothing
exempted on either side. The protocol work is Vendure's own RedisCacheStrategy; the platform's
PlatformCacheStrategy is not reused, because everything it adds over that one — a SigV4 IAM token
per connection, mandatory TLS, an RBAC-user key prefix — is production infrastructure, and
@vendure-cloud/cloud-runtime is private and downstream of this package.
The database is PostgreSQL because a deployed VC Environment runs one (ADR-0020) and TypeORM emits
DDL for the engine it is connected to: a local runtime on another engine produces migrations the
deployed database cannot apply. composeLocalConfig also holds synchronize: false and the
declared migration chain, so a migration generated against it is a diff against what those
migrations built.
runLocalMigrations is the local migrate run mode. It runs the chain the Cloud Config declares
and creates nothing outside it, and refuses with NoDeclaredMigrationsError when there is no chain
— a project created by Vendure's own tooling ships a schema-creating initial migration, and one
without any has no schema this runtime is willing to invent.
test/migration-chain.integration.test.ts builds an empty database from a generated initial
migration and then carries a second one through to a deployed-shaped database.
Install pg, ioredis, @vendure/dashboard and vite as development dependencies. They are
intentionally absent from deployed images, and none is reached until a local configuration is
composed, so an application that never composes one pays nothing for them.
If VC_ENVIRONMENT_ID is present, the local runner refuses to boot. A managed process must use the
private platform entrypoint and cannot silently fall back to a local database.
Why the pins are exact, and what it costs
A plugin package takes @vendure/cloud-config as a peer dependency and depends on it
directly nowhere. This package is the only one that depends on it directly, at an exact
version. Between them those two rules mean a customer's tree cannot end up holding two copies
of @vendure/cloud-config by accident, which matters because two copies break
instanceof CloudConfigError across the seam: a boot failure a caller catches becomes an
uncaught one, and the customer sees a stack trace instead of the message we wrote.
The cost is a lockstep release train. A patch to one plugin bumps every package and this facade with it. ADR-0045 accepts that, and ADR-0046 makes it cheaper than it was: a customer declares these as development dependencies and the Cloud Runtime supplies the production copies, so a patch no longer waits on every customer to install it.
Two standing constraints on anything added here
No top-level await, anywhere in the module graph.
ADR-0049
requires this package to be loadable from a CommonJS application through require(esm), which
refuses a graph containing one — at runtime, in the customer's container, with no compile-time
symptom. packages/cloud-config/test/managed-build.test.ts builds and runs its fixture under
both module systems, which is what would catch it.
Nothing is bundled or minified. A bundler inlines @vendure/core and a minifier rewrites
the class names the boot messages are read from, and both failures are silent.
test/published-output.test.ts builds this package and asserts the
output is neither.
