@stravigor/core 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 (165) hide show
  1. package/README.md +45 -0
  2. package/package.json +83 -0
  3. package/src/auth/access_token.ts +122 -0
  4. package/src/auth/auth.ts +86 -0
  5. package/src/auth/index.ts +7 -0
  6. package/src/auth/middleware/authenticate.ts +64 -0
  7. package/src/auth/middleware/csrf.ts +62 -0
  8. package/src/auth/middleware/guest.ts +46 -0
  9. package/src/broadcast/broadcast_manager.ts +411 -0
  10. package/src/broadcast/client.ts +302 -0
  11. package/src/broadcast/index.ts +58 -0
  12. package/src/cache/cache_manager.ts +56 -0
  13. package/src/cache/cache_store.ts +31 -0
  14. package/src/cache/helpers.ts +74 -0
  15. package/src/cache/http_cache.ts +109 -0
  16. package/src/cache/index.ts +6 -0
  17. package/src/cache/memory_store.ts +63 -0
  18. package/src/cli/bootstrap.ts +37 -0
  19. package/src/cli/commands/generate_api.ts +74 -0
  20. package/src/cli/commands/generate_key.ts +46 -0
  21. package/src/cli/commands/generate_models.ts +48 -0
  22. package/src/cli/commands/migration_compare.ts +152 -0
  23. package/src/cli/commands/migration_fresh.ts +123 -0
  24. package/src/cli/commands/migration_generate.ts +79 -0
  25. package/src/cli/commands/migration_rollback.ts +53 -0
  26. package/src/cli/commands/migration_run.ts +44 -0
  27. package/src/cli/commands/queue_flush.ts +35 -0
  28. package/src/cli/commands/queue_retry.ts +34 -0
  29. package/src/cli/commands/queue_work.ts +40 -0
  30. package/src/cli/commands/scheduler_work.ts +45 -0
  31. package/src/cli/strav.ts +33 -0
  32. package/src/config/configuration.ts +105 -0
  33. package/src/config/loaders/base_loader.ts +69 -0
  34. package/src/config/loaders/env_loader.ts +112 -0
  35. package/src/config/loaders/typescript_loader.ts +56 -0
  36. package/src/config/types.ts +8 -0
  37. package/src/core/application.ts +4 -0
  38. package/src/core/container.ts +117 -0
  39. package/src/core/index.ts +3 -0
  40. package/src/core/inject.ts +39 -0
  41. package/src/database/database.ts +54 -0
  42. package/src/database/index.ts +30 -0
  43. package/src/database/introspector.ts +446 -0
  44. package/src/database/migration/differ.ts +308 -0
  45. package/src/database/migration/file_generator.ts +125 -0
  46. package/src/database/migration/index.ts +18 -0
  47. package/src/database/migration/runner.ts +133 -0
  48. package/src/database/migration/sql_generator.ts +378 -0
  49. package/src/database/migration/tracker.ts +76 -0
  50. package/src/database/migration/types.ts +189 -0
  51. package/src/database/query_builder.ts +474 -0
  52. package/src/encryption/encryption_manager.ts +209 -0
  53. package/src/encryption/helpers.ts +158 -0
  54. package/src/encryption/index.ts +3 -0
  55. package/src/encryption/types.ts +6 -0
  56. package/src/events/emitter.ts +101 -0
  57. package/src/events/index.ts +2 -0
  58. package/src/exceptions/errors.ts +75 -0
  59. package/src/exceptions/exception_handler.ts +126 -0
  60. package/src/exceptions/helpers.ts +25 -0
  61. package/src/exceptions/http_exception.ts +129 -0
  62. package/src/exceptions/index.ts +23 -0
  63. package/src/exceptions/strav_error.ts +11 -0
  64. package/src/generators/api_generator.ts +972 -0
  65. package/src/generators/config.ts +87 -0
  66. package/src/generators/doc_generator.ts +974 -0
  67. package/src/generators/index.ts +11 -0
  68. package/src/generators/model_generator.ts +586 -0
  69. package/src/generators/route_generator.ts +188 -0
  70. package/src/generators/test_generator.ts +1666 -0
  71. package/src/helpers/crypto.ts +4 -0
  72. package/src/helpers/env.ts +50 -0
  73. package/src/helpers/identity.ts +12 -0
  74. package/src/helpers/index.ts +4 -0
  75. package/src/helpers/strings.ts +67 -0
  76. package/src/http/context.ts +215 -0
  77. package/src/http/cookie.ts +59 -0
  78. package/src/http/cors.ts +163 -0
  79. package/src/http/index.ts +16 -0
  80. package/src/http/middleware.ts +39 -0
  81. package/src/http/rate_limit.ts +173 -0
  82. package/src/http/router.ts +556 -0
  83. package/src/http/server.ts +79 -0
  84. package/src/i18n/defaults/en/validation.json +20 -0
  85. package/src/i18n/helpers.ts +72 -0
  86. package/src/i18n/i18n_manager.ts +155 -0
  87. package/src/i18n/index.ts +4 -0
  88. package/src/i18n/middleware.ts +90 -0
  89. package/src/i18n/translator.ts +96 -0
  90. package/src/i18n/types.ts +17 -0
  91. package/src/logger/index.ts +6 -0
  92. package/src/logger/logger.ts +100 -0
  93. package/src/logger/request_logger.ts +19 -0
  94. package/src/logger/sinks/console_sink.ts +24 -0
  95. package/src/logger/sinks/file_sink.ts +24 -0
  96. package/src/logger/sinks/sink.ts +36 -0
  97. package/src/mail/css_inliner.ts +79 -0
  98. package/src/mail/helpers.ts +212 -0
  99. package/src/mail/index.ts +19 -0
  100. package/src/mail/mail_manager.ts +92 -0
  101. package/src/mail/transports/log_transport.ts +69 -0
  102. package/src/mail/transports/resend_transport.ts +59 -0
  103. package/src/mail/transports/sendgrid_transport.ts +77 -0
  104. package/src/mail/transports/smtp_transport.ts +48 -0
  105. package/src/mail/types.ts +80 -0
  106. package/src/notification/base_notification.ts +67 -0
  107. package/src/notification/channels/database_channel.ts +30 -0
  108. package/src/notification/channels/discord_channel.ts +43 -0
  109. package/src/notification/channels/email_channel.ts +37 -0
  110. package/src/notification/channels/webhook_channel.ts +45 -0
  111. package/src/notification/helpers.ts +214 -0
  112. package/src/notification/index.ts +20 -0
  113. package/src/notification/notification_manager.ts +126 -0
  114. package/src/notification/types.ts +122 -0
  115. package/src/orm/base_model.ts +351 -0
  116. package/src/orm/decorators.ts +127 -0
  117. package/src/orm/index.ts +4 -0
  118. package/src/policy/authorize.ts +44 -0
  119. package/src/policy/index.ts +3 -0
  120. package/src/policy/policy_result.ts +13 -0
  121. package/src/queue/index.ts +11 -0
  122. package/src/queue/queue.ts +338 -0
  123. package/src/queue/worker.ts +197 -0
  124. package/src/scheduler/cron.ts +140 -0
  125. package/src/scheduler/index.ts +7 -0
  126. package/src/scheduler/runner.ts +116 -0
  127. package/src/scheduler/schedule.ts +183 -0
  128. package/src/scheduler/scheduler.ts +47 -0
  129. package/src/schema/database_representation.ts +122 -0
  130. package/src/schema/define_association.ts +60 -0
  131. package/src/schema/define_schema.ts +46 -0
  132. package/src/schema/field_builder.ts +155 -0
  133. package/src/schema/field_definition.ts +66 -0
  134. package/src/schema/index.ts +21 -0
  135. package/src/schema/naming.ts +19 -0
  136. package/src/schema/postgres.ts +109 -0
  137. package/src/schema/registry.ts +157 -0
  138. package/src/schema/representation_builder.ts +479 -0
  139. package/src/schema/type_builder.ts +107 -0
  140. package/src/schema/types.ts +35 -0
  141. package/src/session/index.ts +4 -0
  142. package/src/session/middleware.ts +46 -0
  143. package/src/session/session.ts +308 -0
  144. package/src/session/session_manager.ts +81 -0
  145. package/src/storage/index.ts +13 -0
  146. package/src/storage/local_driver.ts +46 -0
  147. package/src/storage/s3_driver.ts +51 -0
  148. package/src/storage/storage.ts +43 -0
  149. package/src/storage/storage_manager.ts +59 -0
  150. package/src/storage/types.ts +42 -0
  151. package/src/storage/upload.ts +91 -0
  152. package/src/validation/index.ts +18 -0
  153. package/src/validation/rules.ts +170 -0
  154. package/src/validation/validate.ts +41 -0
  155. package/src/view/cache.ts +47 -0
  156. package/src/view/client/islands.ts +50 -0
  157. package/src/view/compiler.ts +185 -0
  158. package/src/view/engine.ts +139 -0
  159. package/src/view/escape.ts +14 -0
  160. package/src/view/index.ts +13 -0
  161. package/src/view/islands/island_builder.ts +161 -0
  162. package/src/view/islands/vue_plugin.ts +140 -0
  163. package/src/view/middleware/static.ts +35 -0
  164. package/src/view/tokenizer.ts +172 -0
  165. package/tsconfig.json +4 -0
@@ -0,0 +1,173 @@
1
+ import type { Middleware } from './middleware.ts'
2
+ import type Context from './context.ts'
3
+
4
+ // ---------------------------------------------------------------------------
5
+ // Store interface
6
+ // ---------------------------------------------------------------------------
7
+
8
+ export interface RateLimitInfo {
9
+ /** Total allowed requests in the window. */
10
+ limit: number
11
+ /** Remaining requests in the current window. */
12
+ remaining: number
13
+ /** Unix timestamp (ms) when the window resets. */
14
+ resetTime: number
15
+ /** Whether the current request exceeds the limit. */
16
+ exceeded: boolean
17
+ }
18
+
19
+ /**
20
+ * Pluggable storage backend for rate limit counters.
21
+ * Implement this interface to use Redis, database, or distributed stores.
22
+ */
23
+ export interface RateLimitStore {
24
+ increment(key: string, window: number, max: number): RateLimitInfo | Promise<RateLimitInfo>
25
+ reset(key: string): void | Promise<void>
26
+ }
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // In-memory store (fixed window)
30
+ // ---------------------------------------------------------------------------
31
+
32
+ interface WindowEntry {
33
+ count: number
34
+ resetTime: number
35
+ }
36
+
37
+ /**
38
+ * In-memory rate limit store using fixed time windows.
39
+ * Entries are lazily cleaned up on access. Suitable for single-process deployments.
40
+ */
41
+ export class MemoryStore implements RateLimitStore {
42
+ private windows = new Map<string, WindowEntry>()
43
+
44
+ increment(key: string, window: number, max: number): RateLimitInfo {
45
+ const now = Date.now()
46
+ const entry = this.windows.get(key)
47
+
48
+ if (entry && now < entry.resetTime) {
49
+ entry.count++
50
+ return {
51
+ limit: max,
52
+ remaining: Math.max(0, max - entry.count),
53
+ resetTime: entry.resetTime,
54
+ exceeded: entry.count > max,
55
+ }
56
+ }
57
+
58
+ const resetTime = now + window
59
+ this.windows.set(key, { count: 1, resetTime })
60
+
61
+ if (this.windows.size > 10_000) this.cleanup(now)
62
+
63
+ return { limit: max, remaining: max - 1, resetTime, exceeded: false }
64
+ }
65
+
66
+ reset(key: string): void {
67
+ this.windows.delete(key)
68
+ }
69
+
70
+ private cleanup(now: number): void {
71
+ for (const [key, entry] of this.windows) {
72
+ if (now >= entry.resetTime) this.windows.delete(key)
73
+ }
74
+ }
75
+ }
76
+
77
+ // ---------------------------------------------------------------------------
78
+ // Options
79
+ // ---------------------------------------------------------------------------
80
+
81
+ export interface RateLimitOptions {
82
+ /** Time window in milliseconds. @default 60_000 */
83
+ window?: number
84
+
85
+ /** Maximum requests allowed in the window. @default 60 */
86
+ max?: number
87
+
88
+ /**
89
+ * Extract the rate limit key from the request context.
90
+ * Defaults to client IP via X-Forwarded-For / X-Real-IP.
91
+ */
92
+ keyExtractor?: (ctx: Context) => string
93
+
94
+ /** Return `true` to bypass the rate limit check. */
95
+ skip?: (ctx: Context) => boolean
96
+
97
+ /** Custom storage backend. Defaults to an in-memory fixed-window store. */
98
+ store?: RateLimitStore
99
+
100
+ /** Custom response when rate limit is exceeded. */
101
+ onLimitReached?: (ctx: Context, info: RateLimitInfo) => Response
102
+
103
+ /** Whether to add X-RateLimit-* headers to successful responses. @default true */
104
+ headers?: boolean
105
+ }
106
+
107
+ // ---------------------------------------------------------------------------
108
+ // Default key extractor
109
+ // ---------------------------------------------------------------------------
110
+
111
+ function defaultKeyExtractor(ctx: Context): string {
112
+ const forwarded = ctx.header('x-forwarded-for')
113
+ if (forwarded) return forwarded.split(',')[0]!.trim()
114
+
115
+ const realIp = ctx.header('x-real-ip')
116
+ if (realIp) return realIp
117
+
118
+ return 'unknown'
119
+ }
120
+
121
+ // ---------------------------------------------------------------------------
122
+ // Middleware factory
123
+ // ---------------------------------------------------------------------------
124
+
125
+ export function rateLimit(options: RateLimitOptions = {}): Middleware {
126
+ const {
127
+ window = 60_000,
128
+ max = 60,
129
+ keyExtractor = defaultKeyExtractor,
130
+ skip,
131
+ store = new MemoryStore(),
132
+ onLimitReached,
133
+ headers: addHeaders = true,
134
+ } = options
135
+
136
+ return async (ctx, next) => {
137
+ if (skip?.(ctx)) return next()
138
+
139
+ const key = keyExtractor(ctx)
140
+ const info = await store.increment(key, window, max)
141
+
142
+ if (info.exceeded) {
143
+ if (onLimitReached) return onLimitReached(ctx, info)
144
+
145
+ const retryAfter = Math.ceil((info.resetTime - Date.now()) / 1000)
146
+ return new Response(JSON.stringify({ error: 'Too Many Requests' }), {
147
+ status: 429,
148
+ headers: {
149
+ 'Content-Type': 'application/json',
150
+ 'X-RateLimit-Limit': String(info.limit),
151
+ 'X-RateLimit-Remaining': '0',
152
+ 'X-RateLimit-Reset': String(Math.ceil(info.resetTime / 1000)),
153
+ 'Retry-After': String(Math.max(0, retryAfter)),
154
+ },
155
+ })
156
+ }
157
+
158
+ const response = await next()
159
+
160
+ if (!addHeaders) return response
161
+
162
+ const headers = new Headers(response.headers)
163
+ headers.set('X-RateLimit-Limit', String(info.limit))
164
+ headers.set('X-RateLimit-Remaining', String(info.remaining))
165
+ headers.set('X-RateLimit-Reset', String(Math.ceil(info.resetTime / 1000)))
166
+
167
+ return new Response(response.body, {
168
+ status: response.status,
169
+ statusText: response.statusText,
170
+ headers,
171
+ })
172
+ }
173
+ }