@akira-io/billing-js 0.1.9 → 0.3.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.
- package/dist/client.cjs +6 -0
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +2 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.js +6 -0
- package/dist/client.js.map +1 -1
- package/dist/desktop-react.cjs +26 -0
- package/dist/desktop-react.cjs.map +1 -0
- package/dist/desktop-react.d.cts +17 -0
- package/dist/desktop-react.d.ts +17 -0
- package/dist/desktop-react.js +24 -0
- package/dist/desktop-react.js.map +1 -0
- package/dist/desktop-vue.cjs +29 -0
- package/dist/desktop-vue.cjs.map +1 -0
- package/dist/desktop-vue.d.cts +18 -0
- package/dist/desktop-vue.d.ts +18 -0
- package/dist/desktop-vue.js +27 -0
- package/dist/desktop-vue.js.map +1 -0
- package/dist/desktop.cjs +194 -0
- package/dist/desktop.cjs.map +1 -0
- package/dist/desktop.d.cts +16 -0
- package/dist/desktop.d.ts +16 -0
- package/dist/desktop.js +188 -0
- package/dist/desktop.js.map +1 -0
- package/dist/index.cjs +239 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +82 -2
- package/dist/index.d.ts +82 -2
- package/dist/index.js +233 -1
- package/dist/index.js.map +1 -1
- package/dist/loopback.cjs +120 -0
- package/dist/loopback.cjs.map +1 -0
- package/dist/loopback.d.cts +24 -0
- package/dist/loopback.d.ts +24 -0
- package/dist/loopback.js +118 -0
- package/dist/loopback.js.map +1 -0
- package/dist/use-auth-Bf4NrNdE.d.ts +68 -0
- package/dist/use-auth-BzN6Wcpm.d.cts +68 -0
- package/package.json +21 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/oauth.ts","../src/loopback.ts"],"names":["createServer"],"mappings":"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","file":"loopback.cjs","sourcesContent":["import type { BuildOauthInitUrlOptions, PkceChallenge } from './client-types';\n\nfunction bytesToUrlSafeBase64(bytes: Uint8Array): string {\n let bin = '';\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i] as number);\n return btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction randomBytes(length: number): Uint8Array {\n const buf = new Uint8Array(length);\n globalThis.crypto.getRandomValues(buf);\n return buf;\n}\n\nexport async function generatePkceChallenge(): Promise<PkceChallenge> {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) throw new Error('crypto.subtle not available; cannot generate PKCE challenge');\n\n const verifier = bytesToUrlSafeBase64(randomBytes(48));\n const hash = await subtle.digest('SHA-256', new TextEncoder().encode(verifier));\n const challenge = bytesToUrlSafeBase64(new Uint8Array(hash));\n\n return { verifier, challenge, method: 'S256' };\n}\n\nexport function generateOauthState(): string {\n return bytesToUrlSafeBase64(randomBytes(24));\n}\n\nexport function buildOauthInitUrl(opts: BuildOauthInitUrlOptions): string {\n const base = opts.baseUrl.replace(/\\/$/, '');\n const params = new URLSearchParams({\n product: opts.product,\n redirect_uri: opts.redirectUri,\n code_challenge: opts.codeChallenge,\n code_challenge_method: opts.codeChallengeMethod ?? 'S256',\n });\n if (opts.state) params.set('state', opts.state);\n\n return `${base}/auth/${opts.provider}?${params.toString()}`;\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { AddressInfo } from 'node:net';\nimport { BillingClient } from './client';\nimport type { OauthExchangeResponse, OauthProvider } from './client-types';\nimport { buildOauthInitUrl, generateOauthState, generatePkceChallenge } from './oauth';\n\nconst SUCCESS_HTML = `<!doctype html><meta charset=utf-8><title>Sign in complete</title><style>body{font-family:-apple-system,system-ui,sans-serif;background:#08080b;color:#e6e6ec;display:grid;place-items:center;height:100vh;margin:0}</style><h1>You can close this tab.</h1>`;\n\nexport interface LoopbackLoginOptions {\n provider: OauthProvider;\n product: string;\n /** Caller-controlled browser opener. Receives the OAuth init URL. */\n openBrowser: (url: string) => void | Promise<void>;\n /** Wall-clock timeout for the callback (default: 300 s). */\n timeoutMs?: number;\n}\n\nexport interface LoopbackOutcome {\n exchange: OauthExchangeResponse;\n}\n\n/**\n * Desktop loopback PKCE OAuth flow for Node-based consumers.\n *\n * Binds a transient HTTP server on `127.0.0.1`, opens the system browser, waits\n * for the provider redirect, exchanges the code for an access token through the\n * SDK and stores it on the supplied client.\n */\nexport async function loopbackLogin(\n client: BillingClient,\n opts: LoopbackLoginOptions,\n): Promise<LoopbackOutcome> {\n const pkce = await generatePkceChallenge();\n const state = generateOauthState();\n\n const { port, server, callback } = await listenForCallback(opts.timeoutMs ?? 300_000);\n\n const redirectUri = `http://127.0.0.1:${port}/cb`;\n const authUrl = buildOauthInitUrl({\n baseUrl: client.getBaseUrl(),\n provider: opts.provider,\n product: opts.product,\n redirectUri,\n codeChallenge: pkce.challenge,\n codeChallengeMethod: pkce.method,\n state,\n });\n\n try {\n await opts.openBrowser(authUrl);\n } catch (e) {\n server.close();\n throw new Error(`loopback: open browser failed — ${(e as Error).message}`, { cause: e });\n }\n\n let result: { code: string; state: string };\n try {\n result = await callback;\n } finally {\n server.close();\n }\n\n if (result.state !== state) {\n throw new Error('loopback: oauth state mismatch');\n }\n\n const exchange = await client.exchangeOauthCode({\n code: result.code,\n code_verifier: pkce.verifier,\n });\n\n return { exchange };\n}\n\ninterface ListenResult {\n port: number;\n server: ReturnType<typeof createServer>;\n callback: Promise<{ code: string; state: string }>;\n}\n\nasync function listenForCallback(timeoutMs: number): Promise<ListenResult> {\n return new Promise((resolve, reject) => {\n const server = createServer();\n\n const callback = new Promise<{ code: string; state: string }>((res, rej) => {\n const timer = setTimeout(() => {\n rej(new Error('loopback: callback timed out'));\n server.close();\n }, timeoutMs);\n\n server.once('error', (e) => {\n clearTimeout(timer);\n rej(e);\n });\n\n server.on('request', (req: IncomingMessage, resp: ServerResponse) => {\n try {\n const reqUrl = new URL(req.url ?? '/', 'http://127.0.0.1');\n const code = reqUrl.searchParams.get('code');\n const state = reqUrl.searchParams.get('state');\n\n resp.writeHead(200, {\n 'Content-Type': 'text/html; charset=utf-8',\n 'Connection': 'close',\n });\n resp.end(SUCCESS_HTML);\n\n if (!code) return rej(new Error('loopback: callback missing code'));\n if (!state) return rej(new Error('loopback: callback missing state'));\n\n clearTimeout(timer);\n res({ code, state });\n } catch (e) {\n clearTimeout(timer);\n rej(e as Error);\n }\n });\n });\n\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address() as AddressInfo;\n resolve({ port: addr.port, server, callback });\n });\n\n server.once('error', reject);\n });\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BillingClient } from './client.cjs';
|
|
2
|
+
import { t as OauthProvider, s as OauthExchangeResponse } from './client-types-CtRkHWna.cjs';
|
|
3
|
+
|
|
4
|
+
interface LoopbackLoginOptions {
|
|
5
|
+
provider: OauthProvider;
|
|
6
|
+
product: string;
|
|
7
|
+
/** Caller-controlled browser opener. Receives the OAuth init URL. */
|
|
8
|
+
openBrowser: (url: string) => void | Promise<void>;
|
|
9
|
+
/** Wall-clock timeout for the callback (default: 300 s). */
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
}
|
|
12
|
+
interface LoopbackOutcome {
|
|
13
|
+
exchange: OauthExchangeResponse;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Desktop loopback PKCE OAuth flow for Node-based consumers.
|
|
17
|
+
*
|
|
18
|
+
* Binds a transient HTTP server on `127.0.0.1`, opens the system browser, waits
|
|
19
|
+
* for the provider redirect, exchanges the code for an access token through the
|
|
20
|
+
* SDK and stores it on the supplied client.
|
|
21
|
+
*/
|
|
22
|
+
declare function loopbackLogin(client: BillingClient, opts: LoopbackLoginOptions): Promise<LoopbackOutcome>;
|
|
23
|
+
|
|
24
|
+
export { type LoopbackLoginOptions, type LoopbackOutcome, loopbackLogin };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BillingClient } from './client.js';
|
|
2
|
+
import { t as OauthProvider, s as OauthExchangeResponse } from './client-types-CtRkHWna.js';
|
|
3
|
+
|
|
4
|
+
interface LoopbackLoginOptions {
|
|
5
|
+
provider: OauthProvider;
|
|
6
|
+
product: string;
|
|
7
|
+
/** Caller-controlled browser opener. Receives the OAuth init URL. */
|
|
8
|
+
openBrowser: (url: string) => void | Promise<void>;
|
|
9
|
+
/** Wall-clock timeout for the callback (default: 300 s). */
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
}
|
|
12
|
+
interface LoopbackOutcome {
|
|
13
|
+
exchange: OauthExchangeResponse;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Desktop loopback PKCE OAuth flow for Node-based consumers.
|
|
17
|
+
*
|
|
18
|
+
* Binds a transient HTTP server on `127.0.0.1`, opens the system browser, waits
|
|
19
|
+
* for the provider redirect, exchanges the code for an access token through the
|
|
20
|
+
* SDK and stores it on the supplied client.
|
|
21
|
+
*/
|
|
22
|
+
declare function loopbackLogin(client: BillingClient, opts: LoopbackLoginOptions): Promise<LoopbackOutcome>;
|
|
23
|
+
|
|
24
|
+
export { type LoopbackLoginOptions, type LoopbackOutcome, loopbackLogin };
|
package/dist/loopback.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { createServer } from 'http';
|
|
2
|
+
|
|
3
|
+
// src/loopback.ts
|
|
4
|
+
|
|
5
|
+
// src/oauth.ts
|
|
6
|
+
function bytesToUrlSafeBase64(bytes) {
|
|
7
|
+
let bin = "";
|
|
8
|
+
for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
|
|
9
|
+
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
10
|
+
}
|
|
11
|
+
function randomBytes(length) {
|
|
12
|
+
const buf = new Uint8Array(length);
|
|
13
|
+
globalThis.crypto.getRandomValues(buf);
|
|
14
|
+
return buf;
|
|
15
|
+
}
|
|
16
|
+
async function generatePkceChallenge() {
|
|
17
|
+
const subtle = globalThis.crypto?.subtle;
|
|
18
|
+
if (!subtle) throw new Error("crypto.subtle not available; cannot generate PKCE challenge");
|
|
19
|
+
const verifier = bytesToUrlSafeBase64(randomBytes(48));
|
|
20
|
+
const hash = await subtle.digest("SHA-256", new TextEncoder().encode(verifier));
|
|
21
|
+
const challenge = bytesToUrlSafeBase64(new Uint8Array(hash));
|
|
22
|
+
return { verifier, challenge, method: "S256" };
|
|
23
|
+
}
|
|
24
|
+
function generateOauthState() {
|
|
25
|
+
return bytesToUrlSafeBase64(randomBytes(24));
|
|
26
|
+
}
|
|
27
|
+
function buildOauthInitUrl(opts) {
|
|
28
|
+
const base = opts.baseUrl.replace(/\/$/, "");
|
|
29
|
+
const params = new URLSearchParams({
|
|
30
|
+
product: opts.product,
|
|
31
|
+
redirect_uri: opts.redirectUri,
|
|
32
|
+
code_challenge: opts.codeChallenge,
|
|
33
|
+
code_challenge_method: opts.codeChallengeMethod ?? "S256"
|
|
34
|
+
});
|
|
35
|
+
if (opts.state) params.set("state", opts.state);
|
|
36
|
+
return `${base}/auth/${opts.provider}?${params.toString()}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/loopback.ts
|
|
40
|
+
var SUCCESS_HTML = `<!doctype html><meta charset=utf-8><title>Sign in complete</title><style>body{font-family:-apple-system,system-ui,sans-serif;background:#08080b;color:#e6e6ec;display:grid;place-items:center;height:100vh;margin:0}</style><h1>You can close this tab.</h1>`;
|
|
41
|
+
async function loopbackLogin(client, opts) {
|
|
42
|
+
const pkce = await generatePkceChallenge();
|
|
43
|
+
const state = generateOauthState();
|
|
44
|
+
const { port, server, callback } = await listenForCallback(opts.timeoutMs ?? 3e5);
|
|
45
|
+
const redirectUri = `http://127.0.0.1:${port}/cb`;
|
|
46
|
+
const authUrl = buildOauthInitUrl({
|
|
47
|
+
baseUrl: client.getBaseUrl(),
|
|
48
|
+
provider: opts.provider,
|
|
49
|
+
product: opts.product,
|
|
50
|
+
redirectUri,
|
|
51
|
+
codeChallenge: pkce.challenge,
|
|
52
|
+
codeChallengeMethod: pkce.method,
|
|
53
|
+
state
|
|
54
|
+
});
|
|
55
|
+
try {
|
|
56
|
+
await opts.openBrowser(authUrl);
|
|
57
|
+
} catch (e) {
|
|
58
|
+
server.close();
|
|
59
|
+
throw new Error(`loopback: open browser failed \u2014 ${e.message}`, { cause: e });
|
|
60
|
+
}
|
|
61
|
+
let result;
|
|
62
|
+
try {
|
|
63
|
+
result = await callback;
|
|
64
|
+
} finally {
|
|
65
|
+
server.close();
|
|
66
|
+
}
|
|
67
|
+
if (result.state !== state) {
|
|
68
|
+
throw new Error("loopback: oauth state mismatch");
|
|
69
|
+
}
|
|
70
|
+
const exchange = await client.exchangeOauthCode({
|
|
71
|
+
code: result.code,
|
|
72
|
+
code_verifier: pkce.verifier
|
|
73
|
+
});
|
|
74
|
+
return { exchange };
|
|
75
|
+
}
|
|
76
|
+
async function listenForCallback(timeoutMs) {
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
const server = createServer();
|
|
79
|
+
const callback = new Promise((res, rej) => {
|
|
80
|
+
const timer = setTimeout(() => {
|
|
81
|
+
rej(new Error("loopback: callback timed out"));
|
|
82
|
+
server.close();
|
|
83
|
+
}, timeoutMs);
|
|
84
|
+
server.once("error", (e) => {
|
|
85
|
+
clearTimeout(timer);
|
|
86
|
+
rej(e);
|
|
87
|
+
});
|
|
88
|
+
server.on("request", (req, resp) => {
|
|
89
|
+
try {
|
|
90
|
+
const reqUrl = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
91
|
+
const code = reqUrl.searchParams.get("code");
|
|
92
|
+
const state = reqUrl.searchParams.get("state");
|
|
93
|
+
resp.writeHead(200, {
|
|
94
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
95
|
+
"Connection": "close"
|
|
96
|
+
});
|
|
97
|
+
resp.end(SUCCESS_HTML);
|
|
98
|
+
if (!code) return rej(new Error("loopback: callback missing code"));
|
|
99
|
+
if (!state) return rej(new Error("loopback: callback missing state"));
|
|
100
|
+
clearTimeout(timer);
|
|
101
|
+
res({ code, state });
|
|
102
|
+
} catch (e) {
|
|
103
|
+
clearTimeout(timer);
|
|
104
|
+
rej(e);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
server.listen(0, "127.0.0.1", () => {
|
|
109
|
+
const addr = server.address();
|
|
110
|
+
resolve({ port: addr.port, server, callback });
|
|
111
|
+
});
|
|
112
|
+
server.once("error", reject);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export { loopbackLogin };
|
|
117
|
+
//# sourceMappingURL=loopback.js.map
|
|
118
|
+
//# sourceMappingURL=loopback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/oauth.ts","../src/loopback.ts"],"names":[],"mappings":"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","file":"loopback.js","sourcesContent":["import type { BuildOauthInitUrlOptions, PkceChallenge } from './client-types';\n\nfunction bytesToUrlSafeBase64(bytes: Uint8Array): string {\n let bin = '';\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i] as number);\n return btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction randomBytes(length: number): Uint8Array {\n const buf = new Uint8Array(length);\n globalThis.crypto.getRandomValues(buf);\n return buf;\n}\n\nexport async function generatePkceChallenge(): Promise<PkceChallenge> {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) throw new Error('crypto.subtle not available; cannot generate PKCE challenge');\n\n const verifier = bytesToUrlSafeBase64(randomBytes(48));\n const hash = await subtle.digest('SHA-256', new TextEncoder().encode(verifier));\n const challenge = bytesToUrlSafeBase64(new Uint8Array(hash));\n\n return { verifier, challenge, method: 'S256' };\n}\n\nexport function generateOauthState(): string {\n return bytesToUrlSafeBase64(randomBytes(24));\n}\n\nexport function buildOauthInitUrl(opts: BuildOauthInitUrlOptions): string {\n const base = opts.baseUrl.replace(/\\/$/, '');\n const params = new URLSearchParams({\n product: opts.product,\n redirect_uri: opts.redirectUri,\n code_challenge: opts.codeChallenge,\n code_challenge_method: opts.codeChallengeMethod ?? 'S256',\n });\n if (opts.state) params.set('state', opts.state);\n\n return `${base}/auth/${opts.provider}?${params.toString()}`;\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { AddressInfo } from 'node:net';\nimport { BillingClient } from './client';\nimport type { OauthExchangeResponse, OauthProvider } from './client-types';\nimport { buildOauthInitUrl, generateOauthState, generatePkceChallenge } from './oauth';\n\nconst SUCCESS_HTML = `<!doctype html><meta charset=utf-8><title>Sign in complete</title><style>body{font-family:-apple-system,system-ui,sans-serif;background:#08080b;color:#e6e6ec;display:grid;place-items:center;height:100vh;margin:0}</style><h1>You can close this tab.</h1>`;\n\nexport interface LoopbackLoginOptions {\n provider: OauthProvider;\n product: string;\n /** Caller-controlled browser opener. Receives the OAuth init URL. */\n openBrowser: (url: string) => void | Promise<void>;\n /** Wall-clock timeout for the callback (default: 300 s). */\n timeoutMs?: number;\n}\n\nexport interface LoopbackOutcome {\n exchange: OauthExchangeResponse;\n}\n\n/**\n * Desktop loopback PKCE OAuth flow for Node-based consumers.\n *\n * Binds a transient HTTP server on `127.0.0.1`, opens the system browser, waits\n * for the provider redirect, exchanges the code for an access token through the\n * SDK and stores it on the supplied client.\n */\nexport async function loopbackLogin(\n client: BillingClient,\n opts: LoopbackLoginOptions,\n): Promise<LoopbackOutcome> {\n const pkce = await generatePkceChallenge();\n const state = generateOauthState();\n\n const { port, server, callback } = await listenForCallback(opts.timeoutMs ?? 300_000);\n\n const redirectUri = `http://127.0.0.1:${port}/cb`;\n const authUrl = buildOauthInitUrl({\n baseUrl: client.getBaseUrl(),\n provider: opts.provider,\n product: opts.product,\n redirectUri,\n codeChallenge: pkce.challenge,\n codeChallengeMethod: pkce.method,\n state,\n });\n\n try {\n await opts.openBrowser(authUrl);\n } catch (e) {\n server.close();\n throw new Error(`loopback: open browser failed — ${(e as Error).message}`, { cause: e });\n }\n\n let result: { code: string; state: string };\n try {\n result = await callback;\n } finally {\n server.close();\n }\n\n if (result.state !== state) {\n throw new Error('loopback: oauth state mismatch');\n }\n\n const exchange = await client.exchangeOauthCode({\n code: result.code,\n code_verifier: pkce.verifier,\n });\n\n return { exchange };\n}\n\ninterface ListenResult {\n port: number;\n server: ReturnType<typeof createServer>;\n callback: Promise<{ code: string; state: string }>;\n}\n\nasync function listenForCallback(timeoutMs: number): Promise<ListenResult> {\n return new Promise((resolve, reject) => {\n const server = createServer();\n\n const callback = new Promise<{ code: string; state: string }>((res, rej) => {\n const timer = setTimeout(() => {\n rej(new Error('loopback: callback timed out'));\n server.close();\n }, timeoutMs);\n\n server.once('error', (e) => {\n clearTimeout(timer);\n rej(e);\n });\n\n server.on('request', (req: IncomingMessage, resp: ServerResponse) => {\n try {\n const reqUrl = new URL(req.url ?? '/', 'http://127.0.0.1');\n const code = reqUrl.searchParams.get('code');\n const state = reqUrl.searchParams.get('state');\n\n resp.writeHead(200, {\n 'Content-Type': 'text/html; charset=utf-8',\n 'Connection': 'close',\n });\n resp.end(SUCCESS_HTML);\n\n if (!code) return rej(new Error('loopback: callback missing code'));\n if (!state) return rej(new Error('loopback: callback missing state'));\n\n clearTimeout(timer);\n res({ code, state });\n } catch (e) {\n clearTimeout(timer);\n rej(e as Error);\n }\n });\n });\n\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address() as AddressInfo;\n resolve({ port: addr.port, server, callback });\n });\n\n server.once('error', reject);\n });\n}\n"]}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { BillingClient } from './client.js';
|
|
2
|
+
import { C as Customer, s as OauthExchangeResponse } from './client-types-CtRkHWna.js';
|
|
3
|
+
import { LoopbackOutcome } from './loopback.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Thin wrapper around `keytar` for desktop apps. Consumers install `keytar` as
|
|
7
|
+
* an optional dependency; this module dynamically imports it so server-side
|
|
8
|
+
* bundles never see it.
|
|
9
|
+
*/
|
|
10
|
+
interface TokenKeyringOptions {
|
|
11
|
+
service: string;
|
|
12
|
+
account: string;
|
|
13
|
+
}
|
|
14
|
+
declare class TokenKeyring {
|
|
15
|
+
private readonly service;
|
|
16
|
+
private readonly account;
|
|
17
|
+
constructor(opts: TokenKeyringOptions);
|
|
18
|
+
get(): Promise<string | null>;
|
|
19
|
+
set(value: string): Promise<void>;
|
|
20
|
+
delete(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare class SessionStore {
|
|
24
|
+
private readonly keyring;
|
|
25
|
+
constructor(keyring: TokenKeyring);
|
|
26
|
+
hydrate(client: BillingClient): Promise<boolean>;
|
|
27
|
+
persist(client: BillingClient, token: string): Promise<void>;
|
|
28
|
+
clear(client: BillingClient): Promise<void>;
|
|
29
|
+
hasToken(): Promise<boolean>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type AuthStatusState = {
|
|
33
|
+
state: 'loading';
|
|
34
|
+
} | {
|
|
35
|
+
state: 'guest';
|
|
36
|
+
} | {
|
|
37
|
+
state: 'authenticated';
|
|
38
|
+
customer: Customer;
|
|
39
|
+
licensed: boolean;
|
|
40
|
+
};
|
|
41
|
+
interface AuthControllerOptions {
|
|
42
|
+
client: BillingClient;
|
|
43
|
+
session: SessionStore;
|
|
44
|
+
product: string;
|
|
45
|
+
feature?: string;
|
|
46
|
+
/** Loopback flow used by `oauthLogin`. */
|
|
47
|
+
loopbackLogin: (provider: string) => Promise<LoopbackOutcome>;
|
|
48
|
+
/** Override the runtime license check (e.g. cache, custom feature key). */
|
|
49
|
+
checkLicense?: (client: BillingClient) => Promise<boolean>;
|
|
50
|
+
}
|
|
51
|
+
declare class AuthController {
|
|
52
|
+
private readonly opts;
|
|
53
|
+
private listeners;
|
|
54
|
+
private current;
|
|
55
|
+
constructor(opts: AuthControllerOptions);
|
|
56
|
+
subscribe(listener: (s: AuthStatusState) => void): () => void;
|
|
57
|
+
snapshot(): AuthStatusState;
|
|
58
|
+
private emit;
|
|
59
|
+
bootstrap(): Promise<void>;
|
|
60
|
+
refresh(): Promise<void>;
|
|
61
|
+
private runDefaultLicenseCheck;
|
|
62
|
+
requestOtp(email: string, deviceFp?: string): Promise<void>;
|
|
63
|
+
verifyOtp(email: string, code: string, deviceFp?: string): Promise<Customer>;
|
|
64
|
+
oauthLogin(provider: string): Promise<OauthExchangeResponse>;
|
|
65
|
+
logout(): Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { AuthController as A, SessionStore as S, TokenKeyring as T, type AuthControllerOptions as a, type AuthStatusState as b, type TokenKeyringOptions as c };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { BillingClient } from './client.cjs';
|
|
2
|
+
import { C as Customer, s as OauthExchangeResponse } from './client-types-CtRkHWna.cjs';
|
|
3
|
+
import { LoopbackOutcome } from './loopback.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Thin wrapper around `keytar` for desktop apps. Consumers install `keytar` as
|
|
7
|
+
* an optional dependency; this module dynamically imports it so server-side
|
|
8
|
+
* bundles never see it.
|
|
9
|
+
*/
|
|
10
|
+
interface TokenKeyringOptions {
|
|
11
|
+
service: string;
|
|
12
|
+
account: string;
|
|
13
|
+
}
|
|
14
|
+
declare class TokenKeyring {
|
|
15
|
+
private readonly service;
|
|
16
|
+
private readonly account;
|
|
17
|
+
constructor(opts: TokenKeyringOptions);
|
|
18
|
+
get(): Promise<string | null>;
|
|
19
|
+
set(value: string): Promise<void>;
|
|
20
|
+
delete(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare class SessionStore {
|
|
24
|
+
private readonly keyring;
|
|
25
|
+
constructor(keyring: TokenKeyring);
|
|
26
|
+
hydrate(client: BillingClient): Promise<boolean>;
|
|
27
|
+
persist(client: BillingClient, token: string): Promise<void>;
|
|
28
|
+
clear(client: BillingClient): Promise<void>;
|
|
29
|
+
hasToken(): Promise<boolean>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type AuthStatusState = {
|
|
33
|
+
state: 'loading';
|
|
34
|
+
} | {
|
|
35
|
+
state: 'guest';
|
|
36
|
+
} | {
|
|
37
|
+
state: 'authenticated';
|
|
38
|
+
customer: Customer;
|
|
39
|
+
licensed: boolean;
|
|
40
|
+
};
|
|
41
|
+
interface AuthControllerOptions {
|
|
42
|
+
client: BillingClient;
|
|
43
|
+
session: SessionStore;
|
|
44
|
+
product: string;
|
|
45
|
+
feature?: string;
|
|
46
|
+
/** Loopback flow used by `oauthLogin`. */
|
|
47
|
+
loopbackLogin: (provider: string) => Promise<LoopbackOutcome>;
|
|
48
|
+
/** Override the runtime license check (e.g. cache, custom feature key). */
|
|
49
|
+
checkLicense?: (client: BillingClient) => Promise<boolean>;
|
|
50
|
+
}
|
|
51
|
+
declare class AuthController {
|
|
52
|
+
private readonly opts;
|
|
53
|
+
private listeners;
|
|
54
|
+
private current;
|
|
55
|
+
constructor(opts: AuthControllerOptions);
|
|
56
|
+
subscribe(listener: (s: AuthStatusState) => void): () => void;
|
|
57
|
+
snapshot(): AuthStatusState;
|
|
58
|
+
private emit;
|
|
59
|
+
bootstrap(): Promise<void>;
|
|
60
|
+
refresh(): Promise<void>;
|
|
61
|
+
private runDefaultLicenseCheck;
|
|
62
|
+
requestOtp(email: string, deviceFp?: string): Promise<void>;
|
|
63
|
+
verifyOtp(email: string, code: string, deviceFp?: string): Promise<Customer>;
|
|
64
|
+
oauthLogin(provider: string): Promise<OauthExchangeResponse>;
|
|
65
|
+
logout(): Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { AuthController as A, SessionStore as S, TokenKeyring as T, type AuthControllerOptions as a, type AuthStatusState as b, type TokenKeyringOptions as c };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akira-io/billing-js",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "TypeScript client for the Akira Billing API. Pricing, downloads, checkout helpers for landing pages and web apps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -57,6 +57,26 @@
|
|
|
57
57
|
"types": "./dist/vue.d.ts",
|
|
58
58
|
"import": "./dist/vue.js",
|
|
59
59
|
"require": "./dist/vue.cjs"
|
|
60
|
+
},
|
|
61
|
+
"./loopback": {
|
|
62
|
+
"types": "./dist/loopback.d.ts",
|
|
63
|
+
"import": "./dist/loopback.js",
|
|
64
|
+
"require": "./dist/loopback.cjs"
|
|
65
|
+
},
|
|
66
|
+
"./desktop": {
|
|
67
|
+
"types": "./dist/desktop.d.ts",
|
|
68
|
+
"import": "./dist/desktop.js",
|
|
69
|
+
"require": "./dist/desktop.cjs"
|
|
70
|
+
},
|
|
71
|
+
"./desktop/react": {
|
|
72
|
+
"types": "./dist/desktop-react.d.ts",
|
|
73
|
+
"import": "./dist/desktop-react.js",
|
|
74
|
+
"require": "./dist/desktop-react.cjs"
|
|
75
|
+
},
|
|
76
|
+
"./desktop/vue": {
|
|
77
|
+
"types": "./dist/desktop-vue.d.ts",
|
|
78
|
+
"import": "./dist/desktop-vue.js",
|
|
79
|
+
"require": "./dist/desktop-vue.cjs"
|
|
60
80
|
}
|
|
61
81
|
},
|
|
62
82
|
"peerDependencies": {
|