@opentabs-dev/opentabs-plugin-reddit 0.0.91 → 0.0.92
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/dist/adapter.iife.js +615 -614
- package/dist/adapter.iife.js.map +4 -4
- package/dist/tools.json +1 -1
- package/package.json +3 -3
package/dist/adapter.iife.js
CHANGED
|
@@ -6,471 +6,6 @@
|
|
|
6
6
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
// node_modules/@opentabs-dev/plugin-sdk/dist/errors.js
|
|
10
|
-
var ToolError = class _ToolError extends Error {
|
|
11
|
-
code;
|
|
12
|
-
/** Whether this error is retryable (defaults to false). */
|
|
13
|
-
retryable;
|
|
14
|
-
/** Suggested delay before retrying, in milliseconds. */
|
|
15
|
-
retryAfterMs;
|
|
16
|
-
/** Error category for structured error classification. */
|
|
17
|
-
category;
|
|
18
|
-
constructor(message, code, opts) {
|
|
19
|
-
super(message);
|
|
20
|
-
this.code = code;
|
|
21
|
-
this.name = "ToolError";
|
|
22
|
-
this.retryable = opts?.retryable ?? false;
|
|
23
|
-
this.retryAfterMs = opts?.retryAfterMs;
|
|
24
|
-
this.category = opts?.category;
|
|
25
|
-
}
|
|
26
|
-
/** Authentication or authorization error (not retryable). Accepts an optional domain-specific code. */
|
|
27
|
-
static auth(message, code) {
|
|
28
|
-
return new _ToolError(message, code ?? "AUTH_ERROR", { category: "auth", retryable: false });
|
|
29
|
-
}
|
|
30
|
-
/** Resource not found (not retryable). Accepts an optional domain-specific code. */
|
|
31
|
-
static notFound(message, code) {
|
|
32
|
-
return new _ToolError(message, code ?? "NOT_FOUND", { category: "not_found", retryable: false });
|
|
33
|
-
}
|
|
34
|
-
/** Rate limited (retryable). Accepts an optional retry delay in milliseconds and an optional domain-specific code. */
|
|
35
|
-
static rateLimited(message, retryAfterMs, code) {
|
|
36
|
-
return new _ToolError(message, code ?? "RATE_LIMITED", { category: "rate_limit", retryable: true, retryAfterMs });
|
|
37
|
-
}
|
|
38
|
-
/** Input validation error (not retryable). Accepts an optional domain-specific code. */
|
|
39
|
-
static validation(message, code) {
|
|
40
|
-
return new _ToolError(message, code ?? "VALIDATION_ERROR", { category: "validation", retryable: false });
|
|
41
|
-
}
|
|
42
|
-
/** Operation timed out (retryable). Accepts an optional domain-specific code. */
|
|
43
|
-
static timeout(message, code) {
|
|
44
|
-
return new _ToolError(message, code ?? "TIMEOUT", { category: "timeout", retryable: true });
|
|
45
|
-
}
|
|
46
|
-
/** Internal/unexpected error (not retryable). Accepts an optional domain-specific code. */
|
|
47
|
-
static internal(message, code) {
|
|
48
|
-
return new _ToolError(message, code ?? "INTERNAL_ERROR", { category: "internal", retryable: false });
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// node_modules/@opentabs-dev/plugin-sdk/dist/timing.js
|
|
53
|
-
var waitUntil = (predicate, opts) => {
|
|
54
|
-
const interval = opts?.interval ?? 200;
|
|
55
|
-
const timeout = opts?.timeout ?? 1e4;
|
|
56
|
-
const signal = opts?.signal;
|
|
57
|
-
const abortReason = () => signal?.reason instanceof Error ? signal.reason : new Error("waitUntil: aborted");
|
|
58
|
-
if (signal?.aborted)
|
|
59
|
-
return Promise.reject(abortReason());
|
|
60
|
-
return new Promise((resolve, reject) => {
|
|
61
|
-
let settled = false;
|
|
62
|
-
let poller;
|
|
63
|
-
let lastPredicateError;
|
|
64
|
-
const isSettled = () => settled;
|
|
65
|
-
const cleanup = () => {
|
|
66
|
-
settled = true;
|
|
67
|
-
clearTimeout(timer);
|
|
68
|
-
clearTimeout(poller);
|
|
69
|
-
signal?.removeEventListener("abort", onAbort);
|
|
70
|
-
};
|
|
71
|
-
const onAbort = () => {
|
|
72
|
-
if (isSettled())
|
|
73
|
-
return;
|
|
74
|
-
cleanup();
|
|
75
|
-
reject(abortReason());
|
|
76
|
-
};
|
|
77
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
78
|
-
const timer = setTimeout(() => {
|
|
79
|
-
if (isSettled())
|
|
80
|
-
return;
|
|
81
|
-
cleanup();
|
|
82
|
-
const errorContext = lastPredicateError instanceof Error ? `: predicate last threw \u2014 ${lastPredicateError.message}` : "";
|
|
83
|
-
reject(new Error(`waitUntil: timed out after ${timeout}ms waiting for predicate to return true${errorContext}`));
|
|
84
|
-
}, timeout);
|
|
85
|
-
const check2 = async () => {
|
|
86
|
-
if (isSettled())
|
|
87
|
-
return;
|
|
88
|
-
try {
|
|
89
|
-
const result = await predicate();
|
|
90
|
-
if (result) {
|
|
91
|
-
cleanup();
|
|
92
|
-
resolve();
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
} catch (err2) {
|
|
96
|
-
lastPredicateError = err2;
|
|
97
|
-
}
|
|
98
|
-
if (!isSettled()) {
|
|
99
|
-
poller = setTimeout(() => void check2(), interval);
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
void check2();
|
|
103
|
-
});
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
// node_modules/@opentabs-dev/plugin-sdk/dist/log.js
|
|
107
|
-
var MAX_DATA_LENGTH = 10;
|
|
108
|
-
var MAX_STRING_LENGTH = 4096;
|
|
109
|
-
var MAX_SERIALIZED_SIZE = 64 * 1024;
|
|
110
|
-
var safeSerializeArg = (value) => {
|
|
111
|
-
try {
|
|
112
|
-
if (value === null || value === void 0)
|
|
113
|
-
return value;
|
|
114
|
-
const type = typeof value;
|
|
115
|
-
if (type === "boolean" || type === "number")
|
|
116
|
-
return value;
|
|
117
|
-
if (type === "string") {
|
|
118
|
-
return value.length > MAX_STRING_LENGTH ? `${value.slice(0, MAX_STRING_LENGTH)}\u2026` : value;
|
|
119
|
-
}
|
|
120
|
-
if (type === "function")
|
|
121
|
-
return `[Function: ${value.name || "anonymous"}]`;
|
|
122
|
-
if (type === "symbol")
|
|
123
|
-
return `[Symbol: ${value.description ?? ""}]`;
|
|
124
|
-
if (type === "bigint")
|
|
125
|
-
return `[BigInt: ${value.toString()}]`;
|
|
126
|
-
if (typeof value.nodeType === "number" && typeof value.nodeName === "string") {
|
|
127
|
-
try {
|
|
128
|
-
const node = value;
|
|
129
|
-
let classStr = "";
|
|
130
|
-
if (typeof node.className === "string") {
|
|
131
|
-
classStr = node.className ? `.${node.className.split(" ")[0] ?? ""}` : "";
|
|
132
|
-
} else if (node.className !== null && typeof node.className === "object") {
|
|
133
|
-
const baseVal = node.className.baseVal;
|
|
134
|
-
if (typeof baseVal === "string") {
|
|
135
|
-
classStr = baseVal ? `.${baseVal.split(" ")[0] ?? ""}` : "";
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return `[${node.nodeName}${node.id ? `#${node.id}` : ""}${classStr}]`;
|
|
139
|
-
} catch {
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (value instanceof Error) {
|
|
143
|
-
return { name: value.name, message: value.message, stack: value.stack };
|
|
144
|
-
}
|
|
145
|
-
if (value instanceof WeakRef)
|
|
146
|
-
return "[WeakRef]";
|
|
147
|
-
if (value instanceof WeakMap)
|
|
148
|
-
return "[WeakMap]";
|
|
149
|
-
if (value instanceof WeakSet)
|
|
150
|
-
return "[WeakSet]";
|
|
151
|
-
if (value instanceof ArrayBuffer)
|
|
152
|
-
return "[ArrayBuffer]";
|
|
153
|
-
if (typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer)
|
|
154
|
-
return "[SharedArrayBuffer]";
|
|
155
|
-
try {
|
|
156
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
157
|
-
const json2 = JSON.stringify(value, (_key, v) => {
|
|
158
|
-
if (typeof v === "object" && v !== null) {
|
|
159
|
-
if (seen.has(v))
|
|
160
|
-
return "[Circular]";
|
|
161
|
-
seen.add(v);
|
|
162
|
-
}
|
|
163
|
-
if (typeof v === "function")
|
|
164
|
-
return `[Function: ${v.name || "anonymous"}]`;
|
|
165
|
-
if (typeof v === "bigint")
|
|
166
|
-
return `[BigInt: ${v.toString()}]`;
|
|
167
|
-
if (typeof v === "symbol")
|
|
168
|
-
return `[Symbol: ${v.description ?? ""}]`;
|
|
169
|
-
if (v instanceof WeakRef)
|
|
170
|
-
return "[WeakRef]";
|
|
171
|
-
if (v instanceof WeakMap)
|
|
172
|
-
return "[WeakMap]";
|
|
173
|
-
if (v instanceof WeakSet)
|
|
174
|
-
return "[WeakSet]";
|
|
175
|
-
if (v instanceof ArrayBuffer)
|
|
176
|
-
return "[ArrayBuffer]";
|
|
177
|
-
if (typeof SharedArrayBuffer !== "undefined" && v instanceof SharedArrayBuffer)
|
|
178
|
-
return "[SharedArrayBuffer]";
|
|
179
|
-
return v;
|
|
180
|
-
});
|
|
181
|
-
if (json2.length > MAX_SERIALIZED_SIZE) {
|
|
182
|
-
return `[Object truncated: ${json2.length} chars]`;
|
|
183
|
-
}
|
|
184
|
-
return JSON.parse(json2);
|
|
185
|
-
} catch {
|
|
186
|
-
return `[Unserializable: ${typeof value}]`;
|
|
187
|
-
}
|
|
188
|
-
} catch {
|
|
189
|
-
return `[Unserializable: ${typeof value}]`;
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
var safeSerialize = (args) => {
|
|
193
|
-
const capped = args.length > MAX_DATA_LENGTH ? args.slice(0, MAX_DATA_LENGTH) : args;
|
|
194
|
-
return capped.map(safeSerializeArg);
|
|
195
|
-
};
|
|
196
|
-
var CONSOLE_METHODS = {
|
|
197
|
-
debug: "debug",
|
|
198
|
-
info: "info",
|
|
199
|
-
warning: "warn",
|
|
200
|
-
error: "error"
|
|
201
|
-
};
|
|
202
|
-
var defaultTransport = (entry) => {
|
|
203
|
-
const method = CONSOLE_METHODS[entry.level];
|
|
204
|
-
console[method](`[sdk.log] ${entry.message}`, ...entry.data);
|
|
205
|
-
};
|
|
206
|
-
var activeTransport = defaultTransport;
|
|
207
|
-
var _setLogTransport = (transport) => {
|
|
208
|
-
const previous = activeTransport;
|
|
209
|
-
activeTransport = transport;
|
|
210
|
-
return () => {
|
|
211
|
-
if (activeTransport === transport)
|
|
212
|
-
activeTransport = previous;
|
|
213
|
-
};
|
|
214
|
-
};
|
|
215
|
-
var makeLogMethod = (level) => (message, ...args) => {
|
|
216
|
-
const entry = {
|
|
217
|
-
level,
|
|
218
|
-
message,
|
|
219
|
-
data: safeSerialize(args),
|
|
220
|
-
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
221
|
-
};
|
|
222
|
-
activeTransport(entry);
|
|
223
|
-
};
|
|
224
|
-
var log = Object.freeze({
|
|
225
|
-
debug: makeLogMethod("debug"),
|
|
226
|
-
info: makeLogMethod("info"),
|
|
227
|
-
warn: makeLogMethod("warning"),
|
|
228
|
-
error: makeLogMethod("error")
|
|
229
|
-
});
|
|
230
|
-
var ot = globalThis.__openTabs ?? {};
|
|
231
|
-
globalThis.__openTabs = ot;
|
|
232
|
-
ot._setLogTransport = _setLogTransport;
|
|
233
|
-
ot.log = log;
|
|
234
|
-
|
|
235
|
-
// node_modules/@opentabs-dev/plugin-sdk/dist/storage.js
|
|
236
|
-
var getCookie = (name) => {
|
|
237
|
-
try {
|
|
238
|
-
const prefix = `${name}=`;
|
|
239
|
-
const entries = document.cookie.split("; ");
|
|
240
|
-
for (const entry of entries) {
|
|
241
|
-
if (entry.startsWith(prefix)) {
|
|
242
|
-
try {
|
|
243
|
-
return decodeURIComponent(entry.slice(prefix.length));
|
|
244
|
-
} catch {
|
|
245
|
-
return entry.slice(prefix.length);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return null;
|
|
250
|
-
} catch {
|
|
251
|
-
return null;
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
// node_modules/@opentabs-dev/plugin-sdk/dist/index.js
|
|
256
|
-
var defineTool = (config2) => config2;
|
|
257
|
-
var OpenTabsPlugin = class {
|
|
258
|
-
/**
|
|
259
|
-
* Chrome match patterns for URLs that should NOT match this plugin.
|
|
260
|
-
* Tabs matching both urlPatterns and excludePatterns are excluded.
|
|
261
|
-
* Useful when a broad urlPattern overlaps with another plugin's domain.
|
|
262
|
-
* @see https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns
|
|
263
|
-
*/
|
|
264
|
-
excludePatterns;
|
|
265
|
-
/**
|
|
266
|
-
* URL to open when no matching tab exists and the user triggers an
|
|
267
|
-
* 'open tab' action from the side panel. Should be a concrete URL
|
|
268
|
-
* (e.g., 'https://github.com'), not a match pattern.
|
|
269
|
-
*/
|
|
270
|
-
homepage;
|
|
271
|
-
/** Typed configuration schema — declares settings that users provide via config.json or the side panel. */
|
|
272
|
-
configSchema;
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
// src/reddit-api.ts
|
|
276
|
-
var cachedModhash = null;
|
|
277
|
-
var cachedBearerToken = null;
|
|
278
|
-
var bearerTokenExpiry = 0;
|
|
279
|
-
var isAuthenticated = () => {
|
|
280
|
-
const app = document.querySelector("shreddit-app");
|
|
281
|
-
if (app?.getAttribute("user-logged-in") === "true") return true;
|
|
282
|
-
const userSpan = document.querySelector(".user a");
|
|
283
|
-
if (userSpan && !userSpan.textContent?.includes("login")) return true;
|
|
284
|
-
return false;
|
|
285
|
-
};
|
|
286
|
-
var waitForAuth = () => waitUntil(() => isAuthenticated(), { interval: 500, timeout: 3e3 }).then(
|
|
287
|
-
() => true,
|
|
288
|
-
() => false
|
|
289
|
-
);
|
|
290
|
-
var getModhash = async () => {
|
|
291
|
-
if (cachedModhash) return cachedModhash;
|
|
292
|
-
const response = await fetch("https://www.reddit.com/api/me.json", {
|
|
293
|
-
credentials: "include",
|
|
294
|
-
signal: AbortSignal.timeout(1e4)
|
|
295
|
-
});
|
|
296
|
-
if (!response.ok) {
|
|
297
|
-
throw ToolError.auth(`Failed to fetch modhash: HTTP ${response.status}`);
|
|
298
|
-
}
|
|
299
|
-
const data = await response.json();
|
|
300
|
-
const modhash = data.data?.modhash;
|
|
301
|
-
if (!modhash) {
|
|
302
|
-
throw ToolError.auth("No modhash found \u2014 user may not be logged in");
|
|
303
|
-
}
|
|
304
|
-
cachedModhash = modhash;
|
|
305
|
-
return modhash;
|
|
306
|
-
};
|
|
307
|
-
var getBearerToken = async () => {
|
|
308
|
-
if (cachedBearerToken && Date.now() < bearerTokenExpiry) return cachedBearerToken;
|
|
309
|
-
const csrfToken = getCookie("csrf_token") ?? "";
|
|
310
|
-
const response = await fetch("https://www.reddit.com/svc/shreddit/token", {
|
|
311
|
-
method: "POST",
|
|
312
|
-
headers: { "Content-Type": "application/json" },
|
|
313
|
-
body: JSON.stringify({ csrf_token: csrfToken }),
|
|
314
|
-
credentials: "include",
|
|
315
|
-
signal: AbortSignal.timeout(1e4)
|
|
316
|
-
});
|
|
317
|
-
if (!response.ok) {
|
|
318
|
-
throw ToolError.auth(`Failed to fetch bearer token: HTTP ${response.status}`);
|
|
319
|
-
}
|
|
320
|
-
const data = await response.json();
|
|
321
|
-
if (!data.token) {
|
|
322
|
-
throw ToolError.auth("No bearer token returned \u2014 user may not be logged in");
|
|
323
|
-
}
|
|
324
|
-
cachedBearerToken = data.token;
|
|
325
|
-
bearerTokenExpiry = data.expires ? new Date(data.expires).getTime() - 3e4 : Date.now() + 6e5;
|
|
326
|
-
return cachedBearerToken;
|
|
327
|
-
};
|
|
328
|
-
var redditGet = async (path, params = {}) => {
|
|
329
|
-
const url2 = new URL(path, "https://www.reddit.com");
|
|
330
|
-
for (const [key, value] of Object.entries(params)) {
|
|
331
|
-
if (value !== void 0 && value !== "") {
|
|
332
|
-
url2.searchParams.set(key, value);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
let response;
|
|
336
|
-
try {
|
|
337
|
-
response = await fetch(url2.toString(), {
|
|
338
|
-
credentials: "include",
|
|
339
|
-
signal: AbortSignal.timeout(3e4)
|
|
340
|
-
});
|
|
341
|
-
} catch (error51) {
|
|
342
|
-
if (error51 instanceof DOMException && error51.name === "TimeoutError") {
|
|
343
|
-
throw ToolError.timeout("Reddit API request timed out after 30000ms");
|
|
344
|
-
}
|
|
345
|
-
throw ToolError.internal(`Reddit API network error: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
346
|
-
}
|
|
347
|
-
if (response.status === 429) {
|
|
348
|
-
const reset = response.headers.get("x-ratelimit-reset");
|
|
349
|
-
const retryMs = reset ? Number.parseInt(reset, 10) * 1e3 : void 0;
|
|
350
|
-
throw ToolError.rateLimited("Reddit API rate limited (429)", retryMs);
|
|
351
|
-
}
|
|
352
|
-
if (!response.ok) {
|
|
353
|
-
const errorText = await response.text().catch(() => response.statusText);
|
|
354
|
-
if (response.status === 401 || response.status === 403) {
|
|
355
|
-
throw ToolError.auth(`Reddit API HTTP ${response.status}: ${errorText}`);
|
|
356
|
-
}
|
|
357
|
-
if (response.status === 404) {
|
|
358
|
-
throw ToolError.notFound(`Reddit API HTTP ${response.status}: ${errorText}`);
|
|
359
|
-
}
|
|
360
|
-
throw ToolError.internal(`Reddit API HTTP ${response.status}: ${errorText}`);
|
|
361
|
-
}
|
|
362
|
-
try {
|
|
363
|
-
return await response.json();
|
|
364
|
-
} catch {
|
|
365
|
-
throw ToolError.internal("Failed to parse Reddit API response");
|
|
366
|
-
}
|
|
367
|
-
};
|
|
368
|
-
var redditPost = async (path, body) => {
|
|
369
|
-
const modhash = await getModhash();
|
|
370
|
-
const form = new URLSearchParams();
|
|
371
|
-
for (const [key, value] of Object.entries(body)) {
|
|
372
|
-
if (value !== void 0 && value !== "") {
|
|
373
|
-
form.append(key, value);
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
form.append("uh", modhash);
|
|
377
|
-
form.append("api_type", "json");
|
|
378
|
-
let response;
|
|
379
|
-
try {
|
|
380
|
-
response = await fetch(`https://www.reddit.com${path}`, {
|
|
381
|
-
method: "POST",
|
|
382
|
-
headers: {
|
|
383
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
384
|
-
"X-Modhash": modhash
|
|
385
|
-
},
|
|
386
|
-
body: form.toString(),
|
|
387
|
-
credentials: "include",
|
|
388
|
-
signal: AbortSignal.timeout(3e4)
|
|
389
|
-
});
|
|
390
|
-
} catch (error51) {
|
|
391
|
-
if (error51 instanceof DOMException && error51.name === "TimeoutError") {
|
|
392
|
-
throw ToolError.timeout("Reddit API request timed out after 30000ms");
|
|
393
|
-
}
|
|
394
|
-
throw ToolError.internal(`Reddit API network error: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
395
|
-
}
|
|
396
|
-
if (response.status === 429) {
|
|
397
|
-
const reset = response.headers.get("x-ratelimit-reset");
|
|
398
|
-
const retryMs = reset ? Number.parseInt(reset, 10) * 1e3 : void 0;
|
|
399
|
-
throw ToolError.rateLimited("Reddit API rate limited (429)", retryMs);
|
|
400
|
-
}
|
|
401
|
-
if (!response.ok) {
|
|
402
|
-
const errorText = await response.text().catch(() => response.statusText);
|
|
403
|
-
if (response.status === 401 || response.status === 403) {
|
|
404
|
-
clearSessionCache();
|
|
405
|
-
throw ToolError.auth(`Reddit API HTTP ${response.status}: ${errorText}`);
|
|
406
|
-
}
|
|
407
|
-
if (response.status === 404) {
|
|
408
|
-
throw ToolError.notFound(`Reddit API HTTP ${response.status}: ${errorText}`);
|
|
409
|
-
}
|
|
410
|
-
throw ToolError.internal(`Reddit API HTTP ${response.status}: ${errorText}`);
|
|
411
|
-
}
|
|
412
|
-
try {
|
|
413
|
-
return await response.json();
|
|
414
|
-
} catch {
|
|
415
|
-
throw ToolError.internal("Failed to parse Reddit API response");
|
|
416
|
-
}
|
|
417
|
-
};
|
|
418
|
-
var redditOAuthPost = async (path, body) => {
|
|
419
|
-
const token = await getBearerToken();
|
|
420
|
-
const form = new URLSearchParams();
|
|
421
|
-
for (const [key, value] of Object.entries(body)) {
|
|
422
|
-
if (value !== void 0 && value !== "") {
|
|
423
|
-
form.append(key, value);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
form.append("api_type", "json");
|
|
427
|
-
let response;
|
|
428
|
-
try {
|
|
429
|
-
response = await fetch(`https://oauth.reddit.com${path}`, {
|
|
430
|
-
method: "POST",
|
|
431
|
-
headers: {
|
|
432
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
433
|
-
Authorization: `Bearer ${token}`
|
|
434
|
-
},
|
|
435
|
-
body: form.toString(),
|
|
436
|
-
signal: AbortSignal.timeout(3e4)
|
|
437
|
-
});
|
|
438
|
-
} catch (error51) {
|
|
439
|
-
if (error51 instanceof DOMException && error51.name === "TimeoutError") {
|
|
440
|
-
throw ToolError.timeout("Reddit OAuth API request timed out after 30000ms");
|
|
441
|
-
}
|
|
442
|
-
throw ToolError.internal(
|
|
443
|
-
`Reddit OAuth API network error: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
444
|
-
);
|
|
445
|
-
}
|
|
446
|
-
if (response.status === 429) {
|
|
447
|
-
const reset = response.headers.get("x-ratelimit-reset");
|
|
448
|
-
const retryMs = reset ? Number.parseInt(reset, 10) * 1e3 : void 0;
|
|
449
|
-
throw ToolError.rateLimited("Reddit API rate limited (429)", retryMs);
|
|
450
|
-
}
|
|
451
|
-
if (!response.ok) {
|
|
452
|
-
const errorText = await response.text().catch(() => response.statusText);
|
|
453
|
-
if (response.status === 401 || response.status === 403) {
|
|
454
|
-
clearSessionCache();
|
|
455
|
-
throw ToolError.auth(`Reddit OAuth API HTTP ${response.status}: ${errorText}`);
|
|
456
|
-
}
|
|
457
|
-
if (response.status === 404) {
|
|
458
|
-
throw ToolError.notFound(`Reddit OAuth API HTTP ${response.status}: ${errorText}`);
|
|
459
|
-
}
|
|
460
|
-
throw ToolError.internal(`Reddit OAuth API HTTP ${response.status}: ${errorText}`);
|
|
461
|
-
}
|
|
462
|
-
try {
|
|
463
|
-
return await response.json();
|
|
464
|
-
} catch {
|
|
465
|
-
throw ToolError.internal("Failed to parse Reddit OAuth API response");
|
|
466
|
-
}
|
|
467
|
-
};
|
|
468
|
-
var clearSessionCache = () => {
|
|
469
|
-
cachedModhash = null;
|
|
470
|
-
cachedBearerToken = null;
|
|
471
|
-
bearerTokenExpiry = 0;
|
|
472
|
-
};
|
|
473
|
-
|
|
474
9
|
// node_modules/zod/v4/classic/external.js
|
|
475
10
|
var external_exports = {};
|
|
476
11
|
__export(external_exports, {
|
|
@@ -14808,182 +14343,647 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14808
14343
|
}
|
|
14809
14344
|
zodSchema = result;
|
|
14810
14345
|
}
|
|
14811
|
-
break;
|
|
14346
|
+
break;
|
|
14347
|
+
}
|
|
14348
|
+
const objectSchema = z.object(shape);
|
|
14349
|
+
if (schema.additionalProperties === false) {
|
|
14350
|
+
zodSchema = objectSchema.strict();
|
|
14351
|
+
} else if (typeof schema.additionalProperties === "object") {
|
|
14352
|
+
zodSchema = objectSchema.catchall(convertSchema(schema.additionalProperties, ctx));
|
|
14353
|
+
} else {
|
|
14354
|
+
zodSchema = objectSchema.passthrough();
|
|
14355
|
+
}
|
|
14356
|
+
break;
|
|
14357
|
+
}
|
|
14358
|
+
case "array": {
|
|
14359
|
+
const prefixItems = schema.prefixItems;
|
|
14360
|
+
const items = schema.items;
|
|
14361
|
+
if (prefixItems && Array.isArray(prefixItems)) {
|
|
14362
|
+
const tupleItems = prefixItems.map((item) => convertSchema(item, ctx));
|
|
14363
|
+
const rest = items && typeof items === "object" && !Array.isArray(items) ? convertSchema(items, ctx) : void 0;
|
|
14364
|
+
if (rest) {
|
|
14365
|
+
zodSchema = z.tuple(tupleItems).rest(rest);
|
|
14366
|
+
} else {
|
|
14367
|
+
zodSchema = z.tuple(tupleItems);
|
|
14368
|
+
}
|
|
14369
|
+
if (typeof schema.minItems === "number") {
|
|
14370
|
+
zodSchema = zodSchema.check(z.minLength(schema.minItems));
|
|
14371
|
+
}
|
|
14372
|
+
if (typeof schema.maxItems === "number") {
|
|
14373
|
+
zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
|
|
14374
|
+
}
|
|
14375
|
+
} else if (Array.isArray(items)) {
|
|
14376
|
+
const tupleItems = items.map((item) => convertSchema(item, ctx));
|
|
14377
|
+
const rest = schema.additionalItems && typeof schema.additionalItems === "object" ? convertSchema(schema.additionalItems, ctx) : void 0;
|
|
14378
|
+
if (rest) {
|
|
14379
|
+
zodSchema = z.tuple(tupleItems).rest(rest);
|
|
14380
|
+
} else {
|
|
14381
|
+
zodSchema = z.tuple(tupleItems);
|
|
14382
|
+
}
|
|
14383
|
+
if (typeof schema.minItems === "number") {
|
|
14384
|
+
zodSchema = zodSchema.check(z.minLength(schema.minItems));
|
|
14385
|
+
}
|
|
14386
|
+
if (typeof schema.maxItems === "number") {
|
|
14387
|
+
zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
|
|
14388
|
+
}
|
|
14389
|
+
} else if (items !== void 0) {
|
|
14390
|
+
const element = convertSchema(items, ctx);
|
|
14391
|
+
let arraySchema = z.array(element);
|
|
14392
|
+
if (typeof schema.minItems === "number") {
|
|
14393
|
+
arraySchema = arraySchema.min(schema.minItems);
|
|
14394
|
+
}
|
|
14395
|
+
if (typeof schema.maxItems === "number") {
|
|
14396
|
+
arraySchema = arraySchema.max(schema.maxItems);
|
|
14397
|
+
}
|
|
14398
|
+
zodSchema = arraySchema;
|
|
14399
|
+
} else {
|
|
14400
|
+
zodSchema = z.array(z.any());
|
|
14401
|
+
}
|
|
14402
|
+
break;
|
|
14403
|
+
}
|
|
14404
|
+
default:
|
|
14405
|
+
throw new Error(`Unsupported type: ${type}`);
|
|
14406
|
+
}
|
|
14407
|
+
return zodSchema;
|
|
14408
|
+
}
|
|
14409
|
+
function convertSchema(schema, ctx) {
|
|
14410
|
+
if (typeof schema === "boolean") {
|
|
14411
|
+
return schema ? z.any() : z.never();
|
|
14412
|
+
}
|
|
14413
|
+
let baseSchema = convertBaseSchema(schema, ctx);
|
|
14414
|
+
const hasExplicitType = schema.type || schema.enum !== void 0 || schema.const !== void 0;
|
|
14415
|
+
if (schema.anyOf && Array.isArray(schema.anyOf)) {
|
|
14416
|
+
const options = schema.anyOf.map((s) => convertSchema(s, ctx));
|
|
14417
|
+
const anyOfUnion = z.union(options);
|
|
14418
|
+
baseSchema = hasExplicitType ? z.intersection(baseSchema, anyOfUnion) : anyOfUnion;
|
|
14419
|
+
}
|
|
14420
|
+
if (schema.oneOf && Array.isArray(schema.oneOf)) {
|
|
14421
|
+
const options = schema.oneOf.map((s) => convertSchema(s, ctx));
|
|
14422
|
+
const oneOfUnion = z.xor(options);
|
|
14423
|
+
baseSchema = hasExplicitType ? z.intersection(baseSchema, oneOfUnion) : oneOfUnion;
|
|
14424
|
+
}
|
|
14425
|
+
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
14426
|
+
if (schema.allOf.length === 0) {
|
|
14427
|
+
baseSchema = hasExplicitType ? baseSchema : z.any();
|
|
14428
|
+
} else {
|
|
14429
|
+
let result = hasExplicitType ? baseSchema : convertSchema(schema.allOf[0], ctx);
|
|
14430
|
+
const startIdx = hasExplicitType ? 0 : 1;
|
|
14431
|
+
for (let i = startIdx; i < schema.allOf.length; i++) {
|
|
14432
|
+
result = z.intersection(result, convertSchema(schema.allOf[i], ctx));
|
|
14433
|
+
}
|
|
14434
|
+
baseSchema = result;
|
|
14435
|
+
}
|
|
14436
|
+
}
|
|
14437
|
+
if (schema.nullable === true && ctx.version === "openapi-3.0") {
|
|
14438
|
+
baseSchema = z.nullable(baseSchema);
|
|
14439
|
+
}
|
|
14440
|
+
if (schema.readOnly === true) {
|
|
14441
|
+
baseSchema = z.readonly(baseSchema);
|
|
14442
|
+
}
|
|
14443
|
+
if (schema.default !== void 0) {
|
|
14444
|
+
baseSchema = baseSchema.default(schema.default);
|
|
14445
|
+
}
|
|
14446
|
+
const extraMeta = {};
|
|
14447
|
+
const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
|
|
14448
|
+
for (const key of coreMetadataKeys) {
|
|
14449
|
+
if (key in schema) {
|
|
14450
|
+
extraMeta[key] = schema[key];
|
|
14451
|
+
}
|
|
14452
|
+
}
|
|
14453
|
+
const contentMetadataKeys = ["contentEncoding", "contentMediaType", "contentSchema"];
|
|
14454
|
+
for (const key of contentMetadataKeys) {
|
|
14455
|
+
if (key in schema) {
|
|
14456
|
+
extraMeta[key] = schema[key];
|
|
14457
|
+
}
|
|
14458
|
+
}
|
|
14459
|
+
for (const key of Object.keys(schema)) {
|
|
14460
|
+
if (!RECOGNIZED_KEYS.has(key)) {
|
|
14461
|
+
extraMeta[key] = schema[key];
|
|
14462
|
+
}
|
|
14463
|
+
}
|
|
14464
|
+
if (Object.keys(extraMeta).length > 0) {
|
|
14465
|
+
ctx.registry.add(baseSchema, extraMeta);
|
|
14466
|
+
}
|
|
14467
|
+
if (schema.description) {
|
|
14468
|
+
baseSchema = baseSchema.describe(schema.description);
|
|
14469
|
+
}
|
|
14470
|
+
return baseSchema;
|
|
14471
|
+
}
|
|
14472
|
+
function fromJSONSchema(schema, params) {
|
|
14473
|
+
if (typeof schema === "boolean") {
|
|
14474
|
+
return schema ? z.any() : z.never();
|
|
14475
|
+
}
|
|
14476
|
+
let normalized;
|
|
14477
|
+
try {
|
|
14478
|
+
normalized = JSON.parse(JSON.stringify(schema));
|
|
14479
|
+
} catch {
|
|
14480
|
+
throw new Error("fromJSONSchema input is not valid JSON (possibly cyclic); use $defs/$ref for recursive schemas");
|
|
14481
|
+
}
|
|
14482
|
+
const version2 = detectVersion(normalized, params?.defaultTarget);
|
|
14483
|
+
const defs = normalized.$defs || normalized.definitions || {};
|
|
14484
|
+
const ctx = {
|
|
14485
|
+
version: version2,
|
|
14486
|
+
defs,
|
|
14487
|
+
refs: /* @__PURE__ */ new Map(),
|
|
14488
|
+
processing: /* @__PURE__ */ new Set(),
|
|
14489
|
+
rootSchema: normalized,
|
|
14490
|
+
registry: params?.registry ?? globalRegistry
|
|
14491
|
+
};
|
|
14492
|
+
return convertSchema(normalized, ctx);
|
|
14493
|
+
}
|
|
14494
|
+
|
|
14495
|
+
// node_modules/zod/v4/classic/coerce.js
|
|
14496
|
+
var coerce_exports = {};
|
|
14497
|
+
__export(coerce_exports, {
|
|
14498
|
+
bigint: () => bigint3,
|
|
14499
|
+
boolean: () => boolean3,
|
|
14500
|
+
date: () => date4,
|
|
14501
|
+
number: () => number3,
|
|
14502
|
+
string: () => string3
|
|
14503
|
+
});
|
|
14504
|
+
function string3(params) {
|
|
14505
|
+
return _coercedString(ZodString, params);
|
|
14506
|
+
}
|
|
14507
|
+
function number3(params) {
|
|
14508
|
+
return _coercedNumber(ZodNumber, params);
|
|
14509
|
+
}
|
|
14510
|
+
function boolean3(params) {
|
|
14511
|
+
return _coercedBoolean(ZodBoolean, params);
|
|
14512
|
+
}
|
|
14513
|
+
function bigint3(params) {
|
|
14514
|
+
return _coercedBigint(ZodBigInt, params);
|
|
14515
|
+
}
|
|
14516
|
+
function date4(params) {
|
|
14517
|
+
return _coercedDate(ZodDate, params);
|
|
14518
|
+
}
|
|
14519
|
+
|
|
14520
|
+
// node_modules/zod/v4/classic/external.js
|
|
14521
|
+
config(en_default());
|
|
14522
|
+
|
|
14523
|
+
// node_modules/@opentabs-dev/plugin-sdk/dist/errors.js
|
|
14524
|
+
var ToolError = class _ToolError extends Error {
|
|
14525
|
+
code;
|
|
14526
|
+
/** Whether this error is retryable (defaults to false). */
|
|
14527
|
+
retryable;
|
|
14528
|
+
/** Suggested delay before retrying, in milliseconds. */
|
|
14529
|
+
retryAfterMs;
|
|
14530
|
+
/** Error category for structured error classification. */
|
|
14531
|
+
category;
|
|
14532
|
+
constructor(message, code, opts) {
|
|
14533
|
+
super(message);
|
|
14534
|
+
this.code = code;
|
|
14535
|
+
this.name = "ToolError";
|
|
14536
|
+
this.retryable = opts?.retryable ?? false;
|
|
14537
|
+
this.retryAfterMs = opts?.retryAfterMs;
|
|
14538
|
+
this.category = opts?.category;
|
|
14539
|
+
}
|
|
14540
|
+
/** Authentication or authorization error (not retryable). Accepts an optional domain-specific code. */
|
|
14541
|
+
static auth(message, code) {
|
|
14542
|
+
return new _ToolError(message, code ?? "AUTH_ERROR", { category: "auth", retryable: false });
|
|
14543
|
+
}
|
|
14544
|
+
/** Resource not found (not retryable). Accepts an optional domain-specific code. */
|
|
14545
|
+
static notFound(message, code) {
|
|
14546
|
+
return new _ToolError(message, code ?? "NOT_FOUND", { category: "not_found", retryable: false });
|
|
14547
|
+
}
|
|
14548
|
+
/** Rate limited (retryable). Accepts an optional retry delay in milliseconds and an optional domain-specific code. */
|
|
14549
|
+
static rateLimited(message, retryAfterMs, code) {
|
|
14550
|
+
return new _ToolError(message, code ?? "RATE_LIMITED", { category: "rate_limit", retryable: true, retryAfterMs });
|
|
14551
|
+
}
|
|
14552
|
+
/** Input validation error (not retryable). Accepts an optional domain-specific code. */
|
|
14553
|
+
static validation(message, code) {
|
|
14554
|
+
return new _ToolError(message, code ?? "VALIDATION_ERROR", { category: "validation", retryable: false });
|
|
14555
|
+
}
|
|
14556
|
+
/** Operation timed out (retryable). Accepts an optional domain-specific code. */
|
|
14557
|
+
static timeout(message, code) {
|
|
14558
|
+
return new _ToolError(message, code ?? "TIMEOUT", { category: "timeout", retryable: true });
|
|
14559
|
+
}
|
|
14560
|
+
/** Internal/unexpected error (not retryable). Accepts an optional domain-specific code. */
|
|
14561
|
+
static internal(message, code) {
|
|
14562
|
+
return new _ToolError(message, code ?? "INTERNAL_ERROR", { category: "internal", retryable: false });
|
|
14563
|
+
}
|
|
14564
|
+
};
|
|
14565
|
+
|
|
14566
|
+
// node_modules/@opentabs-dev/plugin-sdk/dist/timing.js
|
|
14567
|
+
var waitUntil = (predicate, opts) => {
|
|
14568
|
+
const interval = opts?.interval ?? 200;
|
|
14569
|
+
const timeout = opts?.timeout ?? 1e4;
|
|
14570
|
+
const signal = opts?.signal;
|
|
14571
|
+
const abortReason = () => signal?.reason instanceof Error ? signal.reason : new Error("waitUntil: aborted");
|
|
14572
|
+
if (signal?.aborted)
|
|
14573
|
+
return Promise.reject(abortReason());
|
|
14574
|
+
return new Promise((resolve, reject) => {
|
|
14575
|
+
let settled = false;
|
|
14576
|
+
let poller;
|
|
14577
|
+
let lastPredicateError;
|
|
14578
|
+
const isSettled = () => settled;
|
|
14579
|
+
const cleanup = () => {
|
|
14580
|
+
settled = true;
|
|
14581
|
+
clearTimeout(timer);
|
|
14582
|
+
clearTimeout(poller);
|
|
14583
|
+
signal?.removeEventListener("abort", onAbort);
|
|
14584
|
+
};
|
|
14585
|
+
const onAbort = () => {
|
|
14586
|
+
if (isSettled())
|
|
14587
|
+
return;
|
|
14588
|
+
cleanup();
|
|
14589
|
+
reject(abortReason());
|
|
14590
|
+
};
|
|
14591
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
14592
|
+
const timer = setTimeout(() => {
|
|
14593
|
+
if (isSettled())
|
|
14594
|
+
return;
|
|
14595
|
+
cleanup();
|
|
14596
|
+
const errorContext = lastPredicateError instanceof Error ? `: predicate last threw \u2014 ${lastPredicateError.message}` : "";
|
|
14597
|
+
reject(new Error(`waitUntil: timed out after ${timeout}ms waiting for predicate to return true${errorContext}`));
|
|
14598
|
+
}, timeout);
|
|
14599
|
+
const check2 = async () => {
|
|
14600
|
+
if (isSettled())
|
|
14601
|
+
return;
|
|
14602
|
+
try {
|
|
14603
|
+
const result = await predicate();
|
|
14604
|
+
if (result) {
|
|
14605
|
+
cleanup();
|
|
14606
|
+
resolve();
|
|
14607
|
+
return;
|
|
14608
|
+
}
|
|
14609
|
+
} catch (err2) {
|
|
14610
|
+
lastPredicateError = err2;
|
|
14812
14611
|
}
|
|
14813
|
-
|
|
14814
|
-
|
|
14815
|
-
zodSchema = objectSchema.strict();
|
|
14816
|
-
} else if (typeof schema.additionalProperties === "object") {
|
|
14817
|
-
zodSchema = objectSchema.catchall(convertSchema(schema.additionalProperties, ctx));
|
|
14818
|
-
} else {
|
|
14819
|
-
zodSchema = objectSchema.passthrough();
|
|
14612
|
+
if (!isSettled()) {
|
|
14613
|
+
poller = setTimeout(() => void check2(), interval);
|
|
14820
14614
|
}
|
|
14821
|
-
|
|
14615
|
+
};
|
|
14616
|
+
void check2();
|
|
14617
|
+
});
|
|
14618
|
+
};
|
|
14619
|
+
|
|
14620
|
+
// node_modules/@opentabs-dev/plugin-sdk/dist/log.js
|
|
14621
|
+
var MAX_DATA_LENGTH = 10;
|
|
14622
|
+
var MAX_STRING_LENGTH = 4096;
|
|
14623
|
+
var MAX_SERIALIZED_SIZE = 64 * 1024;
|
|
14624
|
+
var safeSerializeArg = (value) => {
|
|
14625
|
+
try {
|
|
14626
|
+
if (value === null || value === void 0)
|
|
14627
|
+
return value;
|
|
14628
|
+
const type = typeof value;
|
|
14629
|
+
if (type === "boolean" || type === "number")
|
|
14630
|
+
return value;
|
|
14631
|
+
if (type === "string") {
|
|
14632
|
+
return value.length > MAX_STRING_LENGTH ? `${value.slice(0, MAX_STRING_LENGTH)}\u2026` : value;
|
|
14822
14633
|
}
|
|
14823
|
-
|
|
14824
|
-
|
|
14825
|
-
|
|
14826
|
-
|
|
14827
|
-
|
|
14828
|
-
|
|
14829
|
-
|
|
14830
|
-
|
|
14831
|
-
|
|
14832
|
-
|
|
14833
|
-
|
|
14834
|
-
|
|
14835
|
-
|
|
14836
|
-
|
|
14837
|
-
|
|
14838
|
-
|
|
14839
|
-
|
|
14840
|
-
} else if (Array.isArray(items)) {
|
|
14841
|
-
const tupleItems = items.map((item) => convertSchema(item, ctx));
|
|
14842
|
-
const rest = schema.additionalItems && typeof schema.additionalItems === "object" ? convertSchema(schema.additionalItems, ctx) : void 0;
|
|
14843
|
-
if (rest) {
|
|
14844
|
-
zodSchema = z.tuple(tupleItems).rest(rest);
|
|
14845
|
-
} else {
|
|
14846
|
-
zodSchema = z.tuple(tupleItems);
|
|
14847
|
-
}
|
|
14848
|
-
if (typeof schema.minItems === "number") {
|
|
14849
|
-
zodSchema = zodSchema.check(z.minLength(schema.minItems));
|
|
14850
|
-
}
|
|
14851
|
-
if (typeof schema.maxItems === "number") {
|
|
14852
|
-
zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
|
|
14634
|
+
if (type === "function")
|
|
14635
|
+
return `[Function: ${value.name || "anonymous"}]`;
|
|
14636
|
+
if (type === "symbol")
|
|
14637
|
+
return `[Symbol: ${value.description ?? ""}]`;
|
|
14638
|
+
if (type === "bigint")
|
|
14639
|
+
return `[BigInt: ${value.toString()}]`;
|
|
14640
|
+
if (typeof value.nodeType === "number" && typeof value.nodeName === "string") {
|
|
14641
|
+
try {
|
|
14642
|
+
const node = value;
|
|
14643
|
+
let classStr = "";
|
|
14644
|
+
if (typeof node.className === "string") {
|
|
14645
|
+
classStr = node.className ? `.${node.className.split(" ")[0] ?? ""}` : "";
|
|
14646
|
+
} else if (node.className !== null && typeof node.className === "object") {
|
|
14647
|
+
const baseVal = node.className.baseVal;
|
|
14648
|
+
if (typeof baseVal === "string") {
|
|
14649
|
+
classStr = baseVal ? `.${baseVal.split(" ")[0] ?? ""}` : "";
|
|
14650
|
+
}
|
|
14853
14651
|
}
|
|
14854
|
-
|
|
14855
|
-
|
|
14856
|
-
|
|
14857
|
-
|
|
14858
|
-
|
|
14652
|
+
return `[${node.nodeName}${node.id ? `#${node.id}` : ""}${classStr}]`;
|
|
14653
|
+
} catch {
|
|
14654
|
+
}
|
|
14655
|
+
}
|
|
14656
|
+
if (value instanceof Error) {
|
|
14657
|
+
return { name: value.name, message: value.message, stack: value.stack };
|
|
14658
|
+
}
|
|
14659
|
+
if (value instanceof WeakRef)
|
|
14660
|
+
return "[WeakRef]";
|
|
14661
|
+
if (value instanceof WeakMap)
|
|
14662
|
+
return "[WeakMap]";
|
|
14663
|
+
if (value instanceof WeakSet)
|
|
14664
|
+
return "[WeakSet]";
|
|
14665
|
+
if (value instanceof ArrayBuffer)
|
|
14666
|
+
return "[ArrayBuffer]";
|
|
14667
|
+
if (typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer)
|
|
14668
|
+
return "[SharedArrayBuffer]";
|
|
14669
|
+
try {
|
|
14670
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
14671
|
+
const json2 = JSON.stringify(value, (_key, v) => {
|
|
14672
|
+
if (typeof v === "object" && v !== null) {
|
|
14673
|
+
if (seen.has(v))
|
|
14674
|
+
return "[Circular]";
|
|
14675
|
+
seen.add(v);
|
|
14859
14676
|
}
|
|
14860
|
-
if (typeof
|
|
14861
|
-
|
|
14677
|
+
if (typeof v === "function")
|
|
14678
|
+
return `[Function: ${v.name || "anonymous"}]`;
|
|
14679
|
+
if (typeof v === "bigint")
|
|
14680
|
+
return `[BigInt: ${v.toString()}]`;
|
|
14681
|
+
if (typeof v === "symbol")
|
|
14682
|
+
return `[Symbol: ${v.description ?? ""}]`;
|
|
14683
|
+
if (v instanceof WeakRef)
|
|
14684
|
+
return "[WeakRef]";
|
|
14685
|
+
if (v instanceof WeakMap)
|
|
14686
|
+
return "[WeakMap]";
|
|
14687
|
+
if (v instanceof WeakSet)
|
|
14688
|
+
return "[WeakSet]";
|
|
14689
|
+
if (v instanceof ArrayBuffer)
|
|
14690
|
+
return "[ArrayBuffer]";
|
|
14691
|
+
if (typeof SharedArrayBuffer !== "undefined" && v instanceof SharedArrayBuffer)
|
|
14692
|
+
return "[SharedArrayBuffer]";
|
|
14693
|
+
return v;
|
|
14694
|
+
});
|
|
14695
|
+
if (json2.length > MAX_SERIALIZED_SIZE) {
|
|
14696
|
+
return `[Object truncated: ${json2.length} chars]`;
|
|
14697
|
+
}
|
|
14698
|
+
return JSON.parse(json2);
|
|
14699
|
+
} catch {
|
|
14700
|
+
return `[Unserializable: ${typeof value}]`;
|
|
14701
|
+
}
|
|
14702
|
+
} catch {
|
|
14703
|
+
return `[Unserializable: ${typeof value}]`;
|
|
14704
|
+
}
|
|
14705
|
+
};
|
|
14706
|
+
var safeSerialize = (args) => {
|
|
14707
|
+
const capped = args.length > MAX_DATA_LENGTH ? args.slice(0, MAX_DATA_LENGTH) : args;
|
|
14708
|
+
return capped.map(safeSerializeArg);
|
|
14709
|
+
};
|
|
14710
|
+
var CONSOLE_METHODS = {
|
|
14711
|
+
debug: "debug",
|
|
14712
|
+
info: "info",
|
|
14713
|
+
warning: "warn",
|
|
14714
|
+
error: "error"
|
|
14715
|
+
};
|
|
14716
|
+
var defaultTransport = (entry) => {
|
|
14717
|
+
const method = CONSOLE_METHODS[entry.level];
|
|
14718
|
+
console[method](`[sdk.log] ${entry.message}`, ...entry.data);
|
|
14719
|
+
};
|
|
14720
|
+
var activeTransport = defaultTransport;
|
|
14721
|
+
var _setLogTransport = (transport) => {
|
|
14722
|
+
const previous = activeTransport;
|
|
14723
|
+
activeTransport = transport;
|
|
14724
|
+
return () => {
|
|
14725
|
+
if (activeTransport === transport)
|
|
14726
|
+
activeTransport = previous;
|
|
14727
|
+
};
|
|
14728
|
+
};
|
|
14729
|
+
var makeLogMethod = (level) => (message, ...args) => {
|
|
14730
|
+
const entry = {
|
|
14731
|
+
level,
|
|
14732
|
+
message,
|
|
14733
|
+
data: safeSerialize(args),
|
|
14734
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
14735
|
+
};
|
|
14736
|
+
activeTransport(entry);
|
|
14737
|
+
};
|
|
14738
|
+
var log = Object.freeze({
|
|
14739
|
+
debug: makeLogMethod("debug"),
|
|
14740
|
+
info: makeLogMethod("info"),
|
|
14741
|
+
warn: makeLogMethod("warning"),
|
|
14742
|
+
error: makeLogMethod("error")
|
|
14743
|
+
});
|
|
14744
|
+
var ot = globalThis.__openTabs ?? {};
|
|
14745
|
+
globalThis.__openTabs = ot;
|
|
14746
|
+
ot._setLogTransport = _setLogTransport;
|
|
14747
|
+
ot.log = log;
|
|
14748
|
+
|
|
14749
|
+
// node_modules/@opentabs-dev/plugin-sdk/dist/storage.js
|
|
14750
|
+
var getCookie = (name) => {
|
|
14751
|
+
try {
|
|
14752
|
+
const prefix = `${name}=`;
|
|
14753
|
+
const entries = document.cookie.split("; ");
|
|
14754
|
+
for (const entry of entries) {
|
|
14755
|
+
if (entry.startsWith(prefix)) {
|
|
14756
|
+
try {
|
|
14757
|
+
return decodeURIComponent(entry.slice(prefix.length));
|
|
14758
|
+
} catch {
|
|
14759
|
+
return entry.slice(prefix.length);
|
|
14862
14760
|
}
|
|
14863
|
-
zodSchema = arraySchema;
|
|
14864
|
-
} else {
|
|
14865
|
-
zodSchema = z.array(z.any());
|
|
14866
14761
|
}
|
|
14867
|
-
break;
|
|
14868
14762
|
}
|
|
14869
|
-
|
|
14870
|
-
|
|
14763
|
+
return null;
|
|
14764
|
+
} catch {
|
|
14765
|
+
return null;
|
|
14766
|
+
}
|
|
14767
|
+
};
|
|
14768
|
+
|
|
14769
|
+
// node_modules/@opentabs-dev/plugin-sdk/dist/index.js
|
|
14770
|
+
var defineTool = (config2) => config2;
|
|
14771
|
+
var OpenTabsPlugin = class {
|
|
14772
|
+
/**
|
|
14773
|
+
* Chrome match patterns for URLs that should NOT match this plugin.
|
|
14774
|
+
* Tabs matching both urlPatterns and excludePatterns are excluded.
|
|
14775
|
+
* Useful when a broad urlPattern overlaps with another plugin's domain.
|
|
14776
|
+
* @see https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns
|
|
14777
|
+
*/
|
|
14778
|
+
excludePatterns;
|
|
14779
|
+
/**
|
|
14780
|
+
* URL to open when no matching tab exists and the user triggers an
|
|
14781
|
+
* 'open tab' action from the side panel. Should be a concrete URL
|
|
14782
|
+
* (e.g., 'https://github.com'), not a match pattern.
|
|
14783
|
+
*/
|
|
14784
|
+
homepage;
|
|
14785
|
+
/** Typed configuration schema — declares settings that users provide via config.json or the side panel. */
|
|
14786
|
+
configSchema;
|
|
14787
|
+
};
|
|
14788
|
+
|
|
14789
|
+
// src/reddit-api.ts
|
|
14790
|
+
var cachedModhash = null;
|
|
14791
|
+
var cachedBearerToken = null;
|
|
14792
|
+
var bearerTokenExpiry = 0;
|
|
14793
|
+
var isAuthenticated = () => {
|
|
14794
|
+
const app = document.querySelector("shreddit-app");
|
|
14795
|
+
if (app?.getAttribute("user-logged-in") === "true") return true;
|
|
14796
|
+
const userSpan = document.querySelector(".user a");
|
|
14797
|
+
if (userSpan && !userSpan.textContent?.includes("login")) return true;
|
|
14798
|
+
return false;
|
|
14799
|
+
};
|
|
14800
|
+
var waitForAuth = () => waitUntil(() => isAuthenticated(), { interval: 500, timeout: 3e3 }).then(
|
|
14801
|
+
() => true,
|
|
14802
|
+
() => false
|
|
14803
|
+
);
|
|
14804
|
+
var getModhash = async () => {
|
|
14805
|
+
if (cachedModhash) return cachedModhash;
|
|
14806
|
+
const response = await fetch("https://www.reddit.com/api/me.json", {
|
|
14807
|
+
credentials: "include",
|
|
14808
|
+
signal: AbortSignal.timeout(1e4)
|
|
14809
|
+
});
|
|
14810
|
+
if (!response.ok) {
|
|
14811
|
+
throw ToolError.auth(`Failed to fetch modhash: HTTP ${response.status}`);
|
|
14871
14812
|
}
|
|
14872
|
-
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14876
|
-
return schema ? z.any() : z.never();
|
|
14813
|
+
const data = await response.json();
|
|
14814
|
+
const modhash = data.data?.modhash;
|
|
14815
|
+
if (!modhash) {
|
|
14816
|
+
throw ToolError.auth("No modhash found \u2014 user may not be logged in");
|
|
14877
14817
|
}
|
|
14878
|
-
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
|
|
14882
|
-
|
|
14883
|
-
|
|
14818
|
+
cachedModhash = modhash;
|
|
14819
|
+
return modhash;
|
|
14820
|
+
};
|
|
14821
|
+
var getBearerToken = async () => {
|
|
14822
|
+
if (cachedBearerToken && Date.now() < bearerTokenExpiry) return cachedBearerToken;
|
|
14823
|
+
const csrfToken = getCookie("csrf_token") ?? "";
|
|
14824
|
+
const response = await fetch("https://www.reddit.com/svc/shreddit/token", {
|
|
14825
|
+
method: "POST",
|
|
14826
|
+
headers: { "Content-Type": "application/json" },
|
|
14827
|
+
body: JSON.stringify({ csrf_token: csrfToken }),
|
|
14828
|
+
credentials: "include",
|
|
14829
|
+
signal: AbortSignal.timeout(1e4)
|
|
14830
|
+
});
|
|
14831
|
+
if (!response.ok) {
|
|
14832
|
+
throw ToolError.auth(`Failed to fetch bearer token: HTTP ${response.status}`);
|
|
14884
14833
|
}
|
|
14885
|
-
|
|
14886
|
-
|
|
14887
|
-
|
|
14888
|
-
baseSchema = hasExplicitType ? z.intersection(baseSchema, oneOfUnion) : oneOfUnion;
|
|
14834
|
+
const data = await response.json();
|
|
14835
|
+
if (!data.token) {
|
|
14836
|
+
throw ToolError.auth("No bearer token returned \u2014 user may not be logged in");
|
|
14889
14837
|
}
|
|
14890
|
-
|
|
14891
|
-
|
|
14892
|
-
|
|
14893
|
-
|
|
14894
|
-
|
|
14895
|
-
|
|
14896
|
-
|
|
14897
|
-
|
|
14898
|
-
|
|
14899
|
-
baseSchema = result;
|
|
14838
|
+
cachedBearerToken = data.token;
|
|
14839
|
+
bearerTokenExpiry = data.expires ? new Date(data.expires).getTime() - 3e4 : Date.now() + 6e5;
|
|
14840
|
+
return cachedBearerToken;
|
|
14841
|
+
};
|
|
14842
|
+
var redditGet = async (path, params = {}) => {
|
|
14843
|
+
const url2 = new URL(path, "https://www.reddit.com");
|
|
14844
|
+
for (const [key, value] of Object.entries(params)) {
|
|
14845
|
+
if (value !== void 0 && value !== "") {
|
|
14846
|
+
url2.searchParams.set(key, value);
|
|
14900
14847
|
}
|
|
14901
14848
|
}
|
|
14902
|
-
|
|
14903
|
-
|
|
14849
|
+
let response;
|
|
14850
|
+
try {
|
|
14851
|
+
response = await fetch(url2.toString(), {
|
|
14852
|
+
credentials: "include",
|
|
14853
|
+
signal: AbortSignal.timeout(3e4)
|
|
14854
|
+
});
|
|
14855
|
+
} catch (error51) {
|
|
14856
|
+
if (error51 instanceof DOMException && error51.name === "TimeoutError") {
|
|
14857
|
+
throw ToolError.timeout("Reddit API request timed out after 30000ms");
|
|
14858
|
+
}
|
|
14859
|
+
throw ToolError.internal(`Reddit API network error: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
14904
14860
|
}
|
|
14905
|
-
if (
|
|
14906
|
-
|
|
14861
|
+
if (response.status === 429) {
|
|
14862
|
+
const reset = response.headers.get("x-ratelimit-reset");
|
|
14863
|
+
const retryMs = reset ? Number.parseInt(reset, 10) * 1e3 : void 0;
|
|
14864
|
+
throw ToolError.rateLimited("Reddit API rate limited (429)", retryMs);
|
|
14907
14865
|
}
|
|
14908
|
-
if (
|
|
14909
|
-
|
|
14866
|
+
if (!response.ok) {
|
|
14867
|
+
const errorText = await response.text().catch(() => response.statusText);
|
|
14868
|
+
if (response.status === 401 || response.status === 403) {
|
|
14869
|
+
throw ToolError.auth(`Reddit API HTTP ${response.status}: ${errorText}`);
|
|
14870
|
+
}
|
|
14871
|
+
if (response.status === 404) {
|
|
14872
|
+
throw ToolError.notFound(`Reddit API HTTP ${response.status}: ${errorText}`);
|
|
14873
|
+
}
|
|
14874
|
+
throw ToolError.internal(`Reddit API HTTP ${response.status}: ${errorText}`);
|
|
14910
14875
|
}
|
|
14911
|
-
|
|
14912
|
-
|
|
14913
|
-
|
|
14914
|
-
|
|
14915
|
-
|
|
14876
|
+
try {
|
|
14877
|
+
return await response.json();
|
|
14878
|
+
} catch {
|
|
14879
|
+
throw ToolError.internal("Failed to parse Reddit API response");
|
|
14880
|
+
}
|
|
14881
|
+
};
|
|
14882
|
+
var redditPost = async (path, body) => {
|
|
14883
|
+
const modhash = await getModhash();
|
|
14884
|
+
const form = new URLSearchParams();
|
|
14885
|
+
for (const [key, value] of Object.entries(body)) {
|
|
14886
|
+
if (value !== void 0 && value !== "") {
|
|
14887
|
+
form.append(key, value);
|
|
14916
14888
|
}
|
|
14917
14889
|
}
|
|
14918
|
-
|
|
14919
|
-
|
|
14920
|
-
|
|
14921
|
-
|
|
14890
|
+
form.append("uh", modhash);
|
|
14891
|
+
form.append("api_type", "json");
|
|
14892
|
+
let response;
|
|
14893
|
+
try {
|
|
14894
|
+
response = await fetch(`https://www.reddit.com${path}`, {
|
|
14895
|
+
method: "POST",
|
|
14896
|
+
headers: {
|
|
14897
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
14898
|
+
"X-Modhash": modhash
|
|
14899
|
+
},
|
|
14900
|
+
body: form.toString(),
|
|
14901
|
+
credentials: "include",
|
|
14902
|
+
signal: AbortSignal.timeout(3e4)
|
|
14903
|
+
});
|
|
14904
|
+
} catch (error51) {
|
|
14905
|
+
if (error51 instanceof DOMException && error51.name === "TimeoutError") {
|
|
14906
|
+
throw ToolError.timeout("Reddit API request timed out after 30000ms");
|
|
14922
14907
|
}
|
|
14908
|
+
throw ToolError.internal(`Reddit API network error: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
14923
14909
|
}
|
|
14924
|
-
|
|
14925
|
-
|
|
14926
|
-
|
|
14910
|
+
if (response.status === 429) {
|
|
14911
|
+
const reset = response.headers.get("x-ratelimit-reset");
|
|
14912
|
+
const retryMs = reset ? Number.parseInt(reset, 10) * 1e3 : void 0;
|
|
14913
|
+
throw ToolError.rateLimited("Reddit API rate limited (429)", retryMs);
|
|
14914
|
+
}
|
|
14915
|
+
if (!response.ok) {
|
|
14916
|
+
const errorText = await response.text().catch(() => response.statusText);
|
|
14917
|
+
if (response.status === 401 || response.status === 403) {
|
|
14918
|
+
clearSessionCache();
|
|
14919
|
+
throw ToolError.auth(`Reddit API HTTP ${response.status}: ${errorText}`);
|
|
14920
|
+
}
|
|
14921
|
+
if (response.status === 404) {
|
|
14922
|
+
throw ToolError.notFound(`Reddit API HTTP ${response.status}: ${errorText}`);
|
|
14927
14923
|
}
|
|
14924
|
+
throw ToolError.internal(`Reddit API HTTP ${response.status}: ${errorText}`);
|
|
14928
14925
|
}
|
|
14929
|
-
|
|
14930
|
-
|
|
14926
|
+
try {
|
|
14927
|
+
return await response.json();
|
|
14928
|
+
} catch {
|
|
14929
|
+
throw ToolError.internal("Failed to parse Reddit API response");
|
|
14931
14930
|
}
|
|
14932
|
-
|
|
14933
|
-
|
|
14931
|
+
};
|
|
14932
|
+
var redditOAuthPost = async (path, body) => {
|
|
14933
|
+
const token = await getBearerToken();
|
|
14934
|
+
const form = new URLSearchParams();
|
|
14935
|
+
for (const [key, value] of Object.entries(body)) {
|
|
14936
|
+
if (value !== void 0 && value !== "") {
|
|
14937
|
+
form.append(key, value);
|
|
14938
|
+
}
|
|
14934
14939
|
}
|
|
14935
|
-
|
|
14936
|
-
|
|
14937
|
-
|
|
14938
|
-
|
|
14939
|
-
|
|
14940
|
+
form.append("api_type", "json");
|
|
14941
|
+
let response;
|
|
14942
|
+
try {
|
|
14943
|
+
response = await fetch(`https://oauth.reddit.com${path}`, {
|
|
14944
|
+
method: "POST",
|
|
14945
|
+
headers: {
|
|
14946
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
14947
|
+
Authorization: `Bearer ${token}`
|
|
14948
|
+
},
|
|
14949
|
+
body: form.toString(),
|
|
14950
|
+
signal: AbortSignal.timeout(3e4)
|
|
14951
|
+
});
|
|
14952
|
+
} catch (error51) {
|
|
14953
|
+
if (error51 instanceof DOMException && error51.name === "TimeoutError") {
|
|
14954
|
+
throw ToolError.timeout("Reddit OAuth API request timed out after 30000ms");
|
|
14955
|
+
}
|
|
14956
|
+
throw ToolError.internal(
|
|
14957
|
+
`Reddit OAuth API network error: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
14958
|
+
);
|
|
14959
|
+
}
|
|
14960
|
+
if (response.status === 429) {
|
|
14961
|
+
const reset = response.headers.get("x-ratelimit-reset");
|
|
14962
|
+
const retryMs = reset ? Number.parseInt(reset, 10) * 1e3 : void 0;
|
|
14963
|
+
throw ToolError.rateLimited("Reddit API rate limited (429)", retryMs);
|
|
14964
|
+
}
|
|
14965
|
+
if (!response.ok) {
|
|
14966
|
+
const errorText = await response.text().catch(() => response.statusText);
|
|
14967
|
+
if (response.status === 401 || response.status === 403) {
|
|
14968
|
+
clearSessionCache();
|
|
14969
|
+
throw ToolError.auth(`Reddit OAuth API HTTP ${response.status}: ${errorText}`);
|
|
14970
|
+
}
|
|
14971
|
+
if (response.status === 404) {
|
|
14972
|
+
throw ToolError.notFound(`Reddit OAuth API HTTP ${response.status}: ${errorText}`);
|
|
14973
|
+
}
|
|
14974
|
+
throw ToolError.internal(`Reddit OAuth API HTTP ${response.status}: ${errorText}`);
|
|
14940
14975
|
}
|
|
14941
|
-
let normalized;
|
|
14942
14976
|
try {
|
|
14943
|
-
|
|
14977
|
+
return await response.json();
|
|
14944
14978
|
} catch {
|
|
14945
|
-
throw
|
|
14979
|
+
throw ToolError.internal("Failed to parse Reddit OAuth API response");
|
|
14946
14980
|
}
|
|
14947
|
-
|
|
14948
|
-
|
|
14949
|
-
|
|
14950
|
-
|
|
14951
|
-
|
|
14952
|
-
|
|
14953
|
-
processing: /* @__PURE__ */ new Set(),
|
|
14954
|
-
rootSchema: normalized,
|
|
14955
|
-
registry: params?.registry ?? globalRegistry
|
|
14956
|
-
};
|
|
14957
|
-
return convertSchema(normalized, ctx);
|
|
14958
|
-
}
|
|
14959
|
-
|
|
14960
|
-
// node_modules/zod/v4/classic/coerce.js
|
|
14961
|
-
var coerce_exports = {};
|
|
14962
|
-
__export(coerce_exports, {
|
|
14963
|
-
bigint: () => bigint3,
|
|
14964
|
-
boolean: () => boolean3,
|
|
14965
|
-
date: () => date4,
|
|
14966
|
-
number: () => number3,
|
|
14967
|
-
string: () => string3
|
|
14968
|
-
});
|
|
14969
|
-
function string3(params) {
|
|
14970
|
-
return _coercedString(ZodString, params);
|
|
14971
|
-
}
|
|
14972
|
-
function number3(params) {
|
|
14973
|
-
return _coercedNumber(ZodNumber, params);
|
|
14974
|
-
}
|
|
14975
|
-
function boolean3(params) {
|
|
14976
|
-
return _coercedBoolean(ZodBoolean, params);
|
|
14977
|
-
}
|
|
14978
|
-
function bigint3(params) {
|
|
14979
|
-
return _coercedBigint(ZodBigInt, params);
|
|
14980
|
-
}
|
|
14981
|
-
function date4(params) {
|
|
14982
|
-
return _coercedDate(ZodDate, params);
|
|
14983
|
-
}
|
|
14984
|
-
|
|
14985
|
-
// node_modules/zod/v4/classic/external.js
|
|
14986
|
-
config(en_default());
|
|
14981
|
+
};
|
|
14982
|
+
var clearSessionCache = () => {
|
|
14983
|
+
cachedModhash = null;
|
|
14984
|
+
cachedBearerToken = null;
|
|
14985
|
+
bearerTokenExpiry = 0;
|
|
14986
|
+
};
|
|
14987
14987
|
|
|
14988
14988
|
// src/tools/delete-thing.ts
|
|
14989
14989
|
var deleteThing = defineTool({
|
|
@@ -16072,7 +16072,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16072
16072
|
};
|
|
16073
16073
|
var src_default = new RedditPlugin();
|
|
16074
16074
|
|
|
16075
|
-
// dist/
|
|
16075
|
+
// dist/_adapter_entry_2c57f29f-957f-462f-831d-4d3b45059e26.ts
|
|
16076
|
+
external_exports.config({ jitless: true });
|
|
16076
16077
|
if (!globalThis.__openTabs) {
|
|
16077
16078
|
globalThis.__openTabs = {};
|
|
16078
16079
|
} else {
|
|
@@ -16290,5 +16291,5 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16290
16291
|
};
|
|
16291
16292
|
delete src_default.onDeactivate;
|
|
16292
16293
|
}
|
|
16293
|
-
})();(function(){var o=(globalThis).__openTabs;if(o&&o.adapters&&o.adapters["reddit"]){var a=o.adapters["reddit"];a.__adapterHash="
|
|
16294
|
+
})();(function(){var o=(globalThis).__openTabs;if(o&&o.adapters&&o.adapters["reddit"]){var a=o.adapters["reddit"];a.__adapterHash="75aee871441754aa9ea13afff829ae13ab2b0422dda24fba9acf9e6885cabdc9";if(a.tools&&Array.isArray(a.tools)){for(var i=0;i<a.tools.length;i++){Object.freeze(a.tools[i]);}Object.freeze(a.tools);}Object.freeze(a);Object.defineProperty(o.adapters,"reddit",{value:a,writable:false,configurable:false,enumerable:true});Object.defineProperty(o,"adapters",{value:o.adapters,writable:false,configurable:false});}})();
|
|
16294
16295
|
//# sourceMappingURL=adapter.iife.js.map
|