@drawbridge/drawbridge-utils 0.0.42 → 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.
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;
@@ -26,23 +26,23 @@ 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
- // oauth.js
29
+ // lib/oauth/index.js
30
30
  var oauth_exports = {};
31
31
  __export(oauth_exports, {
32
- DEVELOPER_ALLOWED_SCOPES: () => DEVELOPER_ALLOWED_SCOPES,
33
- SCOPES: () => SCOPES,
34
32
  compare: () => compare,
35
33
  createOAuthClient: () => createOAuthClient,
34
+ developer: () => developer,
36
35
  generateToken: () => generateToken,
37
36
  hashToken: () => hashToken,
38
37
  intersect: () => intersect,
39
38
  isDeveloperAllowed: () => isDeveloperAllowed,
40
39
  parse: () => parse,
40
+ scopes: () => scopes,
41
41
  validate: () => validate
42
42
  });
43
43
  module.exports = __toCommonJS(oauth_exports);
44
44
 
45
- // token.js
45
+ // lib/token.js
46
46
  var import_crypto = __toESM(require("crypto"), 1);
47
47
  var generate = (bytes = 32, encoding = "base64url") => {
48
48
  const buf = import_crypto.default.randomBytes(bytes);
@@ -64,8 +64,8 @@ var compare = (a, b) => {
64
64
  );
65
65
  };
66
66
 
67
- // oauth.js
68
- var SCOPES = [
67
+ // lib/oauth/index.js
68
+ var scopes = [
69
69
  "profile:read",
70
70
  "profile:write",
71
71
  "organization:read",
@@ -82,7 +82,7 @@ var SCOPES = [
82
82
  "billing:write",
83
83
  "admin"
84
84
  ];
85
- var DEVELOPER_ALLOWED_SCOPES = [
85
+ var developer = [
86
86
  "profile:read",
87
87
  "organization:read",
88
88
  "campaigns:read",
@@ -99,9 +99,9 @@ var parse = (raw) => {
99
99
  if (Array.isArray(raw)) return raw;
100
100
  return String(raw).split(/\s+/).filter(Boolean);
101
101
  };
102
- var validate = (scopes) => {
103
- const parsed = parse(scopes);
104
- const invalid = parsed.filter((scope) => !SCOPES.includes(scope));
102
+ var validate = (scopes2) => {
103
+ const parsed = parse(scopes2);
104
+ const invalid = parsed.filter((scope) => !scopes2.includes(scope));
105
105
  return {
106
106
  invalid,
107
107
  valid: invalid.length === 0
@@ -112,14 +112,14 @@ var intersect = (requested, allowed) => {
112
112
  const a = parse(allowed);
113
113
  return r.filter((scope) => a.includes(scope));
114
114
  };
115
- var isDeveloperAllowed = (scope) => DEVELOPER_ALLOWED_SCOPES.includes(scope);
115
+ var isDeveloperAllowed = (scope) => developer.includes(scope);
116
116
  var hashToken = (raw) => hash(raw, process.env.OAUTH_TOKEN_HMAC_KEY);
117
117
  var generateToken = () => generate(32, "base64url");
118
118
  var REFRESH_LEAD_SECONDS = 60;
119
119
  var createOAuthClient = ({
120
120
  clientId,
121
121
  clientSecret,
122
- scopes = [],
122
+ scopes: scopes2 = [],
123
123
  tokenUri
124
124
  }) => {
125
125
  if (!clientId) throw new Error("createOAuthClient: clientId required");
@@ -135,8 +135,8 @@ var createOAuthClient = ({
135
135
  const fetchToken = async () => {
136
136
  const params = new URLSearchParams();
137
137
  params.set("grant_type", "client_credentials");
138
- if (scopes.length > 0) {
139
- params.set("scope", scopes.join(" "));
138
+ if (scopes2.length > 0) {
139
+ params.set("scope", scopes2.join(" "));
140
140
  }
141
141
  const basic = Buffer.from(clientId + ":" + clientSecret).toString("base64");
142
142
  const response = await fetch(
@@ -183,14 +183,14 @@ var createOAuthClient = ({
183
183
  };
184
184
  // Annotate the CommonJS export names for ESM import in node:
185
185
  0 && (module.exports = {
186
- DEVELOPER_ALLOWED_SCOPES,
187
- SCOPES,
188
186
  compare,
189
187
  createOAuthClient,
188
+ developer,
190
189
  generateToken,
191
190
  hashToken,
192
191
  intersect,
193
192
  isDeveloperAllowed,
194
193
  parse,
194
+ scopes,
195
195
  validate
196
196
  });
@@ -1,12 +1,12 @@
1
- import { generate, hash } from './token.js';
2
- export { compare } from './token.js';
1
+ import { generate, hash } from '../token.cjs';
2
+ export { compare } from '../token.cjs';
3
3
  import 'crypto';
4
4
 
5
5
  // Shared OAuth helpers used across drawbridge-api, drawbridge-sync,
6
6
  // drawbridge-app-web, and any first-party app that needs to participate
7
7
  // in the OAuth 2.1 provider:
8
8
  //
9
- // - SCOPES, DEVELOPER_ALLOWED_SCOPES: the locked scope vocabulary
9
+ // - scopes, developer: the locked scope vocabulary
10
10
  // - parse, validate, intersect, isDeveloperAllowed: scope set operations
11
11
  // - hashToken, generateToken, compare: opaque-token primitives
12
12
  // - createOAuthClient: cached client_credentials access token getter
@@ -16,7 +16,7 @@ import 'crypto';
16
16
  // Scope vocabulary (locked — 15 scopes, 10 in the developer-allowed subset)
17
17
  // ─────────────────────────────────────────────────────────────────────────
18
18
 
19
- const SCOPES = [
19
+ const scopes = [
20
20
  'profile:read',
21
21
  'profile:write',
22
22
  'organization:read',
@@ -37,7 +37,7 @@ const SCOPES = [
37
37
  // Subset granted to third-party developer apps via /oauth/clients self-service
38
38
  // registration. Excludes profile:write (account-level), organization:write
39
39
  // (org admin only), billing:* (financial), admin (privileged).
40
- const DEVELOPER_ALLOWED_SCOPES = [
40
+ const developer = [
41
41
  'profile:read',
42
42
  'organization:read',
43
43
  'campaigns:read',
@@ -63,7 +63,7 @@ const parse = ( raw ) => {
63
63
  const validate = ( scopes ) => {
64
64
 
65
65
  const parsed = parse( scopes );
66
- const invalid = parsed.filter( ( scope ) => ! SCOPES.includes( scope ) );
66
+ const invalid = parsed.filter( ( scope ) => ! scopes.includes( scope ) );
67
67
 
68
68
  return {
69
69
  invalid,
@@ -81,7 +81,7 @@ const intersect = ( requested, allowed ) => {
81
81
 
82
82
  };
83
83
 
84
- const isDeveloperAllowed = ( scope ) => DEVELOPER_ALLOWED_SCOPES.includes( scope );
84
+ const isDeveloperAllowed = ( scope ) => developer.includes( scope );
85
85
 
86
86
  // ─────────────────────────────────────────────────────────────────────────
87
87
  // Token primitives — convenience wrappers over drawbridge-utils/token that
@@ -228,4 +228,4 @@ const createOAuthClient = ({
228
228
 
229
229
  };
230
230
 
231
- export { DEVELOPER_ALLOWED_SCOPES, SCOPES, createOAuthClient, generateToken, hashToken, intersect, isDeveloperAllowed, parse, validate };
231
+ export { createOAuthClient, developer, generateToken, hashToken, intersect, isDeveloperAllowed, parse, scopes, validate };
@@ -1,12 +1,12 @@
1
- import { generate, hash } from './token.cjs';
2
- export { compare } from './token.cjs';
1
+ import { generate, hash } from '../token.js';
2
+ export { compare } from '../token.js';
3
3
  import 'crypto';
4
4
 
5
5
  // Shared OAuth helpers used across drawbridge-api, drawbridge-sync,
6
6
  // drawbridge-app-web, and any first-party app that needs to participate
7
7
  // in the OAuth 2.1 provider:
8
8
  //
9
- // - SCOPES, DEVELOPER_ALLOWED_SCOPES: the locked scope vocabulary
9
+ // - scopes, developer: the locked scope vocabulary
10
10
  // - parse, validate, intersect, isDeveloperAllowed: scope set operations
11
11
  // - hashToken, generateToken, compare: opaque-token primitives
12
12
  // - createOAuthClient: cached client_credentials access token getter
@@ -16,7 +16,7 @@ import 'crypto';
16
16
  // Scope vocabulary (locked — 15 scopes, 10 in the developer-allowed subset)
17
17
  // ─────────────────────────────────────────────────────────────────────────
18
18
 
19
- const SCOPES = [
19
+ const scopes = [
20
20
  'profile:read',
21
21
  'profile:write',
22
22
  'organization:read',
@@ -37,7 +37,7 @@ const SCOPES = [
37
37
  // Subset granted to third-party developer apps via /oauth/clients self-service
38
38
  // registration. Excludes profile:write (account-level), organization:write
39
39
  // (org admin only), billing:* (financial), admin (privileged).
40
- const DEVELOPER_ALLOWED_SCOPES = [
40
+ const developer = [
41
41
  'profile:read',
42
42
  'organization:read',
43
43
  'campaigns:read',
@@ -63,7 +63,7 @@ const parse = ( raw ) => {
63
63
  const validate = ( scopes ) => {
64
64
 
65
65
  const parsed = parse( scopes );
66
- const invalid = parsed.filter( ( scope ) => ! SCOPES.includes( scope ) );
66
+ const invalid = parsed.filter( ( scope ) => ! scopes.includes( scope ) );
67
67
 
68
68
  return {
69
69
  invalid,
@@ -81,7 +81,7 @@ const intersect = ( requested, allowed ) => {
81
81
 
82
82
  };
83
83
 
84
- const isDeveloperAllowed = ( scope ) => DEVELOPER_ALLOWED_SCOPES.includes( scope );
84
+ const isDeveloperAllowed = ( scope ) => developer.includes( scope );
85
85
 
86
86
  // ─────────────────────────────────────────────────────────────────────────
87
87
  // Token primitives — convenience wrappers over drawbridge-utils/token that
@@ -228,4 +228,4 @@ const createOAuthClient = ({
228
228
 
229
229
  };
230
230
 
231
- export { DEVELOPER_ALLOWED_SCOPES, SCOPES, createOAuthClient, generateToken, hashToken, intersect, isDeveloperAllowed, parse, validate };
231
+ export { createOAuthClient, developer, generateToken, hashToken, intersect, isDeveloperAllowed, parse, scopes, validate };