@schorts/shared-kernel 1.0.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 (88) hide show
  1. package/.idx/airules.md +186 -0
  2. package/.idx/dev.nix +54 -0
  3. package/.vscode/settings.json +7 -0
  4. package/CHANGELOG +0 -0
  5. package/README.md +98 -0
  6. package/__tests__/auth/auth-provider.test.ts +45 -0
  7. package/__tests__/auth/require-auth.decorator.test.ts +88 -0
  8. package/__tests__/criteria/criteria.test.ts +159 -0
  9. package/__tests__/criteria/direction.test.ts +11 -0
  10. package/__tests__/criteria/filter-criterion.test.ts +15 -0
  11. package/__tests__/criteria/operator.test.ts +22 -0
  12. package/__tests__/criteria/order.test.ts +14 -0
  13. package/__tests__/domain-events/domain-event-primitives.test.ts +34 -0
  14. package/__tests__/domain-events/domain-event.test.ts +50 -0
  15. package/__tests__/entities/entity.test.ts +114 -0
  16. package/__tests__/formatters/pascal-camel-to-snake.test.ts +19 -0
  17. package/__tests__/http/fetch-http-provider.test.ts +155 -0
  18. package/__tests__/http/http-provider.test.ts +55 -0
  19. package/__tests__/json-api/json-api-connector.test.ts +78 -0
  20. package/__tests__/json-api/json-api-list.test.ts +24 -0
  21. package/__tests__/json-api/json-api-single.test.ts +24 -0
  22. package/__tests__/json-api/url-criteria-builder.test.ts +74 -0
  23. package/__tests__/messages/message.test.ts +16 -0
  24. package/__tests__/models/base-model.test.ts +10 -0
  25. package/__tests__/state-manager/state-manager.test.ts +101 -0
  26. package/__tests__/utils/url/url-with-params-builder.test.ts +39 -0
  27. package/__tests__/value-objects/coordinates-value.test.ts +68 -0
  28. package/__tests__/value-objects/email-value.test.ts +43 -0
  29. package/__tests__/value-objects/enum-value.test.ts +51 -0
  30. package/__tests__/value-objects/integer-value.test.ts +115 -0
  31. package/__tests__/value-objects/phone-value.test.ts +82 -0
  32. package/__tests__/value-objects/slug-value.test.ts +43 -0
  33. package/__tests__/value-objects/string-value.test.ts +121 -0
  34. package/__tests__/value-objects/uuid-value.test.ts +67 -0
  35. package/__tests__/value-objects/value-object.test.ts +25 -0
  36. package/jest.config.js +25 -0
  37. package/package.json +289 -0
  38. package/src/auth/auth-provider.ts +10 -0
  39. package/src/auth/exceptions/index.ts +1 -0
  40. package/src/auth/exceptions/not-authenticated.ts +1 -0
  41. package/src/auth/index.ts +3 -0
  42. package/src/auth/require-auth.decorator.ts +41 -0
  43. package/src/criteria/criteria.ts +51 -0
  44. package/src/criteria/direction.ts +1 -0
  45. package/src/criteria/exceptions/index.ts +2 -0
  46. package/src/criteria/exceptions/limit-not-valid.ts +1 -0
  47. package/src/criteria/exceptions/offset-not-valid.ts +1 -0
  48. package/src/criteria/filter-criterion.ts +6 -0
  49. package/src/criteria/index.ts +7 -0
  50. package/src/criteria/operator.ts +12 -0
  51. package/src/criteria/order.ts +4 -0
  52. package/src/domain-events/domain-event-primitives.ts +7 -0
  53. package/src/domain-events/domain-event.ts +15 -0
  54. package/src/domain-events/index.ts +2 -0
  55. package/src/entities/entity.ts +22 -0
  56. package/src/entities/index.ts +1 -0
  57. package/src/formatters/index.ts +1 -0
  58. package/src/formatters/pascal-camel-to-snake.ts +8 -0
  59. package/src/http/exceptions/http-exception.ts +8 -0
  60. package/src/http/exceptions/index.ts +1 -0
  61. package/src/http/fetch-http-provider.ts +120 -0
  62. package/src/http/http-provider.ts +7 -0
  63. package/src/http/index.ts +4 -0
  64. package/src/json-api/index.ts +4 -0
  65. package/src/json-api/json-api-connector.ts +56 -0
  66. package/src/json-api/json-api-list.ts +13 -0
  67. package/src/json-api/json-api-single.ts +13 -0
  68. package/src/json-api/url-criteria-builder.ts +49 -0
  69. package/src/messages/index.ts +1 -0
  70. package/src/messages/message.ts +3 -0
  71. package/src/models/base-model.ts +3 -0
  72. package/src/models/index.ts +1 -0
  73. package/src/state-manager/index.ts +1 -0
  74. package/src/state-manager/state-manager.ts +28 -0
  75. package/src/utils/index.ts +1 -0
  76. package/src/utils/url/index.ts +1 -0
  77. package/src/utils/url/url-with-params-builder.ts +19 -0
  78. package/src/value-objects/coordinates-value.ts +50 -0
  79. package/src/value-objects/email-value.ts +25 -0
  80. package/src/value-objects/enum-value.ts +25 -0
  81. package/src/value-objects/index.ts +10 -0
  82. package/src/value-objects/integer-value.ts +29 -0
  83. package/src/value-objects/phone-value.ts +53 -0
  84. package/src/value-objects/slug-value.ts +25 -0
  85. package/src/value-objects/string-value.ts +27 -0
  86. package/src/value-objects/uuid-value.ts +34 -0
  87. package/src/value-objects/value-object.ts +7 -0
  88. package/tsconfig.json +46 -0
@@ -0,0 +1,67 @@
1
+ import { expectTypeOf } from "expect-type";
2
+
3
+ import { ValueObject, UUIDValue } from "../../src/value-objects";
4
+
5
+ class TestUUIDValue extends UUIDValue {
6
+ readonly attributeName = "test";
7
+ }
8
+
9
+ describe("UUIDValue", () => {
10
+ it('should implement "ValueObject" interface', () => {
11
+ expectTypeOf<UUIDValue>().toExtend<ValueObject>();
12
+ });
13
+
14
+ it('should have a "valueType" with "UUID" as value', () => {
15
+ const testUUIDvalue = new TestUUIDValue();
16
+
17
+ expect(testUUIDvalue.valueType).toEqual("UUID");
18
+ });
19
+
20
+ it('should have a "value" property of type string | undefined', () => {
21
+ expectTypeOf<UUIDValue["value"]>().toEqualTypeOf<string | undefined>();
22
+ });
23
+
24
+ it('should have a "optional" property of type boolean', () => {
25
+ expectTypeOf<UUIDValue["optional"]>().toBeBoolean();
26
+ });
27
+
28
+ it('should define the "equals" method', () => {
29
+ expectTypeOf<UUIDValue["equals"]>().toEqualTypeOf<(valueObject: unknown) => boolean>();
30
+ });
31
+
32
+ describe('when "value" is present', () => {
33
+ describe('when "value" is valid', () => {
34
+ it('should have a getter "isValid" that returns true', () => {
35
+ const testUUIDvalue = new TestUUIDValue("87a00bc1-c586-4d23-bfc7-dd637628777c");
36
+
37
+ expect(testUUIDvalue.isValid).toBeTruthy();
38
+ });
39
+ });
40
+
41
+ describe('when "value" is not valid', () => {
42
+ it('should have a getter "isValid" that returns false', () => {
43
+ const testUUIDvalue = new TestUUIDValue("dummy-uuid-12346-5734");
44
+
45
+ expect(testUUIDvalue.isValid).toBeFalsy();
46
+ });
47
+ });
48
+ });
49
+
50
+ describe('when "value" is not present', () => {
51
+ describe('when "value" is optional', () => {
52
+ it('should have a getter "isValid" that returns true', () => {
53
+ const testUUIDvalue = new TestUUIDValue(undefined, true);
54
+
55
+ expect(testUUIDvalue.isValid).toBeTruthy();
56
+ });
57
+ });
58
+
59
+ describe('when "value" is not optional', () => {
60
+ it('should have a getter "isValid" that runs the validations normally and returns false', () => {
61
+ const testUUIDvalue = new TestUUIDValue(undefined, false);
62
+
63
+ expect(testUUIDvalue.isValid).toBeFalsy();
64
+ });
65
+ });
66
+ });
67
+ });
@@ -0,0 +1,25 @@
1
+ import { expectTypeOf } from "expect-type";
2
+
3
+ import { ValueObject } from "../../src/value-objects";
4
+
5
+ describe("ValueObject", () => {
6
+ it('should have a "value" property of type unknown', () => {
7
+ expectTypeOf<ValueObject>().toHaveProperty("value");
8
+ expectTypeOf<ValueObject['value']>().toBeUnknown();
9
+ });
10
+
11
+ it('should have a "isValid" property of type boolean', () => {
12
+ expectTypeOf<ValueObject>().toHaveProperty("isValid");
13
+ expectTypeOf<ValueObject['isValid']>().toBeBoolean();
14
+ });
15
+
16
+ it('should have a "valueType" property of type string', () => {
17
+ expectTypeOf<ValueObject>().toHaveProperty("valueType");
18
+ expectTypeOf<ValueObject['valueType']>().toBeString();
19
+ });
20
+
21
+ it('should have a "attributeName" property of type string', () => {
22
+ expectTypeOf<ValueObject>().toHaveProperty("attributeName");
23
+ expectTypeOf<ValueObject['attributeName']>().toBeString();
24
+ });
25
+ });
package/jest.config.js ADDED
@@ -0,0 +1,25 @@
1
+ // jest.config.js
2
+ const { defaults: tsjPreset } = require("ts-jest/presets");
3
+ const { transform } = require("typescript");
4
+
5
+ module.exports = {
6
+ preset: "ts-jest/presets/default-esm",
7
+ testEnvironment: "node",
8
+ extensionsToTreatAsEsm: [".ts"],
9
+ transform: {
10
+ '^.+\\.(ts|tsx)$': ['ts-jest', { useESM: true }],
11
+ },
12
+ moduleFileExtensions: ["ts", "js", "json", "node"],
13
+ testMatch: ["**/__tests__/**/*.ts", "**/?(*.)+(spec|test).ts"],
14
+ collectCoverageFrom: [
15
+ "src/**/*.ts",
16
+ "!src/**/*.d.ts",
17
+ "!src/index.ts",
18
+ ],
19
+ coverageDirectory: "coverage",
20
+ coverageReporters: ["text", "lcov", "html"],
21
+ moduleNameMapper: {
22
+ "^@schorts/shared-kernel/(.*)$": "<rootDir>/src/$1",
23
+ },
24
+ };
25
+
package/package.json ADDED
@@ -0,0 +1,289 @@
1
+ {
2
+ "name": "@schorts/shared-kernel",
3
+ "version": "1.0.0",
4
+ "description": "A modular, type-safe foundation for building expressive, maintainable applications. This package provides core abstractions for domain modeling, HTTP integration, authentication, state management, and more — designed to be framework-agnostic and highly extensible.",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ "./auth": {
9
+ "import": "./dist/auth/index.js",
10
+ "types": "./dist/auth/index.d.ts"
11
+ },
12
+ "./criteria": {
13
+ "import": "./dist/criteria/index.js",
14
+ "types": "./dist/criteria/index.d.ts"
15
+ },
16
+ "./domain-events": {
17
+ "import": "./dist/domain-events/index.js",
18
+ "types": "./dist/domain-events/index.d.ts"
19
+ },
20
+ "./entities": {
21
+ "import": "./dist/entities/index.js",
22
+ "types": "./dist/entities/index.d.ts"
23
+ },
24
+ "./formatters": {
25
+ "import": "./dist/formatters/index.js",
26
+ "types": "./dist/formatters/index.d.ts"
27
+ },
28
+ "./http": {
29
+ "import": "./dist/http/index.js",
30
+ "types": "./dist/http/index.d.ts"
31
+ },
32
+ "./json-api": {
33
+ "import": "./dist/json-api/index.js",
34
+ "types": "./dist/json-api/index.d.ts"
35
+ },
36
+ "./messages": {
37
+ "import": "./dist/messages/index.js",
38
+ "types": "./dist/messages/index.d.ts"
39
+ },
40
+ "./models": {
41
+ "import": "./dist/models/index.js",
42
+ "types": "./dist/models/index.d.ts"
43
+ },
44
+ "./utils": {
45
+ "import": "./dist/utils/index.js",
46
+ "types": "./dist/utils/index.d.ts"
47
+ },
48
+ "./state-manager": {
49
+ "import": "./dist/state-manager/index.js",
50
+ "types": "./dist/state-manager/index.d.ts"
51
+ },
52
+ "./value-objects": {
53
+ "import": "./dist/value-objects/index.js",
54
+ "types": "./dist/value-objects/index.d.ts"
55
+ }
56
+ },
57
+ "scripts": {
58
+ "build": "tsc",
59
+ "test": "jest",
60
+ "test:watch": "jest --watch",
61
+ "test:coverage": "jest --coverage",
62
+ "test:ci": "jest --ci --coverage --watchAll=false"
63
+ },
64
+ "author": "Jorge Castillo (https://github.com/schorts)",
65
+ "license": "LGPL-3.0-or-later",
66
+ "devDependencies": {
67
+ "@jest/globals": "^30.1.2",
68
+ "@types/jest": "^30.0.0",
69
+ "@types/node": "^24.5.2",
70
+ "expect-type": "^1.2.2",
71
+ "jest": "^30.1.3",
72
+ "jest-html-reporter": "^4.3.0",
73
+ "ts-jest": "^29.4.4",
74
+ "typescript": "^5.9.2"
75
+ },
76
+ "dependencies": {
77
+ "ansi-escapes": "^4.3.2",
78
+ "ansi-regex": "^6.2.2",
79
+ "ansi-styles": "^4.3.0",
80
+ "anymatch": "^3.1.3",
81
+ "argparse": "^1.0.10",
82
+ "babel-jest": "^30.1.2",
83
+ "babel-plugin-istanbul": "^7.0.1",
84
+ "babel-plugin-jest-hoist": "^30.0.1",
85
+ "babel-preset-current-node-syntax": "^1.2.0",
86
+ "babel-preset-jest": "^30.0.1",
87
+ "balanced-match": "^1.0.2",
88
+ "baseline-browser-mapping": "^2.8.6",
89
+ "brace-expansion": "^2.0.2",
90
+ "braces": "^3.0.3",
91
+ "browserslist": "^4.26.2",
92
+ "bs-logger": "^0.2.6",
93
+ "bser": "^2.1.1",
94
+ "buffer-from": "^1.1.2",
95
+ "callsites": "^3.1.0",
96
+ "camelcase": "^5.3.1",
97
+ "caniuse-lite": "^1.0.30001743",
98
+ "chalk": "^4.1.2",
99
+ "char-regex": "^1.0.2",
100
+ "ci-info": "^4.3.0",
101
+ "cjs-module-lexer": "^2.1.0",
102
+ "cliui": "^8.0.1",
103
+ "co": "^4.6.0",
104
+ "collect-v8-coverage": "^1.0.2",
105
+ "color-convert": "^2.0.1",
106
+ "color-name": "^1.1.4",
107
+ "concat-map": "^0.0.1",
108
+ "convert-source-map": "^2.0.0",
109
+ "cross-spawn": "^7.0.6",
110
+ "dateformat": "^3.0.2",
111
+ "debug": "^4.4.3",
112
+ "dedent": "^1.7.0",
113
+ "deepmerge": "^4.3.1",
114
+ "detect-newline": "^3.1.0",
115
+ "eastasianwidth": "^0.2.0",
116
+ "electron-to-chromium": "^1.5.223",
117
+ "emittery": "^0.13.1",
118
+ "emoji-regex": "^9.2.2",
119
+ "error-ex": "^1.3.4",
120
+ "escalade": "^3.2.0",
121
+ "escape-string-regexp": "^2.0.0",
122
+ "esprima": "^4.0.1",
123
+ "execa": "^5.1.1",
124
+ "exit-x": "^0.2.2",
125
+ "expect": "^30.1.2",
126
+ "fast-json-stable-stringify": "^2.1.0",
127
+ "fb-watchman": "^2.0.2",
128
+ "fill-range": "^7.1.1",
129
+ "find-up": "^4.1.0",
130
+ "foreground-child": "^3.3.1",
131
+ "fs.realpath": "^1.0.0",
132
+ "gensync": "^1.0.0-beta.2",
133
+ "get-caller-file": "^2.0.5",
134
+ "get-package-type": "^0.1.0",
135
+ "get-stream": "^6.0.1",
136
+ "glob": "^10.4.5",
137
+ "graceful-fs": "^4.2.11",
138
+ "handlebars": "^4.7.8",
139
+ "has-flag": "^4.0.0",
140
+ "html-escaper": "^2.0.2",
141
+ "human-signals": "^2.1.0",
142
+ "import-local": "^3.2.0",
143
+ "imurmurhash": "^0.1.4",
144
+ "inflight": "^1.0.6",
145
+ "inherits": "^2.0.4",
146
+ "is-arrayish": "^0.2.1",
147
+ "is-fullwidth-code-point": "^3.0.0",
148
+ "is-generator-fn": "^2.1.0",
149
+ "is-number": "^7.0.0",
150
+ "is-stream": "^2.0.1",
151
+ "isexe": "^2.0.0",
152
+ "istanbul-lib-coverage": "^3.2.2",
153
+ "istanbul-lib-instrument": "^6.0.3",
154
+ "istanbul-lib-report": "^3.0.1",
155
+ "istanbul-lib-source-maps": "^5.0.6",
156
+ "istanbul-reports": "^3.2.0",
157
+ "jackspeak": "^3.4.3",
158
+ "jest-changed-files": "^30.0.5",
159
+ "jest-circus": "^30.1.3",
160
+ "jest-cli": "^30.1.3",
161
+ "jest-config": "^30.1.3",
162
+ "jest-diff": "^30.1.2",
163
+ "jest-docblock": "^30.0.1",
164
+ "jest-each": "^30.1.0",
165
+ "jest-environment-node": "^30.1.2",
166
+ "jest-haste-map": "^30.1.0",
167
+ "jest-leak-detector": "^30.1.0",
168
+ "jest-matcher-utils": "^30.1.2",
169
+ "jest-message-util": "^30.1.0",
170
+ "jest-mock": "^30.0.5",
171
+ "jest-pnp-resolver": "^1.2.3",
172
+ "jest-regex-util": "^30.0.1",
173
+ "jest-resolve": "^30.1.3",
174
+ "jest-resolve-dependencies": "^30.1.3",
175
+ "jest-runner": "^30.1.3",
176
+ "jest-runtime": "^30.1.3",
177
+ "jest-snapshot": "^30.1.2",
178
+ "jest-util": "^30.0.5",
179
+ "jest-validate": "^30.1.0",
180
+ "jest-watcher": "^30.1.3",
181
+ "jest-worker": "^30.1.0",
182
+ "js-tokens": "^4.0.0",
183
+ "js-yaml": "^3.14.1",
184
+ "jsesc": "^3.1.0",
185
+ "json-parse-even-better-errors": "^2.3.1",
186
+ "json5": "^2.2.3",
187
+ "leven": "^3.1.0",
188
+ "lines-and-columns": "^1.2.4",
189
+ "locate-path": "^5.0.0",
190
+ "lodash.memoize": "^4.1.2",
191
+ "lru-cache": "^5.1.1",
192
+ "make-dir": "^4.0.0",
193
+ "make-error": "^1.3.6",
194
+ "makeerror": "^1.0.12",
195
+ "merge-stream": "^2.0.0",
196
+ "micromatch": "^4.0.8",
197
+ "mimic-fn": "^2.1.0",
198
+ "minimatch": "^9.0.5",
199
+ "minimist": "^1.2.8",
200
+ "minipass": "^7.1.2",
201
+ "mkdirp": "^1.0.4",
202
+ "ms": "^2.1.3",
203
+ "napi-postinstall": "^0.3.3",
204
+ "natural-compare": "^1.4.0",
205
+ "neo-async": "^2.6.2",
206
+ "node-int64": "^0.4.0",
207
+ "node-releases": "^2.0.21",
208
+ "normalize-path": "^3.0.0",
209
+ "npm-run-path": "^4.0.1",
210
+ "once": "^1.4.0",
211
+ "onetime": "^5.1.2",
212
+ "p-limit": "^3.1.0",
213
+ "p-locate": "^4.1.0",
214
+ "p-try": "^2.2.0",
215
+ "package-json-from-dist": "^1.0.1",
216
+ "parse-json": "^5.2.0",
217
+ "path-exists": "^4.0.0",
218
+ "path-is-absolute": "^1.0.1",
219
+ "path-key": "^3.1.1",
220
+ "path-scurry": "^1.11.1",
221
+ "picocolors": "^1.1.1",
222
+ "picomatch": "^2.3.1",
223
+ "pirates": "^4.0.7",
224
+ "pkg-dir": "^4.2.0",
225
+ "pretty-format": "^30.0.5",
226
+ "pure-rand": "^7.0.1",
227
+ "react-is": "^18.3.1",
228
+ "require-directory": "^2.1.1",
229
+ "resolve-cwd": "^3.0.0",
230
+ "resolve-from": "^5.0.0",
231
+ "semver": "^6.3.1",
232
+ "shebang-command": "^2.0.0",
233
+ "shebang-regex": "^3.0.0",
234
+ "signal-exit": "^4.1.0",
235
+ "slash": "^3.0.0",
236
+ "source-map": "^0.6.1",
237
+ "source-map-support": "^0.5.13",
238
+ "sprintf-js": "^1.0.3",
239
+ "stack-utils": "^2.0.6",
240
+ "string-length": "^4.0.2",
241
+ "string-width": "^5.1.2",
242
+ "string-width-cjs": "^4.2.3",
243
+ "strip-ansi": "^7.1.2",
244
+ "strip-ansi-cjs": "^6.0.1",
245
+ "strip-bom": "^4.0.0",
246
+ "strip-final-newline": "^2.0.0",
247
+ "strip-json-comments": "^3.1.1",
248
+ "supports-color": "^7.2.0",
249
+ "synckit": "^0.11.11",
250
+ "test-exclude": "^6.0.0",
251
+ "tmpl": "^1.0.5",
252
+ "to-regex-range": "^5.0.1",
253
+ "type-detect": "^4.0.8",
254
+ "type-fest": "^0.21.3",
255
+ "uglify-js": "^3.19.3",
256
+ "undici-types": "^7.12.0",
257
+ "unrs-resolver": "^1.11.1",
258
+ "update-browserslist-db": "^1.1.3",
259
+ "v8-to-istanbul": "^9.3.0",
260
+ "walker": "^1.0.8",
261
+ "which": "^2.0.2",
262
+ "wordwrap": "^1.0.0",
263
+ "wrap-ansi": "^8.1.0",
264
+ "wrap-ansi-cjs": "^7.0.0",
265
+ "wrappy": "^1.0.2",
266
+ "write-file-atomic": "^5.0.1",
267
+ "xmlbuilder": "^15.0.0",
268
+ "y18n": "^5.0.8",
269
+ "yallist": "^3.1.1",
270
+ "yargs": "^17.7.2",
271
+ "yargs-parser": "^21.1.1",
272
+ "yocto-queue": "^0.1.0"
273
+ },
274
+ "repository": {
275
+ "type": "git",
276
+ "url": "git+https://github.com/schorts/shared-kernel.git"
277
+ },
278
+ "keywords": [
279
+ "shared-kernel",
280
+ "auth",
281
+ "jsonapi",
282
+ "kernel",
283
+ "value-objects"
284
+ ],
285
+ "bugs": {
286
+ "url": "https://github.com/schorts/shared-kernel/issues"
287
+ },
288
+ "homepage": "https://github.com/schorts/shared-kernel#readme"
289
+ }
@@ -0,0 +1,10 @@
1
+ import { Entity } from "../entities";
2
+ import { BaseModel } from "../models";
3
+
4
+ export interface AuthProvider<UserEntity extends Entity<BaseModel>> {
5
+ authenticate(...args: any[]): Promise<void>;
6
+ logout(): Promise<void>;
7
+ isAuthenticated(): Promise<boolean>;
8
+ currentUser(): Promise<UserEntity | null>;
9
+ onAuthChange(callback: (user: UserEntity | null) => void): () => void;
10
+ }
@@ -0,0 +1 @@
1
+ export { NotAuthenticated } from "./not-authenticated";
@@ -0,0 +1 @@
1
+ export class NotAuthenticated extends Error {}
@@ -0,0 +1,3 @@
1
+ export type { AuthProvider } from "./auth-provider";
2
+ export { RequireAuth } from "./require-auth.decorator";
3
+ export { NotAuthenticated } from "./exceptions";
@@ -0,0 +1,41 @@
1
+ import { AuthProvider } from "./auth-provider";
2
+ import { NotAuthenticated } from './exceptions';
3
+
4
+ export function RequireAuth(onFail?: () => any) {
5
+ function wrapper<T extends { authProvider?: AuthProvider<any> }, A extends any[], R>(
6
+ originalMethod: (this: T, ...args: A) => Promise<R>
7
+ ): (this: T, ...args: A) => Promise<R> {
8
+ return async function (this: T, ...args: A): Promise<R> {
9
+ if (!this.authProvider) {
10
+ throw new Error("authProvider: AuthProvider is required on this instance");
11
+ }
12
+
13
+ const isAuthenticated = await this.authProvider.isAuthenticated();
14
+
15
+ if (!isAuthenticated) {
16
+ if (onFail) {
17
+ return onFail();
18
+ } else {
19
+ throw new NotAuthenticated();
20
+ }
21
+ }
22
+
23
+ return await originalMethod.apply(this, args);
24
+ };
25
+ }
26
+
27
+ return function (...args: any[]) {
28
+ if (args.length === 3 && typeof args[2] === 'object') {
29
+ const descriptor = args[2] as PropertyDescriptor;
30
+ descriptor.value = wrapper(descriptor.value);
31
+ return descriptor;
32
+ }
33
+
34
+ if (args.length === 2 && typeof args[1] === 'object' && 'kind' in args[1]) {
35
+ const [originalMethod] = args;
36
+ return wrapper(originalMethod);
37
+ }
38
+
39
+ throw new Error("RequireAuth decorator used incorrectly");
40
+ };
41
+ }
@@ -0,0 +1,51 @@
1
+ import { FilterCriterion } from "./filter-criterion";
2
+ import { Order } from "./order";
3
+ import { Operator } from "./operator";
4
+ import { Direction } from "./direction";
5
+ import { OffsetNotValid, LimitNotValid } from "./exceptions";
6
+
7
+ export class Criteria {
8
+ readonly filters: Record<string, FilterCriterion> = {};
9
+ readonly orders: Array<Order> = [];
10
+ limit?: number;
11
+ offset?: number;
12
+
13
+ where(
14
+ field: string,
15
+ operator: Operator,
16
+ value: any,
17
+ ): Criteria {
18
+ this.filters[field] = { value, operator };
19
+
20
+ return this;
21
+ }
22
+
23
+ orderBy(
24
+ field: string,
25
+ direction: Direction = "ASC",
26
+ ): Criteria {
27
+ this.orders.push({ field, direction });
28
+
29
+ return this;
30
+ }
31
+
32
+ limitResults(limit: number): Criteria {
33
+ if (limit < 1) {
34
+ throw new LimitNotValid();
35
+ }
36
+
37
+ this.limit = limit;
38
+
39
+ return this;
40
+ }
41
+
42
+ offsetResults(offset: number): Criteria {
43
+ if (offset < 1) {
44
+ throw new OffsetNotValid();
45
+ }
46
+
47
+ this.offset = offset;
48
+
49
+ return this;
50
+ }
51
+ }
@@ -0,0 +1 @@
1
+ export type Direction = "ASC" | "DESC";
@@ -0,0 +1,2 @@
1
+ export { OffsetNotValid } from "./offset-not-valid";
2
+ export { LimitNotValid } from "./limit-not-valid";
@@ -0,0 +1 @@
1
+ export class LimitNotValid extends Error {}
@@ -0,0 +1 @@
1
+ export class OffsetNotValid extends Error {}
@@ -0,0 +1,6 @@
1
+ import { Operator } from "./operator";
2
+
3
+ export type FilterCriterion = {
4
+ value: any;
5
+ operator: Operator;
6
+ }
@@ -0,0 +1,7 @@
1
+ export type { Operator } from "./operator";
2
+ export type { Order } from "./order";
3
+ export type { FilterCriterion } from "./filter-criterion";
4
+ export type { Direction } from "./direction";
5
+
6
+ export { Criteria } from "./criteria";
7
+ export { OffsetNotValid, LimitNotValid } from "./exceptions";
@@ -0,0 +1,12 @@
1
+ export type Operator =
2
+ | "EQUAL"
3
+ | "GREATER_THAN"
4
+ | "LESS_THAN"
5
+ | "GREATER_THAN_OR_EQUAL"
6
+ | "LESS_THAN_OR_EQUAL"
7
+ | "NOT_EQUAL"
8
+ | "IN"
9
+ | "NOT_IN"
10
+ | "LIKE"
11
+ | "BETWEEN"
12
+ | "GEO_RADIUS";
@@ -0,0 +1,4 @@
1
+ export type Order = {
2
+ field: string;
3
+ direction: "ASC" | "DESC" | "NONE";
4
+ }
@@ -0,0 +1,7 @@
1
+ export type DomainEventPrimitives<PayloadSchema = {}> = {
2
+ id: string;
3
+ occurred_at: string;
4
+ type: string;
5
+ version: number;
6
+ payload: PayloadSchema;
7
+ };
@@ -0,0 +1,15 @@
1
+ import { Message } from "../messages";
2
+ import { DomainEventPrimitives } from "./domain-event-primitives";
3
+
4
+ export abstract class DomainEvent<PayloadSchema = {}> implements Message<DomainEventPrimitives<PayloadSchema>> {
5
+ constructor(
6
+ readonly id: string,
7
+ readonly occurredAt: Date,
8
+ readonly type: string,
9
+ readonly version: number,
10
+ readonly payload: PayloadSchema,
11
+ ) {}
12
+
13
+ abstract getEventName(): string;
14
+ abstract toPrimitives(): DomainEventPrimitives<PayloadSchema>;
15
+ }
@@ -0,0 +1,2 @@
1
+ export { DomainEvent } from "./domain-event";
2
+ export type { DomainEventPrimitives } from "./domain-event-primitives";
@@ -0,0 +1,22 @@
1
+ import { ValueObject } from "../value-objects";
2
+ import { BaseModel } from "../models";
3
+ import { DomainEvent } from "../domain-events";
4
+
5
+ export abstract class Entity<Model extends BaseModel> {
6
+ private domainEvents: Array<DomainEvent> = [];
7
+
8
+ constructor(readonly id: ValueObject) {}
9
+
10
+ pullDomainEvents(): Array<DomainEvent> {
11
+ const domainEvents = [...this.domainEvents];
12
+ this.domainEvents = [];
13
+
14
+ return domainEvents;
15
+ }
16
+
17
+ recordDomainEvent(domainEvent: DomainEvent): void {
18
+ this.domainEvents.push(domainEvent);
19
+ }
20
+
21
+ abstract toPrimitives(): Model;
22
+ }
@@ -0,0 +1 @@
1
+ export { Entity } from "./entity";
@@ -0,0 +1 @@
1
+ export { PascalCamelToSnake } from "./pascal-camel-to-snake";
@@ -0,0 +1,8 @@
1
+ export class PascalCamelToSnake {
2
+ static format(text: string) {
3
+ return text
4
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
5
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
6
+ .toLowerCase();
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ export class HTTPException extends Error {
2
+ constructor(
3
+ readonly message: string,
4
+ readonly statusCode: number,
5
+ ) {
6
+ super()
7
+ }
8
+ }
@@ -0,0 +1 @@
1
+ export { HTTPException } from "./http-exception";