@apiosk/mcp 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +590 -0
- package/docs/marketplace-submission-2026-04-08.md +92 -0
- package/docs/sepa-rail.md +134 -0
- package/dxt.json +46 -0
- package/index.mjs +9 -0
- package/package.json +77 -0
- package/server.json +17 -0
- package/server.mjs +373 -0
- package/src/create-server.mjs +37 -0
- package/src/funding-options.mjs +255 -0
- package/src/gateway-management.mjs +107 -0
- package/src/listing-metadata.mjs +287 -0
- package/src/local-config.mjs +256 -0
- package/src/oauth.mjs +1015 -0
- package/src/payment-guidance.mjs +307 -0
- package/src/runtime.mjs +3090 -0
- package/src/wallet-store.mjs +476 -0
- package/well-known.mjs +11 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import {
|
|
5
|
+
chmod,
|
|
6
|
+
mkdir,
|
|
7
|
+
readFile,
|
|
8
|
+
rename,
|
|
9
|
+
rm,
|
|
10
|
+
writeFile,
|
|
11
|
+
} from "node:fs/promises";
|
|
12
|
+
|
|
13
|
+
import { generatePrivateKey, mnemonicToAccount, privateKeyToAccount } from "viem/accounts";
|
|
14
|
+
|
|
15
|
+
const STORE_VERSION = 1;
|
|
16
|
+
|
|
17
|
+
function trimString(value) {
|
|
18
|
+
return String(value || "").trim();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function defaultApioskDir(env = process.env) {
|
|
22
|
+
const configured = trimString(env.APIOSK_HOME);
|
|
23
|
+
if (configured) return configured;
|
|
24
|
+
|
|
25
|
+
const home = trimString(env.HOME) || os.homedir();
|
|
26
|
+
return path.join(home, ".apiosk");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function createPaths(env = process.env) {
|
|
30
|
+
const apioskDir = defaultApioskDir(env);
|
|
31
|
+
return {
|
|
32
|
+
apioskDir,
|
|
33
|
+
storeFile: trimString(env.APIOSK_MCP_WALLET_STORE) || path.join(apioskDir, "mcp-wallets.json"),
|
|
34
|
+
activeWalletJsonFile: path.join(apioskDir, "wallet.json"),
|
|
35
|
+
activeWalletTextFile: path.join(apioskDir, "wallet.txt"),
|
|
36
|
+
secretExportDir: path.join(apioskDir, "exports"),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function defaultStore() {
|
|
41
|
+
return {
|
|
42
|
+
version: STORE_VERSION,
|
|
43
|
+
active_wallet_id: null,
|
|
44
|
+
wallets: [],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function normalizePrivateKey(secret) {
|
|
49
|
+
const trimmed = trimString(secret);
|
|
50
|
+
if (!trimmed) {
|
|
51
|
+
throw new Error("Wallet secret is required.");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const normalized = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
55
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(normalized)) {
|
|
56
|
+
throw new Error("Private key must be 32 bytes of hex.");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return normalized.toLowerCase();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function normalizeMnemonic(secret) {
|
|
63
|
+
const normalized = trimString(secret)
|
|
64
|
+
.toLowerCase()
|
|
65
|
+
.split(/\s+/)
|
|
66
|
+
.filter(Boolean)
|
|
67
|
+
.join(" ");
|
|
68
|
+
|
|
69
|
+
if (!normalized) {
|
|
70
|
+
throw new Error("Recovery phrase is required.");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return normalized;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function sortWallets(wallets = [], activeWalletId = null) {
|
|
77
|
+
return [...wallets].sort((left, right) => {
|
|
78
|
+
if (left.id === activeWalletId && right.id !== activeWalletId) return -1;
|
|
79
|
+
if (right.id === activeWalletId && left.id !== activeWalletId) return 1;
|
|
80
|
+
|
|
81
|
+
return String(right.updated_at || right.created_at || "").localeCompare(
|
|
82
|
+
String(left.updated_at || left.created_at || "")
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function summarizeWallet(wallet, activeWalletId = null) {
|
|
88
|
+
return {
|
|
89
|
+
id: wallet.id,
|
|
90
|
+
label: wallet.label,
|
|
91
|
+
address: wallet.address,
|
|
92
|
+
active: wallet.id === activeWalletId,
|
|
93
|
+
source: wallet.source,
|
|
94
|
+
created_at: wallet.created_at,
|
|
95
|
+
updated_at: wallet.updated_at,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function safeChmod(filePath, mode) {
|
|
100
|
+
try {
|
|
101
|
+
await chmod(filePath, mode);
|
|
102
|
+
} catch {
|
|
103
|
+
// Best effort only; not all environments support chmod.
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function writeJsonAtomic(filePath, value) {
|
|
108
|
+
const dir = path.dirname(filePath);
|
|
109
|
+
const tempFile = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
110
|
+
|
|
111
|
+
await mkdir(dir, { recursive: true });
|
|
112
|
+
await writeFile(tempFile, JSON.stringify(value, null, 2), "utf8");
|
|
113
|
+
await safeChmod(tempFile, 0o600);
|
|
114
|
+
await rename(tempFile, filePath);
|
|
115
|
+
await safeChmod(filePath, 0o600);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function writeTextAtomic(filePath, value) {
|
|
119
|
+
const dir = path.dirname(filePath);
|
|
120
|
+
const tempFile = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
121
|
+
|
|
122
|
+
await mkdir(dir, { recursive: true });
|
|
123
|
+
await writeFile(tempFile, value, "utf8");
|
|
124
|
+
await safeChmod(tempFile, 0o600);
|
|
125
|
+
await rename(tempFile, filePath);
|
|
126
|
+
await safeChmod(filePath, 0o600);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function removeFileQuietly(filePath) {
|
|
130
|
+
try {
|
|
131
|
+
await rm(filePath, { force: true });
|
|
132
|
+
} catch {
|
|
133
|
+
// Ignore cleanup failures.
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function createLocalWalletStore(env = process.env) {
|
|
138
|
+
const paths = createPaths(env);
|
|
139
|
+
|
|
140
|
+
async function ensureBaseDir() {
|
|
141
|
+
await mkdir(paths.apioskDir, { recursive: true });
|
|
142
|
+
await safeChmod(paths.apioskDir, 0o700);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function readStore() {
|
|
146
|
+
try {
|
|
147
|
+
const raw = await readFile(paths.storeFile, "utf8");
|
|
148
|
+
const parsed = JSON.parse(raw);
|
|
149
|
+
const wallets = Array.isArray(parsed?.wallets) ? parsed.wallets : [];
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
version: STORE_VERSION,
|
|
153
|
+
active_wallet_id:
|
|
154
|
+
typeof parsed?.active_wallet_id === "string" && parsed.active_wallet_id.trim()
|
|
155
|
+
? parsed.active_wallet_id
|
|
156
|
+
: null,
|
|
157
|
+
wallets: wallets.map((wallet) => ({
|
|
158
|
+
id: trimString(wallet.id) || randomUUID(),
|
|
159
|
+
label: trimString(wallet.label) || "Wallet",
|
|
160
|
+
address: trimString(wallet.address).toLowerCase(),
|
|
161
|
+
private_key: normalizePrivateKey(wallet.private_key),
|
|
162
|
+
source: trimString(wallet.source) || "generated",
|
|
163
|
+
created_at: trimString(wallet.created_at) || new Date().toISOString(),
|
|
164
|
+
updated_at: trimString(wallet.updated_at) || new Date().toISOString(),
|
|
165
|
+
})),
|
|
166
|
+
};
|
|
167
|
+
} catch (error) {
|
|
168
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
169
|
+
return defaultStore();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
throw new Error(
|
|
173
|
+
`Could not read the local Apiosk wallet store: ${
|
|
174
|
+
error instanceof Error ? error.message : String(error)
|
|
175
|
+
}`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function writeStore(store) {
|
|
181
|
+
await ensureBaseDir();
|
|
182
|
+
await writeJsonAtomic(paths.storeFile, store);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async function syncActiveWalletFiles(store) {
|
|
186
|
+
const activeWallet = store.wallets.find((wallet) => wallet.id === store.active_wallet_id) || null;
|
|
187
|
+
|
|
188
|
+
if (!activeWallet) {
|
|
189
|
+
await Promise.all([
|
|
190
|
+
removeFileQuietly(paths.activeWalletJsonFile),
|
|
191
|
+
removeFileQuietly(paths.activeWalletTextFile),
|
|
192
|
+
]);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
await ensureBaseDir();
|
|
197
|
+
await writeJsonAtomic(paths.activeWalletJsonFile, {
|
|
198
|
+
id: activeWallet.id,
|
|
199
|
+
label: activeWallet.label,
|
|
200
|
+
address: activeWallet.address,
|
|
201
|
+
private_key: activeWallet.private_key,
|
|
202
|
+
source: activeWallet.source,
|
|
203
|
+
created_at: activeWallet.created_at,
|
|
204
|
+
updated_at: activeWallet.updated_at,
|
|
205
|
+
});
|
|
206
|
+
await writeTextAtomic(paths.activeWalletTextFile, `${activeWallet.address}\n`);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function saveStore(store) {
|
|
210
|
+
await writeStore(store);
|
|
211
|
+
await syncActiveWalletFiles(store);
|
|
212
|
+
return store;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function getStore() {
|
|
216
|
+
return readStore();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async function getWalletOrThrow(walletId) {
|
|
220
|
+
const store = await getStore();
|
|
221
|
+
const wallet = store.wallets.find((candidate) => candidate.id === walletId);
|
|
222
|
+
|
|
223
|
+
if (!wallet) {
|
|
224
|
+
throw new Error(`Unknown wallet id: ${walletId}`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return { store, wallet };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async function listWallets() {
|
|
231
|
+
const store = await getStore();
|
|
232
|
+
return {
|
|
233
|
+
active_wallet_id: store.active_wallet_id,
|
|
234
|
+
store_file: paths.storeFile,
|
|
235
|
+
wallet_json_file: paths.activeWalletJsonFile,
|
|
236
|
+
wallet_txt_file: paths.activeWalletTextFile,
|
|
237
|
+
wallets: sortWallets(store.wallets, store.active_wallet_id).map((wallet) =>
|
|
238
|
+
summarizeWallet(wallet, store.active_wallet_id)
|
|
239
|
+
),
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function resolveActiveWallet() {
|
|
244
|
+
const store = await getStore();
|
|
245
|
+
const wallet = store.wallets.find((candidate) => candidate.id === store.active_wallet_id) || null;
|
|
246
|
+
return wallet ? summarizeWallet(wallet, store.active_wallet_id) : null;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async function getWalletRecord(walletId) {
|
|
250
|
+
const { store, wallet } = await getWalletOrThrow(walletId);
|
|
251
|
+
return summarizeWallet(wallet, store.active_wallet_id);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function getWalletPrivateData(walletId) {
|
|
255
|
+
const { store, wallet } = await getWalletOrThrow(walletId);
|
|
256
|
+
return {
|
|
257
|
+
wallet: summarizeWallet(wallet, store.active_wallet_id),
|
|
258
|
+
private_key: wallet.private_key,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async function createWallet({
|
|
263
|
+
label,
|
|
264
|
+
mode = "create",
|
|
265
|
+
secret = "",
|
|
266
|
+
set_active = true,
|
|
267
|
+
} = {}) {
|
|
268
|
+
const cleanLabel = trimString(label);
|
|
269
|
+
if (!cleanLabel) {
|
|
270
|
+
throw new Error("Wallet label is required.");
|
|
271
|
+
}
|
|
272
|
+
if (cleanLabel.length > 64) {
|
|
273
|
+
throw new Error("Wallet label must be 64 characters or less.");
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
let account;
|
|
277
|
+
let privateKey;
|
|
278
|
+
let source = "generated";
|
|
279
|
+
if (mode === "import_private_key") {
|
|
280
|
+
privateKey = normalizePrivateKey(secret);
|
|
281
|
+
account = privateKeyToAccount(privateKey);
|
|
282
|
+
source = "imported_private_key";
|
|
283
|
+
} else if (mode === "import_phrase") {
|
|
284
|
+
account = mnemonicToAccount(normalizeMnemonic(secret));
|
|
285
|
+
privateKey = `0x${Buffer.from(account.getHdKey().privateKey).toString("hex")}`;
|
|
286
|
+
source = "imported_phrase";
|
|
287
|
+
} else {
|
|
288
|
+
privateKey = generatePrivateKey();
|
|
289
|
+
account = privateKeyToAccount(privateKey);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const store = await getStore();
|
|
293
|
+
const address = account.address.toLowerCase();
|
|
294
|
+
const duplicate = store.wallets.find((wallet) => wallet.address === address);
|
|
295
|
+
|
|
296
|
+
if (duplicate) {
|
|
297
|
+
throw new Error(`Wallet ${address} is already in the local store.`);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const now = new Date().toISOString();
|
|
301
|
+
const wallet = {
|
|
302
|
+
id: randomUUID(),
|
|
303
|
+
label: cleanLabel,
|
|
304
|
+
address,
|
|
305
|
+
private_key: normalizePrivateKey(privateKey),
|
|
306
|
+
source,
|
|
307
|
+
created_at: now,
|
|
308
|
+
updated_at: now,
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
store.wallets.unshift(wallet);
|
|
312
|
+
if (set_active !== false || !store.active_wallet_id) {
|
|
313
|
+
store.active_wallet_id = wallet.id;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
await saveStore(store);
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
wallet: summarizeWallet(wallet, store.active_wallet_id),
|
|
320
|
+
active_wallet_id: store.active_wallet_id,
|
|
321
|
+
store_file: paths.storeFile,
|
|
322
|
+
wallet_json_file: paths.activeWalletJsonFile,
|
|
323
|
+
wallet_txt_file: paths.activeWalletTextFile,
|
|
324
|
+
next_steps: [
|
|
325
|
+
"Use apiosk_execute or any API-specific Apiosk tool to make paid calls with the active wallet.",
|
|
326
|
+
"Use apiosk_publish_api to publish an API with the same active wallet.",
|
|
327
|
+
],
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async function selectWallet(walletId) {
|
|
332
|
+
const { store, wallet } = await getWalletOrThrow(walletId);
|
|
333
|
+
store.active_wallet_id = wallet.id;
|
|
334
|
+
wallet.updated_at = new Date().toISOString();
|
|
335
|
+
await saveStore(store);
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
wallet: summarizeWallet(wallet, store.active_wallet_id),
|
|
339
|
+
wallet_json_file: paths.activeWalletJsonFile,
|
|
340
|
+
wallet_txt_file: paths.activeWalletTextFile,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async function updateWallet(walletId, updates = {}) {
|
|
345
|
+
const { store, wallet } = await getWalletOrThrow(walletId);
|
|
346
|
+
const nextLabel =
|
|
347
|
+
updates.label === undefined ? wallet.label : trimString(updates.label);
|
|
348
|
+
|
|
349
|
+
if (!nextLabel) {
|
|
350
|
+
throw new Error("Wallet label cannot be empty.");
|
|
351
|
+
}
|
|
352
|
+
if (nextLabel.length > 64) {
|
|
353
|
+
throw new Error("Wallet label must be 64 characters or less.");
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
wallet.label = nextLabel;
|
|
357
|
+
wallet.updated_at = new Date().toISOString();
|
|
358
|
+
|
|
359
|
+
if (updates.set_active === true) {
|
|
360
|
+
store.active_wallet_id = wallet.id;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
await saveStore(store);
|
|
364
|
+
return {
|
|
365
|
+
wallet: summarizeWallet(wallet, store.active_wallet_id),
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async function deleteWallet(walletId) {
|
|
370
|
+
const store = await getStore();
|
|
371
|
+
const existingIndex = store.wallets.findIndex((wallet) => wallet.id === walletId);
|
|
372
|
+
|
|
373
|
+
if (existingIndex === -1) {
|
|
374
|
+
throw new Error(`Unknown wallet id: ${walletId}`);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const [removed] = store.wallets.splice(existingIndex, 1);
|
|
378
|
+
if (store.active_wallet_id === removed.id) {
|
|
379
|
+
store.active_wallet_id = store.wallets[0]?.id || null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
await saveStore(store);
|
|
383
|
+
return {
|
|
384
|
+
deleted_wallet_id: removed.id,
|
|
385
|
+
deleted_wallet_address: removed.address,
|
|
386
|
+
active_wallet_id: store.active_wallet_id,
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
async function revealSecret(walletId) {
|
|
391
|
+
const { wallet, private_key } = await getWalletPrivateData(walletId);
|
|
392
|
+
return {
|
|
393
|
+
wallet,
|
|
394
|
+
private_key,
|
|
395
|
+
warning: "This is the raw private key. Only reveal it when the user explicitly asks for it.",
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async function saveSecret(walletId, options = {}) {
|
|
400
|
+
const { wallet, private_key } = await getWalletPrivateData(walletId);
|
|
401
|
+
const format = trimString(options.format || "json").toLowerCase();
|
|
402
|
+
if (!["json", "txt"].includes(format)) {
|
|
403
|
+
throw new Error("Secret export format must be either 'json' or 'txt'.");
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const explicitPath = trimString(options.path);
|
|
407
|
+
const defaultFilename = `${wallet.label
|
|
408
|
+
.toLowerCase()
|
|
409
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
410
|
+
.replace(/^-+|-+$/g, "") || wallet.id}.${format}`;
|
|
411
|
+
const outputPath = explicitPath || path.join(paths.secretExportDir, defaultFilename);
|
|
412
|
+
|
|
413
|
+
await mkdir(path.dirname(outputPath), { recursive: true });
|
|
414
|
+
if (format === "json") {
|
|
415
|
+
await writeJsonAtomic(outputPath, {
|
|
416
|
+
id: wallet.id,
|
|
417
|
+
label: wallet.label,
|
|
418
|
+
address: wallet.address,
|
|
419
|
+
private_key,
|
|
420
|
+
source: wallet.source,
|
|
421
|
+
exported_at: new Date().toISOString(),
|
|
422
|
+
});
|
|
423
|
+
} else {
|
|
424
|
+
await writeTextAtomic(outputPath, `${private_key}\n`);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
wallet,
|
|
429
|
+
saved_to: outputPath,
|
|
430
|
+
format,
|
|
431
|
+
warning: "The exported file contains the raw private key. Keep it private.",
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
async function resolveSigningWallet(walletId = null) {
|
|
436
|
+
const targetWalletId = trimString(walletId);
|
|
437
|
+
if (targetWalletId) {
|
|
438
|
+
const { wallet, private_key } = await getWalletPrivateData(targetWalletId);
|
|
439
|
+
return {
|
|
440
|
+
id: wallet.id,
|
|
441
|
+
label: wallet.label,
|
|
442
|
+
address: wallet.address,
|
|
443
|
+
private_key,
|
|
444
|
+
source: "local_store",
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const store = await getStore();
|
|
449
|
+
const activeWallet = store.wallets.find((wallet) => wallet.id === store.active_wallet_id);
|
|
450
|
+
if (!activeWallet) {
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
return {
|
|
455
|
+
id: activeWallet.id,
|
|
456
|
+
label: activeWallet.label,
|
|
457
|
+
address: activeWallet.address,
|
|
458
|
+
private_key: activeWallet.private_key,
|
|
459
|
+
source: "local_store",
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return {
|
|
464
|
+
paths,
|
|
465
|
+
listWallets,
|
|
466
|
+
resolveActiveWallet,
|
|
467
|
+
resolveSigningWallet,
|
|
468
|
+
getWalletRecord,
|
|
469
|
+
createWallet,
|
|
470
|
+
selectWallet,
|
|
471
|
+
updateWallet,
|
|
472
|
+
deleteWallet,
|
|
473
|
+
revealSecret,
|
|
474
|
+
saveSecret,
|
|
475
|
+
};
|
|
476
|
+
}
|
package/well-known.mjs
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function resolveOpenAiAppsChallengeToken(env = process.env) {
|
|
2
|
+
return String(env?.APIOSK_OPENAI_APPS_CHALLENGE_TOKEN || "").trim();
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function sendOpenAiAppsChallenge(res, token) {
|
|
6
|
+
if (!token) {
|
|
7
|
+
return res.status(404).type("text/plain").send("OpenAI apps challenge token is not configured.");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return res.status(200).type("text/plain; charset=utf-8").send(token);
|
|
11
|
+
}
|