@getstrata/core 0.5.10 → 0.5.12
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/core/database/baseRepository.d.ts +4 -1
- package/dist/core/database/index.d.ts +2 -2
- package/dist/core/database/relationships.d.ts +46 -2
- package/dist/core/database/repositoryQuery.d.ts +4 -1
- package/dist/core/mail/mailer.d.ts +3 -1
- package/dist/core/mail/markdownMail.d.ts +15 -0
- package/dist/core/mail/markdownMailable.d.ts +13 -0
- package/dist/core/notifications/dispatcher.d.ts +13 -0
- package/dist/core/notifications/index.d.ts +3 -0
- package/dist/core/notifications/notification.d.ts +7 -0
- package/dist/core/notifications/types.d.ts +25 -0
- package/dist/entries/auth/guard.js +168 -0
- package/dist/entries/database.js +174 -0
- package/dist/entries/http/webErrorResponse.js +168 -0
- package/dist/entries/http.js +168 -0
- package/dist/entries/queue/createAppQueue.js +168 -0
- package/dist/entries/queue/publicQueue.js +168 -0
- package/dist/entries/queue/queueMetrics.js +168 -0
- package/dist/entries/view.js +168 -0
- package/dist/framework/public-api.d.ts +9 -3
- package/dist/index.js +352 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -942,6 +942,66 @@ function indexBelongsToManyRelation(parents, pivotRows, relatedRows, relation) {
|
|
|
942
942
|
}
|
|
943
943
|
return groups;
|
|
944
944
|
}
|
|
945
|
+
function morphMany(definition) {
|
|
946
|
+
return {
|
|
947
|
+
type: "morphMany",
|
|
948
|
+
...definition
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
function morphOne(definition) {
|
|
952
|
+
return {
|
|
953
|
+
type: "morphOne",
|
|
954
|
+
...definition
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
function morphTo(definition) {
|
|
958
|
+
return {
|
|
959
|
+
type: "morphTo",
|
|
960
|
+
...definition
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
function indexMorphManyRelation(parents, children, relation) {
|
|
964
|
+
const groups = new Map;
|
|
965
|
+
for (const parent of parents) {
|
|
966
|
+
groups.set(parent[relation.localKey], []);
|
|
967
|
+
}
|
|
968
|
+
for (const child of children) {
|
|
969
|
+
if (child[relation.morphTypeKey] !== relation.morphType) {
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
const key = child[relation.morphIdKey];
|
|
973
|
+
const group = groups.get(key);
|
|
974
|
+
if (!group) {
|
|
975
|
+
continue;
|
|
976
|
+
}
|
|
977
|
+
group.push(child);
|
|
978
|
+
}
|
|
979
|
+
return groups;
|
|
980
|
+
}
|
|
981
|
+
function indexMorphOneRelation(parents, children, relation) {
|
|
982
|
+
const grouped = indexMorphManyRelation(parents, children, relation);
|
|
983
|
+
const result = new Map;
|
|
984
|
+
for (const parent of parents) {
|
|
985
|
+
const matches = grouped.get(parent[relation.localKey]) ?? [];
|
|
986
|
+
result.set(parent[relation.localKey], matches[0]);
|
|
987
|
+
}
|
|
988
|
+
return result;
|
|
989
|
+
}
|
|
990
|
+
function indexMorphToRelation(children, parentsByType, relation) {
|
|
991
|
+
const result = new Map;
|
|
992
|
+
for (const child of children) {
|
|
993
|
+
const morphType = String(child[relation.morphTypeKey]);
|
|
994
|
+
const parents = parentsByType.get(morphType);
|
|
995
|
+
if (!parents) {
|
|
996
|
+
continue;
|
|
997
|
+
}
|
|
998
|
+
const parent = parents.get(child[relation.morphIdKey]);
|
|
999
|
+
if (parent) {
|
|
1000
|
+
result.set(child[relation.morphIdKey], parent);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
return result;
|
|
1004
|
+
}
|
|
945
1005
|
|
|
946
1006
|
// ../../src/config/database.ts
|
|
947
1007
|
function readInteger(name, fallback) {
|
|
@@ -1145,6 +1205,37 @@ class RepositoryQuery {
|
|
|
1145
1205
|
});
|
|
1146
1206
|
return this;
|
|
1147
1207
|
}
|
|
1208
|
+
withMorphMany(as, relation, childRepository, options = {}) {
|
|
1209
|
+
this.eagerLoads.push({
|
|
1210
|
+
kind: "morphMany",
|
|
1211
|
+
as,
|
|
1212
|
+
relation,
|
|
1213
|
+
repository: childRepository,
|
|
1214
|
+
options
|
|
1215
|
+
});
|
|
1216
|
+
return this;
|
|
1217
|
+
}
|
|
1218
|
+
withMorphOne(as, relation, childRepository, options = {}) {
|
|
1219
|
+
this.eagerLoads.push({
|
|
1220
|
+
kind: "morphOne",
|
|
1221
|
+
as,
|
|
1222
|
+
relation,
|
|
1223
|
+
repository: childRepository,
|
|
1224
|
+
options
|
|
1225
|
+
});
|
|
1226
|
+
return this;
|
|
1227
|
+
}
|
|
1228
|
+
withMorphTo(as, relation, repositoriesByType, options = {}) {
|
|
1229
|
+
this.eagerLoads.push({
|
|
1230
|
+
kind: "morphTo",
|
|
1231
|
+
as,
|
|
1232
|
+
relation,
|
|
1233
|
+
repository: this.repository,
|
|
1234
|
+
morphRepositories: repositoriesByType,
|
|
1235
|
+
options
|
|
1236
|
+
});
|
|
1237
|
+
return this;
|
|
1238
|
+
}
|
|
1148
1239
|
async get() {
|
|
1149
1240
|
const rows = await this.repository.findAll(this.buildOptions());
|
|
1150
1241
|
return await this.attach(rows);
|
|
@@ -1205,6 +1296,33 @@ class RepositoryQuery {
|
|
|
1205
1296
|
}));
|
|
1206
1297
|
continue;
|
|
1207
1298
|
}
|
|
1299
|
+
if (load.kind === "morphMany") {
|
|
1300
|
+
const relation2 = load.relation;
|
|
1301
|
+
const grouped2 = await load.repository.withConnection(this.repository.getConnection()).loadMorphManyForParents(rows, relation2, load.options);
|
|
1302
|
+
result = result.map((row) => ({
|
|
1303
|
+
...row,
|
|
1304
|
+
[load.as]: grouped2.get(row[relation2.localKey]) ?? []
|
|
1305
|
+
}));
|
|
1306
|
+
continue;
|
|
1307
|
+
}
|
|
1308
|
+
if (load.kind === "morphOne") {
|
|
1309
|
+
const relation2 = load.relation;
|
|
1310
|
+
const grouped2 = await load.repository.withConnection(this.repository.getConnection()).loadMorphOneForParents(rows, relation2, load.options);
|
|
1311
|
+
result = result.map((row) => ({
|
|
1312
|
+
...row,
|
|
1313
|
+
[load.as]: grouped2.get(row[relation2.localKey])
|
|
1314
|
+
}));
|
|
1315
|
+
continue;
|
|
1316
|
+
}
|
|
1317
|
+
if (load.kind === "morphTo") {
|
|
1318
|
+
const relation2 = load.relation;
|
|
1319
|
+
const grouped2 = await this.repository.loadMorphToForChildren(rows, relation2, load.morphRepositories ?? new Map, load.options);
|
|
1320
|
+
result = result.map((row) => ({
|
|
1321
|
+
...row,
|
|
1322
|
+
[load.as]: grouped2.get(row[relation2.morphIdKey])
|
|
1323
|
+
}));
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1208
1326
|
const relation = load.relation;
|
|
1209
1327
|
const grouped = await this.repository.loadBelongsToForParents(rows, relation, load.repository, load.options);
|
|
1210
1328
|
result = result.map((row) => ({
|
|
@@ -1481,6 +1599,56 @@ class BaseRepository {
|
|
|
1481
1599
|
}, options);
|
|
1482
1600
|
return indexBelongsToRelation(children, parents, relation);
|
|
1483
1601
|
}
|
|
1602
|
+
async loadMorphManyForParents(parents, relation, options = {}) {
|
|
1603
|
+
if (parents.length === 0) {
|
|
1604
|
+
return indexMorphManyRelation(parents, [], relation);
|
|
1605
|
+
}
|
|
1606
|
+
const parentIds = [...new Set(parents.map((parent) => parent[relation.localKey]))];
|
|
1607
|
+
const children = await this.findWhere({
|
|
1608
|
+
[relation.morphTypeKey]: relation.morphType,
|
|
1609
|
+
[relation.morphIdKey]: parentIds
|
|
1610
|
+
}, options);
|
|
1611
|
+
return indexMorphManyRelation(parents, children, relation);
|
|
1612
|
+
}
|
|
1613
|
+
async loadMorphOneForParents(parents, relation, options = {}) {
|
|
1614
|
+
const grouped = await this.loadMorphManyForParents(parents, relation, options);
|
|
1615
|
+
const result = new Map;
|
|
1616
|
+
for (const parent of parents) {
|
|
1617
|
+
const matches = grouped.get(parent[relation.localKey]) ?? [];
|
|
1618
|
+
result.set(parent[relation.localKey], matches[0]);
|
|
1619
|
+
}
|
|
1620
|
+
return result;
|
|
1621
|
+
}
|
|
1622
|
+
async loadMorphToForChildren(children, relation, repositoriesByType, options = {}) {
|
|
1623
|
+
if (children.length === 0) {
|
|
1624
|
+
return new Map;
|
|
1625
|
+
}
|
|
1626
|
+
const idsByType = new Map;
|
|
1627
|
+
for (const child of children) {
|
|
1628
|
+
const morphType = String(child[relation.morphTypeKey]);
|
|
1629
|
+
const morphId = child[relation.morphIdKey];
|
|
1630
|
+
const ids = idsByType.get(morphType) ?? new Set;
|
|
1631
|
+
ids.add(morphId);
|
|
1632
|
+
idsByType.set(morphType, ids);
|
|
1633
|
+
}
|
|
1634
|
+
const parentsByType = new Map;
|
|
1635
|
+
for (const [morphType, ids] of idsByType) {
|
|
1636
|
+
const repository = repositoriesByType.get(morphType);
|
|
1637
|
+
if (!repository) {
|
|
1638
|
+
continue;
|
|
1639
|
+
}
|
|
1640
|
+
const ownerKey = repository.getTable().primaryKey;
|
|
1641
|
+
const parents = await repository.withConnection(this.connection).findWhere({
|
|
1642
|
+
[ownerKey]: [...ids]
|
|
1643
|
+
}, options);
|
|
1644
|
+
const indexed = new Map;
|
|
1645
|
+
for (const parent of parents) {
|
|
1646
|
+
indexed.set(parent[ownerKey], parent);
|
|
1647
|
+
}
|
|
1648
|
+
parentsByType.set(morphType, indexed);
|
|
1649
|
+
}
|
|
1650
|
+
return indexMorphToRelation(children, parentsByType, relation);
|
|
1651
|
+
}
|
|
1484
1652
|
}
|
|
1485
1653
|
var baseRepository_default = BaseRepository;
|
|
1486
1654
|
// ../../src/core/database/bindConnection.ts
|
|
@@ -2698,18 +2866,7 @@ async function defaultSmtpTransport(config, message) {
|
|
|
2698
2866
|
await socket.write(`DATA\r
|
|
2699
2867
|
`);
|
|
2700
2868
|
await waitForSmtpResponse(readResponse, ["354"]);
|
|
2701
|
-
const payload =
|
|
2702
|
-
`From: ${config.from}`,
|
|
2703
|
-
`To: ${message.to}`,
|
|
2704
|
-
`Subject: ${message.subject}`,
|
|
2705
|
-
"MIME-Version: 1.0",
|
|
2706
|
-
"Content-Type: text/plain; charset=utf-8",
|
|
2707
|
-
"",
|
|
2708
|
-
message.body,
|
|
2709
|
-
".",
|
|
2710
|
-
""
|
|
2711
|
-
].join(`\r
|
|
2712
|
-
`);
|
|
2869
|
+
const payload = buildSmtpPayload(config.from, message);
|
|
2713
2870
|
await socket.write(payload);
|
|
2714
2871
|
await waitForSmtpResponse(readResponse, ["250"]);
|
|
2715
2872
|
await socket.write(`QUIT\r
|
|
@@ -2719,6 +2876,30 @@ async function defaultSmtpTransport(config, message) {
|
|
|
2719
2876
|
socket.end();
|
|
2720
2877
|
}
|
|
2721
2878
|
}
|
|
2879
|
+
function buildSmtpPayload(from, message) {
|
|
2880
|
+
const headers = [`From: ${from}`, `To: ${message.to}`, `Subject: ${message.subject}`, "MIME-Version: 1.0"];
|
|
2881
|
+
if (message.html) {
|
|
2882
|
+
const boundary = `strata-${Date.now().toString(36)}`;
|
|
2883
|
+
headers.push(`Content-Type: multipart/alternative; boundary="${boundary}"`);
|
|
2884
|
+
const parts = [
|
|
2885
|
+
`--${boundary}`,
|
|
2886
|
+
"Content-Type: text/plain; charset=utf-8",
|
|
2887
|
+
"",
|
|
2888
|
+
message.body,
|
|
2889
|
+
`--${boundary}`,
|
|
2890
|
+
"Content-Type: text/html; charset=utf-8",
|
|
2891
|
+
"",
|
|
2892
|
+
message.html,
|
|
2893
|
+
`--${boundary}--`,
|
|
2894
|
+
""
|
|
2895
|
+
];
|
|
2896
|
+
return [...headers, "", ...parts, ".", ""].join(`\r
|
|
2897
|
+
`);
|
|
2898
|
+
}
|
|
2899
|
+
headers.push("Content-Type: text/plain; charset=utf-8");
|
|
2900
|
+
return [...headers, "", message.body, ".", ""].join(`\r
|
|
2901
|
+
`);
|
|
2902
|
+
}
|
|
2722
2903
|
|
|
2723
2904
|
class LogMailDriver {
|
|
2724
2905
|
async send(message) {
|
|
@@ -2727,7 +2908,8 @@ class LogMailDriver {
|
|
|
2727
2908
|
channel: "mail",
|
|
2728
2909
|
to: message.to,
|
|
2729
2910
|
subject: message.subject,
|
|
2730
|
-
body: message.body
|
|
2911
|
+
body: message.body,
|
|
2912
|
+
...message.html ? { html: message.html } : {}
|
|
2731
2913
|
}));
|
|
2732
2914
|
}
|
|
2733
2915
|
}
|
|
@@ -4867,6 +5049,147 @@ function resetGracefulShutdownForTests() {
|
|
|
4867
5049
|
shutdownInstalled = false;
|
|
4868
5050
|
shuttingDown = false;
|
|
4869
5051
|
}
|
|
5052
|
+
// ../../src/core/mail/markdownMail.ts
|
|
5053
|
+
function escapeHtml(value) {
|
|
5054
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
5055
|
+
}
|
|
5056
|
+
function stripMarkdown(markdown) {
|
|
5057
|
+
return markdown.replace(/^#{1,6}\s+/gm, "").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1 ($2)").replace(/^[-*]\s+/gm, "\u2022 ").replace(/```[\s\S]*?```/g, "").replace(/\n{3,}/g, `
|
|
5058
|
+
|
|
5059
|
+
`).trim();
|
|
5060
|
+
}
|
|
5061
|
+
function markdownToHtml(markdown) {
|
|
5062
|
+
const escaped = markdown.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
5063
|
+
return escaped.replace(/^### (.+)$/gm, "<h3>$1</h3>").replace(/^## (.+)$/gm, "<h2>$1</h2>").replace(/^# (.+)$/gm, "<h1>$1</h1>").replace(/`([^`]+)`/g, "<code>$1</code>").replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>").replace(/\*([^*]+)\*/g, "<em>$1</em>").replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>').replace(/^[-*]\s+(.+)$/gm, "<li>$1</li>").replace(/(<li>[\s\S]*?<\/li>\n?)+/g, (block) => `<ul>${block}</ul>`).replace(/```(\w+)?\n([\s\S]*?)```/g, "<pre><code>$2</code></pre>").split(/\n\n+/).map((block) => {
|
|
5064
|
+
if (block.startsWith("<")) {
|
|
5065
|
+
return block;
|
|
5066
|
+
}
|
|
5067
|
+
return `<p>${block.replace(/\n/g, " ")}</p>`;
|
|
5068
|
+
}).join(`
|
|
5069
|
+
`);
|
|
5070
|
+
}
|
|
5071
|
+
function wrapMarkdownMailLayout(bodyHtml, options = {}) {
|
|
5072
|
+
const title = escapeHtml(options.title ?? "GetStrata");
|
|
5073
|
+
const preview = escapeHtml(options.preview ?? "");
|
|
5074
|
+
const footer = escapeHtml(options.footer ?? "Sent by GetStrata");
|
|
5075
|
+
return `<!DOCTYPE html>
|
|
5076
|
+
<html lang="en">
|
|
5077
|
+
<head>
|
|
5078
|
+
<meta charset="utf-8">
|
|
5079
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
5080
|
+
<title>${title}</title>
|
|
5081
|
+
<style>
|
|
5082
|
+
body { font-family: system-ui, sans-serif; line-height: 1.5; color: #111827; background: #f9fafb; margin: 0; padding: 24px; }
|
|
5083
|
+
.container { max-width: 640px; margin: 0 auto; background: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden; }
|
|
5084
|
+
.header { padding: 20px 24px; border-bottom: 1px solid #e5e7eb; font-weight: 600; }
|
|
5085
|
+
.content { padding: 24px; }
|
|
5086
|
+
.footer { padding: 16px 24px; border-top: 1px solid #e5e7eb; color: #6b7280; font-size: 14px; }
|
|
5087
|
+
a { color: #2563eb; }
|
|
5088
|
+
code { background: #f3f4f6; padding: 2px 4px; border-radius: 4px; }
|
|
5089
|
+
pre { background: #111827; color: #f9fafb; padding: 12px; border-radius: 6px; overflow-x: auto; }
|
|
5090
|
+
</style>
|
|
5091
|
+
</head>
|
|
5092
|
+
<body>
|
|
5093
|
+
${preview ? `<span style="display:none;max-height:0;overflow:hidden;">${preview}</span>` : ""}
|
|
5094
|
+
<div class="container">
|
|
5095
|
+
<div class="header">${title}</div>
|
|
5096
|
+
<div class="content">${bodyHtml}</div>
|
|
5097
|
+
<div class="footer">${footer}</div>
|
|
5098
|
+
</div>
|
|
5099
|
+
</body>
|
|
5100
|
+
</html>`;
|
|
5101
|
+
}
|
|
5102
|
+
function renderMarkdownMail(markdown, options = {}) {
|
|
5103
|
+
const bodyHtml = markdownToHtml(markdown.trim());
|
|
5104
|
+
const html = wrapMarkdownMailLayout(bodyHtml, options);
|
|
5105
|
+
const text = stripMarkdown(markdown);
|
|
5106
|
+
return { html, text };
|
|
5107
|
+
}
|
|
5108
|
+
// ../../src/core/mail/markdownMailable.ts
|
|
5109
|
+
function buildMarkdownMailMessage(input) {
|
|
5110
|
+
const rendered = renderMarkdownMail(input.markdown, {
|
|
5111
|
+
title: input.layout?.title ?? input.subject,
|
|
5112
|
+
...input.layout
|
|
5113
|
+
});
|
|
5114
|
+
return {
|
|
5115
|
+
to: input.to,
|
|
5116
|
+
subject: input.subject,
|
|
5117
|
+
body: rendered.text,
|
|
5118
|
+
html: rendered.html
|
|
5119
|
+
};
|
|
5120
|
+
}
|
|
5121
|
+
async function sendMarkdownMail(mailer2, input) {
|
|
5122
|
+
await mailer2.send(buildMarkdownMailMessage(input));
|
|
5123
|
+
}
|
|
5124
|
+
// ../../src/core/notifications/dispatcher.ts
|
|
5125
|
+
class NotificationDispatcher {
|
|
5126
|
+
mailer;
|
|
5127
|
+
databaseStore;
|
|
5128
|
+
constructor(mailer2, databaseStore = null) {
|
|
5129
|
+
this.mailer = mailer2;
|
|
5130
|
+
this.databaseStore = databaseStore;
|
|
5131
|
+
}
|
|
5132
|
+
async send(notifiable, notification) {
|
|
5133
|
+
for (const channel of notification.via(notifiable)) {
|
|
5134
|
+
if (channel === "mail") {
|
|
5135
|
+
await this.sendMail(notifiable, notification);
|
|
5136
|
+
continue;
|
|
5137
|
+
}
|
|
5138
|
+
if (channel === "database") {
|
|
5139
|
+
await this.sendDatabase(notifiable, notification);
|
|
5140
|
+
}
|
|
5141
|
+
}
|
|
5142
|
+
}
|
|
5143
|
+
async sendMail(notifiable, notification) {
|
|
5144
|
+
const routed = notifiable.routeNotificationFor("mail");
|
|
5145
|
+
if (routed === null) {
|
|
5146
|
+
return;
|
|
5147
|
+
}
|
|
5148
|
+
const message = notification.toMail(notifiable);
|
|
5149
|
+
if (!message) {
|
|
5150
|
+
return;
|
|
5151
|
+
}
|
|
5152
|
+
if (message.markdown) {
|
|
5153
|
+
await this.mailer.send(buildMarkdownMailMessage({
|
|
5154
|
+
to: String(routed),
|
|
5155
|
+
subject: message.subject,
|
|
5156
|
+
markdown: message.markdown
|
|
5157
|
+
}));
|
|
5158
|
+
return;
|
|
5159
|
+
}
|
|
5160
|
+
await this.mailer.send({
|
|
5161
|
+
to: String(routed),
|
|
5162
|
+
subject: message.subject,
|
|
5163
|
+
body: message.body ?? "",
|
|
5164
|
+
...message.html ? { html: message.html } : {}
|
|
5165
|
+
});
|
|
5166
|
+
}
|
|
5167
|
+
async sendDatabase(notifiable, notification) {
|
|
5168
|
+
if (!this.databaseStore) {
|
|
5169
|
+
return;
|
|
5170
|
+
}
|
|
5171
|
+
const payload = notification.toDatabase(notifiable);
|
|
5172
|
+
if (!payload) {
|
|
5173
|
+
return;
|
|
5174
|
+
}
|
|
5175
|
+
await this.databaseStore.create({
|
|
5176
|
+
userId: Number(notifiable.getNotificationKey()),
|
|
5177
|
+
...payload
|
|
5178
|
+
});
|
|
5179
|
+
}
|
|
5180
|
+
}
|
|
5181
|
+
function createNotificationDispatcher(mailer2, databaseStore) {
|
|
5182
|
+
return new NotificationDispatcher(mailer2, databaseStore ?? null);
|
|
5183
|
+
}
|
|
5184
|
+
// ../../src/core/notifications/notification.ts
|
|
5185
|
+
class Notification {
|
|
5186
|
+
toMail(_notifiable) {
|
|
5187
|
+
return null;
|
|
5188
|
+
}
|
|
5189
|
+
toDatabase(_notifiable) {
|
|
5190
|
+
return null;
|
|
5191
|
+
}
|
|
5192
|
+
}
|
|
4870
5193
|
// ../../src/core/queue/index.ts
|
|
4871
5194
|
class Job {
|
|
4872
5195
|
maxAttempts;
|
|
@@ -5370,6 +5693,7 @@ function validateObject(payload, schema) {
|
|
|
5370
5693
|
return output;
|
|
5371
5694
|
}
|
|
5372
5695
|
export {
|
|
5696
|
+
wrapMarkdownMailLayout,
|
|
5373
5697
|
withMigrationLock,
|
|
5374
5698
|
withMiddleware,
|
|
5375
5699
|
withErrorHandling,
|
|
@@ -5377,10 +5701,12 @@ export {
|
|
|
5377
5701
|
validateObject,
|
|
5378
5702
|
toResourceCollection,
|
|
5379
5703
|
toPaginatedResourceCollection,
|
|
5704
|
+
stripMarkdown,
|
|
5380
5705
|
stringRule,
|
|
5381
5706
|
storageFacade as storage,
|
|
5382
5707
|
setActiveApplicationContext,
|
|
5383
5708
|
serializeDate,
|
|
5709
|
+
sendMarkdownMail,
|
|
5384
5710
|
securedBindRouteModelByKey,
|
|
5385
5711
|
securedBindRouteModel,
|
|
5386
5712
|
runWithDatabaseConnection,
|
|
@@ -5403,6 +5729,7 @@ export {
|
|
|
5403
5729
|
resolveApplicationCache,
|
|
5404
5730
|
resolveApplicationAuth,
|
|
5405
5731
|
required,
|
|
5732
|
+
renderMarkdownMail,
|
|
5406
5733
|
registerShutdownHandler,
|
|
5407
5734
|
registerModelRepository,
|
|
5408
5735
|
readSubmittedCsrfTokenFromBody,
|
|
@@ -5416,9 +5743,13 @@ export {
|
|
|
5416
5743
|
paginatedResponse,
|
|
5417
5744
|
normalizeMetricPath,
|
|
5418
5745
|
noContentResponse,
|
|
5746
|
+
morphTo,
|
|
5747
|
+
morphOne,
|
|
5748
|
+
morphMany,
|
|
5419
5749
|
minLength,
|
|
5420
5750
|
migrateDatabase,
|
|
5421
5751
|
maxLength,
|
|
5752
|
+
markdownToHtml,
|
|
5422
5753
|
mailer,
|
|
5423
5754
|
mail,
|
|
5424
5755
|
log,
|
|
@@ -5430,6 +5761,9 @@ export {
|
|
|
5430
5761
|
isEtagEnabled,
|
|
5431
5762
|
installGracefulShutdownSignals,
|
|
5432
5763
|
inferReferencedTable,
|
|
5764
|
+
indexMorphToRelation,
|
|
5765
|
+
indexMorphOneRelation,
|
|
5766
|
+
indexMorphManyRelation,
|
|
5433
5767
|
indexHasOneRelation,
|
|
5434
5768
|
indexHasManyRelation,
|
|
5435
5769
|
indexBelongsToRelation,
|
|
@@ -5459,6 +5793,7 @@ export {
|
|
|
5459
5793
|
createQueueWorker,
|
|
5460
5794
|
createQueue,
|
|
5461
5795
|
createProductionQueue,
|
|
5796
|
+
createNotificationDispatcher,
|
|
5462
5797
|
createMetricsMiddleware,
|
|
5463
5798
|
createMemoryThrottleMiddleware,
|
|
5464
5799
|
createLoginThrottleMiddleware,
|
|
@@ -5474,6 +5809,8 @@ export {
|
|
|
5474
5809
|
composeMiddleware,
|
|
5475
5810
|
compileBlueprint,
|
|
5476
5811
|
cache,
|
|
5812
|
+
buildSmtpPayload,
|
|
5813
|
+
buildMarkdownMailMessage,
|
|
5477
5814
|
bindDatabaseConnection2 as bindDatabaseConnection,
|
|
5478
5815
|
belongsToMany,
|
|
5479
5816
|
belongsTo,
|
|
@@ -5503,6 +5840,8 @@ export {
|
|
|
5503
5840
|
PostgresGrammar,
|
|
5504
5841
|
PolicyGate,
|
|
5505
5842
|
Policy,
|
|
5843
|
+
NotificationDispatcher,
|
|
5844
|
+
Notification,
|
|
5506
5845
|
NotFoundError,
|
|
5507
5846
|
MySqlGrammar,
|
|
5508
5847
|
Model,
|