@chainfuse/helpers 0.1.7 → 0.2.0
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/buffers.mjs +3 -3
- package/dist/discord.d.mts +16 -0
- package/dist/discord.mjs +176 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +1 -0
- package/package.json +5 -4
package/dist/buffers.mjs
CHANGED
|
@@ -60,7 +60,7 @@ export class BufferHelpers {
|
|
|
60
60
|
return Promise.all([CryptoHelpers.secretBytes(16), import('uuid')]).then(([random, { v7: uuidv7 }]) => {
|
|
61
61
|
const uuid = uuidv7({ random });
|
|
62
62
|
const uuidHex = uuid.replaceAll('-', '');
|
|
63
|
-
return this.
|
|
63
|
+
return this.hexToBuffer(uuidHex).then((blob) => ({
|
|
64
64
|
utf8: uuid,
|
|
65
65
|
hex: uuidHex,
|
|
66
66
|
blob,
|
|
@@ -77,7 +77,7 @@ export class BufferHelpers {
|
|
|
77
77
|
input = input.split('_')[1];
|
|
78
78
|
hex = hex.split('_')[1];
|
|
79
79
|
}
|
|
80
|
-
return this.
|
|
80
|
+
return this.hexToBuffer(hex).then((blob) => ({
|
|
81
81
|
utf8: input,
|
|
82
82
|
hex,
|
|
83
83
|
blob,
|
|
@@ -85,7 +85,7 @@ export class BufferHelpers {
|
|
|
85
85
|
}
|
|
86
86
|
else {
|
|
87
87
|
const hex = input;
|
|
88
|
-
return this.
|
|
88
|
+
return this.hexToBuffer(hex).then((blob) => ({
|
|
89
89
|
utf8: `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20)}`,
|
|
90
90
|
hex,
|
|
91
91
|
blob,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CustomLoging } from '@chainfuse/types';
|
|
2
|
+
import type { ExecutionContext } from '@cloudflare/workers-types/experimental';
|
|
3
|
+
import { REST } from '@discordjs/rest';
|
|
4
|
+
export declare class DiscordHelpers {
|
|
5
|
+
/**
|
|
6
|
+
* Discord Epoch, the first second of 2015 or 1420070400000
|
|
7
|
+
* @link https://discord.com/developers/docs/reference#snowflakes
|
|
8
|
+
*/
|
|
9
|
+
static readonly discordEpoch: bigint;
|
|
10
|
+
/**
|
|
11
|
+
* Generate a Discord Snowflake ID from a given date. If no date is provided, the current date is used.
|
|
12
|
+
* @link https://discord.com/developers/docs/reference#snowflake-ids-in-pagination-generating-a-snowflake-id-from-a-timestamp-example
|
|
13
|
+
*/
|
|
14
|
+
static dateToDiscordSnowflake(date?: Date): bigint;
|
|
15
|
+
static discordRest(apiKey: string, cacheTtl?: number, forceCache?: boolean, executionContext?: ExecutionContext, logger?: CustomLoging): REST;
|
|
16
|
+
}
|
package/dist/discord.mjs
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { REST } from '@discordjs/rest';
|
|
2
|
+
import { CryptoHelpers } from './crypto.mjs';
|
|
3
|
+
import { NetHelpers } from './net.mjs';
|
|
4
|
+
export class DiscordHelpers {
|
|
5
|
+
/**
|
|
6
|
+
* Discord Epoch, the first second of 2015 or 1420070400000
|
|
7
|
+
* @link https://discord.com/developers/docs/reference#snowflakes
|
|
8
|
+
*/
|
|
9
|
+
static discordEpoch = BigInt(1420070400000);
|
|
10
|
+
/**
|
|
11
|
+
* Generate a Discord Snowflake ID from a given date. If no date is provided, the current date is used.
|
|
12
|
+
* @link https://discord.com/developers/docs/reference#snowflake-ids-in-pagination-generating-a-snowflake-id-from-a-timestamp-example
|
|
13
|
+
*/
|
|
14
|
+
static dateToDiscordSnowflake(date = new Date()) {
|
|
15
|
+
const minDate = new Date(Number(this.discordEpoch));
|
|
16
|
+
const maxDate = new Date(2 ** 42 - 1);
|
|
17
|
+
if (date < minDate) {
|
|
18
|
+
throw new RangeError("The date is before discord's epoch");
|
|
19
|
+
}
|
|
20
|
+
else if (date > maxDate) {
|
|
21
|
+
throw new RangeError('The date is after the highest supported date');
|
|
22
|
+
}
|
|
23
|
+
return (BigInt(date.valueOf()) - this.discordEpoch) << BigInt(22);
|
|
24
|
+
}
|
|
25
|
+
static discordRest(apiKey, cacheTtl = 24 * 60 * 60, forceCache = false, executionContext, logger = false) {
|
|
26
|
+
return new REST({
|
|
27
|
+
agent: null,
|
|
28
|
+
authPrefix: 'Bot',
|
|
29
|
+
makeRequest: (url, rawInit) => {
|
|
30
|
+
// Extra safety to make sure the string really is a URL
|
|
31
|
+
const info = new URL(url);
|
|
32
|
+
// CF's implementation of `RequestInit` is functionally the same as w3c `RequestInit` but TS doesn't know that
|
|
33
|
+
const init = rawInit;
|
|
34
|
+
const cacheKey = new Request(info, { ...init, headers: NetHelpers.stripSensitiveHeaders(new Headers(init.headers)) });
|
|
35
|
+
if (logger) {
|
|
36
|
+
console.debug('Discord Fetch request', cacheKey.url, JSON.stringify(NetHelpers.initBodyTrimmer({ ...init, headers: Object.fromEntries(NetHelpers.stripSensitiveHeaders(new Headers(init.headers)).entries()) }), null, '\t'));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Only cache GET requests
|
|
40
|
+
* Empty method means GET
|
|
41
|
+
*/
|
|
42
|
+
if (cacheTtl && ((rawInit.method ?? 'GET').toLowerCase() === 'get' || forceCache)) {
|
|
43
|
+
// const cfCacheRef: Promise<Cache> | undefined = caches?.open('cfApi');
|
|
44
|
+
const discordCacheRef = caches?.open(`discordApi`);
|
|
45
|
+
return discordCacheRef
|
|
46
|
+
.then((discordCache) => discordCache
|
|
47
|
+
.match(cacheKey)
|
|
48
|
+
.then(async (cachedResponse) => {
|
|
49
|
+
if (cachedResponse) {
|
|
50
|
+
if (logger) {
|
|
51
|
+
console.debug('Discord Cache hit', cacheKey.url);
|
|
52
|
+
}
|
|
53
|
+
// Clear out bad cache
|
|
54
|
+
if (cachedResponse.status >= 500) {
|
|
55
|
+
if (executionContext) {
|
|
56
|
+
executionContext.waitUntil(discordCache.delete(cacheKey));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
await discordCache.delete(cacheKey);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return cachedResponse;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
if (logger) {
|
|
66
|
+
console.warn('Discord Cache missed', cacheKey.url);
|
|
67
|
+
}
|
|
68
|
+
return NetHelpers.loggingFetch(info, init, undefined, logger).then(async (response) => {
|
|
69
|
+
if (response.ok) {
|
|
70
|
+
response = new Response(response.body, {
|
|
71
|
+
...response,
|
|
72
|
+
headers: NetHelpers.stripSensitiveHeaders(new Headers(response.headers)),
|
|
73
|
+
});
|
|
74
|
+
response.headers.set('Cache-Control', `s-maxage=${cacheTtl}`);
|
|
75
|
+
if (response.headers.has('ETag')) {
|
|
76
|
+
if (executionContext) {
|
|
77
|
+
executionContext.waitUntil(discordCache
|
|
78
|
+
.put(cacheKey, response.clone())
|
|
79
|
+
.then(() => {
|
|
80
|
+
if (logger) {
|
|
81
|
+
console.debug('Discord Cache saved', 'with original etag', cacheKey.url);
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
.catch((error) => {
|
|
85
|
+
if (logger) {
|
|
86
|
+
console.error('Discord Cache put error', error);
|
|
87
|
+
}
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
await discordCache
|
|
92
|
+
.put(cacheKey, response.clone())
|
|
93
|
+
.then(() => {
|
|
94
|
+
if (logger) {
|
|
95
|
+
console.debug('Discord Cache saved', 'with original etag', cacheKey.url);
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
.catch((error) => {
|
|
99
|
+
if (logger) {
|
|
100
|
+
console.error('Discord Cache put error', error);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
if (executionContext) {
|
|
107
|
+
executionContext.waitUntil(CryptoHelpers.generateETag(response)
|
|
108
|
+
.then((etag) => response.headers.set('ETag', etag))
|
|
109
|
+
.then(() => discordCache
|
|
110
|
+
.put(cacheKey, response.clone())
|
|
111
|
+
.then(() => {
|
|
112
|
+
if (logger) {
|
|
113
|
+
console.debug('Discord Cache saved', 'with generated etag', cacheKey.url);
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
.catch((error) => {
|
|
117
|
+
if (logger) {
|
|
118
|
+
console.error('Discord Cache put error', error);
|
|
119
|
+
}
|
|
120
|
+
}))
|
|
121
|
+
.catch((error) => {
|
|
122
|
+
if (logger) {
|
|
123
|
+
console.error('CryptoHelpers generateETag error', error);
|
|
124
|
+
}
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
await CryptoHelpers.generateETag(response)
|
|
129
|
+
.then((etag) => response.headers.set('ETag', etag))
|
|
130
|
+
.then(() => discordCache
|
|
131
|
+
.put(cacheKey, response.clone())
|
|
132
|
+
.then(() => {
|
|
133
|
+
if (logger) {
|
|
134
|
+
console.debug('Discord Cache saved', 'with generated etag', cacheKey.url);
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
.catch((error) => {
|
|
138
|
+
if (logger) {
|
|
139
|
+
console.error('Discord Cache put error', error);
|
|
140
|
+
}
|
|
141
|
+
}))
|
|
142
|
+
.catch((error) => {
|
|
143
|
+
if (logger) {
|
|
144
|
+
console.error('CryptoHelpers generateETag error', error);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return response.clone();
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
.catch((error) => {
|
|
155
|
+
if (logger) {
|
|
156
|
+
console.error('Discord Cache match error', error);
|
|
157
|
+
}
|
|
158
|
+
return NetHelpers.loggingFetch(info, init, undefined, logger);
|
|
159
|
+
}))
|
|
160
|
+
.catch((error) => {
|
|
161
|
+
if (logger) {
|
|
162
|
+
console.error('Discord Cache open error', error);
|
|
163
|
+
}
|
|
164
|
+
return NetHelpers.loggingFetch(info, init, undefined, logger);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
if (logger) {
|
|
169
|
+
console.warn('Discord Cache ignored', cacheKey.url);
|
|
170
|
+
}
|
|
171
|
+
return NetHelpers.loggingFetch(info, init, undefined, logger);
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
}).setToken(apiKey);
|
|
175
|
+
}
|
|
176
|
+
}
|
package/dist/index.d.mts
CHANGED
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chainfuse/helpers",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "ChainFuse",
|
|
6
6
|
"homepage": "https://github.com/ChainFuse/packages/tree/main/packages/helpers#readme",
|
|
@@ -49,13 +49,14 @@
|
|
|
49
49
|
},
|
|
50
50
|
"prettier": "@demosjarco/prettier-config",
|
|
51
51
|
"dependencies": {
|
|
52
|
+
"@discordjs/rest": "^2.4.0",
|
|
52
53
|
"chalk": "^5.3.0",
|
|
53
54
|
"cloudflare": "^3.5.0",
|
|
54
|
-
"uuid": "^11.0.
|
|
55
|
+
"uuid": "^11.0.3"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
|
-
"@chainfuse/types": "^1.1.
|
|
58
|
+
"@chainfuse/types": "^1.1.6",
|
|
58
59
|
"@types/node": "^22.9.0"
|
|
59
60
|
},
|
|
60
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "206ed795a068521dfec992e6ae3b6771c73a3c6a"
|
|
61
62
|
}
|