@vicacha-devs/strapi-plugin-inbox 1.1.0 → 1.1.2
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/admin/{InboxHomePage-B5xUPD7Y.mjs → InboxHomePage-CfoiAI1Z.mjs} +2 -2
- package/dist/admin/{InboxHomePage-BCHbPE2t.js → InboxHomePage-DPuQPIwL.js} +2 -2
- package/dist/admin/{LocalizationRoutingTab-CEXbHNe4.mjs → LocalizationRoutingTab-C_enaoml.mjs} +1 -1
- package/dist/admin/{LocalizationRoutingTab-Dt6U-kXn.js → LocalizationRoutingTab-DLlVOdSz.js} +1 -1
- package/dist/admin/{SettingsPage-qB_efKCl.js → SettingsPage-CWTOJAEO.js} +2 -2
- package/dist/admin/{SettingsPage-Dif7Cq7I.mjs → SettingsPage-Ctvf4SNg.mjs} +2 -2
- package/dist/admin/{index-5e9dAMBs.mjs → index-CvxBUxrS.mjs} +63 -11
- package/dist/admin/{index-DLfoIVZP.js → index-FRs4UYmW.js} +63 -11
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +280 -120
- package/dist/server/index.mjs +280 -120
- package/dist/server/src/bootstrap.d.ts +1 -0
- package/dist/server/src/controllers/formHandlers.d.ts +1 -0
- package/dist/server/src/routes/admin.d.ts +6 -1
- package/dist/server/src/routes/index.d.ts +6 -1
- package/dist/shared/index.d.ts +2 -1
- package/dist/shared/index.js +185 -115
- package/dist/shared/index.mjs +185 -115
- package/package.json +6 -6
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Core } from '@strapi/strapi';
|
|
2
2
|
import { ControllerCtx } from './inboxController';
|
|
3
|
+
export declare function resolveClientIp(ctx: ControllerCtx): string;
|
|
3
4
|
export declare const createFormHandlers: (strapi: Core.Strapi) => {
|
|
4
5
|
getSettings(ctx: ControllerCtx): Promise<void>;
|
|
5
6
|
updateSettings(ctx: ControllerCtx): Promise<void>;
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
declare const shared: Record<string, unknown>;
|
|
2
|
+
export default shared;
|
package/dist/shared/index.js
CHANGED
|
@@ -104,15 +104,122 @@ const DEFAULT_INBOX_SETTINGS = {
|
|
|
104
104
|
defaultNotifyEmails: [],
|
|
105
105
|
outboundWebhookUrl: ""
|
|
106
106
|
};
|
|
107
|
+
const SUPPORTED_INTL_CALENDARS = Object.freeze([
|
|
108
|
+
{ id: "gregory", intlCalendar: "gregory", defaultLabel: "Gregorian" },
|
|
109
|
+
{ id: "iso8601", intlCalendar: "iso8601", defaultLabel: "ISO 8601" },
|
|
110
|
+
{
|
|
111
|
+
id: "islamic-umalqura",
|
|
112
|
+
intlCalendar: "islamic-umalqura",
|
|
113
|
+
defaultLabel: "Hijri (Umm al-Qura)"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: "islamic-civil",
|
|
117
|
+
intlCalendar: "islamic-civil",
|
|
118
|
+
defaultLabel: "Hijri (Civil)"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: "islamic-tbla",
|
|
122
|
+
intlCalendar: "islamic-tbla",
|
|
123
|
+
defaultLabel: "Hijri (Tabular)"
|
|
124
|
+
},
|
|
125
|
+
{ id: "hebrew", intlCalendar: "hebrew", defaultLabel: "Hebrew" },
|
|
126
|
+
{
|
|
127
|
+
id: "persian",
|
|
128
|
+
intlCalendar: "persian",
|
|
129
|
+
defaultLabel: "Persian (Solar Hijri)"
|
|
130
|
+
},
|
|
131
|
+
{ id: "buddhist", intlCalendar: "buddhist", defaultLabel: "Buddhist" },
|
|
132
|
+
{ id: "japanese", intlCalendar: "japanese", defaultLabel: "Japanese" },
|
|
133
|
+
{ id: "chinese", intlCalendar: "chinese", defaultLabel: "Chinese Lunar" },
|
|
134
|
+
{ id: "indian", intlCalendar: "indian", defaultLabel: "Indian National" },
|
|
135
|
+
{ id: "coptic", intlCalendar: "coptic", defaultLabel: "Coptic" },
|
|
136
|
+
{ id: "ethiopic", intlCalendar: "ethiopic", defaultLabel: "Ethiopic" }
|
|
137
|
+
]);
|
|
138
|
+
Object.freeze([
|
|
139
|
+
"none",
|
|
140
|
+
...SUPPORTED_INTL_CALENDARS.map((item) => item.id)
|
|
141
|
+
]);
|
|
142
|
+
const BASE_BCP47_REGEX = /^[a-zA-Z]{2,3}(?:-[a-zA-Z0-9]{2,8})*$/;
|
|
143
|
+
function sanitizeCalendarBaseLocale(locale, fallbackLocale = "es") {
|
|
144
|
+
if (typeof locale !== "string" || !locale.trim()) {
|
|
145
|
+
return fallbackLocale;
|
|
146
|
+
}
|
|
147
|
+
const trimmed = locale.trim();
|
|
148
|
+
const uIdx = trimmed.toLowerCase().indexOf("-u-");
|
|
149
|
+
let stripped = uIdx >= 0 ? trimmed.slice(0, uIdx) : trimmed;
|
|
150
|
+
while (stripped.endsWith("-")) {
|
|
151
|
+
stripped = stripped.slice(0, -1);
|
|
152
|
+
}
|
|
153
|
+
if (!stripped || stripped.length > 35 || !BASE_BCP47_REGEX.test(stripped)) {
|
|
154
|
+
return fallbackLocale;
|
|
155
|
+
}
|
|
156
|
+
return stripped;
|
|
157
|
+
}
|
|
158
|
+
function formatSecondaryDate(isoDateString, calendar = "islamic-umalqura", locale = "es") {
|
|
159
|
+
if (!isoDateString || calendar === "none") {
|
|
160
|
+
return { calendar, formatted: "" };
|
|
161
|
+
}
|
|
162
|
+
const date = new Date(isoDateString);
|
|
163
|
+
if (Number.isNaN(date.getTime())) {
|
|
164
|
+
return { calendar, formatted: isoDateString };
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
const baseLocale = sanitizeCalendarBaseLocale(locale);
|
|
168
|
+
const formatter = new Intl.DateTimeFormat(`${baseLocale}-u-ca-${calendar}`, {
|
|
169
|
+
year: "numeric",
|
|
170
|
+
month: "short",
|
|
171
|
+
day: "numeric"
|
|
172
|
+
});
|
|
173
|
+
const parts = formatter.formatToParts(date);
|
|
174
|
+
const year = Number(parts.find((p) => p.type === "year")?.value) || void 0;
|
|
175
|
+
const month = Number(parts.find((p) => p.type === "month")?.value) || void 0;
|
|
176
|
+
const day = Number(parts.find((p) => p.type === "day")?.value) || void 0;
|
|
177
|
+
return {
|
|
178
|
+
calendar,
|
|
179
|
+
formatted: formatter.format(date),
|
|
180
|
+
year,
|
|
181
|
+
month,
|
|
182
|
+
day
|
|
183
|
+
};
|
|
184
|
+
} catch {
|
|
185
|
+
return {
|
|
186
|
+
calendar,
|
|
187
|
+
formatted: date.toISOString().slice(0, 10)
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
107
191
|
function isValidEmail(value) {
|
|
108
|
-
if (
|
|
192
|
+
if (typeof value !== "string" || value.length < 3 || value.length > 254) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
if (/[\u0000-\u0020\u007f]/.test(value) || /\s/.test(value))
|
|
109
196
|
return false;
|
|
110
197
|
const at = value.indexOf("@");
|
|
111
|
-
if (at < 1 || at !== value.lastIndexOf("@"))
|
|
198
|
+
if (at < 1 || at > 64 || at !== value.lastIndexOf("@"))
|
|
112
199
|
return false;
|
|
200
|
+
const local = value.slice(0, at);
|
|
201
|
+
if (local.startsWith(".") || local.endsWith(".") || local.includes("..")) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
113
204
|
const domain = value.slice(at + 1);
|
|
114
|
-
|
|
115
|
-
|
|
205
|
+
if (domain.startsWith(".") || domain.endsWith(".") || domain.includes("..")) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
const labels = domain.split(".");
|
|
209
|
+
if (labels.length < 2)
|
|
210
|
+
return false;
|
|
211
|
+
return labels.every((label) => label.length > 0 && label.length <= 63 && !label.startsWith("-") && !label.endsWith("-"));
|
|
212
|
+
}
|
|
213
|
+
const CSV_FORMULA_PREFIX_RE = /^[\s\u0085\u2028\u2029]*[=+\-@|]|^[\t\r\n]/;
|
|
214
|
+
function escapeCsvCell(value) {
|
|
215
|
+
if (value === null || value === void 0)
|
|
216
|
+
return "";
|
|
217
|
+
const raw = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
218
|
+
const sanitized = raw.length > 0 && CSV_FORMULA_PREFIX_RE.test(raw) ? `'${raw}` : raw;
|
|
219
|
+
if (sanitized.includes('"') || sanitized.includes(",") || sanitized.includes("\n") || sanitized.includes("\r")) {
|
|
220
|
+
return `"${sanitized.replace(/"/g, '""')}"`;
|
|
221
|
+
}
|
|
222
|
+
return sanitized;
|
|
116
223
|
}
|
|
117
224
|
function freezeOptions(items) {
|
|
118
225
|
return Object.freeze(items.map((item) => Object.freeze({ ...item })));
|
|
@@ -144,6 +251,54 @@ freezeOptions([
|
|
|
144
251
|
{ value: "persian", label: "persian (Solar Hijri)" },
|
|
145
252
|
{ value: "none", label: "none (Gregorian Only)" }
|
|
146
253
|
]);
|
|
254
|
+
class SlidingWindowRateLimiter {
|
|
255
|
+
hits = /* @__PURE__ */ new Map();
|
|
256
|
+
maxTrackedKeys;
|
|
257
|
+
defaultWindowMs;
|
|
258
|
+
constructor(options) {
|
|
259
|
+
this.maxTrackedKeys = options?.maxTrackedKeys ?? 1e4;
|
|
260
|
+
this.defaultWindowMs = options?.defaultWindowMs ?? 60 * 60 * 1e3;
|
|
261
|
+
}
|
|
262
|
+
check(ip, bucketKey, limitPerWindow, nowMs = Date.now(), windowMs = this.defaultWindowMs) {
|
|
263
|
+
if (limitPerWindow <= 0) {
|
|
264
|
+
return { allowed: true, remaining: 999, retryAfterSeconds: 0 };
|
|
265
|
+
}
|
|
266
|
+
if (this.hits.size > this.maxTrackedKeys) {
|
|
267
|
+
const oldestKey = this.hits.keys().next().value;
|
|
268
|
+
if (oldestKey !== void 0) {
|
|
269
|
+
this.hits.delete(oldestKey);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const key = `${bucketKey}::${ip || "unknown"}`;
|
|
273
|
+
const cutoff = nowMs - windowMs;
|
|
274
|
+
const previous = (this.hits.get(key) || []).filter((ts) => ts > cutoff);
|
|
275
|
+
if (previous.length >= limitPerWindow) {
|
|
276
|
+
const oldest = previous[0] ?? nowMs;
|
|
277
|
+
const retryAfterSeconds = Math.max(1, Math.ceil((oldest + windowMs - nowMs) / 1e3));
|
|
278
|
+
this.hits.set(key, previous);
|
|
279
|
+
return {
|
|
280
|
+
allowed: false,
|
|
281
|
+
remaining: 0,
|
|
282
|
+
retryAfterSeconds
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
previous.push(nowMs);
|
|
286
|
+
this.hits.set(key, previous);
|
|
287
|
+
return {
|
|
288
|
+
allowed: true,
|
|
289
|
+
remaining: Math.max(0, limitPerWindow - previous.length),
|
|
290
|
+
retryAfterSeconds: 0
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
reset() {
|
|
294
|
+
this.hits.clear();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const FORBIDDEN_OBJECT_KEYS = /* @__PURE__ */ new Set([
|
|
298
|
+
"__proto__",
|
|
299
|
+
"constructor",
|
|
300
|
+
"prototype"
|
|
301
|
+
]);
|
|
147
302
|
const LOCALIZED_REQUIRED_FALLBACK = {
|
|
148
303
|
es: (label) => `${label} es obligatorio`,
|
|
149
304
|
en: (label) => `${label} is required`,
|
|
@@ -241,12 +396,23 @@ function checkNumericBoundRule(rule, limit, rawValue, fieldLabel, locale) {
|
|
|
241
396
|
}
|
|
242
397
|
return null;
|
|
243
398
|
}
|
|
399
|
+
function hasNestedQuantifier(pattern) {
|
|
400
|
+
return /[+*?}]\s*\)\s*[+*?{]/.test(pattern.replaceAll(/\\./g, ""));
|
|
401
|
+
}
|
|
244
402
|
function checkLengthOrNumberRule(rule, rawValue, strVal, fieldLabel, locale) {
|
|
245
|
-
|
|
246
|
-
|
|
403
|
+
const numRuleVal = typeof rule.value === "number" ? rule.value : typeof rule.value === "string" && rule.value.trim() !== "" ? Number(rule.value) : Number.NaN;
|
|
404
|
+
if (!Number.isFinite(numRuleVal)) return null;
|
|
405
|
+
return checkLengthRule(rule, numRuleVal, strVal, fieldLabel, locale) ?? checkNumericBoundRule(rule, numRuleVal, rawValue, fieldLabel, locale);
|
|
247
406
|
}
|
|
248
407
|
function checkPatternOrEmailRule(rule, fieldType, strVal, fieldLabel, locale) {
|
|
249
408
|
if (rule.type === "pattern" && typeof rule.value === "string") {
|
|
409
|
+
if (strVal.length > 4096 || rule.value.length > 512 || hasNestedQuantifier(rule.value)) {
|
|
410
|
+
return resolveRuleMessage(
|
|
411
|
+
rule,
|
|
412
|
+
locale,
|
|
413
|
+
`${fieldLabel} format is invalid`
|
|
414
|
+
);
|
|
415
|
+
}
|
|
250
416
|
try {
|
|
251
417
|
const regex = new RegExp(rule.value);
|
|
252
418
|
if (!regex.test(strVal)) {
|
|
@@ -266,6 +432,13 @@ function checkPatternOrEmailRule(rule, fieldType, strVal, fieldLabel, locale) {
|
|
|
266
432
|
`${fieldLabel} must be a valid email address`
|
|
267
433
|
);
|
|
268
434
|
}
|
|
435
|
+
if (rule.type === "url" && fieldType !== "url" && !isValidHttpUrl(strVal)) {
|
|
436
|
+
return resolveRuleMessage(
|
|
437
|
+
rule,
|
|
438
|
+
locale,
|
|
439
|
+
`${fieldLabel} must be a valid URL`
|
|
440
|
+
);
|
|
441
|
+
}
|
|
269
442
|
return null;
|
|
270
443
|
}
|
|
271
444
|
function evaluateCustomRules(field, rawValue, strVal, fieldLabel, locale, rules) {
|
|
@@ -300,7 +473,7 @@ function buildRequiredError(rules, locale, fieldLabel) {
|
|
|
300
473
|
return resolveRuleMessage(reqRule, locale, fallbackFn(fieldLabel));
|
|
301
474
|
}
|
|
302
475
|
function validateSingleField(field, data, locale) {
|
|
303
|
-
const rawValue = data[field.name]
|
|
476
|
+
const rawValue = Object.hasOwn(data, field.name) ? data[field.name] : field.defaultValue;
|
|
304
477
|
const fieldLabel = resolveFieldLabel(field, locale);
|
|
305
478
|
const rules = field.validation || [];
|
|
306
479
|
if (field.required && isValueEmpty(rawValue)) {
|
|
@@ -333,7 +506,9 @@ function validateFormSubmission(fields, data, locale = "en") {
|
|
|
333
506
|
const errors = {};
|
|
334
507
|
const cleanedData = {};
|
|
335
508
|
for (const field of fields) {
|
|
336
|
-
if (DECORATIVE_FIELD_TYPES.includes(field.type))
|
|
509
|
+
if (DECORATIVE_FIELD_TYPES.includes(field.type) || FORBIDDEN_OBJECT_KEYS.has(field.name)) {
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
337
512
|
const { fieldErrors, cleanedValue } = validateSingleField(
|
|
338
513
|
field,
|
|
339
514
|
data,
|
|
@@ -352,45 +527,10 @@ function validateFormSubmission(fields, data, locale = "en") {
|
|
|
352
527
|
};
|
|
353
528
|
}
|
|
354
529
|
function isHoneypotTriggered(payload, honeypotField = "_website_url") {
|
|
355
|
-
if (!honeypotField) return false;
|
|
530
|
+
if (!honeypotField || !Object.hasOwn(payload, honeypotField)) return false;
|
|
356
531
|
const val = payload[honeypotField];
|
|
357
532
|
return typeof val === "string" && val.trim().length > 0;
|
|
358
533
|
}
|
|
359
|
-
class SlidingWindowRateLimiter {
|
|
360
|
-
hits = /* @__PURE__ */ new Map();
|
|
361
|
-
check(ip, bucketKey, limitPerHour, nowMs = Date.now()) {
|
|
362
|
-
if (limitPerHour <= 0) {
|
|
363
|
-
return { allowed: true, remaining: 999, retryAfterSeconds: 0 };
|
|
364
|
-
}
|
|
365
|
-
const windowMs = 60 * 60 * 1e3;
|
|
366
|
-
const key = `${bucketKey}::${ip || "unknown"}`;
|
|
367
|
-
const cutoff = nowMs - windowMs;
|
|
368
|
-
const previous = (this.hits.get(key) || []).filter((ts) => ts > cutoff);
|
|
369
|
-
if (previous.length >= limitPerHour) {
|
|
370
|
-
const oldest = previous[0] ?? nowMs;
|
|
371
|
-
const retryAfterSeconds = Math.max(
|
|
372
|
-
1,
|
|
373
|
-
Math.ceil((oldest + windowMs - nowMs) / 1e3)
|
|
374
|
-
);
|
|
375
|
-
this.hits.set(key, previous);
|
|
376
|
-
return {
|
|
377
|
-
allowed: false,
|
|
378
|
-
remaining: 0,
|
|
379
|
-
retryAfterSeconds
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
previous.push(nowMs);
|
|
383
|
-
this.hits.set(key, previous);
|
|
384
|
-
return {
|
|
385
|
-
allowed: true,
|
|
386
|
-
remaining: Math.max(0, limitPerHour - previous.length),
|
|
387
|
-
retryAfterSeconds: 0
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
reset() {
|
|
391
|
-
this.hits.clear();
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
534
|
const defaultRateLimiter = new SlidingWindowRateLimiter();
|
|
395
535
|
function resolveFetchRunner(fetchImpl) {
|
|
396
536
|
return fetchImpl ?? globalThis.fetch;
|
|
@@ -749,16 +889,6 @@ function localizeFormForLocale(form, locale) {
|
|
|
749
889
|
}
|
|
750
890
|
};
|
|
751
891
|
}
|
|
752
|
-
const FORMULA_PREFIXES = ["=", "+", "-", "@", " ", "\r"];
|
|
753
|
-
function escapeCsvCell(value) {
|
|
754
|
-
if (value === null || value === void 0) return "";
|
|
755
|
-
const raw = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
756
|
-
const sanitized = raw.length > 0 && FORMULA_PREFIXES.includes(raw[0]) ? `'${raw}` : raw;
|
|
757
|
-
if (sanitized.includes('"') || sanitized.includes(",") || sanitized.includes("\n") || sanitized.includes("\r")) {
|
|
758
|
-
return `"${sanitized.replace(/"/g, '""')}"`;
|
|
759
|
-
}
|
|
760
|
-
return sanitized;
|
|
761
|
-
}
|
|
762
892
|
function collectDataFieldNames(submissions, fields) {
|
|
763
893
|
const dataFieldNames = [];
|
|
764
894
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -821,68 +951,8 @@ function submissionsToCsv(submissions, fields = []) {
|
|
|
821
951
|
}
|
|
822
952
|
return rows.join("\n");
|
|
823
953
|
}
|
|
824
|
-
const SUPPORTED_INTL_CALENDARS = [
|
|
825
|
-
{ id: "gregory", intlCalendar: "gregory", defaultLabel: "Gregorian" },
|
|
826
|
-
{ id: "iso8601", intlCalendar: "iso8601", defaultLabel: "ISO 8601" },
|
|
827
|
-
{
|
|
828
|
-
id: "islamic-umalqura",
|
|
829
|
-
intlCalendar: "islamic-umalqura",
|
|
830
|
-
defaultLabel: "Hijri (Umm al-Qura)"
|
|
831
|
-
},
|
|
832
|
-
{
|
|
833
|
-
id: "islamic-civil",
|
|
834
|
-
intlCalendar: "islamic-civil",
|
|
835
|
-
defaultLabel: "Hijri (Civil)"
|
|
836
|
-
},
|
|
837
|
-
{
|
|
838
|
-
id: "islamic-tbla",
|
|
839
|
-
intlCalendar: "islamic-tbla",
|
|
840
|
-
defaultLabel: "Hijri (Tabular)"
|
|
841
|
-
},
|
|
842
|
-
{ id: "hebrew", intlCalendar: "hebrew", defaultLabel: "Hebrew" },
|
|
843
|
-
{
|
|
844
|
-
id: "persian",
|
|
845
|
-
intlCalendar: "persian",
|
|
846
|
-
defaultLabel: "Persian (Solar Hijri)"
|
|
847
|
-
},
|
|
848
|
-
{ id: "buddhist", intlCalendar: "buddhist", defaultLabel: "Buddhist" },
|
|
849
|
-
{ id: "japanese", intlCalendar: "japanese", defaultLabel: "Japanese" },
|
|
850
|
-
{ id: "chinese", intlCalendar: "chinese", defaultLabel: "Chinese Lunar" },
|
|
851
|
-
{ id: "indian", intlCalendar: "indian", defaultLabel: "Indian National" },
|
|
852
|
-
{ id: "coptic", intlCalendar: "coptic", defaultLabel: "Coptic" },
|
|
853
|
-
{ id: "ethiopic", intlCalendar: "ethiopic", defaultLabel: "Ethiopic" }
|
|
854
|
-
];
|
|
855
954
|
function convertIsoDateToCalendar(isoDateString, calendar = "islamic-umalqura", locale = "en") {
|
|
856
|
-
|
|
857
|
-
return { calendar, formatted: "" };
|
|
858
|
-
}
|
|
859
|
-
const date = new Date(isoDateString);
|
|
860
|
-
if (Number.isNaN(date.getTime())) {
|
|
861
|
-
return { calendar, formatted: isoDateString };
|
|
862
|
-
}
|
|
863
|
-
try {
|
|
864
|
-
const formatter = new Intl.DateTimeFormat(`${locale}-u-ca-${calendar}`, {
|
|
865
|
-
year: "numeric",
|
|
866
|
-
month: "short",
|
|
867
|
-
day: "numeric"
|
|
868
|
-
});
|
|
869
|
-
const parts = formatter.formatToParts(date);
|
|
870
|
-
const year = Number(parts.find((p) => p.type === "year")?.value) || void 0;
|
|
871
|
-
const month = Number(parts.find((p) => p.type === "month")?.value) || void 0;
|
|
872
|
-
const day = Number(parts.find((p) => p.type === "day")?.value) || void 0;
|
|
873
|
-
return {
|
|
874
|
-
calendar,
|
|
875
|
-
formatted: formatter.format(date),
|
|
876
|
-
year,
|
|
877
|
-
month,
|
|
878
|
-
day
|
|
879
|
-
};
|
|
880
|
-
} catch {
|
|
881
|
-
return {
|
|
882
|
-
calendar,
|
|
883
|
-
formatted: date.toISOString().slice(0, 10)
|
|
884
|
-
};
|
|
885
|
-
}
|
|
955
|
+
return formatSecondaryDate(isoDateString, calendar, locale);
|
|
886
956
|
}
|
|
887
957
|
exports.ALERT_BANNER_UID = ALERT_BANNER_UID;
|
|
888
958
|
exports.ALERT_SEVERITIES = ALERT_SEVERITIES;
|