@okrlinkhub/agent-factory 0.2.0 → 0.2.1

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.
@@ -1,5 +1,6 @@
1
1
  import { v } from "convex/values";
2
- import { mutation, query } from "./_generated/server.js";
2
+ import { internal } from "./_generated/api.js";
3
+ import { action, mutation, query } from "./_generated/server.js";
3
4
  import type { MutationCtx } from "./_generated/server.js";
4
5
 
5
6
  const bindingStatusValidator = v.union(v.literal("active"), v.literal("revoked"));
@@ -38,6 +39,17 @@ const pairingCodeViewValidator = v.object({
38
39
  telegramChatId: v.union(v.null(), v.string()),
39
40
  });
40
41
 
42
+ const telegramWebhookStatusValidator = v.object({
43
+ ok: v.boolean(),
44
+ webhookUrl: v.string(),
45
+ currentUrl: v.union(v.null(), v.string()),
46
+ isReady: v.boolean(),
47
+ pendingUpdateCount: v.number(),
48
+ lastErrorMessage: v.union(v.null(), v.string()),
49
+ lastErrorDate: v.union(v.null(), v.number()),
50
+ description: v.string(),
51
+ });
52
+
41
53
  type BindingSource = "manual" | "telegram_pairing" | "api";
42
54
 
43
55
  type UpsertBindingArgs = {
@@ -50,6 +62,106 @@ type UpsertBindingArgs = {
50
62
  nowMs?: number;
51
63
  };
52
64
 
65
+ export const configureTelegramWebhook = action({
66
+ args: {
67
+ convexSiteUrl: v.string(),
68
+ secretRef: v.optional(v.string()),
69
+ },
70
+ returns: telegramWebhookStatusValidator,
71
+ handler: async (ctx, args) => {
72
+ const secretRef = args.secretRef?.trim() || "telegram.botToken.default";
73
+ const token = await ctx.runQuery(internal.queue.getActiveSecretPlaintext, {
74
+ secretRef,
75
+ });
76
+ if (!token) {
77
+ throw new Error(
78
+ `Missing Telegram token. Import an active '${secretRef}' secret before pairing.`,
79
+ );
80
+ }
81
+
82
+ const rawSiteUrl = args.convexSiteUrl.trim();
83
+ if (!rawSiteUrl) {
84
+ throw new Error("convexSiteUrl is required.");
85
+ }
86
+
87
+ const normalizedSiteUrl = rawSiteUrl
88
+ .replace(/\/+$/, "")
89
+ .replace(/\.cloud$/i, ".site");
90
+ if (!normalizedSiteUrl.startsWith("https://")) {
91
+ throw new Error("convexSiteUrl must start with https://");
92
+ }
93
+
94
+ const webhookUrl = `${normalizedSiteUrl}/agent-factory/telegram/webhook`;
95
+ const telegramApiBaseUrl = `https://api.telegram.org/bot${encodeURIComponent(token)}`;
96
+
97
+ const setWebhookResponse = await fetch(`${telegramApiBaseUrl}/setWebhook`, {
98
+ method: "POST",
99
+ headers: {
100
+ "Content-Type": "application/json",
101
+ },
102
+ body: JSON.stringify({
103
+ url: webhookUrl,
104
+ }),
105
+ });
106
+
107
+ const setWebhookPayload = (await setWebhookResponse.json().catch(() => ({}))) as {
108
+ ok?: boolean;
109
+ description?: string;
110
+ };
111
+
112
+ if (!setWebhookResponse.ok || setWebhookPayload.ok !== true) {
113
+ const description =
114
+ typeof setWebhookPayload.description === "string"
115
+ ? setWebhookPayload.description
116
+ : "setWebhook failed";
117
+ throw new Error(`Telegram setWebhook failed: ${description}`);
118
+ }
119
+
120
+ const webhookInfoResponse = await fetch(`${telegramApiBaseUrl}/getWebhookInfo`);
121
+ const webhookInfoPayload = (await webhookInfoResponse.json().catch(() => ({}))) as {
122
+ ok?: boolean;
123
+ description?: string;
124
+ result?: {
125
+ url?: string;
126
+ pending_update_count?: number;
127
+ last_error_message?: string;
128
+ last_error_date?: number;
129
+ };
130
+ };
131
+
132
+ if (!webhookInfoResponse.ok || webhookInfoPayload.ok !== true) {
133
+ const description =
134
+ typeof webhookInfoPayload.description === "string"
135
+ ? webhookInfoPayload.description
136
+ : "getWebhookInfo failed";
137
+ throw new Error(`Telegram getWebhookInfo failed: ${description}`);
138
+ }
139
+
140
+ const currentUrl = typeof webhookInfoPayload.result?.url === "string"
141
+ ? webhookInfoPayload.result.url
142
+ : null;
143
+ const pendingUpdateCount = Number(webhookInfoPayload.result?.pending_update_count ?? 0);
144
+ const lastErrorMessage = typeof webhookInfoPayload.result?.last_error_message === "string"
145
+ ? webhookInfoPayload.result.last_error_message
146
+ : null;
147
+ const lastErrorDate = typeof webhookInfoPayload.result?.last_error_date === "number"
148
+ ? webhookInfoPayload.result.last_error_date
149
+ : null;
150
+ const isReady = currentUrl === webhookUrl;
151
+
152
+ return {
153
+ ok: true,
154
+ webhookUrl,
155
+ currentUrl,
156
+ isReady,
157
+ pendingUpdateCount,
158
+ lastErrorMessage,
159
+ lastErrorDate,
160
+ description: "Telegram webhook configured and verified.",
161
+ };
162
+ },
163
+ });
164
+
53
165
  export const createPairingCode = mutation({
54
166
  args: {
55
167
  consumerUserId: v.string(),
@@ -29,6 +29,7 @@ export {
29
29
  resolveAgentForUser,
30
30
  resolveAgentForTelegram,
31
31
  getUserAgentBinding,
32
+ configureTelegramWebhook,
32
33
  createPairingCode,
33
34
  consumePairingCode,
34
35
  getPairingCodeStatus,