github ministackorg/ministack v1.5.4

4 hours ago

What's Changed

[1.5.4] — 2026-08-31

Added

  • AppSync — 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, with util.error, util.appendError and runtime.earlyReturn following AWS in both of its documented positions, pipeline resolvers threading ctx.stash, and extensions.evictFromApiCache recorded back to the service. NONE, HTTP, AMAZON_DYNAMODB and AWS_LAMBDA data sources execute; the remaining types refuse with NotImplemented. Evaluation runs on a pool of Node workers — one evaluation in flight per worker, a 30-second bound with kill-and-respawn, a heap cap, and resolver console output surfaced in the service log. Contributed by @jbschooley.
  • AppSync — queries are parsed and executed with graphql-core — the regex data plane failed silently on aliases, fragments, nested selection sets, variables with defaults and directives; an API with a schema now parses, validates and executes with the reference engine (an AppSync prelude supplies the AWS* scalars and @aws_* directives), while a schemaless API keeps the previous lenient path. Adds graphql-core as a dependency. Contributed by @jbschooley.
  • AppSync — schema creation, pipeline functions, environment variables and the Update* operationsStartSchemaCreation, GetSchemaCreationStatus, GetIntrospectionSchema (SDL verbatim, or a real introspection document for format=JSON), the function operations, Put/GetGraphqlApiEnvironmentVariables and UpdateDataSource / UpdateResolver / UpdateFunction / UpdateType all answered Unsupported route. CreateGraphqlApi also omitted apiType, visibility and introspectionConfig and left tags off the API object, so a no-change Terraform plan proposed replacing the API; required members are validated rather than silently defaulted. Contributed by @jbschooley.
  • AppSync — the API cache, control plane and data plane — the five ApiCache operations answered Unsupported route; they now round-trip a record carrying healthMetricsConfig, with ttl (1–3600), apiCachingBehavior and type required and validated as on AWS, and the data plane serves query resolvers from the cache under both caching behaviors, mutations excluded. Contributed by @jbschooley.
  • AppSync — nested type resolvers, ctx.identity from Cognito, ctx.env and ctx.error — only top-level Query/Mutation fields resolved and ctx.identity was only ever set by a Lambda authorizer; a resolved value's type now runs its own resolvers with the parent as ctx.source, a Cognito token populates ctx.identity, and response() sees a data source failure as ctx.error. Contributed by @jbschooley.
  • AppSync — the @aws-appsync/utils/dynamodb helpers, and EvaluateCode — the helper sub-module was stripped with every other import, so ddb.get/put/update/remove/scan/query died with "ddb is not defined"; they are provided and bound to whatever name the import used, and EvaluateCode tests a handler before it is attached to an API. Contributed by @jbschooley.
  • AppSync — util.transform DynamoDB expression builders and the rest of the util surfaceutil.transform was an empty object and 8 of the 21 members @aws-appsync/utils declares were provided; toDynamoDBFilterExpression/toDynamoDBConditionExpression now build the {expression, expressionNames, expressionValues} triple over AWS's documented operator set, and the missing util members (base64*, url*, escapeJavaScript, matches, authType, real autoUlid/autoKsuid, util.str, util.math, util.time, the util.dynamodb to* family, util.rds.toJsonObject) are implemented, with the rest refusing by name. Contributed by @jbschooley.
  • Aurora DSQL — foreign key constraints — every REFERENCES / FOREIGN KEY clause was refused 0A000; they now reach the backend as written, with the two DSQL-specific rules enforced against a live cluster (eu-central-1, 2026-08-30): ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY must use NOT VALID, and DEFERRABLE is refused on any other kind of constraint, in the service's own wordings. Contributed by @vivedo.
  • Aurora DSQL — change data capture streams, and GetVpcEndpointServiceName — the four CDC stream operations answered ValidationException; streams now create, describe, list, page, tag and delete with the API's shapes (clientToken idempotency, the 5-per-cluster quota as ServiceQuotaExceededException). Metadata only: no change record reaches the Kinesis target, and a visibly broken target lands the stream FAILED with the service's statusReason code. GetVpcEndpointServiceName answers a stable per-cluster name. Contributed by @vivedo.
  • Aurora DSQL — SELECT ... FOR KEY SHARE — refused 0A000 alongside FOR SHARE and FOR NO KEY UPDATE although the live service takes it since 2026-08-25; it is now forwarded, and only the other two are refused. Contributed by @vivedo.
  • IoT Core — ListThingGroupsForThing — the reverse lookup answered Unsupported IoT path, so resolving a thing's groups meant scanning every group; it now returns {groupName, groupArn} pairs from the bidirectional membership store, with ResourceNotFoundException for an unknown thing. The full list comes back in one page, like the service's other list operations. Contributed by @iot-rocket.
  • CloudFormation — AWS::IoT::CACertificate provisions onto the CA registry — a template declaring the type rolled the stack back with Unsupported resource type. The provisioner now drives the real API: create registers the PEM with RegistrationConfig and CertificateMode (stored and reported by DescribeCACertificate, DEFAULT when omitted), update applies Status / AutoRegistrationStatus / RegistrationConfig / RemoveAutoRegistration in place, and delete deactivates first, because an ACTIVE CA refuses DeleteCACertificate. A PEM that is already registered fails the create, as CloudFormation does for an existing resource, and a changed CACertificatePem or CertificateMode fails the update loudly rather than silently replacing the CA — the id is derived from the certificate content. Tags are not modeled. Contributed by @iot-rocket.
  • KMS — GenerateRandom — the one keyless KMS operation answered InvalidAction; it now returns the requested 1–1024 bytes from os.urandom, refuses an omitted or out-of-range NumberOfBytes with the service's ValidationException wording, answers CustomKeyStoreNotFoundException for a CustomKeyStoreId, and refuses the Nitro-enclave Recipient parameter loudly rather than answering a plaintext shape real KMS never returns there. Contributed by @iot-rocket.

Changed

  • AppSync — an API's auth modes are enforced — a data-plane request satisfying none of the API's configured providers now answers 401 UnauthorizedException, as on AWS; previously an API declaring AMAZON_COGNITO_USER_POOLS served a caller with no credentials at all. Credentials are still not verified — what is refused is the absence of any credential. Contributed by @jbschooley.

Fixed

  • Persistence — a module that failed to load no longer overwrites its state — the stand-in for a module that cannot import reported empty state and save_all wrote it over the service's file, so one bad boot silently destroyed everything that service had persisted; the stand-in now reports None and the file is left alone. Contributed by @jbschooley.
  • ECS — a restored service relaunches its tasks — a restart restored every task STOPPED (its container went with the process) and nothing reconciled the services, so a service reported its persisted runningCount while nothing listened; ACTIVE services are now reconciled once after a restore on a daemon thread, a service that cannot relaunch is logged and skipped, and ECS joins the boot eager-load list when persisted services exist so a workload reached only through a load balancer recovers too. Contributed by @jbschooley.
  • Six fields accepted on write but never reported on read — Lambda's EventSourceMappingArn (absent on create/get/list, so Terraform read no ESM tags), s3control's ListTagsForResource tag wrapper (<member> where the model says <Tag>, unparseable by aws-sdk-go-v2), Kinesis's KeyId alongside EncryptionType, RDS's ServerlessV2ScalingConfiguration and PerformanceInsightsRetentionPeriod, and Cognito's UserAttributeUpdateSettings and a disabled SoftwareTokenMfaConfiguration all round-trip now, each omitted when never set so an unset field does not read as drift. Contributed by @jbschooley.
  • ECS — a task runs on the architecture its task definition declaresruntimePlatform was stored and never read, so Docker chose the host's architecture and an ARM64 task on an x86_64 host started a container that could not execute its entrypoint; the declared architecture is now passed to Docker. Contributed by @jbschooley.
  • Lambda — a function runs on the architecture it declares — the container was created without a platform whatever Architectures said; the declared architecture is now passed to Docker, and a cached image of the wrong architecture is re-pulled rather than failing opaquely at run. Contributed by @jbschooley.
  • AppSync — an anonymous operation that declares variables is parsedmutation($x: T!) { … } with no space after the keyword — what every SDK sends — never matched the operation pattern, so the whole document was read as one field named "mutation" and answered null with no error. Contributed by @jbschooley.
  • AppSync — resolver execution no longer blocks the event loop — a resolver whose data source calls back into MiniStack deadlocked the request; execution and EvaluateCode now run on worker threads. Contributed by @jbschooley.
  • Cognito — AdminListUserAuthEvents requires user-pool add-ons — the call answered {"AuthEvents": []} for every pool where AWS refuses with UserPoolAddOnNotEnabledException (400) unless UserPoolAddOns.AdvancedSecurityMode is enabled; the stored add-ons now gate the operation, before user resolution, and with add-ons enabled the answer stays an empty list since events are never recorded. Contributed by @iot-rocket.
  • Aurora DSQL — the ALTER TABLE refusals answer what the service answers — measured live (eu-central-1, 2026-08-30): a refused ADD CONSTRAINT drew three invented messages where DSQL answers one, ADD COLUMN accepted constraint clauses DSQL refuses, and ALTER TABLE ASYNC ... VALIDATE CONSTRAINT over violating rows failed at submit time where DSQL fails the job — sys.jobs now reports failed with the violation as details. Contributed by @vivedo.

Don't miss a new ministack release

NewReleases is sending notifications on new releases.