@agentforge-io/core 0.2.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 (151) hide show
  1. package/dist/adapters/billing/billing-adapter.interface.d.ts +41 -0
  2. package/dist/adapters/billing/billing-adapter.interface.js +5 -0
  3. package/dist/adapters/billing/stripe/stripe.adapter.d.ts +30 -0
  4. package/dist/adapters/billing/stripe/stripe.adapter.js +122 -0
  5. package/dist/adapters/email/email-adapter.interface.d.ts +25 -0
  6. package/dist/adapters/email/email-adapter.interface.js +6 -0
  7. package/dist/adapters/email/noop.adapter.d.ts +10 -0
  8. package/dist/adapters/email/noop.adapter.js +15 -0
  9. package/dist/adapters/email/resend.adapter.d.ts +8 -0
  10. package/dist/adapters/email/resend.adapter.js +39 -0
  11. package/dist/adapters/job-queue/in-memory.d.ts +43 -0
  12. package/dist/adapters/job-queue/in-memory.js +154 -0
  13. package/dist/adapters/job-queue/job-queue.types.d.ts +76 -0
  14. package/dist/adapters/job-queue/job-queue.types.js +5 -0
  15. package/dist/adapters/prepared-stream/prepared-stream.types.d.ts +23 -0
  16. package/dist/adapters/prepared-stream/prepared-stream.types.js +5 -0
  17. package/dist/adapters/rate-limiter/in-memory.d.ts +19 -0
  18. package/dist/adapters/rate-limiter/in-memory.js +63 -0
  19. package/dist/adapters/rate-limiter/rate-limiter.types.d.ts +42 -0
  20. package/dist/adapters/rate-limiter/rate-limiter.types.js +5 -0
  21. package/dist/adapters/rate-limiter/redis.d.ts +31 -0
  22. package/dist/adapters/rate-limiter/redis.js +47 -0
  23. package/dist/adapters/upload/noop.adapter.d.ts +9 -0
  24. package/dist/adapters/upload/noop.adapter.js +14 -0
  25. package/dist/adapters/upload/s3.adapter.d.ts +38 -0
  26. package/dist/adapters/upload/s3.adapter.js +69 -0
  27. package/dist/adapters/upload/upload-adapter.interface.d.ts +37 -0
  28. package/dist/adapters/upload/upload-adapter.interface.js +15 -0
  29. package/dist/ai/index.d.ts +15 -0
  30. package/dist/ai/index.js +43 -0
  31. package/dist/billing/index.d.ts +12 -0
  32. package/dist/billing/index.js +28 -0
  33. package/dist/constants.d.ts +3 -0
  34. package/dist/constants.js +8 -0
  35. package/dist/domain/agent.d.ts +59 -0
  36. package/dist/domain/agent.js +2 -0
  37. package/dist/domain/api-key.d.ts +28 -0
  38. package/dist/domain/api-key.js +2 -0
  39. package/dist/domain/auth-identity.d.ts +10 -0
  40. package/dist/domain/auth-identity.js +2 -0
  41. package/dist/domain/chat-token.d.ts +39 -0
  42. package/dist/domain/chat-token.js +2 -0
  43. package/dist/domain/connector-auth.d.ts +42 -0
  44. package/dist/domain/connector-auth.js +2 -0
  45. package/dist/domain/connector.d.ts +52 -0
  46. package/dist/domain/connector.js +2 -0
  47. package/dist/domain/conversation.d.ts +26 -0
  48. package/dist/domain/conversation.js +2 -0
  49. package/dist/domain/email-token.d.ts +11 -0
  50. package/dist/domain/email-token.js +2 -0
  51. package/dist/domain/external-user.d.ts +23 -0
  52. package/dist/domain/external-user.js +2 -0
  53. package/dist/domain/index.d.ts +5 -0
  54. package/dist/domain/index.js +24 -0
  55. package/dist/domain/mcp-server.d.ts +33 -0
  56. package/dist/domain/mcp-server.js +2 -0
  57. package/dist/domain/plan.d.ts +20 -0
  58. package/dist/domain/plan.js +2 -0
  59. package/dist/domain/platform-secret.d.ts +24 -0
  60. package/dist/domain/platform-secret.js +8 -0
  61. package/dist/domain/refresh-token.d.ts +15 -0
  62. package/dist/domain/refresh-token.js +2 -0
  63. package/dist/domain/subscription.d.ts +21 -0
  64. package/dist/domain/subscription.js +2 -0
  65. package/dist/domain/tenant.d.ts +21 -0
  66. package/dist/domain/tenant.js +2 -0
  67. package/dist/domain/usage-record.d.ts +15 -0
  68. package/dist/domain/usage-record.js +2 -0
  69. package/dist/domain/user.d.ts +43 -0
  70. package/dist/domain/user.js +2 -0
  71. package/dist/factory.d.ts +68 -0
  72. package/dist/factory.js +56 -0
  73. package/dist/index.d.ts +14 -0
  74. package/dist/index.js +59 -0
  75. package/dist/repositories/in-memory.d.ts +30 -0
  76. package/dist/repositories/in-memory.js +82 -0
  77. package/dist/repositories/index.d.ts +67 -0
  78. package/dist/repositories/index.js +16 -0
  79. package/dist/services/agent-config.service.d.ts +45 -0
  80. package/dist/services/agent-config.service.js +114 -0
  81. package/dist/services/agent-job.worker.d.ts +32 -0
  82. package/dist/services/agent-job.worker.js +97 -0
  83. package/dist/services/agent-runner.service.d.ts +35 -0
  84. package/dist/services/agent-runner.service.js +224 -0
  85. package/dist/services/agent.service.d.ts +171 -0
  86. package/dist/services/agent.service.js +329 -0
  87. package/dist/services/api-key.service.d.ts +41 -0
  88. package/dist/services/api-key.service.js +80 -0
  89. package/dist/services/auth.service.d.ts +133 -0
  90. package/dist/services/auth.service.js +411 -0
  91. package/dist/services/billing.service.d.ts +67 -0
  92. package/dist/services/billing.service.js +254 -0
  93. package/dist/services/chat-token.service.d.ts +29 -0
  94. package/dist/services/chat-token.service.js +113 -0
  95. package/dist/services/connector-registry.service.d.ts +156 -0
  96. package/dist/services/connector-registry.service.js +278 -0
  97. package/dist/services/conversation.service.d.ts +47 -0
  98. package/dist/services/conversation.service.js +101 -0
  99. package/dist/services/email-templates.d.ts +18 -0
  100. package/dist/services/email-templates.js +39 -0
  101. package/dist/services/email.service.d.ts +26 -0
  102. package/dist/services/email.service.js +42 -0
  103. package/dist/services/errors.d.ts +7 -0
  104. package/dist/services/errors.js +27 -0
  105. package/dist/services/in-memory-prepared-stream.store.d.ts +13 -0
  106. package/dist/services/in-memory-prepared-stream.store.js +35 -0
  107. package/dist/services/index.d.ts +13 -0
  108. package/dist/services/index.js +40 -0
  109. package/dist/services/mcp-client.service.d.ts +64 -0
  110. package/dist/services/mcp-client.service.js +157 -0
  111. package/dist/services/mcp-server.service.d.ts +44 -0
  112. package/dist/services/mcp-server.service.js +147 -0
  113. package/dist/services/oauth.service.d.ts +73 -0
  114. package/dist/services/oauth.service.js +174 -0
  115. package/dist/services/oauth2.service.d.ts +57 -0
  116. package/dist/services/oauth2.service.js +82 -0
  117. package/dist/services/orchestrator.service.d.ts +45 -0
  118. package/dist/services/orchestrator.service.js +180 -0
  119. package/dist/services/plan.service.d.ts +54 -0
  120. package/dist/services/plan.service.js +120 -0
  121. package/dist/services/prepared-stream.service.d.ts +23 -0
  122. package/dist/services/prepared-stream.service.js +43 -0
  123. package/dist/services/refresh-token.service.d.ts +38 -0
  124. package/dist/services/refresh-token.service.js +73 -0
  125. package/dist/services/secrets/crypto.d.ts +37 -0
  126. package/dist/services/secrets/crypto.js +110 -0
  127. package/dist/services/secrets/known-keys.d.ts +38 -0
  128. package/dist/services/secrets/known-keys.js +50 -0
  129. package/dist/services/secrets.service.d.ts +91 -0
  130. package/dist/services/secrets.service.js +193 -0
  131. package/dist/services/tenant-billing.service.d.ts +121 -0
  132. package/dist/services/tenant-billing.service.js +290 -0
  133. package/dist/services/tenant.service.d.ts +54 -0
  134. package/dist/services/tenant.service.js +96 -0
  135. package/dist/services/tool-registry.service.d.ts +42 -0
  136. package/dist/services/tool-registry.service.js +101 -0
  137. package/dist/services/upload.service.d.ts +37 -0
  138. package/dist/services/upload.service.js +84 -0
  139. package/dist/services/usage.service.d.ts +34 -0
  140. package/dist/services/usage.service.js +108 -0
  141. package/dist/types/agent.types.d.ts +160 -0
  142. package/dist/types/agent.types.js +2 -0
  143. package/dist/types/billing.types.d.ts +82 -0
  144. package/dist/types/billing.types.js +3 -0
  145. package/dist/types/config.types.d.ts +127 -0
  146. package/dist/types/config.types.js +9 -0
  147. package/dist/types/hooks.d.ts +85 -0
  148. package/dist/types/hooks.js +2 -0
  149. package/dist/types/index.d.ts +3 -0
  150. package/dist/types/index.js +19 -0
  151. package/package.json +36 -0
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InMemoryRateLimiter = void 0;
4
+ /**
5
+ * Fixed-window counter. Each key gets a bucket holding the current count and
6
+ * the window-start timestamp; the bucket resets when the window expires.
7
+ *
8
+ * Single-instance only — counters live in process memory. For multi-instance
9
+ * deploys use `RedisRateLimiter`, which shares counters across nodes via INCR.
10
+ */
11
+ class InMemoryRateLimiter {
12
+ constructor(opts = {}) {
13
+ this.buckets = new Map();
14
+ const interval = opts.cleanupIntervalMs ?? 60_000;
15
+ // Don't keep the event loop alive just for cleanup.
16
+ if (interval > 0 && typeof setInterval === 'function') {
17
+ this.cleanupInterval = setInterval(() => this.evictExpired(), interval);
18
+ // Node-specific: don't block process exit.
19
+ this.cleanupInterval.unref?.();
20
+ }
21
+ else {
22
+ this.cleanupInterval = null;
23
+ }
24
+ }
25
+ async consume(key, opts) {
26
+ const now = Date.now();
27
+ const bucket = this.buckets.get(key);
28
+ if (!bucket || now - bucket.windowStartedAt >= opts.windowMs) {
29
+ this.buckets.set(key, { count: 1, windowStartedAt: now });
30
+ return {
31
+ allowed: true,
32
+ remaining: Math.max(0, opts.max - 1),
33
+ retryAfterMs: opts.windowMs,
34
+ };
35
+ }
36
+ bucket.count += 1;
37
+ const allowed = bucket.count <= opts.max;
38
+ const retryAfterMs = Math.max(0, opts.windowMs - (now - bucket.windowStartedAt));
39
+ return {
40
+ allowed,
41
+ remaining: Math.max(0, opts.max - bucket.count),
42
+ retryAfterMs,
43
+ };
44
+ }
45
+ /** Stops the periodic cleanup. Call when shutting down a test or worker. */
46
+ close() {
47
+ if (this.cleanupInterval)
48
+ clearInterval(this.cleanupInterval);
49
+ }
50
+ evictExpired() {
51
+ const now = Date.now();
52
+ // Without per-key window sizes recorded we evict bucket entries that have
53
+ // been idle for more than an hour — long enough for any sane window to
54
+ // have elapsed, short enough to keep memory bounded.
55
+ const idleThresholdMs = 60 * 60 * 1000;
56
+ for (const [key, bucket] of this.buckets) {
57
+ if (now - bucket.windowStartedAt > idleThresholdMs) {
58
+ this.buckets.delete(key);
59
+ }
60
+ }
61
+ }
62
+ }
63
+ exports.InMemoryRateLimiter = InMemoryRateLimiter;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Pluggable rate-limiter contract. Used by adapters (Express middleware,
3
+ * Nest guard) to gate sensitive endpoints — anti brute-force on /auth/login,
4
+ * anti enumeration on /auth/request-password-reset, anti abuse on register.
5
+ *
6
+ * Two implementations ship with @agentforge-io/core:
7
+ * - InMemoryRateLimiter — fixed-window counter per key. Default for
8
+ * single-instance deploys; counters reset on process restart.
9
+ * - RedisRateLimiter — INCR + EXPIRE per (key, window). Use when you run
10
+ * more than one API instance: counters are shared across them.
11
+ *
12
+ * Distinct from `UsageService.checkLimits` / `TenantBillingService.checkLimits`,
13
+ * which enforce monthly billing quotas. A rate-limiter caps short-window
14
+ * request volume and returns 429; quotas cap monthly spend and return 403.
15
+ */
16
+ export interface RateLimitOptions {
17
+ /** Length of the window in milliseconds. */
18
+ windowMs: number;
19
+ /** Maximum number of consumed tokens permitted within the window. */
20
+ max: number;
21
+ }
22
+ export interface RateLimitResult {
23
+ /** True when the request is below the cap and may proceed. */
24
+ allowed: boolean;
25
+ /** Remaining permitted requests in the current window. Never negative. */
26
+ remaining: number;
27
+ /** Milliseconds until the window resets. Always set, even when `allowed`. */
28
+ retryAfterMs: number;
29
+ }
30
+ export interface RateLimiter {
31
+ /**
32
+ * Record one consumed token for `key` under `opts`. Returns the new state.
33
+ * Implementations MUST be idempotent on a per-call basis — every call counts
34
+ * as exactly one request, even when `allowed: false`.
35
+ *
36
+ * The `key` is whatever the adapter chose to bucket on: an IP for
37
+ * unauthenticated endpoints, a userId for authenticated rate-limits, a
38
+ * (tenantId, route) pair for API keys. The limiter does not interpret it.
39
+ */
40
+ consume(key: string, opts: RateLimitOptions): Promise<RateLimitResult>;
41
+ }
42
+ export declare const RATE_LIMITER = "AGENTFORGE_RATE_LIMITER";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RATE_LIMITER = void 0;
4
+ // String token (not Symbol) so it survives duplicate package instances.
5
+ exports.RATE_LIMITER = 'AGENTFORGE_RATE_LIMITER';
@@ -0,0 +1,31 @@
1
+ import type { RateLimitOptions, RateLimitResult, RateLimiter } from './rate-limiter.types';
2
+ /**
3
+ * Minimal subset of the Redis client surface this adapter needs. `ioredis`
4
+ * and `redis` both satisfy it structurally — we don't import either to keep
5
+ * `@agentforge-io/core` framework- and dep-free.
6
+ */
7
+ export interface RedisLike {
8
+ incr(key: string): Promise<number>;
9
+ /** Sets the TTL in milliseconds. */
10
+ pexpire(key: string, ms: number): Promise<number>;
11
+ /** Time-to-live in milliseconds. Returns -1 if no TTL, -2 if missing. */
12
+ pttl(key: string): Promise<number>;
13
+ }
14
+ /**
15
+ * Fixed-window counter backed by Redis. The key holds the request count for
16
+ * the current window; the TTL is set on the first INCR of each window so
17
+ * the counter resets cleanly when the window expires.
18
+ *
19
+ * Designed for multi-instance deploys: every API node hits the same Redis,
20
+ * so a brute-force attempt spread across all nodes still hits the cap.
21
+ *
22
+ * Two round-trips per call in the worst case (INCR + PEXPIRE on the first
23
+ * request of a window; INCR + PTTL on subsequent ones). Acceptable for the
24
+ * auth-rate-limit path; if you need lower latency on a hotter endpoint, use
25
+ * a Lua script that does both atomically.
26
+ */
27
+ export declare class RedisRateLimiter implements RateLimiter {
28
+ private readonly redis;
29
+ constructor(redis: RedisLike);
30
+ consume(key: string, opts: RateLimitOptions): Promise<RateLimitResult>;
31
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RedisRateLimiter = void 0;
4
+ const KEY_PREFIX = 'af:rl:';
5
+ /**
6
+ * Fixed-window counter backed by Redis. The key holds the request count for
7
+ * the current window; the TTL is set on the first INCR of each window so
8
+ * the counter resets cleanly when the window expires.
9
+ *
10
+ * Designed for multi-instance deploys: every API node hits the same Redis,
11
+ * so a brute-force attempt spread across all nodes still hits the cap.
12
+ *
13
+ * Two round-trips per call in the worst case (INCR + PEXPIRE on the first
14
+ * request of a window; INCR + PTTL on subsequent ones). Acceptable for the
15
+ * auth-rate-limit path; if you need lower latency on a hotter endpoint, use
16
+ * a Lua script that does both atomically.
17
+ */
18
+ class RedisRateLimiter {
19
+ constructor(redis) {
20
+ this.redis = redis;
21
+ }
22
+ async consume(key, opts) {
23
+ const redisKey = KEY_PREFIX + key;
24
+ const count = await this.redis.incr(redisKey);
25
+ let ttlMs;
26
+ if (count === 1) {
27
+ // First hit of a new window — set the TTL.
28
+ await this.redis.pexpire(redisKey, opts.windowMs);
29
+ ttlMs = opts.windowMs;
30
+ }
31
+ else {
32
+ ttlMs = await this.redis.pttl(redisKey);
33
+ // -1: key exists but has no TTL (race with eviction or a manual SET).
34
+ // Restore a TTL so the counter resets eventually.
35
+ if (ttlMs < 0) {
36
+ await this.redis.pexpire(redisKey, opts.windowMs);
37
+ ttlMs = opts.windowMs;
38
+ }
39
+ }
40
+ return {
41
+ allowed: count <= opts.max,
42
+ remaining: Math.max(0, opts.max - count),
43
+ retryAfterMs: ttlMs,
44
+ };
45
+ }
46
+ }
47
+ exports.RedisRateLimiter = RedisRateLimiter;
@@ -0,0 +1,9 @@
1
+ import type { UploadAdapter } from './upload-adapter.interface';
2
+ /**
3
+ * Used when no upload adapter is wired. Any sign request throws so the
4
+ * controller returns a clear 501 to the client instead of pretending to
5
+ * generate a URL that nobody can PUT to.
6
+ */
7
+ export declare class NoopUploadAdapter implements UploadAdapter {
8
+ signUpload(): Promise<never>;
9
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NoopUploadAdapter = void 0;
4
+ /**
5
+ * Used when no upload adapter is wired. Any sign request throws so the
6
+ * controller returns a clear 501 to the client instead of pretending to
7
+ * generate a URL that nobody can PUT to.
8
+ */
9
+ class NoopUploadAdapter {
10
+ async signUpload() {
11
+ throw new Error('Uploads are not configured. Pass an UploadAdapter (e.g. S3UploadAdapter) when creating AgentForge.');
12
+ }
13
+ }
14
+ exports.NoopUploadAdapter = NoopUploadAdapter;
@@ -0,0 +1,38 @@
1
+ import type { SignUploadInput, SignedUploadTarget, UploadAdapter } from './upload-adapter.interface';
2
+ export interface S3UploadAdapterOptions {
3
+ region: string;
4
+ bucket: string;
5
+ /** AWS access key id. Omit when running on an EC2/EKS instance with an IAM
6
+ * role — the SDK's default credential chain picks it up. */
7
+ accessKeyId?: string;
8
+ secretAccessKey?: string;
9
+ /**
10
+ * Public URL prefix the object will be reachable at. Required because we
11
+ * don't assume CloudFront vs raw S3 vs custom domain. The adapter
12
+ * concatenates `${publicUrlBase}/${key}` for `publicUrl`.
13
+ * Examples:
14
+ * "https://my-bucket.s3.us-east-1.amazonaws.com"
15
+ * "https://cdn.example.com"
16
+ */
17
+ publicUrlBase: string;
18
+ /** PUT URL TTL in seconds. Short by default so the upload window can't be
19
+ * reused by a leaked URL hours later. */
20
+ signedUrlTtlSeconds?: number;
21
+ }
22
+ /**
23
+ * S3 (or S3-compatible — R2, Spaces, MinIO) signed-upload adapter. Uses the
24
+ * official AWS SDK v3 so it talks to any provider that implements the S3 API.
25
+ *
26
+ * Read access model: the adapter assumes objects are world-readable once
27
+ * uploaded (`publicUrlBase` is GETtable). If your bucket is private and you
28
+ * need signed GETs at read-time too, fork this adapter — the interface is
29
+ * intentionally minimal.
30
+ */
31
+ export declare class S3UploadAdapter implements UploadAdapter {
32
+ private readonly client;
33
+ private readonly bucket;
34
+ private readonly publicUrlBase;
35
+ private readonly ttl;
36
+ constructor(opts: S3UploadAdapterOptions);
37
+ signUpload(input: SignUploadInput): Promise<SignedUploadTarget>;
38
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.S3UploadAdapter = void 0;
4
+ const client_s3_1 = require("@aws-sdk/client-s3");
5
+ const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
6
+ /**
7
+ * S3 (or S3-compatible — R2, Spaces, MinIO) signed-upload adapter. Uses the
8
+ * official AWS SDK v3 so it talks to any provider that implements the S3 API.
9
+ *
10
+ * Read access model: the adapter assumes objects are world-readable once
11
+ * uploaded (`publicUrlBase` is GETtable). If your bucket is private and you
12
+ * need signed GETs at read-time too, fork this adapter — the interface is
13
+ * intentionally minimal.
14
+ */
15
+ class S3UploadAdapter {
16
+ constructor(opts) {
17
+ if (!opts.bucket)
18
+ throw new Error('S3UploadAdapter: bucket is required');
19
+ if (!opts.region)
20
+ throw new Error('S3UploadAdapter: region is required');
21
+ if (!opts.publicUrlBase) {
22
+ throw new Error('S3UploadAdapter: publicUrlBase is required');
23
+ }
24
+ this.bucket = opts.bucket;
25
+ this.publicUrlBase = opts.publicUrlBase.replace(/\/+$/, '');
26
+ this.ttl = opts.signedUrlTtlSeconds ?? 300;
27
+ this.client = new client_s3_1.S3Client({
28
+ region: opts.region,
29
+ // Only override credentials when explicit keys were passed. Otherwise
30
+ // let the SDK fall through to its standard provider chain (env vars,
31
+ // shared credentials file, IAM role, etc.) — that's what production
32
+ // deployments on AWS expect.
33
+ ...(opts.accessKeyId && opts.secretAccessKey
34
+ ? {
35
+ credentials: {
36
+ accessKeyId: opts.accessKeyId,
37
+ secretAccessKey: opts.secretAccessKey,
38
+ },
39
+ }
40
+ : {}),
41
+ });
42
+ }
43
+ async signUpload(input) {
44
+ if (!input.key)
45
+ throw new Error('signUpload: key is required');
46
+ if (!input.contentType)
47
+ throw new Error('signUpload: contentType is required');
48
+ const cmd = new client_s3_1.PutObjectCommand({
49
+ Bucket: this.bucket,
50
+ Key: input.key,
51
+ ContentType: input.contentType,
52
+ // ContentLength can't be locked into a presigned URL on plain S3 — the
53
+ // SDK only includes signed headers, and the client controls the
54
+ // Content-Length header. Enforce size at the app layer (callers
55
+ // check the response Content-Length on a HEAD after upload, or trust
56
+ // the size they already validated client-side).
57
+ });
58
+ const uploadUrl = await (0, s3_request_presigner_1.getSignedUrl)(this.client, cmd, {
59
+ expiresIn: this.ttl,
60
+ });
61
+ return {
62
+ uploadUrl,
63
+ publicUrl: `${this.publicUrlBase}/${input.key}`,
64
+ key: input.key,
65
+ expiresInSeconds: this.ttl,
66
+ };
67
+ }
68
+ }
69
+ exports.S3UploadAdapter = S3UploadAdapter;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Provider-agnostic contract for object storage. The default adapter signs
3
+ * S3 PUTs; consumers running on R2, Backblaze B2, or Supabase Storage can
4
+ * write their own and pass it to `createAgentForge({ adapters: { upload } })`.
5
+ *
6
+ * Direct-upload flow (signed PUT) instead of streaming through our backend:
7
+ * 1. Client asks us for a signed URL.
8
+ * 2. We validate intent (MIME, size, scope), generate a key, sign the PUT.
9
+ * 3. Client uploads the bytes straight to the storage provider.
10
+ * 4. The persisted `publicUrl` is what other clients read later.
11
+ */
12
+ export interface SignedUploadTarget {
13
+ /** Pre-authorized URL the client PUTs the file body to. Short-lived. */
14
+ uploadUrl: string;
15
+ /** The eventual GETtable URL once the upload finishes. */
16
+ publicUrl: string;
17
+ /** Object key inside the bucket — useful when callers want to associate
18
+ * the upload with a domain entity for later cleanup. */
19
+ key: string;
20
+ /** Seconds until `uploadUrl` stops being honored by the provider. */
21
+ expiresInSeconds: number;
22
+ }
23
+ export interface SignUploadInput {
24
+ /** Object key path. Adapter is free to add randomness for collision safety. */
25
+ key: string;
26
+ /** Content-Type the client will declare on PUT. Adapters MUST require the
27
+ * same value at PUT time so a different MIME can't be smuggled in. */
28
+ contentType: string;
29
+ /** Max content-length the signed URL will accept. Soft hint to the adapter
30
+ * — providers that don't support content-length pre-sign should still
31
+ * return the URL and rely on app-level validation. */
32
+ maxSizeBytes?: number;
33
+ }
34
+ export interface UploadAdapter {
35
+ signUpload(input: SignUploadInput): Promise<SignedUploadTarget>;
36
+ }
37
+ export declare const UPLOAD_ADAPTER = "AGENTFORGE_UPLOAD_ADAPTER";
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ /**
3
+ * Provider-agnostic contract for object storage. The default adapter signs
4
+ * S3 PUTs; consumers running on R2, Backblaze B2, or Supabase Storage can
5
+ * write their own and pass it to `createAgentForge({ adapters: { upload } })`.
6
+ *
7
+ * Direct-upload flow (signed PUT) instead of streaming through our backend:
8
+ * 1. Client asks us for a signed URL.
9
+ * 2. We validate intent (MIME, size, scope), generate a key, sign the PUT.
10
+ * 3. Client uploads the bytes straight to the storage provider.
11
+ * 4. The persisted `publicUrl` is what other clients read later.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.UPLOAD_ADAPTER = void 0;
15
+ exports.UPLOAD_ADAPTER = 'AGENTFORGE_UPLOAD_ADAPTER';
@@ -0,0 +1,15 @@
1
+ export { AGENT_FORGE_CONFIG, AGENT_QUEUE_NAME, CURRENT_USER, } from '../constants';
2
+ export type { AgentDefinition, AnthropicConfig, McpServerConfig, AgentForgeConfig, DatabaseConfig, RedisConfig, QueueConfig, } from '../types/config.types';
3
+ export type { AgentResponse, AgentOverrides, StreamChunk, TokenUsage, ToolCallRecord, AgentToolDefinition, AgentJobPayload, AgentJobResult, AnthropicMessage, } from '../types/agent.types';
4
+ export type { SdkHooks, UsageEvent, TurnCompleteEvent, ToolCallEvent, } from '../types/hooks';
5
+ export { ToolRegistryService, type Logger } from '../services/tool-registry.service';
6
+ export { AgentRunnerService } from '../services/agent-runner.service';
7
+ export { OrchestratorService } from '../services/orchestrator.service';
8
+ export { PreparedStreamService, PreparedStreamError, } from '../services/prepared-stream.service';
9
+ export { ConversationService, ConversationNotFoundError } from '../services/conversation.service';
10
+ export { AgentService, AgentForbiddenError, type AgentNotFoundError, type AgentResolver, type AgentRecord, type AgentResolveParams, } from '../services/agent.service';
11
+ export { AgentJobWorker } from '../services/agent-job.worker';
12
+ export { PREPARED_STREAM_STORE, type PreparedStreamStore, type PreparedStreamPayload, } from '../adapters/prepared-stream/prepared-stream.types';
13
+ export { InMemoryPreparedStreamStore } from '../services/in-memory-prepared-stream.store';
14
+ export { JOB_QUEUE, type JobQueue, type JobStatus, type JobState, type JobContext, type JobProcessor, type EnqueueOptions, type QueueMetrics, } from '../adapters/job-queue/job-queue.types';
15
+ export { InMemoryJobQueue, type InMemoryJobQueueOptions, } from '../adapters/job-queue/in-memory';
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ // ─── @agentforge-io/core/ai — narrow surface for AI runtime code ─────────────
3
+ //
4
+ // This sub-path exposes ONLY the AI runtime slice (agent loop, orchestration,
5
+ // tools, conversations, streaming, hooks). Pair with `@agentforge-io/core/billing`
6
+ // for the commercial half. Code that imports from here should compile without
7
+ // ever loading Stripe, billing services, plan logic, etc.
8
+ //
9
+ // Files still co-located physically; this is a logical seam.
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.InMemoryJobQueue = exports.JOB_QUEUE = exports.InMemoryPreparedStreamStore = exports.PREPARED_STREAM_STORE = exports.AgentJobWorker = exports.AgentForbiddenError = exports.AgentService = exports.ConversationNotFoundError = exports.ConversationService = exports.PreparedStreamError = exports.PreparedStreamService = exports.OrchestratorService = exports.AgentRunnerService = exports.ToolRegistryService = exports.CURRENT_USER = exports.AGENT_QUEUE_NAME = exports.AGENT_FORGE_CONFIG = void 0;
12
+ // ─── Constants ─────────────────────────────────────────────────────────────
13
+ var constants_1 = require("../constants");
14
+ Object.defineProperty(exports, "AGENT_FORGE_CONFIG", { enumerable: true, get: function () { return constants_1.AGENT_FORGE_CONFIG; } });
15
+ Object.defineProperty(exports, "AGENT_QUEUE_NAME", { enumerable: true, get: function () { return constants_1.AGENT_QUEUE_NAME; } });
16
+ Object.defineProperty(exports, "CURRENT_USER", { enumerable: true, get: function () { return constants_1.CURRENT_USER; } });
17
+ // ─── Services ──────────────────────────────────────────────────────────────
18
+ var tool_registry_service_1 = require("../services/tool-registry.service");
19
+ Object.defineProperty(exports, "ToolRegistryService", { enumerable: true, get: function () { return tool_registry_service_1.ToolRegistryService; } });
20
+ var agent_runner_service_1 = require("../services/agent-runner.service");
21
+ Object.defineProperty(exports, "AgentRunnerService", { enumerable: true, get: function () { return agent_runner_service_1.AgentRunnerService; } });
22
+ var orchestrator_service_1 = require("../services/orchestrator.service");
23
+ Object.defineProperty(exports, "OrchestratorService", { enumerable: true, get: function () { return orchestrator_service_1.OrchestratorService; } });
24
+ var prepared_stream_service_1 = require("../services/prepared-stream.service");
25
+ Object.defineProperty(exports, "PreparedStreamService", { enumerable: true, get: function () { return prepared_stream_service_1.PreparedStreamService; } });
26
+ Object.defineProperty(exports, "PreparedStreamError", { enumerable: true, get: function () { return prepared_stream_service_1.PreparedStreamError; } });
27
+ var conversation_service_1 = require("../services/conversation.service");
28
+ Object.defineProperty(exports, "ConversationService", { enumerable: true, get: function () { return conversation_service_1.ConversationService; } });
29
+ Object.defineProperty(exports, "ConversationNotFoundError", { enumerable: true, get: function () { return conversation_service_1.ConversationNotFoundError; } });
30
+ var agent_service_1 = require("../services/agent.service");
31
+ Object.defineProperty(exports, "AgentService", { enumerable: true, get: function () { return agent_service_1.AgentService; } });
32
+ Object.defineProperty(exports, "AgentForbiddenError", { enumerable: true, get: function () { return agent_service_1.AgentForbiddenError; } });
33
+ var agent_job_worker_1 = require("../services/agent-job.worker");
34
+ Object.defineProperty(exports, "AgentJobWorker", { enumerable: true, get: function () { return agent_job_worker_1.AgentJobWorker; } });
35
+ // ─── Adapters used by the runtime ──────────────────────────────────────────
36
+ var prepared_stream_types_1 = require("../adapters/prepared-stream/prepared-stream.types");
37
+ Object.defineProperty(exports, "PREPARED_STREAM_STORE", { enumerable: true, get: function () { return prepared_stream_types_1.PREPARED_STREAM_STORE; } });
38
+ var in_memory_prepared_stream_store_1 = require("../services/in-memory-prepared-stream.store");
39
+ Object.defineProperty(exports, "InMemoryPreparedStreamStore", { enumerable: true, get: function () { return in_memory_prepared_stream_store_1.InMemoryPreparedStreamStore; } });
40
+ var job_queue_types_1 = require("../adapters/job-queue/job-queue.types");
41
+ Object.defineProperty(exports, "JOB_QUEUE", { enumerable: true, get: function () { return job_queue_types_1.JOB_QUEUE; } });
42
+ var in_memory_1 = require("../adapters/job-queue/in-memory");
43
+ Object.defineProperty(exports, "InMemoryJobQueue", { enumerable: true, get: function () { return in_memory_1.InMemoryJobQueue; } });
@@ -0,0 +1,12 @@
1
+ export type { Plan, NewPlan, PlanPatch, UsageLimits, } from '../domain/plan';
2
+ export type { Subscription, NewSubscription, SubscriptionPatch, } from '../domain/subscription';
3
+ export type { SubscriptionStatus, PaymentStatus, UserSubscription, UsageSummary, UsageRecord, CheckoutResult, PortalResult, BillingOverviewResult, InvoiceRecord, } from '../types/billing.types';
4
+ export type { BillingProvider, BillingModel, BillingConfig, StripeConfig, PlanDefinition, CreditsConfig, } from '../types/config.types';
5
+ export type { PlanRepository, SubscriptionRepository, UsageRecordRepository, } from '../repositories';
6
+ export type { IBillingAdapter } from '../adapters/billing/billing-adapter.interface';
7
+ export { BILLING_ADAPTER } from '../adapters/billing/billing-adapter.interface';
8
+ export { StripeAdapter } from '../adapters/billing/stripe/stripe.adapter';
9
+ export { UsageService, type UsageServiceOptions } from '../services/usage.service';
10
+ export { PlanService } from '../services/plan.service';
11
+ export { BillingService } from '../services/billing.service';
12
+ export { TenantBillingService } from '../services/tenant-billing.service';
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ // ─── @agentforge/core/billing — narrow surface for commercial code ─────────
3
+ //
4
+ // This sub-path exposes ONLY the billing/commercial slice of the core
5
+ // library. Consumers that don't want to pull in the full AI surface (and
6
+ // don't want their type-checker to suggest AI internals on autocomplete)
7
+ // can import from here.
8
+ //
9
+ // Architecturally the files still live alongside the AI code in
10
+ // `packages/core/src/`; this is a narrowed re-export, not a physical move.
11
+ // The goal is to make the seam visible and lintable today, and to make a
12
+ // later physical extraction (to `apps/server/modules/billing/`, or to a
13
+ // separate `@agentforge/billing` package) a localized change.
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.TenantBillingService = exports.BillingService = exports.PlanService = exports.UsageService = exports.StripeAdapter = exports.BILLING_ADAPTER = void 0;
16
+ var billing_adapter_interface_1 = require("../adapters/billing/billing-adapter.interface");
17
+ Object.defineProperty(exports, "BILLING_ADAPTER", { enumerable: true, get: function () { return billing_adapter_interface_1.BILLING_ADAPTER; } });
18
+ var stripe_adapter_1 = require("../adapters/billing/stripe/stripe.adapter");
19
+ Object.defineProperty(exports, "StripeAdapter", { enumerable: true, get: function () { return stripe_adapter_1.StripeAdapter; } });
20
+ // ─── Services ──────────────────────────────────────────────────────────────
21
+ var usage_service_1 = require("../services/usage.service");
22
+ Object.defineProperty(exports, "UsageService", { enumerable: true, get: function () { return usage_service_1.UsageService; } });
23
+ var plan_service_1 = require("../services/plan.service");
24
+ Object.defineProperty(exports, "PlanService", { enumerable: true, get: function () { return plan_service_1.PlanService; } });
25
+ var billing_service_1 = require("../services/billing.service");
26
+ Object.defineProperty(exports, "BillingService", { enumerable: true, get: function () { return billing_service_1.BillingService; } });
27
+ var tenant_billing_service_1 = require("../services/tenant-billing.service");
28
+ Object.defineProperty(exports, "TenantBillingService", { enumerable: true, get: function () { return tenant_billing_service_1.TenantBillingService; } });
@@ -0,0 +1,3 @@
1
+ export declare const AGENT_FORGE_CONFIG = "AGENT_FORGE_CONFIG";
2
+ export declare const AGENT_QUEUE_NAME = "agentforge:agent-jobs";
3
+ export declare const CURRENT_USER = "CURRENT_USER";
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CURRENT_USER = exports.AGENT_QUEUE_NAME = exports.AGENT_FORGE_CONFIG = void 0;
4
+ // Use string tokens (not Symbols) so they're compatible with NestJS string-based
5
+ // DI providers and survive cross-package boundaries without instance mismatch.
6
+ exports.AGENT_FORGE_CONFIG = 'AGENT_FORGE_CONFIG';
7
+ exports.AGENT_QUEUE_NAME = 'agentforge:agent-jobs';
8
+ exports.CURRENT_USER = 'CURRENT_USER';
@@ -0,0 +1,59 @@
1
+ import type { McpServerConfig } from '../types/config.types';
2
+ /**
3
+ * Visual customization shared by every embed of an agent — the public widget
4
+ * (`/widget.js`) and the iframe view both read this. Lives on the agent so a
5
+ * single edit ripples through every site that's embedded it; per-token
6
+ * theming is intentionally NOT supported (was a misfeature). All fields
7
+ * optional — widget falls back to its built-in defaults for anything omitted.
8
+ */
9
+ export interface AgentAppearance {
10
+ primaryColor?: string;
11
+ position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
12
+ title?: string;
13
+ greeting?: string;
14
+ avatarUrl?: string;
15
+ }
16
+ /**
17
+ * Persisted agent configuration scoped to a Tenant. Created and edited from
18
+ * the admin UI; resolved by the SDK at runtime via `(tenantId, slug)`.
19
+ *
20
+ * Shape is intentionally a superset of `AgentDefinition` (the in-process
21
+ * config object used today) plus DB metadata. The orchestrator/runner only
22
+ * needs the prompt/model/limits/tools — everything else here is for
23
+ * lifecycle: who created it, when, is it still active.
24
+ */
25
+ export interface AgentRecord {
26
+ id: string;
27
+ /** Owner tenant — every lookup is scoped to this. */
28
+ tenantId: string;
29
+ /** Human-friendly identifier the SDK uses, e.g. `support-bot`.
30
+ * Unique within a tenant, not globally. */
31
+ slug: string;
32
+ name: string;
33
+ description?: string;
34
+ /** Claude model id, e.g. `claude-sonnet-4-6`. */
35
+ model?: string;
36
+ systemPrompt: string;
37
+ /** Optional plain-text knowledge prepended to the system prompt at run-time.
38
+ * No retrieval — this is the cheap path before RAG. */
39
+ context?: string;
40
+ temperature?: number;
41
+ topP?: number;
42
+ maxTokens?: number;
43
+ /** Tool ids the agent can use. Persisted but not yet exposed in the UI. */
44
+ tools?: string[];
45
+ /** MCP servers the agent can connect to. Same caveat as `tools`. */
46
+ mcpServers?: McpServerConfig[];
47
+ /** Visual customization for embeds. Single source of truth — applies to
48
+ * every chat token issued for this agent. */
49
+ appearance?: AgentAppearance;
50
+ /** Soft-delete: keeps history intact while hiding from active use. */
51
+ isActive: boolean;
52
+ /** UserId of the platform user who created the agent (audit trail). */
53
+ createdByUserId?: string;
54
+ metadata?: Record<string, unknown>;
55
+ createdAt: Date;
56
+ updatedAt: Date;
57
+ }
58
+ export type NewAgentRecord = Pick<AgentRecord, 'id' | 'tenantId' | 'slug' | 'name' | 'systemPrompt'> & Partial<Omit<AgentRecord, 'id' | 'tenantId' | 'slug' | 'name' | 'systemPrompt' | 'createdAt' | 'updatedAt'>>;
59
+ export type AgentRecordPatch = Partial<Omit<AgentRecord, 'id' | 'tenantId' | 'createdAt' | 'updatedAt'>>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Long-lived secret a tenant uses to authenticate machine-to-machine. Format:
3
+ * ak_live_<48 hex chars> (192 bits of entropy)
4
+ *
5
+ * The full key is shown to the user ONLY at creation time. We store the
6
+ * sha256 hash. The first 16 chars (`ak_live_a1b2c3d4`) are kept in plaintext
7
+ * as a `keyPrefix` so users can identify which key in their dashboard.
8
+ *
9
+ * The `ak_live_` prefix is intentional — GitHub secret-scanning, Datadog and
10
+ * similar tools detect leaked credentials by prefix.
11
+ */
12
+ export interface ApiKey {
13
+ id: string;
14
+ tenantId: string;
15
+ /** When set, the key only authorizes calls to this specific agent. NULL
16
+ * means tenant-wide — any agent in the tenant resolves. */
17
+ agentId?: string;
18
+ name: string;
19
+ keyHash: string;
20
+ keyPrefix: string;
21
+ scopes?: string[];
22
+ expiresAt?: Date;
23
+ revokedAt?: Date;
24
+ lastUsedAt?: Date;
25
+ createdAt: Date;
26
+ }
27
+ export type NewApiKey = Omit<ApiKey, 'id' | 'createdAt' | 'lastUsedAt'>;
28
+ export type ApiKeyPatch = Partial<Pick<ApiKey, 'lastUsedAt' | 'revokedAt' | 'expiresAt' | 'name'>>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,10 @@
1
+ export interface AuthIdentity {
2
+ id: string;
3
+ userId: string;
4
+ provider: string;
5
+ providerId: string;
6
+ email?: string;
7
+ metadata?: Record<string, unknown>;
8
+ createdAt: Date;
9
+ }
10
+ export type NewAuthIdentity = Omit<AuthIdentity, 'id' | 'createdAt'>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });