@drawbridge/drawbridge-utils 0.0.88 → 0.0.90

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/fetch.cjs CHANGED
@@ -66,7 +66,19 @@ var request = async ({
66
66
  "?" + import_qs.default.stringify(
67
67
  params,
68
68
  {
69
- encode: false
69
+ // Values MUST be percent-encoded. Params routinely carry user input
70
+ // (a list search for `Smith & Sons`) and whole URLs (the OAuth
71
+ // breakout's redirectTo = /api/oauth/authorize?client_id=…&redirect_uri=…).
72
+ // With encoding off entirely, the first `&` inside a value ended that
73
+ // value and the remainder arrived as sibling params: searches
74
+ // truncated silently, and the Shopify account-link resume lost its
75
+ // redirect_uri, dropping the merchant on /organizations instead of
76
+ // back in the embedded app.
77
+ //
78
+ // encodeValuesOnly — not full encoding — because the bracket notation
79
+ // stays readable (search[keys][0]=…), so every query the api already
80
+ // parses is byte-identical whenever the values needed no escaping.
81
+ encodeValuesOnly: true
70
82
  }
71
83
  )
72
84
  );
package/dist/fetch.d.cts CHANGED
@@ -51,7 +51,19 @@ const request = async ({
51
51
  '?' + qs.stringify(
52
52
  params,
53
53
  {
54
- encode : false
54
+ // Values MUST be percent-encoded. Params routinely carry user input
55
+ // (a list search for `Smith & Sons`) and whole URLs (the OAuth
56
+ // breakout's redirectTo = /api/oauth/authorize?client_id=…&redirect_uri=…).
57
+ // With encoding off entirely, the first `&` inside a value ended that
58
+ // value and the remainder arrived as sibling params: searches
59
+ // truncated silently, and the Shopify account-link resume lost its
60
+ // redirect_uri, dropping the merchant on /organizations instead of
61
+ // back in the embedded app.
62
+ //
63
+ // encodeValuesOnly — not full encoding — because the bracket notation
64
+ // stays readable (search[keys][0]=…), so every query the api already
65
+ // parses is byte-identical whenever the values needed no escaping.
66
+ encodeValuesOnly : true
55
67
  }
56
68
  )
57
69
  );
package/dist/fetch.d.ts CHANGED
@@ -51,7 +51,19 @@ const request = async ({
51
51
  '?' + qs.stringify(
52
52
  params,
53
53
  {
54
- encode : false
54
+ // Values MUST be percent-encoded. Params routinely carry user input
55
+ // (a list search for `Smith & Sons`) and whole URLs (the OAuth
56
+ // breakout's redirectTo = /api/oauth/authorize?client_id=…&redirect_uri=…).
57
+ // With encoding off entirely, the first `&` inside a value ended that
58
+ // value and the remainder arrived as sibling params: searches
59
+ // truncated silently, and the Shopify account-link resume lost its
60
+ // redirect_uri, dropping the merchant on /organizations instead of
61
+ // back in the embedded app.
62
+ //
63
+ // encodeValuesOnly — not full encoding — because the bracket notation
64
+ // stays readable (search[keys][0]=…), so every query the api already
65
+ // parses is byte-identical whenever the values needed no escaping.
66
+ encodeValuesOnly : true
55
67
  }
56
68
  )
57
69
  );
package/dist/fetch.js CHANGED
@@ -30,7 +30,19 @@ var request = async ({
30
30
  "?" + qs.stringify(
31
31
  params,
32
32
  {
33
- encode: false
33
+ // Values MUST be percent-encoded. Params routinely carry user input
34
+ // (a list search for `Smith & Sons`) and whole URLs (the OAuth
35
+ // breakout's redirectTo = /api/oauth/authorize?client_id=…&redirect_uri=…).
36
+ // With encoding off entirely, the first `&` inside a value ended that
37
+ // value and the remainder arrived as sibling params: searches
38
+ // truncated silently, and the Shopify account-link resume lost its
39
+ // redirect_uri, dropping the merchant on /organizations instead of
40
+ // back in the embedded app.
41
+ //
42
+ // encodeValuesOnly — not full encoding — because the bracket notation
43
+ // stays readable (search[keys][0]=…), so every query the api already
44
+ // parses is byte-identical whenever the values needed no escaping.
45
+ encodeValuesOnly: true
34
46
  }
35
47
  )
36
48
  );
package/package.json CHANGED
@@ -13,10 +13,10 @@
13
13
  "tinycolor2": "1.6.0"
14
14
  },
15
15
  "devDependencies": {
16
+ "@drawbridge/drawbridge-agents": "0.1.24",
16
17
  "@node-oauth/oauth2-server": "5.3.0",
17
18
  "tsup": "8.5.1",
18
- "typescript": "5.9.3",
19
- "@drawbridge/drawbridge-agents": "0.1.10"
19
+ "typescript": "5.9.3"
20
20
  },
21
21
  "peerDependencies": {
22
22
  "@node-oauth/oauth2-server": "^5.3.0"
@@ -146,11 +146,6 @@
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"
154
149
  }
155
150
  },
156
151
  "files": [
@@ -169,5 +164,5 @@
169
164
  "test": ". \"$HOME/.nvm/nvm.sh\" && nvm use && node --test"
170
165
  },
171
166
  "types": "dist/index.d.ts",
172
- "version": "0.0.88"
167
+ "version": "0.0.90"
173
168
  }
@@ -1,292 +0,0 @@
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
- });
@@ -1,153 +0,0 @@
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 };
@@ -1,153 +0,0 @@
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 };
@@ -1,255 +0,0 @@
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
- };