@certik/skynet 0.25.2 → 0.25.4
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/CHANGELOG.md +8 -0
- package/dist/api.js +38 -38
- package/dist/app.js +287 -281
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +4 -0
- package/dist/deploy.js +22 -19
- package/dist/dynamodb.js +22 -22
- package/dist/email.d.ts +9 -0
- package/dist/email.js +31 -0
- package/dist/indexer.js +134 -131
- package/examples/api.ts +0 -0
- package/examples/indexer.ts +0 -0
- package/examples/mode-indexer.ts +0 -0
- package/package.json +7 -1
- package/src/app.ts +7 -4
- package/src/cli.ts +6 -1
- package/src/email.ts +40 -0
- package/.vscode/settings.json +0 -5
package/dist/cli.js
CHANGED
|
@@ -33,7 +33,11 @@ function detectBin() {
|
|
|
33
33
|
const wd = detectDirectory(process.argv[1], "package.json");
|
|
34
34
|
return process.argv[1].slice(wd.length + path.sep.length).replace(path.sep, "/");
|
|
35
35
|
}
|
|
36
|
+
function getDeployBin(bin) {
|
|
37
|
+
return bin.endsWith(".ts") ? `bun ${bin}` : bin;
|
|
38
|
+
}
|
|
36
39
|
export {
|
|
40
|
+
getDeployBin,
|
|
37
41
|
getBinaryName,
|
|
38
42
|
detectWorkingDirectory,
|
|
39
43
|
detectSkynetDirectory,
|
package/dist/deploy.js
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
// src/env.ts
|
|
2
|
+
function ensureAndGet(envName, defaultValue) {
|
|
3
|
+
return process.env[envName] || defaultValue;
|
|
4
|
+
}
|
|
5
|
+
function getEnvironment() {
|
|
6
|
+
return ensureAndGet("SKYNET_ENVIRONMENT", "dev");
|
|
7
|
+
}
|
|
8
|
+
function getEnvOrThrow(envName) {
|
|
9
|
+
if (!process.env[envName]) {
|
|
10
|
+
throw new Error(`Must set environment variable ${envName}`);
|
|
11
|
+
}
|
|
12
|
+
return process.env[envName];
|
|
13
|
+
}
|
|
14
|
+
function isProduction() {
|
|
15
|
+
return getEnvironment() === "prd";
|
|
16
|
+
}
|
|
17
|
+
function isDev() {
|
|
18
|
+
return getEnvironment() === "dev";
|
|
19
|
+
}
|
|
1
20
|
// src/selector.ts
|
|
2
21
|
function getSelectorDesc(selector) {
|
|
3
22
|
return Object.keys(selector).map((name) => {
|
|
@@ -36,25 +55,6 @@ function getJobName(name, selectorFlags, mode) {
|
|
|
36
55
|
}
|
|
37
56
|
return jobName;
|
|
38
57
|
}
|
|
39
|
-
// src/env.ts
|
|
40
|
-
function ensureAndGet(envName, defaultValue) {
|
|
41
|
-
return process.env[envName] || defaultValue;
|
|
42
|
-
}
|
|
43
|
-
function getEnvironment() {
|
|
44
|
-
return ensureAndGet("SKYNET_ENVIRONMENT", "dev");
|
|
45
|
-
}
|
|
46
|
-
function getEnvOrThrow(envName) {
|
|
47
|
-
if (!process.env[envName]) {
|
|
48
|
-
throw new Error(`Must set environment variable ${envName}`);
|
|
49
|
-
}
|
|
50
|
-
return process.env[envName];
|
|
51
|
-
}
|
|
52
|
-
function isProduction() {
|
|
53
|
-
return getEnvironment() === "prd";
|
|
54
|
-
}
|
|
55
|
-
function isDev() {
|
|
56
|
-
return getEnvironment() === "dev";
|
|
57
|
-
}
|
|
58
58
|
// src/cli.ts
|
|
59
59
|
import path from "path";
|
|
60
60
|
import fs from "fs";
|
|
@@ -90,6 +90,9 @@ function detectBin() {
|
|
|
90
90
|
const wd = detectDirectory(process.argv[1], "package.json");
|
|
91
91
|
return process.argv[1].slice(wd.length + path.sep.length).replace(path.sep, "/");
|
|
92
92
|
}
|
|
93
|
+
function getDeployBin(bin) {
|
|
94
|
+
return bin.endsWith(".ts") ? `bun ${bin}` : bin;
|
|
95
|
+
}
|
|
93
96
|
// src/deploy.ts
|
|
94
97
|
import fs2 from "fs/promises";
|
|
95
98
|
import fso from "fs";
|
package/dist/dynamodb.js
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
// src/util.ts
|
|
2
|
+
function range(startAt, endAt, step) {
|
|
3
|
+
const arr = [];
|
|
4
|
+
for (let i = startAt;i <= endAt; i += step) {
|
|
5
|
+
arr.push([i, Math.min(endAt, i + step - 1)]);
|
|
6
|
+
}
|
|
7
|
+
return arr;
|
|
8
|
+
}
|
|
9
|
+
function arrayGroup(array, groupSize) {
|
|
10
|
+
const groups = [];
|
|
11
|
+
for (let i = 0;i < array.length; i += groupSize) {
|
|
12
|
+
groups.push(array.slice(i, i + groupSize));
|
|
13
|
+
}
|
|
14
|
+
return groups;
|
|
15
|
+
}
|
|
16
|
+
function fillRange(start, end) {
|
|
17
|
+
const result = [];
|
|
18
|
+
for (let i = start;i <= end; i++) {
|
|
19
|
+
result.push(i);
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
1
23
|
// src/object-hash.ts
|
|
2
24
|
import xh from "@node-rs/xxhash";
|
|
3
25
|
function getHash(obj) {
|
|
@@ -124,28 +146,6 @@ function memoize(func, options) {
|
|
|
124
146
|
}
|
|
125
147
|
return pMemoize(func, options);
|
|
126
148
|
}
|
|
127
|
-
// src/util.ts
|
|
128
|
-
function range(startAt, endAt, step) {
|
|
129
|
-
const arr = [];
|
|
130
|
-
for (let i = startAt;i <= endAt; i += step) {
|
|
131
|
-
arr.push([i, Math.min(endAt, i + step - 1)]);
|
|
132
|
-
}
|
|
133
|
-
return arr;
|
|
134
|
-
}
|
|
135
|
-
function arrayGroup(array, groupSize) {
|
|
136
|
-
const groups = [];
|
|
137
|
-
for (let i = 0;i < array.length; i += groupSize) {
|
|
138
|
-
groups.push(array.slice(i, i + groupSize));
|
|
139
|
-
}
|
|
140
|
-
return groups;
|
|
141
|
-
}
|
|
142
|
-
function fillRange(start, end) {
|
|
143
|
-
const result = [];
|
|
144
|
-
for (let i = start;i <= end; i++) {
|
|
145
|
-
result.push(i);
|
|
146
|
-
}
|
|
147
|
-
return result;
|
|
148
|
-
}
|
|
149
149
|
// src/dynamodb.ts
|
|
150
150
|
import {
|
|
151
151
|
DynamoDBDocumentClient,
|
package/dist/email.d.ts
ADDED
package/dist/email.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/email.ts
|
|
2
|
+
import Mailgun from "mailgun.js";
|
|
3
|
+
import formData from "form-data";
|
|
4
|
+
async function sendEmail({ to, subject, html, from, text }) {
|
|
5
|
+
const apiKey = process.env.MAILGUN_API_KEY;
|
|
6
|
+
if (!apiKey) {
|
|
7
|
+
throw new Error("missing MAILGUN_API_KEY");
|
|
8
|
+
}
|
|
9
|
+
const domain = process.env.MAILGUN_DOMAIN;
|
|
10
|
+
if (!domain) {
|
|
11
|
+
throw new Error("missing MAILGUN_DOMAIN");
|
|
12
|
+
}
|
|
13
|
+
const mailgun = new Mailgun(formData);
|
|
14
|
+
const mg = mailgun.client({ username: "api", key: apiKey });
|
|
15
|
+
const recipients = Array.isArray(to) ? to : [to];
|
|
16
|
+
try {
|
|
17
|
+
await mg.messages.create(domain, {
|
|
18
|
+
from,
|
|
19
|
+
to: recipients,
|
|
20
|
+
subject,
|
|
21
|
+
...text ? { text } : {},
|
|
22
|
+
html
|
|
23
|
+
});
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error("failed to send email", error);
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
sendEmail
|
|
31
|
+
};
|
package/dist/indexer.js
CHANGED
|
@@ -1,41 +1,3 @@
|
|
|
1
|
-
// src/selector.ts
|
|
2
|
-
function getSelectorDesc(selector) {
|
|
3
|
-
return Object.keys(selector).map((name) => {
|
|
4
|
-
return ` --${name.padEnd(14)}${selector[name].desc || selector[name].description || ""}`;
|
|
5
|
-
}).join(`
|
|
6
|
-
`);
|
|
7
|
-
}
|
|
8
|
-
function getSelectorFlags(selector) {
|
|
9
|
-
return Object.keys(selector).reduce((acc, name) => {
|
|
10
|
-
const flag = {
|
|
11
|
-
type: selector[name].type || "string",
|
|
12
|
-
...selector[name]
|
|
13
|
-
};
|
|
14
|
-
if (!selector[name].optional && selector[name].isRequired !== false) {
|
|
15
|
-
flag.isRequired = true;
|
|
16
|
-
}
|
|
17
|
-
return { ...acc, [name]: flag };
|
|
18
|
-
}, {});
|
|
19
|
-
}
|
|
20
|
-
function toSelectorString(selectorFlags, delim = ",") {
|
|
21
|
-
return Object.keys(selectorFlags).sort().map((flag) => {
|
|
22
|
-
return `${flag}=${selectorFlags[flag]}`;
|
|
23
|
-
}).join(delim);
|
|
24
|
-
}
|
|
25
|
-
function normalizeSelectorValue(v) {
|
|
26
|
-
return v.replace(/[^A-Za-z0-9]+/g, "-");
|
|
27
|
-
}
|
|
28
|
-
function getJobName(name, selectorFlags, mode) {
|
|
29
|
-
const selectorNamePart = Object.keys(selectorFlags).sort().map((name2) => selectorFlags[name2]).join("-");
|
|
30
|
-
let jobName = name;
|
|
31
|
-
if (mode) {
|
|
32
|
-
jobName += `-${mode}`;
|
|
33
|
-
}
|
|
34
|
-
if (selectorNamePart.length > 0) {
|
|
35
|
-
jobName += `-${normalizeSelectorValue(selectorNamePart)}`;
|
|
36
|
-
}
|
|
37
|
-
return jobName;
|
|
38
|
-
}
|
|
39
1
|
// src/env.ts
|
|
40
2
|
function ensureAndGet(envName, defaultValue) {
|
|
41
3
|
return process.env[envName] || defaultValue;
|
|
@@ -55,63 +17,56 @@ function isProduction() {
|
|
|
55
17
|
function isDev() {
|
|
56
18
|
return getEnvironment() === "dev";
|
|
57
19
|
}
|
|
58
|
-
// src/
|
|
59
|
-
function
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (Array.isArray(o)) {
|
|
64
|
-
return `[${o.map(print).join(", ")}]`;
|
|
20
|
+
// src/util.ts
|
|
21
|
+
function range(startAt, endAt, step) {
|
|
22
|
+
const arr = [];
|
|
23
|
+
for (let i = startAt;i <= endAt; i += step) {
|
|
24
|
+
arr.push([i, Math.min(endAt, i + step - 1)]);
|
|
65
25
|
}
|
|
66
|
-
|
|
67
|
-
|
|
26
|
+
return arr;
|
|
27
|
+
}
|
|
28
|
+
function arrayGroup(array, groupSize) {
|
|
29
|
+
const groups = [];
|
|
30
|
+
for (let i = 0;i < array.length; i += groupSize) {
|
|
31
|
+
groups.push(array.slice(i, i + groupSize));
|
|
68
32
|
}
|
|
69
|
-
return
|
|
33
|
+
return groups;
|
|
70
34
|
}
|
|
71
|
-
function
|
|
72
|
-
|
|
73
|
-
for (let i =
|
|
74
|
-
|
|
35
|
+
function fillRange(start, end) {
|
|
36
|
+
const result = [];
|
|
37
|
+
for (let i = start;i <= end; i++) {
|
|
38
|
+
result.push(i);
|
|
75
39
|
}
|
|
76
|
-
return
|
|
40
|
+
return result;
|
|
77
41
|
}
|
|
78
|
-
|
|
79
|
-
|
|
42
|
+
// src/date.ts
|
|
43
|
+
var MS_IN_A_DAY = 3600 * 24 * 1000;
|
|
44
|
+
function getDateOnly(date) {
|
|
45
|
+
return new Date(date).toISOString().split("T")[0];
|
|
80
46
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
},
|
|
92
|
-
error: function(...args) {
|
|
93
|
-
if (true) {
|
|
94
|
-
console.error(`${timestamp()} ${getLine(args)}`);
|
|
95
|
-
}
|
|
47
|
+
function findDateAfter(date, n) {
|
|
48
|
+
const d = new Date(date);
|
|
49
|
+
const after = new Date(d.getTime() + MS_IN_A_DAY * n);
|
|
50
|
+
return getDateOnly(after);
|
|
51
|
+
}
|
|
52
|
+
function daysInRange(from, to) {
|
|
53
|
+
const fromTime = new Date(from).getTime();
|
|
54
|
+
const toTime = new Date(to).getTime();
|
|
55
|
+
if (fromTime > toTime) {
|
|
56
|
+
throw new Error(`range to date couldn't be earlier than range from date`);
|
|
96
57
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
console.log(`[${timestamp()}]`, ...args);
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
log: function(...args) {
|
|
105
|
-
if (true) {
|
|
106
|
-
console.log(`[${timestamp()}]`, ...args);
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
error: function(...args) {
|
|
110
|
-
if (true) {
|
|
111
|
-
console.error(`[${timestamp()}]`, ...args);
|
|
112
|
-
}
|
|
58
|
+
const daysBetween = Math.floor((toTime - fromTime) / MS_IN_A_DAY);
|
|
59
|
+
const dates = [getDateOnly(new Date(fromTime))];
|
|
60
|
+
for (let i = 1;i <= daysBetween; i += 1) {
|
|
61
|
+
dates.push(getDateOnly(new Date(fromTime + i * MS_IN_A_DAY)));
|
|
113
62
|
}
|
|
114
|
-
|
|
63
|
+
return dates;
|
|
64
|
+
}
|
|
65
|
+
function dateRange(from, to, step) {
|
|
66
|
+
const days = daysInRange(from, to);
|
|
67
|
+
const windows = arrayGroup(days, step);
|
|
68
|
+
return windows.map((w) => [w[0], w[w.length - 1]]);
|
|
69
|
+
}
|
|
115
70
|
// src/object-hash.ts
|
|
116
71
|
import xh from "@node-rs/xxhash";
|
|
117
72
|
function getHash(obj) {
|
|
@@ -238,28 +193,63 @@ function memoize(func, options) {
|
|
|
238
193
|
}
|
|
239
194
|
return pMemoize(func, options);
|
|
240
195
|
}
|
|
241
|
-
// src/
|
|
242
|
-
function
|
|
243
|
-
|
|
244
|
-
for (let i = startAt;i <= endAt; i += step) {
|
|
245
|
-
arr.push([i, Math.min(endAt, i + step - 1)]);
|
|
246
|
-
}
|
|
247
|
-
return arr;
|
|
196
|
+
// src/log.ts
|
|
197
|
+
function isObject(a) {
|
|
198
|
+
return !!a && a.constructor === Object;
|
|
248
199
|
}
|
|
249
|
-
function
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
groups.push(array.slice(i, i + groupSize));
|
|
200
|
+
function print(o) {
|
|
201
|
+
if (Array.isArray(o)) {
|
|
202
|
+
return `[${o.map(print).join(", ")}]`;
|
|
253
203
|
}
|
|
254
|
-
|
|
204
|
+
if (isObject(o)) {
|
|
205
|
+
return `{${Object.keys(o).map((k) => `${k}: ${o[k]}`).join(", ")}}`;
|
|
206
|
+
}
|
|
207
|
+
return `${o}`;
|
|
255
208
|
}
|
|
256
|
-
function
|
|
257
|
-
|
|
258
|
-
for (let i =
|
|
259
|
-
|
|
209
|
+
function getLine(params) {
|
|
210
|
+
let line = "";
|
|
211
|
+
for (let i = 0, l = params.length;i < l; i++) {
|
|
212
|
+
line += `${print(params[i])} `.replace(/\n/gm, "\t");
|
|
260
213
|
}
|
|
261
|
-
return
|
|
214
|
+
return line.trim();
|
|
262
215
|
}
|
|
216
|
+
function timestamp() {
|
|
217
|
+
return new Date().toISOString();
|
|
218
|
+
}
|
|
219
|
+
var inline = {
|
|
220
|
+
debug: function(...args) {
|
|
221
|
+
if (true) {
|
|
222
|
+
console.log(`${timestamp()} ${getLine(args)}`);
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
log: function(...args) {
|
|
226
|
+
if (true) {
|
|
227
|
+
console.log(`${timestamp()} ${getLine(args)}`);
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
error: function(...args) {
|
|
231
|
+
if (true) {
|
|
232
|
+
console.error(`${timestamp()} ${getLine(args)}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
var logger = {
|
|
237
|
+
debug: function(...args) {
|
|
238
|
+
if (true) {
|
|
239
|
+
console.log(`[${timestamp()}]`, ...args);
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
log: function(...args) {
|
|
243
|
+
if (true) {
|
|
244
|
+
console.log(`[${timestamp()}]`, ...args);
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
error: function(...args) {
|
|
248
|
+
if (true) {
|
|
249
|
+
console.error(`[${timestamp()}]`, ...args);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
};
|
|
263
253
|
// src/dynamodb.ts
|
|
264
254
|
import {
|
|
265
255
|
DynamoDBDocumentClient,
|
|
@@ -574,6 +564,44 @@ async function deleteRecordsByHashKey(tableName, indexName, hashKeyValue, verbos
|
|
|
574
564
|
}
|
|
575
565
|
return totalDeleted;
|
|
576
566
|
}
|
|
567
|
+
// src/selector.ts
|
|
568
|
+
function getSelectorDesc(selector) {
|
|
569
|
+
return Object.keys(selector).map((name) => {
|
|
570
|
+
return ` --${name.padEnd(14)}${selector[name].desc || selector[name].description || ""}`;
|
|
571
|
+
}).join(`
|
|
572
|
+
`);
|
|
573
|
+
}
|
|
574
|
+
function getSelectorFlags(selector) {
|
|
575
|
+
return Object.keys(selector).reduce((acc, name) => {
|
|
576
|
+
const flag = {
|
|
577
|
+
type: selector[name].type || "string",
|
|
578
|
+
...selector[name]
|
|
579
|
+
};
|
|
580
|
+
if (!selector[name].optional && selector[name].isRequired !== false) {
|
|
581
|
+
flag.isRequired = true;
|
|
582
|
+
}
|
|
583
|
+
return { ...acc, [name]: flag };
|
|
584
|
+
}, {});
|
|
585
|
+
}
|
|
586
|
+
function toSelectorString(selectorFlags, delim = ",") {
|
|
587
|
+
return Object.keys(selectorFlags).sort().map((flag) => {
|
|
588
|
+
return `${flag}=${selectorFlags[flag]}`;
|
|
589
|
+
}).join(delim);
|
|
590
|
+
}
|
|
591
|
+
function normalizeSelectorValue(v) {
|
|
592
|
+
return v.replace(/[^A-Za-z0-9]+/g, "-");
|
|
593
|
+
}
|
|
594
|
+
function getJobName(name, selectorFlags, mode) {
|
|
595
|
+
const selectorNamePart = Object.keys(selectorFlags).sort().map((name2) => selectorFlags[name2]).join("-");
|
|
596
|
+
let jobName = name;
|
|
597
|
+
if (mode) {
|
|
598
|
+
jobName += `-${mode}`;
|
|
599
|
+
}
|
|
600
|
+
if (selectorNamePart.length > 0) {
|
|
601
|
+
jobName += `-${normalizeSelectorValue(selectorNamePart)}`;
|
|
602
|
+
}
|
|
603
|
+
return jobName;
|
|
604
|
+
}
|
|
577
605
|
// src/cli.ts
|
|
578
606
|
import path from "path";
|
|
579
607
|
import fs from "fs";
|
|
@@ -609,33 +637,8 @@ function detectBin() {
|
|
|
609
637
|
const wd = detectDirectory(process.argv[1], "package.json");
|
|
610
638
|
return process.argv[1].slice(wd.length + path.sep.length).replace(path.sep, "/");
|
|
611
639
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
function getDateOnly(date) {
|
|
615
|
-
return new Date(date).toISOString().split("T")[0];
|
|
616
|
-
}
|
|
617
|
-
function findDateAfter(date, n) {
|
|
618
|
-
const d = new Date(date);
|
|
619
|
-
const after = new Date(d.getTime() + MS_IN_A_DAY * n);
|
|
620
|
-
return getDateOnly(after);
|
|
621
|
-
}
|
|
622
|
-
function daysInRange(from, to) {
|
|
623
|
-
const fromTime = new Date(from).getTime();
|
|
624
|
-
const toTime = new Date(to).getTime();
|
|
625
|
-
if (fromTime > toTime) {
|
|
626
|
-
throw new Error(`range to date couldn't be earlier than range from date`);
|
|
627
|
-
}
|
|
628
|
-
const daysBetween = Math.floor((toTime - fromTime) / MS_IN_A_DAY);
|
|
629
|
-
const dates = [getDateOnly(new Date(fromTime))];
|
|
630
|
-
for (let i = 1;i <= daysBetween; i += 1) {
|
|
631
|
-
dates.push(getDateOnly(new Date(fromTime + i * MS_IN_A_DAY)));
|
|
632
|
-
}
|
|
633
|
-
return dates;
|
|
634
|
-
}
|
|
635
|
-
function dateRange(from, to, step) {
|
|
636
|
-
const days = daysInRange(from, to);
|
|
637
|
-
const windows = arrayGroup(days, step);
|
|
638
|
-
return windows.map((w) => [w[0], w[w.length - 1]]);
|
|
640
|
+
function getDeployBin(bin) {
|
|
641
|
+
return bin.endsWith(".ts") ? `bun ${bin}` : bin;
|
|
639
642
|
}
|
|
640
643
|
// src/indexer.ts
|
|
641
644
|
import meow from "meow";
|
package/examples/api.ts
CHANGED
|
File without changes
|
package/examples/indexer.ts
CHANGED
|
File without changes
|
package/examples/mode-indexer.ts
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@certik/skynet",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.4",
|
|
4
4
|
"description": "Skynet Shared JS library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -44,6 +44,10 @@
|
|
|
44
44
|
"import": "./dist/dynamodb.js",
|
|
45
45
|
"types": "./dist/dynamodb.d.ts"
|
|
46
46
|
},
|
|
47
|
+
"./email": {
|
|
48
|
+
"import": "./dist/email.js",
|
|
49
|
+
"types": "./dist/email.d.ts"
|
|
50
|
+
},
|
|
47
51
|
"./env": {
|
|
48
52
|
"import": "./dist/env.js",
|
|
49
53
|
"types": "./dist/env.d.ts"
|
|
@@ -116,6 +120,8 @@
|
|
|
116
120
|
"chalk": "^5.6.2",
|
|
117
121
|
"execa": "^9.6.1",
|
|
118
122
|
"express": "^5.2.1",
|
|
123
|
+
"form-data": "^4.0.5",
|
|
124
|
+
"mailgun.js": "^12.7.1",
|
|
119
125
|
"meow": "^14.0.0",
|
|
120
126
|
"p-memoize": "^8.0.0",
|
|
121
127
|
"p-throttle": "^8.1.0",
|
package/src/app.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { createDeploy, createModeDeploy } from "./deploy";
|
|
|
5
5
|
import type { Env } from "./deploy";
|
|
6
6
|
import { startApiApp } from "./api.js";
|
|
7
7
|
import type { Middleware } from "./api";
|
|
8
|
-
import { getBinaryName, detectBin, detectWorkingDirectory } from "./cli.js";
|
|
8
|
+
import { getBinaryName, detectBin, detectWorkingDirectory, getDeployBin } from "./cli.js";
|
|
9
9
|
import type { Selector } from "./selector";
|
|
10
10
|
import type { Request, Response, Application } from "express";
|
|
11
11
|
|
|
@@ -203,13 +203,14 @@ function indexer<TSelector extends Selector>({
|
|
|
203
203
|
},
|
|
204
204
|
onDeploy: () => {
|
|
205
205
|
const bin = detectBin();
|
|
206
|
+
const runBin = getDeployBin(bin);
|
|
206
207
|
const needDoppler = Object.values(env).some((v) => v === SENSITIVE_VALUE);
|
|
207
208
|
|
|
208
209
|
const { deploy } = createDeploy({
|
|
209
210
|
binaryName: `${getBinaryName()} deploy`,
|
|
210
211
|
name,
|
|
211
212
|
workingDirectory: detectWorkingDirectory(),
|
|
212
|
-
bin: needDoppler ? `doppler run -- ${
|
|
213
|
+
bin: needDoppler ? `doppler run -- ${runBin} run` : `${runBin} run`,
|
|
213
214
|
selector,
|
|
214
215
|
region,
|
|
215
216
|
env,
|
|
@@ -313,13 +314,14 @@ function modeIndexer<T extends IndexerStateValue, TSelector extends Selector>({
|
|
|
313
314
|
},
|
|
314
315
|
onDeploy: () => {
|
|
315
316
|
const bin = detectBin();
|
|
317
|
+
const runBin = getDeployBin(bin);
|
|
316
318
|
const needDoppler = Object.values(env).some((v) => v === SENSITIVE_VALUE);
|
|
317
319
|
|
|
318
320
|
const { deploy } = createModeDeploy({
|
|
319
321
|
binaryName: `${getBinaryName()} deploy`,
|
|
320
322
|
name,
|
|
321
323
|
workingDirectory: detectWorkingDirectory(),
|
|
322
|
-
bin: needDoppler ? `doppler run -- ${
|
|
324
|
+
bin: needDoppler ? `doppler run -- ${runBin} run` : `${runBin} run`,
|
|
323
325
|
selector,
|
|
324
326
|
region,
|
|
325
327
|
env,
|
|
@@ -437,13 +439,14 @@ function api({
|
|
|
437
439
|
},
|
|
438
440
|
onDeploy: () => {
|
|
439
441
|
const bin = detectBin();
|
|
442
|
+
const runBin = getDeployBin(bin);
|
|
440
443
|
const needDoppler = Object.values(env).some((v) => v === SENSITIVE_VALUE);
|
|
441
444
|
|
|
442
445
|
const { deploy } = createDeploy({
|
|
443
446
|
binaryName: `${getBinaryName()} deploy`,
|
|
444
447
|
name,
|
|
445
448
|
workingDirectory: detectWorkingDirectory(),
|
|
446
|
-
bin: needDoppler ? `doppler run -- ${
|
|
449
|
+
bin: needDoppler ? `doppler run -- ${runBin} run` : `${runBin} run`,
|
|
447
450
|
selector,
|
|
448
451
|
region,
|
|
449
452
|
env,
|
package/src/cli.ts
CHANGED
|
@@ -45,4 +45,9 @@ function detectBin() {
|
|
|
45
45
|
return process.argv[1].slice(wd.length + path.sep.length).replace(path.sep, "/");
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
// Run ts files via bun so Nomad/Doppler don't try to exec the file directly.
|
|
49
|
+
function getDeployBin(bin: string): string {
|
|
50
|
+
return bin.endsWith(".ts") ? `bun ${bin}` : bin;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { getBinaryName, detectSkynetDirectory, detectWorkingDirectory, detectBin, getDeployBin };
|
package/src/email.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import Mailgun from "mailgun.js";
|
|
2
|
+
import formData from "form-data";
|
|
3
|
+
|
|
4
|
+
interface SendEmailOptions {
|
|
5
|
+
to: string | string[];
|
|
6
|
+
subject: string;
|
|
7
|
+
html: string;
|
|
8
|
+
from: string;
|
|
9
|
+
text?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function sendEmail({ to, subject, html, from, text }: SendEmailOptions) {
|
|
13
|
+
const apiKey = process.env.MAILGUN_API_KEY;
|
|
14
|
+
if (!apiKey) {
|
|
15
|
+
throw new Error("missing MAILGUN_API_KEY");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const domain = process.env.MAILGUN_DOMAIN;
|
|
19
|
+
if (!domain) {
|
|
20
|
+
throw new Error("missing MAILGUN_DOMAIN");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const mailgun = new Mailgun(formData);
|
|
24
|
+
const mg = mailgun.client({ username: "api", key: apiKey });
|
|
25
|
+
|
|
26
|
+
const recipients = Array.isArray(to) ? to : [to];
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
await mg.messages.create(domain, {
|
|
30
|
+
from,
|
|
31
|
+
to: recipients,
|
|
32
|
+
subject,
|
|
33
|
+
...(text ? { text } : {}),
|
|
34
|
+
html,
|
|
35
|
+
});
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error("failed to send email", error);
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|