@kensio/yulin 0.0.1 → 0.1.0

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 (129) hide show
  1. package/.github/workflows/pr.yml +54 -0
  2. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  3. package/.nvmrc +1 -1
  4. package/README.md +44 -1
  5. package/dist/command/command-handler.d.ts +4 -0
  6. package/dist/command/command-handler.d.ts.map +1 -0
  7. package/dist/command/command-handler.js +2 -0
  8. package/dist/command/command-handler.js.map +1 -0
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +2 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/service/cloudfront/factory/cloudfront-functions.factory.d.ts +7 -0
  14. package/dist/service/cloudfront/factory/cloudfront-functions.factory.d.ts.map +1 -0
  15. package/dist/service/cloudfront/factory/cloudfront-functions.factory.js +33 -0
  16. package/dist/service/cloudfront/factory/cloudfront-functions.factory.js.map +1 -0
  17. package/dist/service/cloudfront/index.d.ts +3 -0
  18. package/dist/service/cloudfront/index.d.ts.map +1 -0
  19. package/dist/service/cloudfront/index.js +2 -0
  20. package/dist/service/cloudfront/index.js.map +1 -0
  21. package/dist/service/cloudfront/typings/cloudfront-functions.d.ts +37 -0
  22. package/dist/service/cloudfront/typings/cloudfront-functions.d.ts.map +1 -0
  23. package/dist/service/cloudfront/typings/cloudfront-functions.js +2 -0
  24. package/dist/service/cloudfront/typings/cloudfront-functions.js.map +1 -0
  25. package/dist/service/dynamodb/command/create-table/create-table.handler.d.ts +20 -0
  26. package/dist/service/dynamodb/command/create-table/create-table.handler.d.ts.map +1 -0
  27. package/dist/service/dynamodb/command/create-table/create-table.handler.js +47 -0
  28. package/dist/service/dynamodb/command/create-table/create-table.handler.js.map +1 -0
  29. package/dist/service/dynamodb/command/describe-table/describe-table.handler.d.ts +17 -0
  30. package/dist/service/dynamodb/command/describe-table/describe-table.handler.d.ts.map +1 -0
  31. package/dist/service/dynamodb/command/describe-table/describe-table.handler.js +37 -0
  32. package/dist/service/dynamodb/command/describe-table/describe-table.handler.js.map +1 -0
  33. package/dist/service/dynamodb/command/list-tables/list-tables.handler.d.ts +17 -0
  34. package/dist/service/dynamodb/command/list-tables/list-tables.handler.d.ts.map +1 -0
  35. package/dist/service/dynamodb/command/list-tables/list-tables.handler.js +32 -0
  36. package/dist/service/dynamodb/command/list-tables/list-tables.handler.js.map +1 -0
  37. package/dist/service/dynamodb/command/put-item/put-item.handler.d.ts +17 -0
  38. package/dist/service/dynamodb/command/put-item/put-item.handler.d.ts.map +1 -0
  39. package/dist/service/dynamodb/command/put-item/put-item.handler.js +39 -0
  40. package/dist/service/dynamodb/command/put-item/put-item.handler.js.map +1 -0
  41. package/dist/service/dynamodb/dynamodb.d.ts +27 -0
  42. package/dist/service/dynamodb/dynamodb.d.ts.map +1 -0
  43. package/dist/service/dynamodb/dynamodb.js +43 -0
  44. package/dist/service/dynamodb/dynamodb.js.map +1 -0
  45. package/dist/service/dynamodb/index.d.ts +2 -0
  46. package/dist/service/dynamodb/index.d.ts.map +1 -0
  47. package/dist/service/dynamodb/index.js +2 -0
  48. package/dist/service/dynamodb/index.js.map +1 -0
  49. package/dist/service/dynamodb/item/dynamodb-item-attribute.d.ts +21 -0
  50. package/dist/service/dynamodb/item/dynamodb-item-attribute.d.ts.map +1 -0
  51. package/dist/service/dynamodb/item/dynamodb-item-attribute.js +92 -0
  52. package/dist/service/dynamodb/item/dynamodb-item-attribute.js.map +1 -0
  53. package/dist/service/dynamodb/item/dynamodb-item.d.ts +18 -0
  54. package/dist/service/dynamodb/item/dynamodb-item.d.ts.map +1 -0
  55. package/dist/service/dynamodb/item/dynamodb-item.js +29 -0
  56. package/dist/service/dynamodb/item/dynamodb-item.js.map +1 -0
  57. package/dist/service/dynamodb/table/dynamodb-key-schema.d.ts +30 -0
  58. package/dist/service/dynamodb/table/dynamodb-key-schema.d.ts.map +1 -0
  59. package/dist/service/dynamodb/table/dynamodb-key-schema.js +61 -0
  60. package/dist/service/dynamodb/table/dynamodb-key-schema.js.map +1 -0
  61. package/dist/service/dynamodb/table/dynamodb-table.d.ts +34 -0
  62. package/dist/service/dynamodb/table/dynamodb-table.d.ts.map +1 -0
  63. package/dist/service/dynamodb/table/dynamodb-table.js +55 -0
  64. package/dist/service/dynamodb/table/dynamodb-table.js.map +1 -0
  65. package/dist/service/organizations/index.d.ts +2 -0
  66. package/dist/service/organizations/index.d.ts.map +1 -0
  67. package/dist/service/organizations/index.js +2 -0
  68. package/dist/service/organizations/index.js.map +1 -0
  69. package/dist/service/organizations/sim-aws-account.d.ts +19 -0
  70. package/dist/service/organizations/sim-aws-account.d.ts.map +1 -0
  71. package/dist/service/organizations/sim-aws-account.js +26 -0
  72. package/dist/service/organizations/sim-aws-account.js.map +1 -0
  73. package/dist/service/s3/index.d.ts +2 -0
  74. package/dist/service/s3/index.d.ts.map +1 -0
  75. package/dist/service/s3/index.js +3 -0
  76. package/dist/service/s3/index.js.map +1 -0
  77. package/dist/util/background/background.d.ts +28 -0
  78. package/dist/util/background/background.d.ts.map +1 -0
  79. package/dist/util/background/background.js +44 -0
  80. package/dist/util/background/background.js.map +1 -0
  81. package/dist/util/brand.type.d.ts +8 -0
  82. package/dist/util/brand.type.d.ts.map +1 -0
  83. package/dist/util/brand.type.js +2 -0
  84. package/dist/util/brand.type.js.map +1 -0
  85. package/dist/util/defined.d.ts +5 -0
  86. package/dist/util/defined.d.ts.map +1 -0
  87. package/dist/util/defined.js +11 -0
  88. package/dist/util/defined.js.map +1 -0
  89. package/dist/util/memo/memo.d.ts +15 -0
  90. package/dist/util/memo/memo.d.ts.map +1 -0
  91. package/dist/util/memo/memo.js +24 -0
  92. package/dist/util/memo/memo.js.map +1 -0
  93. package/dist/util/sleep.d.ts +10 -0
  94. package/dist/util/sleep.d.ts.map +1 -0
  95. package/dist/util/sleep.js +16 -0
  96. package/dist/util/sleep.js.map +1 -0
  97. package/eslint.config.ts +18 -4
  98. package/package.json +32 -19
  99. package/pnpm-workspace.yaml +23 -1
  100. package/scripts/publish.sh +14 -0
  101. package/src/index.ts +0 -0
  102. package/src/service/cloudfront/factory/cloudfront-functions.factory.iso.test.ts +10 -0
  103. package/src/service/cloudfront/factory/cloudfront-functions.factory.ts +34 -0
  104. package/src/service/cloudfront/index.ts +13 -0
  105. package/src/service/cloudfront/typings/cloudfront-functions.ts +48 -0
  106. package/src/service/dynamodb/command/create-table/create-table.handler.ts +5 -3
  107. package/src/service/dynamodb/command/create-table/create-table.iso.test.ts +36 -4
  108. package/src/service/dynamodb/command/describe-table/describe-table.handler.ts +3 -1
  109. package/src/service/dynamodb/command/describe-table/describe-table.iso.test.ts +18 -3
  110. package/src/service/dynamodb/command/list-tables/list-tables.handler.ts +3 -1
  111. package/src/service/dynamodb/command/list-tables/list-tables.iso.test.ts +54 -9
  112. package/src/service/dynamodb/command/put-item/put-item.handler.ts +56 -0
  113. package/src/service/dynamodb/command/put-item/put-item.iso.test.ts +354 -0
  114. package/src/service/dynamodb/dynamodb.ts +15 -1
  115. package/src/service/dynamodb/index.ts +0 -0
  116. package/src/service/dynamodb/item/dynamodb-item-attribute.iso.test.ts +19 -0
  117. package/src/service/dynamodb/item/dynamodb-item-attribute.ts +116 -0
  118. package/src/service/dynamodb/item/dynamodb-item.ts +39 -0
  119. package/src/service/dynamodb/table/dynamodb-key-schema.ts +94 -0
  120. package/src/service/dynamodb/{dynamodb-table.iso.test.ts → table/dynamodb-table.iso.test.ts} +8 -3
  121. package/src/service/dynamodb/table/dynamodb-table.ts +75 -0
  122. package/src/service/organizations/index.ts +0 -0
  123. package/src/service/s3/index.ts +1 -0
  124. package/src/util/background/background.ts +1 -1
  125. package/src/util/defined.ts +15 -0
  126. package/src/util/sleep.ts +1 -1
  127. package/tsconfig.json +11 -8
  128. package/src/service/dynamodb/dynamodb-table.ts +0 -46
  129. package/typings/eslint-plugin-promise.d.ts +0 -11
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Simple memoization cache.
3
+ */
4
+ export class Memo {
5
+ cache = new Map();
6
+ /**
7
+ * Returns the cached value for the given key, or creates/caches it using `factory`.
8
+ */
9
+ getOrCreate(key, factory) {
10
+ if (this.cache.has(key)) {
11
+ return this.cache.get(key);
12
+ }
13
+ const value = factory();
14
+ this.cache.set(key, value);
15
+ return value;
16
+ }
17
+ /**
18
+ * Returns whether the cache contains `key`.
19
+ */
20
+ has(key) {
21
+ return this.cache.has(key);
22
+ }
23
+ }
24
+ //# sourceMappingURL=memo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memo.js","sourceRoot":"","sources":["../../../src/util/memo/memo.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,IAAI;IACE,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEnD;;OAEG;IACH,WAAW,CAAc,GAAgB,EAAE,OAAgB;QACzD,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAM,CAAC;QAClC,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,GAAgB;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Async sleep for an approximate number of milliseconds.
3
+ */
4
+ export declare function sleep(ms?: number): Promise<void>;
5
+ /**
6
+ * Sleep for a random but short length of time, e.g. to simulate asynchronous
7
+ * operations completing in a non-deterministic order.
8
+ */
9
+ export declare function jitter(): Promise<void>;
10
+ //# sourceMappingURL=sleep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/util/sleep.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAsB,KAAK,CAAC,EAAE,SAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAIjD;AAED;;;GAGG;AACH,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5C"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Async sleep for an approximate number of milliseconds.
3
+ */
4
+ export async function sleep(ms = 0) {
5
+ await new Promise((resolve) => {
6
+ setTimeout(resolve, ms);
7
+ });
8
+ }
9
+ /**
10
+ * Sleep for a random but short length of time, e.g. to simulate asynchronous
11
+ * operations completing in a non-deterministic order.
12
+ */
13
+ export async function jitter() {
14
+ await sleep(Math.random());
15
+ }
16
+ //# sourceMappingURL=sleep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleep.js","sourceRoot":"","sources":["../../src/util/sleep.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,EAAE,GAAG,CAAC;IAChC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC5B,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7B,CAAC"}
package/eslint.config.ts CHANGED
@@ -14,6 +14,10 @@ import tseslint from "typescript-eslint";
14
14
 
15
15
  const __dirname = dirname(fileURLToPath(import.meta.url));
16
16
 
17
+ const securityRecommended = security.configs.recommended as Parameters<
18
+ typeof defineConfig
19
+ >[0];
20
+
17
21
  export default defineConfig(
18
22
  // ── Global ignores ──────────────────────────────────────
19
23
  {
@@ -75,6 +79,11 @@ export default defineConfig(
75
79
  format: ["camelCase", "PascalCase"],
76
80
  leadingUnderscore: "allow",
77
81
  },
82
+ {
83
+ selector: ["property", "objectLiteralProperty", "typeProperty"],
84
+ modifiers: ["requiresQuotes"],
85
+ format: null,
86
+ },
78
87
  {
79
88
  selector: "default",
80
89
  format: ["camelCase"],
@@ -103,10 +112,8 @@ export default defineConfig(
103
112
  },
104
113
  },
105
114
 
106
- // ── Security (low cost security checks) ────────────────
107
- // TODO: Remove cast when eslint-plugin-security fixes defineConfig() types
108
- // https://github.com/eslint-community/eslint-plugin-security/issues/175
109
- security.configs.recommended as any,
115
+ // ── Security (low-cost security checks) ────────────────
116
+ securityRecommended,
110
117
 
111
118
  // ── Unicorn (modern JS best practices) ──────────────────
112
119
  // https://github.com/sindresorhus/eslint-plugin-unicorn?tab=readme-ov-file#recommended-config
@@ -115,6 +122,13 @@ export default defineConfig(
115
122
  rules: {
116
123
  "unicorn/better-regex": "warn",
117
124
  "unicorn/prevent-abbreviations": "off",
125
+ "unicorn/no-null": "off",
126
+ },
127
+ },
128
+ {
129
+ files: ["**/index.ts"],
130
+ rules: {
131
+ "unicorn/no-empty-file": "off",
118
132
  },
119
133
  },
120
134
 
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@kensio/yulin",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "AWS system behaviour simulation for isolated unit testing",
5
5
  "repository": "https://github.com/KensioSoftware/yulin",
6
6
  "type": "module",
7
- "main": "index.js",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
8
9
  "keywords": [
9
10
  "aws",
10
11
  "test",
@@ -13,32 +14,43 @@
13
14
  "simulator",
14
15
  "isolated"
15
16
  ],
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js"
21
+ },
22
+ "./cloudfront": {
23
+ "types": "./dist/service/cloudfront/index.d.ts",
24
+ "import": "./dist/service/cloudfront/index.js"
25
+ },
26
+ "./package.json": "./package.json"
27
+ },
16
28
  "author": "Kensio Software",
17
29
  "license": "AGPL-3.0",
18
30
  "devDependencies": {
19
- "@aws-sdk/client-dynamodb": "^3.1001.0",
20
- "@aws-sdk/client-s3": "^3.1001.0",
31
+ "@aws-sdk/client-dynamodb": "^3.1056.0",
32
+ "@aws-sdk/client-s3": "^3.1056.0",
21
33
  "@eslint/js": "^10.0.1",
22
- "@kensio/smartass": "^0.1.4",
23
- "@smithy/smithy-client": "^4.12.1",
24
- "@smithy/types": "^4.13.0",
34
+ "@kensio/smartass": "^1.0.0",
35
+ "@smithy/smithy-client": "^4.13.5",
36
+ "@smithy/types": "^4.14.2",
25
37
  "@types/eslint-plugin-security": "^3.0.1",
26
38
  "@types/lodash-es": "^4.17.12",
27
- "@types/node": "^25.3.0",
28
- "@vitest/coverage-v8": "4.0.18",
29
- "@vitest/eslint-plugin": "^1.6.9",
39
+ "@types/node": "^25.9.1",
40
+ "@vitest/coverage-v8": "^4.1.7",
41
+ "@vitest/eslint-plugin": "^1.6.18",
30
42
  "aws-sdk-client-mock": "^4.1.0",
31
- "eslint": "^10.0.1",
43
+ "eslint": "^10.4.0",
32
44
  "eslint-config-prettier": "^10.1.8",
33
- "eslint-plugin-jsdoc": "^62.7.1",
34
- "eslint-plugin-no-secrets": "^2.2.2",
45
+ "eslint-plugin-jsdoc": "^62.9.0",
46
+ "eslint-plugin-no-secrets": "^2.3.3",
35
47
  "eslint-plugin-security": "^4.0.0",
36
48
  "eslint-plugin-unicorn": "^63.0.0",
37
- "globals": "^17.3.0",
38
- "jiti": "^2.6.1",
39
- "prettier": "^3.8.1",
40
- "typescript-eslint": "^8.56.0",
41
- "vitest": "^4.0.18"
49
+ "globals": "^17.6.0",
50
+ "jiti": "^2.7.0",
51
+ "prettier": "^3.8.3",
52
+ "typescript-eslint": "^8.60.0",
53
+ "vitest": "^4.1.7"
42
54
  },
43
55
  "peerDependencies": {
44
56
  "@aws-sdk/client-dynamodb": "^3.1001.0",
@@ -57,7 +69,8 @@
57
69
  }
58
70
  },
59
71
  "dependencies": {
60
- "lodash-es": "^4.17.23"
72
+ "@kensio/part-factory": "^0.1.1",
73
+ "lodash-es": "^4.18.1"
61
74
  },
62
75
  "scripts": {
63
76
  "build": "tsc -p tsconfig.build.json",
@@ -1 +1,23 @@
1
- useNodeVersion: 24.13.1
1
+ minimumReleaseAgeExclude:
2
+ - '@aws-sdk/client-dynamodb@3.1056.0'
3
+ - '@aws-sdk/client-s3@3.1056.0'
4
+ - '@aws-sdk/core@3.974.15'
5
+ - '@aws-sdk/credential-provider-env@3.972.41'
6
+ - '@aws-sdk/credential-provider-http@3.972.43'
7
+ - '@aws-sdk/credential-provider-ini@3.972.45'
8
+ - '@aws-sdk/credential-provider-login@3.972.45'
9
+ - '@aws-sdk/credential-provider-node@3.972.46'
10
+ - '@aws-sdk/credential-provider-process@3.972.41'
11
+ - '@aws-sdk/credential-provider-sso@3.972.45'
12
+ - '@aws-sdk/credential-provider-web-identity@3.972.45'
13
+ - '@aws-sdk/dynamodb-codec@3.973.15'
14
+ - '@aws-sdk/middleware-bucket-endpoint@3.972.17'
15
+ - '@aws-sdk/middleware-endpoint-discovery@3.972.15'
16
+ - '@aws-sdk/middleware-expect-continue@3.972.14'
17
+ - '@aws-sdk/middleware-flexible-checksums@3.974.23'
18
+ - '@aws-sdk/middleware-sdk-s3@3.972.44'
19
+ - '@aws-sdk/nested-clients@3.997.13'
20
+ - '@aws-sdk/signature-v4-multi-region@3.996.30'
21
+ - '@aws-sdk/token-providers@3.1056.0'
22
+ - '@kensio/smartass@1.0.0'
23
+ useNodeVersion: 24.16.0
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -Eeuo pipefail
4
+
5
+ pnpm install
6
+ pnpm lint
7
+ pnpm test:coverage
8
+ pnpm build
9
+ pnpm pack --dry-run
10
+ pnpm version patch
11
+ pnpm login
12
+ pnpm publish --access public
13
+ git push
14
+ git push --tags
package/src/index.ts ADDED
File without changes
@@ -0,0 +1,10 @@
1
+ import { describe, it } from "vitest";
2
+ import { cloudFrontRequestFactory } from "./cloudfront-functions.factory.js";
3
+ import { assertObjectMatches } from "@kensio/smartass";
4
+
5
+ describe("CloudFront Functions object factories", () => {
6
+ it("makes a valid CloudFront Functions request object", () => {
7
+ const cffReq = cloudFrontRequestFactory.make();
8
+ assertObjectMatches(cffReq, { headers: { host: { value: "yulin.test" } } });
9
+ });
10
+ });
@@ -0,0 +1,34 @@
1
+ import type { CloudFrontRequest } from "../typings/cloudfront-functions.js";
2
+ import { StaticFactory } from "@kensio/part-factory";
3
+
4
+ /**
5
+ * Makes instances of the CloudFrontRequest object structure.
6
+ */
7
+ export const cloudFrontRequestFactory = new StaticFactory<CloudFrontRequest>({
8
+ cookies: {
9
+ sessionId: {
10
+ value: "test-session-id",
11
+ },
12
+ },
13
+ headers: {
14
+ accept: {
15
+ value: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
16
+ },
17
+ "accept-language": {
18
+ value: "en-GB,en;q=0.9",
19
+ },
20
+ host: {
21
+ value: "yulin.test",
22
+ },
23
+ "user-agent": {
24
+ value: "Mozilla/5.0",
25
+ },
26
+ },
27
+ method: "GET",
28
+ querystring: {
29
+ page: {
30
+ value: "1",
31
+ },
32
+ },
33
+ uri: "/cloudfront/",
34
+ });
@@ -0,0 +1,13 @@
1
+ export { cloudFrontRequestFactory } from "./factory/cloudfront-functions.factory.js";
2
+ export type {
3
+ CloudFrontCookies,
4
+ CloudFrontEvent,
5
+ CloudFrontEventContext,
6
+ CloudFrontHeaders,
7
+ CloudFrontMultiValue,
8
+ CloudFrontQueryString,
9
+ CloudFrontRequest,
10
+ CloudFrontResponse,
11
+ CloudFrontValue,
12
+ CloudFrontViewer,
13
+ } from "./typings/cloudfront-functions.js";
@@ -0,0 +1,48 @@
1
+ export interface CloudFrontValue {
2
+ value: string;
3
+ }
4
+
5
+ export interface CloudFrontMultiValue {
6
+ multiValue: CloudFrontValue[];
7
+ }
8
+
9
+ export type CloudFrontHeaders = Record<string, CloudFrontValue>;
10
+
11
+ export type CloudFrontQueryString = Record<
12
+ string,
13
+ CloudFrontValue | CloudFrontMultiValue
14
+ >;
15
+
16
+ export type CloudFrontCookies = Record<string, CloudFrontValue>;
17
+
18
+ export interface CloudFrontRequest {
19
+ method: string;
20
+ uri: string;
21
+ headers: CloudFrontHeaders;
22
+ querystring: CloudFrontQueryString;
23
+ cookies: CloudFrontCookies;
24
+ }
25
+
26
+ export interface CloudFrontResponse {
27
+ statusCode: number;
28
+ statusDescription?: string;
29
+ headers?: CloudFrontHeaders;
30
+ }
31
+
32
+ export interface CloudFrontEventContext {
33
+ distributionDomainName?: string;
34
+ endpoint?: string;
35
+ distributionId?: string;
36
+ eventType: "viewer-request" | "viewer-response";
37
+ requestId: string;
38
+ }
39
+
40
+ export interface CloudFrontViewer {
41
+ ip: string;
42
+ }
43
+
44
+ export interface CloudFrontEvent {
45
+ context: CloudFrontEventContext;
46
+ viewer: CloudFrontViewer;
47
+ request: CloudFrontRequest;
48
+ }
@@ -1,5 +1,5 @@
1
- import type { DynamoDbTableName } from "../../dynamodb-table.js";
2
- import { SimDynamoDbTable } from "../../dynamodb-table.js";
1
+ import type { DynamoDbTableName } from "../../table/dynamodb-table.js";
2
+ import { SimDynamoDbTable } from "../../table/dynamodb-table.js";
3
3
  import {
4
4
  type CreateTableCommand,
5
5
  type CreateTableCommandOutput,
@@ -11,6 +11,8 @@ import { jitter } from "../../../../util/sleep.js";
11
11
 
12
12
  /**
13
13
  * DynamoDB CreateTableCommand handler.
14
+ *
15
+ * https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/CreateTableCommand/
14
16
  */
15
17
  export class CreateTableCommandHandler implements CommandHandler<
16
18
  CreateTableCommand,
@@ -39,7 +41,7 @@ export class CreateTableCommandHandler implements CommandHandler<
39
41
 
40
42
  await jitter();
41
43
 
42
- const table = new SimDynamoDbTable(cmd);
44
+ const table = new SimDynamoDbTable(cmd, this.background);
43
45
  this.tables.set(tableName, table);
44
46
 
45
47
  this.background.schedule(() => table.activate());
@@ -10,6 +10,7 @@ import {
10
10
  assertIdentical,
11
11
  assertInstanceOf,
12
12
  assertNonNullable,
13
+ assertStringIncludes,
13
14
  assertThrowsErrorAsync,
14
15
  } from "@kensio/smartass";
15
16
 
@@ -19,7 +20,10 @@ describe("DynamoDB CreateTableCommand", () => {
19
20
  const simDynamoDb = simAccount.getDynamoDb();
20
21
 
21
22
  const createTableOutput = await simDynamoDb.createTable(
22
- new CreateTableCommand({ TableName: "FoobarTable" }),
23
+ new CreateTableCommand({
24
+ TableName: "FoobarTable",
25
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
26
+ }),
23
27
  );
24
28
 
25
29
  assertNonNullable(createTableOutput.TableDescription);
@@ -43,9 +47,34 @@ describe("DynamoDB CreateTableCommand", () => {
43
47
  const simAccount = new SimAwsAccount();
44
48
  const simDynamoDb = simAccount.getDynamoDb();
45
49
 
46
- await assertThrowsErrorAsync(async () =>
47
- simDynamoDb.createTable(new CreateTableCommand({ TableName: undefined })),
50
+ const error = await assertThrowsErrorAsync(async () =>
51
+ simDynamoDb.createTable(
52
+ new CreateTableCommand({
53
+ TableName: undefined,
54
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
55
+ }),
56
+ ),
57
+ );
58
+
59
+ assertInstanceOf(error, Error);
60
+ assertStringIncludes(
61
+ error.message,
62
+ "CreateTableCommand.input.TableName is required",
63
+ );
64
+ });
65
+
66
+ it("throws on missing key schema", async () => {
67
+ const simAccount = new SimAwsAccount();
68
+ const simDynamoDb = simAccount.getDynamoDb();
69
+
70
+ const error = await assertThrowsErrorAsync(async () =>
71
+ simDynamoDb.createTable(
72
+ new CreateTableCommand({ TableName: "FoobarTable" }),
73
+ ),
48
74
  );
75
+
76
+ assertInstanceOf(error, Error);
77
+ assertStringIncludes(error.message, "Table KeySchema is not defined");
49
78
  });
50
79
 
51
80
  it("throws on duplicate Table name", async () => {
@@ -53,7 +82,10 @@ describe("DynamoDB CreateTableCommand", () => {
53
82
  const simDynamoDb = simAccount.getDynamoDb();
54
83
 
55
84
  await simDynamoDb.createTable(
56
- new CreateTableCommand({ TableName: "FoobarTable" }),
85
+ new CreateTableCommand({
86
+ TableName: "FoobarTable",
87
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
88
+ }),
57
89
  );
58
90
 
59
91
  const error = await assertThrowsErrorAsync(async () =>
@@ -7,11 +7,13 @@ import type { CommandHandler } from "../../../../command/command-handler.js";
7
7
  import type {
8
8
  DynamoDbTableName,
9
9
  SimDynamoDbTable,
10
- } from "../../dynamodb-table.js";
10
+ } from "../../table/dynamodb-table.js";
11
11
  import { jitter } from "../../../../util/sleep.js";
12
12
 
13
13
  /**
14
14
  * DynamoDB DescribeTableCommand handler.
15
+ *
16
+ * https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/DescribeTableCommand/
15
17
  */
16
18
  export class DescribeTableCommandHandler implements CommandHandler<
17
19
  DescribeTableCommand,
@@ -19,9 +19,24 @@ describe("DynamoDB DescribeTableCommand", () => {
19
19
  const simDynamoDb = simAccount.getDynamoDb();
20
20
 
21
21
  await Promise.all([
22
- simDynamoDb.createTable(new CreateTableCommand({ TableName: "TableA" })),
23
- simDynamoDb.createTable(new CreateTableCommand({ TableName: "TableB" })),
24
- simDynamoDb.createTable(new CreateTableCommand({ TableName: "TableC" })),
22
+ simDynamoDb.createTable(
23
+ new CreateTableCommand({
24
+ TableName: "TableA",
25
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
26
+ }),
27
+ ),
28
+ simDynamoDb.createTable(
29
+ new CreateTableCommand({
30
+ TableName: "TableB",
31
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
32
+ }),
33
+ ),
34
+ simDynamoDb.createTable(
35
+ new CreateTableCommand({
36
+ TableName: "TableC",
37
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
38
+ }),
39
+ ),
25
40
  ]);
26
41
 
27
42
  const describeTableOutput = await simDynamoDb.describeTable(
@@ -6,11 +6,13 @@ import type {
6
6
  import type {
7
7
  DynamoDbTableName,
8
8
  SimDynamoDbTable,
9
- } from "../../dynamodb-table.js";
9
+ } from "../../table/dynamodb-table.js";
10
10
  import { jitter } from "../../../../util/sleep.js";
11
11
 
12
12
  /**
13
13
  * Simulated DynamoDB ListTablesCommand handler.
14
+ *
15
+ * https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/ListTablesCommand/
14
16
  */
15
17
  export class ListTablesCommandHandler implements CommandHandler<
16
18
  ListTablesCommand,
@@ -12,9 +12,24 @@ describe("DynamoDB ListTablesCommand", () => {
12
12
  const simDynamoDb = simAccount.getDynamoDb();
13
13
 
14
14
  await Promise.all([
15
- simDynamoDb.createTable(new CreateTableCommand({ TableName: "TableA" })),
16
- simDynamoDb.createTable(new CreateTableCommand({ TableName: "TableB" })),
17
- simDynamoDb.createTable(new CreateTableCommand({ TableName: "TableC" })),
15
+ simDynamoDb.createTable(
16
+ new CreateTableCommand({
17
+ TableName: "TableA",
18
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
19
+ }),
20
+ ),
21
+ simDynamoDb.createTable(
22
+ new CreateTableCommand({
23
+ TableName: "TableB",
24
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
25
+ }),
26
+ ),
27
+ simDynamoDb.createTable(
28
+ new CreateTableCommand({
29
+ TableName: "TableC",
30
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
31
+ }),
32
+ ),
18
33
  ]);
19
34
 
20
35
  const listTablesOutput = await simDynamoDb.listTables(
@@ -35,9 +50,24 @@ describe("DynamoDB ListTablesCommand", () => {
35
50
  const simDynamoDb = simAccount.getDynamoDb();
36
51
 
37
52
  await Promise.all([
38
- simDynamoDb.createTable(new CreateTableCommand({ TableName: "TableA" })),
39
- simDynamoDb.createTable(new CreateTableCommand({ TableName: "TableB" })),
40
- simDynamoDb.createTable(new CreateTableCommand({ TableName: "TableC" })),
53
+ simDynamoDb.createTable(
54
+ new CreateTableCommand({
55
+ TableName: "TableA",
56
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
57
+ }),
58
+ ),
59
+ simDynamoDb.createTable(
60
+ new CreateTableCommand({
61
+ TableName: "TableB",
62
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
63
+ }),
64
+ ),
65
+ simDynamoDb.createTable(
66
+ new CreateTableCommand({
67
+ TableName: "TableC",
68
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
69
+ }),
70
+ ),
41
71
  ]);
42
72
 
43
73
  const listTablesOutput = await simDynamoDb.listTables(
@@ -57,9 +87,24 @@ describe("DynamoDB ListTablesCommand", () => {
57
87
  const simDynamoDb = simAccount.getDynamoDb();
58
88
 
59
89
  await Promise.all([
60
- simDynamoDb.createTable(new CreateTableCommand({ TableName: "TableA" })),
61
- simDynamoDb.createTable(new CreateTableCommand({ TableName: "TableB" })),
62
- simDynamoDb.createTable(new CreateTableCommand({ TableName: "TableC" })),
90
+ simDynamoDb.createTable(
91
+ new CreateTableCommand({
92
+ TableName: "TableA",
93
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
94
+ }),
95
+ ),
96
+ simDynamoDb.createTable(
97
+ new CreateTableCommand({
98
+ TableName: "TableB",
99
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
100
+ }),
101
+ ),
102
+ simDynamoDb.createTable(
103
+ new CreateTableCommand({
104
+ TableName: "TableC",
105
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
106
+ }),
107
+ ),
63
108
  ]);
64
109
 
65
110
  const listTablesOutput = await simDynamoDb.listTables(
@@ -0,0 +1,56 @@
1
+ import type { CommandHandler } from "../../../../command/command-handler.js";
2
+ import {
3
+ type PutItemCommand,
4
+ type PutItemCommandOutput,
5
+ ResourceNotFoundException,
6
+ } from "@aws-sdk/client-dynamodb";
7
+ import type {
8
+ DynamoDbTableName,
9
+ SimDynamoDbTable,
10
+ } from "../../table/dynamodb-table.js";
11
+ import { DynamoDbItem } from "../../item/dynamodb-item.js";
12
+
13
+ /**
14
+ * DynamoDB PutItemCommand handler.
15
+ *
16
+ * https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/PutItemCommand/
17
+ */
18
+ export class PutItemCommandHandler implements CommandHandler<
19
+ PutItemCommand,
20
+ PutItemCommandOutput
21
+ > {
22
+ constructor(
23
+ private readonly tables: Map<DynamoDbTableName, SimDynamoDbTable>,
24
+ ) {}
25
+
26
+ /**
27
+ * Put an Item into a DynamoDB Table.
28
+ */
29
+ async handle(cmd: PutItemCommand): Promise<PutItemCommandOutput> {
30
+ const tableName = cmd.input.TableName as DynamoDbTableName | undefined;
31
+ if (tableName === undefined) {
32
+ throw new Error("PutItemCommand.input.TableName is required");
33
+ }
34
+
35
+ const table = this.tables.get(tableName);
36
+ if (table === undefined) {
37
+ throw new ResourceNotFoundException({
38
+ message: `No DynamoDB Table named ${tableName}`,
39
+ $metadata: {},
40
+ });
41
+ }
42
+
43
+ if (cmd.input.Item === undefined) {
44
+ throw new Error("PutItemCommand.input.Item is required");
45
+ }
46
+
47
+ const item = DynamoDbItem.fromAttributeValues(cmd.input.Item);
48
+
49
+ await table.putItem(item);
50
+
51
+ return {
52
+ Attributes: item.toAttributeValues(),
53
+ $metadata: {},
54
+ };
55
+ }
56
+ }