@drawbridge/drawbridge-utils 0.0.87 → 0.0.88
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/axios.cjs +11 -3
- package/dist/axios.d.cts +19 -3
- package/dist/axios.d.ts +19 -3
- package/dist/axios.js +10 -2
- package/dist/cloudflare.cjs +292 -0
- package/dist/cloudflare.d.cts +153 -0
- package/dist/cloudflare.d.ts +153 -0
- package/dist/cloudflare.js +255 -0
- package/package.json +6 -1
package/dist/axios.cjs
CHANGED
|
@@ -36,7 +36,8 @@ __export(axios_exports, {
|
|
|
36
36
|
module.exports = __toCommonJS(axios_exports);
|
|
37
37
|
var import_axios = __toESM(require("axios"), 1);
|
|
38
38
|
var import_dns = __toESM(require("dns"), 1);
|
|
39
|
-
var
|
|
39
|
+
var http = __toESM(require("http"), 1);
|
|
40
|
+
var https = __toESM(require("https"), 1);
|
|
40
41
|
var import_net = __toESM(require("net"), 1);
|
|
41
42
|
var dnsLookup = import_dns.default.promises.lookup;
|
|
42
43
|
var isBlockedIPv4 = (ip) => {
|
|
@@ -101,7 +102,7 @@ var safeGet = async (url, axiosOptions = {}) => {
|
|
|
101
102
|
}
|
|
102
103
|
;
|
|
103
104
|
const pinned = records[0];
|
|
104
|
-
const agent = new
|
|
105
|
+
const agent = new https.Agent({
|
|
105
106
|
lookup: (hostname, options, callback) => {
|
|
106
107
|
if (options == null ? void 0 : options.all) {
|
|
107
108
|
callback(null, [{ address: pinned.address, family: pinned.family }]);
|
|
@@ -112,6 +113,9 @@ var safeGet = async (url, axiosOptions = {}) => {
|
|
|
112
113
|
}
|
|
113
114
|
});
|
|
114
115
|
return import_axios.default.get(url, {
|
|
116
|
+
// Default bound for user-supplied URLs; callers override via
|
|
117
|
+
// axiosOptions.timeout (listed first so the spread wins).
|
|
118
|
+
timeout: 15e3,
|
|
115
119
|
...axiosOptions,
|
|
116
120
|
httpsAgent: agent,
|
|
117
121
|
maxRedirects: 0,
|
|
@@ -122,7 +126,11 @@ var safeGet = async (url, axiosOptions = {}) => {
|
|
|
122
126
|
var safe = {
|
|
123
127
|
get: safeGet
|
|
124
128
|
};
|
|
125
|
-
var axios = import_axios.default
|
|
129
|
+
var axios = import_axios.default.create({
|
|
130
|
+
timeout: 3e4,
|
|
131
|
+
httpAgent: new http.Agent({ keepAlive: true, maxSockets: 128 }),
|
|
132
|
+
httpsAgent: new https.Agent({ keepAlive: true, maxSockets: 128 })
|
|
133
|
+
});
|
|
126
134
|
// Annotate the CommonJS export names for ESM import in node:
|
|
127
135
|
0 && (module.exports = {
|
|
128
136
|
axios,
|
package/dist/axios.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import axiosLib from 'axios';
|
|
2
2
|
import dns from 'dns';
|
|
3
|
-
import
|
|
3
|
+
import * as http from 'node:http';
|
|
4
|
+
import * as https from 'node:https';
|
|
4
5
|
import net from 'net';
|
|
5
6
|
|
|
6
7
|
const dnsLookup = dns.promises.lookup;
|
|
@@ -130,6 +131,9 @@ const safeGet = async ( url, axiosOptions = {} ) => {
|
|
|
130
131
|
});
|
|
131
132
|
|
|
132
133
|
return axiosLib.get( url, {
|
|
134
|
+
// Default bound for user-supplied URLs; callers override via
|
|
135
|
+
// axiosOptions.timeout (listed first so the spread wins).
|
|
136
|
+
timeout : 15000,
|
|
133
137
|
...axiosOptions,
|
|
134
138
|
httpsAgent : agent,
|
|
135
139
|
maxRedirects : 0,
|
|
@@ -145,9 +149,21 @@ const safe = {
|
|
|
145
149
|
get : safeGet
|
|
146
150
|
};
|
|
147
151
|
|
|
148
|
-
// Raw axios
|
|
152
|
+
// Raw axios instance for trusted/hardcoded URLs (Google APIs, Stripe, etc.).
|
|
149
153
|
// await axios.get( 'https://api.stripe.com/...' );
|
|
150
154
|
// await axios.post( ... );
|
|
151
|
-
|
|
155
|
+
//
|
|
156
|
+
// Bounded by default so a forgotten per-call override can never hang a request
|
|
157
|
+
// handler or queue worker indefinitely (the classic unguarded-await failure
|
|
158
|
+
// under load). Every call site can still override: per-request `timeout`,
|
|
159
|
+
// `signal` (used by streaming downloads whose 30s would be wrong), and
|
|
160
|
+
// per-request `httpAgent`/`httpsAgent` (used by the SSRF-pinned agents) all
|
|
161
|
+
// take precedence over these defaults. Audited 2026-07-24: every existing
|
|
162
|
+
// call site already sets its own bound, so this changes no current behavior.
|
|
163
|
+
const axios = axiosLib.create({
|
|
164
|
+
timeout : 30000,
|
|
165
|
+
httpAgent : new http.Agent({ keepAlive : true, maxSockets : 128 }),
|
|
166
|
+
httpsAgent : new https.Agent({ keepAlive : true, maxSockets : 128 })
|
|
167
|
+
});
|
|
152
168
|
|
|
153
169
|
export { axios, isBlockedIP, safe };
|
package/dist/axios.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import axiosLib from 'axios';
|
|
2
2
|
import dns from 'dns';
|
|
3
|
-
import
|
|
3
|
+
import * as http from 'node:http';
|
|
4
|
+
import * as https from 'node:https';
|
|
4
5
|
import net from 'net';
|
|
5
6
|
|
|
6
7
|
const dnsLookup = dns.promises.lookup;
|
|
@@ -130,6 +131,9 @@ const safeGet = async ( url, axiosOptions = {} ) => {
|
|
|
130
131
|
});
|
|
131
132
|
|
|
132
133
|
return axiosLib.get( url, {
|
|
134
|
+
// Default bound for user-supplied URLs; callers override via
|
|
135
|
+
// axiosOptions.timeout (listed first so the spread wins).
|
|
136
|
+
timeout : 15000,
|
|
133
137
|
...axiosOptions,
|
|
134
138
|
httpsAgent : agent,
|
|
135
139
|
maxRedirects : 0,
|
|
@@ -145,9 +149,21 @@ const safe = {
|
|
|
145
149
|
get : safeGet
|
|
146
150
|
};
|
|
147
151
|
|
|
148
|
-
// Raw axios
|
|
152
|
+
// Raw axios instance for trusted/hardcoded URLs (Google APIs, Stripe, etc.).
|
|
149
153
|
// await axios.get( 'https://api.stripe.com/...' );
|
|
150
154
|
// await axios.post( ... );
|
|
151
|
-
|
|
155
|
+
//
|
|
156
|
+
// Bounded by default so a forgotten per-call override can never hang a request
|
|
157
|
+
// handler or queue worker indefinitely (the classic unguarded-await failure
|
|
158
|
+
// under load). Every call site can still override: per-request `timeout`,
|
|
159
|
+
// `signal` (used by streaming downloads whose 30s would be wrong), and
|
|
160
|
+
// per-request `httpAgent`/`httpsAgent` (used by the SSRF-pinned agents) all
|
|
161
|
+
// take precedence over these defaults. Audited 2026-07-24: every existing
|
|
162
|
+
// call site already sets its own bound, so this changes no current behavior.
|
|
163
|
+
const axios = axiosLib.create({
|
|
164
|
+
timeout : 30000,
|
|
165
|
+
httpAgent : new http.Agent({ keepAlive : true, maxSockets : 128 }),
|
|
166
|
+
httpsAgent : new https.Agent({ keepAlive : true, maxSockets : 128 })
|
|
167
|
+
});
|
|
152
168
|
|
|
153
169
|
export { axios, isBlockedIP, safe };
|
package/dist/axios.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// lib/axios.js
|
|
2
2
|
import axiosLib from "axios";
|
|
3
3
|
import dns from "dns";
|
|
4
|
-
import
|
|
4
|
+
import * as http from "http";
|
|
5
|
+
import * as https from "https";
|
|
5
6
|
import net from "net";
|
|
6
7
|
var dnsLookup = dns.promises.lookup;
|
|
7
8
|
var isBlockedIPv4 = (ip) => {
|
|
@@ -77,6 +78,9 @@ var safeGet = async (url, axiosOptions = {}) => {
|
|
|
77
78
|
}
|
|
78
79
|
});
|
|
79
80
|
return axiosLib.get(url, {
|
|
81
|
+
// Default bound for user-supplied URLs; callers override via
|
|
82
|
+
// axiosOptions.timeout (listed first so the spread wins).
|
|
83
|
+
timeout: 15e3,
|
|
80
84
|
...axiosOptions,
|
|
81
85
|
httpsAgent: agent,
|
|
82
86
|
maxRedirects: 0,
|
|
@@ -87,7 +91,11 @@ var safeGet = async (url, axiosOptions = {}) => {
|
|
|
87
91
|
var safe = {
|
|
88
92
|
get: safeGet
|
|
89
93
|
};
|
|
90
|
-
var axios = axiosLib
|
|
94
|
+
var axios = axiosLib.create({
|
|
95
|
+
timeout: 3e4,
|
|
96
|
+
httpAgent: new http.Agent({ keepAlive: true, maxSockets: 128 }),
|
|
97
|
+
httpsAgent: new https.Agent({ keepAlive: true, maxSockets: 128 })
|
|
98
|
+
});
|
|
91
99
|
export {
|
|
92
100
|
axios,
|
|
93
101
|
isBlockedIP,
|
|
@@ -0,0 +1,292 @@
|
|
|
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/cloudflare.js
|
|
30
|
+
var cloudflare_exports = {};
|
|
31
|
+
__export(cloudflare_exports, {
|
|
32
|
+
pageEdgeUrls: () => pageEdgeUrls,
|
|
33
|
+
purge: () => purge
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(cloudflare_exports);
|
|
36
|
+
|
|
37
|
+
// lib/http.js
|
|
38
|
+
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
39
|
+
var request = async ({
|
|
40
|
+
body,
|
|
41
|
+
headers = {},
|
|
42
|
+
method = "GET",
|
|
43
|
+
query,
|
|
44
|
+
timeout = DEFAULT_TIMEOUT_MS,
|
|
45
|
+
type = "json",
|
|
46
|
+
url
|
|
47
|
+
}) => {
|
|
48
|
+
const fullUrl = new URL(url);
|
|
49
|
+
if (query) {
|
|
50
|
+
Object.entries(query).forEach(([k, v]) => fullUrl.searchParams.set(k, v));
|
|
51
|
+
}
|
|
52
|
+
;
|
|
53
|
+
const isForm = type === "form";
|
|
54
|
+
const response = await fetch(fullUrl.toString(), {
|
|
55
|
+
method,
|
|
56
|
+
headers: {
|
|
57
|
+
"Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json",
|
|
58
|
+
...headers
|
|
59
|
+
},
|
|
60
|
+
signal: AbortSignal.timeout(timeout),
|
|
61
|
+
...body !== void 0 && {
|
|
62
|
+
body: isForm ? new URLSearchParams(body).toString() : JSON.stringify(body)
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
const text2 = await response.text().catch(() => "");
|
|
67
|
+
const error = new Error(text2 || response.statusText);
|
|
68
|
+
error.status = response.status;
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
;
|
|
72
|
+
const text = await response.text();
|
|
73
|
+
try {
|
|
74
|
+
return text ? JSON.parse(text) : null;
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// index.js
|
|
81
|
+
var import_currency_codes = require("currency-codes");
|
|
82
|
+
var import_nanoid = require("nanoid");
|
|
83
|
+
|
|
84
|
+
// lib/color.js
|
|
85
|
+
var import_tinycolor2 = __toESM(require("tinycolor2"), 1);
|
|
86
|
+
var colorFormatted = (value) => {
|
|
87
|
+
const color = (0, import_tinycolor2.default)(value);
|
|
88
|
+
const attributes = {
|
|
89
|
+
brightness: color.getBrightness(),
|
|
90
|
+
dark: color.isDark(),
|
|
91
|
+
light: color.isLight(),
|
|
92
|
+
luminance: color.getLuminance()
|
|
93
|
+
};
|
|
94
|
+
return {
|
|
95
|
+
attributes,
|
|
96
|
+
hex: color.toHexString(),
|
|
97
|
+
hsl: color.toHsl(),
|
|
98
|
+
hsv: color.toHsv(),
|
|
99
|
+
rgb: color.toRgbString()
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
var colorAccessible = (background2) => {
|
|
103
|
+
const white = "#ffffff";
|
|
104
|
+
const black = "#000000";
|
|
105
|
+
return import_tinycolor2.default.isReadable(
|
|
106
|
+
background2,
|
|
107
|
+
white,
|
|
108
|
+
{
|
|
109
|
+
level: "AA",
|
|
110
|
+
size: "normal"
|
|
111
|
+
}
|
|
112
|
+
) ? white : black;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// lib/constants.js
|
|
116
|
+
var font = {
|
|
117
|
+
family: "Roboto Flex",
|
|
118
|
+
transform: "none",
|
|
119
|
+
weight: "regular"
|
|
120
|
+
};
|
|
121
|
+
var background = "#ffffff";
|
|
122
|
+
var style = {
|
|
123
|
+
background: {
|
|
124
|
+
color: colorFormatted(background)
|
|
125
|
+
},
|
|
126
|
+
body: font,
|
|
127
|
+
button: {
|
|
128
|
+
background: {
|
|
129
|
+
color: colorFormatted(background)
|
|
130
|
+
},
|
|
131
|
+
radius: 0,
|
|
132
|
+
text: {
|
|
133
|
+
color: colorFormatted(colorAccessible(background))
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
heading: font,
|
|
137
|
+
input: {
|
|
138
|
+
radius: 0
|
|
139
|
+
},
|
|
140
|
+
text: {
|
|
141
|
+
color: colorFormatted(colorAccessible(background))
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// index.js
|
|
146
|
+
var nanoid = (0, import_nanoid.customAlphabet)("0123456789abcdefghijklmnopqrstuvwxyz", 8);
|
|
147
|
+
var megabyte = 1024 * 1024;
|
|
148
|
+
var gigabyte = megabyte * 1024;
|
|
149
|
+
var urlRoot = (string) => (string == null ? void 0 : string.includes("https")) ? "https://" : "http://";
|
|
150
|
+
var shareUrls = ({
|
|
151
|
+
formUri,
|
|
152
|
+
organization,
|
|
153
|
+
page
|
|
154
|
+
}) => {
|
|
155
|
+
var _a;
|
|
156
|
+
const resolvedFormUri = formUri || (typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a.APP_CLIENT_FORM_URI : void 0);
|
|
157
|
+
const preface = urlRoot(resolvedFormUri);
|
|
158
|
+
const base = resolvedFormUri;
|
|
159
|
+
const qr = preface + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.shortId) + "?qr=1";
|
|
160
|
+
const short = preface + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.shortId);
|
|
161
|
+
const url = preface + (organization == null ? void 0 : organization.subdomain) + "." + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.slug);
|
|
162
|
+
const clients = [
|
|
163
|
+
base,
|
|
164
|
+
qr,
|
|
165
|
+
short,
|
|
166
|
+
url
|
|
167
|
+
];
|
|
168
|
+
const urls = {
|
|
169
|
+
qr,
|
|
170
|
+
short,
|
|
171
|
+
url
|
|
172
|
+
};
|
|
173
|
+
if ((organization == null ? void 0 : organization.subdomain) && (page == null ? void 0 : page.shortId)) {
|
|
174
|
+
clients.push(preface + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.shortId));
|
|
175
|
+
clients.push(preface + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.shortId) + "?qr=1");
|
|
176
|
+
clients.push(preface + organization.subdomain + "." + (base == null ? void 0 : base.replace(preface, "")));
|
|
177
|
+
clients.push(preface + organization.subdomain + "." + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.shortId));
|
|
178
|
+
}
|
|
179
|
+
;
|
|
180
|
+
if ((organization == null ? void 0 : organization.shortId) && (page == null ? void 0 : page.slug) && (page == null ? void 0 : page.shortId)) {
|
|
181
|
+
clients.push(preface + organization.shortId + "." + (base == null ? void 0 : base.replace(preface, "")));
|
|
182
|
+
clients.push(preface + organization.shortId + "." + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.slug));
|
|
183
|
+
clients.push(preface + organization.shortId + "." + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.shortId));
|
|
184
|
+
}
|
|
185
|
+
;
|
|
186
|
+
return {
|
|
187
|
+
clients,
|
|
188
|
+
urls
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
var currencies = import_currency_codes.data.map((item) => ({
|
|
192
|
+
...item,
|
|
193
|
+
key: item.currency,
|
|
194
|
+
value: item.code
|
|
195
|
+
}));
|
|
196
|
+
|
|
197
|
+
// lib/cloudflare.js
|
|
198
|
+
var PURGE_BATCH = 30;
|
|
199
|
+
var endpoint = (zoneId) => "https://api.cloudflare.com/client/v4/zones/" + zoneId + "/purge_cache";
|
|
200
|
+
var pageEdgeUrls = ({
|
|
201
|
+
formUri,
|
|
202
|
+
organization,
|
|
203
|
+
page
|
|
204
|
+
}) => {
|
|
205
|
+
if (!page) return [];
|
|
206
|
+
const { clients } = shareUrls({
|
|
207
|
+
formUri,
|
|
208
|
+
organization,
|
|
209
|
+
page
|
|
210
|
+
});
|
|
211
|
+
const set = /* @__PURE__ */ new Set();
|
|
212
|
+
for (const client of clients || []) {
|
|
213
|
+
try {
|
|
214
|
+
const url = new URL(client);
|
|
215
|
+
if (url.pathname && url.pathname !== "/") {
|
|
216
|
+
set.add(url.toString());
|
|
217
|
+
}
|
|
218
|
+
;
|
|
219
|
+
} catch {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
;
|
|
223
|
+
}
|
|
224
|
+
;
|
|
225
|
+
if (page == null ? void 0 : page.slug) {
|
|
226
|
+
for (const item of [...set]) {
|
|
227
|
+
const url = new URL(item);
|
|
228
|
+
if (url.pathname === "/" + page.slug && !url.search) {
|
|
229
|
+
set.add(url.origin + "/" + page.slug + "/embed");
|
|
230
|
+
}
|
|
231
|
+
;
|
|
232
|
+
}
|
|
233
|
+
;
|
|
234
|
+
}
|
|
235
|
+
;
|
|
236
|
+
return [...set];
|
|
237
|
+
};
|
|
238
|
+
var purge = async ({
|
|
239
|
+
files = [],
|
|
240
|
+
logger,
|
|
241
|
+
transport = request
|
|
242
|
+
} = {}) => {
|
|
243
|
+
var _a, _b;
|
|
244
|
+
const apiToken = typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a.CLOUDFLARE_API_TOKEN : void 0;
|
|
245
|
+
const zoneId = typeof process !== "undefined" ? (_b = process.env) == null ? void 0 : _b.CLOUDFLARE_ZONE_ID : void 0;
|
|
246
|
+
if (!apiToken || !zoneId) {
|
|
247
|
+
return {
|
|
248
|
+
purged: 0,
|
|
249
|
+
skipped: true
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
;
|
|
253
|
+
const unique = [...new Set(files.filter(Boolean))];
|
|
254
|
+
let purged = 0;
|
|
255
|
+
for (let index = 0; index < unique.length; index += PURGE_BATCH) {
|
|
256
|
+
const batch = unique.slice(index, index + PURGE_BATCH);
|
|
257
|
+
try {
|
|
258
|
+
await transport({
|
|
259
|
+
method: "POST",
|
|
260
|
+
url: endpoint(zoneId),
|
|
261
|
+
headers: {
|
|
262
|
+
Authorization: "Bearer " + apiToken
|
|
263
|
+
},
|
|
264
|
+
body: {
|
|
265
|
+
files: batch
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
purged += batch.length;
|
|
269
|
+
} catch (error) {
|
|
270
|
+
if (logger == null ? void 0 : logger.error) {
|
|
271
|
+
logger.error(error, {
|
|
272
|
+
extra: {
|
|
273
|
+
batch: batch.length,
|
|
274
|
+
files: batch.slice(0, 5)
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
;
|
|
279
|
+
}
|
|
280
|
+
;
|
|
281
|
+
}
|
|
282
|
+
;
|
|
283
|
+
return {
|
|
284
|
+
purged,
|
|
285
|
+
skipped: false
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
289
|
+
0 && (module.exports = {
|
|
290
|
+
pageEdgeUrls,
|
|
291
|
+
purge
|
|
292
|
+
});
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { request } from './http.cjs';
|
|
2
|
+
import { shareUrls } from './index.cjs';
|
|
3
|
+
import 'currency-codes';
|
|
4
|
+
import 'nanoid';
|
|
5
|
+
import './color.cjs';
|
|
6
|
+
import 'tinycolor2';
|
|
7
|
+
import './usage.cjs';
|
|
8
|
+
|
|
9
|
+
// Cloudflare edge-cache helpers (spike-readiness A1). Server-only — the token
|
|
10
|
+
// is read from plain env (never NEXT_PUBLIC_*), so Next never bundles it.
|
|
11
|
+
//
|
|
12
|
+
// purge() is deliberately safe to wire BEFORE Cloudflare exists in front of
|
|
13
|
+
// the domain: with CLOUDFLARE_API_TOKEN / CLOUDFLARE_ZONE_ID unset it is a
|
|
14
|
+
// no-op, so the sync invalidation paths can carry edge purges today and they
|
|
15
|
+
// simply start working the day the zone goes live. Errors are swallowed and
|
|
16
|
+
// logged — a failed edge purge must never break a stream handler or write
|
|
17
|
+
// path (same contract as drawbridge-redis cache.delete).
|
|
18
|
+
//
|
|
19
|
+
// pageEdgeUrls() enumerates every public HTML URL a page is reachable at —
|
|
20
|
+
// the subdomain + org-shortId hosts with the slug and shortId paths, the
|
|
21
|
+
// shortId redirect on the bare domain (plus its ?qr=1 twin, a distinct edge
|
|
22
|
+
// cache key), and the /embed twin of each full-page URL — derived from the
|
|
23
|
+
// same shareUrls() the rest of the family uses, so the purge set can never
|
|
24
|
+
// drift from the real URL scheme.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
const PURGE_BATCH = 30; // Cloudflare's per-request purge-by-URL cap
|
|
28
|
+
|
|
29
|
+
const endpoint = ( zoneId ) =>
|
|
30
|
+
'https://api.cloudflare.com/client/v4/zones/' + zoneId + '/purge_cache';
|
|
31
|
+
|
|
32
|
+
const pageEdgeUrls = ({
|
|
33
|
+
formUri,
|
|
34
|
+
organization,
|
|
35
|
+
page
|
|
36
|
+
}) => {
|
|
37
|
+
|
|
38
|
+
if( ! page ) return [];
|
|
39
|
+
|
|
40
|
+
const { clients } = shareUrls({
|
|
41
|
+
formUri,
|
|
42
|
+
organization,
|
|
43
|
+
page
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const set = new Set();
|
|
47
|
+
|
|
48
|
+
for( const client of clients || [] ){
|
|
49
|
+
|
|
50
|
+
// Only page-specific URLs — bare hosts (the org/domain roots) are not
|
|
51
|
+
// this page's cache entries and purging them here would be collateral.
|
|
52
|
+
try {
|
|
53
|
+
|
|
54
|
+
const url = new URL( client );
|
|
55
|
+
|
|
56
|
+
if( url.pathname && url.pathname !== '/' ){
|
|
57
|
+
|
|
58
|
+
set.add( url.toString() );
|
|
59
|
+
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
} catch {
|
|
63
|
+
|
|
64
|
+
continue;
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// The form-only embed renders at <host>/<slug>/embed for each full-page
|
|
69
|
+
// host — a second cached HTML surface that must die with the page.
|
|
70
|
+
if( page?.slug ){
|
|
71
|
+
|
|
72
|
+
for( const item of [ ...set ] ){
|
|
73
|
+
|
|
74
|
+
const url = new URL( item );
|
|
75
|
+
|
|
76
|
+
if( url.pathname === '/' + page.slug && ! url.search ){
|
|
77
|
+
|
|
78
|
+
set.add( url.origin + '/' + page.slug + '/embed' );
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return [ ...set ];
|
|
84
|
+
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// transport is injectable for tests (mirrors how stripe injects the shared
|
|
88
|
+
// http request); production callers never pass it.
|
|
89
|
+
const purge = async ({
|
|
90
|
+
files = [],
|
|
91
|
+
logger,
|
|
92
|
+
transport = request
|
|
93
|
+
} = {}) => {
|
|
94
|
+
|
|
95
|
+
const apiToken = typeof process !== 'undefined' ? process.env?.CLOUDFLARE_API_TOKEN : undefined;
|
|
96
|
+
const zoneId = typeof process !== 'undefined' ? process.env?.CLOUDFLARE_ZONE_ID : undefined;
|
|
97
|
+
|
|
98
|
+
// Not configured = deliberate no-op (ships before Cloudflare is live).
|
|
99
|
+
if( ! apiToken || ! zoneId ){
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
purged : 0,
|
|
103
|
+
skipped : true
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
const unique = [ ...new Set( files.filter( Boolean ) ) ];
|
|
108
|
+
|
|
109
|
+
let purged = 0;
|
|
110
|
+
|
|
111
|
+
for( let index = 0; index < unique.length; index += PURGE_BATCH ){
|
|
112
|
+
|
|
113
|
+
const batch = unique.slice( index, index + PURGE_BATCH );
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
|
|
117
|
+
await transport({
|
|
118
|
+
method : 'POST',
|
|
119
|
+
url : endpoint( zoneId ),
|
|
120
|
+
headers : {
|
|
121
|
+
Authorization : 'Bearer ' + apiToken
|
|
122
|
+
},
|
|
123
|
+
body : {
|
|
124
|
+
files : batch
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
purged += batch.length;
|
|
129
|
+
|
|
130
|
+
} catch ( error ) {
|
|
131
|
+
|
|
132
|
+
// Swallow — the edge self-heals via TTL; the caller's write path
|
|
133
|
+
// must not fail because a purge did.
|
|
134
|
+
if( logger?.error ){
|
|
135
|
+
|
|
136
|
+
logger.error( error, {
|
|
137
|
+
extra : {
|
|
138
|
+
batch : batch.length,
|
|
139
|
+
files : batch.slice( 0, 5 )
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
purged,
|
|
148
|
+
skipped : false
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export { pageEdgeUrls, purge };
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { request } from './http.js';
|
|
2
|
+
import { shareUrls } from './index.js';
|
|
3
|
+
import 'currency-codes';
|
|
4
|
+
import 'nanoid';
|
|
5
|
+
import './color.js';
|
|
6
|
+
import 'tinycolor2';
|
|
7
|
+
import './usage.js';
|
|
8
|
+
|
|
9
|
+
// Cloudflare edge-cache helpers (spike-readiness A1). Server-only — the token
|
|
10
|
+
// is read from plain env (never NEXT_PUBLIC_*), so Next never bundles it.
|
|
11
|
+
//
|
|
12
|
+
// purge() is deliberately safe to wire BEFORE Cloudflare exists in front of
|
|
13
|
+
// the domain: with CLOUDFLARE_API_TOKEN / CLOUDFLARE_ZONE_ID unset it is a
|
|
14
|
+
// no-op, so the sync invalidation paths can carry edge purges today and they
|
|
15
|
+
// simply start working the day the zone goes live. Errors are swallowed and
|
|
16
|
+
// logged — a failed edge purge must never break a stream handler or write
|
|
17
|
+
// path (same contract as drawbridge-redis cache.delete).
|
|
18
|
+
//
|
|
19
|
+
// pageEdgeUrls() enumerates every public HTML URL a page is reachable at —
|
|
20
|
+
// the subdomain + org-shortId hosts with the slug and shortId paths, the
|
|
21
|
+
// shortId redirect on the bare domain (plus its ?qr=1 twin, a distinct edge
|
|
22
|
+
// cache key), and the /embed twin of each full-page URL — derived from the
|
|
23
|
+
// same shareUrls() the rest of the family uses, so the purge set can never
|
|
24
|
+
// drift from the real URL scheme.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
const PURGE_BATCH = 30; // Cloudflare's per-request purge-by-URL cap
|
|
28
|
+
|
|
29
|
+
const endpoint = ( zoneId ) =>
|
|
30
|
+
'https://api.cloudflare.com/client/v4/zones/' + zoneId + '/purge_cache';
|
|
31
|
+
|
|
32
|
+
const pageEdgeUrls = ({
|
|
33
|
+
formUri,
|
|
34
|
+
organization,
|
|
35
|
+
page
|
|
36
|
+
}) => {
|
|
37
|
+
|
|
38
|
+
if( ! page ) return [];
|
|
39
|
+
|
|
40
|
+
const { clients } = shareUrls({
|
|
41
|
+
formUri,
|
|
42
|
+
organization,
|
|
43
|
+
page
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const set = new Set();
|
|
47
|
+
|
|
48
|
+
for( const client of clients || [] ){
|
|
49
|
+
|
|
50
|
+
// Only page-specific URLs — bare hosts (the org/domain roots) are not
|
|
51
|
+
// this page's cache entries and purging them here would be collateral.
|
|
52
|
+
try {
|
|
53
|
+
|
|
54
|
+
const url = new URL( client );
|
|
55
|
+
|
|
56
|
+
if( url.pathname && url.pathname !== '/' ){
|
|
57
|
+
|
|
58
|
+
set.add( url.toString() );
|
|
59
|
+
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
} catch {
|
|
63
|
+
|
|
64
|
+
continue;
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// The form-only embed renders at <host>/<slug>/embed for each full-page
|
|
69
|
+
// host — a second cached HTML surface that must die with the page.
|
|
70
|
+
if( page?.slug ){
|
|
71
|
+
|
|
72
|
+
for( const item of [ ...set ] ){
|
|
73
|
+
|
|
74
|
+
const url = new URL( item );
|
|
75
|
+
|
|
76
|
+
if( url.pathname === '/' + page.slug && ! url.search ){
|
|
77
|
+
|
|
78
|
+
set.add( url.origin + '/' + page.slug + '/embed' );
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return [ ...set ];
|
|
84
|
+
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// transport is injectable for tests (mirrors how stripe injects the shared
|
|
88
|
+
// http request); production callers never pass it.
|
|
89
|
+
const purge = async ({
|
|
90
|
+
files = [],
|
|
91
|
+
logger,
|
|
92
|
+
transport = request
|
|
93
|
+
} = {}) => {
|
|
94
|
+
|
|
95
|
+
const apiToken = typeof process !== 'undefined' ? process.env?.CLOUDFLARE_API_TOKEN : undefined;
|
|
96
|
+
const zoneId = typeof process !== 'undefined' ? process.env?.CLOUDFLARE_ZONE_ID : undefined;
|
|
97
|
+
|
|
98
|
+
// Not configured = deliberate no-op (ships before Cloudflare is live).
|
|
99
|
+
if( ! apiToken || ! zoneId ){
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
purged : 0,
|
|
103
|
+
skipped : true
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
const unique = [ ...new Set( files.filter( Boolean ) ) ];
|
|
108
|
+
|
|
109
|
+
let purged = 0;
|
|
110
|
+
|
|
111
|
+
for( let index = 0; index < unique.length; index += PURGE_BATCH ){
|
|
112
|
+
|
|
113
|
+
const batch = unique.slice( index, index + PURGE_BATCH );
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
|
|
117
|
+
await transport({
|
|
118
|
+
method : 'POST',
|
|
119
|
+
url : endpoint( zoneId ),
|
|
120
|
+
headers : {
|
|
121
|
+
Authorization : 'Bearer ' + apiToken
|
|
122
|
+
},
|
|
123
|
+
body : {
|
|
124
|
+
files : batch
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
purged += batch.length;
|
|
129
|
+
|
|
130
|
+
} catch ( error ) {
|
|
131
|
+
|
|
132
|
+
// Swallow — the edge self-heals via TTL; the caller's write path
|
|
133
|
+
// must not fail because a purge did.
|
|
134
|
+
if( logger?.error ){
|
|
135
|
+
|
|
136
|
+
logger.error( error, {
|
|
137
|
+
extra : {
|
|
138
|
+
batch : batch.length,
|
|
139
|
+
files : batch.slice( 0, 5 )
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
purged,
|
|
148
|
+
skipped : false
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export { pageEdgeUrls, purge };
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// lib/http.js
|
|
2
|
+
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
3
|
+
var request = async ({
|
|
4
|
+
body,
|
|
5
|
+
headers = {},
|
|
6
|
+
method = "GET",
|
|
7
|
+
query,
|
|
8
|
+
timeout = DEFAULT_TIMEOUT_MS,
|
|
9
|
+
type = "json",
|
|
10
|
+
url
|
|
11
|
+
}) => {
|
|
12
|
+
const fullUrl = new URL(url);
|
|
13
|
+
if (query) {
|
|
14
|
+
Object.entries(query).forEach(([k, v]) => fullUrl.searchParams.set(k, v));
|
|
15
|
+
}
|
|
16
|
+
;
|
|
17
|
+
const isForm = type === "form";
|
|
18
|
+
const response = await fetch(fullUrl.toString(), {
|
|
19
|
+
method,
|
|
20
|
+
headers: {
|
|
21
|
+
"Content-Type": isForm ? "application/x-www-form-urlencoded" : "application/json",
|
|
22
|
+
...headers
|
|
23
|
+
},
|
|
24
|
+
signal: AbortSignal.timeout(timeout),
|
|
25
|
+
...body !== void 0 && {
|
|
26
|
+
body: isForm ? new URLSearchParams(body).toString() : JSON.stringify(body)
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
const text2 = await response.text().catch(() => "");
|
|
31
|
+
const error = new Error(text2 || response.statusText);
|
|
32
|
+
error.status = response.status;
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
;
|
|
36
|
+
const text = await response.text();
|
|
37
|
+
try {
|
|
38
|
+
return text ? JSON.parse(text) : null;
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// index.js
|
|
45
|
+
import { code, data } from "currency-codes";
|
|
46
|
+
import { customAlphabet } from "nanoid";
|
|
47
|
+
|
|
48
|
+
// lib/color.js
|
|
49
|
+
import tinycolor from "tinycolor2";
|
|
50
|
+
var colorFormatted = (value) => {
|
|
51
|
+
const color = tinycolor(value);
|
|
52
|
+
const attributes = {
|
|
53
|
+
brightness: color.getBrightness(),
|
|
54
|
+
dark: color.isDark(),
|
|
55
|
+
light: color.isLight(),
|
|
56
|
+
luminance: color.getLuminance()
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
attributes,
|
|
60
|
+
hex: color.toHexString(),
|
|
61
|
+
hsl: color.toHsl(),
|
|
62
|
+
hsv: color.toHsv(),
|
|
63
|
+
rgb: color.toRgbString()
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
var colorAccessible = (background2) => {
|
|
67
|
+
const white = "#ffffff";
|
|
68
|
+
const black = "#000000";
|
|
69
|
+
return tinycolor.isReadable(
|
|
70
|
+
background2,
|
|
71
|
+
white,
|
|
72
|
+
{
|
|
73
|
+
level: "AA",
|
|
74
|
+
size: "normal"
|
|
75
|
+
}
|
|
76
|
+
) ? white : black;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// lib/constants.js
|
|
80
|
+
var font = {
|
|
81
|
+
family: "Roboto Flex",
|
|
82
|
+
transform: "none",
|
|
83
|
+
weight: "regular"
|
|
84
|
+
};
|
|
85
|
+
var background = "#ffffff";
|
|
86
|
+
var style = {
|
|
87
|
+
background: {
|
|
88
|
+
color: colorFormatted(background)
|
|
89
|
+
},
|
|
90
|
+
body: font,
|
|
91
|
+
button: {
|
|
92
|
+
background: {
|
|
93
|
+
color: colorFormatted(background)
|
|
94
|
+
},
|
|
95
|
+
radius: 0,
|
|
96
|
+
text: {
|
|
97
|
+
color: colorFormatted(colorAccessible(background))
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
heading: font,
|
|
101
|
+
input: {
|
|
102
|
+
radius: 0
|
|
103
|
+
},
|
|
104
|
+
text: {
|
|
105
|
+
color: colorFormatted(colorAccessible(background))
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// index.js
|
|
110
|
+
var nanoid = customAlphabet("0123456789abcdefghijklmnopqrstuvwxyz", 8);
|
|
111
|
+
var megabyte = 1024 * 1024;
|
|
112
|
+
var gigabyte = megabyte * 1024;
|
|
113
|
+
var urlRoot = (string) => (string == null ? void 0 : string.includes("https")) ? "https://" : "http://";
|
|
114
|
+
var shareUrls = ({
|
|
115
|
+
formUri,
|
|
116
|
+
organization,
|
|
117
|
+
page
|
|
118
|
+
}) => {
|
|
119
|
+
var _a;
|
|
120
|
+
const resolvedFormUri = formUri || (typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a.APP_CLIENT_FORM_URI : void 0);
|
|
121
|
+
const preface = urlRoot(resolvedFormUri);
|
|
122
|
+
const base = resolvedFormUri;
|
|
123
|
+
const qr = preface + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.shortId) + "?qr=1";
|
|
124
|
+
const short = preface + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.shortId);
|
|
125
|
+
const url = preface + (organization == null ? void 0 : organization.subdomain) + "." + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.slug);
|
|
126
|
+
const clients = [
|
|
127
|
+
base,
|
|
128
|
+
qr,
|
|
129
|
+
short,
|
|
130
|
+
url
|
|
131
|
+
];
|
|
132
|
+
const urls = {
|
|
133
|
+
qr,
|
|
134
|
+
short,
|
|
135
|
+
url
|
|
136
|
+
};
|
|
137
|
+
if ((organization == null ? void 0 : organization.subdomain) && (page == null ? void 0 : page.shortId)) {
|
|
138
|
+
clients.push(preface + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.shortId));
|
|
139
|
+
clients.push(preface + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.shortId) + "?qr=1");
|
|
140
|
+
clients.push(preface + organization.subdomain + "." + (base == null ? void 0 : base.replace(preface, "")));
|
|
141
|
+
clients.push(preface + organization.subdomain + "." + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.shortId));
|
|
142
|
+
}
|
|
143
|
+
;
|
|
144
|
+
if ((organization == null ? void 0 : organization.shortId) && (page == null ? void 0 : page.slug) && (page == null ? void 0 : page.shortId)) {
|
|
145
|
+
clients.push(preface + organization.shortId + "." + (base == null ? void 0 : base.replace(preface, "")));
|
|
146
|
+
clients.push(preface + organization.shortId + "." + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.slug));
|
|
147
|
+
clients.push(preface + organization.shortId + "." + (base == null ? void 0 : base.replace(preface, "")) + "/" + (page == null ? void 0 : page.shortId));
|
|
148
|
+
}
|
|
149
|
+
;
|
|
150
|
+
return {
|
|
151
|
+
clients,
|
|
152
|
+
urls
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
var currencies = data.map((item) => ({
|
|
156
|
+
...item,
|
|
157
|
+
key: item.currency,
|
|
158
|
+
value: item.code
|
|
159
|
+
}));
|
|
160
|
+
|
|
161
|
+
// lib/cloudflare.js
|
|
162
|
+
var PURGE_BATCH = 30;
|
|
163
|
+
var endpoint = (zoneId) => "https://api.cloudflare.com/client/v4/zones/" + zoneId + "/purge_cache";
|
|
164
|
+
var pageEdgeUrls = ({
|
|
165
|
+
formUri,
|
|
166
|
+
organization,
|
|
167
|
+
page
|
|
168
|
+
}) => {
|
|
169
|
+
if (!page) return [];
|
|
170
|
+
const { clients } = shareUrls({
|
|
171
|
+
formUri,
|
|
172
|
+
organization,
|
|
173
|
+
page
|
|
174
|
+
});
|
|
175
|
+
const set = /* @__PURE__ */ new Set();
|
|
176
|
+
for (const client of clients || []) {
|
|
177
|
+
try {
|
|
178
|
+
const url = new URL(client);
|
|
179
|
+
if (url.pathname && url.pathname !== "/") {
|
|
180
|
+
set.add(url.toString());
|
|
181
|
+
}
|
|
182
|
+
;
|
|
183
|
+
} catch {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
;
|
|
187
|
+
}
|
|
188
|
+
;
|
|
189
|
+
if (page == null ? void 0 : page.slug) {
|
|
190
|
+
for (const item of [...set]) {
|
|
191
|
+
const url = new URL(item);
|
|
192
|
+
if (url.pathname === "/" + page.slug && !url.search) {
|
|
193
|
+
set.add(url.origin + "/" + page.slug + "/embed");
|
|
194
|
+
}
|
|
195
|
+
;
|
|
196
|
+
}
|
|
197
|
+
;
|
|
198
|
+
}
|
|
199
|
+
;
|
|
200
|
+
return [...set];
|
|
201
|
+
};
|
|
202
|
+
var purge = async ({
|
|
203
|
+
files = [],
|
|
204
|
+
logger,
|
|
205
|
+
transport = request
|
|
206
|
+
} = {}) => {
|
|
207
|
+
var _a, _b;
|
|
208
|
+
const apiToken = typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a.CLOUDFLARE_API_TOKEN : void 0;
|
|
209
|
+
const zoneId = typeof process !== "undefined" ? (_b = process.env) == null ? void 0 : _b.CLOUDFLARE_ZONE_ID : void 0;
|
|
210
|
+
if (!apiToken || !zoneId) {
|
|
211
|
+
return {
|
|
212
|
+
purged: 0,
|
|
213
|
+
skipped: true
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
;
|
|
217
|
+
const unique = [...new Set(files.filter(Boolean))];
|
|
218
|
+
let purged = 0;
|
|
219
|
+
for (let index = 0; index < unique.length; index += PURGE_BATCH) {
|
|
220
|
+
const batch = unique.slice(index, index + PURGE_BATCH);
|
|
221
|
+
try {
|
|
222
|
+
await transport({
|
|
223
|
+
method: "POST",
|
|
224
|
+
url: endpoint(zoneId),
|
|
225
|
+
headers: {
|
|
226
|
+
Authorization: "Bearer " + apiToken
|
|
227
|
+
},
|
|
228
|
+
body: {
|
|
229
|
+
files: batch
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
purged += batch.length;
|
|
233
|
+
} catch (error) {
|
|
234
|
+
if (logger == null ? void 0 : logger.error) {
|
|
235
|
+
logger.error(error, {
|
|
236
|
+
extra: {
|
|
237
|
+
batch: batch.length,
|
|
238
|
+
files: batch.slice(0, 5)
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
;
|
|
243
|
+
}
|
|
244
|
+
;
|
|
245
|
+
}
|
|
246
|
+
;
|
|
247
|
+
return {
|
|
248
|
+
purged,
|
|
249
|
+
skipped: false
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
export {
|
|
253
|
+
pageEdgeUrls,
|
|
254
|
+
purge
|
|
255
|
+
};
|
package/package.json
CHANGED
|
@@ -146,6 +146,11 @@
|
|
|
146
146
|
"types": "./dist/plans.d.ts",
|
|
147
147
|
"import": "./dist/plans.js",
|
|
148
148
|
"require": "./dist/plans.cjs"
|
|
149
|
+
},
|
|
150
|
+
"./cloudflare": {
|
|
151
|
+
"types": "./dist/cloudflare.d.ts",
|
|
152
|
+
"import": "./dist/cloudflare.js",
|
|
153
|
+
"require": "./dist/cloudflare.cjs"
|
|
149
154
|
}
|
|
150
155
|
},
|
|
151
156
|
"files": [
|
|
@@ -164,5 +169,5 @@
|
|
|
164
169
|
"test": ". \"$HOME/.nvm/nvm.sh\" && nvm use && node --test"
|
|
165
170
|
},
|
|
166
171
|
"types": "dist/index.d.ts",
|
|
167
|
-
"version": "0.0.
|
|
172
|
+
"version": "0.0.88"
|
|
168
173
|
}
|