@kensio/yulin 1.20.15 → 1.20.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. package/README.md +13 -0
  2. package/dist/sdk/module/sim-sdk-module-client-interceptor.d.ts +5 -0
  3. package/dist/sdk/module/sim-sdk-module-client-interceptor.js +14 -0
  4. package/dist/sdk/module/sim-sdk-static-client-factory.d.ts +26 -0
  5. package/dist/sdk/module/sim-sdk-static-client-factory.js +59 -0
  6. package/dist/sdk/send-patch.d.ts +8 -0
  7. package/dist/sdk/send-patch.js +11 -0
  8. package/dist/service/aws/caller/sim-aws-ambient-caller.d.ts +23 -0
  9. package/dist/service/aws/caller/sim-aws-ambient-caller.js +12 -0
  10. package/dist/service/aws/caller/sim-aws-caller-resolver.d.ts +39 -6
  11. package/dist/service/aws/caller/sim-aws-caller-resolver.js +32 -30
  12. package/dist/service/aws/caller/sim-aws-caller.d.ts +9 -0
  13. package/dist/service/aws/caller/sim-aws-resolved-caller.d.ts +19 -0
  14. package/dist/service/aws/caller/sim-aws-resolved-caller.js +26 -0
  15. package/dist/service/aws/factory/sim-aws-account-region-service-builder.d.ts +12 -0
  16. package/dist/service/aws/factory/sim-aws-account-region-service-builder.js +6 -0
  17. package/dist/service/aws/factory/sim-aws-account-service-cache.d.ts +12 -0
  18. package/dist/service/aws/factory/sim-aws-account-service-cache.js +9 -0
  19. package/dist/service/aws/factory/sim-aws-registered-service-builder.js +3 -1
  20. package/dist/service/aws/factory/sim-aws-service-factory.d.ts +5 -0
  21. package/dist/service/aws/factory/sim-aws-service-factory.js +14 -0
  22. package/dist/service/aws/sim-aws-properties.d.ts +15 -0
  23. package/dist/service/aws/sim-aws.js +2 -1
  24. package/dist/service/cloudformation/command/create-stack/create-stack.handler.d.ts +4 -0
  25. package/dist/service/cloudformation/command/create-stack/create-stack.handler.js +4 -1
  26. package/dist/service/cloudformation/deploy/sim-cfn-cdk-out-deployer.js +2 -1
  27. package/dist/service/cloudformation/deploy/sim-cfn-cdk-out-plan.d.ts +11 -2
  28. package/dist/service/cloudformation/deploy/sim-cfn-cdk-out-plan.js +2 -1
  29. package/dist/service/cloudformation/deploy/sim-cfn-cdk-out-stack-options.d.ts +6 -0
  30. package/dist/service/cloudformation/deploy/sim-cfn-template-deployer.d.ts +11 -0
  31. package/dist/service/cloudformation/deploy/sim-cfn-template-deployer.js +17 -15
  32. package/dist/service/cloudformation/deploy/sim-cfn-template-file-loader.d.ts +12 -0
  33. package/dist/service/cloudformation/deploy/sim-cfn-template-file-loader.js +2 -1
  34. package/dist/service/cloudformation/resource/cfn/cloudfront/sim-cloudfront-cache-policy-cfn.d.ts +23 -0
  35. package/dist/service/cloudformation/resource/cfn/cloudfront/sim-cloudfront-cache-policy-cfn.js +30 -0
  36. package/dist/service/cloudformation/resource/cfn/cloudfront/sim-cloudfront-cfn-value-adapter.js +8 -0
  37. package/dist/service/cloudformation/resource/name/sim-cfn-generated-resource-name.d.ts +29 -12
  38. package/dist/service/cloudformation/resource/name/sim-cfn-generated-resource-name.js +51 -20
  39. package/dist/service/cloudformation/stack/deploy/sim-cfn-resource-order.d.ts +19 -0
  40. package/dist/service/cloudformation/stack/deploy/sim-cfn-resource-order.js +6 -0
  41. package/dist/service/cloudformation/stack/deploy/sim-cfn-stack-resource-batch-creator.d.ts +7 -0
  42. package/dist/service/cloudformation/stack/deploy/sim-cfn-stack-resource-batch-creator.js +9 -2
  43. package/dist/service/cloudformation/stack/deploy/sim-cfn-stack-resource-creator.d.ts +2 -0
  44. package/dist/service/cloudformation/stack/deploy/sim-cfn-stack-resource-creator.js +2 -1
  45. package/dist/service/cloudformation/stack/sim-cfn-stack-resource-operations.d.ts +6 -0
  46. package/dist/service/cloudformation/stack/sim-cfn-stack-resource-operations.js +4 -1
  47. package/dist/service/cloudformation/stack/sim-cfn-stack.js +2 -1
  48. package/dist/service/cloudformation/stack/sim-cfn-stack.type.d.ts +6 -0
  49. package/dist/service/cloudfront/behaviour/sim-cloud-front-behavior.d.ts +5 -0
  50. package/dist/service/cloudfront/cache-policy/sim-cf-cache-policy-registry.d.ts +37 -0
  51. package/dist/service/cloudfront/cache-policy/sim-cf-cache-policy-registry.js +50 -0
  52. package/dist/service/cloudfront/cache-policy/sim-cf-cache-policy.d.ts +25 -0
  53. package/dist/service/cloudfront/cache-policy/sim-cf-cache-policy.js +21 -0
  54. package/dist/service/cloudfront/cache-policy/sim-cf-managed-cache-policies.d.ts +28 -0
  55. package/dist/service/cloudfront/cache-policy/sim-cf-managed-cache-policies.js +48 -0
  56. package/dist/service/cloudfront/cff/function-code-input/cff-function-code-input.d.ts +8 -0
  57. package/dist/service/cloudfront/cff/function-code-input/cff-function-code-input.js +13 -0
  58. package/dist/service/cloudfront/cff/sim-cf-function-commands.d.ts +52 -0
  59. package/dist/service/cloudfront/cff/sim-cf-function-commands.js +51 -0
  60. package/dist/service/cloudfront/cff/sim-cff-configuration.d.ts +41 -0
  61. package/dist/service/cloudfront/cff/sim-cff-configuration.js +34 -0
  62. package/dist/service/cloudfront/cff/sim-cff-stage.d.ts +23 -0
  63. package/dist/service/cloudfront/cff/sim-cff-stage.js +30 -0
  64. package/dist/service/cloudfront/cff/sim-cloudfront-function.d.ts +6 -1
  65. package/dist/service/cloudfront/cff/sim-cloudfront-function.js +6 -0
  66. package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-config.d.ts +27 -0
  67. package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-config.js +42 -0
  68. package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-creator.d.ts +24 -0
  69. package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-creator.js +32 -0
  70. package/dist/service/cloudfront/cfn/distro/{sim-cfn-cf-distro-response-headers-policy.d.ts → sim-cfn-cf-distro-behavior-policies.d.ts} +8 -7
  71. package/dist/service/cloudfront/cfn/distro/{sim-cfn-cf-distro-response-headers-policy.js → sim-cfn-cf-distro-behavior-policies.js} +11 -37
  72. package/dist/service/cloudfront/cfn/distro/sim-cfn-cf-distro-creator.d.ts +6 -5
  73. package/dist/service/cloudfront/cfn/distro/sim-cfn-cf-distro-creator.js +8 -7
  74. package/dist/service/cloudfront/cfn/distro/sim-cfn-cf-distro-policy-drops.d.ts +23 -0
  75. package/dist/service/cloudfront/cfn/distro/sim-cfn-cf-distro-policy-drops.js +50 -0
  76. package/dist/service/cloudfront/cfn/sim-cfn-cloudfront-resource-factory.d.ts +1 -0
  77. package/dist/service/cloudfront/cfn/sim-cfn-cloudfront-resource-factory.js +10 -0
  78. package/dist/service/cloudfront/command/create-distribution/create-distribution.command.d.ts +1 -0
  79. package/dist/service/cloudfront/command/create-distribution/create-distribution.handler.d.ts +2 -0
  80. package/dist/service/cloudfront/command/create-function/create-function.handler.js +7 -1
  81. package/dist/service/cloudfront/command/function/sim-cf-describe-function.d.ts +22 -0
  82. package/dist/service/cloudfront/command/function/sim-cf-describe-function.js +32 -0
  83. package/dist/service/cloudfront/command/function/sim-cf-function-access.d.ts +48 -0
  84. package/dist/service/cloudfront/command/function/sim-cf-function-access.js +48 -0
  85. package/dist/service/cloudfront/command/function/sim-cf-function-command.types.d.ts +97 -0
  86. package/dist/service/cloudfront/command/function/sim-cf-function-command.types.js +10 -0
  87. package/dist/service/cloudfront/command/function/sim-cf-function-lookup.d.ts +12 -0
  88. package/dist/service/cloudfront/command/function/sim-cf-function-lookup.js +21 -0
  89. package/dist/service/cloudfront/command/function/sim-cf-function-summary.d.ts +11 -0
  90. package/dist/service/cloudfront/command/function/sim-cf-function-summary.js +30 -0
  91. package/dist/service/cloudfront/command/function/sim-cf-get-function.d.ts +23 -0
  92. package/dist/service/cloudfront/command/function/sim-cf-get-function.js +33 -0
  93. package/dist/service/cloudfront/command/function/sim-cf-list-functions.d.ts +22 -0
  94. package/dist/service/cloudfront/command/function/sim-cf-list-functions.js +38 -0
  95. package/dist/service/cloudfront/command/update-distribution/update-distribution.handler.d.ts +2 -0
  96. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-cache-policy.d.ts +18 -0
  97. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-cache-policy.js +30 -0
  98. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-policies.d.ts +28 -0
  99. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-policies.js +41 -0
  100. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-properties.d.ts +2 -2
  101. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-properties.js +6 -3
  102. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-response-headers-policy.d.ts +0 -10
  103. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-response-headers-policy.js +0 -19
  104. package/dist/service/cloudfront/distribution/configurator/sim-cf-distribution-configurator.factory.d.ts +2 -0
  105. package/dist/service/cloudfront/distribution/configurator/sim-cf-distribution-configurator.factory.js +4 -2
  106. package/dist/service/cloudfront/distribution/configurator/sim-cloud-front-behavior-configurator.d.ts +3 -3
  107. package/dist/service/cloudfront/distribution/configurator/sim-cloud-front-behavior-configurator.js +5 -5
  108. package/dist/service/cloudfront/distribution/configurator/sim-cloud-front-distribution-configurator.d.ts +3 -3
  109. package/dist/service/cloudfront/distribution/configurator/sim-cloud-front-distribution-configurator.js +4 -4
  110. package/dist/service/cloudfront/distribution/sim-cf-distribution-configuration-state.d.ts +3 -1
  111. package/dist/service/cloudfront/distribution/sim-cf-distribution-reconfigurer.d.ts +2 -0
  112. package/dist/service/cloudfront/error/sim-cloudfront.error.d.ts +21 -0
  113. package/dist/service/cloudfront/error/sim-cloudfront.error.js +25 -0
  114. package/dist/service/cloudfront/key-value-store/sim-cf-key-value-store-access.js +2 -10
  115. package/dist/service/cloudfront/key-value-store/sim-cf-key-value-store.js +2 -1
  116. package/dist/service/cloudfront/sdk/sim-cloudfront-sdk-command-router.js +12 -0
  117. package/dist/service/cloudfront/sim-cf-authorize.d.ts +16 -0
  118. package/dist/service/cloudfront/sim-cf-authorize.js +19 -0
  119. package/dist/service/cloudfront/sim-cf-etag.d.ts +7 -0
  120. package/dist/service/cloudfront/sim-cf-etag.js +10 -0
  121. package/dist/service/cloudfront/sim-cloudfront-commands.d.ts +8 -12
  122. package/dist/service/cloudfront/sim-cloudfront-commands.js +8 -17
  123. package/dist/service/cloudfront/sim-cloudfront-policies.d.ts +43 -0
  124. package/dist/service/cloudfront/sim-cloudfront-policies.js +53 -0
  125. package/dist/service/cloudfront/sim-cloudfront.d.ts +13 -17
  126. package/dist/service/cloudfront/sim-cloudfront.js +22 -25
  127. package/dist/service/ecr/authorize/sim-ecr-authorizer.d.ts +31 -0
  128. package/dist/service/ecr/authorize/sim-ecr-authorizer.js +38 -0
  129. package/dist/service/ecr/cfn/repository/sim-cfn-ecr-repository-creator.d.ts +11 -2
  130. package/dist/service/ecr/cfn/repository/sim-cfn-ecr-repository-creator.js +11 -2
  131. package/dist/service/ecr/cfn/sim-ecr-cfn-resource-factory.d.ts +4 -2
  132. package/dist/service/ecr/cfn/sim-ecr-cfn-resource-factory.js +8 -9
  133. package/dist/service/ecr/cfn/sim-ecr-cfn-unsupported-resource.d.ts +7 -0
  134. package/dist/service/ecr/cfn/sim-ecr-cfn-unsupported-resource.js +9 -0
  135. package/dist/service/ecr/sim-ecr.d.ts +7 -0
  136. package/dist/service/ecr/sim-ecr.js +16 -4
  137. package/dist/service/ecs/command/authorize/sim-ecs-authorizer.d.ts +12 -0
  138. package/dist/service/ecs/command/authorize/sim-ecs-authorizer.js +21 -0
  139. package/dist/service/ecs/command/register-task-definition/register-task-definition.handler.js +1 -0
  140. package/dist/service/ecs/sim-ecs-service-principal.d.ts +8 -0
  141. package/dist/service/ecs/sim-ecs-service-principal.js +8 -0
  142. package/dist/service/eventbridge/command/authorize/sim-event-bridge-authorizer.d.ts +12 -0
  143. package/dist/service/eventbridge/command/authorize/sim-event-bridge-authorizer.js +21 -0
  144. package/dist/service/eventbridge/command/rule/sim-event-bridge-rule-access.d.ts +13 -0
  145. package/dist/service/eventbridge/command/rule/sim-event-bridge-rule-access.js +9 -0
  146. package/dist/service/eventbridge/command/target/sim-event-bridge-put-targets.js +1 -0
  147. package/dist/service/firehose/command/authorize/sim-firehose-authorizer.d.ts +12 -0
  148. package/dist/service/firehose/command/authorize/sim-firehose-authorizer.js +20 -0
  149. package/dist/service/firehose/command/sim-firehose-delivery-stream-access.d.ts +4 -0
  150. package/dist/service/firehose/command/sim-firehose-delivery-stream-access.js +6 -0
  151. package/dist/service/firehose/command/stream/sim-firehose-create-delivery-stream.js +3 -1
  152. package/dist/service/firehose/sim-firehose-service-principal.d.ts +8 -0
  153. package/dist/service/firehose/sim-firehose-service-principal.js +8 -0
  154. package/dist/service/firehose/source/sim-firehose-source.d.ts +5 -0
  155. package/dist/service/firehose/source/sim-firehose-source.js +5 -0
  156. package/dist/service/glue/cfn/database/sim-cfn-glue-database-properties.js +2 -2
  157. package/dist/service/glue/cfn/sim-cfn-glue-generated-name.d.ts +10 -0
  158. package/dist/service/glue/cfn/sim-cfn-glue-generated-name.js +25 -0
  159. package/dist/service/glue/cfn/table/sim-cfn-glue-table-properties.js +2 -3
  160. package/dist/service/iam/authorize/allow/sim-iam-allow-requirement.d.ts +33 -2
  161. package/dist/service/iam/authorize/allow/sim-iam-allow-requirement.js +33 -2
  162. package/dist/service/iam/authorize/allow/sim-iam-allow-statements.d.ts +4 -3
  163. package/dist/service/iam/authorize/allow/sim-iam-allow-statements.js +9 -3
  164. package/dist/service/iam/authorize/context/sim-iam-auth-z-allow-requirement.d.ts +14 -5
  165. package/dist/service/iam/authorize/context/sim-iam-auth-z-allow-requirement.js +16 -12
  166. package/dist/service/iam/authorize/context/sim-iam-auth-z-caller-context-builder.d.ts +36 -7
  167. package/dist/service/iam/authorize/context/sim-iam-auth-z-caller-context-builder.js +22 -11
  168. package/dist/service/iam/authorize/context/sim-iam-auth-z-context-builder.d.ts +10 -71
  169. package/dist/service/iam/authorize/context/sim-iam-auth-z-context-builder.js +7 -2
  170. package/dist/service/iam/authorize/context/sim-iam-auth-z-input.d.ts +87 -0
  171. package/dist/service/iam/authorize/context/sim-iam-auth-z-input.js +1 -0
  172. package/dist/service/iam/authorize/match/sim-iam-policy-principal-matcher.d.ts +21 -3
  173. package/dist/service/iam/authorize/match/sim-iam-policy-principal-matcher.js +34 -10
  174. package/dist/service/iam/authorize/match/sim-iam-principal-match.d.ts +29 -8
  175. package/dist/service/iam/authorize/match/sim-iam-principal-match.js +38 -13
  176. package/dist/service/iam/authorize/pass-role/sim-iam-pass-role-authorizer.d.ts +74 -0
  177. package/dist/service/iam/authorize/pass-role/sim-iam-pass-role-authorizer.js +92 -0
  178. package/dist/service/iam/authorize/sim-iam-account-auth-z.d.ts +21 -5
  179. package/dist/service/iam/authorize/sim-iam-account-auth-z.js +7 -3
  180. package/dist/service/iam/authorize/sim-iam-authorizer.d.ts +5 -2
  181. package/dist/service/iam/authorize/sim-iam-authorizer.js +3 -1
  182. package/dist/service/iam/authorize/sim-iam-inter-service-auth-z.d.ts +1 -1
  183. package/dist/service/iam/authorize/sim-iam-wildcard.js +39 -4
  184. package/dist/service/iam/cfn/managed-policy/sim-cfn-iam-managed-policy-creator.js +2 -1
  185. package/dist/service/iam/cfn/name/sim-cfn-iam-generated-name.d.ts +16 -0
  186. package/dist/service/iam/cfn/name/sim-cfn-iam-generated-name.js +36 -0
  187. package/dist/service/iam/cfn/role/sim-cfn-iam-role-properties-parser.js +9 -8
  188. package/dist/service/iam/cfn/sim-cfn-iam-optional-string.d.ts +17 -0
  189. package/dist/service/iam/cfn/sim-cfn-iam-optional-string.js +17 -0
  190. package/dist/service/iam/cfn/user/sim-cfn-iam-user-properties-parser.js +4 -8
  191. package/dist/service/iam/command/policy/create-policy/create-policy-input-resolver.js +2 -0
  192. package/dist/service/iam/command/policy/put-role-policy/put-role-policy.handler.js +5 -0
  193. package/dist/service/iam/command/policy/put-user-policy/put-user-policy.handler.js +5 -0
  194. package/dist/service/iam/command/role/create-role/create-role.handler.js +4 -1
  195. package/dist/service/iam/error/sim-iam.error.d.ts +11 -0
  196. package/dist/service/iam/error/sim-iam.error.js +13 -0
  197. package/dist/service/iam/index.d.ts +1 -0
  198. package/dist/service/iam/policy/sim-iam-policy-document-of-size.d.ts +18 -0
  199. package/dist/service/iam/policy/sim-iam-policy-document-of-size.js +41 -0
  200. package/dist/service/iam/role/sim-iam-deploy-role.d.ts +56 -0
  201. package/dist/service/iam/role/sim-iam-deploy-role.js +50 -0
  202. package/dist/service/iam/role/sim-iam-role-with-policy.factory.d.ts +11 -0
  203. package/dist/service/iam/role/sim-iam-role-with-policy.factory.js +4 -2
  204. package/dist/service/iam/sim-iam-account-parts.d.ts +16 -0
  205. package/dist/service/iam/sim-iam-account-parts.js +2 -0
  206. package/dist/service/iam/sim-iam.d.ts +12 -2
  207. package/dist/service/iam/sim-iam.js +12 -0
  208. package/dist/service/iam/validate/size/sim-iam-policy-document-size.d.ts +57 -0
  209. package/dist/service/iam/validate/size/sim-iam-policy-document-size.js +71 -0
  210. package/dist/service/kms/command/authorize/sim-kms-authorizer.d.ts +3 -1
  211. package/dist/service/kms/command/authorize/sim-kms-authorizer.js +4 -1
  212. package/dist/service/kms/command/sim-kms-request-options.d.ts +11 -0
  213. package/dist/service/kms/key/sim-kms-key-policy.d.ts +5 -4
  214. package/dist/service/kms/key/sim-kms-key-policy.js +4 -3
  215. package/dist/service/lambda/cfn/function/sim-cfn-lambda-function-properties-parser.d.ts +2 -2
  216. package/dist/service/lambda/cfn/function/sim-cfn-lambda-function-properties-parser.js +4 -3
  217. package/dist/service/lambda/cfn/function/sim-cfn-lambda-generated-function-name.d.ts +10 -0
  218. package/dist/service/lambda/cfn/function/sim-cfn-lambda-generated-function-name.js +25 -0
  219. package/dist/service/lambda/command/authorize/sim-lambda-resource-policies.d.ts +1 -1
  220. package/dist/service/lambda/command/create-function/create-function-authorizer.d.ts +9 -2
  221. package/dist/service/lambda/command/create-function/create-function-authorizer.js +16 -2
  222. package/dist/service/lambda/command/create-function/create-function.handler.js +1 -1
  223. package/dist/service/lambda/command/update-function-configuration/update-function-configuration-authorizer.d.ts +7 -2
  224. package/dist/service/lambda/command/update-function-configuration/update-function-configuration-authorizer.js +14 -2
  225. package/dist/service/lambda/command/update-function-configuration/update-function-configuration.handler.js +1 -1
  226. package/dist/service/lambda/function/logging/sim-lambda-function-logging.d.ts +10 -1
  227. package/dist/service/lambda/function/logging/sim-lambda-function-logging.js +25 -1
  228. package/dist/service/lambda/function/logging/sim-lambda-invoke-error-log.d.ts +13 -0
  229. package/dist/service/lambda/function/logging/sim-lambda-invoke-error-log.js +18 -0
  230. package/dist/service/lambda/sim-lambda-service-principal.d.ts +7 -0
  231. package/dist/service/lambda/sim-lambda-service-principal.js +7 -0
  232. package/dist/service/logs/cfn/delivery/sim-cfn-delivery-authorization.d.ts +46 -0
  233. package/dist/service/logs/cfn/delivery/sim-cfn-delivery-authorization.js +49 -0
  234. package/dist/service/logs/cfn/delivery/sim-cfn-delivery-creator.d.ts +5 -0
  235. package/dist/service/logs/cfn/delivery/sim-cfn-delivery-creator.js +6 -0
  236. package/dist/service/logs/cfn/delivery/sim-cfn-delivery-destination-creator.d.ts +5 -0
  237. package/dist/service/logs/cfn/delivery/sim-cfn-delivery-destination-creator.js +6 -0
  238. package/dist/service/logs/cfn/delivery/sim-cfn-delivery-source-creator.d.ts +5 -0
  239. package/dist/service/logs/cfn/delivery/sim-cfn-delivery-source-creator.js +6 -0
  240. package/dist/service/logs/cfn/group/sim-cfn-log-group-creator.d.ts +9 -2
  241. package/dist/service/logs/cfn/group/sim-cfn-log-group-creator.js +34 -5
  242. package/dist/service/logs/cfn/sim-logs-cfn-resource-deleter.js +1 -1
  243. package/dist/service/logs/cfn/sim-logs-cfn-resource-factory.d.ts +4 -0
  244. package/dist/service/logs/cfn/sim-logs-cfn-resource-factory.js +9 -4
  245. package/dist/service/logs/sim-logs-commands.d.ts +3 -0
  246. package/dist/service/logs/sim-logs-commands.js +4 -0
  247. package/dist/service/logs/sim-logs.js +6 -1
  248. package/dist/service/s3/cfn/bucket/sim-cfn-s3-bucket-creator.d.ts +2 -2
  249. package/dist/service/s3/cfn/bucket/sim-cfn-s3-bucket-creator.js +4 -3
  250. package/dist/service/s3/cfn/bucket/sim-cfn-s3-bucket-generated-name.d.ts +12 -0
  251. package/dist/service/s3/cfn/bucket/sim-cfn-s3-bucket-generated-name.js +22 -0
  252. package/dist/service/s3/command/authorize/sim-s3-bucket-resource-policies.d.ts +1 -1
  253. package/dist/service/scheduler/command/authorize/sim-scheduler-authorizer.d.ts +10 -1
  254. package/dist/service/scheduler/command/authorize/sim-scheduler-authorizer.js +19 -1
  255. package/dist/service/scheduler/command/schedule/sim-scheduler-create-schedule.js +1 -0
  256. package/dist/service/scheduler/command/schedule/sim-scheduler-schedule-access.d.ts +8 -0
  257. package/dist/service/scheduler/command/schedule/sim-scheduler-schedule-access.js +9 -0
  258. package/dist/service/scheduler/command/schedule/sim-scheduler-update-schedule.js +1 -0
  259. package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-generated-name.d.ts +15 -0
  260. package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-generated-name.js +22 -0
  261. package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-properties.d.ts +4 -10
  262. package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-properties.js +13 -31
  263. package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-value.d.ts +17 -0
  264. package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-value.js +30 -0
  265. package/dist/service/secretsmanager/secret/sim-secrets-manager-secret-name.d.ts +6 -0
  266. package/dist/service/secretsmanager/secret/sim-secrets-manager-secret-name.js +8 -3
  267. package/dist/service/sns/command/authorize/sim-sns-topic-resource-policies.d.ts +1 -1
  268. package/dist/service/sqs/command/authorize/sim-sqs-queue-resource-policies.d.ts +1 -1
  269. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-generated-parameter-name.d.ts +16 -0
  270. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-generated-parameter-name.js +23 -0
  271. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-properties.d.ts +2 -4
  272. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-properties.js +5 -5
  273. package/dist/service/ssm/parameter/sim-ssm-kms-crypto.d.ts +6 -4
  274. package/dist/service/ssm/parameter/sim-ssm-kms-crypto.js +4 -4
  275. package/dist/service/ssm/parameter/sim-ssm-parameter-arn.d.ts +17 -0
  276. package/dist/service/ssm/parameter/sim-ssm-parameter-arn.js +20 -0
  277. package/dist/service/ssm/parameter/sim-ssm-parameter-kms.d.ts +15 -9
  278. package/dist/service/ssm/parameter/sim-ssm-parameter-kms.js +20 -10
  279. package/dist/service/ssm/parameter/sim-ssm-parameter-name.js +3 -12
  280. package/dist/service/stepfunctions/command/authorize/sim-step-functions-authorizer.d.ts +41 -0
  281. package/dist/service/stepfunctions/command/authorize/sim-step-functions-authorizer.js +64 -0
  282. package/dist/service/stepfunctions/command/machine/sim-state-machine-create.d.ts +5 -2
  283. package/dist/service/stepfunctions/command/machine/sim-state-machine-create.js +6 -2
  284. package/dist/service/stepfunctions/command/machine/sim-state-machine-delete.d.ts +26 -0
  285. package/dist/service/stepfunctions/command/machine/sim-state-machine-delete.js +29 -0
  286. package/dist/service/stepfunctions/command/machine/sim-state-machine-lookup.d.ts +7 -0
  287. package/dist/service/stepfunctions/command/machine/sim-state-machine-lookup.js +12 -3
  288. package/dist/service/stepfunctions/command/machine/sim-state-machine-update.d.ts +19 -0
  289. package/dist/service/stepfunctions/command/machine/{sim-state-machine-writes.js → sim-state-machine-update.js} +3 -14
  290. package/dist/service/stepfunctions/sim-step-functions.d.ts +8 -2
  291. package/dist/service/stepfunctions/sim-step-functions.js +26 -9
  292. package/dist/service/sts/auth-z/assume-role-auth-z-coordinator.d.ts +9 -2
  293. package/dist/service/sts/auth-z/assume-role-auth-z-coordinator.js +2 -2
  294. package/dist/service/sts/auth-z/assume-role-source-account-auth-z.d.ts +10 -4
  295. package/dist/service/sts/auth-z/assume-role-source-account-auth-z.js +8 -7
  296. package/dist/service/sts/auth-z/assume-role-target-auth-z.d.ts +2 -2
  297. package/dist/service/sts/auth-z/assume-role-trust-policy-authorizer.d.ts +6 -2
  298. package/dist/service/sts/auth-z/assume-role-trust-policy-authorizer.js +14 -11
  299. package/dist/service/sts/command/assume-role/assume-role.handler.d.ts +10 -1
  300. package/dist/service/sts/command/assume-role/assume-role.handler.js +6 -2
  301. package/dist/service/sts/command/get-caller-identity/get-caller-identity.handler.d.ts +10 -1
  302. package/dist/service/sts/command/get-caller-identity/get-caller-identity.handler.js +5 -1
  303. package/dist/service/sts/service-role/sim-service-role.js +5 -1
  304. package/dist/service/sts/sim-sts.d.ts +18 -1
  305. package/dist/service/sts/sim-sts.js +8 -0
  306. package/dist/util/memo/bounded-memo.d.ts +36 -0
  307. package/dist/util/memo/bounded-memo.js +58 -0
  308. package/docs/README.md +54 -0
  309. package/docs/ai-skill/README.md +69 -0
  310. package/docs/cli/README.md +284 -0
  311. package/docs/factories/README.md +140 -0
  312. package/docs/lint/README.md +176 -0
  313. package/docs/non-aws-dependencies/README.md +261 -0
  314. package/docs/sdk/README.md +274 -0
  315. package/docs/serve/README.md +1126 -0
  316. package/docs/services/acm/README.md +823 -0
  317. package/docs/services/apigateway/README.md +1919 -0
  318. package/docs/services/apigatewayv2/README.md +2678 -0
  319. package/docs/services/athena/README.md +1044 -0
  320. package/docs/services/bedrock/README.md +350 -0
  321. package/docs/services/cloudformation/README.md +3625 -0
  322. package/docs/services/cloudfront/README.md +3098 -0
  323. package/docs/services/cloudwatch/README.md +422 -0
  324. package/docs/services/cognito/README.md +4924 -0
  325. package/docs/services/dynamodb/README.md +3785 -0
  326. package/docs/services/ecr/README.md +302 -0
  327. package/docs/services/ecs/README.md +2021 -0
  328. package/docs/services/elbv2/README.md +1901 -0
  329. package/docs/services/eventbridge/README.md +1118 -0
  330. package/docs/services/firehose/README.md +811 -0
  331. package/docs/services/glue/README.md +507 -0
  332. package/docs/services/iam/README.md +1578 -0
  333. package/docs/services/kinesis/README.md +455 -0
  334. package/docs/services/kms/README.md +664 -0
  335. package/docs/services/lambda/README.md +3719 -0
  336. package/docs/services/logs/README.md +882 -0
  337. package/docs/services/organizations/README.md +574 -0
  338. package/docs/services/personalize/README.md +835 -0
  339. package/docs/services/rekognition/README.md +1070 -0
  340. package/docs/services/route53/README.md +1783 -0
  341. package/docs/services/s3/README.md +3029 -0
  342. package/docs/services/scheduler/README.md +814 -0
  343. package/docs/services/secretsmanager/README.md +670 -0
  344. package/docs/services/ses/README.md +1013 -0
  345. package/docs/services/sns/README.md +1904 -0
  346. package/docs/services/sqs/README.md +1185 -0
  347. package/docs/services/ssm/README.md +1096 -0
  348. package/docs/services/stepfunctions/README.md +1341 -0
  349. package/docs/services/sts/README.md +245 -0
  350. package/docs/services/wafv2/README.md +1380 -0
  351. package/docs/terraform/README.md +248 -0
  352. package/docs/time/README.md +284 -0
  353. package/llms.txt +59 -0
  354. package/package.json +7 -4
  355. package/dist/service/stepfunctions/command/machine/sim-state-machine-writes.d.ts +0 -25
@@ -0,0 +1,1013 @@
1
+ # Simulated SES
2
+
3
+ Yulin includes a simulated Amazon SES for tests and local development, through the SES v2 API. It
4
+ holds email identities, applies the sandbox rules, and keeps a record of every message it would have
5
+ sent. A test can assert that signing someone up produced a welcome email addressed to them, without
6
+ an AWS account and without a mailbox to read.
7
+
8
+ There is no delivery to simulate. A message SES accepts leaves AWS for a mail system. The whole of
9
+ the observable AWS behaviour is whether SES would have accepted the message and what it would have
10
+ sent. That is what makes this service small and what makes it useful.
11
+
12
+ SES specific types are imported from the `@kensio/yulin/ses` subpath.
13
+
14
+ ## Asserting on a message that was sent
15
+
16
+ `sentEmails()` hands over the record. Each message carries who it was from, the three recipient
17
+ lists, the subject, the body and the message id SES answered with.
18
+
19
+ ```typescript sim-ses-send-and-assert
20
+ /**
21
+ * Sending a welcome email through simulated SES and asserting on it.
22
+ */
23
+
24
+ import { SendEmailCommand } from "@aws-sdk/client-sesv2";
25
+
26
+ import { SimAws } from "@kensio/yulin";
27
+
28
+ const simAws = new SimAws();
29
+ const ses = simAws.sesV2();
30
+
31
+ // Both ends have to be verified in the sandbox, which is where an account
32
+ // starts.
33
+ ses.verifyIdentity("hello@example.com");
34
+ ses.verifyIdentity("someone@example.org");
35
+
36
+ await ses.sendEmail(
37
+ new SendEmailCommand({
38
+ FromEmailAddress: "hello@example.com",
39
+ Destination: { ToAddresses: ["someone@example.org"] },
40
+ Content: {
41
+ Simple: {
42
+ Subject: { Data: "Welcome" },
43
+ Body: { Text: { Data: "Hi there, thanks for signing up." } },
44
+ },
45
+ },
46
+ }),
47
+ );
48
+
49
+ const [email] = ses.sentEmails();
50
+
51
+ // "Welcome" someone@example.org
52
+ console.log(email?.subject, email?.destination.toAddresses[0]);
53
+ ```
54
+
55
+ Messages come back in the order they were sent, and the first message of a flow is the first one
56
+ read. The three recipient lists stay apart, leaving a test free to assert that a bcc was a bcc.
57
+ `recipients` gathers all three where it makes no difference which was which.
58
+
59
+ `body` keeps `text` and `html` apart too. A message sent with only an HTML body reports `undefined`
60
+ for its text, and never the markup.
61
+
62
+ ## Verifying identities
63
+
64
+ Real SES verifies an email address by emailing it a link and a domain by looking for DNS records.
65
+ Neither can happen inside a test process, so verification here is the simulator's own operation
66
+ instead of an API call. `verifyIdentity` performs it, creating the identity where one is absent.
67
+
68
+ Everything else about identities is the ordinary SES API. `CreateEmailIdentity` starts one, and it
69
+ starts unverified, exactly as a real one does:
70
+
71
+ ```typescript sim-ses-identities
72
+ /**
73
+ * Creating an email identity, and verifying it the way only a simulator can.
74
+ */
75
+
76
+ import {
77
+ CreateEmailIdentityCommand,
78
+ GetEmailIdentityCommand,
79
+ } from "@aws-sdk/client-sesv2";
80
+
81
+ import { SimAws } from "@kensio/yulin";
82
+
83
+ const ses = new SimAws().sesV2();
84
+
85
+ await ses.createEmailIdentity(
86
+ new CreateEmailIdentityCommand({ EmailIdentity: "example.com" }),
87
+ );
88
+
89
+ const pending = await ses.getEmailIdentity(
90
+ new GetEmailIdentityCommand({ EmailIdentity: "example.com" }),
91
+ );
92
+
93
+ // "DOMAIN" "PENDING" false
94
+ console.log(
95
+ pending.IdentityType,
96
+ pending.VerificationStatus,
97
+ pending.VerifiedForSendingStatus,
98
+ );
99
+
100
+ // Standing in for the DNS records a real domain identity waits on.
101
+ ses.verifyIdentity("example.com");
102
+
103
+ const verified = await ses.getEmailIdentity(
104
+ new GetEmailIdentityCommand({ EmailIdentity: "example.com" }),
105
+ );
106
+
107
+ // "SUCCESS" true
108
+ console.log(verified.VerificationStatus, verified.VerifiedForSendingStatus);
109
+ ```
110
+
111
+ Whether an identity is an address or a domain follows from whether the name has an `@` in it. That
112
+ is how SES itself decides, with no parameter saying which is meant.
113
+
114
+ A verified domain covers every address at it, the whole reason domain identities exist. Its
115
+ subdomains are a separate matter, and `example.com` leaves `orders@mail.example.com` uncovered, here
116
+ or on real SES. Domains match without regard to case. The local part of an address is
117
+ case-sensitive, per RFC 5321, so `Sales@example.com` and `sales@example.com` are two identities.
118
+
119
+ `unverify()` on an identity puts it back to `PENDING`, as a real one goes when the records that
120
+ proved it stop resolving. That gives a test somewhere to go when it wants to see sending fail after
121
+ it once worked.
122
+
123
+ ## How an identity is configured
124
+
125
+ An identity holds the DKIM signing, custom MAIL FROM domain, feedback forwarding, configuration set
126
+ and tags it was created with, and `GetEmailIdentity` reads them back. The configuration set is the
127
+ one setting a send acts on, covered under
128
+ [Sending through a configuration set](#sending-through-a-configuration-set). The others are held and
129
+ reported. Each of them decides what happens to a message after it leaves AWS, where a test process
130
+ cannot watch.
131
+
132
+ A test can ask one question of it. Is the identity configured the way the stack said? That catches a
133
+ stack declaring DKIM wrongly, and a stack that stops declaring it.
134
+
135
+ ```typescript sim-ses-identity-settings
136
+ /**
137
+ * Asserting on the DKIM signing an identity was created with.
138
+ */
139
+
140
+ import {
141
+ CreateEmailIdentityCommand,
142
+ GetEmailIdentityCommand,
143
+ } from "@aws-sdk/client-sesv2";
144
+
145
+ import { SimAws } from "@kensio/yulin";
146
+
147
+ const ses = new SimAws().sesV2();
148
+
149
+ await ses.createEmailIdentity(
150
+ new CreateEmailIdentityCommand({
151
+ EmailIdentity: "example.com",
152
+ ConfigurationSetName: "transactional",
153
+ Tags: [{ Key: "team", Value: "orders" }],
154
+ }),
155
+ );
156
+
157
+ const identity = await ses.getEmailIdentity(
158
+ new GetEmailIdentityCommand({ EmailIdentity: "example.com" }),
159
+ );
160
+
161
+ // true "AWS_SES" 3
162
+ console.log(
163
+ identity.DkimAttributes?.SigningEnabled,
164
+ identity.DkimAttributes?.SigningAttributesOrigin,
165
+ identity.DkimAttributes?.Tokens?.length,
166
+ );
167
+
168
+ // "transactional" "orders"
169
+ console.log(identity.ConfigurationSetName, identity.Tags?.[0]?.Value);
170
+ ```
171
+
172
+ Easy DKIM is on for a domain identity, as it is for one real SES creates through the v2 API, and its
173
+ three tokens are the ones `Fn::GetAtt` publishes. An email address identity gets no DKIM, since the
174
+ records carrying it belong to the domain rather than to one mailbox at it.
175
+ `DkimSigningAttributes.DomainSigningSelector` switches the origin to `EXTERNAL` and leaves the
176
+ identity with no tokens of its own, the way real SES answers for a key the caller brought. The
177
+ private key beside it is dropped, because holding a secret nothing signs with is worse than
178
+ forgetting it.
179
+
180
+ `DkimAttributes.Status` and `MailFromAttributes.MailFromDomainStatus` both follow the identity's own
181
+ verification. Real SES waits on separate DNS records for each, and `verifyIdentity` here stands for
182
+ all of them at once.
183
+
184
+ ## Email templates
185
+
186
+ The assertion a test usually wants is "the welcome email went to this address, from this template,
187
+ with these substitutions". Asserting on the prose instead breaks whenever someone rewords it.
188
+ Storing the template in SES and sending from it by name is what makes the better assertion possible.
189
+
190
+ Templates are managed with `CreateEmailTemplate`, `GetEmailTemplate`, `UpdateEmailTemplate`,
191
+ `ListEmailTemplates` and `DeleteEmailTemplate`. A send carrying `Content.Template` renders the
192
+ stored wording against the JSON in `TemplateData`. The recorded send carries the template name and
193
+ the parsed data alongside the rendered result, leaving a test free to assert on either.
194
+
195
+ ```typescript sim-ses-templates
196
+ /**
197
+ * Sending from a stored template and asserting on the substitutions.
198
+ */
199
+
200
+ import {
201
+ CreateEmailTemplateCommand,
202
+ SendEmailCommand,
203
+ } from "@aws-sdk/client-sesv2";
204
+
205
+ import { SimAws } from "@kensio/yulin";
206
+
207
+ const ses = new SimAws().sesV2();
208
+
209
+ ses.verifyIdentity("hello@example.com");
210
+ ses.verifyIdentity("someone@example.org");
211
+
212
+ await ses.createEmailTemplate(
213
+ new CreateEmailTemplateCommand({
214
+ TemplateName: "welcome",
215
+ TemplateContent: {
216
+ Subject: "Welcome, {{name}}",
217
+ Text: "Hi {{name}}, thanks for signing up.",
218
+ Html: "<p>Hi {{name}}, thanks for signing up.</p>",
219
+ },
220
+ }),
221
+ );
222
+
223
+ await ses.sendEmail(
224
+ new SendEmailCommand({
225
+ FromEmailAddress: "hello@example.com",
226
+ Destination: { ToAddresses: ["someone@example.org"] },
227
+ Content: {
228
+ Template: { TemplateName: "welcome", TemplateData: '{"name":"Ada"}' },
229
+ },
230
+ }),
231
+ );
232
+
233
+ const [email] = ses.sentEmails();
234
+
235
+ // "welcome" { name: "Ada" } "Welcome, Ada"
236
+ console.log(email?.templateName, email?.templateData, email?.subject);
237
+ ```
238
+
239
+ A message written out in full reports `undefined` for both, leaving a test able to tell the two
240
+ kinds of send apart.
241
+
242
+ ### What the substitution does
243
+
244
+ Real SES renders templates with Handlebars, and this simulator renders the substitution part of it,
245
+ being `{{name}}` and dotted paths like `{{order.id}}`.
246
+
247
+ A placeholder naming something the data lacks renders as an empty string. That is what real SES
248
+ does, and it is much the commonest surprise in an SES template. The message goes out with a hole in
249
+ it and nothing reports a problem. Asserting on the rendered body is how that gets caught.
250
+
251
+ `{{name}}` HTML-escapes its value where `{{{name}}}` leaves it alone, again following Handlebars.
252
+ The escaping applies to the text part as well as the HTML one, because Handlebars renders a string
253
+ without knowing what it is for. A plain text email carrying an ampersand comes out with `&amp;` in
254
+ it.
255
+
256
+ Everything else Handlebars can do is refused where the template is written:
257
+
258
+ ```typescript sim-ses-template-refusals
259
+ /**
260
+ * The Handlebars this simulator will not render, refused at the template.
261
+ */
262
+
263
+ import { CreateEmailTemplateCommand } from "@aws-sdk/client-sesv2";
264
+
265
+ import { SimAws } from "@kensio/yulin";
266
+ import { SimSesUnsupportedOperationException } from "@kensio/yulin/ses";
267
+
268
+ const ses = new SimAws().sesV2();
269
+
270
+ try {
271
+ await ses.createEmailTemplate(
272
+ new CreateEmailTemplateCommand({
273
+ TemplateName: "welcome",
274
+ TemplateContent: {
275
+ Subject: "Welcome",
276
+ Text: "{{#if premium}}Thanks for subscribing{{/if}}",
277
+ },
278
+ }),
279
+ );
280
+ } catch (error) {
281
+ // true: block helpers, partials and comments are not rendered here, and a
282
+ // template carrying one is refused rather than sent with it still in place.
283
+ console.log(error instanceof SimSesUnsupportedOperationException);
284
+ }
285
+ ```
286
+
287
+ Refusing at the template is deliberate. It fails where the mistake is written, and a template
288
+ surviving into a sent message with `{{#if premium}}` still in it would make a test pass on a message
289
+ no real SES would produce.
290
+
291
+ `TemplateData` is checked only when a send carries it. Malformed JSON, or JSON that is anything but
292
+ an object, is refused. A send with no `TemplateData` at all is accepted and renders every
293
+ placeholder empty, as real SES treats it.
294
+
295
+ A send may name a stored template or write its wording out in `TemplateContent`, but not both.
296
+ Naming both is refused. Which of them real SES renders is beyond what this simulator knows, and
297
+ recording the message under a template it was not rendered from would be worse than failing.
298
+
299
+ ## Configuration sets
300
+
301
+ A configuration set is a named group of settings a send can be made under. Suppression reasons, the
302
+ sending switch, the delivery options and the reputation switch are all declared on one. Simulated
303
+ SES holds a set as state. A test can then assert what a stack declared, with no AWS account to read
304
+ it back from.
305
+
306
+ A set is attached to an identity, or named on a send. `SendingEnabled` is the one option a send acts
307
+ on. The rest are held for a test to read back.
308
+
309
+ ```typescript sim-ses-configuration-sets
310
+ /**
311
+ * Creating a configuration set and reading its settings back.
312
+ */
313
+
314
+ import {
315
+ CreateConfigurationSetCommand,
316
+ GetConfigurationSetCommand,
317
+ } from "@aws-sdk/client-sesv2";
318
+
319
+ import { SimAws } from "@kensio/yulin";
320
+
321
+ const ses = new SimAws().sesV2();
322
+
323
+ await ses.createConfigurationSet(
324
+ new CreateConfigurationSetCommand({
325
+ ConfigurationSetName: "transactional",
326
+ SuppressionOptions: { SuppressedReasons: ["BOUNCE", "COMPLAINT"] },
327
+ DeliveryOptions: { TlsPolicy: "REQUIRE" },
328
+ }),
329
+ );
330
+
331
+ const read = await ses.getConfigurationSet(
332
+ new GetConfigurationSetCommand({ ConfigurationSetName: "transactional" }),
333
+ );
334
+
335
+ // ["BOUNCE", "COMPLAINT"] true
336
+ console.log(
337
+ read.SuppressionOptions?.SuppressedReasons,
338
+ read.SendingOptions?.SendingEnabled,
339
+ );
340
+
341
+ // The simulator's own accessors, for a test that would rather skip a Command
342
+ // and its authorization.
343
+ const configurationSet = ses.findConfigurationSet("transactional");
344
+
345
+ // "REQUIRE"
346
+ console.log(configurationSet?.deliveryOptions.tlsPolicy);
347
+
348
+ // ["transactional"]
349
+ console.log(ses.allConfigurationSets().map((set) => set.configurationSetName));
350
+ ```
351
+
352
+ A set declaring only its name gets the defaults real SES applies. Sending is on, TLS is optional,
353
+ reputation metrics are off and no reason is suppressed. `GetConfigurationSet` reports those defaults
354
+ back rather than leaving the groups out of the answer.
355
+
356
+ `findConfigurationSet` reaches one set by name and `allConfigurationSets` hands over every set in
357
+ the scope, oldest first.
358
+
359
+ ### Sending through a configuration set
360
+
361
+ An identity carries a configuration set from `CreateEmailIdentity`, and `AWS::SES::EmailIdentity`
362
+ attaches one through `ConfigurationSetAttributes`. A send that names no set of its own goes through
363
+ the set its sending identity carries, and the recorded message names whichever set applied. A test
364
+ can then assert a message went through the right set without the code under test naming it at every
365
+ send.
366
+
367
+ A send that does name a set goes through that one. Where the sending address is an identity with a
368
+ set of its own and its domain is another, the address's set applies, as the more specific identity
369
+ does everywhere else here.
370
+
371
+ ```typescript sim-ses-configuration-set-attachment
372
+ /**
373
+ * Attaching a configuration set to an identity, and sending through it.
374
+ */
375
+
376
+ import {
377
+ CreateConfigurationSetCommand,
378
+ CreateEmailIdentityCommand,
379
+ SendEmailCommand,
380
+ } from "@aws-sdk/client-sesv2";
381
+
382
+ import { SimAws } from "@kensio/yulin";
383
+
384
+ const ses = new SimAws().sesV2();
385
+
386
+ await ses.createConfigurationSet(
387
+ new CreateConfigurationSetCommand({ ConfigurationSetName: "transactional" }),
388
+ );
389
+
390
+ await ses.createEmailIdentity(
391
+ new CreateEmailIdentityCommand({
392
+ EmailIdentity: "example.com",
393
+ ConfigurationSetName: "transactional",
394
+ }),
395
+ );
396
+
397
+ // Standing in for the DNS records a real domain identity waits on.
398
+ ses.verifyIdentity("example.com");
399
+ ses.verifyIdentity("someone@example.org");
400
+
401
+ await ses.sendEmail(
402
+ new SendEmailCommand({
403
+ FromEmailAddress: "hello@example.com",
404
+ Destination: { ToAddresses: ["someone@example.org"] },
405
+ Content: {
406
+ Simple: {
407
+ Subject: { Data: "Welcome" },
408
+ Body: { Text: { Data: "Hi there" } },
409
+ },
410
+ },
411
+ }),
412
+ );
413
+
414
+ // "transactional", off the identity, with the send naming nothing.
415
+ console.log(ses.sentEmails()[0]?.configurationSetName);
416
+ ```
417
+
418
+ A name that `CreateConfigurationSet` never created is accepted on both paths, and the record keeps
419
+ it. Real SES refuses one. Refusing here would fail a test over a set the developer left out of their
420
+ local setup. A test that wants the strict reading asks `findConfigurationSet` for the set and finds
421
+ nothing.
422
+
423
+ A set created with `SendingOptions.SendingEnabled` set to `false` refuses every send made through
424
+ it, with `SendingPausedException`. That switch is a declaration the developer wrote deliberately, and
425
+ a send through the set honours it. The refusal reaches a send that named the set and a send that
426
+ picked it up off its identity.
427
+
428
+ Sets are managed with `CreateConfigurationSet`, `GetConfigurationSet`, `ListConfigurationSets` and
429
+ `DeleteConfigurationSet`. There is no update. Real SES changes a set through a `Put` command per
430
+ group of options, and none of those is here yet. A set holds what it was created with.
431
+
432
+ `ListConfigurationSets` answers names alone, as real SES does. A caller after the settings reads one
433
+ set at a time.
434
+
435
+ `TrackingOptions` and `VdmOptions` are refused by name. Open and click tracking needs a redirect
436
+ domain and the events that report a click. The Virtual Deliverability Manager reports on engagement,
437
+ which this simulation never measures.
438
+
439
+ A set's suppression reasons are held and read back, and that is all they do. On real SES they decide
440
+ what a bounce or a complaint would add to the account suppression list. Both are absent here. The
441
+ list itself is a separate thing, filled by hand.
442
+
443
+ `TlsPolicy` accepts `REQUIRE` and `OPTIONAL` and refuses anything else, and a `SuppressedReasons`
444
+ entry that is neither `BOUNCE` nor `COMPLAINT` is refused too. `MaxDeliverySeconds` takes whole
445
+ seconds from 300 to 50400, the five minutes to fourteen hours real SES attempts delivery for. A name
446
+ is letters, digits, dashes and underscores. All of it is validated in the command, so a template and
447
+ an SDK caller hear the same answer.
448
+
449
+ ## Deploying SES resources with CloudFormation
450
+
451
+ `AWS::SES::EmailIdentity`, `AWS::SES::Template` and `AWS::SES::ConfigurationSet` deploy into
452
+ simulated SES. A project that declares them in CDK or CloudFormation can deploy the same template
453
+ its application deploys, with no hand-written test setup.
454
+
455
+ ```typescript sim-ses-cloudformation
456
+ /**
457
+ * Deploying an SES identity and template, then sending from them.
458
+ */
459
+
460
+ import { SendEmailCommand } from "@aws-sdk/client-sesv2";
461
+
462
+ import { SimAws } from "@kensio/yulin";
463
+
464
+ const simAws = new SimAws();
465
+
466
+ await simAws.cloudFormation().deployTemplate({
467
+ stackName: "orders",
468
+ template: {
469
+ Resources: {
470
+ SenderIdentity: {
471
+ Type: "AWS::SES::EmailIdentity",
472
+ Properties: { EmailIdentity: "example.com" },
473
+ },
474
+ WelcomeEmail: {
475
+ Type: "AWS::SES::Template",
476
+ Properties: {
477
+ Template: {
478
+ TemplateName: "welcome",
479
+ SubjectPart: "Welcome, {{name}}",
480
+ TextPart: "Hi {{name}}",
481
+ },
482
+ },
483
+ },
484
+ },
485
+ },
486
+ });
487
+
488
+ const ses = simAws.sesV2();
489
+
490
+ // The stack leaves the identity unverified, as a real deploy does. Verifying
491
+ // finds the one the stack made rather than creating a second.
492
+ ses.verifyIdentity("example.com");
493
+ ses.verifyIdentity("example.org");
494
+
495
+ await ses.sendEmail(
496
+ new SendEmailCommand({
497
+ FromEmailAddress: "hello@example.com",
498
+ Destination: { ToAddresses: ["someone@example.org"] },
499
+ Content: {
500
+ Template: { TemplateName: "welcome", TemplateData: '{"name":"Ada"}' },
501
+ },
502
+ }),
503
+ );
504
+
505
+ // "Welcome, Ada"
506
+ console.log(ses.sentEmails()[0]?.subject);
507
+ ```
508
+
509
+ An identity deploys **unverified**. That is what a real deploy leaves behind, with the confirmation
510
+ link or the DKIM records still to be dealt with out of band. Verify it afterwards with
511
+ `verifyIdentity`, in that order. Verifying first and deploying second fails the deploy, because
512
+ CloudFormation is creating an identity that is already there.
513
+
514
+ `Ref` on an identity returns the address or domain itself, directly usable as a
515
+ `FromEmailAddress`. `Ref` on a template, and its `Id` attribute, both return the template name.
516
+ `Ref` on a configuration set returns its name. That Resource type has no `Fn::GetAtt` attributes at
517
+ all, so reading one fails the deploy rather than answering something AWS would not. A set with no
518
+ `Name` is named after the stack, the logical ID and a tail derived from both, as
519
+ [the CloudFormation docs](https://yulinsim.dev/services/cloudformation/#names-cloudformation-generates "Names CloudFormation generates")
520
+ describe.
521
+
522
+ Deleting the stack removes all three.
523
+
524
+ ### DKIM tokens
525
+
526
+ `Fn::GetAtt` on an identity reads the six DKIM token attributes, and this simulator answers them
527
+ with tokens it made up. They are derived from the identity's own name, and come out the same on every
528
+ run. They are invented, and no message here is signed.
529
+
530
+ They exist because `ses.Identity.publicHostedZone()` in CDK emits three `AWS::Route53::RecordSet`
531
+ Resources reading exactly these attributes. Refusing them would take an ordinary CDK stack down over
532
+ records this simulation never reads. The stack deploys with records of the right shape and no
533
+ target.
534
+
535
+ ### What an identity Resource carries
536
+
537
+ `EmailIdentity` names the identity. `DkimAttributes`, `DkimSigningAttributes`, `MailFromAttributes`,
538
+ `FeedbackAttributes`, `ConfigurationSetAttributes` and `Tags` are all held on the deployed identity
539
+ and read back by `GetEmailIdentity`, as described under
540
+ [How an identity is configured](#how-an-identity-is-configured). A stack that declares DKIM signing
541
+ can assert the identity it deployed is the one it described.
542
+
543
+ The settings land on the identity after it is created, which is the order real CloudFormation works
544
+ in. Two of them have no `CreateEmailIdentity` parameter on real SES either, and are put on the
545
+ identity by a separate call once it exists.
546
+
547
+ `DkimSigningAttributes.DomainSigningPrivateKey` is the one part dropped, and it turns up on
548
+ `stack.ignoredProperties` with the reason. A property this Resource type has no name for lands there
549
+ too, which in practice catches a misspelling. Real CloudFormation refuses a property it does not
550
+ recognise, and a stack failing over a property AWS added last week is a worse way to find out.
551
+
552
+ A template Resource has no such list, because everything `AWS::SES::Template` can usefully say is
553
+ wording and all of it is acted on. Anything else it says is still reported, at both levels. That
554
+ covers a property beside `Template`, and a part inside it that is none of the four. In practice it
555
+ catches a misspelling. `TextPart` written `Textpart` would otherwise send a message with no body and
556
+ no explanation for it.
557
+
558
+ A template carrying Handlebars this simulator leaves unrendered is a different matter, and fails the
559
+ deploy where it would otherwise sit in the stack waiting to fail at the first send.
560
+
561
+ ### What a configuration set Resource is deployed without
562
+
563
+ `Name`, `SuppressionOptions`, `SendingOptions`, `DeliveryOptions` and `ReputationOptions` are acted
564
+ on. `TrackingOptions` and `VdmOptions` are recorded as ignored and the set is created without them. That
565
+ is the same split the identity Resource has. The SDK path refuses both by name, and a template
566
+ is a whole document one property should leave standing.
567
+
568
+ A set naming a suppression reason or a TLS policy SES has no meaning for does fail the deploy. The
569
+ Resource is created through `CreateConfigurationSet`. The validation is the command's, and there is
570
+ one answer whoever asked.
571
+
572
+ ## The sandbox
573
+
574
+ An account starts in the SES sandbox, where **both** the sender and every recipient have to be
575
+ verified. That is the state most tests should be written against. It is the configuration that
576
+ refuses to mail an address nobody verified, and catching that refusal in a test is much better than
577
+ catching it in an account.
578
+
579
+ Outside the sandbox only the sender is checked. `PutAccountDetails` with `ProductionAccessEnabled`
580
+ is how an account gets there:
581
+
582
+ ```typescript sim-ses-sandbox
583
+ /**
584
+ * The sandbox rules, and leaving the sandbox.
585
+ */
586
+
587
+ import {
588
+ PutAccountDetailsCommand,
589
+ SendEmailCommand,
590
+ } from "@aws-sdk/client-sesv2";
591
+
592
+ import { SimAws } from "@kensio/yulin";
593
+ import { SimSesMessageRejected } from "@kensio/yulin/ses";
594
+
595
+ const ses = new SimAws().sesV2();
596
+
597
+ ses.verifyIdentity("hello@example.com");
598
+
599
+ const message = new SendEmailCommand({
600
+ FromEmailAddress: "hello@example.com",
601
+ Destination: { ToAddresses: ["someone@example.org"] },
602
+ Content: {
603
+ Simple: {
604
+ Subject: { Data: "Welcome" },
605
+ Body: { Text: { Data: "Hi there" } },
606
+ },
607
+ },
608
+ });
609
+
610
+ try {
611
+ await ses.sendEmail(message);
612
+ } catch (error) {
613
+ // MessageRejected: the recipient is not verified and this account is still
614
+ // in the sandbox.
615
+ console.log(error instanceof SimSesMessageRejected, ses.isInSandbox());
616
+ }
617
+
618
+ await ses.putAccountDetails(
619
+ new PutAccountDetailsCommand({
620
+ MailType: "TRANSACTIONAL",
621
+ WebsiteURL: "https://example.com",
622
+ ProductionAccessEnabled: true,
623
+ }),
624
+ );
625
+
626
+ await ses.sendEmail(message);
627
+
628
+ // 1
629
+ console.log(ses.sentEmails().length);
630
+ ```
631
+
632
+ A rejection names every identity that failed the check in one message, the way real SES does. A
633
+ caller finds out everything it has to verify from one failure:
634
+
635
+ ```text
636
+ Email address is not verified. The following identities failed the check in region US-EAST-1: someone@example.org
637
+ ```
638
+
639
+ Real SES treats `ProductionAccessEnabled` as a request that a human at AWS then reviews, and an
640
+ account stays in the sandbox until that review lands. Granting it immediately is a deliberate
641
+ divergence. The alternative is a simulator no test can get out of the sandbox in, and waiting for a
642
+ review is beyond what a test can assert on anyway.
643
+
644
+ ## The suppression list
645
+
646
+ Real SES holds an account-level suppression list and fills it from hard bounces and complaints.
647
+ Nothing bounces here, so every address on this one was put there by a caller. That is what makes it
648
+ worth having in a test. The support tool that lists suppressed addresses, the form that removes one
649
+ and the script that seeds the list all have somewhere to run.
650
+
651
+ `PutSuppressedDestination`, `GetSuppressedDestination`, `ListSuppressedDestinations` and
652
+ `DeleteSuppressedDestination` manage it.
653
+
654
+ ```typescript sim-ses-suppression
655
+ /**
656
+ * Suppressing an address, and what a send to it records.
657
+ */
658
+
659
+ import {
660
+ PutSuppressedDestinationCommand,
661
+ SendEmailCommand,
662
+ } from "@aws-sdk/client-sesv2";
663
+
664
+ import { SimAws } from "@kensio/yulin";
665
+
666
+ const ses = new SimAws().sesV2();
667
+
668
+ ses.verifyIdentity("hello@example.com");
669
+ ses.verifyIdentity("someone@example.org");
670
+
671
+ await ses.putSuppressedDestination(
672
+ new PutSuppressedDestinationCommand({
673
+ EmailAddress: "someone@example.org",
674
+ Reason: "BOUNCE",
675
+ }),
676
+ );
677
+
678
+ // SES accepts this and holds it back from the recipient.
679
+ await ses.sendEmail(
680
+ new SendEmailCommand({
681
+ FromEmailAddress: "hello@example.com",
682
+ Destination: { ToAddresses: ["someone@example.org"] },
683
+ Content: {
684
+ Simple: {
685
+ Subject: { Data: "Welcome" },
686
+ Body: { Text: { Data: "Hi there" } },
687
+ },
688
+ },
689
+ }),
690
+ );
691
+
692
+ const [email] = ses.sentEmails();
693
+
694
+ // "someone@example.org" "BOUNCE" true
695
+ console.log(
696
+ email?.suppressedRecipients[0]?.emailAddress,
697
+ email?.suppressedRecipients[0]?.reason,
698
+ email?.isFullySuppressed,
699
+ );
700
+ ```
701
+
702
+ A send to a suppressed address is accepted. Real SES takes the message, holds it back from that
703
+ recipient, and counts it toward the daily sending quota. The send succeeds here too, and the record
704
+ carries the answer. `suppressedRecipients` names who was held back and why,
705
+ and `isFullySuppressed` is the narrower question of whether the message reached nobody. A message to
706
+ two recipients with one of them suppressed went to the other.
707
+
708
+ `ListSuppressedDestinations` pages with `PageSize` and `NextToken`, and narrows with `Reasons`,
709
+ `StartDate` and `EndDate`. Removing an address that was never on the list succeeds, so a form that
710
+ removes one twice has no failure to handle.
711
+
712
+ ### What the account is suppressing for
713
+
714
+ An address is held back only when the account is suppressing for the reason it was listed under. An
715
+ address on the list for `COMPLAINT`, on an account suppressing only `BOUNCE`, is mailed. That is
716
+ much the easiest part of the suppression rules to get wrong, and it is worth a test.
717
+
718
+ `PutAccountSuppressionAttributes` sets the reasons and `GetAccount` reports them as
719
+ `SuppressionAttributes`. An account here starts on both, where every real account opened after
720
+ November 2019 starts. Putting the attributes with no reasons at all turns the list off, which is
721
+ what the console's Enabled box does. The addresses stay on the list and SES stops reading it.
722
+
723
+ ### Case, and the sandbox
724
+
725
+ Managing the list is case sensitive and sending is not, following real SES. `Someone@example.org` is
726
+ stored as written and `DeleteSuppressedDestination` needs that spelling to remove it, while a
727
+ message addressed to `SOMEONE@example.org` is held back by a listed `someone@example.org`.
728
+
729
+ Real SES refuses `PutSuppressedDestination` until an account leaves the sandbox. This one accepts it
730
+ either way. The sandbox is kept here so that a send to an unverified recipient fails the way it
731
+ would in an account, and making every test that seeds this list leave the sandbox first buys
732
+ nothing.
733
+
734
+ ## Messages another service sends
735
+
736
+ A simulated Cognito user pool whose `EmailConfiguration` names `EmailSendingAccount: DEVELOPER`
737
+ sends its verification messages and invitations through the SES of the region its `SourceArn` names.
738
+ Those messages land in `sentEmails()` alongside the ones an SDK client sent, and the sandbox and
739
+ suppression rules above decide them the same way. See
740
+ [Sending a pool's email through SES](https://yulinsim.dev/services/cognito/#sending-a-pools-email-through-ses).
741
+
742
+ Such a send skips IAM. Real Cognito sends through a service-linked role rather than as whoever
743
+ called `SignUp`, so the permissions of that caller decide nothing about it. Nothing else about the
744
+ send differs. The sender is checked, the sandbox checks the recipient, and the message is
745
+ recorded.
746
+
747
+ ## Messages on the console
748
+
749
+ `sentEmails()` is test code. A dev server has the same messages going past and nothing to read them
750
+ with, so `serveSimAws` prints a summary of each one as SES accepts it:
751
+
752
+ ```
753
+ sim SES: hello@example.com to alice@example.com, bcc audit@example.com
754
+ Subject: Reset your password
755
+ Template: password-reset {"code":"483920"}
756
+ Text body:
757
+ Follow this link to reset your password.
758
+ https://app.example.com/reset?token=abc123
759
+ HTML body: 4.1 kB, not printed
760
+ ```
761
+
762
+ The first line holds the sender and the three recipient lists, with an empty list left out. Under it
763
+ come the subject, the template the message was rendered from and the data it was filled with, and
764
+ the text part. An HTML part is measured and left out, because kilobytes of markup on the console
765
+ bury the rest of the block.
766
+
767
+ The text part is printed up to 2000 characters, and what runs past that is counted. Move the limit
768
+ with `emailTextLimit`, and turn the SES lines off with `ses: false`, both on the `messageLogging`
769
+ option. See [Messages on the console](https://yulinsim.dev/serve/#messages-on-the-console) for the rest of
770
+ it.
771
+
772
+ A user pool sending through SES prints twice, once for the SES send and once for the message the
773
+ pool kept. Both services recorded it, and each block says what that service holds. See
774
+ [Sending a pool's email through SES](https://yulinsim.dev/services/cognito/#sending-a-pools-email-through-ses).
775
+
776
+ ## Permissions
777
+
778
+ Every command authorizes through simulated IAM. A send authorizes against the identity being sent
779
+ **from**, and recipients never enter into it. That is worth knowing when a policy looks like it
780
+ should cover a send and fails to.
781
+
782
+ ```typescript sim-ses-permissions
783
+ /**
784
+ * A Role that may only send from one domain.
785
+ */
786
+
787
+ import { CreateRoleCommand, PutRolePolicyCommand } from "@aws-sdk/client-iam";
788
+ import { SendEmailCommand } from "@aws-sdk/client-sesv2";
789
+
790
+ import { SimAws } from "@kensio/yulin";
791
+
792
+ const simAws = new SimAws({ defaultAccountId: "111111111111" });
793
+ const ses = simAws.sesV2();
794
+
795
+ ses.verifyIdentity("example.com");
796
+
797
+ await simAws.iam().createRole(
798
+ new CreateRoleCommand({
799
+ RoleName: "SignUpFunctionRole",
800
+ AssumeRolePolicyDocument: JSON.stringify({
801
+ Version: "2012-10-17",
802
+ Statement: [
803
+ {
804
+ Effect: "Allow",
805
+ Principal: { Service: "lambda.amazonaws.com" },
806
+ Action: "sts:AssumeRole",
807
+ },
808
+ ],
809
+ }),
810
+ }),
811
+ );
812
+
813
+ await simAws.iam().putRolePolicy(
814
+ new PutRolePolicyCommand({
815
+ RoleName: "SignUpFunctionRole",
816
+ PolicyName: "SendWelcomeEmail",
817
+ PolicyDocument: JSON.stringify({
818
+ Version: "2012-10-17",
819
+ Statement: [
820
+ {
821
+ Effect: "Allow",
822
+ Action: "ses:SendEmail",
823
+ Resource: "arn:aws:ses:us-east-1:111111111111:identity/example.com",
824
+ },
825
+ ],
826
+ }),
827
+ }),
828
+ );
829
+
830
+ await ses.sendEmail(
831
+ new SendEmailCommand({
832
+ FromEmailAddress: "anything@example.com",
833
+ Destination: { ToAddresses: ["someone@example.com"] },
834
+ Content: {
835
+ Simple: {
836
+ Subject: { Data: "Welcome" },
837
+ Body: { Text: { Data: "Hi there" } },
838
+ },
839
+ },
840
+ }),
841
+ {
842
+ caller: {
843
+ kind: "arn",
844
+ arn: "arn:aws:iam::111111111111:role/SignUpFunctionRole",
845
+ },
846
+ },
847
+ );
848
+
849
+ // 1
850
+ console.log(ses.sentEmails().length);
851
+ ```
852
+
853
+ The more specific identity wins when both exist. A policy naming `identity/example.com` covers a
854
+ send from any address at the domain, unless that address is an identity in its own right, in which
855
+ case the send authorizes against `identity/hello@example.com` instead.
856
+
857
+ `ses:ListEmailIdentities`, `ses:GetAccount` and `ses:PutAccountDetails` have no resource type at all
858
+ on real SES, and only a policy written against `*` allows them. A policy scoped to identity ARNs
859
+ allows none of the three. Not even one written against `identity/*`, the intuitive reading and the
860
+ wrong one.
861
+
862
+ IAM is evaluated before the identity check, as it is on real AWS. A caller with no permission is
863
+ refused whether or not its identities are verified. The error a test sees says which of the two is
864
+ wrong.
865
+
866
+ ## SDK interception
867
+
868
+ An intercepted `SESv2Client` reaches simulated SES, served in process:
869
+
870
+ ```typescript sim-ses-sdk-interception
871
+ /**
872
+ * Application code sending through an intercepted SES client.
873
+ */
874
+
875
+ import { SendEmailCommand, SESv2Client } from "@aws-sdk/client-sesv2";
876
+
877
+ import { SimSdk } from "@kensio/yulin/sdk";
878
+
879
+ using simSdk = new SimSdk();
880
+ simSdk.intercept(SESv2Client);
881
+
882
+ const scoped = simSdk.simAws.accountRegionScope(
883
+ simSdk.simAws.defaultAccountId,
884
+ "eu-west-2",
885
+ );
886
+
887
+ scoped.sesV2().verifyIdentity("example.com");
888
+ scoped.sesV2().verifyIdentity("example.org");
889
+
890
+ // Ordinary application code, unaware it is not talking to AWS.
891
+ const client = new SESv2Client({ region: "eu-west-2" });
892
+
893
+ await client.send(
894
+ new SendEmailCommand({
895
+ FromEmailAddress: "hello@example.com",
896
+ Destination: { ToAddresses: ["someone@example.org"] },
897
+ Content: {
898
+ Simple: {
899
+ Subject: { Data: "Welcome" },
900
+ Body: { Text: { Data: "Hi there" } },
901
+ },
902
+ },
903
+ }),
904
+ );
905
+
906
+ // "Welcome"
907
+ console.log(scoped.sesV2().sentEmails()[0]?.subject);
908
+ ```
909
+
910
+ ## Reading the account
911
+
912
+ `GetAccount` reports whether the account has production access and what it may send:
913
+
914
+ ```typescript sim-ses-account
915
+ /**
916
+ * Reading the sandbox state and the sending limits.
917
+ */
918
+
919
+ import { GetAccountCommand } from "@aws-sdk/client-sesv2";
920
+
921
+ import { SimAws } from "@kensio/yulin";
922
+
923
+ const account = await new SimAws()
924
+ .sesV2()
925
+ .getAccount(new GetAccountCommand({}));
926
+
927
+ // false 200 1
928
+ console.log(
929
+ account.ProductionAccessEnabled,
930
+ account.SendQuota?.Max24HourSend,
931
+ account.SendQuota?.MaxSendRate,
932
+ );
933
+ ```
934
+
935
+ The quota figures are the real sandbox and production ones, and both are reported without being
936
+ enforced. `SentLast24Hours` counts what was actually sent, on the simulated clock. A test that moves
937
+ time forward past the window sees the count fall the way an account's would.
938
+
939
+ ## Simulated commands
940
+
941
+ | Command | Notes |
942
+ | --------------------------------- | --------------------------------------------------------------------------------------------------------- |
943
+ | `SendEmail` | `Content.Simple` and `Content.Template`. Recorded rather than delivered. |
944
+ | `CreateEmailIdentity` | Starts unverified. `Tags`, `DkimSigningAttributes` and `ConfigurationSetName` are held and reported back. |
945
+ | `GetEmailIdentity` | Reports the DKIM, MAIL FROM, feedback, configuration set and tag settings the identity holds. |
946
+ | `ListEmailIdentities` | Paged with `PageSize` and `NextToken`. |
947
+ | `DeleteEmailIdentity` | |
948
+ | `CreateEmailTemplate` | Substitution only. `Tags` are refused. |
949
+ | `GetEmailTemplate` | Reports the wording with its placeholders unrendered. |
950
+ | `UpdateEmailTemplate` | Replaces the wording outright, keeping the creation time. |
951
+ | `ListEmailTemplates` | Names and creation times only, paged. |
952
+ | `DeleteEmailTemplate` | |
953
+ | `CreateConfigurationSet` | `TrackingOptions`, `VdmOptions` and `Tags` are refused. |
954
+ | `GetConfigurationSet` | Reports the defaults it applied as well as what was declared. |
955
+ | `ListConfigurationSets` | Names only, paged with `PageSize` and `NextToken`. |
956
+ | `DeleteConfigurationSet` | |
957
+ | `GetAccount` | Reports `SuppressionAttributes` alongside the quota. |
958
+ | `PutAccountDetails` | `MailType` and `WebsiteURL` are required, as on real SES. |
959
+ | `PutAccountSuppressionAttributes` | No reasons at all turns the suppression list off. |
960
+ | `PutSuppressedDestination` | Accepted in the sandbox, which real SES refuses. |
961
+ | `GetSuppressedDestination` | |
962
+ | `ListSuppressedDestinations` | Paged, and narrowed by `Reasons`, `StartDate` and `EndDate`. |
963
+ | `DeleteSuppressedDestination` | Removing an address that is not on the list succeeds. |
964
+
965
+ Anything else refuses on send with `SimSdkUnsupportedCommandError`.
966
+
967
+ ## Divergences and limitations
968
+
969
+ - **Verification is a simulator call.** `verifyIdentity` has no counterpart on AWS. It is the only
970
+ way an identity becomes verified here, because the real mechanisms are an emailed link and a DNS
971
+ record.
972
+ - **Production access is granted on request.** Real SES has a human review it first.
973
+ - **Send quotas are reported, not enforced.** A send past the daily figure still succeeds, and
974
+ a per-second rate would cost real time to respect.
975
+ - **`Content.Raw` is refused by name.** A raw MIME message would have to be parsed to say anything
976
+ about its subject or body.
977
+ - **Only Handlebars substitution is rendered.** Block helpers, partials and comments are refused at
978
+ the template. Template data holding an object where the template wants a value is refused too,
979
+ where real Handlebars would render `[object Object]`.
980
+ - **`SendBulkEmail` is absent**, along with its per-recipient replacement data.
981
+ - **Nothing is delivered, and nothing bounces.** There are no bounce or complaint events and no
982
+ event destinations.
983
+ - **A configuration set acts on one send.** `SendingEnabled` refuses a send made through the set.
984
+ The suppression reasons, delivery options and reputation switch are held and read back, and
985
+ nothing acts on those.
986
+ - **A set name nothing created is still accepted.** Real SES refuses one on an identity and on a
987
+ send. Both stand here and the name is recorded, because a test failing over a set missing from a
988
+ local setup fails for a reason unrelated to what it asserts.
989
+ - **A configuration set holds what it was created with.** The `Put` commands that change one group
990
+ of options are absent. A set cannot be changed once it exists.
991
+ - **The suppression list fills only by hand.** Every address on it was put there by a caller,
992
+ because no message here ever bounces. A configuration set's `SuppressedReasons` name what a bounce
993
+ or a complaint would suppress for, and both are absent.
994
+ - **Tenant-level suppression lists are left out.** A suppression command carrying `TenantName` is
995
+ refused rather than answered from the account-level list.
996
+ - **`PutSuppressedDestination` works in the sandbox.** Real SES refuses it until an account has
997
+ production access.
998
+ - **DKIM tokens are made up.** They are stable per identity so a test can assert on them, and they
999
+ prove no ownership of anything.
1000
+ - **Only `AWS::SES::EmailIdentity`, `AWS::SES::Template` and `AWS::SES::ConfigurationSet` deploy.**
1001
+ `AWS::SES::ConfigurationSetEventDestination`, `AWS::SES::ContactList`, `AWS::SES::ReceiptRule` and
1002
+ the rest are left out.
1003
+ - **SES v2 only.** The older `@aws-sdk/client-ses` API is absent.
1004
+ - **DKIM and MAIL FROM domains are recorded, never performed.** An identity reports the signing and
1005
+ envelope sender settings it was created with. No message is signed, no signature is checked, and
1006
+ no MX record is looked for. Deliverability is decided outside AWS, where a test process cannot
1007
+ follow.
1008
+ - **The commands that change an identity's settings are absent.** `PutEmailIdentityDkimAttributes`,
1009
+ `PutEmailIdentityMailFromAttributes` and `PutEmailIdentityFeedbackAttributes` have no counterpart
1010
+ here. A CloudFormation deploy sets all three, and `CreateEmailIdentity` sets the rest.
1011
+ - **Sending authorization policies are left out.** A Cognito user pool sending through an identity
1012
+ is checked only for that identity being verified, where real Cognito needs a policy on the
1013
+ identity allowing it as well.