qstd 0.3.23 → 0.3.25

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.
@@ -264,14 +264,18 @@ __export(time_exports, {
264
264
  startTimer: () => startTimer,
265
265
  toMs: () => toMs
266
266
  });
267
- var formatDuration = (ms, options = {}) => {
268
- if (ms === null || ms === void 0) return "--:--";
267
+ var formatDuration = (value, options = {}) => {
268
+ if (value === null || value === void 0 || !Number.isFinite(value) || value < 0) {
269
+ return "--:--";
270
+ }
269
271
  const {
270
272
  format: fmt = "clock",
273
+ unit = "ms",
271
274
  showZero = false,
272
275
  showMs = false,
273
276
  spaces = true
274
277
  } = options;
278
+ const ms = unit === "ss" ? value * 1e3 : unit === "mm" ? value * 60 * 1e3 : value;
275
279
  const absMs = Math.abs(ms);
276
280
  const totalSeconds = Math.floor(absMs / 1e3);
277
281
  const hours = Math.floor(totalSeconds / 3600);
@@ -308,7 +312,7 @@ var formatDuration = (ms, options = {}) => {
308
312
  return parts2.join(" ") || "0 seconds";
309
313
  }
310
314
  if (fmt === "fractional") {
311
- const totalSecondsWithFraction = Math.abs(ms) / 1e3;
315
+ const totalSecondsWithFraction = absMs / 1e3;
312
316
  const totalMinutes = Math.floor(totalSecondsWithFraction / 60);
313
317
  if (totalMinutes === 0) {
314
318
  const fractionalSeconds = totalSecondsWithFraction.toFixed(1);
@@ -262,14 +262,18 @@ __export(time_exports, {
262
262
  startTimer: () => startTimer,
263
263
  toMs: () => toMs
264
264
  });
265
- var formatDuration = (ms, options = {}) => {
266
- if (ms === null || ms === void 0) return "--:--";
265
+ var formatDuration = (value, options = {}) => {
266
+ if (value === null || value === void 0 || !Number.isFinite(value) || value < 0) {
267
+ return "--:--";
268
+ }
267
269
  const {
268
270
  format: fmt = "clock",
271
+ unit = "ms",
269
272
  showZero = false,
270
273
  showMs = false,
271
274
  spaces = true
272
275
  } = options;
276
+ const ms = unit === "ss" ? value * 1e3 : unit === "mm" ? value * 60 * 1e3 : value;
273
277
  const absMs = Math.abs(ms);
274
278
  const totalSeconds = Math.floor(absMs / 1e3);
275
279
  const hours = Math.floor(totalSeconds / 3600);
@@ -306,7 +310,7 @@ var formatDuration = (ms, options = {}) => {
306
310
  return parts2.join(" ") || "0 seconds";
307
311
  }
308
312
  if (fmt === "fractional") {
309
- const totalSecondsWithFraction = Math.abs(ms) / 1e3;
313
+ const totalSecondsWithFraction = absMs / 1e3;
310
314
  const totalMinutes = Math.floor(totalSecondsWithFraction / 60);
311
315
  if (totalMinutes === 0) {
312
316
  const fractionalSeconds = totalSecondsWithFraction.toFixed(1);
@@ -7,6 +7,7 @@ var libDynamodb = require('@aws-sdk/lib-dynamodb');
7
7
  var clientDynamodb = require('@aws-sdk/client-dynamodb');
8
8
  var clientSns = require('@aws-sdk/client-sns');
9
9
  var clientSqs = require('@aws-sdk/client-sqs');
10
+ var clientSes = require('@aws-sdk/client-ses');
10
11
  var clientS3 = require('@aws-sdk/client-s3');
11
12
  var s3RequestPresigner = require('@aws-sdk/s3-request-presigner');
12
13
  var s3PresignedPost = require('@aws-sdk/s3-presigned-post');
@@ -273,14 +274,18 @@ __export(time_exports, {
273
274
  startTimer: () => startTimer,
274
275
  toMs: () => toMs
275
276
  });
276
- var formatDuration = (ms, options = {}) => {
277
- if (ms === null || ms === void 0) return "--:--";
277
+ var formatDuration = (value, options = {}) => {
278
+ if (value === null || value === void 0 || !Number.isFinite(value) || value < 0) {
279
+ return "--:--";
280
+ }
278
281
  const {
279
282
  format: fmt = "clock",
283
+ unit = "ms",
280
284
  showZero = false,
281
285
  showMs = false,
282
286
  spaces = true
283
287
  } = options;
288
+ const ms = unit === "ss" ? value * 1e3 : unit === "mm" ? value * 60 * 1e3 : value;
284
289
  const absMs = Math.abs(ms);
285
290
  const totalSeconds = Math.floor(absMs / 1e3);
286
291
  const hours = Math.floor(totalSeconds / 3600);
@@ -317,7 +322,7 @@ var formatDuration = (ms, options = {}) => {
317
322
  return parts2.join(" ") || "0 seconds";
318
323
  }
319
324
  if (fmt === "fractional") {
320
- const totalSecondsWithFraction = Math.abs(ms) / 1e3;
325
+ const totalSecondsWithFraction = absMs / 1e3;
321
326
  const totalMinutes = Math.floor(totalSecondsWithFraction / 60);
322
327
  if (totalMinutes === 0) {
323
328
  const fractionalSeconds = totalSecondsWithFraction.toFixed(1);
@@ -1427,11 +1432,43 @@ var send = (sqs, props) => sqs.client.send(
1427
1432
  })
1428
1433
  );
1429
1434
 
1435
+ // src/server/aws/ses/index.ts
1436
+ var ses_exports = {};
1437
+ __export(ses_exports, {
1438
+ create: () => create5,
1439
+ send: () => send2
1440
+ });
1441
+
1442
+ // src/server/aws/ses/fns.ts
1443
+ var stripHtml = (html) => html.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/\s+/g, " ").trim();
1444
+
1445
+ // src/server/aws/ses/index.ts
1446
+ var create5 = () => new clientSes.SESClient({ apiVersion: "2010-12-01" });
1447
+ var send2 = (ses, email) => {
1448
+ const Source = `"${email.fromName}" <${email.from}>`;
1449
+ console.log(`[ses] Sending email to ${email.to} from ${email.from}`);
1450
+ const Destination = { ToAddresses: [email.to] };
1451
+ const Body = {
1452
+ Html: { Charset: "UTF-8", Data: email.content },
1453
+ Text: {
1454
+ Charset: "UTF-8",
1455
+ Data: email.textContent || stripHtml(email.content)
1456
+ }
1457
+ };
1458
+ const Subject = { Charset: "UTF-8", Data: email.subject };
1459
+ const command = new clientSes.SendEmailCommand({
1460
+ Message: { Subject, Body },
1461
+ Destination,
1462
+ Source
1463
+ });
1464
+ return ses.send(command);
1465
+ };
1466
+
1430
1467
  // src/server/aws/s3/index.ts
1431
1468
  var s3_exports = {};
1432
1469
  __export(s3_exports, {
1433
1470
  bucketHandle: () => bucketHandle,
1434
- create: () => create5,
1471
+ create: () => create6,
1435
1472
  createSignedUrl: () => createSignedUrl,
1436
1473
  deleteFile: () => deleteFile,
1437
1474
  getFile: () => getFile,
@@ -1452,7 +1489,7 @@ var getBucketNameOrThrow = (...candidates) => {
1452
1489
  };
1453
1490
 
1454
1491
  // src/server/aws/s3/domain.ts
1455
- var create5 = (props = {}) => {
1492
+ var create6 = (props = {}) => {
1456
1493
  const { cdn } = props;
1457
1494
  const client = new clientS3.S3Client({});
1458
1495
  const bucketName = getBucketNameOrThrow(props.bucketName);
@@ -1611,6 +1648,7 @@ exports.Log = log_exports;
1611
1648
  exports.Money = money_exports;
1612
1649
  exports.Random = random_exports;
1613
1650
  exports.S3 = s3_exports;
1651
+ exports.SES = ses_exports;
1614
1652
  exports.SNS = sns_exports;
1615
1653
  exports.SQS = sqs_exports;
1616
1654
  exports.Str = str_exports;
@@ -12,5 +12,6 @@ export * as Lambda from "./aws/lambda";
12
12
  export * as DDB from "./aws/ddb";
13
13
  export * as SNS from "./aws/sns";
14
14
  export * as SQS from "./aws/sqs";
15
+ export * as SES from "./aws/ses";
15
16
  export * as S3 from "./aws/s3";
16
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AACrC,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AACrC,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAC;AACzC,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAC3C,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AAGrC,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC/B,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AACvC,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AACrC,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AACrC,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAC;AACzC,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAC3C,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AAGrC,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC/B,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AACvC,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,MAAM,UAAU,CAAC"}
@@ -5,6 +5,7 @@ import { DynamoDBDocumentClient, ScanCommand, QueryCommand, DeleteCommand, PutCo
5
5
  import { DynamoDBClient, DeleteTableCommand, DescribeTableCommand, DynamoDBServiceException } from '@aws-sdk/client-dynamodb';
6
6
  import { SNSClient, PublishCommand } from '@aws-sdk/client-sns';
7
7
  import { SQSClient, SendMessageCommand } from '@aws-sdk/client-sqs';
8
+ import { SESClient, SendEmailCommand } from '@aws-sdk/client-ses';
8
9
  import { S3Client, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, HeadObjectCommand, CreateBucketCommand, DeleteBucketCommand, HeadBucketCommand, ListObjectsV2Command, CopyObjectCommand } from '@aws-sdk/client-s3';
9
10
  import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
10
11
  import { createPresignedPost } from '@aws-sdk/s3-presigned-post';
@@ -271,14 +272,18 @@ __export(time_exports, {
271
272
  startTimer: () => startTimer,
272
273
  toMs: () => toMs
273
274
  });
274
- var formatDuration = (ms, options = {}) => {
275
- if (ms === null || ms === void 0) return "--:--";
275
+ var formatDuration = (value, options = {}) => {
276
+ if (value === null || value === void 0 || !Number.isFinite(value) || value < 0) {
277
+ return "--:--";
278
+ }
276
279
  const {
277
280
  format: fmt = "clock",
281
+ unit = "ms",
278
282
  showZero = false,
279
283
  showMs = false,
280
284
  spaces = true
281
285
  } = options;
286
+ const ms = unit === "ss" ? value * 1e3 : unit === "mm" ? value * 60 * 1e3 : value;
282
287
  const absMs = Math.abs(ms);
283
288
  const totalSeconds = Math.floor(absMs / 1e3);
284
289
  const hours = Math.floor(totalSeconds / 3600);
@@ -315,7 +320,7 @@ var formatDuration = (ms, options = {}) => {
315
320
  return parts2.join(" ") || "0 seconds";
316
321
  }
317
322
  if (fmt === "fractional") {
318
- const totalSecondsWithFraction = Math.abs(ms) / 1e3;
323
+ const totalSecondsWithFraction = absMs / 1e3;
319
324
  const totalMinutes = Math.floor(totalSecondsWithFraction / 60);
320
325
  if (totalMinutes === 0) {
321
326
  const fractionalSeconds = totalSecondsWithFraction.toFixed(1);
@@ -1425,11 +1430,43 @@ var send = (sqs, props) => sqs.client.send(
1425
1430
  })
1426
1431
  );
1427
1432
 
1433
+ // src/server/aws/ses/index.ts
1434
+ var ses_exports = {};
1435
+ __export(ses_exports, {
1436
+ create: () => create5,
1437
+ send: () => send2
1438
+ });
1439
+
1440
+ // src/server/aws/ses/fns.ts
1441
+ var stripHtml = (html) => html.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/\s+/g, " ").trim();
1442
+
1443
+ // src/server/aws/ses/index.ts
1444
+ var create5 = () => new SESClient({ apiVersion: "2010-12-01" });
1445
+ var send2 = (ses, email) => {
1446
+ const Source = `"${email.fromName}" <${email.from}>`;
1447
+ console.log(`[ses] Sending email to ${email.to} from ${email.from}`);
1448
+ const Destination = { ToAddresses: [email.to] };
1449
+ const Body = {
1450
+ Html: { Charset: "UTF-8", Data: email.content },
1451
+ Text: {
1452
+ Charset: "UTF-8",
1453
+ Data: email.textContent || stripHtml(email.content)
1454
+ }
1455
+ };
1456
+ const Subject = { Charset: "UTF-8", Data: email.subject };
1457
+ const command = new SendEmailCommand({
1458
+ Message: { Subject, Body },
1459
+ Destination,
1460
+ Source
1461
+ });
1462
+ return ses.send(command);
1463
+ };
1464
+
1428
1465
  // src/server/aws/s3/index.ts
1429
1466
  var s3_exports = {};
1430
1467
  __export(s3_exports, {
1431
1468
  bucketHandle: () => bucketHandle,
1432
- create: () => create5,
1469
+ create: () => create6,
1433
1470
  createSignedUrl: () => createSignedUrl,
1434
1471
  deleteFile: () => deleteFile,
1435
1472
  getFile: () => getFile,
@@ -1450,7 +1487,7 @@ var getBucketNameOrThrow = (...candidates) => {
1450
1487
  };
1451
1488
 
1452
1489
  // src/server/aws/s3/domain.ts
1453
- var create5 = (props = {}) => {
1490
+ var create6 = (props = {}) => {
1454
1491
  const { cdn } = props;
1455
1492
  const client = new S3Client({});
1456
1493
  const bucketName = getBucketNameOrThrow(props.bucketName);
@@ -1598,4 +1635,4 @@ var recordsFromSqs = (body) => {
1598
1635
  }
1599
1636
  };
1600
1637
 
1601
- export { ddb_exports as DDB, dict_exports as Dict, file_exports as File, flow_exports as Flow, int_exports as Int, lambda_exports as Lambda, list_exports as List, log_exports as Log, money_exports as Money, random_exports as Random, s3_exports as S3, sns_exports as SNS, sqs_exports as SQS, str_exports as Str, time_exports as Time };
1638
+ export { ddb_exports as DDB, dict_exports as Dict, file_exports as File, flow_exports as Flow, int_exports as Int, lambda_exports as Lambda, list_exports as List, log_exports as Log, money_exports as Money, random_exports as Random, s3_exports as S3, ses_exports as SES, sns_exports as SNS, sqs_exports as SQS, str_exports as Str, time_exports as Time };
@@ -1,8 +1,11 @@
1
1
  import type { Locale } from "date-fns";
2
2
  type DurationFormat = "compact" | "full" | "clock" | "fractional";
3
+ type DurationUnit = "ms" | "ss" | "mm";
3
4
  type DurationOptions = {
4
5
  /** Format style: 'compact' (1h 2m), 'full' (1 hour 2 minutes), 'clock' (01:02:03), 'fractional' (1.4s, 1m4.4s) */
5
6
  format?: DurationFormat;
7
+ /** Input unit: 'ms' (milliseconds, default), 'ss' (seconds), or 'mm' (minutes). Use 'ss' for audio/video currentTime. */
8
+ unit?: DurationUnit;
6
9
  /** Show zero values for intermediate units (e.g., "1h 0m 30s" vs "1h 30s") */
7
10
  showZero?: boolean;
8
11
  /** Include milliseconds in compact format (e.g., "1s 200ms") */
@@ -11,30 +14,88 @@ type DurationOptions = {
11
14
  spaces?: boolean;
12
15
  };
13
16
  /**
14
- * Formats milliseconds into human-readable duration strings
15
- * Supports compact (1h 2m), full (`1 hour 2 minutes`), clock (`01:02:03`), and fractional (1.4s, 1m4.4s) formats
17
+ * Formats durations into human-readable strings for audio players, timers, and recording UIs.
16
18
  *
17
- * @param {Object} [options={}] - Configuration options
18
- * @param {string} [options.format="clock"] - format
19
- * @param {boolean} [options.showZero=false] - show zero prefix
20
- * @param {boolean} [options.showMs=false] - include milliseconds (compact format only)
21
- * @param {boolean} [options.spaces=true] - use spaces between units (compact format only)
19
+ * Audio/video APIs typically provide time in seconds (e.g., `audio.currentTime`), while
20
+ * JavaScript timers use milliseconds. This function handles both via the `unit` option,
21
+ * eliminating manual conversion at call sites. Invalid inputs (null, undefined, NaN,
22
+ * Infinity, negative) return "--:--" for safe display in UIs.
23
+ *
24
+ * @param value - Duration value in the specified unit (defaults to milliseconds)
25
+ * @param options - Configuration options
26
+ * @param options.format - Output format: 'clock' (default), 'compact', 'full', or 'fractional'
27
+ * @param options.unit - Input unit: 'ms' (milliseconds, default), 'ss' (seconds), or 'mm' (minutes)
28
+ * @param options.showZero - Show zero intermediate units (e.g., "1h 0m 0s" vs "1h")
29
+ * @param options.showMs - Include milliseconds in compact format
30
+ * @param options.spaces - Use spaces between units in compact format (default: true)
22
31
  *
23
32
  * @example
24
- * formatDuration(90000) // "1:30"
25
- * formatDuration(3661000) // "1:01:01"
26
- * formatDuration(90000, { format: "compact" }) // "1m 30s"
27
- * formatDuration(90000, { format: "full" }) // "1 minute 30 seconds"
28
- * formatDuration(3600000, { format: "compact" }) // "1h"
33
+ * ```ts
34
+ * // ─────────────────────────────────────────────────────────────────────────────
35
+ * // CLOCK FORMAT (default) - "m:ss" or "h:mm:ss"
36
+ * // Best for: audio players, video players, media timelines
37
+ * // ─────────────────────────────────────────────────────────────────────────────
38
+ * formatDuration(90000) // "1:30"
39
+ * formatDuration(3661000) // "1:01:01"
40
+ * formatDuration(45, { unit: "ss" }) // "0:45"
41
+ * formatDuration(225, { unit: "ss" }) // "3:45"
42
+ * formatDuration(3661, { unit: "ss" }) // "1:01:01"
43
+ * formatDuration(90, { unit: "mm" }) // "1:30:00"
44
+ *
45
+ * // ─────────────────────────────────────────────────────────────────────────────
46
+ * // COMPACT FORMAT - "1h 2m 3s" or "1h2m3s"
47
+ * // Best for: recording timers, duration badges, compact displays
48
+ * // ─────────────────────────────────────────────────────────────────────────────
49
+ * formatDuration(90000, { format: "compact" }) // "1m 30s"
50
+ * formatDuration(3600000, { format: "compact" }) // "1h"
51
+ * formatDuration(3661000, { format: "compact" }) // "1h 1m 1s"
52
+ * formatDuration(45, { unit: "ss", format: "compact" }) // "45s"
53
+ * formatDuration(90, { unit: "ss", format: "compact" }) // "1m 30s"
54
+ * formatDuration(3661, { unit: "ss", format: "compact" }) // "1h 1m 1s"
55
+ *
56
+ * // Without spaces (recording timer style)
57
+ * formatDuration(3661, { unit: "ss", format: "compact", spaces: false }) // "1h1m1s"
58
+ * formatDuration(90, { unit: "ss", format: "compact", spaces: false }) // "1m30s"
59
+ * formatDuration(45, { unit: "ss", format: "compact", spaces: false }) // "45s"
60
+ *
61
+ * // With zero intermediate units
29
62
  * formatDuration(3600000, { format: "compact", showZero: true }) // "1h 0m 0s"
30
- * formatDuration(3660000, { format: "full", showZero: true }) // "1 hour 1 minute 0 seconds"
31
- * formatDuration(1400, { format: "fractional" }) // "1.4s"
32
- * formatDuration(45300, { format: "fractional" }) // "45.3s"
33
- * formatDuration(64400, { format: "fractional" }) // "1m 4.4s"
34
- * formatDuration(1234, { format: "compact", showMs: true }) // "1s 234ms"
63
+ * formatDuration(3601000, { format: "compact", showZero: true }) // "1h 0m 1s"
64
+ *
65
+ * // With milliseconds
66
+ * formatDuration(1234, { format: "compact", showMs: true }) // "1s 234ms"
35
67
  * formatDuration(1234, { format: "compact", showMs: true, spaces: false }) // "1s234ms"
68
+ *
69
+ * // ─────────────────────────────────────────────────────────────────────────────
70
+ * // FULL FORMAT - "1 hour 2 minutes 3 seconds"
71
+ * // Best for: accessibility, screen readers, verbose displays
72
+ * // ─────────────────────────────────────────────────────────────────────────────
73
+ * formatDuration(90000, { format: "full" }) // "1 minute 30 seconds"
74
+ * formatDuration(3600000, { format: "full" }) // "1 hour"
75
+ * formatDuration(3661000, { format: "full" }) // "1 hour 1 minute 1 second"
76
+ * formatDuration(7200000, { format: "full" }) // "2 hours"
77
+ * formatDuration(3660000, { format: "full", showZero: true }) // "1 hour 1 minute 0 seconds"
78
+ *
79
+ * // ─────────────────────────────────────────────────────────────────────────────
80
+ * // FRACTIONAL FORMAT - "1.4s" or "1m 4.4s"
81
+ * // Best for: precise timing, animations, performance metrics
82
+ * // ─────────────────────────────────────────────────────────────────────────────
83
+ * formatDuration(1400, { format: "fractional" }) // "1.4s"
84
+ * formatDuration(45300, { format: "fractional" }) // "45.3s"
85
+ * formatDuration(64400, { format: "fractional" }) // "1m 4.4s"
86
+ *
87
+ * // ─────────────────────────────────────────────────────────────────────────────
88
+ * // INVALID/LOADING STATES - Returns "--:--" for safe UI display
89
+ * // ─────────────────────────────────────────────────────────────────────────────
90
+ * formatDuration(null) // "--:--"
91
+ * formatDuration(undefined) // "--:--"
92
+ * formatDuration(NaN) // "--:--"
93
+ * formatDuration(Infinity) // "--:--"
94
+ * formatDuration(-5) // "--:--"
95
+ * formatDuration(-5, { unit: "ss" }) // "--:--"
96
+ * ```
36
97
  */
37
- export declare const formatDuration: (ms: number | null | undefined, options?: DurationOptions) => string;
98
+ export declare const formatDuration: (value: number | null | undefined, options?: DurationOptions) => string;
38
99
  type DateInput = Date | string | number;
39
100
  type DateFormatStyle = "iso" | "short" | "medium" | "long" | "relative" | "year";
40
101
  type DateOptions = {
@@ -1 +1 @@
1
- {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/shared/time.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/shared/time.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qstd",
3
- "version": "0.3.23",
3
+ "version": "0.3.25",
4
4
  "description": "Standard Block component and utilities library with Panda CSS",
5
5
  "author": "malin1",
6
6
  "license": "MIT",
@@ -42,6 +42,24 @@
42
42
  "sideEffects": [
43
43
  "dist/react/index.css"
44
44
  ],
45
+ "scripts": {
46
+ "build": "panda codegen && panda cssgen && tsup && tsc -p tsconfig.build.json && node scripts/inject-css-import.js",
47
+ "build:js": "tsup",
48
+ "build:types": "tsc -p tsconfig.build.json",
49
+ "dev": "tsup --watch",
50
+ "prepublishOnly": "pnpm build",
51
+ "prepare:local": "pnpm build && cd playground && pnpm prepare",
52
+ "test": "vitest run",
53
+ "test:watch": "vitest",
54
+ "test:all": "pnpx tsx tests/test-all.ts",
55
+ "test:block": "node tests/test-block.tsx",
56
+ "test:playground": "node tests/playground-e2e.mjs",
57
+ "typecheck": "tsc --noEmit",
58
+ "typecheck:perf": "tsc --noEmit --extendedDiagnostics",
59
+ "typecheck:trace": "tsc --noEmit --generateTrace ./performance/ts-trace",
60
+ "analyze:tsserver": "bash performance/analyze-tsserver.sh",
61
+ "lint": "eslint ."
62
+ },
45
63
  "peerDependencies": {
46
64
  "react": "^18.0.0 || ^19.0.0",
47
65
  "react-dom": "^18.0.0 || ^19.0.0"
@@ -108,22 +126,5 @@
108
126
  "bugs": {
109
127
  "url": "https://github.com/55cancri/qstd/issues"
110
128
  },
111
- "homepage": "https://github.com/55cancri/qstd#readme",
112
- "scripts": {
113
- "build": "panda codegen && panda cssgen && tsup && tsc -p tsconfig.build.json && node scripts/inject-css-import.js",
114
- "build:js": "tsup",
115
- "build:types": "tsc -p tsconfig.build.json",
116
- "dev": "tsup --watch",
117
- "prepare:local": "pnpm build && cd playground && pnpm prepare",
118
- "test": "vitest run",
119
- "test:watch": "vitest",
120
- "test:all": "pnpx tsx tests/test-all.ts",
121
- "test:block": "node tests/test-block.tsx",
122
- "test:playground": "node tests/playground-e2e.mjs",
123
- "typecheck": "tsc --noEmit",
124
- "typecheck:perf": "tsc --noEmit --extendedDiagnostics",
125
- "typecheck:trace": "tsc --noEmit --generateTrace ./performance/ts-trace",
126
- "analyze:tsserver": "bash performance/analyze-tsserver.sh",
127
- "lint": "eslint ."
128
- }
129
- }
129
+ "homepage": "https://github.com/55cancri/qstd#readme"
130
+ }