@drawbridge/drawbridge-utils 0.0.41 → 0.0.43

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 (47) hide show
  1. package/dist/ai.cjs +4 -4
  2. package/dist/ai.js +127 -8
  3. package/dist/axios.cjs +1 -1
  4. package/dist/axios.js +1 -1
  5. package/dist/cdn.cjs +1 -1
  6. package/dist/cdn.js +1 -1
  7. package/dist/circuit.cjs +1 -1
  8. package/dist/circuit.js +50 -3
  9. package/dist/encrypt.cjs +3 -3
  10. package/dist/encrypt.js +38 -5
  11. package/dist/fetch.cjs +1 -1
  12. package/dist/fetch.js +1 -1
  13. package/dist/http.cjs +1 -1
  14. package/dist/http.js +1 -1
  15. package/dist/nanoid.cjs +1 -1
  16. package/dist/nanoid.js +1 -1
  17. package/dist/oauth/index.cjs +196 -0
  18. package/dist/oauth/index.d.cts +231 -0
  19. package/dist/oauth/index.d.ts +231 -0
  20. package/dist/oauth/index.js +151 -0
  21. package/dist/oauth/server.cjs +377 -0
  22. package/dist/oauth/server.d.cts +387 -0
  23. package/dist/oauth/server.d.ts +387 -0
  24. package/dist/oauth/server.js +341 -0
  25. package/dist/orders.cjs +1 -1
  26. package/dist/orders.js +1 -1
  27. package/dist/redirect.cjs +1 -1
  28. package/dist/redirect.js +1 -1
  29. package/dist/shopify.cjs +5 -5
  30. package/dist/shopify.js +46 -11
  31. package/dist/slugify.cjs +1 -1
  32. package/dist/slugify.js +1 -1
  33. package/dist/token.cjs +1 -1
  34. package/dist/token.js +21 -5
  35. package/dist/transactions.cjs +1 -1
  36. package/dist/transactions.js +108 -4
  37. package/dist/upload.cjs +1 -1
  38. package/dist/upload.js +1 -1
  39. package/package.json +20 -4
  40. package/dist/chunk-2DRAIKGZ.js +0 -38
  41. package/dist/chunk-6HH36OK6.js +0 -54
  42. package/dist/chunk-JT2PAZAZ.js +0 -113
  43. package/dist/chunk-OS2AHUWX.js +0 -27
  44. package/dist/oauth.cjs +0 -94
  45. package/dist/oauth.d.cts +0 -129
  46. package/dist/oauth.d.ts +0 -129
  47. package/dist/oauth.js +0 -70
package/dist/ai.cjs CHANGED
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
16
16
  };
17
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
18
 
19
- // ai.js
19
+ // lib/ai.js
20
20
  var ai_exports = {};
21
21
  __export(ai_exports, {
22
22
  MARKUP: () => MARKUP,
@@ -31,7 +31,7 @@ __export(ai_exports, {
31
31
  module.exports = __toCommonJS(ai_exports);
32
32
  var import_genai = require("@google/genai");
33
33
 
34
- // circuit.js
34
+ // lib/circuit.js
35
35
  var CLOSED = "CLOSED";
36
36
  var OPEN = "OPEN";
37
37
  var HALF_OPEN = "HALF_OPEN";
@@ -82,7 +82,7 @@ var circuit = ({
82
82
  };
83
83
  };
84
84
 
85
- // transactions.js
85
+ // lib/transactions.js
86
86
  var import_drawbridge_telemetry = require("@drawbridge/drawbridge-telemetry");
87
87
  var insertTransaction = async ({
88
88
  db,
@@ -155,7 +155,7 @@ var debit = async ({
155
155
  });
156
156
  };
157
157
 
158
- // ai.js
158
+ // lib/ai.js
159
159
  var google_client = new import_genai.GoogleGenAI({
160
160
  apiKey: process.env.GOOGLE_API_KEY
161
161
  });
package/dist/ai.js CHANGED
@@ -1,12 +1,131 @@
1
- import {
2
- debit
3
- } from "./chunk-JT2PAZAZ.js";
4
- import {
5
- circuit
6
- } from "./chunk-6HH36OK6.js";
7
-
8
- // ai.js
1
+ // lib/ai.js
9
2
  import { GoogleGenAI } from "@google/genai";
3
+
4
+ // lib/circuit.js
5
+ var CLOSED = "CLOSED";
6
+ var OPEN = "OPEN";
7
+ var HALF_OPEN = "HALF_OPEN";
8
+ var circuit = ({
9
+ name,
10
+ threshold = 5,
11
+ timeout = 3e4
12
+ }) => {
13
+ let state = CLOSED;
14
+ let failures = 0;
15
+ let openedAt = null;
16
+ const trip = () => {
17
+ state = OPEN;
18
+ openedAt = Date.now();
19
+ console.error(`Circuit breaker OPEN: ${name}`);
20
+ };
21
+ const reset = () => {
22
+ state = CLOSED;
23
+ failures = 0;
24
+ openedAt = null;
25
+ console.log(`Circuit breaker CLOSED: ${name}`);
26
+ };
27
+ return async (fn) => {
28
+ if (state === OPEN) {
29
+ if (Date.now() - openedAt >= timeout) {
30
+ state = HALF_OPEN;
31
+ } else {
32
+ const error = new Error(`${name} is temporarily unavailable`);
33
+ error.status = 503;
34
+ throw error;
35
+ }
36
+ }
37
+ try {
38
+ const result = await fn();
39
+ if (state === HALF_OPEN) {
40
+ reset();
41
+ } else {
42
+ failures = 0;
43
+ }
44
+ return result;
45
+ } catch (error) {
46
+ failures++;
47
+ if (state === HALF_OPEN || failures >= threshold) {
48
+ trip();
49
+ }
50
+ throw error;
51
+ }
52
+ };
53
+ };
54
+
55
+ // lib/transactions.js
56
+ import { currentTraceId } from "@drawbridge/drawbridge-telemetry";
57
+ var insertTransaction = async ({
58
+ db,
59
+ user,
60
+ type,
61
+ category,
62
+ source,
63
+ amount,
64
+ _id,
65
+ stripeInvoiceId,
66
+ stripeEventId,
67
+ session,
68
+ ...rest
69
+ }) => {
70
+ var _a;
71
+ const beforeRaw = (_a = user == null ? void 0 : user.balance) == null ? void 0 : _a[type];
72
+ const balance = typeof beforeRaw === "number" ? { before: beforeRaw, after: beforeRaw + amount } : void 0;
73
+ const trace = currentTraceId();
74
+ await db.create({
75
+ authenticated: user,
76
+ collection: "transaction",
77
+ data: {
78
+ ..._id && { _id },
79
+ user: user == null ? void 0 : user.id,
80
+ type,
81
+ category,
82
+ source,
83
+ amount,
84
+ ...balance && { balance },
85
+ ...trace && { trace },
86
+ ...rest,
87
+ ...stripeInvoiceId && { stripeInvoiceId },
88
+ ...stripeEventId && { stripeEventId }
89
+ },
90
+ ...session && { options: { session } }
91
+ });
92
+ };
93
+ var debit = async ({
94
+ db,
95
+ user,
96
+ amount,
97
+ type,
98
+ category,
99
+ source,
100
+ stripeInvoiceId,
101
+ stripeEventId,
102
+ session,
103
+ ...rest
104
+ }) => {
105
+ if (!Number.isInteger(amount) || amount <= 0) {
106
+ throw new Error(`debit() requires a positive integer amount, got ${amount}`);
107
+ }
108
+ if (!type) {
109
+ throw new Error('debit() requires a type (e.g., "ai")');
110
+ }
111
+ if (!source) {
112
+ throw new Error('debit() requires a source ("system" | "admin" | "user")');
113
+ }
114
+ await insertTransaction({
115
+ db,
116
+ user,
117
+ type,
118
+ category,
119
+ source,
120
+ amount: -amount,
121
+ stripeInvoiceId,
122
+ stripeEventId,
123
+ session,
124
+ ...rest
125
+ });
126
+ };
127
+
128
+ // lib/ai.js
10
129
  var google_client = new GoogleGenAI({
11
130
  apiKey: process.env.GOOGLE_API_KEY
12
131
  });
package/dist/axios.cjs CHANGED
@@ -26,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  ));
27
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
28
 
29
- // axios.js
29
+ // lib/axios.js
30
30
  var axios_exports = {};
31
31
  __export(axios_exports, {
32
32
  axios: () => axios,
package/dist/axios.js CHANGED
@@ -1,4 +1,4 @@
1
- // axios.js
1
+ // lib/axios.js
2
2
  import axiosLib from "axios";
3
3
  import dns from "dns";
4
4
  import https from "https";
package/dist/cdn.cjs CHANGED
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
16
16
  };
17
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
18
 
19
- // cdn.js
19
+ // lib/cdn.js
20
20
  var cdn_exports = {};
21
21
  __export(cdn_exports, {
22
22
  cdnShopify: () => cdnShopify,
package/dist/cdn.js CHANGED
@@ -1,4 +1,4 @@
1
- // cdn.js
1
+ // lib/cdn.js
2
2
  var cdnSrc = (asset, size, timestamp) => {
3
3
  var _a;
4
4
  const src = (_a = asset == null ? void 0 : asset.sizes) == null ? void 0 : _a[size];
package/dist/circuit.cjs CHANGED
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
16
16
  };
17
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
18
 
19
- // circuit.js
19
+ // lib/circuit.js
20
20
  var circuit_exports = {};
21
21
  __export(circuit_exports, {
22
22
  circuit: () => circuit
package/dist/circuit.js CHANGED
@@ -1,6 +1,53 @@
1
- import {
2
- circuit
3
- } from "./chunk-6HH36OK6.js";
1
+ // lib/circuit.js
2
+ var CLOSED = "CLOSED";
3
+ var OPEN = "OPEN";
4
+ var HALF_OPEN = "HALF_OPEN";
5
+ var circuit = ({
6
+ name,
7
+ threshold = 5,
8
+ timeout = 3e4
9
+ }) => {
10
+ let state = CLOSED;
11
+ let failures = 0;
12
+ let openedAt = null;
13
+ const trip = () => {
14
+ state = OPEN;
15
+ openedAt = Date.now();
16
+ console.error(`Circuit breaker OPEN: ${name}`);
17
+ };
18
+ const reset = () => {
19
+ state = CLOSED;
20
+ failures = 0;
21
+ openedAt = null;
22
+ console.log(`Circuit breaker CLOSED: ${name}`);
23
+ };
24
+ return async (fn) => {
25
+ if (state === OPEN) {
26
+ if (Date.now() - openedAt >= timeout) {
27
+ state = HALF_OPEN;
28
+ } else {
29
+ const error = new Error(`${name} is temporarily unavailable`);
30
+ error.status = 503;
31
+ throw error;
32
+ }
33
+ }
34
+ try {
35
+ const result = await fn();
36
+ if (state === HALF_OPEN) {
37
+ reset();
38
+ } else {
39
+ failures = 0;
40
+ }
41
+ return result;
42
+ } catch (error) {
43
+ failures++;
44
+ if (state === HALF_OPEN || failures >= threshold) {
45
+ trip();
46
+ }
47
+ throw error;
48
+ }
49
+ };
50
+ };
4
51
  export {
5
52
  circuit
6
53
  };
package/dist/encrypt.cjs CHANGED
@@ -26,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  ));
27
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
28
 
29
- // encrypt.js
29
+ // lib/encrypt.js
30
30
  var encrypt_exports = {};
31
31
  __export(encrypt_exports, {
32
32
  decrypt: () => decrypt,
@@ -35,14 +35,14 @@ __export(encrypt_exports, {
35
35
  module.exports = __toCommonJS(encrypt_exports);
36
36
  var import_crypto2 = __toESM(require("crypto"), 1);
37
37
 
38
- // token.js
38
+ // lib/token.js
39
39
  var import_crypto = __toESM(require("crypto"), 1);
40
40
  var generate = (bytes = 32, encoding = "base64url") => {
41
41
  const buf = import_crypto.default.randomBytes(bytes);
42
42
  return encoding ? buf.toString(encoding) : buf;
43
43
  };
44
44
 
45
- // encrypt.js
45
+ // lib/encrypt.js
46
46
  var ALGORITHM = "aes-256-gcm";
47
47
  var getKey = () => Buffer.from(process.env.ENCRYPT_CONNECTION_SECRET, "hex");
48
48
  var encrypt = (value) => {
package/dist/encrypt.js CHANGED
@@ -1,8 +1,41 @@
1
- import {
2
- decrypt,
3
- encrypt
4
- } from "./chunk-2DRAIKGZ.js";
5
- import "./chunk-OS2AHUWX.js";
1
+ // lib/encrypt.js
2
+ import crypto2 from "crypto";
3
+
4
+ // lib/token.js
5
+ import crypto from "crypto";
6
+ var generate = (bytes = 32, encoding = "base64url") => {
7
+ const buf = crypto.randomBytes(bytes);
8
+ return encoding ? buf.toString(encoding) : buf;
9
+ };
10
+
11
+ // lib/encrypt.js
12
+ var ALGORITHM = "aes-256-gcm";
13
+ var getKey = () => Buffer.from(process.env.ENCRYPT_CONNECTION_SECRET, "hex");
14
+ var encrypt = (value) => {
15
+ const iv = generate(12, null);
16
+ const cipher = crypto2.createCipheriv(ALGORITHM, getKey(), iv);
17
+ const data = Buffer.concat([
18
+ cipher.update(JSON.stringify(value), "utf8"),
19
+ cipher.final()
20
+ ]);
21
+ const tag = cipher.getAuthTag();
22
+ return [iv, tag, data].map((b) => b.toString("hex")).join(":");
23
+ };
24
+ var decrypt = (value) => {
25
+ if (typeof value !== "string") return value;
26
+ const [ivHex, tagHex, dataHex] = value.split(":");
27
+ const decipher = crypto2.createDecipheriv(
28
+ ALGORITHM,
29
+ getKey(),
30
+ Buffer.from(ivHex, "hex")
31
+ );
32
+ decipher.setAuthTag(Buffer.from(tagHex, "hex"));
33
+ const result = Buffer.concat([
34
+ decipher.update(Buffer.from(dataHex, "hex")),
35
+ decipher.final()
36
+ ]);
37
+ return JSON.parse(result.toString("utf8"));
38
+ };
6
39
  export {
7
40
  decrypt,
8
41
  encrypt
package/dist/fetch.cjs CHANGED
@@ -26,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  ));
27
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
28
 
29
- // fetch.js
29
+ // lib/fetch.js
30
30
  var fetch_exports = {};
31
31
  __export(fetch_exports, {
32
32
  queryString: () => queryString,
package/dist/fetch.js CHANGED
@@ -1,4 +1,4 @@
1
- // fetch.js
1
+ // lib/fetch.js
2
2
  import qs from "qs";
3
3
  var queryString = qs;
4
4
  var memoryToken = null;
package/dist/http.cjs CHANGED
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
16
16
  };
17
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
18
 
19
- // http.js
19
+ // lib/http.js
20
20
  var http_exports = {};
21
21
  __export(http_exports, {
22
22
  request: () => request
package/dist/http.js CHANGED
@@ -1,4 +1,4 @@
1
- // http.js
1
+ // lib/http.js
2
2
  var DEFAULT_TIMEOUT_MS = 15e3;
3
3
  var request = async ({
4
4
  body,
package/dist/nanoid.cjs CHANGED
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
16
16
  };
17
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
18
 
19
- // nanoid.js
19
+ // lib/nanoid.js
20
20
  var nanoid_exports = {};
21
21
  __export(nanoid_exports, {
22
22
  nanoid: () => nanoid,
package/dist/nanoid.js CHANGED
@@ -1,4 +1,4 @@
1
- // nanoid.js
1
+ // lib/nanoid.js
2
2
  import { customAlphabet } from "nanoid";
3
3
  var nanoid = customAlphabet("0123456789abcdefghijklmnopqrstuvwxyz", 8);
4
4
  var DEFAULT_MAX_RETRIES = 5;
@@ -0,0 +1,196 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // lib/oauth/index.js
30
+ var oauth_exports = {};
31
+ __export(oauth_exports, {
32
+ compare: () => compare,
33
+ createOAuthClient: () => createOAuthClient,
34
+ developer: () => developer,
35
+ generateToken: () => generateToken,
36
+ hashToken: () => hashToken,
37
+ intersect: () => intersect,
38
+ isDeveloperAllowed: () => isDeveloperAllowed,
39
+ parse: () => parse,
40
+ scopes: () => scopes,
41
+ validate: () => validate
42
+ });
43
+ module.exports = __toCommonJS(oauth_exports);
44
+
45
+ // lib/token.js
46
+ var import_crypto = __toESM(require("crypto"), 1);
47
+ var generate = (bytes = 32, encoding = "base64url") => {
48
+ const buf = import_crypto.default.randomBytes(bytes);
49
+ return encoding ? buf.toString(encoding) : buf;
50
+ };
51
+ var hash = (value, key) => {
52
+ if (!value) return null;
53
+ if (key) {
54
+ return import_crypto.default.createHmac("sha256", key).update(String(value)).digest("base64url");
55
+ }
56
+ return import_crypto.default.createHash("sha256").update(String(value)).digest("base64url");
57
+ };
58
+ var compare = (a, b) => {
59
+ if (typeof a !== "string" || typeof b !== "string") return false;
60
+ if (a.length !== b.length) return false;
61
+ return import_crypto.default.timingSafeEqual(
62
+ Buffer.from(a),
63
+ Buffer.from(b)
64
+ );
65
+ };
66
+
67
+ // lib/oauth/index.js
68
+ var scopes = [
69
+ "profile:read",
70
+ "profile:write",
71
+ "organization:read",
72
+ "organization:write",
73
+ "campaigns:read",
74
+ "campaigns:write",
75
+ "contacts:read",
76
+ "contacts:write",
77
+ "workflows:read",
78
+ "workflows:write",
79
+ "connections:read",
80
+ "connections:write",
81
+ "billing:read",
82
+ "billing:write",
83
+ "admin"
84
+ ];
85
+ var developer = [
86
+ "profile:read",
87
+ "organization:read",
88
+ "campaigns:read",
89
+ "campaigns:write",
90
+ "contacts:read",
91
+ "contacts:write",
92
+ "workflows:read",
93
+ "workflows:write",
94
+ "connections:read",
95
+ "connections:write"
96
+ ];
97
+ var parse = (raw) => {
98
+ if (!raw) return [];
99
+ if (Array.isArray(raw)) return raw;
100
+ return String(raw).split(/\s+/).filter(Boolean);
101
+ };
102
+ var validate = (scopes2) => {
103
+ const parsed = parse(scopes2);
104
+ const invalid = parsed.filter((scope) => !scopes2.includes(scope));
105
+ return {
106
+ invalid,
107
+ valid: invalid.length === 0
108
+ };
109
+ };
110
+ var intersect = (requested, allowed) => {
111
+ const r = parse(requested);
112
+ const a = parse(allowed);
113
+ return r.filter((scope) => a.includes(scope));
114
+ };
115
+ var isDeveloperAllowed = (scope) => developer.includes(scope);
116
+ var hashToken = (raw) => hash(raw, process.env.OAUTH_TOKEN_HMAC_KEY);
117
+ var generateToken = () => generate(32, "base64url");
118
+ var REFRESH_LEAD_SECONDS = 60;
119
+ var createOAuthClient = ({
120
+ clientId,
121
+ clientSecret,
122
+ scopes: scopes2 = [],
123
+ tokenUri
124
+ }) => {
125
+ if (!clientId) throw new Error("createOAuthClient: clientId required");
126
+ if (!clientSecret) throw new Error("createOAuthClient: clientSecret required");
127
+ if (!tokenUri) throw new Error("createOAuthClient: tokenUri required");
128
+ let cached = null;
129
+ let pending = null;
130
+ const isFresh = () => {
131
+ if (!cached) return false;
132
+ const now = Math.floor(Date.now() / 1e3);
133
+ return cached.expiresAt - REFRESH_LEAD_SECONDS > now;
134
+ };
135
+ const fetchToken = async () => {
136
+ const params = new URLSearchParams();
137
+ params.set("grant_type", "client_credentials");
138
+ if (scopes2.length > 0) {
139
+ params.set("scope", scopes2.join(" "));
140
+ }
141
+ const basic = Buffer.from(clientId + ":" + clientSecret).toString("base64");
142
+ const response = await fetch(
143
+ tokenUri,
144
+ {
145
+ body: params.toString(),
146
+ headers: {
147
+ "authorization": "Basic " + basic,
148
+ "content-type": "application/x-www-form-urlencoded"
149
+ },
150
+ method: "POST"
151
+ }
152
+ );
153
+ if (!response.ok) {
154
+ const text = await response.text();
155
+ throw new Error("createOAuthClient: token fetch failed (" + response.status + "): " + text);
156
+ }
157
+ const body = await response.json();
158
+ cached = {
159
+ accessToken: body.access_token,
160
+ expiresAt: Math.floor(Date.now() / 1e3) + Number(body.expires_in || 3600),
161
+ scope: body.scope
162
+ };
163
+ return cached.accessToken;
164
+ };
165
+ const refresh = () => {
166
+ if (pending) return pending;
167
+ pending = fetchToken().finally(() => {
168
+ pending = null;
169
+ });
170
+ return pending;
171
+ };
172
+ return {
173
+ token: async () => {
174
+ if (isFresh()) return cached.accessToken;
175
+ return refresh();
176
+ },
177
+ // Force a refresh on the next call. Use this when a request returns 401
178
+ // before the cached token's expiry — the server may have revoked it.
179
+ invalidate: () => {
180
+ cached = null;
181
+ }
182
+ };
183
+ };
184
+ // Annotate the CommonJS export names for ESM import in node:
185
+ 0 && (module.exports = {
186
+ compare,
187
+ createOAuthClient,
188
+ developer,
189
+ generateToken,
190
+ hashToken,
191
+ intersect,
192
+ isDeveloperAllowed,
193
+ parse,
194
+ scopes,
195
+ validate
196
+ });