@akira-io/billing-js 0.2.0 → 0.3.2

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.
Files changed (45) hide show
  1. package/dist/{client-types-CtRkHWna.d.cts → client-types-BRHIoFm6.d.cts} +1 -0
  2. package/dist/{client-types-CtRkHWna.d.ts → client-types-BRHIoFm6.d.ts} +1 -0
  3. package/dist/client.cjs +6 -0
  4. package/dist/client.cjs.map +1 -1
  5. package/dist/client.d.cts +3 -1
  6. package/dist/client.d.ts +3 -1
  7. package/dist/client.js +6 -0
  8. package/dist/client.js.map +1 -1
  9. package/dist/desktop-react.cjs +26 -0
  10. package/dist/desktop-react.cjs.map +1 -0
  11. package/dist/desktop-react.d.cts +17 -0
  12. package/dist/desktop-react.d.ts +17 -0
  13. package/dist/desktop-react.js +24 -0
  14. package/dist/desktop-react.js.map +1 -0
  15. package/dist/desktop-vue.cjs +29 -0
  16. package/dist/desktop-vue.cjs.map +1 -0
  17. package/dist/desktop-vue.d.cts +18 -0
  18. package/dist/desktop-vue.d.ts +18 -0
  19. package/dist/desktop-vue.js +27 -0
  20. package/dist/desktop-vue.js.map +1 -0
  21. package/dist/desktop.cjs +198 -0
  22. package/dist/desktop.cjs.map +1 -0
  23. package/dist/desktop.d.cts +19 -0
  24. package/dist/desktop.d.ts +19 -0
  25. package/dist/desktop.js +191 -0
  26. package/dist/desktop.js.map +1 -0
  27. package/dist/index.cjs +6 -0
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +6 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/license.d.cts +1 -1
  34. package/dist/license.d.ts +1 -1
  35. package/dist/loopback.cjs +120 -0
  36. package/dist/loopback.cjs.map +1 -0
  37. package/dist/loopback.d.cts +24 -0
  38. package/dist/loopback.d.ts +24 -0
  39. package/dist/loopback.js +118 -0
  40. package/dist/loopback.js.map +1 -0
  41. package/dist/oauth.d.cts +1 -1
  42. package/dist/oauth.d.ts +1 -1
  43. package/dist/use-auth-BaAeVSZO.d.ts +68 -0
  44. package/dist/use-auth-Dbol539E.d.cts +68 -0
  45. package/package.json +21 -1
@@ -0,0 +1,198 @@
1
+ 'use strict';
2
+
3
+ var child_process = require('child_process');
4
+ var crypto = require('crypto');
5
+ var os = require('os');
6
+
7
+ // src/desktop/checkout.ts
8
+ function checkoutUrl(baseUrl, product) {
9
+ return `${baseUrl.replace(/\/$/, "")}/plans?product=${encodeURIComponent(product)}`;
10
+ }
11
+ function openBrowser(url) {
12
+ return new Promise((resolve, reject) => {
13
+ let cmd;
14
+ let args;
15
+ switch (process.platform) {
16
+ case "darwin":
17
+ cmd = "open";
18
+ args = [url];
19
+ break;
20
+ case "win32":
21
+ cmd = "rundll32";
22
+ args = ["url.dll,FileProtocolHandler", url];
23
+ break;
24
+ default:
25
+ cmd = "xdg-open";
26
+ args = [url];
27
+ }
28
+ const child = child_process.spawn(cmd, args, { stdio: "ignore", detached: true });
29
+ child.once("error", reject);
30
+ child.unref();
31
+ resolve();
32
+ });
33
+ }
34
+ async function machineId() {
35
+ const dyn = new Function("m", "return import(m)");
36
+ try {
37
+ const mod = await dyn("node-machine-id").catch(() => null);
38
+ if (mod?.machineIdSync) return mod.machineIdSync(true);
39
+ } catch {
40
+ }
41
+ return os.hostname();
42
+ }
43
+ async function deviceFingerprint(appVersion) {
44
+ const id = await machineId();
45
+ const plat = os.platform();
46
+ const hash = crypto.createHash("sha256");
47
+ hash.update(id);
48
+ hash.update("::");
49
+ hash.update(plat);
50
+ hash.update("::");
51
+ hash.update(appVersion);
52
+ return {
53
+ fingerprint: hash.digest("hex"),
54
+ platform: plat,
55
+ app_version: appVersion
56
+ };
57
+ }
58
+
59
+ // src/desktop/keyring.ts
60
+ async function loadKeytar() {
61
+ const dyn = new Function("m", "return import(m)");
62
+ const mod = await dyn("keytar").catch(() => null);
63
+ if (!mod) throw new Error("TokenKeyring: install `keytar` to use the desktop keyring helper.");
64
+ return mod.default ?? mod;
65
+ }
66
+ var TokenKeyring = class {
67
+ service;
68
+ account;
69
+ constructor(opts) {
70
+ this.service = opts.service;
71
+ this.account = opts.account;
72
+ }
73
+ async get() {
74
+ const k = await loadKeytar();
75
+ return k.getPassword(this.service, this.account);
76
+ }
77
+ async set(value) {
78
+ const k = await loadKeytar();
79
+ await k.setPassword(this.service, this.account, value);
80
+ }
81
+ async delete() {
82
+ const k = await loadKeytar();
83
+ await k.deletePassword(this.service, this.account);
84
+ }
85
+ };
86
+
87
+ // src/desktop/session.ts
88
+ var SessionStore = class {
89
+ constructor(keyring) {
90
+ this.keyring = keyring;
91
+ }
92
+ keyring;
93
+ async hydrate(client) {
94
+ const token = await this.keyring.get();
95
+ if (!token) return false;
96
+ client.setCustomerToken(token);
97
+ return true;
98
+ }
99
+ async persist(client, token) {
100
+ await this.keyring.set(token);
101
+ client.setCustomerToken(token);
102
+ }
103
+ async clear(client) {
104
+ await this.keyring.delete();
105
+ client.setCustomerToken("");
106
+ }
107
+ async hasToken() {
108
+ const v = await this.keyring.get();
109
+ return !!v;
110
+ }
111
+ };
112
+
113
+ // src/desktop/use-auth.ts
114
+ var AuthController = class {
115
+ constructor(opts) {
116
+ this.opts = opts;
117
+ }
118
+ opts;
119
+ listeners = /* @__PURE__ */ new Set();
120
+ current = { state: "loading" };
121
+ subscribe(listener) {
122
+ this.listeners.add(listener);
123
+ listener(this.current);
124
+ return () => this.listeners.delete(listener);
125
+ }
126
+ snapshot() {
127
+ return this.current;
128
+ }
129
+ emit(next) {
130
+ this.current = next;
131
+ this.listeners.forEach((l) => l(next));
132
+ }
133
+ async bootstrap() {
134
+ await this.opts.session.hydrate(this.opts.client);
135
+ await this.refresh();
136
+ }
137
+ async refresh() {
138
+ if (!await this.opts.session.hasToken()) {
139
+ this.emit({ state: "guest" });
140
+ return;
141
+ }
142
+ try {
143
+ const customer = await this.opts.client.customerMe();
144
+ const licensed = this.opts.checkLicense ? await this.opts.checkLicense(this.opts.client) : await this.runDefaultLicenseCheck();
145
+ this.emit({ state: "authenticated", customer, licensed });
146
+ } catch (e) {
147
+ if (e.status === 401) {
148
+ await this.opts.session.clear(this.opts.client);
149
+ this.emit({ state: "guest" });
150
+ return;
151
+ }
152
+ throw e;
153
+ }
154
+ }
155
+ async runDefaultLicenseCheck() {
156
+ try {
157
+ const resp = await this.opts.client.licenseCheck({
158
+ product: this.opts.product,
159
+ feature: this.opts.feature ?? "general"
160
+ });
161
+ return resp.allowed;
162
+ } catch {
163
+ return false;
164
+ }
165
+ }
166
+ async requestOtp(email, deviceFp) {
167
+ await this.opts.client.requestOtp({ email, device_fp: deviceFp ?? "" });
168
+ }
169
+ async verifyOtp(email, code, deviceFp) {
170
+ const resp = await this.opts.client.verifyOtp({
171
+ email,
172
+ code,
173
+ device_fp: deviceFp ?? ""
174
+ });
175
+ await this.opts.session.persist(this.opts.client, resp.access_token);
176
+ await this.refresh();
177
+ return await this.opts.client.customerMe();
178
+ }
179
+ async oauthLogin(provider) {
180
+ const outcome = await this.opts.loopbackLogin(provider);
181
+ await this.opts.session.persist(this.opts.client, outcome.exchange.access_token);
182
+ await this.refresh();
183
+ return outcome.exchange;
184
+ }
185
+ async logout() {
186
+ await this.opts.session.clear(this.opts.client);
187
+ this.emit({ state: "guest" });
188
+ }
189
+ };
190
+
191
+ exports.AuthController = AuthController;
192
+ exports.SessionStore = SessionStore;
193
+ exports.TokenKeyring = TokenKeyring;
194
+ exports.checkoutUrl = checkoutUrl;
195
+ exports.deviceFingerprint = deviceFingerprint;
196
+ exports.openBrowser = openBrowser;
197
+ //# sourceMappingURL=desktop.cjs.map
198
+ //# sourceMappingURL=desktop.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/desktop/checkout.ts","../src/desktop/browser.ts","../src/desktop/fingerprint.ts","../src/desktop/keyring.ts","../src/desktop/session.ts","../src/desktop/use-auth.ts"],"names":["spawn","hostname","platform","createHash"],"mappings":";;;;;;;AACO,SAAS,WAAA,CAAY,SAAiB,OAAA,EAAyB;AAClE,EAAA,OAAO,CAAA,EAAG,QAAQ,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,eAAA,EAAkB,kBAAA,CAAmB,OAAO,CAAC,CAAA,CAAA;AACrF;ACAO,SAAS,YAAY,GAAA,EAA4B;AACpD,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACpC,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI,IAAA;AACJ,IAAA,QAAQ,QAAQ,QAAA;AAAU,MACtB,KAAK,QAAA;AACD,QAAA,GAAA,GAAM,MAAA;AACN,QAAA,IAAA,GAAO,CAAC,GAAG,CAAA;AACX,QAAA;AAAA,MACJ,KAAK,OAAA;AACD,QAAA,GAAA,GAAM,UAAA;AACN,QAAA,IAAA,GAAO,CAAC,+BAA+B,GAAG,CAAA;AAC1C,QAAA;AAAA,MACJ;AACI,QAAA,GAAA,GAAM,UAAA;AACN,QAAA,IAAA,GAAO,CAAC,GAAG,CAAA;AAAA;AAEnB,IAAA,MAAM,KAAA,GAAQA,oBAAM,GAAA,EAAK,IAAA,EAAM,EAAE,KAAA,EAAO,QAAA,EAAU,QAAA,EAAU,IAAA,EAAM,CAAA;AAClE,IAAA,KAAA,CAAM,IAAA,CAAK,SAAS,MAAM,CAAA;AAC1B,IAAA,KAAA,CAAM,KAAA,EAAM;AACZ,IAAA,OAAA,EAAQ;AAAA,EACZ,CAAC,CAAA;AACL;AChBA,eAAe,SAAA,GAA6B;AACxC,EAAA,MAAM,GAAA,GAAM,IAAI,QAAA,CAAS,GAAA,EAAK,kBAAkB,CAAA;AAChD,EAAA,IAAI;AACA,IAAA,MAAM,MAAO,MAAM,GAAA,CAAI,iBAAiB,CAAA,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA;AAC1D,IAAA,IAAI,GAAA,EAAK,aAAA,EAAe,OAAO,GAAA,CAAI,cAAc,IAAI,CAAA;AAAA,EACzD,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,OAAOC,WAAA,EAAS;AACpB;AAEA,eAAsB,kBAAkB,UAAA,EAAgD;AACpF,EAAA,MAAM,EAAA,GAAK,MAAM,SAAA,EAAU;AAC3B,EAAA,MAAM,OAAOC,WAAA,EAAS;AACtB,EAAA,MAAM,IAAA,GAAOC,kBAAW,QAAQ,CAAA;AAChC,EAAA,IAAA,CAAK,OAAO,EAAE,CAAA;AACd,EAAA,IAAA,CAAK,OAAO,IAAI,CAAA;AAChB,EAAA,IAAA,CAAK,OAAO,IAAI,CAAA;AAChB,EAAA,IAAA,CAAK,OAAO,IAAI,CAAA;AAChB,EAAA,IAAA,CAAK,OAAO,UAAU,CAAA;AACtB,EAAA,OAAO;AAAA,IACH,WAAA,EAAa,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA;AAAA,IAC9B,QAAA,EAAU,IAAA;AAAA,IACV,WAAA,EAAa;AAAA,GACjB;AACJ;;;AClBA,eAAe,UAAA,GAA8B;AAIzC,EAAA,MAAM,GAAA,GAAM,IAAI,QAAA,CAAS,GAAA,EAAK,kBAAkB,CAAA;AAChD,EAAA,MAAM,MAAO,MAAM,GAAA,CAAI,QAAQ,CAAA,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA;AACjD,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,MAAM,mEAAmE,CAAA;AAC7F,EAAA,OAAO,IAAI,OAAA,IAAY,GAAA;AAC3B;AAEO,IAAM,eAAN,MAAmB;AAAA,EACL,OAAA;AAAA,EACA,OAAA;AAAA,EAEjB,YAAY,IAAA,EAA2B;AACnC,IAAA,IAAA,CAAK,UAAU,IAAA,CAAK,OAAA;AACpB,IAAA,IAAA,CAAK,UAAU,IAAA,CAAK,OAAA;AAAA,EACxB;AAAA,EAEA,MAAM,GAAA,GAA8B;AAChC,IAAA,MAAM,CAAA,GAAI,MAAM,UAAA,EAAW;AAC3B,IAAA,OAAO,CAAA,CAAE,WAAA,CAAY,IAAA,CAAK,OAAA,EAAS,KAAK,OAAO,CAAA;AAAA,EACnD;AAAA,EAEA,MAAM,IAAI,KAAA,EAA8B;AACpC,IAAA,MAAM,CAAA,GAAI,MAAM,UAAA,EAAW;AAC3B,IAAA,MAAM,EAAE,WAAA,CAAY,IAAA,CAAK,OAAA,EAAS,IAAA,CAAK,SAAS,KAAK,CAAA;AAAA,EACzD;AAAA,EAEA,MAAM,MAAA,GAAwB;AAC1B,IAAA,MAAM,CAAA,GAAI,MAAM,UAAA,EAAW;AAC3B,IAAA,MAAM,CAAA,CAAE,cAAA,CAAe,IAAA,CAAK,OAAA,EAAS,KAAK,OAAO,CAAA;AAAA,EACrD;AACJ;;;AC9CO,IAAM,eAAN,MAAmB;AAAA,EACtB,YAA6B,OAAA,EAAuB;AAAvB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAAwB;AAAA,EAAxB,OAAA;AAAA,EAE7B,MAAM,QAAQ,MAAA,EAAyC;AACnD,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAA,EAAI;AACrC,IAAA,IAAI,CAAC,OAAO,OAAO,KAAA;AACnB,IAAA,MAAA,CAAO,iBAAiB,KAAK,CAAA;AAC7B,IAAA,OAAO,IAAA;AAAA,EACX;AAAA,EAEA,MAAM,OAAA,CAAQ,MAAA,EAAuB,KAAA,EAA8B;AAC/D,IAAA,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA;AAC5B,IAAA,MAAA,CAAO,iBAAiB,KAAK,CAAA;AAAA,EACjC;AAAA,EAEA,MAAM,MAAM,MAAA,EAAsC;AAC9C,IAAA,MAAM,IAAA,CAAK,QAAQ,MAAA,EAAO;AAC1B,IAAA,MAAA,CAAO,iBAAiB,EAAE,CAAA;AAAA,EAC9B;AAAA,EAEA,MAAM,QAAA,GAA6B;AAC/B,IAAA,MAAM,CAAA,GAAI,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAA,EAAI;AACjC,IAAA,OAAO,CAAC,CAAC,CAAA;AAAA,EACb;AACJ;;;ACNO,IAAM,iBAAN,MAAqB;AAAA,EAIxB,YAA6B,IAAA,EAA6B;AAA7B,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA,EAA8B;AAAA,EAA9B,IAAA;AAAA,EAHrB,SAAA,uBAAgB,GAAA,EAAkC;AAAA,EAClD,OAAA,GAA2B,EAAE,KAAA,EAAO,SAAA,EAAU;AAAA,EAItD,UAAU,QAAA,EAAoD;AAC1D,IAAA,IAAA,CAAK,SAAA,CAAU,IAAI,QAAQ,CAAA;AAC3B,IAAA,QAAA,CAAS,KAAK,OAAO,CAAA;AACrB,IAAA,OAAO,MAAM,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,QAAQ,CAAA;AAAA,EAC/C;AAAA,EAEA,QAAA,GAA4B;AACxB,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EAChB;AAAA,EAEQ,KAAK,IAAA,EAA6B;AACtC,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,IAAA,IAAA,CAAK,UAAU,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,EACzC;AAAA,EAEA,MAAM,SAAA,GAA2B;AAC7B,IAAA,MAAM,KAAK,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,IAAA,CAAK,KAAK,MAAM,CAAA;AAChD,IAAA,MAAM,KAAK,OAAA,EAAQ;AAAA,EACvB;AAAA,EAEA,MAAM,OAAA,GAAyB;AAC3B,IAAA,IAAI,CAAE,MAAM,IAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,UAAS,EAAI;AACvC,MAAA,IAAA,CAAK,IAAA,CAAK,EAAE,KAAA,EAAO,OAAA,EAAS,CAAA;AAC5B,MAAA;AAAA,IACJ;AACA,IAAA,IAAI;AACA,MAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,IAAA,CAAK,OAAO,UAAA,EAAW;AACnD,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,IAAA,CAAK,YAAA,GACrB,MAAM,IAAA,CAAK,IAAA,CAAK,YAAA,CAAa,IAAA,CAAK,IAAA,CAAK,MAAM,CAAA,GAC7C,MAAM,KAAK,sBAAA,EAAuB;AACxC,MAAA,IAAA,CAAK,KAAK,EAAE,KAAA,EAAO,eAAA,EAAiB,QAAA,EAAU,UAAU,CAAA;AAAA,IAC5D,SAAS,CAAA,EAAG;AACR,MAAA,IAAK,CAAA,CAA0B,WAAW,GAAA,EAAK;AAC3C,QAAA,MAAM,KAAK,IAAA,CAAK,OAAA,CAAQ,KAAA,CAAM,IAAA,CAAK,KAAK,MAAM,CAAA;AAC9C,QAAA,IAAA,CAAK,IAAA,CAAK,EAAE,KAAA,EAAO,OAAA,EAAS,CAAA;AAC5B,QAAA;AAAA,MACJ;AACA,MAAA,MAAM,CAAA;AAAA,IACV;AAAA,EACJ;AAAA,EAEA,MAAc,sBAAA,GAA2C;AACrD,IAAA,IAAI;AACA,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,IAAA,CAAK,OAAO,YAAA,CAAa;AAAA,QAC7C,OAAA,EAAS,KAAK,IAAA,CAAK,OAAA;AAAA,QACnB,OAAA,EAAS,IAAA,CAAK,IAAA,CAAK,OAAA,IAAW;AAAA,OACjC,CAAA;AACD,MAAA,OAAO,IAAA,CAAK,OAAA;AAAA,IAChB,CAAA,CAAA,MAAQ;AACJ,MAAA,OAAO,KAAA;AAAA,IACX;AAAA,EACJ;AAAA,EAEA,MAAM,UAAA,CAAW,KAAA,EAAe,QAAA,EAAkC;AAC9D,IAAA,MAAM,IAAA,CAAK,KAAK,MAAA,CAAO,UAAA,CAAW,EAAE,KAAA,EAAO,SAAA,EAAW,QAAA,IAAY,EAAA,EAAI,CAAA;AAAA,EAC1E;AAAA,EAEA,MAAM,SAAA,CAAU,KAAA,EAAe,IAAA,EAAc,QAAA,EAAsC;AAC/E,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,IAAA,CAAK,OAAO,SAAA,CAAU;AAAA,MAC1C,KAAA;AAAA,MACA,IAAA;AAAA,MACA,WAAW,QAAA,IAAY;AAAA,KAC1B,CAAA;AACD,IAAA,MAAM,IAAA,CAAK,KAAK,OAAA,CAAQ,OAAA,CAAQ,KAAK,IAAA,CAAK,MAAA,EAAQ,KAAK,YAAY,CAAA;AACnE,IAAA,MAAM,KAAK,OAAA,EAAQ;AACnB,IAAA,OAAQ,MAAM,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,UAAA,EAAW;AAAA,EAC9C;AAAA,EAEA,MAAM,WAAW,QAAA,EAAkD;AAC/D,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,IAAA,CAAK,cAAc,QAAQ,CAAA;AACtD,IAAA,MAAM,IAAA,CAAK,KAAK,OAAA,CAAQ,OAAA,CAAQ,KAAK,IAAA,CAAK,MAAA,EAAQ,OAAA,CAAQ,QAAA,CAAS,YAAY,CAAA;AAC/E,IAAA,MAAM,KAAK,OAAA,EAAQ;AACnB,IAAA,OAAO,OAAA,CAAQ,QAAA;AAAA,EACnB;AAAA,EAEA,MAAM,MAAA,GAAwB;AAC1B,IAAA,MAAM,KAAK,IAAA,CAAK,OAAA,CAAQ,KAAA,CAAM,IAAA,CAAK,KAAK,MAAM,CAAA;AAC9C,IAAA,IAAA,CAAK,IAAA,CAAK,EAAE,KAAA,EAAO,OAAA,EAAS,CAAA;AAAA,EAChC;AACJ","file":"desktop.cjs","sourcesContent":["/** Build the public checkout URL for a product on the billing site. */\nexport function checkoutUrl(baseUrl: string, product: string): string {\n return `${baseUrl.replace(/\\/$/, '')}/plans?product=${encodeURIComponent(product)}`;\n}\n","import { spawn } from 'node:child_process';\n\n/** Launch the system default browser. Node-only. */\nexport function openBrowser(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n let cmd: string;\n let args: string[];\n switch (process.platform) {\n case 'darwin':\n cmd = 'open';\n args = [url];\n break;\n case 'win32':\n cmd = 'rundll32';\n args = ['url.dll,FileProtocolHandler', url];\n break;\n default:\n cmd = 'xdg-open';\n args = [url];\n }\n const child = spawn(cmd, args, { stdio: 'ignore', detached: true });\n child.once('error', reject);\n child.unref();\n resolve();\n });\n}\n","import { createHash } from 'node:crypto';\nimport { hostname, platform } from 'node:os';\n\nexport interface DeviceFingerprint {\n fingerprint: string;\n platform: string;\n app_version: string;\n}\n\nasync function machineId(): Promise<string> {\n const dyn = new Function('m', 'return import(m)') as (m: string) => Promise<unknown>;\n try {\n const mod = (await dyn('node-machine-id').catch(() => null)) as { machineIdSync?: (orig?: boolean) => string } | null;\n if (mod?.machineIdSync) return mod.machineIdSync(true);\n } catch {\n // fallthrough\n }\n return hostname();\n}\n\nexport async function deviceFingerprint(appVersion: string): Promise<DeviceFingerprint> {\n const id = await machineId();\n const plat = platform();\n const hash = createHash('sha256');\n hash.update(id);\n hash.update('::');\n hash.update(plat);\n hash.update('::');\n hash.update(appVersion);\n return {\n fingerprint: hash.digest('hex'),\n platform: plat,\n app_version: appVersion,\n };\n}\n","/**\n * Thin wrapper around `keytar` for desktop apps. Consumers install `keytar` as\n * an optional dependency; this module dynamically imports it so server-side\n * bundles never see it.\n */\nexport interface TokenKeyringOptions {\n service: string;\n account: string;\n}\n\ntype Keytar = {\n getPassword: (service: string, account: string) => Promise<string | null>;\n setPassword: (service: string, account: string, password: string) => Promise<void>;\n deletePassword: (service: string, account: string) => Promise<boolean>;\n};\n\nasync function loadKeytar(): Promise<Keytar> {\n // Use Function constructor so tsup/typescript don't try to resolve the\n // optional module at build time. Consumers add `keytar` as a peer/optional\n // dependency.\n const dyn = new Function('m', 'return import(m)') as (m: string) => Promise<unknown>;\n const mod = (await dyn('keytar').catch(() => null)) as { default?: Keytar } | null;\n if (!mod) throw new Error('TokenKeyring: install `keytar` to use the desktop keyring helper.');\n return mod.default ?? (mod as unknown as Keytar);\n}\n\nexport class TokenKeyring {\n private readonly service: string;\n private readonly account: string;\n\n constructor(opts: TokenKeyringOptions) {\n this.service = opts.service;\n this.account = opts.account;\n }\n\n async get(): Promise<string | null> {\n const k = await loadKeytar();\n return k.getPassword(this.service, this.account);\n }\n\n async set(value: string): Promise<void> {\n const k = await loadKeytar();\n await k.setPassword(this.service, this.account, value);\n }\n\n async delete(): Promise<void> {\n const k = await loadKeytar();\n await k.deletePassword(this.service, this.account);\n }\n}\n","import { BillingClient } from '../client';\nimport { TokenKeyring } from './keyring';\n\nexport class SessionStore {\n constructor(private readonly keyring: TokenKeyring) {}\n\n async hydrate(client: BillingClient): Promise<boolean> {\n const token = await this.keyring.get();\n if (!token) return false;\n client.setCustomerToken(token);\n return true;\n }\n\n async persist(client: BillingClient, token: string): Promise<void> {\n await this.keyring.set(token);\n client.setCustomerToken(token);\n }\n\n async clear(client: BillingClient): Promise<void> {\n await this.keyring.delete();\n client.setCustomerToken('');\n }\n\n async hasToken(): Promise<boolean> {\n const v = await this.keyring.get();\n return !!v;\n }\n}\n","import type { BillingClient } from '../client';\nimport type { Customer, OauthExchangeResponse } from '../client-types';\nimport type { LoopbackOutcome } from '../loopback';\nimport type { SessionStore } from './session';\n\nexport type AuthStatusState =\n | { state: 'loading' }\n | { state: 'guest' }\n | { state: 'authenticated'; customer: Customer; licensed: boolean };\n\nexport interface AuthControllerOptions {\n client: BillingClient;\n session: SessionStore;\n product: string;\n feature?: string;\n /** Loopback flow used by `oauthLogin`. */\n loopbackLogin: (provider: string) => Promise<LoopbackOutcome>;\n /** Override the runtime license check (e.g. cache, custom feature key). */\n checkLicense?: (client: BillingClient) => Promise<boolean>;\n}\n\nexport class AuthController {\n private listeners = new Set<(s: AuthStatusState) => void>();\n private current: AuthStatusState = { state: 'loading' };\n\n constructor(private readonly opts: AuthControllerOptions) {}\n\n subscribe(listener: (s: AuthStatusState) => void): () => void {\n this.listeners.add(listener);\n listener(this.current);\n return () => this.listeners.delete(listener);\n }\n\n snapshot(): AuthStatusState {\n return this.current;\n }\n\n private emit(next: AuthStatusState): void {\n this.current = next;\n this.listeners.forEach((l) => l(next));\n }\n\n async bootstrap(): Promise<void> {\n await this.opts.session.hydrate(this.opts.client);\n await this.refresh();\n }\n\n async refresh(): Promise<void> {\n if (!(await this.opts.session.hasToken())) {\n this.emit({ state: 'guest' });\n return;\n }\n try {\n const customer = await this.opts.client.customerMe();\n const licensed = this.opts.checkLicense\n ? await this.opts.checkLicense(this.opts.client)\n : await this.runDefaultLicenseCheck();\n this.emit({ state: 'authenticated', customer, licensed });\n } catch (e) {\n if ((e as { status?: number }).status === 401) {\n await this.opts.session.clear(this.opts.client);\n this.emit({ state: 'guest' });\n return;\n }\n throw e;\n }\n }\n\n private async runDefaultLicenseCheck(): Promise<boolean> {\n try {\n const resp = await this.opts.client.licenseCheck({\n product: this.opts.product,\n feature: this.opts.feature ?? 'general',\n });\n return resp.allowed;\n } catch {\n return false;\n }\n }\n\n async requestOtp(email: string, deviceFp?: string): Promise<void> {\n await this.opts.client.requestOtp({ email, device_fp: deviceFp ?? '' });\n }\n\n async verifyOtp(email: string, code: string, deviceFp?: string): Promise<Customer> {\n const resp = await this.opts.client.verifyOtp({\n email,\n code,\n device_fp: deviceFp ?? '',\n });\n await this.opts.session.persist(this.opts.client, resp.access_token);\n await this.refresh();\n return (await this.opts.client.customerMe());\n }\n\n async oauthLogin(provider: string): Promise<OauthExchangeResponse> {\n const outcome = await this.opts.loopbackLogin(provider);\n await this.opts.session.persist(this.opts.client, outcome.exchange.access_token);\n await this.refresh();\n return outcome.exchange;\n }\n\n async logout(): Promise<void> {\n await this.opts.session.clear(this.opts.client);\n this.emit({ state: 'guest' });\n }\n}\n"]}
@@ -0,0 +1,19 @@
1
+ export { A as AuthController, a as AuthControllerOptions, b as AuthStatusState, S as SessionStore, T as TokenKeyring, c as TokenKeyringOptions } from './use-auth-Dbol539E.cjs';
2
+ import './client.cjs';
3
+ import './client-types-BRHIoFm6.cjs';
4
+ import './loopback.cjs';
5
+
6
+ /** Build the public checkout URL for a product on the billing site. */
7
+ declare function checkoutUrl(baseUrl: string, product: string): string;
8
+
9
+ /** Launch the system default browser. Node-only. */
10
+ declare function openBrowser(url: string): Promise<void>;
11
+
12
+ interface DeviceFingerprint {
13
+ fingerprint: string;
14
+ platform: string;
15
+ app_version: string;
16
+ }
17
+ declare function deviceFingerprint(appVersion: string): Promise<DeviceFingerprint>;
18
+
19
+ export { type DeviceFingerprint, checkoutUrl, deviceFingerprint, openBrowser };
@@ -0,0 +1,19 @@
1
+ export { A as AuthController, a as AuthControllerOptions, b as AuthStatusState, S as SessionStore, T as TokenKeyring, c as TokenKeyringOptions } from './use-auth-BaAeVSZO.js';
2
+ import './client.js';
3
+ import './client-types-BRHIoFm6.js';
4
+ import './loopback.js';
5
+
6
+ /** Build the public checkout URL for a product on the billing site. */
7
+ declare function checkoutUrl(baseUrl: string, product: string): string;
8
+
9
+ /** Launch the system default browser. Node-only. */
10
+ declare function openBrowser(url: string): Promise<void>;
11
+
12
+ interface DeviceFingerprint {
13
+ fingerprint: string;
14
+ platform: string;
15
+ app_version: string;
16
+ }
17
+ declare function deviceFingerprint(appVersion: string): Promise<DeviceFingerprint>;
18
+
19
+ export { type DeviceFingerprint, checkoutUrl, deviceFingerprint, openBrowser };
@@ -0,0 +1,191 @@
1
+ import { spawn } from 'child_process';
2
+ import { createHash } from 'crypto';
3
+ import { platform, hostname } from 'os';
4
+
5
+ // src/desktop/checkout.ts
6
+ function checkoutUrl(baseUrl, product) {
7
+ return `${baseUrl.replace(/\/$/, "")}/plans?product=${encodeURIComponent(product)}`;
8
+ }
9
+ function openBrowser(url) {
10
+ return new Promise((resolve, reject) => {
11
+ let cmd;
12
+ let args;
13
+ switch (process.platform) {
14
+ case "darwin":
15
+ cmd = "open";
16
+ args = [url];
17
+ break;
18
+ case "win32":
19
+ cmd = "rundll32";
20
+ args = ["url.dll,FileProtocolHandler", url];
21
+ break;
22
+ default:
23
+ cmd = "xdg-open";
24
+ args = [url];
25
+ }
26
+ const child = spawn(cmd, args, { stdio: "ignore", detached: true });
27
+ child.once("error", reject);
28
+ child.unref();
29
+ resolve();
30
+ });
31
+ }
32
+ async function machineId() {
33
+ const dyn = new Function("m", "return import(m)");
34
+ try {
35
+ const mod = await dyn("node-machine-id").catch(() => null);
36
+ if (mod?.machineIdSync) return mod.machineIdSync(true);
37
+ } catch {
38
+ }
39
+ return hostname();
40
+ }
41
+ async function deviceFingerprint(appVersion) {
42
+ const id = await machineId();
43
+ const plat = platform();
44
+ const hash = createHash("sha256");
45
+ hash.update(id);
46
+ hash.update("::");
47
+ hash.update(plat);
48
+ hash.update("::");
49
+ hash.update(appVersion);
50
+ return {
51
+ fingerprint: hash.digest("hex"),
52
+ platform: plat,
53
+ app_version: appVersion
54
+ };
55
+ }
56
+
57
+ // src/desktop/keyring.ts
58
+ async function loadKeytar() {
59
+ const dyn = new Function("m", "return import(m)");
60
+ const mod = await dyn("keytar").catch(() => null);
61
+ if (!mod) throw new Error("TokenKeyring: install `keytar` to use the desktop keyring helper.");
62
+ return mod.default ?? mod;
63
+ }
64
+ var TokenKeyring = class {
65
+ service;
66
+ account;
67
+ constructor(opts) {
68
+ this.service = opts.service;
69
+ this.account = opts.account;
70
+ }
71
+ async get() {
72
+ const k = await loadKeytar();
73
+ return k.getPassword(this.service, this.account);
74
+ }
75
+ async set(value) {
76
+ const k = await loadKeytar();
77
+ await k.setPassword(this.service, this.account, value);
78
+ }
79
+ async delete() {
80
+ const k = await loadKeytar();
81
+ await k.deletePassword(this.service, this.account);
82
+ }
83
+ };
84
+
85
+ // src/desktop/session.ts
86
+ var SessionStore = class {
87
+ constructor(keyring) {
88
+ this.keyring = keyring;
89
+ }
90
+ keyring;
91
+ async hydrate(client) {
92
+ const token = await this.keyring.get();
93
+ if (!token) return false;
94
+ client.setCustomerToken(token);
95
+ return true;
96
+ }
97
+ async persist(client, token) {
98
+ await this.keyring.set(token);
99
+ client.setCustomerToken(token);
100
+ }
101
+ async clear(client) {
102
+ await this.keyring.delete();
103
+ client.setCustomerToken("");
104
+ }
105
+ async hasToken() {
106
+ const v = await this.keyring.get();
107
+ return !!v;
108
+ }
109
+ };
110
+
111
+ // src/desktop/use-auth.ts
112
+ var AuthController = class {
113
+ constructor(opts) {
114
+ this.opts = opts;
115
+ }
116
+ opts;
117
+ listeners = /* @__PURE__ */ new Set();
118
+ current = { state: "loading" };
119
+ subscribe(listener) {
120
+ this.listeners.add(listener);
121
+ listener(this.current);
122
+ return () => this.listeners.delete(listener);
123
+ }
124
+ snapshot() {
125
+ return this.current;
126
+ }
127
+ emit(next) {
128
+ this.current = next;
129
+ this.listeners.forEach((l) => l(next));
130
+ }
131
+ async bootstrap() {
132
+ await this.opts.session.hydrate(this.opts.client);
133
+ await this.refresh();
134
+ }
135
+ async refresh() {
136
+ if (!await this.opts.session.hasToken()) {
137
+ this.emit({ state: "guest" });
138
+ return;
139
+ }
140
+ try {
141
+ const customer = await this.opts.client.customerMe();
142
+ const licensed = this.opts.checkLicense ? await this.opts.checkLicense(this.opts.client) : await this.runDefaultLicenseCheck();
143
+ this.emit({ state: "authenticated", customer, licensed });
144
+ } catch (e) {
145
+ if (e.status === 401) {
146
+ await this.opts.session.clear(this.opts.client);
147
+ this.emit({ state: "guest" });
148
+ return;
149
+ }
150
+ throw e;
151
+ }
152
+ }
153
+ async runDefaultLicenseCheck() {
154
+ try {
155
+ const resp = await this.opts.client.licenseCheck({
156
+ product: this.opts.product,
157
+ feature: this.opts.feature ?? "general"
158
+ });
159
+ return resp.allowed;
160
+ } catch {
161
+ return false;
162
+ }
163
+ }
164
+ async requestOtp(email, deviceFp) {
165
+ await this.opts.client.requestOtp({ email, device_fp: deviceFp ?? "" });
166
+ }
167
+ async verifyOtp(email, code, deviceFp) {
168
+ const resp = await this.opts.client.verifyOtp({
169
+ email,
170
+ code,
171
+ device_fp: deviceFp ?? ""
172
+ });
173
+ await this.opts.session.persist(this.opts.client, resp.access_token);
174
+ await this.refresh();
175
+ return await this.opts.client.customerMe();
176
+ }
177
+ async oauthLogin(provider) {
178
+ const outcome = await this.opts.loopbackLogin(provider);
179
+ await this.opts.session.persist(this.opts.client, outcome.exchange.access_token);
180
+ await this.refresh();
181
+ return outcome.exchange;
182
+ }
183
+ async logout() {
184
+ await this.opts.session.clear(this.opts.client);
185
+ this.emit({ state: "guest" });
186
+ }
187
+ };
188
+
189
+ export { AuthController, SessionStore, TokenKeyring, checkoutUrl, deviceFingerprint, openBrowser };
190
+ //# sourceMappingURL=desktop.js.map
191
+ //# sourceMappingURL=desktop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/desktop/checkout.ts","../src/desktop/browser.ts","../src/desktop/fingerprint.ts","../src/desktop/keyring.ts","../src/desktop/session.ts","../src/desktop/use-auth.ts"],"names":[],"mappings":"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","file":"desktop.js","sourcesContent":["/** Build the public checkout URL for a product on the billing site. */\nexport function checkoutUrl(baseUrl: string, product: string): string {\n return `${baseUrl.replace(/\\/$/, '')}/plans?product=${encodeURIComponent(product)}`;\n}\n","import { spawn } from 'node:child_process';\n\n/** Launch the system default browser. Node-only. */\nexport function openBrowser(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n let cmd: string;\n let args: string[];\n switch (process.platform) {\n case 'darwin':\n cmd = 'open';\n args = [url];\n break;\n case 'win32':\n cmd = 'rundll32';\n args = ['url.dll,FileProtocolHandler', url];\n break;\n default:\n cmd = 'xdg-open';\n args = [url];\n }\n const child = spawn(cmd, args, { stdio: 'ignore', detached: true });\n child.once('error', reject);\n child.unref();\n resolve();\n });\n}\n","import { createHash } from 'node:crypto';\nimport { hostname, platform } from 'node:os';\n\nexport interface DeviceFingerprint {\n fingerprint: string;\n platform: string;\n app_version: string;\n}\n\nasync function machineId(): Promise<string> {\n const dyn = new Function('m', 'return import(m)') as (m: string) => Promise<unknown>;\n try {\n const mod = (await dyn('node-machine-id').catch(() => null)) as { machineIdSync?: (orig?: boolean) => string } | null;\n if (mod?.machineIdSync) return mod.machineIdSync(true);\n } catch {\n // fallthrough\n }\n return hostname();\n}\n\nexport async function deviceFingerprint(appVersion: string): Promise<DeviceFingerprint> {\n const id = await machineId();\n const plat = platform();\n const hash = createHash('sha256');\n hash.update(id);\n hash.update('::');\n hash.update(plat);\n hash.update('::');\n hash.update(appVersion);\n return {\n fingerprint: hash.digest('hex'),\n platform: plat,\n app_version: appVersion,\n };\n}\n","/**\n * Thin wrapper around `keytar` for desktop apps. Consumers install `keytar` as\n * an optional dependency; this module dynamically imports it so server-side\n * bundles never see it.\n */\nexport interface TokenKeyringOptions {\n service: string;\n account: string;\n}\n\ntype Keytar = {\n getPassword: (service: string, account: string) => Promise<string | null>;\n setPassword: (service: string, account: string, password: string) => Promise<void>;\n deletePassword: (service: string, account: string) => Promise<boolean>;\n};\n\nasync function loadKeytar(): Promise<Keytar> {\n // Use Function constructor so tsup/typescript don't try to resolve the\n // optional module at build time. Consumers add `keytar` as a peer/optional\n // dependency.\n const dyn = new Function('m', 'return import(m)') as (m: string) => Promise<unknown>;\n const mod = (await dyn('keytar').catch(() => null)) as { default?: Keytar } | null;\n if (!mod) throw new Error('TokenKeyring: install `keytar` to use the desktop keyring helper.');\n return mod.default ?? (mod as unknown as Keytar);\n}\n\nexport class TokenKeyring {\n private readonly service: string;\n private readonly account: string;\n\n constructor(opts: TokenKeyringOptions) {\n this.service = opts.service;\n this.account = opts.account;\n }\n\n async get(): Promise<string | null> {\n const k = await loadKeytar();\n return k.getPassword(this.service, this.account);\n }\n\n async set(value: string): Promise<void> {\n const k = await loadKeytar();\n await k.setPassword(this.service, this.account, value);\n }\n\n async delete(): Promise<void> {\n const k = await loadKeytar();\n await k.deletePassword(this.service, this.account);\n }\n}\n","import { BillingClient } from '../client';\nimport { TokenKeyring } from './keyring';\n\nexport class SessionStore {\n constructor(private readonly keyring: TokenKeyring) {}\n\n async hydrate(client: BillingClient): Promise<boolean> {\n const token = await this.keyring.get();\n if (!token) return false;\n client.setCustomerToken(token);\n return true;\n }\n\n async persist(client: BillingClient, token: string): Promise<void> {\n await this.keyring.set(token);\n client.setCustomerToken(token);\n }\n\n async clear(client: BillingClient): Promise<void> {\n await this.keyring.delete();\n client.setCustomerToken('');\n }\n\n async hasToken(): Promise<boolean> {\n const v = await this.keyring.get();\n return !!v;\n }\n}\n","import type { BillingClient } from '../client';\nimport type { Customer, OauthExchangeResponse } from '../client-types';\nimport type { LoopbackOutcome } from '../loopback';\nimport type { SessionStore } from './session';\n\nexport type AuthStatusState =\n | { state: 'loading' }\n | { state: 'guest' }\n | { state: 'authenticated'; customer: Customer; licensed: boolean };\n\nexport interface AuthControllerOptions {\n client: BillingClient;\n session: SessionStore;\n product: string;\n feature?: string;\n /** Loopback flow used by `oauthLogin`. */\n loopbackLogin: (provider: string) => Promise<LoopbackOutcome>;\n /** Override the runtime license check (e.g. cache, custom feature key). */\n checkLicense?: (client: BillingClient) => Promise<boolean>;\n}\n\nexport class AuthController {\n private listeners = new Set<(s: AuthStatusState) => void>();\n private current: AuthStatusState = { state: 'loading' };\n\n constructor(private readonly opts: AuthControllerOptions) {}\n\n subscribe(listener: (s: AuthStatusState) => void): () => void {\n this.listeners.add(listener);\n listener(this.current);\n return () => this.listeners.delete(listener);\n }\n\n snapshot(): AuthStatusState {\n return this.current;\n }\n\n private emit(next: AuthStatusState): void {\n this.current = next;\n this.listeners.forEach((l) => l(next));\n }\n\n async bootstrap(): Promise<void> {\n await this.opts.session.hydrate(this.opts.client);\n await this.refresh();\n }\n\n async refresh(): Promise<void> {\n if (!(await this.opts.session.hasToken())) {\n this.emit({ state: 'guest' });\n return;\n }\n try {\n const customer = await this.opts.client.customerMe();\n const licensed = this.opts.checkLicense\n ? await this.opts.checkLicense(this.opts.client)\n : await this.runDefaultLicenseCheck();\n this.emit({ state: 'authenticated', customer, licensed });\n } catch (e) {\n if ((e as { status?: number }).status === 401) {\n await this.opts.session.clear(this.opts.client);\n this.emit({ state: 'guest' });\n return;\n }\n throw e;\n }\n }\n\n private async runDefaultLicenseCheck(): Promise<boolean> {\n try {\n const resp = await this.opts.client.licenseCheck({\n product: this.opts.product,\n feature: this.opts.feature ?? 'general',\n });\n return resp.allowed;\n } catch {\n return false;\n }\n }\n\n async requestOtp(email: string, deviceFp?: string): Promise<void> {\n await this.opts.client.requestOtp({ email, device_fp: deviceFp ?? '' });\n }\n\n async verifyOtp(email: string, code: string, deviceFp?: string): Promise<Customer> {\n const resp = await this.opts.client.verifyOtp({\n email,\n code,\n device_fp: deviceFp ?? '',\n });\n await this.opts.session.persist(this.opts.client, resp.access_token);\n await this.refresh();\n return (await this.opts.client.customerMe());\n }\n\n async oauthLogin(provider: string): Promise<OauthExchangeResponse> {\n const outcome = await this.opts.loopbackLogin(provider);\n await this.opts.session.persist(this.opts.client, outcome.exchange.access_token);\n await this.refresh();\n return outcome.exchange;\n }\n\n async logout(): Promise<void> {\n await this.opts.session.clear(this.opts.client);\n this.emit({ state: 'guest' });\n }\n}\n"]}
package/dist/index.cjs CHANGED
@@ -86,6 +86,12 @@ var BillingClient = class {
86
86
  setCustomerToken(token) {
87
87
  this.customerToken = token;
88
88
  }
89
+ getBaseUrl() {
90
+ return this.baseUrl;
91
+ }
92
+ getProductSlug() {
93
+ return this.productSlug;
94
+ }
89
95
  async requestOtp(payload) {
90
96
  await this.signed("POST", "/api/auth/customer/otp/request", payload);
91
97
  }