From 5f0a4c9971e5ecfaff28fd5d1a51fa35e776e409 Mon Sep 17 00:00:00 2001
From: Victor Korzunin <5180700+floydspace@users.noreply.github.com>
Date: Thu, 21 Sep 2023 20:20:28 +0200
Subject: [PATCH] feat: implement effectful sns client
---
.changeset/large-carrots-beam.md | 5 +
.projenrc.ts | 13 +
README.md | 2 +-
package.json | 1 +
packages/client-sns/.eslintrc.json | 131 ++++++
packages/client-sns/.gitattributes | 21 +
packages/client-sns/.gitignore | 46 ++
packages/client-sns/.npmignore | 19 +
packages/client-sns/.prettierignore | 1 +
packages/client-sns/.prettierrc.json | 3 +
packages/client-sns/.projen/deps.json | 107 +++++
packages/client-sns/.projen/files.json | 20 +
packages/client-sns/.projen/tasks.json | 112 +++++
packages/client-sns/LICENSE | 19 +
packages/client-sns/README.md | 1 +
packages/client-sns/jest.config.json | 37 ++
packages/client-sns/package.json | 59 +++
packages/client-sns/project.json | 77 ++++
packages/client-sns/src/Context.ts | 39 ++
packages/client-sns/src/SNS.ts | 556 +++++++++++++++++++++++++
packages/client-sns/src/index.ts | 2 +
packages/client-sns/test/SNS.test.ts | 137 ++++++
packages/client-sns/tsconfig.dev.json | 37 ++
packages/client-sns/tsconfig.esm.json | 10 +
packages/client-sns/tsconfig.json | 35 ++
pnpm-lock.yaml | 113 +++++
pnpm-workspace.yaml | 1 +
27 files changed, 1603 insertions(+), 1 deletion(-)
create mode 100644 .changeset/large-carrots-beam.md
create mode 100644 packages/client-sns/.eslintrc.json
create mode 100644 packages/client-sns/.gitattributes
create mode 100644 packages/client-sns/.gitignore
create mode 100644 packages/client-sns/.npmignore
create mode 100644 packages/client-sns/.prettierignore
create mode 100644 packages/client-sns/.prettierrc.json
create mode 100644 packages/client-sns/.projen/deps.json
create mode 100644 packages/client-sns/.projen/files.json
create mode 100644 packages/client-sns/.projen/tasks.json
create mode 100644 packages/client-sns/LICENSE
create mode 100644 packages/client-sns/README.md
create mode 100644 packages/client-sns/jest.config.json
create mode 100644 packages/client-sns/package.json
create mode 100644 packages/client-sns/project.json
create mode 100644 packages/client-sns/src/Context.ts
create mode 100644 packages/client-sns/src/SNS.ts
create mode 100644 packages/client-sns/src/index.ts
create mode 100644 packages/client-sns/test/SNS.test.ts
create mode 100644 packages/client-sns/tsconfig.dev.json
create mode 100644 packages/client-sns/tsconfig.esm.json
create mode 100644 packages/client-sns/tsconfig.json
diff --git a/.changeset/large-carrots-beam.md b/.changeset/large-carrots-beam.md
new file mode 100644
index 0000000..b8931df
--- /dev/null
+++ b/.changeset/large-carrots-beam.md
@@ -0,0 +1,5 @@
+---
+"@effect-aws/client-sns": minor
+---
+
+implement effectful sns client
diff --git a/.projenrc.ts b/.projenrc.ts
index e2716e7..8d0b834 100644
--- a/.projenrc.ts
+++ b/.projenrc.ts
@@ -51,6 +51,19 @@ new TypeScriptLibProject({
peerDeps: ["@effect/data@^0.18.4", "@effect/io@^0.40.0"],
});
+new TypeScriptLibProject({
+ parent: project,
+ name: "client-sns",
+ deps: ["@aws-sdk/types@^3", "@aws-sdk/client-sns@^3"],
+ devDeps: [
+ "@effect/data@^0.18.4",
+ "@effect/io@^0.40.0",
+ "aws-sdk-client-mock",
+ "aws-sdk-client-mock-jest",
+ ],
+ peerDeps: ["@effect/data@^0.18.4", "@effect/io@^0.40.0"],
+});
+
project.addGitIgnore(".direnv/"); // flake environment creates .direnv folder
project.synth();
diff --git a/README.md b/README.md
index 6db4e4c..15d025f 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ Effect Docs: https://www.effect.website
- [x] S3 Client
- [ ] DynamoDB Client
- [ ] SQS Client
-- [ ] SNS Client
+- [x] SNS Client
- [ ] EventBridge Client
- [ ] Lambda Client
diff --git a/package.json b/package.json
index 6bfea3e..2e6fc8b 100644
--- a/package.json
+++ b/package.json
@@ -77,6 +77,7 @@
"workspaces": {
"packages": [
"packages/client-s3",
+ "packages/client-sns",
"packages/powertools-logger"
]
},
diff --git a/packages/client-sns/.eslintrc.json b/packages/client-sns/.eslintrc.json
new file mode 100644
index 0000000..140ba19
--- /dev/null
+++ b/packages/client-sns/.eslintrc.json
@@ -0,0 +1,131 @@
+// ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen".
+{
+ "env": {
+ "jest": true,
+ "node": true
+ },
+ "root": true,
+ "plugins": [
+ "@typescript-eslint",
+ "import",
+ "prettier"
+ ],
+ "parser": "@typescript-eslint/parser",
+ "parserOptions": {
+ "ecmaVersion": 2018,
+ "sourceType": "module",
+ "project": "./tsconfig.dev.json"
+ },
+ "extends": [
+ "plugin:import/typescript",
+ "prettier",
+ "plugin:prettier/recommended"
+ ],
+ "settings": {
+ "import/parsers": {
+ "@typescript-eslint/parser": [
+ ".ts",
+ ".tsx"
+ ]
+ },
+ "import/resolver": {
+ "node": {},
+ "typescript": {
+ "project": "./tsconfig.dev.json",
+ "alwaysTryTypes": true
+ }
+ }
+ },
+ "ignorePatterns": [
+ "*.js",
+ "*.d.ts",
+ "node_modules/",
+ "*.generated.ts",
+ "coverage"
+ ],
+ "rules": {
+ "prettier/prettier": [
+ "error"
+ ],
+ "@typescript-eslint/no-require-imports": [
+ "error"
+ ],
+ "import/no-extraneous-dependencies": [
+ "error",
+ {
+ "devDependencies": [
+ "**/test/**",
+ "**/build-tools/**"
+ ],
+ "optionalDependencies": false,
+ "peerDependencies": true
+ }
+ ],
+ "import/no-unresolved": [
+ "error"
+ ],
+ "import/order": [
+ "warn",
+ {
+ "groups": [
+ "builtin",
+ "external"
+ ],
+ "alphabetize": {
+ "order": "asc",
+ "caseInsensitive": true
+ }
+ }
+ ],
+ "no-duplicate-imports": [
+ "error"
+ ],
+ "no-shadow": [
+ "off"
+ ],
+ "@typescript-eslint/no-shadow": [
+ "error"
+ ],
+ "key-spacing": [
+ "error"
+ ],
+ "no-multiple-empty-lines": [
+ "error"
+ ],
+ "@typescript-eslint/no-floating-promises": [
+ "error"
+ ],
+ "no-return-await": [
+ "off"
+ ],
+ "@typescript-eslint/return-await": [
+ "error"
+ ],
+ "no-trailing-spaces": [
+ "error"
+ ],
+ "dot-notation": [
+ "error"
+ ],
+ "no-bitwise": [
+ "error"
+ ],
+ "@typescript-eslint/member-ordering": [
+ "error",
+ {
+ "default": [
+ "public-static-field",
+ "public-static-method",
+ "protected-static-field",
+ "protected-static-method",
+ "private-static-field",
+ "private-static-method",
+ "field",
+ "constructor",
+ "method"
+ ]
+ }
+ ]
+ },
+ "overrides": []
+}
diff --git a/packages/client-sns/.gitattributes b/packages/client-sns/.gitattributes
new file mode 100644
index 0000000..3d4472e
--- /dev/null
+++ b/packages/client-sns/.gitattributes
@@ -0,0 +1,21 @@
+# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen".
+
+/./tsconfig.esm.json linguist-generated
+/.eslintrc.json linguist-generated
+/.gitattributes linguist-generated
+/.gitignore linguist-generated
+/.npmignore linguist-generated
+/.npmrc linguist-generated
+/.prettierignore linguist-generated
+/.prettierrc.json linguist-generated
+/.projen/** linguist-generated
+/.projen/deps.json linguist-generated
+/.projen/files.json linguist-generated
+/.projen/tasks.json linguist-generated
+/jest.config.json linguist-generated
+/LICENSE linguist-generated
+/package.json linguist-generated
+/pnpm-lock.yaml linguist-generated
+/project.json linguist-generated
+/tsconfig.dev.json linguist-generated
+/tsconfig.json linguist-generated
\ No newline at end of file
diff --git a/packages/client-sns/.gitignore b/packages/client-sns/.gitignore
new file mode 100644
index 0000000..cd4750b
--- /dev/null
+++ b/packages/client-sns/.gitignore
@@ -0,0 +1,46 @@
+# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen".
+!/.gitattributes
+!/.projen/tasks.json
+!/.projen/deps.json
+!/.projen/files.json
+!/package.json
+!/LICENSE
+!/.npmignore
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+pids
+*.pid
+*.seed
+*.pid.lock
+lib-cov
+coverage
+*.lcov
+.nyc_output
+build/Release
+node_modules/
+jspm_packages/
+*.tsbuildinfo
+.eslintcache
+*.tgz
+.yarn-integrity
+.cache
+!/.projenrc.js
+!/jest.config.json
+/coverage/
+!/.prettierignore
+!/.prettierrc.json
+!/.npmrc
+!/test/
+!/tsconfig.json
+!/tsconfig.dev.json
+!/src/
+/lib
+/dist/
+!/.eslintrc.json
+!/./tsconfig.esm.json
+!/project.json
diff --git a/packages/client-sns/.npmignore b/packages/client-sns/.npmignore
new file mode 100644
index 0000000..aaeff68
--- /dev/null
+++ b/packages/client-sns/.npmignore
@@ -0,0 +1,19 @@
+# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen".
+/.projen/
+/jest.config.json
+/coverage/
+/test/
+/tsconfig.dev.json
+/src/
+!/lib/
+!/lib/**/*.js
+!/lib/**/*.d.ts
+dist
+/tsconfig.json
+/.github/
+/.vscode/
+/.idea/
+/.projenrc.js
+tsconfig.tsbuildinfo
+/.eslintrc.json
+/tsconfig.esm.json
diff --git a/packages/client-sns/.prettierignore b/packages/client-sns/.prettierignore
new file mode 100644
index 0000000..46704c7
--- /dev/null
+++ b/packages/client-sns/.prettierignore
@@ -0,0 +1 @@
+# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen".
diff --git a/packages/client-sns/.prettierrc.json b/packages/client-sns/.prettierrc.json
new file mode 100644
index 0000000..84c85a3
--- /dev/null
+++ b/packages/client-sns/.prettierrc.json
@@ -0,0 +1,3 @@
+{
+ "overrides": []
+}
diff --git a/packages/client-sns/.projen/deps.json b/packages/client-sns/.projen/deps.json
new file mode 100644
index 0000000..551fb94
--- /dev/null
+++ b/packages/client-sns/.projen/deps.json
@@ -0,0 +1,107 @@
+{
+ "dependencies": [
+ {
+ "name": "@effect/data",
+ "version": "0.18.4",
+ "type": "build"
+ },
+ {
+ "name": "@effect/io",
+ "version": "0.40.0",
+ "type": "build"
+ },
+ {
+ "name": "@types/jest",
+ "type": "build"
+ },
+ {
+ "name": "@types/node",
+ "version": "^16",
+ "type": "build"
+ },
+ {
+ "name": "@typescript-eslint/eslint-plugin",
+ "version": "^6",
+ "type": "build"
+ },
+ {
+ "name": "@typescript-eslint/parser",
+ "version": "^6",
+ "type": "build"
+ },
+ {
+ "name": "aws-sdk-client-mock",
+ "type": "build"
+ },
+ {
+ "name": "aws-sdk-client-mock-jest",
+ "type": "build"
+ },
+ {
+ "name": "eslint-config-prettier",
+ "type": "build"
+ },
+ {
+ "name": "eslint-import-resolver-node",
+ "type": "build"
+ },
+ {
+ "name": "eslint-import-resolver-typescript",
+ "type": "build"
+ },
+ {
+ "name": "eslint-plugin-import",
+ "type": "build"
+ },
+ {
+ "name": "eslint-plugin-prettier",
+ "type": "build"
+ },
+ {
+ "name": "eslint",
+ "version": "^8",
+ "type": "build"
+ },
+ {
+ "name": "jest",
+ "type": "build"
+ },
+ {
+ "name": "prettier",
+ "type": "build"
+ },
+ {
+ "name": "projen",
+ "type": "build"
+ },
+ {
+ "name": "ts-jest",
+ "type": "build"
+ },
+ {
+ "name": "typescript",
+ "type": "build"
+ },
+ {
+ "name": "@effect/data",
+ "version": "^0.18.4",
+ "type": "peer"
+ },
+ {
+ "name": "@effect/io",
+ "version": "^0.40.0",
+ "type": "peer"
+ },
+ {
+ "name": "@aws-sdk/client-sns",
+ "version": "^3",
+ "type": "runtime"
+ },
+ {
+ "name": "@aws-sdk/types",
+ "version": "^3",
+ "type": "runtime"
+ }
+ ],
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"."
+}
diff --git a/packages/client-sns/.projen/files.json b/packages/client-sns/.projen/files.json
new file mode 100644
index 0000000..312ff31
--- /dev/null
+++ b/packages/client-sns/.projen/files.json
@@ -0,0 +1,20 @@
+{
+ "files": [
+ "./tsconfig.esm.json",
+ ".eslintrc.json",
+ ".gitattributes",
+ ".gitignore",
+ ".npmignore",
+ ".prettierignore",
+ ".prettierrc.json",
+ ".projen/deps.json",
+ ".projen/files.json",
+ ".projen/tasks.json",
+ "jest.config.json",
+ "LICENSE",
+ "project.json",
+ "tsconfig.dev.json",
+ "tsconfig.json"
+ ],
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"."
+}
diff --git a/packages/client-sns/.projen/tasks.json b/packages/client-sns/.projen/tasks.json
new file mode 100644
index 0000000..de5fc10
--- /dev/null
+++ b/packages/client-sns/.projen/tasks.json
@@ -0,0 +1,112 @@
+{
+ "tasks": {
+ "build": {
+ "name": "build",
+ "description": "Full release build",
+ "steps": [
+ {
+ "spawn": "pre-compile"
+ },
+ {
+ "spawn": "compile"
+ },
+ {
+ "spawn": "post-compile"
+ },
+ {
+ "spawn": "test"
+ },
+ {
+ "spawn": "package"
+ }
+ ]
+ },
+ "compile": {
+ "name": "compile",
+ "description": "Only compile",
+ "steps": [
+ {
+ "exec": "tsc -b ./tsconfig.json ./tsconfig.esm.json"
+ }
+ ]
+ },
+ "default": {
+ "name": "default",
+ "description": "Synthesize project files"
+ },
+ "eslint": {
+ "name": "eslint",
+ "description": "Runs eslint against the codebase",
+ "steps": [
+ {
+ "exec": "eslint --ext .ts,.tsx --fix --no-error-on-unmatched-pattern src test build-tools"
+ }
+ ]
+ },
+ "install": {
+ "name": "install",
+ "description": "Install project dependencies and update lockfile (non-frozen)",
+ "steps": [
+ {
+ "exec": "pnpm i --no-frozen-lockfile"
+ }
+ ]
+ },
+ "install:ci": {
+ "name": "install:ci",
+ "description": "Install project dependencies using frozen lockfile",
+ "steps": [
+ {
+ "exec": "pnpm i --frozen-lockfile"
+ }
+ ]
+ },
+ "package": {
+ "name": "package",
+ "description": "Creates the distribution package"
+ },
+ "post-compile": {
+ "name": "post-compile",
+ "description": "Runs after successful compilation"
+ },
+ "pre-compile": {
+ "name": "pre-compile",
+ "description": "Prepare the project for compilation"
+ },
+ "test": {
+ "name": "test",
+ "description": "Run tests",
+ "steps": [
+ {
+ "exec": "jest --passWithNoTests --updateSnapshot",
+ "receiveArgs": true
+ },
+ {
+ "spawn": "eslint"
+ }
+ ]
+ },
+ "test:watch": {
+ "name": "test:watch",
+ "description": "Run jest in watch mode",
+ "steps": [
+ {
+ "exec": "jest --watch"
+ }
+ ]
+ },
+ "watch": {
+ "name": "watch",
+ "description": "Watch & compile in the background",
+ "steps": [
+ {
+ "exec": "tsc --build -w"
+ }
+ ]
+ }
+ },
+ "env": {
+ "PATH": "$(pnpm -c exec \"node --print process.env.PATH\")"
+ },
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"."
+}
diff --git a/packages/client-sns/LICENSE b/packages/client-sns/LICENSE
new file mode 100644
index 0000000..c5b4e3d
--- /dev/null
+++ b/packages/client-sns/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2023 Victor Korzunin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/client-sns/README.md b/packages/client-sns/README.md
new file mode 100644
index 0000000..b3fa7dd
--- /dev/null
+++ b/packages/client-sns/README.md
@@ -0,0 +1 @@
+# replace this
\ No newline at end of file
diff --git a/packages/client-sns/jest.config.json b/packages/client-sns/jest.config.json
new file mode 100644
index 0000000..894210f
--- /dev/null
+++ b/packages/client-sns/jest.config.json
@@ -0,0 +1,37 @@
+{
+ "transform": {
+ "^.+\\.tsx?$": [
+ "ts-jest",
+ {
+ "tsconfig": "tsconfig.dev.json"
+ }
+ ]
+ },
+ "testMatch": [
+ "/src/**/__tests__/**/*.ts?(x)",
+ "/(test|src)/**/*(*.)@(spec|test).ts?(x)"
+ ],
+ "clearMocks": true,
+ "collectCoverage": true,
+ "coverageReporters": [
+ "json",
+ "lcov",
+ "clover",
+ "cobertura",
+ "text"
+ ],
+ "coverageDirectory": "coverage",
+ "coveragePathIgnorePatterns": [
+ "/node_modules/"
+ ],
+ "testPathIgnorePatterns": [
+ "/node_modules/"
+ ],
+ "watchPathIgnorePatterns": [
+ "/node_modules/"
+ ],
+ "reporters": [
+ "default"
+ ],
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"."
+}
diff --git a/packages/client-sns/package.json b/packages/client-sns/package.json
new file mode 100644
index 0000000..0548edd
--- /dev/null
+++ b/packages/client-sns/package.json
@@ -0,0 +1,59 @@
+{
+ "name": "@effect-aws/client-sns",
+ "scripts": {
+ "build": "npx projen build",
+ "compile": "npx projen compile",
+ "default": "npx projen default",
+ "eslint": "npx projen eslint",
+ "package": "npx projen package",
+ "post-compile": "npx projen post-compile",
+ "pre-compile": "npx projen pre-compile",
+ "test": "npx projen test",
+ "test:watch": "npx projen test:watch",
+ "watch": "npx projen watch"
+ },
+ "author": {
+ "name": "Victor Korzunin",
+ "email": "ifloydrose@gmail.com",
+ "organization": false
+ },
+ "devDependencies": {
+ "@effect/data": "0.18.4",
+ "@effect/io": "0.40.0",
+ "@types/jest": "^29.5.5",
+ "@types/node": "^16",
+ "@typescript-eslint/eslint-plugin": "^6",
+ "@typescript-eslint/parser": "^6",
+ "aws-sdk-client-mock": "^3.0.0",
+ "aws-sdk-client-mock-jest": "^3.0.0",
+ "eslint": "^8",
+ "eslint-config-prettier": "^9.0.0",
+ "eslint-import-resolver-node": "^0.3.9",
+ "eslint-import-resolver-typescript": "^3.6.0",
+ "eslint-plugin-import": "^2.28.1",
+ "eslint-plugin-prettier": "^5.0.0",
+ "jest": "^29.7.0",
+ "prettier": "^3.0.3",
+ "projen": "^0.73.25",
+ "ts-jest": "^29.1.1",
+ "typescript": "^5.2.2"
+ },
+ "peerDependencies": {
+ "@effect/data": "^0.18.4",
+ "@effect/io": "^0.40.0"
+ },
+ "dependencies": {
+ "@aws-sdk/client-sns": "^3",
+ "@aws-sdk/types": "^3"
+ },
+ "pnpm": {},
+ "main": "lib/index.js",
+ "license": "MIT",
+ "publishConfig": {
+ "access": "public"
+ },
+ "version": "0.0.0",
+ "types": "lib/index.d.ts",
+ "module": "lib/esm/index.js",
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"."
+}
diff --git a/packages/client-sns/project.json b/packages/client-sns/project.json
new file mode 100644
index 0000000..02581e5
--- /dev/null
+++ b/packages/client-sns/project.json
@@ -0,0 +1,77 @@
+{
+ "name": "@effect-aws/client-sns",
+ "root": "packages/client-sns",
+ "targets": {
+ "default": {
+ "executor": "nx:run-commands",
+ "options": {
+ "command": "pnpm exec projen default",
+ "cwd": "packages/client-sns"
+ }
+ },
+ "pre-compile": {
+ "executor": "nx:run-commands",
+ "options": {
+ "command": "pnpm exec projen pre-compile",
+ "cwd": "packages/client-sns"
+ }
+ },
+ "compile": {
+ "executor": "nx:run-commands",
+ "options": {
+ "command": "pnpm exec projen compile",
+ "cwd": "packages/client-sns"
+ }
+ },
+ "post-compile": {
+ "executor": "nx:run-commands",
+ "options": {
+ "command": "pnpm exec projen post-compile",
+ "cwd": "packages/client-sns"
+ }
+ },
+ "test": {
+ "executor": "nx:run-commands",
+ "options": {
+ "command": "pnpm exec projen test",
+ "cwd": "packages/client-sns"
+ }
+ },
+ "package": {
+ "executor": "nx:run-commands",
+ "options": {
+ "command": "pnpm exec projen package",
+ "cwd": "packages/client-sns"
+ }
+ },
+ "build": {
+ "executor": "nx:run-commands",
+ "options": {
+ "command": "pnpm exec projen build",
+ "cwd": "packages/client-sns"
+ }
+ },
+ "test:watch": {
+ "executor": "nx:run-commands",
+ "options": {
+ "command": "pnpm exec projen test:watch",
+ "cwd": "packages/client-sns"
+ }
+ },
+ "watch": {
+ "executor": "nx:run-commands",
+ "options": {
+ "command": "pnpm exec projen watch",
+ "cwd": "packages/client-sns"
+ }
+ },
+ "eslint": {
+ "executor": "nx:run-commands",
+ "options": {
+ "command": "pnpm exec projen eslint",
+ "cwd": "packages/client-sns"
+ }
+ }
+ },
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"."
+}
diff --git a/packages/client-sns/src/Context.ts b/packages/client-sns/src/Context.ts
new file mode 100644
index 0000000..940fa20
--- /dev/null
+++ b/packages/client-sns/src/Context.ts
@@ -0,0 +1,39 @@
+import { SNSClient, SNSClientConfig } from "@aws-sdk/client-sns";
+import * as Context from "@effect/data/Context";
+import { flow } from "@effect/data/Function";
+import * as Effect from "@effect/io/Effect";
+import * as Layer from "@effect/io/Layer";
+import * as Runtime from "@effect/io/Runtime";
+
+export const SNSClientConfigTag = Context.Tag(
+ "@effect-aws/SNSClient/Config",
+);
+
+export const DefaultSNSClientConfigLayer = Layer.effect(
+ SNSClientConfigTag,
+ Effect.runtime().pipe(
+ Effect.map((runtime) => ({
+ logger: {
+ info: flow(Effect.logInfo, Runtime.runSync(runtime)),
+ warn: flow(Effect.logWarning, Runtime.runSync(runtime)),
+ error: flow(Effect.logError, Runtime.runSync(runtime)),
+ debug: flow(Effect.logDebug, Runtime.runSync(runtime)),
+ trace: flow(Effect.logTrace, Runtime.runSync(runtime)),
+ },
+ })),
+ ),
+);
+
+export const SNSClientInstanceTag = Context.Tag(
+ "@effect-aws/SNSClient/Instance",
+);
+
+export const SNSClientInstanceLayer = Layer.effect(
+ SNSClientInstanceTag,
+ SNSClientConfigTag.pipe(Effect.map((config) => new SNSClient(config))),
+);
+
+export const DefaultSNSClientInstanceLayer = Layer.provide(
+ DefaultSNSClientConfigLayer,
+ SNSClientInstanceLayer,
+);
diff --git a/packages/client-sns/src/SNS.ts b/packages/client-sns/src/SNS.ts
new file mode 100644
index 0000000..c155767
--- /dev/null
+++ b/packages/client-sns/src/SNS.ts
@@ -0,0 +1,556 @@
+import {
+ AddPermissionCommand,
+ CheckIfPhoneNumberIsOptedOutCommand,
+ ConfirmSubscriptionCommand,
+ CreatePlatformApplicationCommand,
+ CreatePlatformEndpointCommand,
+ CreateSMSSandboxPhoneNumberCommand,
+ CreateTopicCommand,
+ DeleteEndpointCommand,
+ DeletePlatformApplicationCommand,
+ DeleteSMSSandboxPhoneNumberCommand,
+ DeleteTopicCommand,
+ GetDataProtectionPolicyCommand,
+ GetEndpointAttributesCommand,
+ GetPlatformApplicationAttributesCommand,
+ GetSMSAttributesCommand,
+ GetSMSSandboxAccountStatusCommand,
+ GetSubscriptionAttributesCommand,
+ GetTopicAttributesCommand,
+ ListEndpointsByPlatformApplicationCommand,
+ ListOriginationNumbersCommand,
+ ListPhoneNumbersOptedOutCommand,
+ ListPlatformApplicationsCommand,
+ ListSMSSandboxPhoneNumbersCommand,
+ ListSubscriptionsCommand,
+ ListSubscriptionsByTopicCommand,
+ ListTagsForResourceCommand,
+ ListTopicsCommand,
+ OptInPhoneNumberCommand,
+ PublishCommand,
+ PublishBatchCommand,
+ PutDataProtectionPolicyCommand,
+ RemovePermissionCommand,
+ SetEndpointAttributesCommand,
+ SetPlatformApplicationAttributesCommand,
+ SetSMSAttributesCommand,
+ SetSubscriptionAttributesCommand,
+ SetTopicAttributesCommand,
+ SubscribeCommand,
+ TagResourceCommand,
+ UnsubscribeCommand,
+ UntagResourceCommand,
+ VerifySMSSandboxPhoneNumberCommand,
+ AddPermissionCommandInput,
+ AddPermissionCommandOutput,
+ CheckIfPhoneNumberIsOptedOutCommandInput,
+ CheckIfPhoneNumberIsOptedOutCommandOutput,
+ ConfirmSubscriptionCommandInput,
+ ConfirmSubscriptionCommandOutput,
+ CreatePlatformApplicationCommandInput,
+ CreatePlatformApplicationCommandOutput,
+ CreatePlatformEndpointCommandInput,
+ CreatePlatformEndpointCommandOutput,
+ CreateSMSSandboxPhoneNumberCommandInput,
+ CreateSMSSandboxPhoneNumberCommandOutput,
+ CreateTopicCommandInput,
+ CreateTopicCommandOutput,
+ DeleteEndpointCommandInput,
+ DeleteEndpointCommandOutput,
+ DeletePlatformApplicationCommandInput,
+ DeletePlatformApplicationCommandOutput,
+ DeleteSMSSandboxPhoneNumberCommandInput,
+ DeleteSMSSandboxPhoneNumberCommandOutput,
+ DeleteTopicCommandInput,
+ DeleteTopicCommandOutput,
+ GetDataProtectionPolicyCommandInput,
+ GetDataProtectionPolicyCommandOutput,
+ GetEndpointAttributesCommandInput,
+ GetEndpointAttributesCommandOutput,
+ GetPlatformApplicationAttributesCommandInput,
+ GetPlatformApplicationAttributesCommandOutput,
+ GetSMSAttributesCommandInput,
+ GetSMSAttributesCommandOutput,
+ GetSMSSandboxAccountStatusCommandInput,
+ GetSMSSandboxAccountStatusCommandOutput,
+ GetSubscriptionAttributesCommandInput,
+ GetSubscriptionAttributesCommandOutput,
+ GetTopicAttributesCommandInput,
+ GetTopicAttributesCommandOutput,
+ ListEndpointsByPlatformApplicationCommandInput,
+ ListEndpointsByPlatformApplicationCommandOutput,
+ ListOriginationNumbersCommandInput,
+ ListOriginationNumbersCommandOutput,
+ ListPhoneNumbersOptedOutCommandInput,
+ ListPhoneNumbersOptedOutCommandOutput,
+ ListPlatformApplicationsCommandInput,
+ ListPlatformApplicationsCommandOutput,
+ ListSMSSandboxPhoneNumbersCommandInput,
+ ListSMSSandboxPhoneNumbersCommandOutput,
+ ListSubscriptionsByTopicCommandInput,
+ ListSubscriptionsByTopicCommandOutput,
+ ListSubscriptionsCommandInput,
+ ListSubscriptionsCommandOutput,
+ ListTagsForResourceCommandInput,
+ ListTagsForResourceCommandOutput,
+ ListTopicsCommandInput,
+ ListTopicsCommandOutput,
+ OptInPhoneNumberCommandInput,
+ OptInPhoneNumberCommandOutput,
+ PublishBatchCommandInput,
+ PublishBatchCommandOutput,
+ PublishCommandInput,
+ PublishCommandOutput,
+ PutDataProtectionPolicyCommandInput,
+ PutDataProtectionPolicyCommandOutput,
+ RemovePermissionCommandInput,
+ RemovePermissionCommandOutput,
+ SetEndpointAttributesCommandInput,
+ SetEndpointAttributesCommandOutput,
+ SetPlatformApplicationAttributesCommandInput,
+ SetPlatformApplicationAttributesCommandOutput,
+ SetSMSAttributesCommandInput,
+ SetSMSAttributesCommandOutput,
+ SetSubscriptionAttributesCommandInput,
+ SetSubscriptionAttributesCommandOutput,
+ SetTopicAttributesCommandInput,
+ SetTopicAttributesCommandOutput,
+ SubscribeCommandInput,
+ SubscribeCommandOutput,
+ TagResourceCommandInput,
+ TagResourceCommandOutput,
+ UnsubscribeCommandInput,
+ UnsubscribeCommandOutput,
+ UntagResourceCommandInput,
+ UntagResourceCommandOutput,
+ VerifySMSSandboxPhoneNumberCommandInput,
+ VerifySMSSandboxPhoneNumberCommandOutput,
+} from "@aws-sdk/client-sns";
+import { HttpHandlerOptions as __HttpHandlerOptions } from "@aws-sdk/types";
+import * as RR from "@effect/data/ReadonlyRecord";
+import * as Effect from "@effect/io/Effect";
+import {
+ DefaultSNSClientInstanceLayer,
+ SNSClientInstanceLayer,
+ SNSClientInstanceTag,
+} from "./Context";
+
+const commands = {
+ AddPermissionCommand,
+ CheckIfPhoneNumberIsOptedOutCommand,
+ ConfirmSubscriptionCommand,
+ CreatePlatformApplicationCommand,
+ CreatePlatformEndpointCommand,
+ CreateSMSSandboxPhoneNumberCommand,
+ CreateTopicCommand,
+ DeleteEndpointCommand,
+ DeletePlatformApplicationCommand,
+ DeleteSMSSandboxPhoneNumberCommand,
+ DeleteTopicCommand,
+ GetDataProtectionPolicyCommand,
+ GetEndpointAttributesCommand,
+ GetPlatformApplicationAttributesCommand,
+ GetSMSAttributesCommand,
+ GetSMSSandboxAccountStatusCommand,
+ GetSubscriptionAttributesCommand,
+ GetTopicAttributesCommand,
+ ListEndpointsByPlatformApplicationCommand,
+ ListOriginationNumbersCommand,
+ ListPhoneNumbersOptedOutCommand,
+ ListPlatformApplicationsCommand,
+ ListSMSSandboxPhoneNumbersCommand,
+ ListSubscriptionsCommand,
+ ListSubscriptionsByTopicCommand,
+ ListTagsForResourceCommand,
+ ListTopicsCommand,
+ OptInPhoneNumberCommand,
+ PublishCommand,
+ PublishBatchCommand,
+ PutDataProtectionPolicyCommand,
+ RemovePermissionCommand,
+ SetEndpointAttributesCommand,
+ SetPlatformApplicationAttributesCommand,
+ SetSMSAttributesCommand,
+ SetSubscriptionAttributesCommand,
+ SetTopicAttributesCommand,
+ SubscribeCommand,
+ TagResourceCommand,
+ UnsubscribeCommand,
+ UntagResourceCommand,
+ VerifySMSSandboxPhoneNumberCommand,
+};
+
+export interface SNSService {
+ /**
+ * @see {@link AddPermissionCommand}
+ */
+ addPermission(
+ args: AddPermissionCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link CheckIfPhoneNumberIsOptedOutCommand}
+ */
+ checkIfPhoneNumberIsOptedOut(
+ args: CheckIfPhoneNumberIsOptedOutCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link ConfirmSubscriptionCommand}
+ */
+ confirmSubscription(
+ args: ConfirmSubscriptionCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link CreatePlatformApplicationCommand}
+ */
+ createPlatformApplication(
+ args: CreatePlatformApplicationCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link CreatePlatformEndpointCommand}
+ */
+ createPlatformEndpoint(
+ args: CreatePlatformEndpointCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link CreateSMSSandboxPhoneNumberCommand}
+ */
+ createSMSSandboxPhoneNumber(
+ args: CreateSMSSandboxPhoneNumberCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link CreateTopicCommand}
+ */
+ createTopic(
+ args: CreateTopicCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link DeleteEndpointCommand}
+ */
+ deleteEndpoint(
+ args: DeleteEndpointCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link DeletePlatformApplicationCommand}
+ */
+ deletePlatformApplication(
+ args: DeletePlatformApplicationCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link DeleteSMSSandboxPhoneNumberCommand}
+ */
+ deleteSMSSandboxPhoneNumber(
+ args: DeleteSMSSandboxPhoneNumberCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link DeleteTopicCommand}
+ */
+ deleteTopic(
+ args: DeleteTopicCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link GetDataProtectionPolicyCommand}
+ */
+ getDataProtectionPolicy(
+ args: GetDataProtectionPolicyCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link GetEndpointAttributesCommand}
+ */
+ getEndpointAttributes(
+ args: GetEndpointAttributesCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link GetPlatformApplicationAttributesCommand}
+ */
+ getPlatformApplicationAttributes(
+ args: GetPlatformApplicationAttributesCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect<
+ never,
+ unknown,
+ GetPlatformApplicationAttributesCommandOutput
+ >;
+
+ /**
+ * @see {@link GetSMSAttributesCommand}
+ */
+ getSMSAttributes(
+ args: GetSMSAttributesCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link GetSMSSandboxAccountStatusCommand}
+ */
+ getSMSSandboxAccountStatus(
+ args: GetSMSSandboxAccountStatusCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link GetSubscriptionAttributesCommand}
+ */
+ getSubscriptionAttributes(
+ args: GetSubscriptionAttributesCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link GetTopicAttributesCommand}
+ */
+ getTopicAttributes(
+ args: GetTopicAttributesCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link ListEndpointsByPlatformApplicationCommand}
+ */
+ listEndpointsByPlatformApplication(
+ args: ListEndpointsByPlatformApplicationCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect<
+ never,
+ unknown,
+ ListEndpointsByPlatformApplicationCommandOutput
+ >;
+
+ /**
+ * @see {@link ListOriginationNumbersCommand}
+ */
+ listOriginationNumbers(
+ args: ListOriginationNumbersCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link ListPhoneNumbersOptedOutCommand}
+ */
+ listPhoneNumbersOptedOut(
+ args: ListPhoneNumbersOptedOutCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link ListPlatformApplicationsCommand}
+ */
+ listPlatformApplications(
+ args: ListPlatformApplicationsCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link ListSMSSandboxPhoneNumbersCommand}
+ */
+ listSMSSandboxPhoneNumbers(
+ args: ListSMSSandboxPhoneNumbersCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link ListSubscriptionsCommand}
+ */
+ listSubscriptions(
+ args: ListSubscriptionsCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link ListSubscriptionsByTopicCommand}
+ */
+ listSubscriptionsByTopic(
+ args: ListSubscriptionsByTopicCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link ListTagsForResourceCommand}
+ */
+ listTagsForResource(
+ args: ListTagsForResourceCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link ListTopicsCommand}
+ */
+ listTopics(
+ args: ListTopicsCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link OptInPhoneNumberCommand}
+ */
+ optInPhoneNumber(
+ args: OptInPhoneNumberCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link PublishCommand}
+ */
+ publish(
+ args: PublishCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link PublishBatchCommand}
+ */
+ publishBatch(
+ args: PublishBatchCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link PutDataProtectionPolicyCommand}
+ */
+ putDataProtectionPolicy(
+ args: PutDataProtectionPolicyCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link RemovePermissionCommand}
+ */
+ removePermission(
+ args: RemovePermissionCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link SetEndpointAttributesCommand}
+ */
+ setEndpointAttributes(
+ args: SetEndpointAttributesCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link SetPlatformApplicationAttributesCommand}
+ */
+ setPlatformApplicationAttributes(
+ args: SetPlatformApplicationAttributesCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect<
+ never,
+ unknown,
+ SetPlatformApplicationAttributesCommandOutput
+ >;
+
+ /**
+ * @see {@link SetSMSAttributesCommand}
+ */
+ setSMSAttributes(
+ args: SetSMSAttributesCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link SetSubscriptionAttributesCommand}
+ */
+ setSubscriptionAttributes(
+ args: SetSubscriptionAttributesCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link SetTopicAttributesCommand}
+ */
+ setTopicAttributes(
+ args: SetTopicAttributesCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link SubscribeCommand}
+ */
+ subscribe(
+ args: SubscribeCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link TagResourceCommand}
+ */
+ tagResource(
+ args: TagResourceCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link UnsubscribeCommand}
+ */
+ unsubscribe(
+ args: UnsubscribeCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link UntagResourceCommand}
+ */
+ untagResource(
+ args: UntagResourceCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+
+ /**
+ * @see {@link VerifySMSSandboxPhoneNumberCommand}
+ */
+ verifySMSSandboxPhoneNumber(
+ args: VerifySMSSandboxPhoneNumberCommandInput,
+ options?: __HttpHandlerOptions,
+ ): Effect.Effect;
+}
+
+export const BaseSNSServiceEffect = Effect.gen(function* (_) {
+ const client = yield* _(SNSClientInstanceTag);
+
+ return RR.toEntries(commands).reduce((acc, [command]) => {
+ const CommandCtor = commands[command] as any;
+ const methodImpl = (args: any, options: any) =>
+ Effect.tryPromise(() =>
+ client.send(new CommandCtor(args), options ?? {}),
+ );
+ const methodName = (command[0].toLowerCase() + command.slice(1)).replace(
+ /Command$/,
+ "",
+ );
+ return { ...acc, [methodName]: methodImpl };
+ }, {}) as SNSService;
+});
+
+export const SNSServiceEffect = BaseSNSServiceEffect.pipe(
+ Effect.provideLayer(SNSClientInstanceLayer),
+);
+
+export const DefaultSNSServiceEffect = BaseSNSServiceEffect.pipe(
+ Effect.provideLayer(DefaultSNSClientInstanceLayer),
+);
diff --git a/packages/client-sns/src/index.ts b/packages/client-sns/src/index.ts
new file mode 100644
index 0000000..d156cdf
--- /dev/null
+++ b/packages/client-sns/src/index.ts
@@ -0,0 +1,2 @@
+export * from "./Context";
+export * from "./SNS";
diff --git a/packages/client-sns/test/SNS.test.ts b/packages/client-sns/test/SNS.test.ts
new file mode 100644
index 0000000..7d810ae
--- /dev/null
+++ b/packages/client-sns/test/SNS.test.ts
@@ -0,0 +1,137 @@
+import {
+ PublishCommand,
+ PublishCommandInput,
+ SNSClient,
+} from "@aws-sdk/client-sns";
+import { pipe } from "@effect/data/Function";
+import * as Effect from "@effect/io/Effect";
+import * as Exit from "@effect/io/Exit";
+import * as Layer from "@effect/io/Layer";
+import { mockClient } from "aws-sdk-client-mock";
+import {
+ BaseSNSServiceEffect,
+ DefaultSNSClientConfigLayer,
+ DefaultSNSServiceEffect,
+ SNSClientConfigTag,
+ SNSClientInstanceTag,
+ SNSServiceEffect,
+} from "../src";
+
+import "aws-sdk-client-mock-jest";
+
+const snsMock = mockClient(SNSClient);
+
+describe("SNSClientImpl", () => {
+ it("default", async () => {
+ snsMock.reset().on(PublishCommand).resolves({});
+
+ const args: PublishCommandInput = { TopicArn: "test", Message: "test" };
+
+ const program = Effect.flatMap(DefaultSNSServiceEffect, (sns) =>
+ sns.publish(args),
+ );
+
+ const result = await pipe(program, Effect.runPromiseExit);
+
+ expect(result).toEqual(Exit.succeed({}));
+ expect(snsMock).toHaveReceivedCommandTimes(PublishCommand, 1);
+ expect(snsMock).toHaveReceivedCommandWith(PublishCommand, args);
+ });
+
+ it("configurable", async () => {
+ snsMock.reset().on(PublishCommand).resolves({});
+
+ const args: PublishCommandInput = { TopicArn: "test", Message: "test" };
+
+ const program = Effect.flatMap(SNSServiceEffect, (sns) =>
+ sns.publish(args),
+ );
+
+ const SNSClientConfigLayer = Layer.succeed(SNSClientConfigTag, {
+ region: "eu-central-1",
+ });
+
+ const result = await pipe(
+ program,
+ Effect.provideLayer(SNSClientConfigLayer),
+ Effect.runPromiseExit,
+ );
+
+ expect(result).toEqual(Exit.succeed({}));
+ expect(snsMock).toHaveReceivedCommandTimes(PublishCommand, 1);
+ expect(snsMock).toHaveReceivedCommandWith(PublishCommand, args);
+ });
+
+ it("base", async () => {
+ snsMock.reset().on(PublishCommand).resolves({});
+
+ const args: PublishCommandInput = { TopicArn: "test", Message: "test" };
+
+ const program = Effect.flatMap(BaseSNSServiceEffect, (sns) =>
+ sns.publish(args),
+ );
+
+ const SNSClientInstanceLayer = Layer.succeed(
+ SNSClientInstanceTag,
+ new SNSClient({ region: "eu-central-1" }),
+ );
+
+ const result = await pipe(
+ program,
+ Effect.provideLayer(SNSClientInstanceLayer),
+ Effect.runPromiseExit,
+ );
+
+ expect(result).toEqual(Exit.succeed({}));
+ expect(snsMock).toHaveReceivedCommandTimes(PublishCommand, 1);
+ expect(snsMock).toHaveReceivedCommandWith(PublishCommand, args);
+ });
+
+ it("extended", async () => {
+ snsMock.reset().on(PublishCommand).resolves({});
+
+ const args: PublishCommandInput = { TopicArn: "test", Message: "test" };
+
+ const program = Effect.flatMap(BaseSNSServiceEffect, (sns) =>
+ sns.publish(args),
+ );
+
+ const SNSClientInstanceLayer = Layer.provide(
+ DefaultSNSClientConfigLayer,
+ Layer.effect(
+ SNSClientInstanceTag,
+ SNSClientConfigTag.pipe(
+ Effect.map(
+ (config) => new SNSClient({ ...config, region: "eu-central-1" }),
+ ),
+ ),
+ ),
+ );
+
+ const result = await pipe(
+ program,
+ Effect.provideLayer(SNSClientInstanceLayer),
+ Effect.runPromiseExit,
+ );
+
+ expect(result).toEqual(Exit.succeed({}));
+ expect(snsMock).toHaveReceivedCommandTimes(PublishCommand, 1);
+ expect(snsMock).toHaveReceivedCommandWith(PublishCommand, args);
+ });
+
+ it("fail", async () => {
+ snsMock.reset().on(PublishCommand).rejects(new Error("test"));
+
+ const args: PublishCommandInput = { TopicArn: "test", Message: "test" };
+
+ const program = Effect.flatMap(DefaultSNSServiceEffect, (sns) =>
+ sns.publish(args, { requestTimeout: 1000 }),
+ );
+
+ const result = await pipe(program, Effect.runPromiseExit);
+
+ expect(result).toEqual(Exit.fail(new Error("test")));
+ expect(snsMock).toHaveReceivedCommandTimes(PublishCommand, 1);
+ expect(snsMock).toHaveReceivedCommandWith(PublishCommand, args);
+ });
+});
diff --git a/packages/client-sns/tsconfig.dev.json b/packages/client-sns/tsconfig.dev.json
new file mode 100644
index 0000000..bdb2a8a
--- /dev/null
+++ b/packages/client-sns/tsconfig.dev.json
@@ -0,0 +1,37 @@
+// ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen".
+{
+ "compilerOptions": {
+ "alwaysStrict": true,
+ "declaration": true,
+ "esModuleInterop": true,
+ "experimentalDecorators": true,
+ "inlineSourceMap": true,
+ "inlineSources": true,
+ "lib": [
+ "es2019"
+ ],
+ "module": "CommonJS",
+ "noEmitOnError": false,
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitAny": true,
+ "noImplicitReturns": true,
+ "noImplicitThis": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "resolveJsonModule": true,
+ "strict": true,
+ "strictNullChecks": true,
+ "strictPropertyInitialization": true,
+ "stripInternal": true,
+ "target": "ES2019",
+ "moduleResolution": "node"
+ },
+ "include": [
+ ".projenrc.js",
+ "src/**/*.ts",
+ "test/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
diff --git a/packages/client-sns/tsconfig.esm.json b/packages/client-sns/tsconfig.esm.json
new file mode 100644
index 0000000..1b04668
--- /dev/null
+++ b/packages/client-sns/tsconfig.esm.json
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./lib/esm",
+ "module": "es6",
+ "resolveJsonModule": false,
+ "declaration": false
+ },
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"."
+}
diff --git a/packages/client-sns/tsconfig.json b/packages/client-sns/tsconfig.json
new file mode 100644
index 0000000..2c65812
--- /dev/null
+++ b/packages/client-sns/tsconfig.json
@@ -0,0 +1,35 @@
+// ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen".
+{
+ "compilerOptions": {
+ "rootDir": "src",
+ "outDir": "lib",
+ "alwaysStrict": true,
+ "declaration": true,
+ "esModuleInterop": true,
+ "experimentalDecorators": true,
+ "inlineSourceMap": true,
+ "inlineSources": true,
+ "lib": [
+ "es2019"
+ ],
+ "module": "CommonJS",
+ "noEmitOnError": false,
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitAny": true,
+ "noImplicitReturns": true,
+ "noImplicitThis": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "resolveJsonModule": true,
+ "strict": true,
+ "strictNullChecks": true,
+ "strictPropertyInitialization": true,
+ "stripInternal": true,
+ "target": "ES2019",
+ "moduleResolution": "node"
+ },
+ "include": [
+ "src/**/*.ts"
+ ],
+ "exclude": []
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9bac7ca..c688fb2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -147,6 +147,73 @@ importers:
specifier: ^5.2.2
version: 5.2.2
+ packages/client-sns:
+ dependencies:
+ '@aws-sdk/client-sns':
+ specifier: ^3
+ version: 3.414.0
+ '@aws-sdk/types':
+ specifier: ^3
+ version: 3.413.0
+ devDependencies:
+ '@effect/data':
+ specifier: 0.18.4
+ version: 0.18.4
+ '@effect/io':
+ specifier: 0.40.0
+ version: 0.40.0(@effect/data@0.18.4)
+ '@types/jest':
+ specifier: ^29.5.5
+ version: 29.5.5
+ '@types/node':
+ specifier: ^16
+ version: 16.18.52
+ '@typescript-eslint/eslint-plugin':
+ specifier: ^6
+ version: 6.7.0(@typescript-eslint/parser@6.7.0)(eslint@8.49.0)(typescript@5.2.2)
+ '@typescript-eslint/parser':
+ specifier: ^6
+ version: 6.7.0(eslint@8.49.0)(typescript@5.2.2)
+ aws-sdk-client-mock:
+ specifier: ^3.0.0
+ version: 3.0.0
+ aws-sdk-client-mock-jest:
+ specifier: ^3.0.0
+ version: 3.0.0(aws-sdk-client-mock@3.0.0)
+ eslint:
+ specifier: ^8
+ version: 8.49.0
+ eslint-config-prettier:
+ specifier: ^9.0.0
+ version: 9.0.0(eslint@8.49.0)
+ eslint-import-resolver-node:
+ specifier: ^0.3.9
+ version: 0.3.9
+ eslint-import-resolver-typescript:
+ specifier: ^3.6.0
+ version: 3.6.0(@typescript-eslint/parser@6.7.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.49.0)
+ eslint-plugin-import:
+ specifier: ^2.28.1
+ version: 2.28.1(@typescript-eslint/parser@6.7.0)(eslint-import-resolver-typescript@3.6.0)(eslint@8.49.0)
+ eslint-plugin-prettier:
+ specifier: ^5.0.0
+ version: 5.0.0(eslint-config-prettier@9.0.0)(eslint@8.49.0)(prettier@3.0.3)
+ jest:
+ specifier: ^29.7.0
+ version: 29.7.0(@types/node@16.18.52)(ts-node@10.9.1)
+ prettier:
+ specifier: ^3.0.3
+ version: 3.0.3
+ projen:
+ specifier: ^0.73.25
+ version: 0.73.25
+ ts-jest:
+ specifier: ^29.1.1
+ version: 29.1.1(@babel/core@7.22.20)(jest@29.7.0)(typescript@5.2.2)
+ typescript:
+ specifier: ^5.2.2
+ version: 5.2.2
+
packages/powertools-logger:
dependencies:
'@aws-lambda-powertools/logger':
@@ -391,6 +458,52 @@ packages:
- aws-crt
dev: false
+ /@aws-sdk/client-sns@3.414.0:
+ resolution: {integrity: sha512-i89Ornl2f1RgoZcB6ZkNcSaCKHVkP97WgDFiRNqx4nG3ukHFEp5B3N5jRVp4VBPQbgFIx7WKkXD8QzGpSzYLIQ==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-crypto/sha256-browser': 3.0.0
+ '@aws-crypto/sha256-js': 3.0.0
+ '@aws-sdk/client-sts': 3.414.0
+ '@aws-sdk/credential-provider-node': 3.414.0
+ '@aws-sdk/middleware-host-header': 3.413.0
+ '@aws-sdk/middleware-logger': 3.413.0
+ '@aws-sdk/middleware-recursion-detection': 3.413.0
+ '@aws-sdk/middleware-signing': 3.413.0
+ '@aws-sdk/middleware-user-agent': 3.413.0
+ '@aws-sdk/region-config-resolver': 3.413.0
+ '@aws-sdk/types': 3.413.0
+ '@aws-sdk/util-endpoints': 3.413.0
+ '@aws-sdk/util-user-agent-browser': 3.413.0
+ '@aws-sdk/util-user-agent-node': 3.413.0
+ '@smithy/config-resolver': 2.0.9
+ '@smithy/fetch-http-handler': 2.1.4
+ '@smithy/hash-node': 2.0.8
+ '@smithy/invalid-dependency': 2.0.8
+ '@smithy/middleware-content-length': 2.0.10
+ '@smithy/middleware-endpoint': 2.0.8
+ '@smithy/middleware-retry': 2.0.11
+ '@smithy/middleware-serde': 2.0.8
+ '@smithy/middleware-stack': 2.0.1
+ '@smithy/node-config-provider': 2.0.11
+ '@smithy/node-http-handler': 2.1.4
+ '@smithy/protocol-http': 3.0.4
+ '@smithy/smithy-client': 2.1.5
+ '@smithy/types': 2.3.2
+ '@smithy/url-parser': 2.0.8
+ '@smithy/util-base64': 2.0.0
+ '@smithy/util-body-length-browser': 2.0.0
+ '@smithy/util-body-length-node': 2.1.0
+ '@smithy/util-defaults-mode-browser': 2.0.9
+ '@smithy/util-defaults-mode-node': 2.0.11
+ '@smithy/util-retry': 2.0.1
+ '@smithy/util-utf8': 2.0.0
+ fast-xml-parser: 4.2.5
+ tslib: 2.6.2
+ transitivePeerDependencies:
+ - aws-crt
+ dev: false
+
/@aws-sdk/client-sso@3.414.0:
resolution: {integrity: sha512-GvRwQ7wA3edzsQEKS70ZPhkOUZ62PAiXasjp6GxrsADEb8sV1z4FxXNl9Un/7fQxKkh9QYaK1Wu1PmhLi9MLMg==}
engines: {node: '>=14.0.0'}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 0008da6..d42c515 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -2,4 +2,5 @@
packages:
- packages/client-s3
+ - packages/client-sns
- packages/powertools-logger