@drawbridge/drawbridge-utils 0.0.42 → 0.0.44
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 +4 -4
- package/dist/ai.js +127 -8
- package/dist/axios.cjs +1 -1
- package/dist/axios.js +1 -1
- package/dist/cdn.cjs +1 -1
- package/dist/cdn.js +1 -1
- package/dist/circuit.cjs +1 -1
- package/dist/circuit.js +50 -3
- package/dist/encrypt.cjs +3 -3
- package/dist/encrypt.js +38 -5
- package/dist/fetch.cjs +1 -1
- package/dist/fetch.js +1 -1
- package/dist/http.cjs +1 -1
- package/dist/http.js +1 -1
- package/dist/nanoid.cjs +1 -1
- package/dist/nanoid.js +1 -1
- package/dist/{oauth.cjs → oauth/index.cjs} +45 -16
- package/dist/{oauth.d.ts → oauth/index.d.cts} +40 -8
- package/dist/{oauth.d.cts → oauth/index.d.ts} +40 -8
- package/dist/{oauth.js → oauth/index.js} +59 -17
- package/dist/oauth/server.cjs +417 -0
- package/dist/oauth/server.d.cts +387 -0
- package/dist/oauth/server.d.ts +387 -0
- package/dist/oauth/server.js +381 -0
- package/dist/orders.cjs +1 -1
- package/dist/orders.js +1 -1
- package/dist/redirect.cjs +1 -1
- package/dist/redirect.js +1 -1
- package/dist/shopify.cjs +5 -5
- package/dist/shopify.js +46 -11
- package/dist/slugify.cjs +1 -1
- package/dist/slugify.js +1 -1
- package/dist/token.cjs +1 -1
- package/dist/token.js +21 -5
- package/dist/transactions.cjs +1 -1
- package/dist/transactions.js +108 -4
- package/dist/upload.cjs +1 -1
- package/dist/upload.js +1 -1
- package/package.json +20 -4
- package/dist/chunk-2DRAIKGZ.js +0 -38
- package/dist/chunk-6HH36OK6.js +0 -54
- package/dist/chunk-JT2PAZAZ.js +0 -113
- package/dist/chunk-OS2AHUWX.js +0 -27
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
|
-
|
|
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
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
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import "
|
|
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
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
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
|
@@ -26,23 +26,26 @@ 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,
|
|
35
|
+
developerOptions: () => developerOptions,
|
|
36
36
|
generateToken: () => generateToken,
|
|
37
37
|
hashToken: () => hashToken,
|
|
38
38
|
intersect: () => intersect,
|
|
39
39
|
isDeveloperAllowed: () => isDeveloperAllowed,
|
|
40
40
|
parse: () => parse,
|
|
41
|
+
scopeLabels: () => scopeLabels,
|
|
42
|
+
scopeOptions: () => scopeOptions,
|
|
43
|
+
scopes: () => scopes,
|
|
41
44
|
validate: () => validate
|
|
42
45
|
});
|
|
43
46
|
module.exports = __toCommonJS(oauth_exports);
|
|
44
47
|
|
|
45
|
-
// token.js
|
|
48
|
+
// lib/token.js
|
|
46
49
|
var import_crypto = __toESM(require("crypto"), 1);
|
|
47
50
|
var generate = (bytes = 32, encoding = "base64url") => {
|
|
48
51
|
const buf = import_crypto.default.randomBytes(bytes);
|
|
@@ -64,8 +67,8 @@ var compare = (a, b) => {
|
|
|
64
67
|
);
|
|
65
68
|
};
|
|
66
69
|
|
|
67
|
-
// oauth.js
|
|
68
|
-
var
|
|
70
|
+
// lib/oauth/index.js
|
|
71
|
+
var scopes = [
|
|
69
72
|
"profile:read",
|
|
70
73
|
"profile:write",
|
|
71
74
|
"organization:read",
|
|
@@ -82,7 +85,7 @@ var SCOPES = [
|
|
|
82
85
|
"billing:write",
|
|
83
86
|
"admin"
|
|
84
87
|
];
|
|
85
|
-
var
|
|
88
|
+
var developer = [
|
|
86
89
|
"profile:read",
|
|
87
90
|
"organization:read",
|
|
88
91
|
"campaigns:read",
|
|
@@ -99,9 +102,9 @@ var parse = (raw) => {
|
|
|
99
102
|
if (Array.isArray(raw)) return raw;
|
|
100
103
|
return String(raw).split(/\s+/).filter(Boolean);
|
|
101
104
|
};
|
|
102
|
-
var validate = (
|
|
103
|
-
const parsed = parse(
|
|
104
|
-
const invalid = parsed.filter((scope) => !
|
|
105
|
+
var validate = (scopes2) => {
|
|
106
|
+
const parsed = parse(scopes2);
|
|
107
|
+
const invalid = parsed.filter((scope) => !scopes2.includes(scope));
|
|
105
108
|
return {
|
|
106
109
|
invalid,
|
|
107
110
|
valid: invalid.length === 0
|
|
@@ -112,14 +115,37 @@ var intersect = (requested, allowed) => {
|
|
|
112
115
|
const a = parse(allowed);
|
|
113
116
|
return r.filter((scope) => a.includes(scope));
|
|
114
117
|
};
|
|
115
|
-
var isDeveloperAllowed = (scope) =>
|
|
118
|
+
var isDeveloperAllowed = (scope) => developer.includes(scope);
|
|
119
|
+
var scopeLabels = {
|
|
120
|
+
"profile:read": "Read own profile",
|
|
121
|
+
"profile:write": "Update own profile",
|
|
122
|
+
"organization:read": "Read organization info",
|
|
123
|
+
"organization:write": "Manage organization",
|
|
124
|
+
"campaigns:read": "Read campaigns",
|
|
125
|
+
"campaigns:write": "Manage campaigns",
|
|
126
|
+
"contacts:read": "Read contacts",
|
|
127
|
+
"contacts:write": "Manage contacts",
|
|
128
|
+
"workflows:read": "Read workflows",
|
|
129
|
+
"workflows:write": "Manage workflows",
|
|
130
|
+
"connections:read": "Read integrations",
|
|
131
|
+
"connections:write": "Manage integrations",
|
|
132
|
+
"billing:read": "Read billing",
|
|
133
|
+
"billing:write": "Manage billing",
|
|
134
|
+
admin: "Admin access"
|
|
135
|
+
};
|
|
136
|
+
var toOption = (scope) => ({
|
|
137
|
+
key: scopeLabels[scope] || scope,
|
|
138
|
+
value: scope
|
|
139
|
+
});
|
|
140
|
+
var developerOptions = developer.map(toOption);
|
|
141
|
+
var scopeOptions = scopes.map(toOption);
|
|
116
142
|
var hashToken = (raw) => hash(raw, process.env.OAUTH_TOKEN_HMAC_KEY);
|
|
117
143
|
var generateToken = () => generate(32, "base64url");
|
|
118
144
|
var REFRESH_LEAD_SECONDS = 60;
|
|
119
145
|
var createOAuthClient = ({
|
|
120
146
|
clientId,
|
|
121
147
|
clientSecret,
|
|
122
|
-
scopes = [],
|
|
148
|
+
scopes: scopes2 = [],
|
|
123
149
|
tokenUri
|
|
124
150
|
}) => {
|
|
125
151
|
if (!clientId) throw new Error("createOAuthClient: clientId required");
|
|
@@ -135,8 +161,8 @@ var createOAuthClient = ({
|
|
|
135
161
|
const fetchToken = async () => {
|
|
136
162
|
const params = new URLSearchParams();
|
|
137
163
|
params.set("grant_type", "client_credentials");
|
|
138
|
-
if (
|
|
139
|
-
params.set("scope",
|
|
164
|
+
if (scopes2.length > 0) {
|
|
165
|
+
params.set("scope", scopes2.join(" "));
|
|
140
166
|
}
|
|
141
167
|
const basic = Buffer.from(clientId + ":" + clientSecret).toString("base64");
|
|
142
168
|
const response = await fetch(
|
|
@@ -183,14 +209,17 @@ var createOAuthClient = ({
|
|
|
183
209
|
};
|
|
184
210
|
// Annotate the CommonJS export names for ESM import in node:
|
|
185
211
|
0 && (module.exports = {
|
|
186
|
-
DEVELOPER_ALLOWED_SCOPES,
|
|
187
|
-
SCOPES,
|
|
188
212
|
compare,
|
|
189
213
|
createOAuthClient,
|
|
214
|
+
developer,
|
|
215
|
+
developerOptions,
|
|
190
216
|
generateToken,
|
|
191
217
|
hashToken,
|
|
192
218
|
intersect,
|
|
193
219
|
isDeveloperAllowed,
|
|
194
220
|
parse,
|
|
221
|
+
scopeLabels,
|
|
222
|
+
scopeOptions,
|
|
223
|
+
scopes,
|
|
195
224
|
validate
|
|
196
225
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { generate, hash } from '
|
|
2
|
-
export { compare } from '
|
|
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
|
-
// -
|
|
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
|
|
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
|
|
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 ) => !
|
|
66
|
+
const invalid = parsed.filter( ( scope ) => ! scopes.includes( scope ) );
|
|
67
67
|
|
|
68
68
|
return {
|
|
69
69
|
invalid,
|
|
@@ -81,7 +81,39 @@ const intersect = ( requested, allowed ) => {
|
|
|
81
81
|
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
-
const isDeveloperAllowed = ( scope ) =>
|
|
84
|
+
const isDeveloperAllowed = ( scope ) => developer.includes( scope );
|
|
85
|
+
|
|
86
|
+
// User-facing labels for each scope — used by UI components rendering
|
|
87
|
+
// scope pickers. Centralized here so the dashboard, future admin tools,
|
|
88
|
+
// and any other consumer surface the same strings.
|
|
89
|
+
const scopeLabels = {
|
|
90
|
+
'profile:read' : 'Read own profile',
|
|
91
|
+
'profile:write' : 'Update own profile',
|
|
92
|
+
'organization:read' : 'Read organization info',
|
|
93
|
+
'organization:write' : 'Manage organization',
|
|
94
|
+
'campaigns:read' : 'Read campaigns',
|
|
95
|
+
'campaigns:write' : 'Manage campaigns',
|
|
96
|
+
'contacts:read' : 'Read contacts',
|
|
97
|
+
'contacts:write' : 'Manage contacts',
|
|
98
|
+
'workflows:read' : 'Read workflows',
|
|
99
|
+
'workflows:write' : 'Manage workflows',
|
|
100
|
+
'connections:read' : 'Read integrations',
|
|
101
|
+
'connections:write' : 'Manage integrations',
|
|
102
|
+
'billing:read' : 'Read billing',
|
|
103
|
+
'billing:write' : 'Manage billing',
|
|
104
|
+
admin : 'Admin access'
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const toOption = ( scope ) => ({
|
|
108
|
+
key : scopeLabels[ scope ] || scope,
|
|
109
|
+
value : scope
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// `{ key, value }` option arrays ready to feed any standard checkbox-list
|
|
113
|
+
// component. Derived from the canonical scope arrays so vocabulary
|
|
114
|
+
// changes auto-propagate to every consumer on the next utils bump.
|
|
115
|
+
const developerOptions = developer.map( toOption );
|
|
116
|
+
const scopeOptions = scopes.map( toOption );
|
|
85
117
|
|
|
86
118
|
// ─────────────────────────────────────────────────────────────────────────
|
|
87
119
|
// Token primitives — convenience wrappers over drawbridge-utils/token that
|
|
@@ -228,4 +260,4 @@ const createOAuthClient = ({
|
|
|
228
260
|
|
|
229
261
|
};
|
|
230
262
|
|
|
231
|
-
export {
|
|
263
|
+
export { createOAuthClient, developer, developerOptions, generateToken, hashToken, intersect, isDeveloperAllowed, parse, scopeLabels, scopeOptions, scopes, validate };
|