@okrlinkhub/agent-bridge 0.1.0 → 2.0.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 (58) hide show
  1. package/README.md +96 -127
  2. package/dist/cli/init.d.ts +3 -0
  3. package/dist/cli/init.d.ts.map +1 -0
  4. package/dist/cli/init.js +100 -0
  5. package/dist/cli/init.js.map +1 -0
  6. package/dist/client/index.d.ts +50 -173
  7. package/dist/client/index.d.ts.map +1 -1
  8. package/dist/client/index.js +129 -263
  9. package/dist/client/index.js.map +1 -1
  10. package/dist/component/_generated/api.d.ts +4 -4
  11. package/dist/component/_generated/api.d.ts.map +1 -1
  12. package/dist/component/_generated/component.d.ts +66 -162
  13. package/dist/component/_generated/component.d.ts.map +1 -1
  14. package/dist/component/agentBridgeUtils.d.ts +8 -0
  15. package/dist/component/agentBridgeUtils.d.ts.map +1 -0
  16. package/dist/component/agentBridgeUtils.js +33 -0
  17. package/dist/component/agentBridgeUtils.js.map +1 -0
  18. package/dist/component/agents.d.ts +27 -0
  19. package/dist/component/agents.d.ts.map +1 -0
  20. package/dist/component/agents.js +94 -0
  21. package/dist/component/agents.js.map +1 -0
  22. package/dist/component/gateway.d.ts +30 -44
  23. package/dist/component/gateway.d.ts.map +1 -1
  24. package/dist/component/gateway.js +127 -132
  25. package/dist/component/gateway.js.map +1 -1
  26. package/dist/component/permissions.d.ts +30 -84
  27. package/dist/component/permissions.d.ts.map +1 -1
  28. package/dist/component/permissions.js +80 -203
  29. package/dist/component/permissions.js.map +1 -1
  30. package/dist/component/schema.d.ts +55 -153
  31. package/dist/component/schema.d.ts.map +1 -1
  32. package/dist/component/schema.js +30 -80
  33. package/dist/component/schema.js.map +1 -1
  34. package/dist/react/index.d.ts +2 -2
  35. package/dist/react/index.d.ts.map +1 -1
  36. package/dist/react/index.js +2 -3
  37. package/dist/react/index.js.map +1 -1
  38. package/package.json +7 -3
  39. package/src/cli/init.ts +116 -0
  40. package/src/client/index.ts +228 -389
  41. package/src/component/_generated/api.ts +4 -4
  42. package/src/component/_generated/component.ts +79 -195
  43. package/src/component/agentBridgeUtils.ts +52 -0
  44. package/src/component/agents.ts +106 -0
  45. package/src/component/gateway.ts +149 -163
  46. package/src/component/permissions.ts +89 -259
  47. package/src/component/schema.ts +31 -96
  48. package/src/react/index.ts +5 -6
  49. package/dist/component/provisioning.d.ts +0 -87
  50. package/dist/component/provisioning.d.ts.map +0 -1
  51. package/dist/component/provisioning.js +0 -343
  52. package/dist/component/provisioning.js.map +0 -1
  53. package/dist/component/registry.d.ts +0 -46
  54. package/dist/component/registry.d.ts.map +0 -1
  55. package/dist/component/registry.js +0 -121
  56. package/dist/component/registry.js.map +0 -1
  57. package/src/component/provisioning.ts +0 -402
  58. package/src/component/registry.ts +0 -152
@@ -8,10 +8,10 @@
8
8
  * @module
9
9
  */
10
10
 
11
+ import type * as agentBridgeUtils from "../agentBridgeUtils.js";
12
+ import type * as agents from "../agents.js";
11
13
  import type * as gateway from "../gateway.js";
12
14
  import type * as permissions from "../permissions.js";
13
- import type * as provisioning from "../provisioning.js";
14
- import type * as registry from "../registry.js";
15
15
 
16
16
  import type {
17
17
  ApiFromModules,
@@ -21,10 +21,10 @@ import type {
21
21
  import { anyApi, componentsGeneric } from "convex/server";
22
22
 
23
23
  const fullApi: ApiFromModules<{
24
+ agentBridgeUtils: typeof agentBridgeUtils;
25
+ agents: typeof agents;
24
26
  gateway: typeof gateway;
25
27
  permissions: typeof permissions;
26
- provisioning: typeof provisioning;
27
- registry: typeof registry;
28
28
  }> = anyApi as any;
29
29
 
30
30
  /**
@@ -23,258 +23,142 @@ import type { FunctionReference } from "convex/server";
23
23
  */
24
24
  export type ComponentApi<Name extends string | undefined = string | undefined> =
25
25
  {
26
- gateway: {
27
- authorizeRequest: FunctionReference<
28
- "mutation",
29
- "internal",
30
- { appName: string; functionName: string; instanceToken: string },
31
- | {
32
- agentId: string;
33
- appName: string;
34
- authorized: true;
35
- functionHandle: string;
36
- functionType: "query" | "mutation" | "action";
37
- }
38
- | {
39
- agentId?: string;
40
- authorized: false;
41
- error: string;
42
- matchedPattern?: string;
43
- matchedPermission?: "allow" | "deny" | "rate_limited";
44
- statusCode: number;
45
- },
46
- Name
47
- >;
48
- logAccess: FunctionReference<
49
- "mutation",
50
- "internal",
51
- {
52
- agentId: string;
53
- appName: string;
54
- durationMs?: number;
55
- errorMessage?: string;
56
- functionCalled: string;
57
- permission: string;
58
- },
59
- null,
60
- Name
61
- >;
62
- queryAccessLog: FunctionReference<
63
- "query",
64
- "internal",
65
- { agentId?: string; appName?: string; limit?: number },
66
- Array<{
67
- agentId: string;
68
- appName: string;
69
- durationMs?: number;
70
- errorMessage?: string;
71
- functionCalled: string;
72
- permission: string;
73
- timestamp: number;
74
- }>,
75
- Name
76
- >;
77
- };
78
- permissions: {
79
- checkPermission: FunctionReference<
80
- "query",
81
- "internal",
82
- { agentId: string; appName: string; functionName: string },
83
- {
84
- matchedPattern?: string;
85
- permission: "allow" | "deny" | "rate_limited";
86
- rateLimitConfig?: { requestsPerHour: number; tokenBudget: number };
87
- },
88
- Name
89
- >;
90
- clearPermissions: FunctionReference<
26
+ agents: {
27
+ createAgent: FunctionReference<
91
28
  "mutation",
92
29
  "internal",
93
- { agentId: string; appName: string },
94
- number,
30
+ { apiKey: string; enabled?: boolean; name: string; rateLimit?: number },
31
+ { agentId: string },
95
32
  Name
96
33
  >;
97
- debugMatchPermission: FunctionReference<
98
- "query",
99
- "internal",
100
- { agentId: string; appName: string; functionName: string },
101
- {
102
- bestMatch?: {
103
- functionPattern: string;
104
- permission: "allow" | "deny" | "rate_limited";
105
- specificity: number;
106
- };
107
- functionName: string;
108
- matches: Array<{
109
- functionPattern: string;
110
- permission: "allow" | "deny" | "rate_limited";
111
- specificity: number;
112
- }>;
113
- permissions: Array<{
114
- functionPattern: string;
115
- permission: "allow" | "deny" | "rate_limited";
116
- specificity: number;
117
- }>;
118
- },
119
- Name
120
- >;
121
- listPermissions: FunctionReference<
34
+ listAgents: FunctionReference<
122
35
  "query",
123
36
  "internal",
124
- { agentId: string; appName: string },
37
+ {},
125
38
  Array<{
39
+ _id: string;
126
40
  createdAt: number;
127
- createdBy: string;
128
- functionPattern: string;
129
- permission: "allow" | "deny" | "rate_limited";
130
- rateLimitConfig?: { requestsPerHour: number; tokenBudget: number };
41
+ enabled: boolean;
42
+ lastUsed?: number;
43
+ name: string;
44
+ rateLimit: number;
131
45
  }>,
132
46
  Name
133
47
  >;
134
- removePermission: FunctionReference<
48
+ rotateApiKey: FunctionReference<
135
49
  "mutation",
136
50
  "internal",
137
- { agentId: string; appName: string; functionPattern: string },
138
- boolean,
51
+ { agentId: string; newApiKey: string },
52
+ null,
139
53
  Name
140
54
  >;
141
- setPermission: FunctionReference<
55
+ updateAgent: FunctionReference<
142
56
  "mutation",
143
57
  "internal",
144
58
  {
145
59
  agentId: string;
146
- appName: string;
147
- createdBy: string;
148
- functionPattern: string;
149
- permission: "allow" | "deny" | "rate_limited";
150
- rateLimitConfig?: { requestsPerHour: number; tokenBudget: number };
60
+ enabled?: boolean;
61
+ name?: string;
62
+ rateLimit?: number;
151
63
  },
152
- string,
64
+ null,
153
65
  Name
154
66
  >;
155
67
  };
156
- provisioning: {
157
- configure: FunctionReference<
68
+ gateway: {
69
+ authorizeRequest: FunctionReference<
158
70
  "mutation",
159
71
  "internal",
160
- {
161
- appName: string;
162
- defaultPermissions: Array<{
163
- pattern: string;
164
- permission: "allow" | "deny" | "rate_limited";
165
- rateLimitConfig?: { requestsPerHour: number; tokenBudget: number };
166
- }>;
167
- },
168
- null,
72
+ { apiKey: string; estimatedCost?: number; functionKey: string },
73
+ | { agentId: string; authorized: true }
74
+ | {
75
+ agentId?: string;
76
+ authorized: false;
77
+ error: string;
78
+ retryAfterSeconds?: number;
79
+ statusCode: number;
80
+ },
169
81
  Name
170
82
  >;
171
- generateProvisioningToken: FunctionReference<
83
+ logAccess: FunctionReference<
172
84
  "mutation",
173
85
  "internal",
174
86
  {
175
- createdBy: string;
176
- department: string;
177
- employeeEmail: string;
178
- expiresInDays?: number;
179
- maxApps?: number;
87
+ agentId: string;
88
+ args: any;
89
+ duration: number;
90
+ error?: string;
91
+ functionKey: string;
92
+ result?: any;
93
+ timestamp: number;
180
94
  },
181
- { expiresAt: number; token: string },
95
+ null,
182
96
  Name
183
97
  >;
184
- listAgents: FunctionReference<
98
+ queryAccessLog: FunctionReference<
185
99
  "query",
186
100
  "internal",
187
- { activeOnly?: boolean },
101
+ { agentId?: string; functionKey?: string; limit?: number },
188
102
  Array<{
103
+ _id: string;
189
104
  agentId: string;
190
- department: string;
191
- employeeEmail: string;
192
- firstRegisteredAt: number;
193
- isActive: boolean;
194
- lastSeenAt: number;
195
- revokedAt?: number;
196
- revokedBy?: string;
105
+ args: any;
106
+ duration: number;
107
+ error?: string;
108
+ functionKey: string;
109
+ result?: any;
110
+ timestamp: number;
197
111
  }>,
198
112
  Name
199
113
  >;
200
- provisionAgent: FunctionReference<
201
- "mutation",
202
- "internal",
203
- { appName: string; provisioningToken: string },
204
- {
205
- agentId: string;
206
- appName: string;
207
- expiresAt: number;
208
- instanceToken: string;
209
- message: string;
210
- },
211
- Name
212
- >;
213
- refreshInstanceToken: FunctionReference<
214
- "mutation",
215
- "internal",
216
- { agentId: string; appName: string; currentTokenHash: string },
217
- { expiresAt: number; instanceToken: string },
218
- Name
219
- >;
220
- revokeAgent: FunctionReference<
221
- "mutation",
222
- "internal",
223
- { agentId: string; revokedBy: string },
224
- boolean,
225
- Name
226
- >;
227
- revokeAppInstance: FunctionReference<
228
- "mutation",
229
- "internal",
230
- { agentId: string; appName: string },
231
- boolean,
232
- Name
233
- >;
234
114
  };
235
- registry: {
236
- getHandle: FunctionReference<
115
+ permissions: {
116
+ listAgentPermissions: FunctionReference<
237
117
  "query",
238
118
  "internal",
239
- { appName: string; functionName: string },
240
- null | {
241
- description?: string;
242
- functionHandle: string;
243
- functionName: string;
244
- functionType: "query" | "mutation" | "action";
245
- },
119
+ { agentId: string },
120
+ Array<{
121
+ functionPattern: string;
122
+ permission: "allow" | "deny" | "rate_limited";
123
+ rateLimitConfig?: { requestsPerHour: number; tokenBudget?: number };
124
+ updatedAt: number;
125
+ }>,
246
126
  Name
247
127
  >;
248
- listFunctions: FunctionReference<
128
+ listFunctionOverrides: FunctionReference<
249
129
  "query",
250
130
  "internal",
251
- { appName: string },
252
- Array<{
253
- description?: string;
254
- functionName: string;
255
- functionType: "query" | "mutation" | "action";
256
- registeredAt: number;
257
- }>,
131
+ {},
132
+ Array<{ enabled: boolean; globalRateLimit?: number; key: string }>,
258
133
  Name
259
134
  >;
260
- register: FunctionReference<
135
+ setAgentPermissions: FunctionReference<
261
136
  "mutation",
262
137
  "internal",
263
138
  {
264
- appName: string;
265
- description?: string;
266
- functionHandle: string;
267
- functionName: string;
268
- functionType: "query" | "mutation" | "action";
139
+ agentId: string;
140
+ availableFunctionKeys: Array<string>;
141
+ rules: Array<{
142
+ pattern: string;
143
+ permission: "allow" | "deny" | "rate_limited";
144
+ rateLimitConfig?: { requestsPerHour: number; tokenBudget?: number };
145
+ }>;
269
146
  },
270
- string,
147
+ number,
271
148
  Name
272
149
  >;
273
- unregister: FunctionReference<
150
+ setFunctionOverrides: FunctionReference<
274
151
  "mutation",
275
152
  "internal",
276
- { appName: string; functionName: string },
277
- boolean,
153
+ {
154
+ availableFunctionKeys: Array<string>;
155
+ overrides: Array<{
156
+ enabled: boolean;
157
+ globalRateLimit?: number;
158
+ key: string;
159
+ }>;
160
+ },
161
+ number,
278
162
  Name
279
163
  >;
280
164
  };
@@ -0,0 +1,52 @@
1
+ import type { Doc } from "./_generated/dataModel.js";
2
+
3
+ export type PermissionType = "allow" | "deny" | "rate_limited";
4
+
5
+ export async function hashApiKey(apiKey: string): Promise<string> {
6
+ const encoder = new TextEncoder();
7
+ const data = encoder.encode(apiKey);
8
+ const hash = await crypto.subtle.digest("SHA-256", data);
9
+ return Array.from(new Uint8Array(hash))
10
+ .map((byte) => byte.toString(16).padStart(2, "0"))
11
+ .join("");
12
+ }
13
+
14
+ export function matchesPattern(functionKey: string, pattern: string): boolean {
15
+ if (pattern === "*") {
16
+ return true;
17
+ }
18
+
19
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
20
+ const regexPattern = "^" + escaped.replace(/\*/g, ".*") + "$";
21
+ return new RegExp(regexPattern).test(functionKey);
22
+ }
23
+
24
+ export function patternSpecificity(pattern: string): number {
25
+ const wildcardIndex = pattern.indexOf("*");
26
+ if (wildcardIndex === -1) {
27
+ return pattern.length;
28
+ }
29
+ return wildcardIndex;
30
+ }
31
+
32
+ export function findBestPermissionMatch(
33
+ functionKey: string,
34
+ permissions: Array<Doc<"agentPermissions">>,
35
+ ): Doc<"agentPermissions"> | null {
36
+ const matches = permissions
37
+ .filter((permission) => matchesPattern(functionKey, permission.functionPattern))
38
+ .sort(
39
+ (a, b) =>
40
+ patternSpecificity(b.functionPattern) - patternSpecificity(a.functionPattern),
41
+ );
42
+ return matches[0] ?? null;
43
+ }
44
+
45
+ export function patternMatchesAvailableFunctions(
46
+ pattern: string,
47
+ availableFunctionKeys: string[],
48
+ ): boolean {
49
+ return availableFunctionKeys.some((functionKey) =>
50
+ matchesPattern(functionKey, pattern),
51
+ );
52
+ }
@@ -0,0 +1,106 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query } from "./_generated/server.js";
3
+ import { hashApiKey } from "./agentBridgeUtils.js";
4
+
5
+ export const createAgent = mutation({
6
+ args: {
7
+ name: v.string(),
8
+ apiKey: v.string(),
9
+ enabled: v.optional(v.boolean()),
10
+ rateLimit: v.optional(v.number()),
11
+ },
12
+ returns: v.object({
13
+ agentId: v.id("agents"),
14
+ }),
15
+ handler: async (ctx, args) => {
16
+ const apiKeyHash = await hashApiKey(args.apiKey);
17
+ const existing = await ctx.db
18
+ .query("agents")
19
+ .withIndex("by_apiKeyHash", (q) => q.eq("apiKeyHash", apiKeyHash))
20
+ .unique();
21
+
22
+ if (existing) {
23
+ throw new Error("An agent with this API key already exists");
24
+ }
25
+
26
+ const agentId = await ctx.db.insert("agents", {
27
+ name: args.name,
28
+ apiKeyHash,
29
+ enabled: args.enabled ?? true,
30
+ rateLimit: args.rateLimit ?? 1000,
31
+ createdAt: Date.now(),
32
+ });
33
+
34
+ return { agentId };
35
+ },
36
+ });
37
+
38
+ export const rotateApiKey = mutation({
39
+ args: {
40
+ agentId: v.id("agents"),
41
+ newApiKey: v.string(),
42
+ },
43
+ returns: v.null(),
44
+ handler: async (ctx, args) => {
45
+ const agent = await ctx.db.get(args.agentId);
46
+ if (!agent) {
47
+ throw new Error("Agent not found");
48
+ }
49
+
50
+ const newApiKeyHash = await hashApiKey(args.newApiKey);
51
+ await ctx.db.patch(args.agentId, {
52
+ apiKeyHash: newApiKeyHash,
53
+ });
54
+
55
+ return null;
56
+ },
57
+ });
58
+
59
+ export const updateAgent = mutation({
60
+ args: {
61
+ agentId: v.id("agents"),
62
+ name: v.optional(v.string()),
63
+ enabled: v.optional(v.boolean()),
64
+ rateLimit: v.optional(v.number()),
65
+ },
66
+ returns: v.null(),
67
+ handler: async (ctx, args) => {
68
+ const agent = await ctx.db.get(args.agentId);
69
+ if (!agent) {
70
+ throw new Error("Agent not found");
71
+ }
72
+
73
+ await ctx.db.patch(args.agentId, {
74
+ name: args.name ?? agent.name,
75
+ enabled: args.enabled ?? agent.enabled,
76
+ rateLimit: args.rateLimit ?? agent.rateLimit,
77
+ });
78
+
79
+ return null;
80
+ },
81
+ });
82
+
83
+ export const listAgents = query({
84
+ args: {},
85
+ returns: v.array(
86
+ v.object({
87
+ _id: v.id("agents"),
88
+ name: v.string(),
89
+ enabled: v.boolean(),
90
+ rateLimit: v.number(),
91
+ lastUsed: v.optional(v.number()),
92
+ createdAt: v.number(),
93
+ }),
94
+ ),
95
+ handler: async (ctx) => {
96
+ const agents = await ctx.db.query("agents").collect();
97
+ return agents.map((agent) => ({
98
+ _id: agent._id,
99
+ name: agent.name,
100
+ enabled: agent.enabled,
101
+ rateLimit: agent.rateLimit,
102
+ lastUsed: agent.lastUsed,
103
+ createdAt: agent.createdAt,
104
+ }));
105
+ },
106
+ });