letsfg 2026.5.70 → 2026.5.72

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,126 +0,0 @@
1
- // src/auth.ts
2
- import { readFileSync, writeFileSync, mkdirSync, chmodSync, existsSync } from "fs";
3
- import { homedir, platform } from "os";
4
- import { join, dirname } from "path";
5
- var BASE_URL = process.env.LETSFG_BASE_URL || "https://letsfg.co";
6
- var TOKEN_TTL_MS = 90 * 24 * 3600 * 1e3;
7
- var BearerTokenError = class extends Error {
8
- };
9
- function configPath() {
10
- const base = platform() === "win32" ? process.env.APPDATA || homedir() : homedir();
11
- return join(base, ".letsfg", "config.json");
12
- }
13
- function loadConfig() {
14
- const p = configPath();
15
- if (!existsSync(p)) return {};
16
- try {
17
- return JSON.parse(readFileSync(p, "utf-8"));
18
- } catch {
19
- return {};
20
- }
21
- }
22
- function saveConfig(cfg) {
23
- const p = configPath();
24
- mkdirSync(dirname(p), { recursive: true });
25
- writeFileSync(p, JSON.stringify(cfg, null, 2));
26
- try {
27
- chmodSync(p, 384);
28
- } catch {
29
- }
30
- }
31
- function getBearerToken() {
32
- const env = process.env.LETSFG_BEARER_TOKEN;
33
- if (env) return env;
34
- const auth = loadConfig().pfs_auth;
35
- if (auth?.token && Date.now() < auth.expires_at - 36e5) {
36
- return auth.token;
37
- }
38
- throw new BearerTokenError(
39
- "No valid LetsFG Bearer token.\n Run: letsfg auth (adds a payment method \u2014 nothing is charged)\n Or: export LETSFG_BEARER_TOKEN=<token>"
40
- );
41
- }
42
- function saveToken(token, expiresAt) {
43
- const cfg = loadConfig();
44
- cfg.pfs_auth = { token, expires_at: expiresAt ?? Date.now() + TOKEN_TTL_MS };
45
- saveConfig(cfg);
46
- }
47
- async function postJson(path, payload) {
48
- const resp = await fetch(`${BASE_URL}${path}`, {
49
- method: "POST",
50
- headers: { "Content-Type": "application/json", "User-Agent": "LetsFG-js/0.1.0", "X-Client-Type": "js-sdk" },
51
- body: JSON.stringify(payload)
52
- });
53
- const data = await resp.json().catch(() => ({}));
54
- return { status: resp.status, data };
55
- }
56
- function parseExpiry(raw) {
57
- if (typeof raw === "number") return raw * 1e3;
58
- if (typeof raw === "string") {
59
- const ms = Date.parse(raw);
60
- if (!Number.isNaN(ms)) return ms;
61
- }
62
- return Date.now() + TOKEN_TTL_MS;
63
- }
64
- async function requestEnrolment() {
65
- const { status, data } = await postJson("/api/agent-access/request", {});
66
- if (status !== 200 && status !== 402) {
67
- throw new BearerTokenError(`Could not start authentication (HTTP ${status}): ${data.error || ""}`);
68
- }
69
- return data;
70
- }
71
- async function verifyPaymentMethod(opts) {
72
- const payload = {};
73
- if (opts.setupSessionId) payload.setup_session_id = opts.setupSessionId;
74
- else if (opts.paymentMethodId) payload.payment_method_id = opts.paymentMethodId;
75
- else if (opts.cardToken) payload.card_token = opts.cardToken;
76
- else throw new BearerTokenError("Provide one of setupSessionId, paymentMethodId, or cardToken.");
77
- const { status, data } = await postJson("/api/agent-access/verify", payload);
78
- if (status !== 200 || !data.token) {
79
- throw new BearerTokenError(`Verification failed (HTTP ${status}). ${data.hint || data.error || ""}`.trim());
80
- }
81
- const token = data.token;
82
- saveToken(token, parseExpiry(data.expires_at));
83
- return token;
84
- }
85
- function openBrowser(url) {
86
- import("child_process").then(({ exec }) => {
87
- const cmd = platform() === "win32" ? `start "" "${url}"` : platform() === "darwin" ? `open "${url}"` : `xdg-open "${url}"`;
88
- exec(cmd, () => {
89
- });
90
- }).catch(() => {
91
- });
92
- }
93
- async function paymentAuth(openBrowserFlag = true) {
94
- console.log("\n Connecting to LetsFG...");
95
- const data = await requestEnrolment();
96
- const setupUrl = data.setup_url;
97
- const sessionId = data.setup_session_id;
98
- if (!setupUrl || !sessionId) {
99
- throw new BearerTokenError("Server did not return a setup URL. Check https://letsfg.co/for-agents");
100
- }
101
- console.log("\n LetsFG needs a payment method on file before it can search or book.");
102
- console.log(" Nothing is charged now \u2014 this is a zero-amount card setup.\n");
103
- console.log(" Step 1 \u2014 add a card here:\n");
104
- console.log(` ${setupUrl}
105
- `);
106
- if (openBrowserFlag) openBrowser(setupUrl);
107
- console.log(" Step 2 \u2014 press Enter once you've finished.");
108
- const readline = await import("readline/promises");
109
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
110
- await rl.question("");
111
- rl.close();
112
- process.stdout.write(" Verifying... ");
113
- const token = await verifyPaymentMethod({ setupSessionId: sessionId });
114
- const expiresAt = loadConfig().pfs_auth?.expires_at ?? Date.now() + TOKEN_TTL_MS;
115
- console.log(`done. Token valid until ${new Date(expiresAt).toISOString().slice(0, 10)}.`);
116
- return token;
117
- }
118
-
119
- export {
120
- BearerTokenError,
121
- getBearerToken,
122
- saveToken,
123
- requestEnrolment,
124
- verifyPaymentMethod,
125
- paymentAuth
126
- };