tshex-cli 1.0.25 → 1.0.26

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.
@@ -0,0 +1,533 @@
1
+ /**
2
+ * Type-only specification for Open Graph metadata.
3
+ *
4
+ * Core protocol source: https://ogp.me/
5
+ * Tool reference: https://opengraph.dev/
6
+ * Facebook compatibility source: https://developers.facebook.com/documentation/sharing/webmasters
7
+ *
8
+ * This module intentionally contains no runtime values or implementations.
9
+ */
10
+
11
+ /* -------------------------------------------------------------------------- */
12
+ /* Scalar types */
13
+ /* -------------------------------------------------------------------------- */
14
+
15
+ export type HttpUrl = `http://${string}` | `https://${string}`;
16
+ export type HttpsUrl = `https://${string}`;
17
+ export type MimeType = `${string}/${string}`;
18
+ export type Iso8601DateTime = string;
19
+ export type Iso4217CurrencyCode = string;
20
+ export type OpenGraphLocale = `${string}_${string}`;
21
+ export type IntegerString = `${bigint}`;
22
+ export type NumberString = `${number}`;
23
+ export type TwitterHandle = `@${string}`;
24
+
25
+ /** TypeScript cannot statically enforce integer, positive, ISO, MIME, or URL validity. */
26
+ export type PositiveInteger = number;
27
+
28
+ export type OneOrMore<T> = readonly [T, ...T[]];
29
+
30
+ /* -------------------------------------------------------------------------- */
31
+ /* Open Graph core */
32
+ /* -------------------------------------------------------------------------- */
33
+
34
+ export type OpenGraphDeterminer = "a" | "an" | "the" | "" | "auto";
35
+
36
+ export type OpenGraphStandardType =
37
+ | "website"
38
+ | "article"
39
+ | "book"
40
+ | "profile"
41
+ | "music.song"
42
+ | "music.album"
43
+ | "music.playlist"
44
+ | "music.radio_station"
45
+ | "video.movie"
46
+ | "video.episode"
47
+ | "video.tv_show"
48
+ | "video.other"
49
+ | "payment.link";
50
+
51
+ /** Custom Open Graph types use CURIE syntax, such as "product:item". */
52
+ export type OpenGraphCustomType = `${string}:${string}`;
53
+ export type OpenGraphType = OpenGraphStandardType | OpenGraphCustomType;
54
+
55
+ export interface OpenGraphImage {
56
+ readonly url: HttpUrl;
57
+ readonly secureUrl?: HttpsUrl;
58
+ readonly type?: MimeType;
59
+ readonly width?: PositiveInteger;
60
+ readonly height?: PositiveInteger;
61
+ readonly alt?: string;
62
+ }
63
+
64
+ export interface OpenGraphVideo {
65
+ readonly url: HttpUrl;
66
+ readonly secureUrl?: HttpsUrl;
67
+ readonly type?: MimeType;
68
+ readonly width?: PositiveInteger;
69
+ readonly height?: PositiveInteger;
70
+ readonly alt?: string;
71
+ }
72
+
73
+ export interface OpenGraphAudio {
74
+ readonly url: HttpUrl;
75
+ readonly secureUrl?: HttpsUrl;
76
+ readonly type?: MimeType;
77
+ }
78
+
79
+ export interface OpenGraphBase<TType extends OpenGraphType = OpenGraphType> {
80
+ /** Required by the Open Graph protocol. */
81
+ readonly title: string;
82
+ /** Required by the Open Graph protocol. */
83
+ readonly type: TType;
84
+ /** Required by the Open Graph protocol. The first image has precedence. */
85
+ readonly images: OneOrMore<OpenGraphImage>;
86
+ /** Required by the Open Graph protocol. */
87
+ readonly url: HttpUrl;
88
+
89
+ readonly audio?: OneOrMore<OpenGraphAudio>;
90
+ readonly description?: string;
91
+ readonly determiner?: OpenGraphDeterminer;
92
+ readonly locale?: OpenGraphLocale;
93
+ readonly alternateLocales?: OneOrMore<OpenGraphLocale>;
94
+ readonly siteName?: string;
95
+ readonly videos?: OneOrMore<OpenGraphVideo>;
96
+ }
97
+
98
+ export interface OpenGraphObjectExtensions {
99
+ /** Namespaced custom properties, represented without interpreting their values. */
100
+ readonly extensions?: Readonly<
101
+ Partial<Record<`${string}:${string}`, string | OneOrMore<string>>>
102
+ >;
103
+ }
104
+
105
+ /* -------------------------------------------------------------------------- */
106
+ /* Open Graph object references and structured relations */
107
+ /* -------------------------------------------------------------------------- */
108
+
109
+ export type OpenGraphProfileReference = HttpUrl;
110
+ export type OpenGraphMusicSongReferenceUrl = HttpUrl;
111
+ export type OpenGraphMusicAlbumReferenceUrl = HttpUrl;
112
+ export type OpenGraphVideoSeriesReference = HttpUrl;
113
+
114
+ export interface OpenGraphMusicAlbumReference {
115
+ readonly url: OpenGraphMusicAlbumReferenceUrl;
116
+ readonly disc?: PositiveInteger;
117
+ readonly track?: PositiveInteger;
118
+ }
119
+
120
+ export interface OpenGraphMusicSongReference {
121
+ readonly url: OpenGraphMusicSongReferenceUrl;
122
+ readonly disc?: PositiveInteger;
123
+ readonly track?: PositiveInteger;
124
+ }
125
+
126
+ export interface OpenGraphVideoActorReference {
127
+ readonly url: OpenGraphProfileReference;
128
+ readonly role?: string;
129
+ }
130
+
131
+ /* -------------------------------------------------------------------------- */
132
+ /* Standard object types */
133
+ /* -------------------------------------------------------------------------- */
134
+
135
+ export interface OpenGraphWebsite
136
+ extends OpenGraphBase<"website">,
137
+ OpenGraphObjectExtensions {}
138
+
139
+ export interface OpenGraphArticle
140
+ extends OpenGraphBase<"article">,
141
+ OpenGraphObjectExtensions {
142
+ readonly publishedTime?: Iso8601DateTime;
143
+ readonly modifiedTime?: Iso8601DateTime;
144
+ readonly expirationTime?: Iso8601DateTime;
145
+ readonly authors?: OneOrMore<OpenGraphProfileReference>;
146
+ readonly section?: string;
147
+ readonly tags?: OneOrMore<string>;
148
+ }
149
+
150
+ export interface OpenGraphBook
151
+ extends OpenGraphBase<"book">,
152
+ OpenGraphObjectExtensions {
153
+ readonly authors?: OneOrMore<OpenGraphProfileReference>;
154
+ readonly isbn?: string;
155
+ readonly releaseDate?: Iso8601DateTime;
156
+ readonly tags?: OneOrMore<string>;
157
+ }
158
+
159
+ export type OpenGraphProfileGender = "male" | "female";
160
+
161
+ export interface OpenGraphProfile
162
+ extends OpenGraphBase<"profile">,
163
+ OpenGraphObjectExtensions {
164
+ readonly firstName?: string;
165
+ readonly lastName?: string;
166
+ readonly username?: string;
167
+ readonly gender?: OpenGraphProfileGender;
168
+ }
169
+
170
+ export interface OpenGraphMusicSong
171
+ extends OpenGraphBase<"music.song">,
172
+ OpenGraphObjectExtensions {
173
+ readonly duration?: PositiveInteger;
174
+ readonly albums?: OneOrMore<OpenGraphMusicAlbumReference>;
175
+ readonly musicians?: OneOrMore<OpenGraphProfileReference>;
176
+ }
177
+
178
+ export interface OpenGraphMusicAlbum
179
+ extends OpenGraphBase<"music.album">,
180
+ OpenGraphObjectExtensions {
181
+ readonly songs?: OneOrMore<OpenGraphMusicSongReference>;
182
+ readonly musicians?: OneOrMore<OpenGraphProfileReference>;
183
+ readonly releaseDate?: Iso8601DateTime;
184
+ }
185
+
186
+ export interface OpenGraphMusicPlaylist
187
+ extends OpenGraphBase<"music.playlist">,
188
+ OpenGraphObjectExtensions {
189
+ readonly songs?: OneOrMore<OpenGraphMusicSongReference>;
190
+ readonly creator?: OpenGraphProfileReference;
191
+ }
192
+
193
+ export interface OpenGraphMusicRadioStation
194
+ extends OpenGraphBase<"music.radio_station">,
195
+ OpenGraphObjectExtensions {
196
+ readonly creator?: OpenGraphProfileReference;
197
+ }
198
+
199
+ export interface OpenGraphVideoMetadata {
200
+ readonly actors?: OneOrMore<OpenGraphVideoActorReference>;
201
+ readonly directors?: OneOrMore<OpenGraphProfileReference>;
202
+ readonly writers?: OneOrMore<OpenGraphProfileReference>;
203
+ readonly duration?: PositiveInteger;
204
+ readonly releaseDate?: Iso8601DateTime;
205
+ readonly tags?: OneOrMore<string>;
206
+ }
207
+
208
+ export interface OpenGraphVideoMovie
209
+ extends OpenGraphBase<"video.movie">,
210
+ OpenGraphVideoMetadata,
211
+ OpenGraphObjectExtensions {}
212
+
213
+ export interface OpenGraphVideoEpisode
214
+ extends OpenGraphBase<"video.episode">,
215
+ OpenGraphVideoMetadata,
216
+ OpenGraphObjectExtensions {
217
+ readonly series?: OpenGraphVideoSeriesReference;
218
+ }
219
+
220
+ export interface OpenGraphVideoTvShow
221
+ extends OpenGraphBase<"video.tv_show">,
222
+ OpenGraphVideoMetadata,
223
+ OpenGraphObjectExtensions {}
224
+
225
+ export interface OpenGraphVideoOther
226
+ extends OpenGraphBase<"video.other">,
227
+ OpenGraphVideoMetadata,
228
+ OpenGraphObjectExtensions {}
229
+
230
+ export type OpenGraphPaymentStatus =
231
+ | "PENDING"
232
+ | "PAID"
233
+ | "FAILED"
234
+ | "EXPIRED";
235
+
236
+ /** `payment.link` is marked beta by the Open Graph protocol. */
237
+ export interface OpenGraphPaymentLink
238
+ extends OpenGraphBase<"payment.link">,
239
+ OpenGraphObjectExtensions {
240
+ readonly paymentDescription?: string;
241
+ readonly currency?: Iso4217CurrencyCode;
242
+ readonly amount?: number;
243
+ readonly expiresAt?: Iso8601DateTime;
244
+ readonly paymentStatus?: OpenGraphPaymentStatus;
245
+ readonly paymentId?: string;
246
+ readonly successUrl?: HttpUrl;
247
+ }
248
+
249
+ export interface OpenGraphCustomObject
250
+ extends OpenGraphBase<OpenGraphCustomType>,
251
+ OpenGraphObjectExtensions {}
252
+
253
+ export type OpenGraphMetadata =
254
+ | OpenGraphWebsite
255
+ | OpenGraphArticle
256
+ | OpenGraphBook
257
+ | OpenGraphProfile
258
+ | OpenGraphMusicSong
259
+ | OpenGraphMusicAlbum
260
+ | OpenGraphMusicPlaylist
261
+ | OpenGraphMusicRadioStation
262
+ | OpenGraphVideoMovie
263
+ | OpenGraphVideoEpisode
264
+ | OpenGraphVideoTvShow
265
+ | OpenGraphVideoOther
266
+ | OpenGraphPaymentLink
267
+ | OpenGraphCustomObject;
268
+
269
+ /* -------------------------------------------------------------------------- */
270
+ /* Raw Open Graph meta-tag representation */
271
+ /* -------------------------------------------------------------------------- */
272
+
273
+ export interface PropertyMetaTag<
274
+ TProperty extends string = string,
275
+ TContent extends string = string,
276
+ > {
277
+ readonly property: TProperty;
278
+ readonly content: TContent;
279
+ }
280
+
281
+ export type OpenGraphCoreMetaTag =
282
+ | PropertyMetaTag<"og:title">
283
+ | PropertyMetaTag<"og:type", OpenGraphType>
284
+ | PropertyMetaTag<"og:image", HttpUrl>
285
+ | PropertyMetaTag<"og:url", HttpUrl>
286
+ | PropertyMetaTag<"og:audio", HttpUrl>
287
+ | PropertyMetaTag<"og:description">
288
+ | PropertyMetaTag<"og:determiner", OpenGraphDeterminer>
289
+ | PropertyMetaTag<"og:locale", OpenGraphLocale>
290
+ | PropertyMetaTag<"og:locale:alternate", OpenGraphLocale>
291
+ | PropertyMetaTag<"og:site_name">
292
+ | PropertyMetaTag<"og:video", HttpUrl>;
293
+
294
+ export type OpenGraphImageMetaTag =
295
+ | PropertyMetaTag<"og:image:url", HttpUrl>
296
+ | PropertyMetaTag<"og:image:secure_url", HttpsUrl>
297
+ | PropertyMetaTag<"og:image:type", MimeType>
298
+ | PropertyMetaTag<"og:image:width", IntegerString>
299
+ | PropertyMetaTag<"og:image:height", IntegerString>
300
+ | PropertyMetaTag<"og:image:alt">;
301
+
302
+ export type OpenGraphVideoMetaTag =
303
+ | PropertyMetaTag<"og:video:url", HttpUrl>
304
+ | PropertyMetaTag<"og:video:secure_url", HttpsUrl>
305
+ | PropertyMetaTag<"og:video:type", MimeType>
306
+ | PropertyMetaTag<"og:video:width", IntegerString>
307
+ | PropertyMetaTag<"og:video:height", IntegerString>
308
+ | PropertyMetaTag<"og:video:alt">;
309
+
310
+ export type OpenGraphAudioMetaTag =
311
+ | PropertyMetaTag<"og:audio:url", HttpUrl>
312
+ | PropertyMetaTag<"og:audio:secure_url", HttpsUrl>
313
+ | PropertyMetaTag<"og:audio:type", MimeType>;
314
+
315
+ export type OpenGraphMusicMetaTag =
316
+ | PropertyMetaTag<"music:duration", IntegerString>
317
+ | PropertyMetaTag<"music:album", HttpUrl>
318
+ | PropertyMetaTag<"music:album:disc", IntegerString>
319
+ | PropertyMetaTag<"music:album:track", IntegerString>
320
+ | PropertyMetaTag<"music:musician", HttpUrl>
321
+ | PropertyMetaTag<"music:song", HttpUrl>
322
+ | PropertyMetaTag<"music:song:disc", IntegerString>
323
+ | PropertyMetaTag<"music:song:track", IntegerString>
324
+ | PropertyMetaTag<"music:release_date", Iso8601DateTime>
325
+ | PropertyMetaTag<"music:creator", HttpUrl>;
326
+
327
+ export type OpenGraphVideoObjectMetaTag =
328
+ | PropertyMetaTag<"video:actor", HttpUrl>
329
+ | PropertyMetaTag<"video:actor:role">
330
+ | PropertyMetaTag<"video:director", HttpUrl>
331
+ | PropertyMetaTag<"video:writer", HttpUrl>
332
+ | PropertyMetaTag<"video:duration", IntegerString>
333
+ | PropertyMetaTag<"video:release_date", Iso8601DateTime>
334
+ | PropertyMetaTag<"video:tag">
335
+ | PropertyMetaTag<"video:series", HttpUrl>;
336
+
337
+ export type OpenGraphArticleMetaTag =
338
+ | PropertyMetaTag<"article:published_time", Iso8601DateTime>
339
+ | PropertyMetaTag<"article:modified_time", Iso8601DateTime>
340
+ | PropertyMetaTag<"article:expiration_time", Iso8601DateTime>
341
+ | PropertyMetaTag<"article:author", HttpUrl>
342
+ | PropertyMetaTag<"article:section">
343
+ | PropertyMetaTag<"article:tag">;
344
+
345
+ export type OpenGraphBookMetaTag =
346
+ | PropertyMetaTag<"book:author", HttpUrl>
347
+ | PropertyMetaTag<"book:isbn">
348
+ | PropertyMetaTag<"book:release_date", Iso8601DateTime>
349
+ | PropertyMetaTag<"book:tag">;
350
+
351
+ export type OpenGraphProfileMetaTag =
352
+ | PropertyMetaTag<"profile:first_name">
353
+ | PropertyMetaTag<"profile:last_name">
354
+ | PropertyMetaTag<"profile:username">
355
+ | PropertyMetaTag<"profile:gender", OpenGraphProfileGender>;
356
+
357
+ export type OpenGraphPaymentMetaTag =
358
+ | PropertyMetaTag<"payment:description">
359
+ | PropertyMetaTag<"payment:currency", Iso4217CurrencyCode>
360
+ | PropertyMetaTag<"payment:amount", NumberString>
361
+ | PropertyMetaTag<"payment:expires_at", Iso8601DateTime>
362
+ | PropertyMetaTag<"payment:status", OpenGraphPaymentStatus>
363
+ | PropertyMetaTag<"payment:id">
364
+ | PropertyMetaTag<"payment:success_url", HttpUrl>;
365
+
366
+ export type OpenGraphStandardMetaTag =
367
+ | OpenGraphCoreMetaTag
368
+ | OpenGraphImageMetaTag
369
+ | OpenGraphVideoMetaTag
370
+ | OpenGraphAudioMetaTag
371
+ | OpenGraphMusicMetaTag
372
+ | OpenGraphVideoObjectMetaTag
373
+ | OpenGraphArticleMetaTag
374
+ | OpenGraphBookMetaTag
375
+ | OpenGraphProfileMetaTag
376
+ | OpenGraphPaymentMetaTag;
377
+
378
+ export type OpenGraphCustomMetaTag = PropertyMetaTag<
379
+ `${string}:${string}`,
380
+ string
381
+ >;
382
+
383
+ export type OpenGraphMetaTag =
384
+ | OpenGraphStandardMetaTag
385
+ | OpenGraphCustomMetaTag;
386
+
387
+ /* -------------------------------------------------------------------------- */
388
+ /* Twitter Card compatibility namespace */
389
+ /* -------------------------------------------------------------------------- */
390
+
391
+ export type TwitterCardType =
392
+ | "summary"
393
+ | "summary_large_image"
394
+ | "app"
395
+ | "player";
396
+
397
+ export interface TwitterCardBase<TCard extends TwitterCardType> {
398
+ readonly card: TCard;
399
+ readonly site?: TwitterHandle;
400
+ readonly siteId?: string;
401
+ readonly creator?: TwitterHandle;
402
+ readonly creatorId?: string;
403
+ readonly title?: string;
404
+ readonly description?: string;
405
+ }
406
+
407
+ export interface TwitterCardImage {
408
+ readonly url: HttpUrl;
409
+ readonly alt?: string;
410
+ }
411
+
412
+ export interface TwitterSummaryCard
413
+ extends TwitterCardBase<"summary"> {
414
+ readonly image?: TwitterCardImage;
415
+ }
416
+
417
+ export interface TwitterSummaryLargeImageCard
418
+ extends TwitterCardBase<"summary_large_image"> {
419
+ readonly image?: TwitterCardImage;
420
+ }
421
+
422
+ export interface TwitterPlayerCard
423
+ extends TwitterCardBase<"player"> {
424
+ readonly image: TwitterCardImage;
425
+ readonly player: HttpsUrl;
426
+ readonly playerWidth: PositiveInteger;
427
+ readonly playerHeight: PositiveInteger;
428
+ readonly playerStream?: HttpsUrl;
429
+ readonly playerStreamContentType?: MimeType;
430
+ }
431
+
432
+ export interface TwitterAppPlatform {
433
+ readonly name?: string;
434
+ readonly id?: string;
435
+ readonly url?: string;
436
+ }
437
+
438
+ export interface TwitterAppCard
439
+ extends TwitterCardBase<"app"> {
440
+ readonly country?: string;
441
+ readonly iphone?: TwitterAppPlatform;
442
+ readonly ipad?: TwitterAppPlatform;
443
+ readonly googlePlay?: TwitterAppPlatform;
444
+ }
445
+
446
+ export type TwitterCardMetadata =
447
+ | TwitterSummaryCard
448
+ | TwitterSummaryLargeImageCard
449
+ | TwitterPlayerCard
450
+ | TwitterAppCard;
451
+
452
+ export interface NameMetaTag<
453
+ TName extends string = string,
454
+ TContent extends string = string,
455
+ > {
456
+ readonly name: TName;
457
+ readonly content: TContent;
458
+ }
459
+
460
+ export type TwitterMetaTag =
461
+ | NameMetaTag<"twitter:card", TwitterCardType>
462
+ | NameMetaTag<"twitter:site", TwitterHandle>
463
+ | NameMetaTag<"twitter:site:id">
464
+ | NameMetaTag<"twitter:creator", TwitterHandle>
465
+ | NameMetaTag<"twitter:creator:id">
466
+ | NameMetaTag<"twitter:title">
467
+ | NameMetaTag<"twitter:description">
468
+ | NameMetaTag<"twitter:image", HttpUrl>
469
+ | NameMetaTag<"twitter:image:alt">
470
+ | NameMetaTag<"twitter:player", HttpsUrl>
471
+ | NameMetaTag<"twitter:player:width", IntegerString>
472
+ | NameMetaTag<"twitter:player:height", IntegerString>
473
+ | NameMetaTag<"twitter:player:stream", HttpsUrl>
474
+ | NameMetaTag<"twitter:player:stream:content_type", MimeType>
475
+ | NameMetaTag<"twitter:app:country">
476
+ | NameMetaTag<"twitter:app:name:iphone">
477
+ | NameMetaTag<"twitter:app:id:iphone">
478
+ | NameMetaTag<"twitter:app:url:iphone">
479
+ | NameMetaTag<"twitter:app:name:ipad">
480
+ | NameMetaTag<"twitter:app:id:ipad">
481
+ | NameMetaTag<"twitter:app:url:ipad">
482
+ | NameMetaTag<"twitter:app:name:googleplay">
483
+ | NameMetaTag<"twitter:app:id:googleplay">
484
+ | NameMetaTag<"twitter:app:url:googleplay">;
485
+
486
+ /* -------------------------------------------------------------------------- */
487
+ /* Facebook and HTML-head compatibility */
488
+ /* -------------------------------------------------------------------------- */
489
+
490
+ export interface FacebookOpenGraphMetadata {
491
+ readonly appId?: string;
492
+ }
493
+
494
+ export type FacebookMetaTag = PropertyMetaTag<"fb:app_id">;
495
+
496
+ export interface StandardHeadMetadata {
497
+ readonly title?: string;
498
+ readonly description?: string;
499
+ readonly canonicalUrl?: HttpUrl;
500
+ readonly themeColor?: string;
501
+ }
502
+
503
+ export type StandardHtmlMetaTag =
504
+ | NameMetaTag<"description">
505
+ | NameMetaTag<"theme-color">;
506
+
507
+ export interface CanonicalLinkTag {
508
+ readonly rel: "canonical";
509
+ readonly href: HttpUrl;
510
+ }
511
+
512
+ /* -------------------------------------------------------------------------- */
513
+ /* Aggregate document contract */
514
+ /* -------------------------------------------------------------------------- */
515
+
516
+ export interface SocialMetadataDocument {
517
+ readonly head?: StandardHeadMetadata;
518
+ readonly openGraph: OpenGraphMetadata;
519
+ readonly twitter?: TwitterCardMetadata;
520
+ readonly facebook?: FacebookOpenGraphMetadata;
521
+ }
522
+
523
+ export type SocialMetaTag =
524
+ | OpenGraphMetaTag
525
+ | TwitterMetaTag
526
+ | FacebookMetaTag
527
+ | StandardHtmlMetaTag;
528
+
529
+ export interface RawSocialMetadataDocument {
530
+ readonly title?: string;
531
+ readonly meta: readonly SocialMetaTag[];
532
+ readonly links?: readonly CanonicalLinkTag[];
533
+ }
@@ -1,3 +1,6 @@
1
+ import { type TimeZone } from '../../types/iana'
2
+ import { type Locale } from '../../types/cldr'
3
+
1
4
  export const DEBUG = 10
2
5
 
3
6
  export const INFO = 20
@@ -15,6 +18,24 @@ export const CRITICAL = 50
15
18
  export abstract class Logger {
16
19
  [property: string]: unknown
17
20
 
21
+ public name: string = 'main'
22
+
23
+ public level: number = 0
24
+
25
+ public datetimeLocales: Locale[] = ['en-GB']
26
+
27
+ public datetimeFormatOptions: Intl.DateTimeFormatOptions & { timeZone: TimeZone } = {
28
+ timeZone: 'UTC',
29
+ year: 'numeric',
30
+ month: '2-digit',
31
+ day: '2-digit',
32
+ hour: '2-digit',
33
+ minute: '2-digit',
34
+ second: '2-digit',
35
+ fractionalSecondDigits: 3,
36
+ hourCycle: 'h23'
37
+ }
38
+
18
39
  public abstract debug(data: unknown): void
19
40
 
20
41
  public abstract info(data: unknown): void
@@ -24,4 +45,8 @@ export abstract class Logger {
24
45
  public abstract error(data: unknown): void
25
46
 
26
47
  public abstract critical(data: unknown): void
48
+
49
+ protected getCurrentDatetime(): string {
50
+ return new Date().toLocaleString(this.datetimeLocales, this.datetimeFormatOptions)
51
+ }
27
52
  } //:: class