August 31, 2026 · v1.5.4
v1.5.4 turns AppSync from stored configuration into a running GraphQL service: APPSYNC_JS resolvers execute, queries parse and validate through graphql-core, the schema / pipeline-function / API-cache control plane lands, and an API's auth modes are enforced the way AWS enforces them. Aurora DSQL gains foreign keys and change-data-capture streams, CloudFormation provisions a JITR fleet's CA certificate, and a wave of stale-state fixes lands across ECS, Lambda, RDS, Kinesis and Cognito.
APPSYNC_JS resolvers execute. Resolver code was stored and never run. request() now decides what the data source is asked for and response() shapes the answer — util/runtime/extensions globals, runtime.earlyReturn in both documented positions, pipelines threading ctx.stash, and the @aws-appsync/utils/dynamodb helpers — against NONE, HTTP, DynamoDB and Lambda data sources. Evaluation runs on a pool of warm Node workers with a 30-second bound, kill-and-respawn recovery and a heap cap, reusing the Node the image already ships. Contributed by @jbschooley.graphql-core. An API with a schema parses, validates and executes with the reference engine — aliases, fragments, nested selections, variable defaults — so an invalid query is a validation error, as on AWS; an AppSync prelude supplies the AWS* scalars and @aws_* directives, and a schemaless API keeps the previous lenient path. Contributed by @jbschooley.StartSchemaCreation, GetIntrospectionSchema (SDL, or a real format=JSON introspection document), pipeline functions, environment variables, the Update* family, and the five ApiCache operations — validated as AWS validates them, and honored by the data plane under both caching behaviors. EvaluateCode tests a handler before it is attached to an API. Contributed by @jbschooley.FOR KEY SHARE. REFERENCES reaches the backend as written with DSQL's two live-measured rules enforced; the four stream operations create, page, tag and delete with the API's shapes and quotas (metadata only — no change record reaches the Kinesis target); GetVpcEndpointServiceName answers a stable per-cluster name. Contributed by @vivedo.ListThingGroupsForThing. The reverse membership lookup answered Unsupported IoT path; it now returns {{groupName, groupArn}} pairs straight from the bidirectional store. Contributed by @iot-rocket.AWS::IoT::CACertificate. The provisioner drives the real registry API: create registers the PEM with RegistrationConfig and CertificateMode, update applies the no-interruption properties in place, delete deactivates first. An already-registered PEM fails the create, as CloudFormation does, and a PEM or mode change fails loudly rather than silently replacing the CA. Contributed by @iot-rocket.GenerateRandom. The one keyless KMS operation: 1–1024 bytes from os.urandom, the service's own refusal wordings, and a loud refusal of the Nitro-enclave Recipient parameter rather than a plaintext shape real KMS never returns there. Contributed by @iot-rocket.401 UnauthorizedException, as on AWS. Credentials are still not verified — what is refused is the absence of any credential, which is what makes an authorization test against MiniStack meaningful. Contributed by @jbschooley.runningCount while nothing listened; ACTIVE services now reconcile once after a restore, and ECS eager-loads at boot when persisted services exist so a workload reached only through a load balancer recovers too. Contributed by @jbschooley.EventSourceMappingArn, s3control's tag-list wire wrapper, Kinesis's KeyId, RDS's ServerlessV2ScalingConfiguration and PI retention period, and two Cognito pool settings all round-trip now — each omitted when never set, so nothing reads as Terraform drift. Contributed by @jbschooley.runtimePlatform and Architectures were stored and ignored, so an arm64 workload on an x86_64 host ran the wrong architecture and failed opaquely; the declared platform is now passed to Docker, and a wrong-architecture cached image is re-pulled. Contributed by @jbschooley.mutation($x: T!), what every SDK sends — parsed as a field named "mutation" and answered null; and resolver execution blocked the event loop, deadlocking any resolver whose data source calls back into MiniStack. Both fixed. Contributed by @jbschooley.AdminListUserAuthEvents requires user-pool add-ons. Every pool answered an empty list where AWS refuses with UserPoolAddOnNotEnabledException unless AdvancedSecurityMode is enabled; the stored add-ons now gate the call, before user resolution, as the live service does. Contributed by @iot-rocket.ALTER TABLE refusals answer what the service answers. Measured against a live cluster: one refusal message where three were invented, ADD COLUMN refusing the clauses DSQL refuses, and a failing VALIDATE CONSTRAINT failing as a job with the violation in sys.jobs. Contributed by @vivedo.docker pull ministackorg/ministack:1.5.4 docker run -d -p 4566:4566 ministackorg/ministack:1.5.4
Or pin in compose.yaml:
services:
ministack:
image: ministackorg/ministack:1.5.4
ports:
- "4566:4566"
Issues and PRs welcome on GitHub. Discussion on r/ministack.