@gatewaystack/limitabl-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.
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # @gatewaystack/limitabl-core
2
+
3
+ Framework-agnostic rate limiting, budget tracking, and agent guard for AI gateways.
4
+
5
+ `@gatewaystack/limitabl-core` is the low-level engine behind [@gatewaystack/limitabl](https://www.npmjs.com/package/@gatewaystack/limitabl). Use it directly when you need usage controls without Express.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @gatewaystack/limitabl-core
11
+ ```
12
+
13
+ ## Features
14
+
15
+ - **Sliding-window rate limiter** — per-user/org/IP request throttling
16
+ - **Budget tracker** — per-user spend caps with preflight estimation
17
+ - **Agent guard** — tool call limits, workflow cost caps, and duration caps to prevent runaway agents
18
+ - **Unified preflight engine** — runs all checks in a single call
19
+ - **Key resolution** — automatic key priority: `sub` > `orgId` > `ip` > `anonymous`, with optional tenant prefix
20
+
21
+ ## Quick Start
22
+
23
+ ### Rate limiting
24
+
25
+ ```ts
26
+ import { InMemoryRateLimiter } from "@gatewaystack/limitabl-core";
27
+
28
+ const limiter = new InMemoryRateLimiter({ windowMs: 60_000, maxRequests: 10 });
29
+
30
+ const result = limiter.check({ sub: "user1" });
31
+ // { allowed: true, remaining: 9, resetAt: 1738886400000 }
32
+ ```
33
+
34
+ ### Budget tracking
35
+
36
+ ```ts
37
+ import { InMemoryBudgetTracker } from "@gatewaystack/limitabl-core";
38
+
39
+ const budget = new InMemoryBudgetTracker({ maxSpend: 100, periodMs: 86_400_000 });
40
+
41
+ // Pre-flight check with estimated cost
42
+ budget.check({ sub: "user1" }, 25);
43
+ // { allowed: true, currentSpend: 0, maxSpend: 100, percentUsed: 0 }
44
+
45
+ // Record actual usage after execution
46
+ budget.record({ sub: "user1" }, { timestamp: Date.now(), cost: 22, tokens: 1500 });
47
+ ```
48
+
49
+ ### Agent guard
50
+
51
+ ```ts
52
+ import { AgentGuard } from "@gatewaystack/limitabl-core";
53
+
54
+ const guard = new AgentGuard({ maxToolCalls: 20, maxWorkflowCost: 500, maxDurationMs: 120_000 });
55
+
56
+ // Before each tool call
57
+ const result = guard.check("workflow-abc");
58
+ // { allowed: true, toolCallCount: 0, workflowCost: 0, durationMs: 3 }
59
+
60
+ // After each tool call
61
+ guard.recordToolCall("workflow-abc", 12); // cost = 12
62
+
63
+ // When workflow finishes
64
+ guard.endWorkflow("workflow-abc");
65
+ ```
66
+
67
+ ### Unified preflight
68
+
69
+ ```ts
70
+ import { LimitablEngine } from "@gatewaystack/limitabl-core";
71
+
72
+ const engine = new LimitablEngine({
73
+ rateLimit: { windowMs: 60_000, maxRequests: 100 },
74
+ budget: { maxSpend: 1000, periodMs: 86_400_000 },
75
+ agentGuard: { maxToolCalls: 50 },
76
+ });
77
+
78
+ const result = engine.preflight(
79
+ { sub: "user1", tenantId: "tenant-a" },
80
+ { estimatedCost: 5, workflowId: "wf-123" }
81
+ );
82
+ // { allowed: true, reason: "All checks passed", rateLimit: {...}, budget: {...}, agentGuard: {...} }
83
+
84
+ // Record usage post-execution
85
+ engine.recordUsage({
86
+ key: { sub: "user1" },
87
+ workflowId: "wf-123",
88
+ usage: { timestamp: Date.now(), cost: 4.5, tokens: 800 },
89
+ });
90
+
91
+ // Cleanup on shutdown
92
+ engine.destroy();
93
+ ```
94
+
95
+ ## API
96
+
97
+ ### `InMemoryRateLimiter`
98
+
99
+ ```ts
100
+ new InMemoryRateLimiter(config: { windowMs: number, maxRequests: number })
101
+ ```
102
+
103
+ | Method | Description |
104
+ |--------|-------------|
105
+ | `check(key)` | Check and record a request. Returns `{ allowed, remaining, resetAt, retryAfterSec? }` |
106
+ | `destroy()` | Stop the internal cleanup interval |
107
+
108
+ ### `InMemoryBudgetTracker`
109
+
110
+ ```ts
111
+ new InMemoryBudgetTracker(config: { maxSpend: number, periodMs: number })
112
+ ```
113
+
114
+ | Method | Description |
115
+ |--------|-------------|
116
+ | `check(key, estimatedCost?)` | Pre-flight budget check. Returns `{ allowed, currentSpend, maxSpend, percentUsed }` |
117
+ | `record(key, usage)` | Record actual usage after execution |
118
+ | `getUsageSummary(key)` | Returns `{ totalSpend, totalTokens, requestCount }` |
119
+ | `destroy()` | Stop the internal cleanup interval |
120
+
121
+ ### `AgentGuard`
122
+
123
+ ```ts
124
+ new AgentGuard(config?: { maxToolCalls?, maxWorkflowCost?, maxDurationMs? })
125
+ ```
126
+
127
+ | Method | Description |
128
+ |--------|-------------|
129
+ | `check(workflowId)` | Check if a tool call is allowed. Returns `{ allowed, toolCallCount, workflowCost, durationMs }` |
130
+ | `recordToolCall(workflowId, cost?)` | Record a tool call with optional cost |
131
+ | `endWorkflow(workflowId)` | Clean up workflow state |
132
+
133
+ ### `LimitablEngine`
134
+
135
+ Orchestrates all three components. Configure any combination of rate limiting, budget tracking, and agent guard.
136
+
137
+ ### `resolveKey(key)`
138
+
139
+ Resolves a `LimitKey` to a string: `sub` > `orgId` > `ip` > `anonymous`, with optional `tenantId` prefix.
140
+
141
+ ```ts
142
+ resolveKey({ tenantId: "t1", sub: "u1" }) // "t:t1|u:u1"
143
+ resolveKey({ ip: "1.2.3.4" }) // "ip:1.2.3.4"
144
+ resolveKey({}) // "anonymous"
145
+ ```
146
+
147
+ ## Related Packages
148
+
149
+ - [@gatewaystack/limitabl](https://www.npmjs.com/package/@gatewaystack/limitabl) — Express middleware wrapper
150
+ - [@gatewaystack/identifiabl-core](https://www.npmjs.com/package/@gatewaystack/identifiabl-core) — JWT identity (provides `sub`, `orgId`)
151
+ - [@gatewaystack/validatabl-core](https://www.npmjs.com/package/@gatewaystack/validatabl-core) — Policy enforcement
152
+
153
+ ## License
154
+
155
+ MIT
@@ -0,0 +1,17 @@
1
+ import type { AgentGuardConfig, AgentGuardResult } from "./types.js";
2
+ export declare class AgentGuard {
3
+ private workflows;
4
+ private config;
5
+ constructor(config?: AgentGuardConfig);
6
+ /**
7
+ * Check if a tool call is allowed within the workflow constraints.
8
+ * Call this BEFORE executing each tool call.
9
+ */
10
+ check(workflowId: string): AgentGuardResult;
11
+ /** Record a tool call after execution (updates counters). */
12
+ recordToolCall(workflowId: string, cost?: number): void;
13
+ /** End a workflow (clean up state). */
14
+ endWorkflow(workflowId: string): void;
15
+ private getOrCreate;
16
+ }
17
+ //# sourceMappingURL=agentGuard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentGuard.d.ts","sourceRoot":"","sources":["../src/agentGuard.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAYrE,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,MAAM,CAA6B;gBAE/B,MAAM,GAAE,gBAAqB;IAQzC;;;OAGG;IACH,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB;IA+C3C,6DAA6D;IAC7D,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,MAAU,GAAG,IAAI;IAM1D,uCAAuC;IACvC,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIrC,OAAO,CAAC,WAAW;CAQpB"}
@@ -0,0 +1,88 @@
1
+ // packages/limitabl-core/src/agentGuard.ts
2
+ //
3
+ // Prevents agentic runaway: tool call limits, workflow cost caps, duration caps.
4
+ //
5
+ // FUTURE WORK:
6
+ // - Recursion depth detection (detect A→B→A→B loops)
7
+ // - Duplicate tool call detection with configurable thresholds
8
+ // - Per-tool call limits (e.g., max 5 calls to expensive-tool per workflow)
9
+ // - Circuit breaker pattern (stop all tool calls after N consecutive failures)
10
+ const DEFAULT_MAX_TOOL_CALLS = 50;
11
+ const DEFAULT_MAX_WORKFLOW_COST = 1000; // $10 in cents
12
+ const DEFAULT_MAX_DURATION_MS = 300_000; // 5 minutes
13
+ export class AgentGuard {
14
+ workflows = new Map();
15
+ config;
16
+ constructor(config = {}) {
17
+ this.config = {
18
+ maxToolCalls: config.maxToolCalls ?? DEFAULT_MAX_TOOL_CALLS,
19
+ maxWorkflowCost: config.maxWorkflowCost ?? DEFAULT_MAX_WORKFLOW_COST,
20
+ maxDurationMs: config.maxDurationMs ?? DEFAULT_MAX_DURATION_MS,
21
+ };
22
+ }
23
+ /**
24
+ * Check if a tool call is allowed within the workflow constraints.
25
+ * Call this BEFORE executing each tool call.
26
+ */
27
+ check(workflowId) {
28
+ const state = this.getOrCreate(workflowId);
29
+ const now = Date.now();
30
+ const durationMs = now - state.startedAt;
31
+ // Check duration
32
+ if (durationMs > this.config.maxDurationMs) {
33
+ return {
34
+ allowed: false,
35
+ reason: `Workflow exceeded max duration: ${durationMs}ms > ${this.config.maxDurationMs}ms`,
36
+ toolCallCount: state.toolCallCount,
37
+ workflowCost: state.totalCost,
38
+ durationMs,
39
+ };
40
+ }
41
+ // Check tool call count
42
+ if (state.toolCallCount >= this.config.maxToolCalls) {
43
+ return {
44
+ allowed: false,
45
+ reason: `Workflow exceeded max tool calls: ${state.toolCallCount} >= ${this.config.maxToolCalls}`,
46
+ toolCallCount: state.toolCallCount,
47
+ workflowCost: state.totalCost,
48
+ durationMs,
49
+ };
50
+ }
51
+ // Check cost
52
+ if (state.totalCost >= this.config.maxWorkflowCost) {
53
+ return {
54
+ allowed: false,
55
+ reason: `Workflow exceeded max cost: ${state.totalCost} >= ${this.config.maxWorkflowCost}`,
56
+ toolCallCount: state.toolCallCount,
57
+ workflowCost: state.totalCost,
58
+ durationMs,
59
+ };
60
+ }
61
+ return {
62
+ allowed: true,
63
+ reason: "Within workflow limits",
64
+ toolCallCount: state.toolCallCount,
65
+ workflowCost: state.totalCost,
66
+ durationMs,
67
+ };
68
+ }
69
+ /** Record a tool call after execution (updates counters). */
70
+ recordToolCall(workflowId, cost = 0) {
71
+ const state = this.getOrCreate(workflowId);
72
+ state.toolCallCount++;
73
+ state.totalCost += cost;
74
+ }
75
+ /** End a workflow (clean up state). */
76
+ endWorkflow(workflowId) {
77
+ this.workflows.delete(workflowId);
78
+ }
79
+ getOrCreate(workflowId) {
80
+ let state = this.workflows.get(workflowId);
81
+ if (!state) {
82
+ state = { startedAt: Date.now(), toolCallCount: 0, totalCost: 0 };
83
+ this.workflows.set(workflowId, state);
84
+ }
85
+ return state;
86
+ }
87
+ }
88
+ //# sourceMappingURL=agentGuard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentGuard.js","sourceRoot":"","sources":["../src/agentGuard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { LimitKey, BudgetConfig, BudgetCheckResult, UsageRecord } from "./types.js";
2
+ export declare class InMemoryBudgetTracker {
3
+ private budgets;
4
+ private config;
5
+ private cleanupInterval;
6
+ constructor(config: BudgetConfig);
7
+ /** Check if a request is within budget (pre-flight). */
8
+ check(key: LimitKey, estimatedCost?: number): BudgetCheckResult;
9
+ /** Record usage after execution (post-execution / Phase 2). */
10
+ record(key: LimitKey, usage: UsageRecord): void;
11
+ /** Get current spend in the budget period. */
12
+ getCurrentSpend(keyStr: string): number;
13
+ /** Get usage summary for a key. */
14
+ getUsageSummary(key: LimitKey): {
15
+ totalSpend: number;
16
+ totalTokens: number;
17
+ requestCount: number;
18
+ };
19
+ private cleanup;
20
+ destroy(): void;
21
+ }
22
+ //# sourceMappingURL=budgetTracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budgetTracker.d.ts","sourceRoot":"","sources":["../src/budgetTracker.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACZ,MAAM,YAAY,CAAC;AAOpB,qBAAa,qBAAqB;IAChC,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,eAAe,CAA+C;gBAE1D,MAAM,EAAE,YAAY;IAShC,wDAAwD;IACxD,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,iBAAiB;IAwB/D,+DAA+D;IAC/D,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI;IAU/C,8CAA8C;IAC9C,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAUvC,mCAAmC;IACnC,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG;QAC9B,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;KACtB;IAeD,OAAO,CAAC,OAAO;IAQf,OAAO;CAMR"}
@@ -0,0 +1,94 @@
1
+ // packages/limitabl-core/src/budgetTracker.ts
2
+ //
3
+ // Per-user and per-org budget tracking with spend caps.
4
+ // In-memory implementation.
5
+ //
6
+ // FUTURE WORK:
7
+ // - Persistent storage adapter (Firestore, Redis, DynamoDB)
8
+ // - Budget alerting (webhook when 80%, 90%, 100% thresholds hit)
9
+ // - Per-model budget tracking (e.g., limit GPT-4 spend separately)
10
+ // - Budget rollover (carry unused budget to next period)
11
+ // - Budget delegation (org admin allocates budget to users)
12
+ import { resolveKey } from "./rateLimiter.js";
13
+ export class InMemoryBudgetTracker {
14
+ budgets = new Map();
15
+ config;
16
+ cleanupInterval = null;
17
+ constructor(config) {
18
+ this.config = config;
19
+ this.cleanupInterval = setInterval(() => this.cleanup(), config.periodMs / 10);
20
+ if (this.cleanupInterval.unref)
21
+ this.cleanupInterval.unref();
22
+ }
23
+ /** Check if a request is within budget (pre-flight). */
24
+ check(key, estimatedCost) {
25
+ const k = resolveKey(key);
26
+ const currentSpend = this.getCurrentSpend(k);
27
+ const effectiveSpend = currentSpend + (estimatedCost ?? 0);
28
+ if (effectiveSpend > this.config.maxSpend) {
29
+ return {
30
+ allowed: false,
31
+ currentSpend,
32
+ maxSpend: this.config.maxSpend,
33
+ percentUsed: Math.round((currentSpend / this.config.maxSpend) * 100),
34
+ reason: `Budget exceeded: ${currentSpend} / ${this.config.maxSpend} (estimated +${estimatedCost ?? 0})`,
35
+ };
36
+ }
37
+ return {
38
+ allowed: true,
39
+ currentSpend,
40
+ maxSpend: this.config.maxSpend,
41
+ percentUsed: Math.round((currentSpend / this.config.maxSpend) * 100),
42
+ reason: "Within budget",
43
+ };
44
+ }
45
+ /** Record usage after execution (post-execution / Phase 2). */
46
+ record(key, usage) {
47
+ const k = resolveKey(key);
48
+ let entry = this.budgets.get(k);
49
+ if (!entry) {
50
+ entry = { records: [] };
51
+ this.budgets.set(k, entry);
52
+ }
53
+ entry.records.push(usage);
54
+ }
55
+ /** Get current spend in the budget period. */
56
+ getCurrentSpend(keyStr) {
57
+ const entry = this.budgets.get(keyStr);
58
+ if (!entry)
59
+ return 0;
60
+ const periodStart = Date.now() - this.config.periodMs;
61
+ return entry.records
62
+ .filter((r) => r.timestamp > periodStart)
63
+ .reduce((sum, r) => sum + r.cost, 0);
64
+ }
65
+ /** Get usage summary for a key. */
66
+ getUsageSummary(key) {
67
+ const k = resolveKey(key);
68
+ const entry = this.budgets.get(k);
69
+ if (!entry)
70
+ return { totalSpend: 0, totalTokens: 0, requestCount: 0 };
71
+ const periodStart = Date.now() - this.config.periodMs;
72
+ const inPeriod = entry.records.filter((r) => r.timestamp > periodStart);
73
+ return {
74
+ totalSpend: inPeriod.reduce((s, r) => s + r.cost, 0),
75
+ totalTokens: inPeriod.reduce((s, r) => s + (r.tokens ?? 0), 0),
76
+ requestCount: inPeriod.length,
77
+ };
78
+ }
79
+ cleanup() {
80
+ const cutoff = Date.now() - this.config.periodMs;
81
+ for (const [key, entry] of this.budgets) {
82
+ entry.records = entry.records.filter((r) => r.timestamp > cutoff);
83
+ if (entry.records.length === 0)
84
+ this.budgets.delete(key);
85
+ }
86
+ }
87
+ destroy() {
88
+ if (this.cleanupInterval) {
89
+ clearInterval(this.cleanupInterval);
90
+ this.cleanupInterval = null;
91
+ }
92
+ }
93
+ }
94
+ //# sourceMappingURL=budgetTracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budgetTracker.js","sourceRoot":"","sources":["../src/budgetTracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export * from "./rateLimiter.js";
2
+ export * from "./budgetTracker.js";
3
+ export * from "./agentGuard.js";
4
+ export * from "./preflight.js";
5
+ export type * from "./types.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,mBAAmB,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ // packages/limitabl-core/src/index.ts
2
+ //
3
+ // Core rate-limiting, budget, and agent protection logic.
4
+ // No Express, no HTTP. Pure functions + in-memory stores.
5
+ //
6
+ // FUTURE WORK:
7
+ // - Redis adapter for distributed rate limiting across instances
8
+ // - Anomaly detection (spike detection, unusual patterns)
9
+ // - Fallback provider routing (route to cheaper model when budget low)
10
+ // - Recursion depth tracking and duplicate tool call detection
11
+ // - Configurable storage backends (Redis, DynamoDB, Firestore)
12
+ export * from "./rateLimiter.js";
13
+ export * from "./budgetTracker.js";
14
+ export * from "./agentGuard.js";
15
+ export * from "./preflight.js";
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,EAAE;AACF,0DAA0D;AAC1D,0DAA0D;AAC1D,EAAE;AACF,eAAe;AACf,iEAAiE;AACjE,0DAA0D;AAC1D,uEAAuE;AACvE,+DAA+D;AAC/D,+DAA+D;AAE/D,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { LimitKey, RateLimitConfig, BudgetConfig, AgentGuardConfig, PreflightResult, PostExecutionInput } from "./types.js";
2
+ export interface LimitablCoreConfig {
3
+ rateLimit?: RateLimitConfig;
4
+ budget?: BudgetConfig;
5
+ agentGuard?: AgentGuardConfig;
6
+ }
7
+ /**
8
+ * Orchestrates all limitabl checks.
9
+ *
10
+ * Phase 1 (pre-flight): call preflight() before executing a request.
11
+ * Phase 2 (post-execution): call recordUsage() after execution completes.
12
+ */
13
+ export declare class LimitablEngine {
14
+ private rateLimiter?;
15
+ private budgetTracker?;
16
+ private agentGuard?;
17
+ constructor(config: LimitablCoreConfig);
18
+ /**
19
+ * Phase 1: Pre-flight check.
20
+ * Returns whether the request should proceed.
21
+ */
22
+ preflight(key: LimitKey, opts?: {
23
+ workflowId?: string;
24
+ estimatedCost?: number;
25
+ }): PreflightResult;
26
+ /**
27
+ * Phase 2: Record usage after execution.
28
+ * Updates budget tracker and agent guard counters.
29
+ */
30
+ recordUsage(input: PostExecutionInput): void;
31
+ /** Clean up (stop timers). */
32
+ destroy(): void;
33
+ }
34
+ //# sourceMappingURL=preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,eAAe,EAEf,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAKpB,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED;;;;;GAKG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAC,CAAsB;IAC1C,OAAO,CAAC,aAAa,CAAC,CAAwB;IAC9C,OAAO,CAAC,UAAU,CAAC,CAAa;gBAEpB,MAAM,EAAE,kBAAkB;IAYtC;;;OAGG;IACH,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,eAAe;IAwCjG;;;OAGG;IACH,WAAW,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAS5C,8BAA8B;IAC9B,OAAO,IAAI,IAAI;CAIhB"}
@@ -0,0 +1,87 @@
1
+ // packages/limitabl-core/src/preflight.ts
2
+ //
3
+ // Combined pre-flight check: runs rate limit + budget + agent guard
4
+ // and returns a single decision.
5
+ import { InMemoryRateLimiter } from "./rateLimiter.js";
6
+ import { InMemoryBudgetTracker } from "./budgetTracker.js";
7
+ import { AgentGuard } from "./agentGuard.js";
8
+ /**
9
+ * Orchestrates all limitabl checks.
10
+ *
11
+ * Phase 1 (pre-flight): call preflight() before executing a request.
12
+ * Phase 2 (post-execution): call recordUsage() after execution completes.
13
+ */
14
+ export class LimitablEngine {
15
+ rateLimiter;
16
+ budgetTracker;
17
+ agentGuard;
18
+ constructor(config) {
19
+ if (config.rateLimit) {
20
+ this.rateLimiter = new InMemoryRateLimiter(config.rateLimit);
21
+ }
22
+ if (config.budget) {
23
+ this.budgetTracker = new InMemoryBudgetTracker(config.budget);
24
+ }
25
+ if (config.agentGuard) {
26
+ this.agentGuard = new AgentGuard(config.agentGuard);
27
+ }
28
+ }
29
+ /**
30
+ * Phase 1: Pre-flight check.
31
+ * Returns whether the request should proceed.
32
+ */
33
+ preflight(key, opts) {
34
+ // Rate limit check
35
+ if (this.rateLimiter) {
36
+ const rl = this.rateLimiter.check(key);
37
+ if (!rl.allowed) {
38
+ return {
39
+ allowed: false,
40
+ reason: `Rate limited. Retry after ${rl.retryAfterSec}s`,
41
+ rateLimit: rl,
42
+ };
43
+ }
44
+ }
45
+ // Budget check
46
+ if (this.budgetTracker) {
47
+ const budget = this.budgetTracker.check(key, opts?.estimatedCost);
48
+ if (!budget.allowed) {
49
+ return {
50
+ allowed: false,
51
+ reason: budget.reason,
52
+ budget,
53
+ };
54
+ }
55
+ }
56
+ // Agent guard check
57
+ if (this.agentGuard && opts?.workflowId) {
58
+ const guard = this.agentGuard.check(opts.workflowId);
59
+ if (!guard.allowed) {
60
+ return {
61
+ allowed: false,
62
+ reason: guard.reason,
63
+ agentGuard: guard,
64
+ };
65
+ }
66
+ }
67
+ return { allowed: true, reason: "All checks passed" };
68
+ }
69
+ /**
70
+ * Phase 2: Record usage after execution.
71
+ * Updates budget tracker and agent guard counters.
72
+ */
73
+ recordUsage(input) {
74
+ if (this.budgetTracker) {
75
+ this.budgetTracker.record(input.key, input.usage);
76
+ }
77
+ if (this.agentGuard && input.workflowId) {
78
+ this.agentGuard.recordToolCall(input.workflowId, input.usage.cost);
79
+ }
80
+ }
81
+ /** Clean up (stop timers). */
82
+ destroy() {
83
+ this.rateLimiter?.destroy();
84
+ this.budgetTracker?.destroy();
85
+ }
86
+ }
87
+ //# sourceMappingURL=preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.js","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { LimitKey, RateLimitConfig, RateLimitResult } from "./types.js";
2
+ /**
3
+ * Resolve a LimitKey to a string key.
4
+ * Priority: sub > orgId > ip > "anonymous".
5
+ */
6
+ export declare function resolveKey(key: LimitKey): string;
7
+ export declare class InMemoryRateLimiter {
8
+ private windows;
9
+ private config;
10
+ private cleanupInterval;
11
+ constructor(config: RateLimitConfig);
12
+ /** Check if a request is allowed and record it if so. */
13
+ check(key: LimitKey): RateLimitResult;
14
+ /** Remove expired entries to prevent memory growth. */
15
+ private cleanup;
16
+ /** Stop the cleanup interval (for graceful shutdown / testing). */
17
+ destroy(): void;
18
+ }
19
+ //# sourceMappingURL=rateLimiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rateLimiter.d.ts","sourceRoot":"","sources":["../src/rateLimiter.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAM7E;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,CAQhD;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,eAAe,CAA+C;gBAE1D,MAAM,EAAE,eAAe;IAQnC,yDAAyD;IACzD,KAAK,CAAC,GAAG,EAAE,QAAQ,GAAG,eAAe;IAmCrC,uDAAuD;IACvD,OAAO,CAAC,OAAO;IAQf,mEAAmE;IACnE,OAAO;CAMR"}
@@ -0,0 +1,86 @@
1
+ // packages/limitabl-core/src/rateLimiter.ts
2
+ //
3
+ // Sliding window rate limiter. In-memory implementation.
4
+ //
5
+ // FUTURE WORK:
6
+ // - Redis adapter: replace InMemoryRateLimiter with RedisRateLimiter
7
+ // that uses MULTI/EXEC for atomic window operations.
8
+ // - Token bucket algorithm option for burst-friendly workloads.
9
+ /**
10
+ * Resolve a LimitKey to a string key.
11
+ * Priority: sub > orgId > ip > "anonymous".
12
+ */
13
+ export function resolveKey(key) {
14
+ const parts = [];
15
+ if (key.tenantId)
16
+ parts.push(`t:${key.tenantId}`);
17
+ if (key.sub)
18
+ parts.push(`u:${key.sub}`);
19
+ else if (key.orgId)
20
+ parts.push(`o:${key.orgId}`);
21
+ else if (key.ip)
22
+ parts.push(`ip:${key.ip}`);
23
+ else
24
+ parts.push("anonymous");
25
+ return parts.join("|");
26
+ }
27
+ export class InMemoryRateLimiter {
28
+ windows = new Map();
29
+ config;
30
+ cleanupInterval = null;
31
+ constructor(config) {
32
+ this.config = config;
33
+ // Periodically clean expired entries
34
+ this.cleanupInterval = setInterval(() => this.cleanup(), config.windowMs * 2);
35
+ // Allow process to exit even if interval is active
36
+ if (this.cleanupInterval.unref)
37
+ this.cleanupInterval.unref();
38
+ }
39
+ /** Check if a request is allowed and record it if so. */
40
+ check(key) {
41
+ const k = resolveKey(key);
42
+ const now = Date.now();
43
+ const windowStart = now - this.config.windowMs;
44
+ let entry = this.windows.get(k);
45
+ if (!entry) {
46
+ entry = { timestamps: [] };
47
+ this.windows.set(k, entry);
48
+ }
49
+ // Remove expired timestamps
50
+ entry.timestamps = entry.timestamps.filter((t) => t > windowStart);
51
+ if (entry.timestamps.length >= this.config.maxRequests) {
52
+ const oldestInWindow = entry.timestamps[0];
53
+ const resetAt = oldestInWindow + this.config.windowMs;
54
+ return {
55
+ allowed: false,
56
+ remaining: 0,
57
+ resetAt,
58
+ retryAfterSec: Math.ceil((resetAt - now) / 1000),
59
+ };
60
+ }
61
+ // Record this request
62
+ entry.timestamps.push(now);
63
+ return {
64
+ allowed: true,
65
+ remaining: this.config.maxRequests - entry.timestamps.length,
66
+ resetAt: now + this.config.windowMs,
67
+ };
68
+ }
69
+ /** Remove expired entries to prevent memory growth. */
70
+ cleanup() {
71
+ const cutoff = Date.now() - this.config.windowMs;
72
+ for (const [key, entry] of this.windows) {
73
+ entry.timestamps = entry.timestamps.filter((t) => t > cutoff);
74
+ if (entry.timestamps.length === 0)
75
+ this.windows.delete(key);
76
+ }
77
+ }
78
+ /** Stop the cleanup interval (for graceful shutdown / testing). */
79
+ destroy() {
80
+ if (this.cleanupInterval) {
81
+ clearInterval(this.cleanupInterval);
82
+ this.cleanupInterval = null;
83
+ }
84
+ }
85
+ }
86
+ //# sourceMappingURL=rateLimiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rateLimiter.js","sourceRoot":"","sources":["../src/rateLimiter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"fileNames":["../../../node_modules/typescript/lib/lib.es5.d.ts","../../../node_modules/typescript/lib/lib.es2015.d.ts","../../../node_modules/typescript/lib/lib.es2016.d.ts","../../../node_modules/typescript/lib/lib.es2017.d.ts","../../../node_modules/typescript/lib/lib.es2018.d.ts","../../../node_modules/typescript/lib/lib.es2019.d.ts","../../../node_modules/typescript/lib/lib.es2020.d.ts","../../../node_modules/typescript/lib/lib.es2021.d.ts","../../../node_modules/typescript/lib/lib.es2022.d.ts","../../../node_modules/typescript/lib/lib.dom.d.ts","../../../node_modules/typescript/lib/lib.dom.iterable.d.ts","../../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../node_modules/typescript/lib/lib.decorators.d.ts","../../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../node_modules/@types/react/global.d.ts","../../../node_modules/csstype/index.d.ts","../../../node_modules/@types/react/index.d.ts","../../../node_modules/@types/react/jsx-runtime.d.ts","../src/types.ts","../src/agentguard.ts","../src/ratelimiter.ts","../src/budgettracker.ts","../src/preflight.ts","../src/index.ts","../../../node_modules/@types/node/compatibility/disposable.d.ts","../../../node_modules/@types/node/compatibility/indexable.d.ts","../../../node_modules/@types/node/compatibility/iterators.d.ts","../../../node_modules/@types/node/compatibility/index.d.ts","../../../node_modules/@types/node/globals.typedarray.d.ts","../../../node_modules/@types/node/buffer.buffer.d.ts","../../../node_modules/@types/node/globals.d.ts","../../../node_modules/@types/node/web-globals/abortcontroller.d.ts","../../../node_modules/@types/node/web-globals/domexception.d.ts","../../../node_modules/@types/node/web-globals/events.d.ts","../../../node_modules/undici-types/header.d.ts","../../../node_modules/undici-types/readable.d.ts","../../../node_modules/undici-types/file.d.ts","../../../node_modules/undici-types/fetch.d.ts","../../../node_modules/undici-types/formdata.d.ts","../../../node_modules/undici-types/connector.d.ts","../../../node_modules/undici-types/client.d.ts","../../../node_modules/undici-types/errors.d.ts","../../../node_modules/undici-types/dispatcher.d.ts","../../../node_modules/undici-types/global-dispatcher.d.ts","../../../node_modules/undici-types/global-origin.d.ts","../../../node_modules/undici-types/pool-stats.d.ts","../../../node_modules/undici-types/pool.d.ts","../../../node_modules/undici-types/handlers.d.ts","../../../node_modules/undici-types/balanced-pool.d.ts","../../../node_modules/undici-types/agent.d.ts","../../../node_modules/undici-types/mock-interceptor.d.ts","../../../node_modules/undici-types/mock-agent.d.ts","../../../node_modules/undici-types/mock-client.d.ts","../../../node_modules/undici-types/mock-pool.d.ts","../../../node_modules/undici-types/mock-errors.d.ts","../../../node_modules/undici-types/proxy-agent.d.ts","../../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../../node_modules/undici-types/retry-handler.d.ts","../../../node_modules/undici-types/retry-agent.d.ts","../../../node_modules/undici-types/api.d.ts","../../../node_modules/undici-types/interceptors.d.ts","../../../node_modules/undici-types/util.d.ts","../../../node_modules/undici-types/cookies.d.ts","../../../node_modules/undici-types/patch.d.ts","../../../node_modules/undici-types/websocket.d.ts","../../../node_modules/undici-types/eventsource.d.ts","../../../node_modules/undici-types/filereader.d.ts","../../../node_modules/undici-types/diagnostics-channel.d.ts","../../../node_modules/undici-types/content-type.d.ts","../../../node_modules/undici-types/cache.d.ts","../../../node_modules/undici-types/index.d.ts","../../../node_modules/@types/node/web-globals/fetch.d.ts","../../../node_modules/@types/node/web-globals/navigator.d.ts","../../../node_modules/@types/node/web-globals/storage.d.ts","../../../node_modules/@types/node/assert.d.ts","../../../node_modules/@types/node/assert/strict.d.ts","../../../node_modules/@types/node/async_hooks.d.ts","../../../node_modules/@types/node/buffer.d.ts","../../../node_modules/@types/node/child_process.d.ts","../../../node_modules/@types/node/cluster.d.ts","../../../node_modules/@types/node/console.d.ts","../../../node_modules/@types/node/constants.d.ts","../../../node_modules/@types/node/crypto.d.ts","../../../node_modules/@types/node/dgram.d.ts","../../../node_modules/@types/node/diagnostics_channel.d.ts","../../../node_modules/@types/node/dns.d.ts","../../../node_modules/@types/node/dns/promises.d.ts","../../../node_modules/@types/node/domain.d.ts","../../../node_modules/@types/node/events.d.ts","../../../node_modules/@types/node/fs.d.ts","../../../node_modules/@types/node/fs/promises.d.ts","../../../node_modules/@types/node/http.d.ts","../../../node_modules/@types/node/http2.d.ts","../../../node_modules/@types/node/https.d.ts","../../../node_modules/@types/node/inspector.d.ts","../../../node_modules/@types/node/inspector.generated.d.ts","../../../node_modules/@types/node/module.d.ts","../../../node_modules/@types/node/net.d.ts","../../../node_modules/@types/node/os.d.ts","../../../node_modules/@types/node/path.d.ts","../../../node_modules/@types/node/perf_hooks.d.ts","../../../node_modules/@types/node/process.d.ts","../../../node_modules/@types/node/punycode.d.ts","../../../node_modules/@types/node/querystring.d.ts","../../../node_modules/@types/node/readline.d.ts","../../../node_modules/@types/node/readline/promises.d.ts","../../../node_modules/@types/node/repl.d.ts","../../../node_modules/@types/node/sea.d.ts","../../../node_modules/@types/node/sqlite.d.ts","../../../node_modules/@types/node/stream.d.ts","../../../node_modules/@types/node/stream/promises.d.ts","../../../node_modules/@types/node/stream/consumers.d.ts","../../../node_modules/@types/node/stream/web.d.ts","../../../node_modules/@types/node/string_decoder.d.ts","../../../node_modules/@types/node/test.d.ts","../../../node_modules/@types/node/timers.d.ts","../../../node_modules/@types/node/timers/promises.d.ts","../../../node_modules/@types/node/tls.d.ts","../../../node_modules/@types/node/trace_events.d.ts","../../../node_modules/@types/node/tty.d.ts","../../../node_modules/@types/node/url.d.ts","../../../node_modules/@types/node/util.d.ts","../../../node_modules/@types/node/v8.d.ts","../../../node_modules/@types/node/vm.d.ts","../../../node_modules/@types/node/wasi.d.ts","../../../node_modules/@types/node/worker_threads.d.ts","../../../node_modules/@types/node/zlib.d.ts","../../../node_modules/@types/node/index.d.ts"],"fileIdsList":[[75,120,121,123,140,141],[75,122,123,140,141],[123,140,141],[75,123,128,140,141,158],[75,123,124,129,134,140,141,143,155,166],[75,123,124,125,134,140,141,143],[75,123,140,141],[70,71,72,75,123,140,141],[75,123,126,140,141,167],[75,123,127,128,135,140,141,144],[75,123,128,140,141,155,163],[75,123,129,131,134,140,141,143],[75,122,123,130,140,141],[75,123,131,132,140,141],[75,123,133,134,140,141],[75,122,123,134,140,141],[75,123,134,135,136,140,141,155,166],[75,123,134,135,136,140,141,150,155,158],[75,116,123,131,134,137,140,141,143,155,166],[75,123,134,135,137,138,140,141,143,155,163,166],[75,123,137,139,140,141,155,163,166],[73,74,75,76,77,78,79,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172],[75,123,134,140,141],[75,123,140,141,142,166],[75,123,131,134,140,141,143,155],[75,123,140,141,144],[75,123,140,141,145],[75,122,123,140,141,146],[75,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172],[75,123,140,141,148],[75,123,140,141,149],[75,123,134,140,141,150,151],[75,123,140,141,150,152,167,169],[75,123,135,140,141],[75,123,134,140,141,155,156,158],[75,123,140,141,157,158],[75,123,140,141,155,156],[75,123,140,141,158],[75,123,140,141,159],[75,120,123,140,141,155,160],[75,123,134,140,141,161,162],[75,123,140,141,161,162],[75,123,128,140,141,143,155,163],[75,123,140,141,164],[75,123,140,141,143,165],[75,123,137,140,141,149,166],[75,123,128,140,141,167],[75,123,140,141,155,168],[75,123,140,141,142,169],[75,123,140,141,170],[75,116,123,140,141],[75,116,123,134,136,140,141,146,155,158,166,168,169,171],[75,123,140,141,155,172],[60,61,75,123,140,141],[62,75,123,140,141],[75,88,92,123,140,141,166],[75,88,123,140,141,155,166],[75,83,123,140,141],[75,85,88,123,140,141,163,166],[75,123,140,141,143,163],[75,123,140,141,173],[75,83,123,140,141,173],[75,85,88,123,140,141,143,166],[75,80,81,84,87,123,134,140,141,155,166],[75,88,95,123,140,141],[75,80,86,123,140,141],[75,88,109,110,123,140,141],[75,84,88,123,140,141,158,166,173],[75,109,123,140,141,173],[75,82,83,123,140,141,173],[75,88,123,140,141],[75,82,83,84,85,86,87,88,89,90,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,110,111,112,113,114,115,123,140,141],[75,88,103,123,140,141],[75,88,95,96,123,140,141],[75,86,88,96,97,123,140,141],[75,87,123,140,141],[75,80,83,88,123,140,141],[75,88,92,96,97,123,140,141],[75,92,123,140,141],[75,86,88,91,123,140,141,166],[75,80,85,88,95,123,140,141],[75,123,140,141,155],[75,83,88,109,123,140,141,171,173],[63,64,75,123,140,141],[63,64,66,75,123,140,141],[63,64,65,66,67,68,75,123,140,141],[63,64,65,66,67,75,123,140,141],[63,75,123,140,141]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"170d4db14678c68178ee8a3d5a990d5afb759ecb6ec44dbd885c50f6da6204f6","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"5e76305d58bcdc924ff2bf14f6a9dc2aa5441ed06464b7e7bd039e611d66a89b","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"33794c9a810b6fd1d450fd827c7ef2cc49255fc3f6bf271b4cd6314e30e87173","signature":"e248889ecee6474f7964a1fc7049688812d7a021c118dd81d930486d2dfff0ac"},{"version":"d54b20ad3dc2666e17e4b002c3245fdd061b71d372296c6f573b6f122e4321ad","signature":"62f0b841ce3f6e2b6b5a06e4af57681bdb49b8785d40f6ac4aab3aa2a6a688d9"},{"version":"b5dd8566da60fca8b3221d981c61ade56203e61de26b2133687ac2dca6d9b1c4","signature":"e80a16497a424b984f17bd7cacc49c46614bda5caa8774701c150b0fa18d66e2"},{"version":"e14bae7c47df944cdb6176bb5729c0a8685520b25bc308eac6a1085bc0f448bf","signature":"8c59bc43b4d0e42eea23a90559518227cce8466a1954277d28cb8a7641ae153b"},{"version":"a788d57499cb25974ddb4f89abba90deb8d10ce2c818aefb5346bb24feb3c10f","signature":"a8a4d64e9843f68f449422b6b83cb9cc4cf4ca8b48da8376c2825fa0f7e791ac"},{"version":"232ef7aee8e8f5d3f34c0798b7395e43623b14c41feaceabaf087fe9a7b2b4fc","signature":"9bae6ea8b79a90c927fe69d7294ab67c51922bd60ef95eaee225fe6c0f9c5db4"},{"version":"6c7176368037af28cb72f2392010fa1cef295d6d6744bca8cfb54985f3a18c3e","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"437e20f2ba32abaeb7985e0afe0002de1917bc74e949ba585e49feba65da6ca1","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"3af97acf03cc97de58a3a4bc91f8f616408099bc4233f6d0852e72a8ffb91ac9","affectsGlobalScope":true,"impliedFormat":1},{"version":"808069bba06b6768b62fd22429b53362e7af342da4a236ed2d2e1c89fcca3b4a","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"2cbe0621042e2a68c7cbce5dfed3906a1862a16a7d496010636cdbdb91341c0f","affectsGlobalScope":true,"impliedFormat":1},{"version":"f9501cc13ce624c72b61f12b3963e84fad210fbdf0ffbc4590e08460a3f04eba","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0fa06ada475b910e2106c98c68b10483dc8811d0c14a8a8dd36efb2672485b29","impliedFormat":1},{"version":"33e5e9aba62c3193d10d1d33ae1fa75c46a1171cf76fef750777377d53b0303f","impliedFormat":1},{"version":"2b06b93fd01bcd49d1a6bd1f9b65ddcae6480b9a86e9061634d6f8e354c1468f","impliedFormat":1},{"version":"6a0cd27e5dc2cfbe039e731cf879d12b0e2dded06d1b1dedad07f7712de0d7f4","affectsGlobalScope":true,"impliedFormat":1},{"version":"13f5c844119c43e51ce777c509267f14d6aaf31eafb2c2b002ca35584cd13b29","impliedFormat":1},{"version":"e60477649d6ad21542bd2dc7e3d9ff6853d0797ba9f689ba2f6653818999c264","impliedFormat":1},{"version":"c2510f124c0293ab80b1777c44d80f812b75612f297b9857406468c0f4dafe29","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"4c829ab315f57c5442c6667b53769975acbf92003a66aef19bce151987675bd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"b2ade7657e2db96d18315694789eff2ddd3d8aea7215b181f8a0b303277cc579","impliedFormat":1},{"version":"9855e02d837744303391e5623a531734443a5f8e6e8755e018c41d63ad797db2","impliedFormat":1},{"version":"4d631b81fa2f07a0e63a9a143d6a82c25c5f051298651a9b69176ba28930756d","impliedFormat":1},{"version":"836a356aae992ff3c28a0212e3eabcb76dd4b0cc06bcb9607aeef560661b860d","impliedFormat":1},{"version":"1e0d1f8b0adfa0b0330e028c7941b5a98c08b600efe7f14d2d2a00854fb2f393","impliedFormat":1},{"version":"41670ee38943d9cbb4924e436f56fc19ee94232bc96108562de1a734af20dc2c","affectsGlobalScope":true,"impliedFormat":1},{"version":"c906fb15bd2aabc9ed1e3f44eb6a8661199d6c320b3aa196b826121552cb3695","impliedFormat":1},{"version":"22295e8103f1d6d8ea4b5d6211e43421fe4564e34d0dd8e09e520e452d89e659","impliedFormat":1},{"version":"bb45cd435da536500f1d9692a9b49d0c570b763ccbf00473248b777f5c1f353b","impliedFormat":1},{"version":"6b4e081d55ac24fc8a4631d5dd77fe249fa25900abd7d046abb87d90e3b45645","impliedFormat":1},{"version":"a10f0e1854f3316d7ee437b79649e5a6ae3ae14ffe6322b02d4987071a95362e","impliedFormat":1},{"version":"e208f73ef6a980104304b0d2ca5f6bf1b85de6009d2c7e404028b875020fa8f2","impliedFormat":1},{"version":"d163b6bc2372b4f07260747cbc6c0a6405ab3fbcea3852305e98ac43ca59f5bc","impliedFormat":1},{"version":"e6fa9ad47c5f71ff733744a029d1dc472c618de53804eae08ffc243b936f87ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"83e63d6ccf8ec004a3bb6d58b9bb0104f60e002754b1e968024b320730cc5311","impliedFormat":1},{"version":"24826ed94a78d5c64bd857570fdbd96229ad41b5cb654c08d75a9845e3ab7dde","impliedFormat":1},{"version":"8b479a130ccb62e98f11f136d3ac80f2984fdc07616516d29881f3061f2dd472","impliedFormat":1},{"version":"928af3d90454bf656a52a48679f199f64c1435247d6189d1caf4c68f2eaf921f","affectsGlobalScope":true,"impliedFormat":1},{"version":"21145ce1c54e05ef9e52092b98a4ebfb326b92f52e76e47211c50cfcd2a2b4ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f16a7e4deafa527ed9995a772bb380eb7d3c2c0fd4ae178c5263ed18394db2c","impliedFormat":1},{"version":"933921f0bb0ec12ef45d1062a1fc0f27635318f4d294e4d99de9a5493e618ca2","impliedFormat":1},{"version":"71a0f3ad612c123b57239a7749770017ecfe6b66411488000aba83e4546fde25","impliedFormat":1},{"version":"77fbe5eecb6fac4b6242bbf6eebfc43e98ce5ccba8fa44e0ef6a95c945ff4d98","impliedFormat":1},{"version":"4f9d8ca0c417b67b69eeb54c7ca1bedd7b56034bb9bfd27c5d4f3bc4692daca7","impliedFormat":1},{"version":"814118df420c4e38fe5ae1b9a3bafb6e9c2aa40838e528cde908381867be6466","impliedFormat":1},{"version":"a3fc63c0d7b031693f665f5494412ba4b551fe644ededccc0ab5922401079c95","impliedFormat":1},{"version":"f27524f4bef4b6519c604bdb23bf4465bddcccbf3f003abb901acbd0d7404d99","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"dba28a419aec76ed864ef43e5f577a5c99a010c32e5949fe4e17a4d57c58dd11","affectsGlobalScope":true,"impliedFormat":1},{"version":"18fd40412d102c5564136f29735e5d1c3b455b8a37f920da79561f1fde068208","impliedFormat":1},{"version":"c959a391a75be9789b43c8468f71e3fa06488b4d691d5729dde1416dcd38225b","impliedFormat":1},{"version":"f0be1b8078cd549d91f37c30c222c2a187ac1cf981d994fb476a1adc61387b14","affectsGlobalScope":true,"impliedFormat":1},{"version":"0aaed1d72199b01234152f7a60046bc947f1f37d78d182e9ae09c4289e06a592","impliedFormat":1},{"version":"5ebe6f4cc3b803cbfc962bae0d954f9c80e5078ca41eb3f1de41d92e7193ef37","impliedFormat":1},{"version":"66ba1b2c3e3a3644a1011cd530fb444a96b1b2dfe2f5e837a002d41a1a799e60","impliedFormat":1},{"version":"7e514f5b852fdbc166b539fdd1f4e9114f29911592a5eb10a94bb3a13ccac3c4","impliedFormat":1},{"version":"5b7aa3c4c1a5d81b411e8cb302b45507fea9358d3569196b27eb1a27ae3a90ef","affectsGlobalScope":true,"impliedFormat":1},{"version":"5987a903da92c7462e0b35704ce7da94d7fdc4b89a984871c0e2b87a8aae9e69","affectsGlobalScope":true,"impliedFormat":1},{"version":"ea08a0345023ade2b47fbff5a76d0d0ed8bff10bc9d22b83f40858a8e941501c","impliedFormat":1},{"version":"47613031a5a31510831304405af561b0ffaedb734437c595256bb61a90f9311b","impliedFormat":1},{"version":"ae062ce7d9510060c5d7e7952ae379224fb3f8f2dd74e88959878af2057c143b","impliedFormat":1},{"version":"8a1a0d0a4a06a8d278947fcb66bf684f117bf147f89b06e50662d79a53be3e9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"9f663c2f91127ef7024e8ca4b3b4383ff2770e5f826696005de382282794b127","impliedFormat":1},{"version":"9f55299850d4f0921e79b6bf344b47c420ce0f507b9dcf593e532b09ea7eeea1","impliedFormat":1}],"root":[[64,69]],"options":{"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"jsx":4,"jsxImportSource":"react","module":99,"outDir":"./","rootDir":"../src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":9,"tsBuildInfoFile":"./tsconfig.tsbuildinfo"},"referencedMap":[[120,1],[121,1],[122,2],[75,3],[123,4],[124,5],[125,6],[70,7],[73,8],[71,7],[72,7],[126,9],[127,10],[128,11],[129,12],[130,13],[131,14],[132,14],[133,15],[134,16],[135,17],[136,18],[76,7],[74,7],[137,19],[138,20],[139,21],[173,22],[140,23],[141,7],[142,24],[143,25],[144,26],[145,27],[146,28],[147,29],[148,30],[149,31],[150,32],[151,32],[152,33],[153,7],[154,34],[155,35],[157,36],[156,37],[158,38],[159,39],[160,40],[161,41],[162,42],[163,43],[164,44],[165,45],[166,46],[167,47],[168,48],[169,49],[170,50],[77,7],[78,7],[79,7],[117,51],[118,7],[119,7],[171,52],[172,53],[60,7],[62,54],[63,55],[61,7],[58,7],[59,7],[10,7],[11,7],[13,7],[12,7],[2,7],[14,7],[15,7],[16,7],[17,7],[18,7],[19,7],[20,7],[21,7],[3,7],[22,7],[23,7],[4,7],[24,7],[28,7],[25,7],[26,7],[27,7],[29,7],[30,7],[31,7],[5,7],[32,7],[33,7],[34,7],[35,7],[6,7],[39,7],[36,7],[37,7],[38,7],[40,7],[7,7],[41,7],[46,7],[47,7],[42,7],[43,7],[44,7],[45,7],[8,7],[51,7],[48,7],[49,7],[50,7],[52,7],[9,7],[53,7],[54,7],[55,7],[57,7],[56,7],[1,7],[95,56],[105,57],[94,56],[115,58],[86,59],[85,60],[114,61],[108,62],[113,63],[88,64],[102,65],[87,66],[111,67],[83,68],[82,61],[112,69],[84,70],[89,71],[90,7],[93,71],[80,7],[116,72],[106,73],[97,74],[98,75],[100,76],[96,77],[99,78],[109,61],[91,79],[92,80],[101,81],[81,82],[104,73],[103,71],[107,7],[110,83],[65,84],[67,85],[69,86],[68,87],[66,84],[64,88]],"latestChangedDtsFile":"./index.d.ts","version":"5.9.3"}
@@ -0,0 +1,93 @@
1
+ /** Identity key used for rate limiting and budget tracking. */
2
+ export interface LimitKey {
3
+ /** User ID (from JWT sub claim). */
4
+ sub?: string;
5
+ /** Organization ID (from JWT org_id claim). */
6
+ orgId?: string;
7
+ /** IP address (fallback). */
8
+ ip?: string;
9
+ /** Tenant ID (for multi-tenant deployments). */
10
+ tenantId?: string;
11
+ }
12
+ /** Rate limit configuration. */
13
+ export interface RateLimitConfig {
14
+ /** Window size in milliseconds. */
15
+ windowMs: number;
16
+ /** Maximum requests per window. */
17
+ maxRequests: number;
18
+ }
19
+ /** Result of a rate limit check. */
20
+ export interface RateLimitResult {
21
+ allowed: boolean;
22
+ /** Requests remaining in current window. */
23
+ remaining: number;
24
+ /** When the current window resets (epoch ms). */
25
+ resetAt: number;
26
+ /** Retry-After value in seconds (if denied). */
27
+ retryAfterSec?: number;
28
+ }
29
+ /** Budget configuration for a single entity (user, org, tenant). */
30
+ export interface BudgetConfig {
31
+ /** Maximum spend in the budget period (in cents or smallest currency unit). */
32
+ maxSpend: number;
33
+ /** Budget period in milliseconds (e.g., 30 days). */
34
+ periodMs: number;
35
+ /** Optional per-model spend limits. */
36
+ modelLimits?: Record<string, number>;
37
+ }
38
+ /** A single usage record (post-execution). */
39
+ export interface UsageRecord {
40
+ /** When the usage occurred (epoch ms). */
41
+ timestamp: number;
42
+ /** Cost in cents or smallest currency unit. */
43
+ cost: number;
44
+ /** Token count (input + output). */
45
+ tokens?: number;
46
+ /** Model used. */
47
+ model?: string;
48
+ /** Tool invoked. */
49
+ tool?: string;
50
+ }
51
+ /** Result of a budget check. */
52
+ export interface BudgetCheckResult {
53
+ allowed: boolean;
54
+ /** Current spend in the budget period. */
55
+ currentSpend: number;
56
+ /** Maximum allowed spend. */
57
+ maxSpend: number;
58
+ /** Percentage of budget used (0-100+). */
59
+ percentUsed: number;
60
+ reason: string;
61
+ }
62
+ /** Agent guard configuration. */
63
+ export interface AgentGuardConfig {
64
+ /** Maximum tool calls per workflow/session. Default: 50. */
65
+ maxToolCalls?: number;
66
+ /** Maximum total cost per workflow (cents). Default: 1000 ($10). */
67
+ maxWorkflowCost?: number;
68
+ /** Maximum workflow duration in milliseconds. Default: 300000 (5 min). */
69
+ maxDurationMs?: number;
70
+ }
71
+ /** Result of an agent guard check. */
72
+ export interface AgentGuardResult {
73
+ allowed: boolean;
74
+ reason: string;
75
+ toolCallCount: number;
76
+ workflowCost: number;
77
+ durationMs: number;
78
+ }
79
+ /** Combined pre-flight check result. */
80
+ export interface PreflightResult {
81
+ allowed: boolean;
82
+ reason: string;
83
+ rateLimit?: RateLimitResult;
84
+ budget?: BudgetCheckResult;
85
+ agentGuard?: AgentGuardResult;
86
+ }
87
+ /** Post-execution recording input. */
88
+ export interface PostExecutionInput {
89
+ key: LimitKey;
90
+ usage: UsageRecord;
91
+ workflowId?: string;
92
+ }
93
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,+DAA+D;AAC/D,MAAM,WAAW,QAAQ;IACvB,oCAAoC;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,gCAAgC;AAChC,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,oCAAoC;AACpC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,oEAAoE;AACpE,MAAM,WAAW,YAAY;IAC3B,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,8CAA8C;AAC9C,MAAM,WAAW,WAAW;IAC1B,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,gCAAgC;AAChC,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,iCAAiC;AACjC,MAAM,WAAW,gBAAgB;IAC/B,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,sCAAsC;AACtC,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wCAAwC;AACxC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED,sCAAsC;AACtC,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,WAAW,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // packages/limitabl-core/src/types.ts
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,sCAAsC"}
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@gatewaystack/limitabl-core",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": "./dist/index.js"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "README.md",
15
+ "LICENSE"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc -p tsconfig.json",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "devDependencies": {
22
+ "typescript": "^5.6.3"
23
+ }
24
+ }