@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.
- package/LICENSE +21 -0
- package/README.md +206 -0
- package/bin/synapse.ts +919 -0
- package/package.json +70 -0
- package/src/client/components.tsx +508 -0
- package/src/client/context.tsx +62 -0
- package/src/client/hooks.ts +152 -0
- package/src/client/i18n.ts +40 -0
- package/src/client.ts +66 -0
- package/src/compiler/agent-diagnostic-json.ts +113 -0
- package/src/compiler/ast-daemon-compressor.ts +190 -0
- package/src/compiler/client-bundler.ts +356 -0
- package/src/compiler/context-bench.ts +191 -0
- package/src/compiler/contract.ts +260 -0
- package/src/compiler/db-schema-generator.ts +306 -0
- package/src/compiler/fields-parser.ts +267 -0
- package/src/compiler/impact-analyzer.ts +279 -0
- package/src/compiler/migration-runner.ts +555 -0
- package/src/compiler/oracle-runner.ts +293 -0
- package/src/compiler/scaffolder.ts +528 -0
- package/src/compiler/schema-dag.ts +137 -0
- package/src/compiler/schema-drift.ts +184 -0
- package/src/compiler/slice-discovery.ts +154 -0
- package/src/compiler/slice-splitter.ts +838 -0
- package/src/compiler/slice-templates.ts +1527 -0
- package/src/compiler/standalone-builder.ts +117 -0
- package/src/core/action-context.ts +152 -0
- package/src/core/config.ts +77 -0
- package/src/core/database-client.ts +246 -0
- package/src/core/database-factory.ts +46 -0
- package/src/core/image-optimizer.ts +83 -0
- package/src/core/index.ts +14 -0
- package/src/core/jobs.ts +53 -0
- package/src/core/machine-types.ts +75 -0
- package/src/core/oracle.ts +20 -0
- package/src/core/postgres-client.ts +164 -0
- package/src/core/postgres-queue.ts +288 -0
- package/src/core/query-builder.ts +343 -0
- package/src/core/rpc-client.ts +70 -0
- package/src/core/session-context.ts +87 -0
- package/src/core/session-cookie.ts +81 -0
- package/src/core/session-token.ts +170 -0
- package/src/core/sqlite-client.ts +201 -0
- package/src/core/storage.ts +317 -0
- package/src/index.ts +133 -0
- package/src/mcp/server.ts +553 -0
- package/src/runtime/client-entry.ts +65 -0
- package/src/runtime/discovery-rules.ts +63 -0
- package/src/runtime/event-hub.ts +97 -0
- package/src/runtime/postgres-event-hub.ts +148 -0
- package/src/runtime/queue-engine.ts +255 -0
- package/src/runtime/rate-limiter.ts +152 -0
- package/src/runtime/server.ts +1550 -0
- package/src/runtime/uploads.ts +192 -0
- package/templates/starter/.dockerignore +7 -0
- package/templates/starter/Dockerfile +40 -0
- package/templates/starter/README.md +40 -0
- package/templates/starter/gitignore +6 -0
- package/templates/starter/package.json +34 -0
- package/templates/starter/src/slices/welcome/hello-world.slice.tsx +172 -0
- 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
|
+
}
|