@ai-matrx/kit 0.5.0

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 (118) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +21 -0
  3. package/README.md +72 -0
  4. package/dist/autosave.cjs +92 -0
  5. package/dist/autosave.cjs.map +1 -0
  6. package/dist/autosave.d.cts +17 -0
  7. package/dist/autosave.d.ts +17 -0
  8. package/dist/autosave.js +72 -0
  9. package/dist/autosave.js.map +1 -0
  10. package/dist/clipboard.cjs +152 -0
  11. package/dist/clipboard.cjs.map +1 -0
  12. package/dist/clipboard.d.cts +17 -0
  13. package/dist/clipboard.d.ts +17 -0
  14. package/dist/clipboard.js +132 -0
  15. package/dist/clipboard.js.map +1 -0
  16. package/dist/color-util.cjs +790 -0
  17. package/dist/color-util.cjs.map +1 -0
  18. package/dist/color-util.d.cts +235 -0
  19. package/dist/color-util.d.ts +235 -0
  20. package/dist/color-util.js +767 -0
  21. package/dist/color-util.js.map +1 -0
  22. package/dist/concurrency.cjs +59 -0
  23. package/dist/concurrency.cjs.map +1 -0
  24. package/dist/concurrency.d.cts +19 -0
  25. package/dist/concurrency.d.ts +19 -0
  26. package/dist/concurrency.js +38 -0
  27. package/dist/concurrency.js.map +1 -0
  28. package/dist/confirm.cjs +344 -0
  29. package/dist/confirm.cjs.map +1 -0
  30. package/dist/confirm.d.cts +132 -0
  31. package/dist/confirm.d.ts +132 -0
  32. package/dist/confirm.js +312 -0
  33. package/dist/confirm.js.map +1 -0
  34. package/dist/delimiter-guard.cjs +172 -0
  35. package/dist/delimiter-guard.cjs.map +1 -0
  36. package/dist/delimiter-guard.d.cts +119 -0
  37. package/dist/delimiter-guard.d.ts +119 -0
  38. package/dist/delimiter-guard.js +151 -0
  39. package/dist/delimiter-guard.js.map +1 -0
  40. package/dist/drafts.cjs +223 -0
  41. package/dist/drafts.cjs.map +1 -0
  42. package/dist/drafts.d.cts +62 -0
  43. package/dist/drafts.d.ts +62 -0
  44. package/dist/drafts.js +201 -0
  45. package/dist/drafts.js.map +1 -0
  46. package/dist/idb-store.cjs +178 -0
  47. package/dist/idb-store.cjs.map +1 -0
  48. package/dist/idb-store.d.cts +111 -0
  49. package/dist/idb-store.d.ts +111 -0
  50. package/dist/idb-store.js +155 -0
  51. package/dist/idb-store.js.map +1 -0
  52. package/dist/idle-scheduler.cjs +268 -0
  53. package/dist/idle-scheduler.cjs.map +1 -0
  54. package/dist/idle-scheduler.d.cts +185 -0
  55. package/dist/idle-scheduler.d.ts +185 -0
  56. package/dist/idle-scheduler.js +246 -0
  57. package/dist/idle-scheduler.js.map +1 -0
  58. package/dist/index.cjs +3113 -0
  59. package/dist/index.cjs.map +1 -0
  60. package/dist/index.d.cts +897 -0
  61. package/dist/index.d.ts +897 -0
  62. package/dist/index.js +3088 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/invalidation.cjs +64 -0
  65. package/dist/invalidation.cjs.map +1 -0
  66. package/dist/invalidation.d.cts +52 -0
  67. package/dist/invalidation.d.ts +52 -0
  68. package/dist/invalidation.js +43 -0
  69. package/dist/invalidation.js.map +1 -0
  70. package/dist/json-format.cjs +319 -0
  71. package/dist/json-format.cjs.map +1 -0
  72. package/dist/json-format.d.cts +148 -0
  73. package/dist/json-format.d.ts +148 -0
  74. package/dist/json-format.js +286 -0
  75. package/dist/json-format.js.map +1 -0
  76. package/dist/latest-request.cjs +36 -0
  77. package/dist/latest-request.cjs.map +1 -0
  78. package/dist/latest-request.d.cts +29 -0
  79. package/dist/latest-request.d.ts +29 -0
  80. package/dist/latest-request.js +16 -0
  81. package/dist/latest-request.js.map +1 -0
  82. package/dist/qr.cjs +109 -0
  83. package/dist/qr.cjs.map +1 -0
  84. package/dist/qr.d.cts +47 -0
  85. package/dist/qr.d.ts +47 -0
  86. package/dist/qr.js +78 -0
  87. package/dist/qr.js.map +1 -0
  88. package/dist/react-tree.cjs +69 -0
  89. package/dist/react-tree.cjs.map +1 -0
  90. package/dist/react-tree.d.cts +38 -0
  91. package/dist/react-tree.d.ts +38 -0
  92. package/dist/react-tree.js +38 -0
  93. package/dist/react-tree.js.map +1 -0
  94. package/dist/search-scoring.cjs +116 -0
  95. package/dist/search-scoring.cjs.map +1 -0
  96. package/dist/search-scoring.d.cts +77 -0
  97. package/dist/search-scoring.d.ts +77 -0
  98. package/dist/search-scoring.js +95 -0
  99. package/dist/search-scoring.js.map +1 -0
  100. package/dist/text-case.cjs +313 -0
  101. package/dist/text-case.cjs.map +1 -0
  102. package/dist/text-case.d.cts +53 -0
  103. package/dist/text-case.d.ts +53 -0
  104. package/dist/text-case.js +292 -0
  105. package/dist/text-case.js.map +1 -0
  106. package/dist/toast.cjs +74 -0
  107. package/dist/toast.cjs.map +1 -0
  108. package/dist/toast.d.cts +92 -0
  109. package/dist/toast.d.ts +92 -0
  110. package/dist/toast.js +54 -0
  111. package/dist/toast.js.map +1 -0
  112. package/dist/url-state.cjs +212 -0
  113. package/dist/url-state.cjs.map +1 -0
  114. package/dist/url-state.d.cts +90 -0
  115. package/dist/url-state.d.ts +90 -0
  116. package/dist/url-state.js +199 -0
  117. package/dist/url-state.js.map +1 -0
  118. package/package.json +286 -0
@@ -0,0 +1,111 @@
1
+ import { IDBPDatabase } from 'idb';
2
+
3
+ /**
4
+ * @ai-matrx/kit/idb-store — base manager.
5
+ *
6
+ * Ported verbatim from matrx-frontend `lib/idb/store-manager.ts`, with ONE
7
+ * structural inversion: the original documented a `protected static _instance`
8
+ * convention (each subclass held its singleton on its own static field).
9
+ * A class-static is module state — with this package built `splitting: false`
10
+ * in dual ESM/CJS format the class is duplicated into the root bundle and the
11
+ * `./idb-store` bundle, and CJS/ESM each instantiate their own module graph,
12
+ * so a static field would silently split "the" singleton into up to four
13
+ * instances racing the same IndexedDB database. The singleton slot therefore
14
+ * lives on `globalThis` under `Symbol.for("ai-matrx.kit.idb-store-state")`
15
+ * instead — see `singleton.ts` (`getIdbStoreSingleton`). Never "clean this
16
+ * up" back into a static field.
17
+ */
18
+
19
+ type AsyncResult<T> = Promise<{
20
+ data: T | null;
21
+ error: Error | null;
22
+ }>;
23
+ declare abstract class DBStoreManager<T> {
24
+ protected db: IDBPDatabase | null;
25
+ protected dbName: string;
26
+ protected version: number;
27
+ protected constructor(dbName: string, version: number);
28
+ protected abstract setupStores(db: IDBPDatabase): void;
29
+ protected initDB(): Promise<void>;
30
+ protected add<TRecord = T>(storeName: string, data: TRecord): AsyncResult<string>;
31
+ protected get<TRecord = T>(storeName: string, id: string): AsyncResult<TRecord>;
32
+ protected getAll(storeName: string): AsyncResult<T[]>;
33
+ protected update<U extends object>(storeName: string, id: number, data: Partial<U>): AsyncResult<boolean>;
34
+ protected delete(storeName: string, id: number): AsyncResult<boolean>;
35
+ protected query<U>(storeName: string, indexName: string, query: IDBValidKey | IDBKeyRange): AsyncResult<U[]>;
36
+ }
37
+
38
+ /**
39
+ * Public CRUD surface over `DBStoreManager` — ported verbatim from
40
+ * matrx-frontend `lib/idb/store-interface.ts`. The base keeps its operations
41
+ * `protected` so feature stores expose intent-named methods; this subclass is
42
+ * the escape hatch for hosts that want the raw generic surface (e.g. a
43
+ * `useIDB(store)` hook driving arbitrary stores).
44
+ *
45
+ * NOTE (original API shape, kept verbatim): `getItem` takes a string id while
46
+ * `updateItem`/`deleteItem` take a number id. With an `autoIncrement` key path
47
+ * the generated keys are numbers, so reads use `String(id)` only against
48
+ * string-keyed stores — this asymmetry is the original public contract.
49
+ */
50
+
51
+ declare abstract class PublicStoreManager<T> extends DBStoreManager<T> {
52
+ constructor(dbName: string, version: number);
53
+ addItem(storeName: string, data: T): AsyncResult<string>;
54
+ getItem(storeName: string, id: string): AsyncResult<T>;
55
+ getAllItems(storeName: string): AsyncResult<T[]>;
56
+ updateItem<U extends object>(storeName: string, id: number, data: Partial<U>): AsyncResult<boolean>;
57
+ deleteItem(storeName: string, id: number): AsyncResult<boolean>;
58
+ queryItems<U>(storeName: string, indexName: string, query: IDBValidKey | IDBKeyRange): AsyncResult<U[]>;
59
+ }
60
+
61
+ /**
62
+ * Convenience base for a store class bound to one named object store —
63
+ * ported from matrx-frontend `lib/idb/feature-store.ts`.
64
+ *
65
+ * DEFECT FIX vs the original: the constructor kicks off `initDB()` without
66
+ * awaiting it (by design — construction stays synchronous and operations
67
+ * before init resolve `{ error: "Database not initialized" }`), but the
68
+ * original left that floating promise unhandled, so a failed `openDB` (e.g.
69
+ * private-mode storage denial) surfaced as an unhandled promise rejection on
70
+ * top of the `initDB` console.error. The rejection is now absorbed here —
71
+ * `initDB` has already screamed, and every operation still reports the
72
+ * uninitialized state through its `AsyncResult` error.
73
+ */
74
+
75
+ declare abstract class FeatureStore<T> extends PublicStoreManager<T> {
76
+ protected storeName: string;
77
+ protected constructor(dbName: string, version: number, storeName: string);
78
+ protected abstract setupStores(db: IDBPDatabase): void;
79
+ getStoreName(): string;
80
+ }
81
+
82
+ /**
83
+ * The one place a store singleton may live.
84
+ *
85
+ * The original host pattern held each store's singleton on a
86
+ * `protected static _instance` field of the store class. In this package that
87
+ * is a hazard, not a convenience: built `splitting: false` in dual ESM/CJS
88
+ * format, the class body is duplicated into the root bundle and the
89
+ * `./idb-store` bundle, and the ESM and CJS graphs each instantiate their own
90
+ * copy — a class-static would silently split "the" singleton into several
91
+ * instances, each opening its own connection (and racing upgrades) against
92
+ * the same IndexedDB database. So per-store instances live on `globalThis`
93
+ * under `Symbol.for("ai-matrx.kit.idb-store-state")`, keyed by a
94
+ * caller-chosen name. Never "clean this up" into module or class state.
95
+ *
96
+ * Host usage (replaces the old static `getInstance` body):
97
+ *
98
+ * class AudioStore extends DBStoreManager<Recording> { ... }
99
+ * export const audioStore = getIdbStoreSingleton("voiceNotesDB/audio", () => new AudioStore());
100
+ */
101
+ /**
102
+ * Returns the one instance registered under `key`, creating it via `create`
103
+ * on first call. The key should uniquely name the store (a good convention is
104
+ * `"<dbName>/<storeName>"`) — two different classes registering the same key
105
+ * is a caller bug and gets whichever registered first.
106
+ */
107
+ declare function getIdbStoreSingleton<T>(key: string, create: () => T): T;
108
+ /** @internal Test-only: drop every registered store instance. */
109
+ declare function _resetIdbStoreSingletons(): void;
110
+
111
+ export { type AsyncResult, DBStoreManager, FeatureStore, PublicStoreManager, _resetIdbStoreSingletons, getIdbStoreSingleton };
@@ -0,0 +1,155 @@
1
+ // src/idb-store/store-manager.ts
2
+ import { openDB } from "idb";
3
+ var DBStoreManager = class {
4
+ db = null;
5
+ dbName;
6
+ version;
7
+ constructor(dbName, version) {
8
+ this.dbName = dbName;
9
+ this.version = version;
10
+ }
11
+ async initDB() {
12
+ if (this.db) return;
13
+ try {
14
+ this.db = await openDB(this.dbName, this.version, {
15
+ upgrade: (db) => {
16
+ this.setupStores(db);
17
+ }
18
+ });
19
+ } catch (error) {
20
+ console.error("Failed to initialize database:", error);
21
+ throw error;
22
+ }
23
+ }
24
+ // `add`/`get` carry their own generic (like `query` below) so a subclass
25
+ // whose `T` covers one IDB object store (e.g. Recording) can still read/write
26
+ // a different store's record shape (e.g. RecordingChunk) without a cast —
27
+ // see the audio store in the original host, which manages both `recordings`
28
+ // and `chunks` stores.
29
+ async add(storeName, data) {
30
+ try {
31
+ if (!this.db) throw new Error("Database not initialized");
32
+ const id = await this.db.add(storeName, data);
33
+ return { data: id.toString(), error: null };
34
+ } catch (error) {
35
+ return { data: null, error };
36
+ }
37
+ }
38
+ async get(storeName, id) {
39
+ try {
40
+ if (!this.db) throw new Error("Database not initialized");
41
+ const result = await this.db.get(storeName, id);
42
+ return { data: result, error: null };
43
+ } catch (error) {
44
+ return { data: null, error };
45
+ }
46
+ }
47
+ async getAll(storeName) {
48
+ try {
49
+ if (!this.db) throw new Error("Database not initialized");
50
+ const result = await this.db.getAll(storeName);
51
+ return { data: result, error: null };
52
+ } catch (error) {
53
+ return { data: null, error };
54
+ }
55
+ }
56
+ async update(storeName, id, data) {
57
+ try {
58
+ if (!this.db) throw new Error("Database not initialized");
59
+ const existing = await this.db.get(storeName, id);
60
+ if (!existing) throw new Error("Record not found");
61
+ const updated = { ...existing, ...data };
62
+ await this.db.put(storeName, updated);
63
+ return { data: true, error: null };
64
+ } catch (error) {
65
+ return { data: null, error };
66
+ }
67
+ }
68
+ async delete(storeName, id) {
69
+ try {
70
+ if (!this.db) throw new Error("Database not initialized");
71
+ await this.db.delete(storeName, id);
72
+ return { data: true, error: null };
73
+ } catch (error) {
74
+ return { data: null, error };
75
+ }
76
+ }
77
+ async query(storeName, indexName, query) {
78
+ try {
79
+ if (!this.db) throw new Error("Database not initialized");
80
+ const result = await this.db.getAllFromIndex(storeName, indexName, query);
81
+ return { data: result, error: null };
82
+ } catch (error) {
83
+ return { data: null, error };
84
+ }
85
+ }
86
+ };
87
+
88
+ // src/idb-store/store-interface.ts
89
+ var PublicStoreManager = class extends DBStoreManager {
90
+ constructor(dbName, version) {
91
+ super(dbName, version);
92
+ }
93
+ addItem(storeName, data) {
94
+ return this.add(storeName, data);
95
+ }
96
+ getItem(storeName, id) {
97
+ return this.get(storeName, id);
98
+ }
99
+ getAllItems(storeName) {
100
+ return this.getAll(storeName);
101
+ }
102
+ updateItem(storeName, id, data) {
103
+ return this.update(storeName, id, data);
104
+ }
105
+ deleteItem(storeName, id) {
106
+ return this.delete(storeName, id);
107
+ }
108
+ queryItems(storeName, indexName, query) {
109
+ return this.query(storeName, indexName, query);
110
+ }
111
+ };
112
+
113
+ // src/idb-store/feature-store.ts
114
+ var FeatureStore = class extends PublicStoreManager {
115
+ storeName;
116
+ constructor(dbName, version, storeName) {
117
+ super(dbName, version);
118
+ this.storeName = storeName;
119
+ this.initDB().catch(() => {
120
+ });
121
+ }
122
+ getStoreName() {
123
+ return this.storeName;
124
+ }
125
+ };
126
+
127
+ // src/idb-store/singleton.ts
128
+ var STATE_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.kit.idb-store-state");
129
+ function getState() {
130
+ const holder = globalThis;
131
+ let state = holder[STATE_SLOT];
132
+ if (!state) {
133
+ state = { instances: /* @__PURE__ */ new Map() };
134
+ holder[STATE_SLOT] = state;
135
+ }
136
+ return state;
137
+ }
138
+ function getIdbStoreSingleton(key, create) {
139
+ const state = getState();
140
+ if (!state.instances.has(key)) {
141
+ state.instances.set(key, create());
142
+ }
143
+ return state.instances.get(key);
144
+ }
145
+ function _resetIdbStoreSingletons() {
146
+ getState().instances.clear();
147
+ }
148
+ export {
149
+ DBStoreManager,
150
+ FeatureStore,
151
+ PublicStoreManager,
152
+ _resetIdbStoreSingletons,
153
+ getIdbStoreSingleton
154
+ };
155
+ //# sourceMappingURL=idb-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/idb-store/store-manager.ts","../src/idb-store/store-interface.ts","../src/idb-store/feature-store.ts","../src/idb-store/singleton.ts"],"sourcesContent":["/**\n * @ai-matrx/kit/idb-store — base manager.\n *\n * Ported verbatim from matrx-frontend `lib/idb/store-manager.ts`, with ONE\n * structural inversion: the original documented a `protected static _instance`\n * convention (each subclass held its singleton on its own static field).\n * A class-static is module state — with this package built `splitting: false`\n * in dual ESM/CJS format the class is duplicated into the root bundle and the\n * `./idb-store` bundle, and CJS/ESM each instantiate their own module graph,\n * so a static field would silently split \"the\" singleton into up to four\n * instances racing the same IndexedDB database. The singleton slot therefore\n * lives on `globalThis` under `Symbol.for(\"ai-matrx.kit.idb-store-state\")`\n * instead — see `singleton.ts` (`getIdbStoreSingleton`). Never \"clean this\n * up\" back into a static field.\n */\n\nimport { openDB, IDBPDatabase } from \"idb\";\n\nexport type AsyncResult<T> = Promise<{ data: T | null; error: Error | null }>;\n\nexport abstract class DBStoreManager<T> {\n protected db: IDBPDatabase | null = null;\n protected dbName: string;\n protected version: number;\n\n protected constructor(dbName: string, version: number) {\n this.dbName = dbName;\n this.version = version;\n }\n\n protected abstract setupStores(db: IDBPDatabase): void;\n\n protected async initDB(): Promise<void> {\n if (this.db) return;\n\n try {\n this.db = await openDB(this.dbName, this.version, {\n upgrade: (db) => {\n this.setupStores(db);\n },\n });\n } catch (error) {\n console.error(\"Failed to initialize database:\", error);\n throw error;\n }\n }\n\n // `add`/`get` carry their own generic (like `query` below) so a subclass\n // whose `T` covers one IDB object store (e.g. Recording) can still read/write\n // a different store's record shape (e.g. RecordingChunk) without a cast —\n // see the audio store in the original host, which manages both `recordings`\n // and `chunks` stores.\n protected async add<TRecord = T>(storeName: string, data: TRecord): AsyncResult<string> {\n try {\n if (!this.db) throw new Error(\"Database not initialized\");\n const id = await this.db.add(storeName, data);\n return { data: id.toString(), error: null };\n } catch (error) {\n return { data: null, error: error as Error };\n }\n }\n\n protected async get<TRecord = T>(storeName: string, id: string): AsyncResult<TRecord> {\n try {\n if (!this.db) throw new Error(\"Database not initialized\");\n const result = await this.db.get(storeName, id);\n return { data: result as TRecord, error: null };\n } catch (error) {\n return { data: null, error: error as Error };\n }\n }\n\n protected async getAll(storeName: string): AsyncResult<T[]> {\n try {\n if (!this.db) throw new Error(\"Database not initialized\");\n const result = await this.db.getAll(storeName);\n return { data: result as T[], error: null };\n } catch (error) {\n return { data: null, error: error as Error };\n }\n }\n\n protected async update<U extends object>(storeName: string, id: number, data: Partial<U>): AsyncResult<boolean> {\n try {\n if (!this.db) throw new Error(\"Database not initialized\");\n const existing = await this.db.get(storeName, id);\n if (!existing) throw new Error(\"Record not found\");\n\n const updated = { ...existing, ...data };\n await this.db.put(storeName, updated);\n return { data: true, error: null };\n } catch (error) {\n return { data: null, error: error as Error };\n }\n }\n\n protected async delete(storeName: string, id: number): AsyncResult<boolean> {\n try {\n if (!this.db) throw new Error(\"Database not initialized\");\n await this.db.delete(storeName, id);\n return { data: true, error: null };\n } catch (error) {\n return { data: null, error: error as Error };\n }\n }\n\n protected async query<U>(\n storeName: string,\n indexName: string,\n query: IDBValidKey | IDBKeyRange\n ): AsyncResult<U[]> {\n try {\n if (!this.db) throw new Error(\"Database not initialized\");\n const result = await this.db.getAllFromIndex(storeName, indexName, query);\n return { data: result as U[], error: null };\n } catch (error) {\n return { data: null, error: error as Error };\n }\n }\n}\n","/**\n * Public CRUD surface over `DBStoreManager` — ported verbatim from\n * matrx-frontend `lib/idb/store-interface.ts`. The base keeps its operations\n * `protected` so feature stores expose intent-named methods; this subclass is\n * the escape hatch for hosts that want the raw generic surface (e.g. a\n * `useIDB(store)` hook driving arbitrary stores).\n *\n * NOTE (original API shape, kept verbatim): `getItem` takes a string id while\n * `updateItem`/`deleteItem` take a number id. With an `autoIncrement` key path\n * the generated keys are numbers, so reads use `String(id)` only against\n * string-keyed stores — this asymmetry is the original public contract.\n */\n\nimport { DBStoreManager, AsyncResult } from \"./store-manager\";\n\nexport abstract class PublicStoreManager<T> extends DBStoreManager<T> {\n constructor(dbName: string, version: number) {\n super(dbName, version);\n }\n\n public addItem(storeName: string, data: T): AsyncResult<string> {\n return this.add(storeName, data);\n }\n\n public getItem(storeName: string, id: string): AsyncResult<T> {\n return this.get(storeName, id);\n }\n\n public getAllItems(storeName: string): AsyncResult<T[]> {\n return this.getAll(storeName);\n }\n\n public updateItem<U extends object>(\n storeName: string,\n id: number,\n data: Partial<U>\n ): AsyncResult<boolean> {\n return this.update<U>(storeName, id, data);\n }\n\n public deleteItem(storeName: string, id: number): AsyncResult<boolean> {\n return this.delete(storeName, id);\n }\n\n public queryItems<U>(\n storeName: string,\n indexName: string,\n query: IDBValidKey | IDBKeyRange\n ): AsyncResult<U[]> {\n return this.query<U>(storeName, indexName, query);\n }\n}\n","/**\n * Convenience base for a store class bound to one named object store —\n * ported from matrx-frontend `lib/idb/feature-store.ts`.\n *\n * DEFECT FIX vs the original: the constructor kicks off `initDB()` without\n * awaiting it (by design — construction stays synchronous and operations\n * before init resolve `{ error: \"Database not initialized\" }`), but the\n * original left that floating promise unhandled, so a failed `openDB` (e.g.\n * private-mode storage denial) surfaced as an unhandled promise rejection on\n * top of the `initDB` console.error. The rejection is now absorbed here —\n * `initDB` has already screamed, and every operation still reports the\n * uninitialized state through its `AsyncResult` error.\n */\n\nimport { IDBPDatabase } from \"idb\";\nimport { PublicStoreManager } from \"./store-interface\";\n\nexport abstract class FeatureStore<T> extends PublicStoreManager<T> {\n protected storeName: string;\n\n protected constructor(dbName: string, version: number, storeName: string) {\n super(dbName, version);\n this.storeName = storeName;\n this.initDB().catch(() => {\n // Already logged loudly by initDB; operations report\n // \"Database not initialized\" through their AsyncResult.\n });\n }\n\n protected abstract override setupStores(db: IDBPDatabase): void;\n\n public getStoreName(): string {\n return this.storeName;\n }\n}\n","/**\n * The one place a store singleton may live.\n *\n * The original host pattern held each store's singleton on a\n * `protected static _instance` field of the store class. In this package that\n * is a hazard, not a convenience: built `splitting: false` in dual ESM/CJS\n * format, the class body is duplicated into the root bundle and the\n * `./idb-store` bundle, and the ESM and CJS graphs each instantiate their own\n * copy — a class-static would silently split \"the\" singleton into several\n * instances, each opening its own connection (and racing upgrades) against\n * the same IndexedDB database. So per-store instances live on `globalThis`\n * under `Symbol.for(\"ai-matrx.kit.idb-store-state\")`, keyed by a\n * caller-chosen name. Never \"clean this up\" into module or class state.\n *\n * Host usage (replaces the old static `getInstance` body):\n *\n * class AudioStore extends DBStoreManager<Recording> { ... }\n * export const audioStore = getIdbStoreSingleton(\"voiceNotesDB/audio\", () => new AudioStore());\n */\n\ninterface IdbStoreState {\n instances: Map<string, unknown>;\n}\n\nconst STATE_SLOT = Symbol.for(\"ai-matrx.kit.idb-store-state\");\n\nfunction getState(): IdbStoreState {\n const holder = globalThis as Record<symbol, IdbStoreState | undefined>;\n let state = holder[STATE_SLOT];\n if (!state) {\n state = { instances: new Map() };\n holder[STATE_SLOT] = state;\n }\n return state;\n}\n\n/**\n * Returns the one instance registered under `key`, creating it via `create`\n * on first call. The key should uniquely name the store (a good convention is\n * `\"<dbName>/<storeName>\"`) — two different classes registering the same key\n * is a caller bug and gets whichever registered first.\n */\nexport function getIdbStoreSingleton<T>(key: string, create: () => T): T {\n const state = getState();\n if (!state.instances.has(key)) {\n state.instances.set(key, create());\n }\n return state.instances.get(key) as T;\n}\n\n/** @internal Test-only: drop every registered store instance. */\nexport function _resetIdbStoreSingletons(): void {\n getState().instances.clear();\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,268 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/idle-scheduler.ts
22
+ var idle_scheduler_exports = {};
23
+ __export(idle_scheduler_exports, {
24
+ getSchedulerState: () => getSchedulerState,
25
+ onFlushComplete: () => onFlushComplete,
26
+ registerIdleTask: () => registerIdleTask,
27
+ resetScheduler: () => resetScheduler,
28
+ useIdleGate: () => useIdleGate,
29
+ useIdleReady: () => useIdleReady,
30
+ useIdleRegister: () => useIdleRegister,
31
+ useIdleTask: () => useIdleTask,
32
+ whenPageIdle: () => whenPageIdle
33
+ });
34
+ module.exports = __toCommonJS(idle_scheduler_exports);
35
+
36
+ // src/idle-scheduler/scheduler.ts
37
+ var STATE_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.kit.idle-scheduler-state");
38
+ function getState() {
39
+ const holder = globalThis;
40
+ let state = holder[STATE_SLOT];
41
+ if (!state) {
42
+ state = {
43
+ queue: /* @__PURE__ */ new Map(),
44
+ flushState: "idle",
45
+ cleanupFns: [],
46
+ flushListeners: /* @__PURE__ */ new Set()
47
+ };
48
+ holder[STATE_SLOT] = state;
49
+ if (typeof window !== "undefined") {
50
+ window.__idleSched = getSchedulerState;
51
+ }
52
+ }
53
+ return state;
54
+ }
55
+ function registerIdleTask(key, priority, callback) {
56
+ const state = getState();
57
+ if (state.flushState === "done") {
58
+ scheduleImmediate(callback);
59
+ return () => {
60
+ };
61
+ }
62
+ state.queue.set(key, { key, priority, callback });
63
+ if (state.flushState === "idle") {
64
+ startFlushPipeline(state);
65
+ }
66
+ return () => {
67
+ state.queue.delete(key);
68
+ };
69
+ }
70
+ function onFlushComplete(listener) {
71
+ const state = getState();
72
+ if (state.flushState === "done") {
73
+ queueMicrotask(listener);
74
+ return () => {
75
+ };
76
+ }
77
+ state.flushListeners.add(listener);
78
+ if (state.flushState === "idle") {
79
+ startFlushPipeline(state);
80
+ }
81
+ return () => {
82
+ state.flushListeners.delete(listener);
83
+ };
84
+ }
85
+ function whenPageIdle(signal) {
86
+ if (signal?.aborted) return Promise.resolve(false);
87
+ return new Promise((resolve) => {
88
+ let settled = false;
89
+ let unsubscribe = () => {
90
+ };
91
+ const finish = (ready) => {
92
+ if (settled) return;
93
+ settled = true;
94
+ unsubscribe();
95
+ signal?.removeEventListener("abort", onAbort);
96
+ resolve(ready);
97
+ };
98
+ const onAbort = () => finish(false);
99
+ unsubscribe = onFlushComplete(() => finish(true));
100
+ signal?.addEventListener("abort", onAbort, { once: true });
101
+ });
102
+ }
103
+ function getSchedulerState() {
104
+ const state = getState();
105
+ return {
106
+ flushState: state.flushState,
107
+ pendingCount: state.queue.size,
108
+ pendingKeys: Array.from(state.queue.keys())
109
+ };
110
+ }
111
+ function resetScheduler() {
112
+ const state = getState();
113
+ state.cleanupFns.forEach((fn) => fn());
114
+ state.cleanupFns = [];
115
+ state.queue.clear();
116
+ state.flushListeners.clear();
117
+ state.flushState = "idle";
118
+ }
119
+ function startFlushPipeline(state) {
120
+ if (typeof window === "undefined") return;
121
+ state.flushState = "waiting";
122
+ const waitForLoad = () => {
123
+ if (document.readyState === "complete") {
124
+ waitForPaint();
125
+ } else {
126
+ const onLoad = () => waitForPaint();
127
+ window.addEventListener("load", onLoad, { once: true });
128
+ state.cleanupFns.push(() => window.removeEventListener("load", onLoad));
129
+ }
130
+ };
131
+ const waitForPaint = () => {
132
+ let advanced = false;
133
+ const advance = () => {
134
+ if (advanced) return;
135
+ advanced = true;
136
+ waitForIdle();
137
+ };
138
+ const rafId = requestAnimationFrame(advance);
139
+ const timeoutId = setTimeout(
140
+ advance,
141
+ document.visibilityState === "hidden" ? 250 : 1500
142
+ );
143
+ state.cleanupFns.push(() => {
144
+ cancelAnimationFrame(rafId);
145
+ clearTimeout(timeoutId);
146
+ });
147
+ };
148
+ const waitForIdle = () => {
149
+ const schedulerGlobal = globalThis.scheduler;
150
+ if (schedulerGlobal && "postTask" in schedulerGlobal) {
151
+ schedulerGlobal.postTask(() => void flush(state), { priority: "background" }).catch(() => {
152
+ });
153
+ return;
154
+ }
155
+ if ("requestIdleCallback" in window) {
156
+ const idleId = requestIdleCallback(() => void flush(state));
157
+ state.cleanupFns.push(() => cancelIdleCallback(idleId));
158
+ return;
159
+ }
160
+ const channel = new MessageChannel();
161
+ channel.port1.onmessage = () => void flush(state);
162
+ channel.port2.postMessage(void 0);
163
+ };
164
+ waitForLoad();
165
+ }
166
+ async function flush(state) {
167
+ if (state.flushState === "done" || state.flushState === "flushing") return;
168
+ state.flushState = "flushing";
169
+ const sorted = Array.from(state.queue.values()).sort(
170
+ (a, b) => a.priority - b.priority
171
+ );
172
+ state.queue.clear();
173
+ for (const task of sorted) {
174
+ try {
175
+ await task.callback();
176
+ } catch (err) {
177
+ console.error(`[IdleScheduler] Task "${task.key}" failed:`, err);
178
+ }
179
+ }
180
+ state.flushState = "done";
181
+ if (state.queue.size > 0) {
182
+ const late = Array.from(state.queue.values()).sort(
183
+ (a, b) => a.priority - b.priority
184
+ );
185
+ state.queue.clear();
186
+ for (const task of late) scheduleImmediate(task.callback);
187
+ }
188
+ state.flushListeners.forEach((listener) => {
189
+ try {
190
+ listener();
191
+ } catch (err) {
192
+ console.error("[IdleScheduler] Flush listener failed:", err);
193
+ }
194
+ });
195
+ state.flushListeners.clear();
196
+ }
197
+ function scheduleImmediate(callback) {
198
+ requestAnimationFrame(() => {
199
+ const schedulerGlobal = globalThis.scheduler;
200
+ if (schedulerGlobal && "postTask" in schedulerGlobal) {
201
+ schedulerGlobal.postTask(() => void callback(), { priority: "background" }).catch(() => {
202
+ });
203
+ return;
204
+ }
205
+ if ("requestIdleCallback" in window) {
206
+ requestIdleCallback(() => void callback());
207
+ return;
208
+ }
209
+ const channel = new MessageChannel();
210
+ channel.port1.onmessage = () => void callback();
211
+ channel.port2.postMessage(void 0);
212
+ });
213
+ }
214
+
215
+ // src/idle-scheduler/hooks.ts
216
+ var import_react = require("react");
217
+ function useIdleTask(key, priority, callback) {
218
+ const callbackRef = (0, import_react.useRef)(callback);
219
+ callbackRef.current = callback;
220
+ (0, import_react.useEffect)(() => {
221
+ const unregister = registerIdleTask(key, priority, () => {
222
+ return callbackRef.current();
223
+ });
224
+ return unregister;
225
+ }, [key, priority]);
226
+ }
227
+ function useIdleReady() {
228
+ const [ready, setReady] = (0, import_react.useState)(false);
229
+ (0, import_react.useEffect)(() => {
230
+ const unsubscribe = onFlushComplete(() => {
231
+ setReady(true);
232
+ });
233
+ return unsubscribe;
234
+ }, []);
235
+ return ready;
236
+ }
237
+ function useIdleGate(key, priority, callback) {
238
+ const [ready, setReady] = (0, import_react.useState)(false);
239
+ const callbackRef = (0, import_react.useRef)(callback);
240
+ callbackRef.current = callback;
241
+ (0, import_react.useEffect)(() => {
242
+ const unregister = registerIdleTask(key, priority, async () => {
243
+ await callbackRef.current();
244
+ setReady(true);
245
+ });
246
+ return unregister;
247
+ }, [key, priority]);
248
+ return { ready };
249
+ }
250
+ function useIdleRegister() {
251
+ const unregisterRefs = (0, import_react.useRef)(/* @__PURE__ */ new Map());
252
+ (0, import_react.useEffect)(() => {
253
+ const refs = unregisterRefs.current;
254
+ return () => {
255
+ refs.forEach((unregister) => unregister());
256
+ refs.clear();
257
+ };
258
+ }, []);
259
+ return (0, import_react.useCallback)(
260
+ (key, priority, callback) => {
261
+ unregisterRefs.current.get(key)?.();
262
+ const unregister = registerIdleTask(key, priority, callback);
263
+ unregisterRefs.current.set(key, unregister);
264
+ },
265
+ []
266
+ );
267
+ }
268
+ //# sourceMappingURL=idle-scheduler.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/idle-scheduler.ts","../src/idle-scheduler/scheduler.ts","../src/idle-scheduler/hooks.ts"],"sourcesContent":["/**\n * @ai-matrx/kit/idle-scheduler — priority-aware deferred execution: register\n * work that must wait until the page is fully rendered AND the browser is\n * truly idle, then run it in priority order (1 first … 5 last).\n *\n * Idle detection chain: document load → paint (rAF, raced against a timeout so\n * hidden tabs still flush) → `scheduler.postTask({priority:'background'})` /\n * `requestIdleCallback` / MessageChannel (universal, incl. Safari).\n *\n * - Hooks: `useIdleTask` (fire-and-forget), `useIdleReady` (one re-render\n * false→true), `useIdleGate` (work + ready signal), `useIdleRegister`\n * (imperative/conditional).\n * - Direct API for non-React callers: `registerIdleTask`, `onFlushComplete`,\n * `whenPageIdle(signal?)`, `getSchedulerState`, `resetScheduler`.\n *\n * Scheduler state lives on `globalThis` under\n * `Symbol.for(\"ai-matrx.kit.idle-scheduler-state\")` so the ESM and CJS bundle\n * graphs share ONE pipeline — see the note in `idle-scheduler/scheduler.ts`.\n * SSR-safe: registering before a `window` exists queues without starting the\n * pipeline.\n */\nexport {\n registerIdleTask,\n onFlushComplete,\n whenPageIdle,\n getSchedulerState,\n resetScheduler,\n} from \"./idle-scheduler/scheduler\";\nexport type {\n IdlePriority,\n IdleRegistration,\n UnregisterFn,\n FlushState,\n} from \"./idle-scheduler/scheduler\";\nexport {\n useIdleTask,\n useIdleReady,\n useIdleGate,\n useIdleRegister,\n} from \"./idle-scheduler/hooks\";\n","/**\n * IdleScheduler — a priority-aware deferred execution system for browser apps.\n *\n * Architecture:\n * - Process-wide singleton (NOT React context) — registrations cause zero re-renders\n * - Components register lightweight callbacks with priority 1-5\n * - The scheduler waits for the browser to be truly idle after full page render\n * - Then flushes all registered callbacks in priority order\n *\n * Priority levels:\n * 1 = Highest (first of the \"last things\") — e.g., analytics init, critical measurements\n * 2 = High — e.g., prefetching next-page data, service worker registration\n * 3 = Normal — e.g., lazy-loading non-critical UI, initializing 3rd party widgets\n * 4 = Low — e.g., telemetry, background sync setup\n * 5 = Lowest (absolute last) — e.g., prewarming caches, speculative prefetch\n *\n * Cross-browser idle detection chain:\n * document.readyState === 'complete'\n * → requestAnimationFrame (past next paint)\n * → scheduler.postTask({ priority: 'background' }) [Chrome/Edge/Firefox 142+]\n * → requestIdleCallback [Chrome/Firefox, NOT Safari]\n * → MessageChannel postMessage [Universal — React's own trick]\n *\n * Ported from matrx-frontend `utils/idle-scheduler/idle-scheduler.ts`, with\n * TWO structural inversions, behavior otherwise verbatim:\n * - Scheduler state (queue, flush state, cleanups, listeners) lives on\n * `globalThis` under `Symbol.for(\"ai-matrx.kit.idle-scheduler-state\")`\n * instead of module-level variables. With the package built\n * `splitting: false` in dual ESM/CJS format this module is duplicated into\n * the root and `./idle-scheduler` bundles, and CJS/ESM each instantiate\n * their own module graph — module-level state would silently split the\n * flush pipeline from some registrants (the confirm-opener hazard). Never\n * \"clean this up\" into module locals.\n * - The `window.__idleSched()` diagnostics probe installs on first API use\n * instead of at module evaluation, keeping every entry point import-time\n * inert (the package standard). The probe itself is unchanged.\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type IdlePriority = 1 | 2 | 3 | 4 | 5;\n\nexport interface IdleRegistration {\n /** Unique key for deduplication and cancellation */\n key: string;\n /** 1 = highest (first to run), 5 = lowest (last to run) */\n priority: IdlePriority;\n /** The deferred work */\n callback: () => void | Promise<void>;\n}\n\nexport type UnregisterFn = () => void;\n\nexport type FlushState = \"idle\" | \"waiting\" | \"flushing\" | \"done\";\n\n/** Experimental Scheduler API (Chrome/Edge/Firefox 142+) — not yet in standard lib types. */\ninterface GlobalThisWithScheduler {\n scheduler?: {\n postTask: (callback: () => void, options?: { priority: string }) => Promise<void>;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Singleton state — on globalThis so every bundle graph shares ONE pipeline\n// ---------------------------------------------------------------------------\n\ninterface SchedulerState {\n queue: Map<string, IdleRegistration>;\n flushState: FlushState;\n cleanupFns: Array<() => void>;\n /** Listeners that want to know when flush completes (for useIdleReady) */\n flushListeners: Set<() => void>;\n}\n\nconst STATE_SLOT = Symbol.for(\"ai-matrx.kit.idle-scheduler-state\");\n\nfunction getState(): SchedulerState {\n const holder = globalThis as Record<symbol, SchedulerState | undefined>;\n let state = holder[STATE_SLOT];\n if (!state) {\n state = {\n queue: new Map(),\n flushState: \"idle\",\n cleanupFns: [],\n flushListeners: new Set(),\n };\n holder[STATE_SLOT] = state;\n\n // Diagnostics probe: lets a console / agent read the live scheduler state\n // (`window.__idleSched()`) — the wrapper-never-mounts class of bug is\n // invisible without it.\n if (typeof window !== \"undefined\") {\n (window as unknown as { __idleSched?: () => unknown }).__idleSched =\n getSchedulerState;\n }\n }\n return state;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Register a callback to run after the page is fully idle.\n *\n * - If the scheduler hasn't flushed yet: queues the callback.\n * - If the scheduler already flushed: runs the callback immediately\n * (through the same idle detection chain, so it still won't block).\n *\n * Returns an unregister function for cleanup.\n */\nexport function registerIdleTask(\n key: string,\n priority: IdlePriority,\n callback: () => void | Promise<void>,\n): UnregisterFn {\n const state = getState();\n\n // If we already flushed, schedule this one immediately (still deferred)\n if (state.flushState === \"done\") {\n scheduleImmediate(callback);\n return () => {};\n }\n\n state.queue.set(key, { key, priority, callback });\n\n // Ensure the flush pipeline is started\n if (state.flushState === \"idle\") {\n startFlushPipeline(state);\n }\n\n return () => {\n state.queue.delete(key);\n };\n}\n\n/**\n * Subscribe to the flush-complete event.\n * Useful for components that just need a \"ready\" signal without registering work.\n */\nexport function onFlushComplete(listener: () => void): UnregisterFn {\n const state = getState();\n\n if (state.flushState === \"done\") {\n // Already flushed — notify immediately (but async to avoid sync side effects)\n queueMicrotask(listener);\n return () => {};\n }\n\n state.flushListeners.add(listener);\n\n // A \"tell me when idle\" subscriber needs the pipeline RUNNING. If only\n // registerIdleTask started it, then on pages where nothing registered an\n // idle task the flush would never run and every ready-gated mount would\n // stay dormant forever. Subscribing must start the pipeline too.\n if (state.flushState === \"idle\") {\n startFlushPipeline(state);\n }\n\n return () => {\n state.flushListeners.delete(listener);\n };\n}\n\n/**\n * Resolve after the initial page-load idle flush, or earlier when aborted.\n * Non-React startup services use this instead of recreating the scheduler's\n * load → paint → browser-idle detection chain.\n *\n * @returns false when the caller aborted before idle; true otherwise.\n */\nexport function whenPageIdle(signal?: AbortSignal): Promise<boolean> {\n if (signal?.aborted) return Promise.resolve(false);\n\n return new Promise((resolve) => {\n let settled = false;\n let unsubscribe: UnregisterFn = () => {};\n\n const finish = (ready: boolean) => {\n if (settled) return;\n settled = true;\n unsubscribe();\n signal?.removeEventListener(\"abort\", onAbort);\n resolve(ready);\n };\n const onAbort = () => finish(false);\n\n unsubscribe = onFlushComplete(() => finish(true));\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/**\n * Get current state — useful for debugging or conditional logic.\n */\nexport function getSchedulerState(): {\n flushState: FlushState;\n pendingCount: number;\n pendingKeys: string[];\n} {\n const state = getState();\n return {\n flushState: state.flushState,\n pendingCount: state.queue.size,\n pendingKeys: Array.from(state.queue.keys()),\n };\n}\n\n/**\n * Reset the scheduler — primarily for testing or hot-reload scenarios.\n */\nexport function resetScheduler(): void {\n const state = getState();\n state.cleanupFns.forEach((fn) => fn());\n state.cleanupFns = [];\n state.queue.clear();\n state.flushListeners.clear();\n state.flushState = \"idle\";\n}\n\n// ---------------------------------------------------------------------------\n// Flush pipeline\n// ---------------------------------------------------------------------------\n\nfunction startFlushPipeline(state: SchedulerState): void {\n if (typeof window === \"undefined\") return; // SSR guard\n\n state.flushState = \"waiting\";\n\n const waitForLoad = () => {\n if (document.readyState === \"complete\") {\n waitForPaint();\n } else {\n const onLoad = () => waitForPaint();\n window.addEventListener(\"load\", onLoad, { once: true });\n state.cleanupFns.push(() => window.removeEventListener(\"load\", onLoad));\n }\n };\n\n const waitForPaint = () => {\n // requestAnimationFrame NEVER fires while the tab is hidden (background\n // tab, restored session, headless browser) — waiting on it alone hangs the\n // whole pipeline forever in that state, so every ready-gated mount stays\n // dormant. Paint alignment is an optimization, not a correctness\n // requirement: race the rAF against a timeout so a hidden tab still\n // flushes.\n let advanced = false;\n const advance = () => {\n if (advanced) return;\n advanced = true;\n waitForIdle();\n };\n const rafId = requestAnimationFrame(advance);\n const timeoutId = setTimeout(\n advance,\n document.visibilityState === \"hidden\" ? 250 : 1_500,\n );\n state.cleanupFns.push(() => {\n cancelAnimationFrame(rafId);\n clearTimeout(timeoutId);\n });\n };\n\n const waitForIdle = () => {\n // Tier 1: scheduler.postTask with background priority (Chrome/Edge/Firefox 142+)\n const schedulerGlobal = (globalThis as GlobalThisWithScheduler).scheduler;\n if (schedulerGlobal && \"postTask\" in schedulerGlobal) {\n schedulerGlobal\n .postTask(() => void flush(state), { priority: \"background\" })\n .catch(() => {});\n return;\n }\n\n // Tier 2: requestIdleCallback (Chrome, Firefox — NOT Safari stable)\n if (\"requestIdleCallback\" in window) {\n const idleId = requestIdleCallback(() => void flush(state));\n state.cleanupFns.push(() => cancelIdleCallback(idleId));\n return;\n }\n\n // Tier 3: MessageChannel — universal, including Safari + iOS Safari\n // This is what React's scheduler uses internally.\n const channel = new MessageChannel();\n channel.port1.onmessage = () => void flush(state);\n channel.port2.postMessage(undefined);\n };\n\n waitForLoad();\n}\n\nasync function flush(state: SchedulerState): Promise<void> {\n if (state.flushState === \"done\" || state.flushState === \"flushing\") return;\n state.flushState = \"flushing\";\n\n // Sort by priority (1 first, 5 last), stable sort preserving insertion order within priority\n const sorted = Array.from(state.queue.values()).sort(\n (a, b) => a.priority - b.priority,\n );\n\n // Clear the queue before executing (so late registrations during flush\n // are treated as \"post-flush\" and get scheduled immediately)\n state.queue.clear();\n\n for (const task of sorted) {\n try {\n await task.callback();\n } catch (err) {\n console.error(`[IdleScheduler] Task \"${task.key}\" failed:`, err);\n }\n }\n\n state.flushState = \"done\";\n\n // DEFECT FIX vs the original (see CHANGELOG 0.4.0): a task registered WHILE\n // the flush loop was running (flushState === \"flushing\") landed back in the\n // queue — which nothing ever drained again, so the task silently never ran.\n // The comment above promises such registrations are \"treated as post-flush\n // and get scheduled immediately\"; make that true.\n if (state.queue.size > 0) {\n const late = Array.from(state.queue.values()).sort(\n (a, b) => a.priority - b.priority,\n );\n state.queue.clear();\n for (const task of late) scheduleImmediate(task.callback);\n }\n\n // Notify all listeners\n state.flushListeners.forEach((listener) => {\n try {\n listener();\n } catch (err) {\n console.error(\"[IdleScheduler] Flush listener failed:\", err);\n }\n });\n state.flushListeners.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Schedule a single callback through the idle chain (for post-flush registrations) */\nfunction scheduleImmediate(callback: () => void | Promise<void>): void {\n requestAnimationFrame(() => {\n const schedulerGlobal = (globalThis as GlobalThisWithScheduler).scheduler;\n if (schedulerGlobal && \"postTask\" in schedulerGlobal) {\n schedulerGlobal\n .postTask(() => void callback(), { priority: \"background\" })\n .catch(() => {});\n return;\n }\n if (\"requestIdleCallback\" in window) {\n requestIdleCallback(() => void callback());\n return;\n }\n const channel = new MessageChannel();\n channel.port1.onmessage = () => void callback();\n channel.port2.postMessage(undefined);\n });\n}\n","/**\n * React hooks for the IdleScheduler.\n *\n * These are intentionally thin — they just wire up registration/cleanup\n * to React's lifecycle. No state, no context, no re-renders on registration.\n *\n * Three hooks for three use cases:\n *\n * 1. useIdleTask(key, priority, callback)\n * → \"Run this callback when idle. I don't need to know when.\"\n * → Fire-and-forget. Zero re-renders.\n *\n * 2. useIdleReady()\n * → \"Just tell me when idle flush is done so I can wake up.\"\n * → Returns a boolean. One re-render: false → true.\n *\n * 3. useIdleGate(key, priority, callback)\n * → \"Run this callback when idle AND tell me when it's done.\"\n * → Returns { ready: boolean }. Combines both patterns.\n *\n * Plus useIdleRegister() for imperative/conditional registration.\n *\n * Ported verbatim from matrx-frontend `utils/idle-scheduler/hooks.ts`.\n */\n\n\"use client\";\n\nimport { useEffect, useRef, useState, useCallback } from \"react\";\nimport {\n registerIdleTask,\n onFlushComplete,\n type IdlePriority,\n} from \"./scheduler\";\n\n// ---------------------------------------------------------------------------\n// useIdleTask — fire-and-forget deferred work\n// ---------------------------------------------------------------------------\n\n/**\n * Register a callback to execute after page idle. Zero re-renders.\n *\n * @param key Unique identifier (for deduplication/cancellation)\n * @param priority 1 (first of last) through 5 (absolute last)\n * @param callback The deferred work\n *\n * @example\n * ```tsx\n * useIdleTask('analytics-init', 3, () => {\n * initializeAnalytics();\n * });\n * ```\n */\nexport function useIdleTask(\n key: string,\n priority: IdlePriority,\n callback: () => void | Promise<void>,\n): void {\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n useEffect(() => {\n const unregister = registerIdleTask(key, priority, () => {\n return callbackRef.current();\n });\n return unregister;\n }, [key, priority]);\n}\n\n// ---------------------------------------------------------------------------\n// useIdleReady — \"am I allowed to wake up yet?\"\n// ---------------------------------------------------------------------------\n\n/**\n * Returns `true` once the idle flush has completed.\n * Causes exactly one re-render (false → true). No work is registered.\n *\n * Use this when a component wants to stay dormant (show nothing, or a skeleton)\n * until the page is fully settled, then \"turn on.\"\n *\n * @example\n * ```tsx\n * function HeavyWidget() {\n * const ready = useIdleReady();\n * if (!ready) return null; // or a skeleton\n * return <ExpensiveComponent />;\n * }\n * ```\n */\nexport function useIdleReady(): boolean {\n const [ready, setReady] = useState(false);\n\n useEffect(() => {\n const unsubscribe = onFlushComplete(() => {\n setReady(true);\n });\n return unsubscribe;\n }, []);\n\n return ready;\n}\n\n// ---------------------------------------------------------------------------\n// useIdleGate — register work AND get a ready signal\n// ---------------------------------------------------------------------------\n\n/**\n * Register deferred work and get a `ready` signal when it completes.\n *\n * This is the \"full package\" — your component stays dormant, the scheduler\n * runs your callback at the right time, and then you get notified to\n * update your UI.\n *\n * @example\n * ```tsx\n * function PrefetchedSection() {\n * const { ready } = useIdleGate('prefetch-recommendations', 2, async () => {\n * await prefetchRecommendations();\n * });\n *\n * if (!ready) return <Skeleton />;\n * return <Recommendations />;\n * }\n * ```\n */\nexport function useIdleGate(\n key: string,\n priority: IdlePriority,\n callback: () => void | Promise<void>,\n): { ready: boolean } {\n const [ready, setReady] = useState(false);\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n useEffect(() => {\n const unregister = registerIdleTask(key, priority, async () => {\n await callbackRef.current();\n setReady(true);\n });\n return unregister;\n }, [key, priority]);\n\n return { ready };\n}\n\n// ---------------------------------------------------------------------------\n// useIdleRegister — imperative registration (for dynamic/conditional work)\n// ---------------------------------------------------------------------------\n\n/**\n * Returns a `register` function you can call imperatively.\n * Useful when the deferred work depends on runtime conditions.\n *\n * @example\n * ```tsx\n * function SearchResults({ query }) {\n * const scheduleIdle = useIdleRegister();\n *\n * useEffect(() => {\n * if (query) {\n * scheduleIdle(`prefetch-${query}`, 4, () => {\n * prefetchRelatedResults(query);\n * });\n * }\n * }, [query, scheduleIdle]);\n * }\n * ```\n */\nexport function useIdleRegister(): (\n key: string,\n priority: IdlePriority,\n callback: () => void | Promise<void>,\n) => void {\n const unregisterRefs = useRef<Map<string, () => void>>(new Map());\n\n // Cleanup all registrations on unmount\n useEffect(() => {\n const refs = unregisterRefs.current;\n return () => {\n refs.forEach((unregister) => unregister());\n refs.clear();\n };\n }, []);\n\n return useCallback(\n (\n key: string,\n priority: IdlePriority,\n callback: () => void | Promise<void>,\n ) => {\n // Cancel previous registration with same key\n unregisterRefs.current.get(key)?.();\n\n const unregister = registerIdleTask(key, priority, callback);\n unregisterRefs.current.set(key, unregister);\n },\n [],\n );\n}\n"],"mappings":"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","names":[]}