@ismaelsoilet/synapsejs 1.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 (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +206 -0
  3. package/bin/synapse.ts +919 -0
  4. package/package.json +70 -0
  5. package/src/client/components.tsx +508 -0
  6. package/src/client/context.tsx +62 -0
  7. package/src/client/hooks.ts +152 -0
  8. package/src/client/i18n.ts +40 -0
  9. package/src/client.ts +66 -0
  10. package/src/compiler/agent-diagnostic-json.ts +113 -0
  11. package/src/compiler/ast-daemon-compressor.ts +190 -0
  12. package/src/compiler/client-bundler.ts +356 -0
  13. package/src/compiler/context-bench.ts +191 -0
  14. package/src/compiler/contract.ts +260 -0
  15. package/src/compiler/db-schema-generator.ts +306 -0
  16. package/src/compiler/fields-parser.ts +267 -0
  17. package/src/compiler/impact-analyzer.ts +279 -0
  18. package/src/compiler/migration-runner.ts +555 -0
  19. package/src/compiler/oracle-runner.ts +293 -0
  20. package/src/compiler/scaffolder.ts +528 -0
  21. package/src/compiler/schema-dag.ts +137 -0
  22. package/src/compiler/schema-drift.ts +184 -0
  23. package/src/compiler/slice-discovery.ts +154 -0
  24. package/src/compiler/slice-splitter.ts +838 -0
  25. package/src/compiler/slice-templates.ts +1527 -0
  26. package/src/compiler/standalone-builder.ts +117 -0
  27. package/src/core/action-context.ts +152 -0
  28. package/src/core/config.ts +77 -0
  29. package/src/core/database-client.ts +246 -0
  30. package/src/core/database-factory.ts +46 -0
  31. package/src/core/image-optimizer.ts +83 -0
  32. package/src/core/index.ts +14 -0
  33. package/src/core/jobs.ts +53 -0
  34. package/src/core/machine-types.ts +75 -0
  35. package/src/core/oracle.ts +20 -0
  36. package/src/core/postgres-client.ts +164 -0
  37. package/src/core/postgres-queue.ts +288 -0
  38. package/src/core/query-builder.ts +343 -0
  39. package/src/core/rpc-client.ts +70 -0
  40. package/src/core/session-context.ts +87 -0
  41. package/src/core/session-cookie.ts +81 -0
  42. package/src/core/session-token.ts +170 -0
  43. package/src/core/sqlite-client.ts +201 -0
  44. package/src/core/storage.ts +317 -0
  45. package/src/index.ts +133 -0
  46. package/src/mcp/server.ts +553 -0
  47. package/src/runtime/client-entry.ts +65 -0
  48. package/src/runtime/discovery-rules.ts +63 -0
  49. package/src/runtime/event-hub.ts +97 -0
  50. package/src/runtime/postgres-event-hub.ts +148 -0
  51. package/src/runtime/queue-engine.ts +255 -0
  52. package/src/runtime/rate-limiter.ts +152 -0
  53. package/src/runtime/server.ts +1550 -0
  54. package/src/runtime/uploads.ts +192 -0
  55. package/templates/starter/.dockerignore +7 -0
  56. package/templates/starter/Dockerfile +40 -0
  57. package/templates/starter/README.md +40 -0
  58. package/templates/starter/gitignore +6 -0
  59. package/templates/starter/package.json +34 -0
  60. package/templates/starter/src/slices/welcome/hello-world.slice.tsx +172 -0
  61. package/templates/starter/tsconfig.json +21 -0
@@ -0,0 +1,152 @@
1
+ /**
2
+ * SynapseJS - Native Token Bucket Rate Limiter
3
+ *
4
+ * Provides in-memory sliding token bucket rate limiting to protect RPC,
5
+ * Webhooks, and API endpoints against DoS, brute-force, and noisy neighbors.
6
+ *
7
+ * Implements RFC 6585 standard headers:
8
+ * - Retry-After
9
+ * - X-RateLimit-Limit
10
+ * - X-RateLimit-Remaining
11
+ * - X-RateLimit-Reset
12
+ */
13
+
14
+ export interface RateLimitOptions {
15
+ /** Maximum burst capacity (default: 150) */
16
+ capacity?: number;
17
+ /** Refill rate in tokens per second (default: 100) */
18
+ refillRate?: number;
19
+ /** Inactivity window in ms before bucket is evicted (default: 60,000ms = 1m) */
20
+ idleTimeoutMs?: number;
21
+ }
22
+
23
+ export interface RateLimitResult {
24
+ allowed: boolean;
25
+ limit: number;
26
+ remaining: number;
27
+ resetMs: number;
28
+ }
29
+
30
+ interface Bucket {
31
+ tokens: number;
32
+ lastRefill: number;
33
+ lastAccess: number;
34
+ }
35
+
36
+ export class TokenBucketRateLimiter {
37
+ private capacity: number;
38
+ private refillRate: number;
39
+ private idleTimeoutMs: number;
40
+ private buckets: Map<string, Bucket> = new Map();
41
+ private cleanupTimer: ReturnType<typeof setInterval> | null = null;
42
+
43
+ constructor(options: RateLimitOptions = {}) {
44
+ const envRps = Number(process.env.SYNAPSE_RATE_LIMIT_RPS);
45
+ const envBurst = Number(process.env.SYNAPSE_RATE_LIMIT_BURST);
46
+
47
+ this.refillRate = options.refillRate ?? (Number.isFinite(envRps) && envRps > 0 ? envRps : 100);
48
+ this.capacity = options.capacity ?? (Number.isFinite(envBurst) && envBurst > 0 ? envBurst : 150);
49
+ this.idleTimeoutMs = options.idleTimeoutMs ?? 60_000;
50
+
51
+ // Run background prune of idle buckets every minute
52
+ this.cleanupTimer = setInterval(() => this.pruneIdleBuckets(), this.idleTimeoutMs);
53
+ if (this.cleanupTimer.unref) {
54
+ this.cleanupTimer.unref();
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Consumes `cost` tokens from the bucket for `key`.
60
+ */
61
+ consume(key: string, cost = 1): RateLimitResult {
62
+ const now = Date.now();
63
+ let bucket = this.buckets.get(key);
64
+
65
+ if (!bucket) {
66
+ bucket = {
67
+ tokens: this.capacity,
68
+ lastRefill: now,
69
+ lastAccess: now
70
+ };
71
+ this.buckets.set(key, bucket);
72
+ }
73
+
74
+ // Refill tokens based on elapsed time
75
+ const elapsedSeconds = (now - bucket.lastRefill) / 1000;
76
+ if (elapsedSeconds > 0) {
77
+ bucket.tokens = Math.min(this.capacity, bucket.tokens + elapsedSeconds * this.refillRate);
78
+ bucket.lastRefill = now;
79
+ }
80
+ bucket.lastAccess = now;
81
+
82
+ if (bucket.tokens >= cost) {
83
+ bucket.tokens -= cost;
84
+ const remaining = Math.floor(bucket.tokens);
85
+ const resetMs = Math.ceil(((this.capacity - bucket.tokens) / this.refillRate) * 1000);
86
+
87
+ return {
88
+ allowed: true,
89
+ limit: this.capacity,
90
+ remaining,
91
+ resetMs: Math.max(0, resetMs)
92
+ };
93
+ }
94
+
95
+ // Insufficient tokens: calculate wait time
96
+ const deficit = cost - bucket.tokens;
97
+ const resetMs = Math.ceil((deficit / this.refillRate) * 1000);
98
+
99
+ return {
100
+ allowed: false,
101
+ limit: this.capacity,
102
+ remaining: 0,
103
+ resetMs: Math.max(100, resetMs)
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Resets rate limit for a specific key, or all keys.
109
+ */
110
+ reset(key?: string): void {
111
+ if (key) {
112
+ this.buckets.delete(key);
113
+ } else {
114
+ this.buckets.clear();
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Evicts buckets that haven't been accessed for `idleTimeoutMs`.
120
+ */
121
+ pruneIdleBuckets(): number {
122
+ const now = Date.now();
123
+ let evicted = 0;
124
+
125
+ for (const [key, bucket] of this.buckets.entries()) {
126
+ if (now - bucket.lastAccess > this.idleTimeoutMs && bucket.tokens >= this.capacity - 0.001) {
127
+ this.buckets.delete(key);
128
+ evicted++;
129
+ }
130
+ }
131
+
132
+ return evicted;
133
+ }
134
+
135
+ /**
136
+ * Returns current active bucket count.
137
+ */
138
+ get activeKeysCount(): number {
139
+ return this.buckets.size;
140
+ }
141
+
142
+ /**
143
+ * Stops background cleanup timer.
144
+ */
145
+ close(): void {
146
+ if (this.cleanupTimer) {
147
+ clearInterval(this.cleanupTimer);
148
+ this.cleanupTimer = null;
149
+ }
150
+ this.buckets.clear();
151
+ }
152
+ }