ranuts 0.2.0-alpha.1 → 0.4.0-alpha.1

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.
Files changed (119) hide show
  1. package/CLAUDE.md +126 -24
  2. package/README.md +7 -5
  3. package/README.zh-CN.md +7 -5
  4. package/dist/chain-CTywmh_H.js +1 -0
  5. package/dist/{color-CRdlaDqQ.js → color-Dohr9BXX.js} +1 -1
  6. package/dist/enums-BAgbyGdH.js +1 -0
  7. package/dist/i18n-Cf5TtRb4.js +1 -0
  8. package/dist/index.d.ts +1 -5
  9. package/dist/index.js +1 -1
  10. package/dist/src/node/appendFile.d.ts +3 -3
  11. package/dist/src/node/fileInfo.d.ts +2 -2
  12. package/dist/src/node/index.js +1 -1
  13. package/dist/src/node/paresUrl.d.ts +1 -1
  14. package/dist/src/node/readFile.d.ts +3 -3
  15. package/dist/src/node/traverse.d.ts +2 -2
  16. package/dist/src/node/watchFile.d.ts +3 -3
  17. package/dist/src/node/writeFile.d.ts +3 -3
  18. package/dist/src/sw/index.d.ts +109 -0
  19. package/dist/src/sw/index.js +1 -0
  20. package/dist/src/utils/async.d.ts +81 -0
  21. package/dist/src/utils/audioRecorder.d.ts +1 -1
  22. package/dist/src/utils/behavior.d.ts +12 -3
  23. package/dist/src/utils/bom.d.ts +68 -178
  24. package/dist/src/utils/bridge.d.ts +153 -0
  25. package/dist/src/utils/canvas.d.ts +54 -0
  26. package/dist/src/utils/chain.d.ts +80 -0
  27. package/dist/src/utils/color.d.ts +76 -4
  28. package/dist/src/utils/compose.d.ts +1 -1
  29. package/dist/src/utils/console.d.ts +19 -1
  30. package/dist/src/utils/debounce.d.ts +27 -5
  31. package/dist/src/utils/device.d.ts +31 -3
  32. package/dist/src/utils/dom.d.ts +5 -84
  33. package/dist/src/utils/error.d.ts +18 -1
  34. package/dist/src/utils/event.d.ts +61 -0
  35. package/dist/src/utils/file.d.ts +35 -0
  36. package/dist/src/utils/i18n/index.js +1 -0
  37. package/dist/src/utils/i18n.d.ts +69 -0
  38. package/dist/src/utils/idb.d.ts +218 -0
  39. package/dist/src/utils/img.d.ts +60 -4
  40. package/dist/src/utils/index.d.ts +50 -16
  41. package/dist/src/utils/index.js +1 -1
  42. package/dist/src/utils/lang.d.ts +69 -0
  43. package/dist/src/utils/localePath.d.ts +62 -0
  44. package/dist/src/utils/memoize.d.ts +53 -5
  45. package/dist/src/utils/monitor.d.ts +55 -26
  46. package/dist/src/utils/number.d.ts +46 -9
  47. package/dist/src/utils/obj.d.ts +56 -31
  48. package/dist/src/utils/paginate.d.ts +73 -0
  49. package/dist/src/utils/prefetch.d.ts +81 -0
  50. package/dist/src/utils/queue.d.ts +53 -23
  51. package/dist/src/utils/report.d.ts +51 -3
  52. package/dist/src/utils/request.d.ts +26 -7
  53. package/dist/src/utils/script.d.ts +26 -4
  54. package/dist/src/utils/segment.d.ts +62 -0
  55. package/dist/src/utils/signal.d.ts +35 -3
  56. package/dist/src/utils/storage.d.ts +57 -0
  57. package/dist/src/utils/str.d.ts +112 -88
  58. package/dist/src/utils/style.d.ts +31 -0
  59. package/dist/src/utils/subscribe.d.ts +5 -5
  60. package/dist/src/utils/throttle.d.ts +26 -13
  61. package/dist/src/utils/time.d.ts +38 -6
  62. package/dist/src/utils/tween.d.ts +40 -0
  63. package/dist/src/utils/visual/application.d.ts +4 -4
  64. package/dist/src/utils/visual/enums.d.ts +4 -4
  65. package/dist/src/utils/visual/graphics/graphics.d.ts +25 -25
  66. package/dist/src/utils/visual/graphics/graphicsData.d.ts +1 -1
  67. package/dist/src/utils/visual/graphics/graphicsGeometry.d.ts +6 -6
  68. package/dist/src/utils/visual/index.js +1 -1
  69. package/dist/src/utils/visual/math/matrix.d.ts +8 -8
  70. package/dist/src/utils/visual/math/transform.d.ts +1 -1
  71. package/dist/src/utils/visual/render/batchRenderer.d.ts +20 -18
  72. package/dist/src/utils/visual/render/utils/batch/index.d.ts +13 -13
  73. package/dist/src/utils/visual/render/utils/float.d.ts +13 -13
  74. package/dist/src/utils/visual/render/utils/verticy.d.ts +3 -3
  75. package/dist/src/utils/visual/render/utils/webgl/initShader.d.ts +3 -2
  76. package/dist/src/utils/visual/render/utils/webgpu/shaders.d.ts +2 -2
  77. package/dist/src/utils/visual/render/webGPURenderer.d.ts +8 -8
  78. package/dist/src/utils/visual/vertex/container.d.ts +17 -16
  79. package/dist/src/utils/worker.d.ts +125 -0
  80. package/dist/src/utils/zip.d.ts +162 -0
  81. package/dist/src/vnode/index.d.ts +1 -1
  82. package/dist/src/vnode/index.js +1 -1
  83. package/dist/src/vnode/is.d.ts +4 -0
  84. package/dist/test/canvas.test.d.ts +1 -0
  85. package/dist/test/color.test.d.ts +1 -0
  86. package/dist/test/sw.test.d.ts +1 -0
  87. package/dist/test/tween.test.d.ts +1 -0
  88. package/dist/test/utils/async.test.d.ts +1 -0
  89. package/dist/test/utils/file-read.test.d.ts +1 -0
  90. package/dist/test/utils/format.test.d.ts +1 -0
  91. package/dist/test/utils/idb-collection.test.d.ts +1 -0
  92. package/dist/test/utils/idb.test.d.ts +1 -0
  93. package/dist/test/utils/instrumentation.test.d.ts +1 -0
  94. package/dist/test/utils/lang.test.d.ts +1 -0
  95. package/dist/test/utils/locale-path.test.d.ts +1 -0
  96. package/dist/test/utils/media-query.test.d.ts +1 -0
  97. package/dist/test/utils/number-parse.test.d.ts +1 -0
  98. package/dist/test/utils/paginate.test.d.ts +1 -0
  99. package/dist/test/utils/prefetch.test.d.ts +1 -0
  100. package/dist/test/utils/query-storage.test.d.ts +1 -0
  101. package/dist/test/utils/queue.test.d.ts +1 -0
  102. package/dist/test/utils/report-config.test.d.ts +1 -0
  103. package/dist/test/utils/report-image.test.d.ts +1 -0
  104. package/dist/test/utils/segment.test.d.ts +1 -0
  105. package/dist/test/utils/signal-once.test.d.ts +1 -0
  106. package/dist/test/utils/single-flight.test.d.ts +1 -0
  107. package/dist/test/utils/timing.test.d.ts +1 -0
  108. package/dist/test/utils/worker-client.test.d.ts +1 -0
  109. package/dist/test/utils/worker-serve.test.d.ts +1 -0
  110. package/dist/test/utils/zip.test.d.ts +1 -0
  111. package/dist/umd/index.umd.cjs +1 -1
  112. package/dist/umd/node/node.umd.cjs +1 -1
  113. package/dist/umd/utils/utils.umd.cjs +1 -1
  114. package/dist/utils-8TVtLBjA.js +1 -0
  115. package/docs/API.md +341 -147
  116. package/package.json +13 -6
  117. package/dist/src/vnode/chainDom.d.ts +0 -47
  118. package/dist/subscribe-CINWsor3.js +0 -1
  119. package/dist/utils-_OxsVZmz.js +0 -1
@@ -2,37 +2,66 @@ export interface Payload {
2
2
  payload: Record<string, unknown>;
3
3
  type?: string;
4
4
  }
5
+ export interface MonitorOptions {
6
+ /** Telemetry endpoint. Required — without it nothing is sent. */
7
+ url: string;
8
+ /** Cookie holding the user id, included in every envelope */
9
+ userIdCookie?: string;
10
+ /** Minimum interval between beacons, ms. Default 300 */
11
+ throttleMs?: number;
12
+ /** Which channels to instrument. Everything except `console` is on by default. */
13
+ channels?: Partial<Record<MonitorChannel, boolean>>;
14
+ }
15
+ export type MonitorChannel = 'click' | 'error' | 'fetch' | 'xhr' | 'performance' | 'console';
16
+ /**
17
+ * @description: Front-end telemetry: page-load performance, clicks, errors, fetch/XHR traffic
18
+ * and (optionally) console output, all beaconed to one endpoint.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const monitor = new Monitor({ url: 'https://telemetry.example.com/collect' });
23
+ * const stop = monitor.start();
24
+ * monitor.log({ event: 'checkout' }); // manual event
25
+ * // on teardown (HMR, SPA route with a different config, tests)
26
+ * stop();
27
+ * ```
28
+ */
5
29
  export declare class Monitor {
6
- constructor();
7
- /**
8
- * @description: 页面加载性能上报
9
- * @param {Payload} param1
10
- */
11
- reportPerformance(): void;
12
- /**
13
- * @description: 手动触发的上报
14
- * @param {Record} payload
15
- * @param {*} unknown
16
- */
17
- log(payload: Record<string, unknown>): void;
18
- /**
19
- * @description: 点击上报
20
- * @return {*}
21
- */
22
- reportClick(): void;
23
- reportXhr(): void;
30
+ private options;
31
+ private teardown;
32
+ private send;
33
+ constructor(options: MonitorOptions);
34
+ /** Whether instrumentation is currently installed */
35
+ get running(): boolean;
24
36
  /**
25
- * @description: fetch上报
37
+ * @description: Install the configured channels. Idempotent — calling it twice does not
38
+ * double-instrument.
39
+ * @return {Function} stop — removes every listener and global patch
26
40
  */
27
- reportFetch(): void;
41
+ start: () => (() => void);
42
+ /** @description: Remove every listener and restore every patched global */
43
+ stop: () => void;
28
44
  /**
29
- * @description: 错误上报
45
+ * Build one event. `createData()` is called **per event**, not once at install time — the
46
+ * old version captured it when the hook was registered, so every later click reported the
47
+ * URL and timestamp of page load rather than of the click.
30
48
  */
31
- reportError(): void;
49
+ private event;
50
+ /** @description: Report a one-off event with the standard envelope */
51
+ log: (payload: Record<string, unknown>) => void;
52
+ /** @description: Page-load performance metrics; fires once, so it is not throttled */
53
+ reportPerformance: () => void;
54
+ /** @description: Click tracking */
55
+ reportClick: () => (() => void);
56
+ /** @description: Uncaught errors and unhandled rejections */
57
+ reportError: () => (() => void);
58
+ /** @description: fetch traffic */
59
+ reportFetch: () => (() => void);
60
+ /** @description: XMLHttpRequest traffic */
61
+ reportXhr: () => (() => void);
32
62
  /**
33
- * @description: 上报console
63
+ * @description: console output. Off by default — see `DEFAULT_CHANNELS`; a backend that
64
+ * logs to the console would loop.
34
65
  */
35
- reportConsole(): void;
36
- init: () => void;
37
- initialize(): void;
66
+ reportConsole: () => (() => void);
38
67
  }
@@ -3,32 +3,32 @@ interface ComputeNumberResult {
3
3
  next: (a: string, b: number) => ComputeNumberResult;
4
4
  }
5
5
  /**
6
- * @description: 百分比转换成数字
6
+ * @description: Convert a percentage string into a number
7
7
  * @param {string} str
8
8
  * @return {*}
9
9
  */
10
10
  export declare const perToNum: (str?: string) => number;
11
11
  /**
12
- * @description: 限制最大和最小值
12
+ * @description: Clamp a value between a minimum and a maximum
13
13
  * @return {*}
14
14
  */
15
15
  export declare const range: (num: number, min?: number, max?: number) => number;
16
16
  /**
17
- * 数字运算(主要用于小数点精度问题)
18
- * @param {number} a 前面的值
19
- * @param {"+"|"-"|"*"|"/"} type 计算方式
20
- * @param {number} b 后面的值
17
+ * Arithmetic that works around floating-point precision.
18
+ * @param {number} a left operand
19
+ * @param {"+"|"-"|"*"|"/"} type operation
20
+ * @param {number} b right operand
21
21
  * @example
22
22
  * ```js
23
- * // 可链式调用
23
+ * // chainable
24
24
  * const res = computeNumber(1.3, "-", 1.2).next("+", 1.5).next("*", 2.3).next("/", 0.2).result;
25
25
  * console.log(res);
26
26
  * ```
27
27
  */
28
28
  export declare class Mathjs {
29
29
  /**
30
- * 获取数字小数点的长度
31
- * @param {number} n 数字
30
+ * Number of digits after the decimal point
31
+ * @param {number} n the number
32
32
  */
33
33
  getDecimalLength: (n: number) => number;
34
34
  amend: (n: number, precision?: number) => number;
@@ -42,4 +42,41 @@ export declare class Mathjs {
42
42
  export declare function mathjs(a: number, type: string, b: number): ComputeNumberResult;
43
43
  export declare const transformNumber: (value: string, locale?: string, precision?: number, fixed?: number) => string;
44
44
  export declare const addNumSym: (value: string | number, flag?: string | number) => string;
45
+ /**
46
+ * @description: Chinese numerals to Arabic, covering 「十五」「二十三」「一百零三」「一千零一」「三万」.
47
+ * Simplified and traditional alike (万/萬); full-width digits are normalised first. Returns
48
+ * null when an unrecognised character is present.
49
+ * @param {string} value
50
+ * @return {number | null}
51
+ * @example
52
+ * ```ts
53
+ * parseChineseNumber('二十三'); // 23
54
+ * parseChineseNumber('一百零三'); // 103
55
+ * parseChineseNumber('第三章'); // null — contains non-numeral characters, slice the number out first
56
+ * ```
57
+ */
58
+ export declare const parseChineseNumber: (value: string) => number | null;
59
+ /**
60
+ * @description: Roman numerals to Arabic (either case, handling subtractive forms such as IV / IX). Returns null for invalid input.
61
+ * @param {string} value
62
+ * @return {number | null}
63
+ * @example
64
+ * ```ts
65
+ * parseRomanNumber('XIV'); // 14
66
+ * parseRomanNumber('mcmxciv'); // 1994
67
+ * ```
68
+ */
69
+ export declare const parseRomanNumber: (value: string) => number | null;
70
+ /**
71
+ * @description: English ordinals to numbers, tried in order: Arabic digits, number words
72
+ * (one–twenty), then Roman numerals. Returns null when none match.
73
+ * @param {string} value
74
+ * @return {number | null}
75
+ * @example
76
+ * ```ts
77
+ * parseEnglishNumber('Three'); // 3
78
+ * parseEnglishNumber('XII'); // 12
79
+ * ```
80
+ */
81
+ export declare const parseEnglishNumber: (value: string) => number | null;
45
82
  export {};
@@ -1,83 +1,108 @@
1
1
  /**
2
- * @description: 对象转 url 字符串
2
+ * @description: Serialise an object into a URL query string
3
3
  * @param {*} data
4
4
  * @return {*}
5
5
  */
6
6
  export declare function querystring(data?: {}): string;
7
- export declare const formatJson: (jsonObj: string, callback?: () => void) => string;
8
7
  /**
9
- * @description: 过滤对象的属性,去除对象中在list数组里面有的属性,返回一个新对象,一般是用于去除空字符和null
10
- * @param {Object} obj 传入对象
11
- * @param {Array} list 传入数组
8
+ * @description: Pretty-print JSON. Accepts an object or a JSON string (single quotes are
9
+ * tolerated and normalized to double quotes, which is common in hand-written config).
10
+ *
11
+ * This is `JSON.stringify(value, null, indent)` with lenient parsing in front. It replaces a
12
+ * ~90-line hand-rolled formatter that rebuilt the layout by regex-injecting newlines around
13
+ * every brace, bracket and comma, then tried to undo the damage inside string literals by
14
+ * counting quotes per line — which mis-handled escaped quotes, and treated a brace or comma
15
+ * inside a string value as structure. The platform serializer has none of those problems and
16
+ * is orders of magnitude faster.
17
+ *
18
+ * @param {string | object} value object, or a JSON string to reformat
19
+ * @param {Function} onError called with the parse/serialize error; the function returns `''`
20
+ * @param {number} indent spaces per level, default 4
21
+ * @return {string} formatted JSON, or `''` when the input could not be parsed
22
+ * @example
23
+ * ```ts
24
+ * formatJson({ a: 1, b: [2, 3] });
25
+ * formatJson("{'a': 1}"); // single quotes tolerated
26
+ * formatJson('nope', (e) => log(e)); // '' + the error handed to the callback
27
+ * ```
28
+ */
29
+ export declare const formatJson: (value: string | object, onError?: (error: Error) => void, indent?: number) => string;
30
+ /**
31
+ * @description: Return a new object without the properties whose values appear in `list` — typically used to drop empty strings and nulls
32
+ * @param {Object} obj source object
33
+ * @param {Array} list values to remove
12
34
  * @return {Object}
13
35
  */
14
36
  export declare const filterObj: (obj: Record<string, unknown>, list: Array<string>) => Record<string, unknown>;
15
37
  type Obj = Record<string, any>;
16
38
  /**
17
- * @description: 合并对象
39
+ * @description: Merge objects
18
40
  * @param {Obj} a
19
41
  * @param {Obj} b
20
42
  * @return {*}
21
43
  */
22
44
  export declare const merge: (a: Obj, b?: Obj) => Obj;
23
45
  /**
24
- * 重写对象上面的某个属性
46
+ * @description: Replace a property on an object, wrapping whatever was there before.
47
+ *
48
+ * Returns a **restore function**. Patching a global is a one-way door without it: tests cannot
49
+ * clean up after themselves, two instrumentation layers cannot be unwound in order, and a hot
50
+ * reload stacks wrapper on wrapper until the call is nested a dozen deep. Always keep the
51
+ * returned function and call it on teardown.
25
52
  *
26
- * @export
27
- * @param {IAnyObject} source 需要被重写的对象
28
- * @param {string} name 需要被重写对象的 key
29
- * @param {(...args: any[]) => any} replacement 以原有的函数作为参数,执行并重写原有函数
30
- * @param {boolean} isForced 是否强制重写(可能原先没有该属性)
53
+ * @param {any} source object to patch
54
+ * @param {string} name key to patch
55
+ * @param {Function} replacement receives the original value, returns the wrapper
56
+ * @param {boolean} isForced patch even when the key does not exist yet
57
+ * @return {Function} restore — puts the original value back; safe to call more than once
31
58
  */
32
- export declare function replaceOld(source: any, name: string, replacement: (...args: unknown[]) => unknown, isForced?: boolean): void;
59
+ export declare function replaceOld(source: any, name: string, replacement: (...args: unknown[]) => unknown, isForced?: boolean): () => void;
33
60
  /**
34
- * @description: exports 对象拼接到 obj 上,并冻结 obj
61
+ * @description: Copy an exports object onto `obj`, then freeze it
35
62
  * @param {Object} obj
36
63
  * @param {Object} exports
37
64
  * @return {Object}
38
65
  */
39
66
  export declare const mergeExports: (obj: Record<string, string>, exports: Record<string, string>) => Record<string, string>;
40
67
  /**
41
- * @description: 给全局对象上增加属性
68
+ * @description: Define a property on the global object
42
69
  * @param {string} name
43
70
  * @param {string} value
44
71
  * @return {*}
45
72
  */
46
73
  export declare const setAttributeByGlobal: (name: string, value: unknown) => void;
47
74
  /**
48
- * 深度比较两个值是否相等
49
- * 实现类似 Lodash 的 isEqual 函数
75
+ * Deep-compare two values, in the manner of Lodash's isEqual.
50
76
  */
51
77
  /**
52
- * 检查两个值是否为基本相同的值
53
- * 处理特殊情况如 NaN, -0/+0
78
+ * Whether two primitives are the same value, handling the special cases NaN and -0/+0.
54
79
  */
55
80
  export declare function sameValueZero(x: any, y: any): boolean;
56
81
  /**
57
- * 判断是否为类对象
82
+ * Whether the value is object-like
58
83
  */
59
84
  export declare function isObjectLike(value: any): boolean;
60
85
  /**
61
- * 获取对象的标签
86
+ * The object's internal [[Class]] tag
62
87
  */
63
88
  export declare function getTag(value: any): string;
64
89
  /**
65
- * 检查是否是类数组对象
90
+ * Whether the value is array-like
66
91
  */
67
92
  export declare function isArrayLike(value: any): boolean;
68
93
  /**
69
- * 深度比较两个值是否相等
70
- * @param value 第一个值
71
- * @param other 第二个值
72
- * @param seen 已经比较过的对象(用于处理循环引用)
73
- * @returns 两个值是否相等
94
+ * Deep-compare two values.
95
+ * @param value first value
96
+ * @param other second value
97
+ * @param seen objects already compared, so circular references terminate
98
+ * @returns whether the two are equal
74
99
  */
75
100
  export declare function isEqual(value: any, other: any, seen?: Map<any, any>): boolean;
76
101
  /**
77
- * 深克隆函数,支持各种复杂数据类型和循环引用
78
- * @param value 需要深度克隆的值
79
- * @param cloneMap 用于跟踪已克隆的对象,避免循环引用问题
80
- * @returns 克隆后的值
102
+ * Deep clone, covering the complex built-in types and circular references.
103
+ * @param value value to clone
104
+ * @param cloneMap objects already cloned, so circular references terminate
105
+ * @returns the cloned value
81
106
  */
82
107
  export declare const cloneDeep: <T>(value: T, cloneMap?: WeakMap<object, any>) => T;
83
108
  export {};
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Paginate plain text into fixed-size boxes — the layout a reader, a teleprompter or a
3
+ * printable preview needs, where the same text must be cut into pages of a known size.
4
+ *
5
+ * The whole thing is **pure arithmetic**: it takes the box dimensions and the type metrics as
6
+ * numbers and never touches the DOM. That is what lets it run inside a Worker, on the server,
7
+ * or in a test — measure the container once on the main thread, then paginate anywhere.
8
+ *
9
+ * It assumes a **monospaced grid**: every character advances either one cell (CJK, full-width)
10
+ * or `narrowRatio` of one (ASCII). That is exactly true for a monospaced font and close enough
11
+ * for the CJK-dominant body text this was built for; it is *not* a substitute for real shaping
12
+ * on proportional Latin text.
13
+ */
14
+ /** The box each page must fit into, in px. */
15
+ export interface TextBox {
16
+ width: number;
17
+ height: number;
18
+ }
19
+ export interface TextGridMetrics {
20
+ /** Advance width of one full-width character, px (font size + letter spacing). */
21
+ charWidth: number;
22
+ /** Distance between baselines, px. */
23
+ lineHeight: number;
24
+ /**
25
+ * Advance of a narrow (ASCII) character as a fraction of `charWidth`. Default `0.5625`
26
+ * (9/16), the usual half-width-plus-spacing ratio.
27
+ */
28
+ narrowRatio?: number;
29
+ }
30
+ export interface PaginateOptions {
31
+ /**
32
+ * Below this, in either dimension, the box is treated as not yet laid out and pagination
33
+ * returns nothing. Default `30`. Guards against paginating during first paint, when a
34
+ * container still measures 0 and a naive `floor(0 / charWidth)` would loop forever.
35
+ */
36
+ minBox?: number;
37
+ }
38
+ export interface TextPage {
39
+ text: string;
40
+ /** Offset of this page's first character in the source text. */
41
+ start: number;
42
+ /** Offset one past this page's last character. */
43
+ end: number;
44
+ index: number;
45
+ }
46
+ export interface PaginateResult {
47
+ pages: TextPage[];
48
+ /** Length of the normalized source text. */
49
+ total: number;
50
+ charsPerLine: number;
51
+ linesPerPage: number;
52
+ /** `charsPerLine * linesPerPage` — the budget one page spends. */
53
+ charsPerPage: number;
54
+ }
55
+ /**
56
+ * @description: Cut text into pages that fit `box`, given the type metrics.
57
+ *
58
+ * ASCII words are kept whole: a page never ends mid-word unless the word is longer than a
59
+ * line. Newlines start a new line and are charged one character.
60
+ *
61
+ * @param {string} text source text; `\r\n` / `\r` are normalized to `\n` first
62
+ * @param {TextBox} box page box in px — measure the container once, then call this anywhere
63
+ * @param {TextGridMetrics} metrics character advance and line height, px
64
+ * @param {PaginateOptions} options
65
+ * @return {PaginateResult} pages plus the grid it derived
66
+ * @example
67
+ * ```ts
68
+ * const { width, height } = container.getBoundingClientRect();
69
+ * const result = paginateText(book, { width, height }, { charWidth: 18.4, lineHeight: 40 });
70
+ * render(result.pages[0].text);
71
+ * ```
72
+ */
73
+ export declare const paginateText: (text: string, box: TextBox, metrics: TextGridMetrics, options?: PaginateOptions) => PaginateResult;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Background prefetching plus cache probing.
3
+ *
4
+ * The key fact: a same-origin GET that has been fetched once lands in the service worker's
5
+ * CacheStorage (assuming the SW is cache-first for same-origin GETs), and from then on any
6
+ * code requesting that URL hits the cache and works offline. So "warming up a large asset"
7
+ * needs no dedicated downloader — pulling the bytes into the cache is enough.
8
+ *
9
+ * But prefetching **spends the user's data on their behalf**, so it must be constrained:
10
+ * it should stay quiet under data-saver mode, on slow 2G, and whenever the user turned it off.
11
+ */
12
+ export interface WhenIdleOptions {
13
+ /** Maximum wait for requestIdleCallback in milliseconds, defaults to 8000 */
14
+ timeout?: number;
15
+ /** Fallback delay in milliseconds when requestIdleCallback is unavailable, defaults to 2500 */
16
+ fallbackDelay?: number;
17
+ }
18
+ /**
19
+ * @description: Run a callback while the browser is idle, falling back to setTimeout where
20
+ * `requestIdleCallback` is missing (long absent in Safari).
21
+ * @param {Function} callback runs when idle
22
+ * @param {WhenIdleOptions} options
23
+ * @return {Function} cancel function; calling it after the callback ran is a no-op
24
+ */
25
+ export declare const whenIdle: (callback: () => void, options?: WhenIdleOptions) => (() => void);
26
+ export interface NetworkAllowanceOptions {
27
+ /** localStorage switch: any value stored under this key means the user turned prefetching off */
28
+ optOutKey?: string;
29
+ /** effectiveType values treated as a "slow network", defaults to slow-2g / 2g */
30
+ slowTypes?: string[];
31
+ }
32
+ /**
33
+ * @description: Whether the current network and user settings allow proactively downloading
34
+ * a large asset. Returns false under data-saver (`saveData`), on a slow network, or when the
35
+ * user opted out. When the information is unavailable it **defaults to allowed** — the
36
+ * Network Information API does not exist in Safari/Firefox, and a missing reading must not
37
+ * disable prefetching everywhere.
38
+ * @param {NetworkAllowanceOptions} options
39
+ * @return {boolean}
40
+ */
41
+ export declare const networkAllowsDownload: (options?: NetworkAllowanceOptions) => boolean;
42
+ /**
43
+ * @description: Whether a URL is already in CacheStorage. When probing a group of files,
44
+ * test the one that **finishes downloading last** (usually the largest), otherwise a
45
+ * half-finished download reads as fully cached.
46
+ * @param {string} url
47
+ * @return {Promise<boolean>}
48
+ */
49
+ export declare const isUrlCached: (url: string) => Promise<boolean>;
50
+ /**
51
+ * @description: Pull a single URL into the cache; skipped when already cached. Failures are
52
+ * silent — a failed prefetch only means the later load performs a real download, it must not
53
+ * bubble up and interrupt the main flow.
54
+ * @param {string} url
55
+ * @return {Promise<void>}
56
+ */
57
+ export declare const prefetchUrl: (url: string) => Promise<void>;
58
+ export interface PrefetchOptions {
59
+ /**
60
+ * Message type used to hand prefetching to the service worker. The SW keeps the work alive
61
+ * with `event.waitUntil`, so a download survives page navigation (very noticeable when the
62
+ * user moves around quickly); without a controlling SW it falls back to a main-thread fetch.
63
+ */
64
+ serviceWorkerMessage?: string;
65
+ }
66
+ /**
67
+ * @description: Prefetch a group of URLs, **serially** — prefetching is background work, and
68
+ * saturating the bandwidth in parallel slows down the page the user is actually looking at.
69
+ * @param {string[]} urls
70
+ * @param {PrefetchOptions} options
71
+ * @return {Promise<void>}
72
+ */
73
+ export declare const prefetchUrls: (urls: string[], options?: PrefetchOptions) => Promise<void>;
74
+ /**
75
+ * @description: Prefetch a group of URLs while idle, subject to `networkAllowsDownload`.
76
+ * Non-blocking, returns immediately.
77
+ * @param {string[]} urls
78
+ * @param {object} options the idle-scheduling, network-allowance and SW-forwarding options combined
79
+ * @return {Function} cancel function (can only cancel a schedule that has not started)
80
+ */
81
+ export declare const prefetchWhenIdle: (urls: string[], options?: WhenIdleOptions & NetworkAllowanceOptions & PrefetchOptions) => (() => void);
@@ -1,33 +1,63 @@
1
- import type { Func } from '@/utils/memoize';
2
- interface QuestQueueOptions {
3
- simultaneous: number;
4
- total: number;
1
+ export type QueueTask<T = unknown> = () => Promise<T> | T;
2
+ export interface QuestQueueOptions {
3
+ /** Maximum concurrency; `<= 0` is treated as 1 */
4
+ simultaneous?: number;
5
5
  }
6
- type Fun = Function | Func;
6
+ /**
7
+ * @description: An async task queue with limited concurrency. At most `simultaneous` tasks
8
+ * run at once, the rest wait, and each completion pulls in the next. For batch uploads or
9
+ * batch requests — anything that must not be fired all at once.
10
+ *
11
+ * The queue is **FIFO**, and `add()` returns that task's own promise, so one failing task
12
+ * only rejects its own promise instead of taking the whole queue down. (The previous
13
+ * implementation popped LIFO, packed every task's result into a single shared promise, and
14
+ * `add` never started anything — `running` had to be called by hand.)
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const queue = new QuestQueue({ simultaneous: 3 });
19
+ * const results = await Promise.all(urls.map((url) => queue.add(() => fetch(url))));
20
+ * // or wait for the whole queue to drain (failures included):
21
+ * await queue.onIdle();
22
+ * ```
23
+ */
7
24
  export declare class QuestQueue {
8
- current: number;
9
- queue: Fun[];
10
- simultaneous: number;
25
+ /** Number of tasks currently running */
26
+ running: number;
27
+ /** Number of finished tasks (failures included) */
11
28
  executed: number;
12
- total: number;
13
- constructor({ simultaneous, total }: QuestQueueOptions);
29
+ /** Maximum concurrency */
30
+ simultaneous: number;
31
+ private queue;
32
+ private idleWaiters;
33
+ constructor({ simultaneous }?: QuestQueueOptions);
34
+ /** Number of tasks waiting to run */
35
+ get pending(): number;
36
+ /** Whether the queue has drained (nothing queued, nothing running) */
37
+ get idle(): boolean;
14
38
  /**
15
- * @description: 传入异步函数,添加到队列并执行
16
- * @param {Fun} asynchronous
17
- * @return {*}
39
+ * @description: Enqueue an async task and get back its own result promise. Starts
40
+ * immediately when a slot is free.
41
+ * @param {QueueTask<T>} task nullary function returning a promise or a plain value
42
+ * @return {Promise<T>}
18
43
  */
19
- add: (asynchronous: Fun) => void;
44
+ add: <T = unknown>(task: QueueTask<T>) => Promise<T>;
20
45
  /**
21
- * @description: 执行异步函数
22
- * @param {*} Promise
23
- * @return {*}
46
+ * @description: Enqueue a batch with `Promise.allSettled` semantics: wait for all of them,
47
+ * report each outcome individually **in input order**, and never drop the remaining results
48
+ * because one failed.
49
+ * @param {QueueTask[]} tasks
50
+ * @return {Promise<PromiseSettledResult<T>[]>}
24
51
  */
25
- running: () => Promise<unknown>;
52
+ allSettled: <T = unknown>(tasks: Array<QueueTask<T>>) => Promise<Array<PromiseSettledResult<T>>>;
26
53
  /**
27
- * @description: 并发执行所有的异步函数,并返回所有的结果
28
- * @param {*} Promise
29
- * @return {*}
54
+ * @description: Wait for the queue to drain. Resolves immediately when already empty.
55
+ * @return {Promise<void>}
30
56
  */
31
- allSettled: () => Promise<unknown>;
57
+ onIdle: () => Promise<void>;
58
+ /** @description: Drop every task that has not started (running ones are untouched); their promises reject */
59
+ clear: () => void;
60
+ /** Pull tasks off the head while slots are free; called again after each task to keep the loop going */
61
+ private next;
62
+ private settleIdle;
32
63
  }
33
- export {};
@@ -1,8 +1,56 @@
1
- interface BeaconPayload {
1
+ export interface BeaconPayload {
2
+ /** Endpoint to send to. Falls back to whatever `setReportUrl` configured. */
2
3
  url?: string;
3
4
  type?: string;
4
5
  payload: Record<string, unknown>;
5
6
  }
6
- export declare const report: ({ url, type, payload, }: BeaconPayload) => boolean | undefined | void;
7
+ export interface ReportConfig {
8
+ /** Default endpoint for every `report()` that does not pass its own `url` */
9
+ url?: string;
10
+ /** Cookie holding the current user id, included in `createData()`. Unset means no user id. */
11
+ userIdCookie?: string;
12
+ }
13
+ /**
14
+ * @description: Configure the default reporting endpoint (and optionally the cookie holding
15
+ * the user id). Call it once at startup so `report({ payload })` needs no `url`.
16
+ *
17
+ * There is deliberately no default. The previous version derived one from `getHost()`, which
18
+ * built a URL from a domain hard-coded to this repo's author — and a leftover edit had already
19
+ * degraded it to the literal `'//log.'`, so every report without an explicit `url` was posted
20
+ * to an unreachable host. A library cannot know where your telemetry belongs; it has to be told.
21
+ *
22
+ * @param {ReportConfig} next merged into the current configuration
23
+ * @example
24
+ * ```ts
25
+ * setReportUrl({ url: 'https://telemetry.example.com/collect', userIdCookie: 'uid' });
26
+ * report({ payload: { event: 'page_view' } });
27
+ * ```
28
+ */
29
+ export declare const setReportUrl: (next: ReportConfig | string) => void;
30
+ /** @description: The currently configured reporting endpoint, or `''` when none was set */
31
+ export declare const getReportUrl: () => string;
32
+ /**
33
+ * @description: Send a telemetry beacon. Prefers `navigator.sendBeacon` (does not block
34
+ * unload, delivery is the browser's job) and falls back to a 1x1 image.
35
+ *
36
+ * The fallback is chosen by whether **sendBeacon itself is available and succeeded**, not by
37
+ * whether `navigator` exists — `navigator` exists in every browser, so testing that made the
38
+ * image fallback unreachable and silently dropped the report whenever sendBeacon was missing
39
+ * or returned false.
40
+ *
41
+ * @param {BeaconPayload} options
42
+ * @return {boolean} whether some transport accepted it
43
+ */
44
+ export declare const report: ({ url, type, payload }: BeaconPayload) => boolean;
45
+ /**
46
+ * @description: Build the standard envelope that accompanies a report — page URL, referrer,
47
+ * viewport, user agent, a random event id and a timestamp. Merge your own fields on top.
48
+ *
49
+ * The user id comes from the cookie named by `setReportUrl({ userIdCookie })`; without that
50
+ * configuration no user id is included. (It used to read a cookie named after this repo's
51
+ * author's own deployment, which was never going to exist in anyone else's app.)
52
+ *
53
+ * @param {Record<string, unknown>} params extra fields, applied last
54
+ * @return {Record<string, unknown>} empty object under SSR
55
+ */
7
56
  export declare function createData(params?: Record<string, unknown>): Record<string, unknown>;
8
- export {};
@@ -5,13 +5,32 @@ export interface Options {
5
5
  errorHook: Hooks;
6
6
  }
7
7
  /**
8
- * @description: fetch
9
- * @param {Partial} options
8
+ * @description: Instrument `window.fetch` so every request, response and failure reaches your
9
+ * hooks. The original behaviour is untouched: the response is passed through and errors are
10
+ * re-thrown.
11
+ *
12
+ * Returns a **restore function**. Without one, instrumenting a global is a one-way door — a
13
+ * hot reload stacks a new wrapper on the previous one, and a test can never give the page a
14
+ * clean `fetch` back.
15
+ *
16
+ * @param {Partial<Options>} options requestHook / responseHook / errorHook
17
+ * @return {Function} restore — puts the original `fetch` back
18
+ * @example
19
+ * ```ts
20
+ * const restore = handleFetchHook({ errorHook: (url, error) => report({ payload: { url } }) });
21
+ * // on teardown
22
+ * restore();
23
+ * ```
10
24
  */
11
- export declare const handleFetchHook: (options?: Partial<Options>) => void;
25
+ export declare const handleFetchHook: (options?: Partial<Options>) => (() => void);
12
26
  /**
13
- * @description: xhr
14
- * @param {Partial} options
15
- * @return {*}
27
+ * @description: Instrument `XMLHttpRequest` (`open` / `send`) so requests, responses and
28
+ * failures reach your hooks. Patches the prototype, so it applies to every instance.
29
+ *
30
+ * Returns a **restore function** that undoes both patches. See `handleFetchHook` for why that
31
+ * matters.
32
+ *
33
+ * @param {Partial<Options>} options requestHook / responseHook / errorHook
34
+ * @return {Function} restore — puts the original `open` and `send` back
16
35
  */
17
- export declare const handleXhrHook: (options?: Partial<Options>) => void;
36
+ export declare const handleXhrHook: (options?: Partial<Options>) => (() => void);