What's Changed
New Contributors
[1.3.40] — 2026-05-15
Added
- Cognito invitation and verification emails via SES —
AdminCreateUser,SignUp,ResendConfirmationCode,ForgotPassword, andAdminResetUserPasswordnow hand their welcome / temporary-password / verification mail to the in-process SES emulator, so simulated apps see the message in/_ministack/ses/messagesand it relays via SMTP whenSMTP_HOSTis set. Mirrors AWS behaviour:MessageAction=SUPPRESSskips,RESENDre-sends,DesiredDeliveryMediums=["SMS"]excludes email, and template placeholders ({username},{####}) expand. Sender resolves toEmailConfiguration.From, falling back tono-reply@verificationemail.com(overridable viaCOGNITO_DEFAULT_FROM); setCOGNITO_EMAIL_ENABLED=falseto short-circuit globally. Adds the previously-missingResendConfirmationCodeaction while wiring the delivery path. Contributed by @kjdev. - Step Functions JSONata
Assign+ workflow variables — state-levelAssignfields now bind values into an execution-scoped variable store, and later JSONata expressions can reference them as$name(with dotted-path access like$user.email). Pass$states.resultresolves to the computed Output; Task$states.resultto the raw API result; Catch handlers expose$states.errorOutput. Undefined references surface asStates.QueryEvaluationError, matching the AWS error code for JSONata evaluation failures. Reported by @youngkwangk.
Fixed
- Cognito alias-attribute user lookup —
_resolve_usernow honors the pool'sAliasAttributesandUsernameAttributes, so signing in byemail/phone_number/preferred_usernameresolves correctly. Email and phone aliases require the corresponding_verifiedattribute to equal"true"(matches AWS);preferred_usernamehas no verification gate. The change routesAdminInitiateAuth,InitiateAuth,AdminRespondToAuthChallenge,RespondToAuthChallenge,ConfirmSignUp,ForgotPassword,ConfirmForgotPassword, and the hosted-UI/loginform through the resolver — internal call sites that need the canonical username (group iteration, create-time uniqueness, post-code token issuance) are left untouched. Contributed by @rjmackay. - SQS
ReceiveMessageInternalErroron FIFO queues withRedrivePolicy— a double-JSON-encodedRedrivePolicyvalue slipped pastCreateQueue/SetQueueAttributes, then crashed_dlq_sweepon receive becausejson.loadsreturned a string (not a dict) and.get()raisedAttributeError. MiniStack now validatesRedrivePolicyat intake (parseable JSON object with non-emptydeadLetterTargetArnand numericmaxReceiveCountbetween 1 and 1000) and rejects malformed values withInvalidAttributeValue(400), matching real AWS. Receive carries a defensive guard so legacy persisted state doesn't crash. Reported by @rbonestell. - DynamoDB
if_not_existsarithmetic inSETexpressions —SET v = (if_not_exists(v, :d) - :amt)previously dropped the arithmetic and assigned the resolved value directly: the outer parens kept every token at depth > 0, so the top-level operator scan never saw the-at depth 0._eval_set_valuenow strips a single layer of matched outer parens before parsing, guarded so(a) + (b)(two adjacent groups) isn't accidentally flattened. Reported by @youngkwangk. - S3 → Lambda notifications fire for non-boto3 SDK clients — MiniStack's notification XML parser only recognised the legacy
<CloudFunction>ARN tag, which is what botocore wire-serialisesLambdaFunctionArnas. AWS SDK for Java v2, Go SDK, Terraform'saws_s3_bucket_notification, and any hand-crafted XML send the modern<LambdaFunctionArn>tag — MiniStack silently dropped those configs, so uploads succeeded but the Lambda never fired. Both shapes are now accepted, matching real S3. Reported by @michael-denyer.