@schafevormfenster/rest-commons 0.1.1

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 (264) hide show
  1. package/CONTRIBUTING.md +1190 -0
  2. package/README.md +275 -0
  3. package/bin/setup.js +10 -0
  4. package/dist/api-schemas/error.schema.d.ts +20 -0
  5. package/dist/api-schemas/error.schema.d.ts.map +1 -0
  6. package/dist/api-schemas/error.schema.js +17 -0
  7. package/dist/api-schemas/health.schema.d.ts +497 -0
  8. package/dist/api-schemas/health.schema.d.ts.map +1 -0
  9. package/dist/api-schemas/health.schema.js +33 -0
  10. package/dist/api-schemas/okay.schema.d.ts +13 -0
  11. package/dist/api-schemas/okay.schema.d.ts.map +1 -0
  12. package/dist/api-schemas/okay.schema.js +5 -0
  13. package/dist/api-schemas/paginated-results.schema.d.ts +59 -0
  14. package/dist/api-schemas/paginated-results.schema.d.ts.map +1 -0
  15. package/dist/api-schemas/paginated-results.schema.js +10 -0
  16. package/dist/api-schemas/partial-results.schema.d.ts +30 -0
  17. package/dist/api-schemas/partial-results.schema.d.ts.map +1 -0
  18. package/dist/api-schemas/partial-results.schema.js +10 -0
  19. package/dist/api-schemas/result.schema.d.ts +17 -0
  20. package/dist/api-schemas/result.schema.d.ts.map +1 -0
  21. package/dist/api-schemas/result.schema.js +5 -0
  22. package/dist/api-schemas/results.schema.d.ts +21 -0
  23. package/dist/api-schemas/results.schema.d.ts.map +1 -0
  24. package/dist/api-schemas/results.schema.js +5 -0
  25. package/dist/helpers/correlation/get-correlation-id.d.ts +7 -0
  26. package/dist/helpers/correlation/get-correlation-id.d.ts.map +1 -0
  27. package/dist/helpers/correlation/get-correlation-id.js +16 -0
  28. package/dist/helpers/correlation/get-header.d.ts +7 -0
  29. package/dist/helpers/correlation/get-header.d.ts.map +1 -0
  30. package/dist/helpers/correlation/get-header.js +11 -0
  31. package/dist/helpers/detect-mime-type.d.ts +11 -0
  32. package/dist/helpers/detect-mime-type.d.ts.map +1 -0
  33. package/dist/helpers/detect-mime-type.js +40 -0
  34. package/dist/helpers/detect-suspicious-patterns.d.ts +8 -0
  35. package/dist/helpers/detect-suspicious-patterns.d.ts.map +1 -0
  36. package/dist/helpers/detect-suspicious-patterns.js +55 -0
  37. package/dist/helpers/eventify-constants.types.d.ts +32 -0
  38. package/dist/helpers/eventify-constants.types.d.ts.map +1 -0
  39. package/dist/helpers/eventify-constants.types.js +40 -0
  40. package/dist/helpers/hash-binary.d.ts +21 -0
  41. package/dist/helpers/hash-binary.d.ts.map +1 -0
  42. package/dist/helpers/hash-binary.js +28 -0
  43. package/dist/helpers/mime-types/detect-image-mime-type.d.ts +5 -0
  44. package/dist/helpers/mime-types/detect-image-mime-type.d.ts.map +1 -0
  45. package/dist/helpers/mime-types/detect-image-mime-type.js +41 -0
  46. package/dist/helpers/mime-types/detect-ole-mime-type.d.ts +6 -0
  47. package/dist/helpers/mime-types/detect-ole-mime-type.d.ts.map +1 -0
  48. package/dist/helpers/mime-types/detect-ole-mime-type.js +34 -0
  49. package/dist/helpers/mime-types/detect-pdf-mime-type.d.ts +5 -0
  50. package/dist/helpers/mime-types/detect-pdf-mime-type.d.ts.map +1 -0
  51. package/dist/helpers/mime-types/detect-pdf-mime-type.js +13 -0
  52. package/dist/helpers/mime-types/detect-zip-mime-type.d.ts +6 -0
  53. package/dist/helpers/mime-types/detect-zip-mime-type.d.ts.map +1 -0
  54. package/dist/helpers/mime-types/detect-zip-mime-type.js +23 -0
  55. package/dist/helpers/parameter-validation.d.ts +6 -0
  56. package/dist/helpers/parameter-validation.d.ts.map +1 -0
  57. package/dist/helpers/parameter-validation.js +19 -0
  58. package/dist/helpers/parameter-validation.types.d.ts +16 -0
  59. package/dist/helpers/parameter-validation.types.d.ts.map +1 -0
  60. package/dist/helpers/parameter-validation.types.js +38 -0
  61. package/dist/helpers/response-headers/build-api-unauthorized-headers.d.ts +6 -0
  62. package/dist/helpers/response-headers/build-api-unauthorized-headers.d.ts.map +1 -0
  63. package/dist/helpers/response-headers/build-api-unauthorized-headers.js +23 -0
  64. package/dist/helpers/response-headers/environment.types.d.ts +2 -0
  65. package/dist/helpers/response-headers/environment.types.d.ts.map +1 -0
  66. package/dist/helpers/response-headers/environment.types.js +1 -0
  67. package/dist/helpers/response-headers/resolve-environment.d.ts +8 -0
  68. package/dist/helpers/response-headers/resolve-environment.d.ts.map +1 -0
  69. package/dist/helpers/response-headers/resolve-environment.js +18 -0
  70. package/dist/helpers/slugify.d.ts +15 -0
  71. package/dist/helpers/slugify.d.ts.map +1 -0
  72. package/dist/helpers/slugify.js +32 -0
  73. package/dist/index.d.ts +36 -0
  74. package/dist/index.d.ts.map +1 -0
  75. package/dist/index.js +41 -0
  76. package/dist/normalization/normalize-list.d.ts +11 -0
  77. package/dist/normalization/normalize-list.d.ts.map +1 -0
  78. package/dist/normalization/normalize-list.js +19 -0
  79. package/dist/normalization/normalize-location.d.ts +16 -0
  80. package/dist/normalization/normalize-location.d.ts.map +1 -0
  81. package/dist/normalization/normalize-location.js +26 -0
  82. package/dist/primitives/coordinate-precision.d.ts +10 -0
  83. package/dist/primitives/coordinate-precision.d.ts.map +1 -0
  84. package/dist/primitives/coordinate-precision.js +27 -0
  85. package/dist/primitives/geo-point.schema.d.ts +8 -0
  86. package/dist/primitives/geo-point.schema.d.ts.map +1 -0
  87. package/dist/primitives/geo-point.schema.js +10 -0
  88. package/dist/primitives/geoname-id.schema.d.ts +8 -0
  89. package/dist/primitives/geoname-id.schema.d.ts.map +1 -0
  90. package/dist/primitives/geoname-id.schema.js +9 -0
  91. package/dist/primitives/international-zip.schema.d.ts +76 -0
  92. package/dist/primitives/international-zip.schema.d.ts.map +1 -0
  93. package/dist/primitives/international-zip.schema.js +81 -0
  94. package/dist/primitives/latitude.schema.d.ts +9 -0
  95. package/dist/primitives/latitude.schema.d.ts.map +1 -0
  96. package/dist/primitives/latitude.schema.js +13 -0
  97. package/dist/primitives/location.schema.d.ts +8 -0
  98. package/dist/primitives/location.schema.d.ts.map +1 -0
  99. package/dist/primitives/location.schema.js +15 -0
  100. package/dist/primitives/longitude.schema.d.ts +9 -0
  101. package/dist/primitives/longitude.schema.d.ts.map +1 -0
  102. package/dist/primitives/longitude.schema.js +13 -0
  103. package/dist/primitives/numeric-id.schema.d.ts +8 -0
  104. package/dist/primitives/numeric-id.schema.d.ts.map +1 -0
  105. package/dist/primitives/numeric-id.schema.js +10 -0
  106. package/dist/primitives/slug.schema.d.ts +17 -0
  107. package/dist/primitives/slug.schema.d.ts.map +1 -0
  108. package/dist/primitives/slug.schema.js +30 -0
  109. package/dist/primitives/uuid.schema.d.ts +8 -0
  110. package/dist/primitives/uuid.schema.d.ts.map +1 -0
  111. package/dist/primitives/uuid.schema.js +9 -0
  112. package/dist/primitives/wikidata-id.schema.d.ts +9 -0
  113. package/dist/primitives/wikidata-id.schema.d.ts.map +1 -0
  114. package/dist/primitives/wikidata-id.schema.js +10 -0
  115. package/dist/time/boundary-enforcement.d.ts +11 -0
  116. package/dist/time/boundary-enforcement.d.ts.map +1 -0
  117. package/dist/time/boundary-enforcement.js +43 -0
  118. package/dist/time/bounded-time.schema.d.ts +31 -0
  119. package/dist/time/bounded-time.schema.d.ts.map +1 -0
  120. package/dist/time/bounded-time.schema.js +77 -0
  121. package/dist/time/flexible-time-parser.d.ts +12 -0
  122. package/dist/time/flexible-time-parser.d.ts.map +1 -0
  123. package/dist/time/flexible-time-parser.js +94 -0
  124. package/dist/time/flexible-time.schema.d.ts +31 -0
  125. package/dist/time/flexible-time.schema.d.ts.map +1 -0
  126. package/dist/time/flexible-time.schema.js +31 -0
  127. package/dist/time/get-week-end.d.ts +10 -0
  128. package/dist/time/get-week-end.d.ts.map +1 -0
  129. package/dist/time/get-week-end.js +25 -0
  130. package/dist/time/get-week-start.d.ts +10 -0
  131. package/dist/time/get-week-start.d.ts.map +1 -0
  132. package/dist/time/get-week-start.js +25 -0
  133. package/dist/time/is-relative-time.d.ts +8 -0
  134. package/dist/time/is-relative-time.d.ts.map +1 -0
  135. package/dist/time/is-relative-time.js +9 -0
  136. package/dist/time/iso8601.schema.d.ts +14 -0
  137. package/dist/time/iso8601.schema.d.ts.map +1 -0
  138. package/dist/time/iso8601.schema.js +17 -0
  139. package/dist/time/iso8601.types.d.ts +6 -0
  140. package/dist/time/iso8601.types.d.ts.map +1 -0
  141. package/dist/time/iso8601.types.js +11 -0
  142. package/dist/time/parse-relative-time.d.ts +9 -0
  143. package/dist/time/parse-relative-time.d.ts.map +1 -0
  144. package/dist/time/parse-relative-time.js +36 -0
  145. package/dist/time/relative-time.schema.d.ts +23 -0
  146. package/dist/time/relative-time.schema.d.ts.map +1 -0
  147. package/dist/time/relative-time.schema.js +25 -0
  148. package/dist/time/since-parameter.schema.d.ts +8 -0
  149. package/dist/time/since-parameter.schema.d.ts.map +1 -0
  150. package/dist/time/since-parameter.schema.js +56 -0
  151. package/dist/time/time-helpers.d.ts +19 -0
  152. package/dist/time/time-helpers.d.ts.map +1 -0
  153. package/dist/time/time-helpers.js +56 -0
  154. package/dist/time/time-schemas.d.ts +20 -0
  155. package/dist/time/time-schemas.d.ts.map +1 -0
  156. package/dist/time/time-schemas.js +25 -0
  157. package/dist/time/timezone.types.d.ts +17 -0
  158. package/dist/time/timezone.types.d.ts.map +1 -0
  159. package/dist/time/timezone.types.js +15 -0
  160. package/dist/validation/zod-error-handler.d.ts +3 -0
  161. package/dist/validation/zod-error-handler.d.ts.map +1 -0
  162. package/dist/validation/zod-error-handler.js +189 -0
  163. package/dist/validation/zod-utils.d.ts +9 -0
  164. package/dist/validation/zod-utils.d.ts.map +1 -0
  165. package/dist/validation/zod-utils.js +23 -0
  166. package/eslint.config.mjs +16 -0
  167. package/package.json +44 -0
  168. package/src/api-schemas/error.schema.test.ts +27 -0
  169. package/src/api-schemas/error.schema.ts +23 -0
  170. package/src/api-schemas/health.schema.test.ts +104 -0
  171. package/src/api-schemas/health.schema.ts +63 -0
  172. package/src/api-schemas/okay.schema.test.ts +15 -0
  173. package/src/api-schemas/okay.schema.ts +8 -0
  174. package/src/api-schemas/paginated-results.schema.ts +17 -0
  175. package/src/api-schemas/partial-results.schema.ts +13 -0
  176. package/src/api-schemas/result.schema.test.ts +19 -0
  177. package/src/api-schemas/result.schema.ts +9 -0
  178. package/src/api-schemas/results.schema.test.ts +15 -0
  179. package/src/api-schemas/results.schema.ts +9 -0
  180. package/src/helpers/correlation/get-correlation-id.test.ts +126 -0
  181. package/src/helpers/correlation/get-correlation-id.ts +22 -0
  182. package/src/helpers/correlation/get-header.test.ts +179 -0
  183. package/src/helpers/correlation/get-header.ts +21 -0
  184. package/src/helpers/detect-mime-type.test.ts +100 -0
  185. package/src/helpers/detect-mime-type.ts +46 -0
  186. package/src/helpers/detect-suspicious-patterns.test.ts +45 -0
  187. package/src/helpers/detect-suspicious-patterns.ts +57 -0
  188. package/src/helpers/eventify-constants.test.ts +52 -0
  189. package/src/helpers/eventify-constants.types.test.ts +52 -0
  190. package/src/helpers/eventify-constants.types.ts +51 -0
  191. package/src/helpers/hash-binary.test.ts +60 -0
  192. package/src/helpers/hash-binary.ts +30 -0
  193. package/src/helpers/mime-types/detect-image-mime-type.test.ts +73 -0
  194. package/src/helpers/mime-types/detect-image-mime-type.ts +50 -0
  195. package/src/helpers/mime-types/detect-ole-mime-type.test.ts +86 -0
  196. package/src/helpers/mime-types/detect-ole-mime-type.ts +44 -0
  197. package/src/helpers/mime-types/detect-pdf-mime-type.test.ts +39 -0
  198. package/src/helpers/mime-types/detect-pdf-mime-type.ts +15 -0
  199. package/src/helpers/mime-types/detect-zip-mime-type.test.ts +88 -0
  200. package/src/helpers/mime-types/detect-zip-mime-type.ts +28 -0
  201. package/src/helpers/parameter-validation.test.ts +35 -0
  202. package/src/helpers/parameter-validation.ts +32 -0
  203. package/src/helpers/process-eventify-request.ts +146 -0
  204. package/src/helpers/response-headers/build-api-unauthorized-headers.ts +30 -0
  205. package/src/helpers/response-headers/environment.types.ts +1 -0
  206. package/src/helpers/response-headers/resolve-environment.ts +17 -0
  207. package/src/helpers/slugify.test.ts +77 -0
  208. package/src/helpers/slugify.ts +34 -0
  209. package/src/index.ts +46 -0
  210. package/src/normalization/normalize-list.test.ts +43 -0
  211. package/src/normalization/normalize-list.ts +21 -0
  212. package/src/normalization/normalize-location.test.ts +91 -0
  213. package/src/normalization/normalize-location.ts +29 -0
  214. package/src/primitives/coordinate-precision.test.ts +46 -0
  215. package/src/primitives/coordinate-precision.ts +30 -0
  216. package/src/primitives/geo-point.schema.test.ts +70 -0
  217. package/src/primitives/geo-point.schema.ts +14 -0
  218. package/src/primitives/geoname-id.schema.test.ts +60 -0
  219. package/src/primitives/geoname-id.schema.ts +12 -0
  220. package/src/primitives/international-zip.schema.test.ts +212 -0
  221. package/src/primitives/international-zip.schema.ts +103 -0
  222. package/src/primitives/latitude.schema.test.ts +77 -0
  223. package/src/primitives/latitude.schema.ts +20 -0
  224. package/src/primitives/location.schema.test.ts +21 -0
  225. package/src/primitives/location.schema.ts +22 -0
  226. package/src/primitives/longitude.schema.test.ts +77 -0
  227. package/src/primitives/longitude.schema.ts +20 -0
  228. package/src/primitives/numeric-id.schema.test.ts +32 -0
  229. package/src/primitives/numeric-id.schema.ts +13 -0
  230. package/src/primitives/slug.schema.test.ts +101 -0
  231. package/src/primitives/slug.schema.ts +41 -0
  232. package/src/primitives/uuid.schema.test.ts +45 -0
  233. package/src/primitives/uuid.schema.ts +12 -0
  234. package/src/primitives/wikidata-id.schema.test.ts +51 -0
  235. package/src/primitives/wikidata-id.schema.ts +16 -0
  236. package/src/time/README.md +220 -0
  237. package/src/time/boundary-enforcement.test.ts +130 -0
  238. package/src/time/boundary-enforcement.ts +59 -0
  239. package/src/time/bounded-time.schema.test.ts +294 -0
  240. package/src/time/bounded-time.schema.ts +111 -0
  241. package/src/time/flexible-time-parser.test.ts +586 -0
  242. package/src/time/flexible-time-parser.ts +122 -0
  243. package/src/time/flexible-time.schema.test.ts +243 -0
  244. package/src/time/flexible-time.schema.ts +43 -0
  245. package/src/time/is-relative-time.test.ts +23 -0
  246. package/src/time/is-relative-time.ts +9 -0
  247. package/src/time/iso8601.schema.ts +29 -0
  248. package/src/time/iso8601.types.test.ts +112 -0
  249. package/src/time/iso8601.types.ts +21 -0
  250. package/src/time/parse-relative-time.test.ts +49 -0
  251. package/src/time/parse-relative-time.ts +50 -0
  252. package/src/time/relative-time.schema.test.ts +23 -0
  253. package/src/time/relative-time.schema.ts +38 -0
  254. package/src/time/since-parameter.schema.test.ts +59 -0
  255. package/src/time/since-parameter.schema.ts +69 -0
  256. package/src/time/time-helpers.test.ts +263 -0
  257. package/src/time/time-helpers.ts +78 -0
  258. package/src/time/time-schemas.test.ts +181 -0
  259. package/src/time/time-schemas.ts +42 -0
  260. package/src/time/time.schema.test.ts +237 -0
  261. package/src/time/timezone-independence.test.ts +188 -0
  262. package/src/time/timezone.types.test.ts +55 -0
  263. package/src/time/timezone.types.ts +22 -0
  264. package/tsconfig.json +26 -0
package/README.md ADDED
@@ -0,0 +1,275 @@
1
+ # @schafevormfenster/rest-commons
2
+
3
+ > Centralized authority for REST API standards and schemas
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@schafevormfenster/rest-commons.svg)](https://www.npmjs.com/package/@schafevormfenster/rest-commons)
6
+ [![License](https://img.shields.io/npm/l/@schafevormfenster/rest-commons.svg)](LICENSE)
7
+
8
+ ## What is this package?
9
+
10
+ **@schafevormfenster/rest-commons** is the central repository for REST API standards, schemas, and utilities used across all @schafevormfenster services. It provides a standardized foundation for building consistent, type-safe REST APIs with built-in validation, security, and best practices.
11
+
12
+ Think of it as the **"XSD for REST APIs"** - a single source of truth for API contracts, data structures, and validation rules.
13
+
14
+ ## Why does this package exist?
15
+
16
+ ### The Problem
17
+
18
+ Without centralized standards, REST APIs often suffer from:
19
+
20
+ - **Inconsistent response formats** across different endpoints
21
+ - **Duplicated validation logic** in multiple services
22
+ - **Type mismatches** between client and server
23
+ - **Security vulnerabilities** from inadequate input validation
24
+ - **Poor API documentation** due to lack of standard structures
25
+ - **Maintenance burden** when response formats need to change
26
+
27
+ ### The Solution
28
+
29
+ This package provides:
30
+
31
+ 1. **Standardized Response Schemas**: Consistent wrappers for all API responses (success, error, collections, health checks)
32
+ 2. **Reusable Primitive Schemas**: Common data types (UUID, slug, location, timestamps) that work across all services
33
+ 3. **Type-Safe Validation**: Runtime validation with Zod that automatically generates TypeScript types
34
+ 4. **Security Utilities**: Input sanitization, suspicious pattern detection, and validation helpers
35
+ 5. **Time Handling**: Robust ISO 8601 support, relative time parsing, and timezone handling
36
+ 6. **Response Utilities**: Correlation IDs, standardized headers, and environment detection
37
+
38
+ ## What problems does it solve?
39
+
40
+ ### 1. Response Consistency
41
+
42
+ **Before**: Every service defines its own response format
43
+ ```typescript
44
+ // Service A
45
+ { data: {...}, success: true }
46
+
47
+ // Service B
48
+ { result: {...}, status: "ok" }
49
+
50
+ // Service C
51
+ { body: {...}, code: 200 }
52
+ ```
53
+
54
+ **After**: All services use standard response schemas
55
+ ```typescript
56
+ // All services
57
+ {
58
+ status: 200,
59
+ timestamp: "2024-01-15T10:30:00.000Z",
60
+ data: {...}
61
+ }
62
+ ```
63
+
64
+ ### 2. Type Safety
65
+
66
+ **Before**: Manual type definitions that can drift from runtime validation
67
+ ```typescript
68
+ // Types might not match actual validation
69
+ type User = { id: string; name: string };
70
+ // Validation is separate and can diverge
71
+ const validateUser = (data: any) => { ... };
72
+ ```
73
+
74
+ **After**: Single source of truth with Zod
75
+ ```typescript
76
+ // Schema and type are always in sync
77
+ export const UserSchema = z.object({
78
+ id: z.string().uuid(),
79
+ name: z.string().min(1),
80
+ });
81
+ export type User = z.infer<typeof UserSchema>;
82
+ ```
83
+
84
+ ### 3. Code Reusability
85
+
86
+ **Before**: Every service implements its own validation
87
+ ```typescript
88
+ // Service A
89
+ function validateUUID(id: string) { ... }
90
+
91
+ // Service B (duplicate implementation)
92
+ function validateUUID(id: string) { ... }
93
+ ```
94
+
95
+ **After**: Import and reuse from commons
96
+ ```typescript
97
+ import { UuidSchema } from "@schafevormfenster/rest-commons";
98
+
99
+ const validated = UuidSchema.parse(id);
100
+ ```
101
+
102
+ ### 4. Security & Validation
103
+
104
+ **Before**: Inconsistent or missing security checks
105
+ ```typescript
106
+ // Some services check for suspicious patterns, others don't
107
+ ```
108
+
109
+ **After**: Built-in security utilities
110
+ ```typescript
111
+ import { detectSuspiciousPatterns } from "@schafevormfenster/rest-commons";
112
+
113
+ if (detectSuspiciousPatterns(userInput)) {
114
+ throw new ValidationError("Invalid input detected");
115
+ }
116
+ ```
117
+
118
+ ### 5. API Documentation
119
+
120
+ **Before**: Manual documentation that quickly becomes outdated
121
+ ```markdown
122
+ ## Response Format
123
+ Returns a JSON object with...
124
+ ```
125
+
126
+ **After**: Self-documenting schemas
127
+ ```typescript
128
+ // Schema serves as executable documentation
129
+ export const MyResponseSchema = ResultSchema.extend({
130
+ data: MyDataSchema,
131
+ });
132
+ // Automatically generates OpenAPI spec, TypeScript types, and validation
133
+ ```
134
+
135
+ ## When should you use this package?
136
+
137
+ Use **@schafevormfenster/rest-commons** when you:
138
+
139
+ - ✅ Build REST APIs in the @schafevormfenster ecosystem
140
+ - ✅ Need standardized response formats
141
+ - ✅ Want type-safe validation with Zod
142
+ - ✅ Require input sanitization and security checks
143
+ - ✅ Need to handle ISO 8601 timestamps or relative time
144
+ - ✅ Want consistent error handling across services
145
+ - ✅ Need correlation IDs for request tracing
146
+
147
+ Don't use this package if you:
148
+
149
+ - ❌ Build GraphQL APIs (use appropriate GraphQL schema tools)
150
+ - ❌ Work outside the @schafevormfenster ecosystem (fork and adapt instead)
151
+ - ❌ Need real-time WebSocket protocols (this is for REST only)
152
+
153
+ ## What's included?
154
+
155
+ ### Core Response Schemas
156
+
157
+ - **ResultSchema**: Single resource responses
158
+ - **ResultsSchema**: Collection responses
159
+ - **ErrorSchema**: Standardized error responses
160
+ - **HealthSchema**: Service health checks
161
+ - **OkaySchema**: Simple success acknowledgments
162
+
163
+ ### Primitive Schemas
164
+
165
+ - **UuidSchema**: UUID validation
166
+ - **SlugSchema**: URL-safe slugs
167
+ - **LocationSchema**: Geographic locations
168
+ - **ISO8601Schema**: Timestamp validation
169
+ - **RelativeTimeSchema**: Relative time expressions
170
+ - And more...
171
+
172
+ ### Utilities
173
+
174
+ - **Time Handling**: ISO 8601 parsing, relative time, week boundaries
175
+ - **Validation**: Suspicious pattern detection, parameter validation
176
+ - **Normalization**: List normalization, location normalization
177
+ - **Response Helpers**: Correlation IDs, header builders, environment detection
178
+
179
+ ## Installation
180
+
181
+ ```bash
182
+ pnpm add @schafevormfenster/rest-commons
183
+ ```
184
+
185
+ ## Quick Start
186
+
187
+ ```typescript
188
+ import {
189
+ ResultSchema,
190
+ ErrorSchema,
191
+ UuidSchema,
192
+ detectSuspiciousPatterns,
193
+ getCorrelationId,
194
+ } from "@schafevormfenster/rest-commons";
195
+
196
+ // Define your data schema
197
+ const UserSchema = z.object({
198
+ id: UuidSchema,
199
+ name: z.string(),
200
+ email: z.string().email(),
201
+ });
202
+
203
+ // Create response schema
204
+ const UserResponseSchema = ResultSchema.extend({
205
+ data: UserSchema,
206
+ });
207
+
208
+ // Use in your API route
209
+ export async function GET(request: Request) {
210
+ const correlationId = getCorrelationId(request);
211
+
212
+ // Your business logic here
213
+ const user = await fetchUser();
214
+
215
+ // Validate and return
216
+ const response = UserResponseSchema.parse({
217
+ status: 200,
218
+ timestamp: new Date().toISOString(),
219
+ data: user,
220
+ });
221
+
222
+ return Response.json(response);
223
+ }
224
+ ```
225
+
226
+ ## Documentation
227
+
228
+ For detailed implementation guides and best practices, see:
229
+
230
+ - **[CONTRIBUTING.md](./CONTRIBUTING.md)** - How to use this package and develop REST endpoints
231
+ - **[REST Service Design Guide](../eslint-plugin/docs/rest-service-design-guide.md)** - Architectural patterns
232
+ - **[E2E Testing Guide](../eslint-plugin/docs/instructions/rest-api-e2e-testing-guide.md)** - Testing patterns
233
+ - **[Tech Stack](../eslint-plugin/docs/instructions/tech-stack.md)** - Technology choices
234
+
235
+ ## Key Principles
236
+
237
+ This package embodies these principles:
238
+
239
+ 1. **Contract-First Development**: Define schemas before implementation
240
+ 2. **Type Safety**: Runtime validation generates compile-time types
241
+ 3. **Consistency**: Standardized formats across all services
242
+ 4. **Security**: Built-in input validation and sanitization
243
+ 5. **Observability**: Correlation IDs and structured responses
244
+ 6. **Developer Experience**: Self-documenting, autocomplete-friendly APIs
245
+
246
+ ## Tech Stack
247
+
248
+ This package is built with:
249
+
250
+ - **Zod**: Schema validation and type inference
251
+ - **TypeScript**: Type-safe development
252
+ - **Vitest**: Unit testing
253
+ - **ESLint**: Code quality enforcement
254
+
255
+ ## Contributing
256
+
257
+ This package is part of the @schafevormfenster monorepo. For contribution guidelines, see:
258
+
259
+ - [CONTRIBUTING.md](./CONTRIBUTING.md) - Development guide for this package
260
+ - Root monorepo CONTRIBUTING.md - General contribution guidelines
261
+
262
+ ## Related Packages
263
+
264
+ - **@schafevormfenster/eslint-plugin**: Custom ESLint rules for REST APIs
265
+ - **@schafevormfenster/eslint-config**: ESLint configurations for the monorepo
266
+ - **@schafevormfenster/logging**: Structured logging utilities
267
+ - **@schafevormfenster/security**: Security helpers and utilities
268
+
269
+ ## License
270
+
271
+ See the root LICENSE file for license information.
272
+
273
+ ---
274
+
275
+ **Built with ❤️ by the Schafe vorm Fenster team**
package/bin/setup.js ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * NPX script to sync coding instructions and update local Agent.md files
5
+ * Usage: npx @schafevormfenster/rest-commons setup
6
+ */
7
+
8
+ console.log('Setting up REST commons coding instructions...');
9
+ console.log('This script will be implemented to sync coding instructions to Agent.md files.');
10
+ console.log('Setup complete!');
@@ -0,0 +1,20 @@
1
+ import { z } from "zod";
2
+ export declare const ApiErrorSchema: z.ZodObject<{
3
+ status: z.ZodNumber;
4
+ error: z.ZodString;
5
+ trace: z.ZodOptional<z.ZodAny>;
6
+ }, "strict", z.ZodTypeAny, {
7
+ status: number;
8
+ error: string;
9
+ trace?: any;
10
+ }, {
11
+ status: number;
12
+ error: string;
13
+ trace?: any;
14
+ }>;
15
+ export type ApiError = z.infer<typeof ApiErrorSchema>;
16
+ export declare class ApiErrorConstructor extends Error {
17
+ readonly status: number;
18
+ constructor(status: number, message: string);
19
+ }
20
+ //# sourceMappingURL=error.schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.schema.d.ts","sourceRoot":"","sources":["../../src/api-schemas/error.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc;;;;;;;;;;;;EAMhB,CAAC;AAGZ,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAGtD,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK5C"}
@@ -0,0 +1,17 @@
1
+ import { z } from "zod";
2
+ export const ApiErrorSchema = z
3
+ .object({
4
+ status: z.number().min(400).max(599),
5
+ error: z.string(),
6
+ trace: z.any().optional(),
7
+ })
8
+ .strict();
9
+ // Class for error handling with instanceof checks and throwing
10
+ export class ApiErrorConstructor extends Error {
11
+ status;
12
+ constructor(status, message) {
13
+ super(message);
14
+ this.status = status;
15
+ this.name = "ApiError";
16
+ }
17
+ }