inspector-ng 0.0.7 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,9 +11,11 @@ Inspired by [ibelick](https://github.com/ibelick)'s original design.
11
11
  ## Installation
12
12
 
13
13
  ```bash
14
- npm install inspector-ng
14
+ npm install inspector-ng@0.0.8 @ngrx/store@^17.2.0
15
15
  ```
16
16
 
17
+ For a complete new-project walkthrough with copy-paste Store, Router, Redux DevTools, state, local-package, and troubleshooting examples, see the [setup guide](https://github.com/destx0/inspector/blob/main/SETUP_GUIDE.md).
18
+
17
19
  ## Getting Started
18
20
 
19
21
  ### Step 1: Import the component
@@ -58,43 +60,25 @@ That's it. Press **`M`** in your browser to open the inspector toolbar. No furth
58
60
 
59
61
  ### Developer checkpoints
60
62
 
61
- Checkpoints save the current Angular Router URL plus state you explicitly register. They do **not** record or replay HTTP requests.
63
+ Add `@ngrx/store` and provide a single root Store before `provideInspectorCheckpoints()`:
62
64
 
63
65
  ```ts
64
66
  import { ApplicationConfig } from '@angular/core';
65
- import { BehaviorSubject } from 'rxjs';
66
- import {
67
- createBehaviorSubjectCheckpointAdapter,
68
- InspectorCheckpointRegistry,
69
- provideInspectorCheckpoints,
70
- } from 'inspector-ng';
67
+ import { provideRouter } from '@angular/router';
68
+ import { provideStore } from '@ngrx/store';
69
+ import { provideInspectorCheckpoints } from 'inspector-ng';
70
+ import { routes } from './app.routes';
71
71
 
72
72
  export const appConfig: ApplicationConfig = {
73
- providers: [provideInspectorCheckpoints()],
73
+ providers: [provideRouter(routes), provideStore(), provideInspectorCheckpoints()],
74
74
  };
75
75
  ```
76
76
 
77
- Register serializable state from an application service or component:
77
+ Use the compact toolbar button to save the current JSON-serializable NgRx root state immediately. Use `Ctrl/Cmd+Shift+P` to open the fuzzy checkpoint finder. `F2` renames the selected record and `Delete` opens inline confirmation.
78
78
 
79
- ```ts
80
- const application = new BehaviorSubject({ customerName: '', amount: 0 });
81
- const unregister = checkpointRegistry.register(
82
- createBehaviorSubjectCheckpointAdapter('workflow:application', application),
83
- );
84
- ```
79
+ Records are stored per origin in IndexedDB database `inspector-ng`, object store `checkpoints`. This needs no browser permission prompt and does not map to a visible or fixed OS path. Nothing is evicted automatically. Existing `inspector-checkpoints-v1` localStorage records are deliberately ignored.
85
80
 
86
- Open the inspector and use the checkpoint button to save, restore, rename, or delete snapshots. Checkpoints use `localStorage`; when the browser quota is reached, the oldest checkpoint is removed to make room. Do not register sensitive values.
87
-
88
- For Native Federation, the shell owns `provideInspectorCheckpoints()`. Remotes receive the shell's `InspectorCheckpointRegistry` and register namespaced adapters such as `workflow:application`. The shell should register a remote loader for each scope so remotes are loaded before state is restored:
89
-
90
- ```ts
91
- checkpointRegistry.registerRemoteScope('workflow', async () => {
92
- const remote = await loadRemoteModule('workflow', './CheckpointAdapters');
93
- remote.registerInspectorCheckpointAdapters(checkpointRegistry);
94
- });
95
- ```
96
-
97
- Repeated remote adapter registration is safe, so a bridge may run before every restore. Share `inspector-ng` as a Native Federation singleton in both shell and remotes.
81
+ A checkpoint contains the root Store value and current route. Restore dispatches `[Inspector Checkpoints] Restore`, then navigates through Angular Router to the saved route, so NgRx Store DevTools records the state change normally. It does not restore action history, component-local state, HTTP activity, or backend state. Native Redux DevTools Import/Export files remain separate and cannot be searched from the Inspector command bar.
98
82
 
99
83
  ### Inputs
100
84
 
@@ -129,6 +113,9 @@ Repeated remote adapter registration is safe, so a bridge may run before every r
129
113
  | `Ctrl/Cmd + Z` | Undo last guide change |
130
114
  | `Ctrl/Cmd + Shift + Z` | Redo guide change |
131
115
  | `Backspace` / `Delete` | Delete the selected guide |
116
+ | `Ctrl/Cmd + Shift + P` | Search and restore checkpoints when configured |
117
+
118
+ Tool shortcuts never run while the Inspector is disabled or while focus is inside a form control, form, editable region, or textbox-like editor. Modified application/browser shortcuts such as `Ctrl/Cmd+S` are not intercepted. `Ctrl/Cmd+Shift+P` is the only intentional exception and remains available from inputs and with the Inspector rail disabled.
132
119
 
133
120
  ## Features
134
121
 
@@ -148,6 +135,8 @@ Repeated remote adapter registration is safe, so a bridge may run before every r
148
135
  |---|---|
149
136
  | `@angular/core` | `^17.3.0` |
150
137
  | `@angular/common` | `^17.3.0` |
138
+ | `@angular/router` | `^17.3.0` |
139
+ | `@ngrx/store` | `^17.2.0` (peer dependency used only for checkpoints) |
151
140
 
152
141
  Built as a standalone component with signal-based reactivity and `OnPush` change detection.
153
142
 
@@ -0,0 +1,50 @@
1
+ export function fuzzyCheckpoints(checkpoints, query) {
2
+ const normalizedQuery = normalize(query.trim());
3
+ if (!normalizedQuery)
4
+ return [...checkpoints].sort(newestFirst);
5
+ return checkpoints
6
+ .map((checkpoint) => {
7
+ const score = fuzzyScore(checkpoint.name, normalizedQuery);
8
+ return score === null ? null : { checkpoint, score };
9
+ })
10
+ .filter((item) => item !== null)
11
+ .sort((a, b) => b.score - a.score || newestFirst(a.checkpoint, b.checkpoint))
12
+ .map(({ checkpoint }) => checkpoint);
13
+ }
14
+ export function fuzzyScore(value, normalizedQuery) {
15
+ const candidate = normalize(value);
16
+ if (candidate === normalizedQuery)
17
+ return 10_000;
18
+ if (candidate.startsWith(normalizedQuery))
19
+ return 8_000 - candidate.length;
20
+ const substringIndex = candidate.indexOf(normalizedQuery);
21
+ if (substringIndex >= 0)
22
+ return 6_000 - substringIndex * 10 - candidate.length;
23
+ let queryIndex = 0;
24
+ let firstIndex = -1;
25
+ let lastIndex = -1;
26
+ let gapPenalty = 0;
27
+ for (let index = 0; index < candidate.length && queryIndex < normalizedQuery.length; index += 1) {
28
+ if (candidate[index] !== normalizedQuery[queryIndex])
29
+ continue;
30
+ if (firstIndex < 0)
31
+ firstIndex = index;
32
+ if (lastIndex >= 0)
33
+ gapPenalty += index - lastIndex - 1;
34
+ lastIndex = index;
35
+ queryIndex += 1;
36
+ }
37
+ if (queryIndex !== normalizedQuery.length)
38
+ return null;
39
+ return 4_000 - firstIndex * 10 - gapPenalty * 20 - candidate.length;
40
+ }
41
+ function normalize(value) {
42
+ return value
43
+ .normalize('NFKD')
44
+ .replace(/[\u0300-\u036f]/g, '')
45
+ .toLocaleLowerCase();
46
+ }
47
+ function newestFirst(a, b) {
48
+ return b.createdAt.localeCompare(a.createdAt) || b.id.localeCompare(a.id);
49
+ }
50
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2twb2ludC1zZWFyY2guanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9pbnNwZWN0b3Itbmcvc3JjL2xpYi9jaGVja3BvaW50LXNlYXJjaC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFPQSxNQUFNLFVBQVUsZ0JBQWdCLENBQzlCLFdBQXdDLEVBQ3hDLEtBQWE7SUFFYixNQUFNLGVBQWUsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDaEQsSUFBSSxDQUFDLGVBQWU7UUFBRSxPQUFPLENBQUMsR0FBRyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFFaEUsT0FBTyxXQUFXO1NBQ2YsR0FBRyxDQUFDLENBQUMsVUFBVSxFQUEyQixFQUFFO1FBQzNDLE1BQU0sS0FBSyxHQUFHLFVBQVUsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBQzNELE9BQU8sS0FBSyxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsQ0FBQztJQUN2RCxDQUFDLENBQUM7U0FDRCxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQTRCLEVBQUUsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDO1NBQ3pELElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLEtBQUssSUFBSSxXQUFXLENBQUMsQ0FBQyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUM7U0FDNUUsR0FBRyxDQUFDLENBQUMsRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLENBQUM7QUFDekMsQ0FBQztBQUVELE1BQU0sVUFBVSxVQUFVLENBQUMsS0FBYSxFQUFFLGVBQXVCO0lBQy9ELE1BQU0sU0FBUyxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNuQyxJQUFJLFNBQVMsS0FBSyxlQUFlO1FBQUUsT0FBTyxNQUFNLENBQUM7SUFDakQsSUFBSSxTQUFTLENBQUMsVUFBVSxDQUFDLGVBQWUsQ0FBQztRQUFFLE9BQU8sS0FBSyxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUM7SUFFM0UsTUFBTSxjQUFjLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUMxRCxJQUFJLGNBQWMsSUFBSSxDQUFDO1FBQUUsT0FBTyxLQUFLLEdBQUcsY0FBYyxHQUFHLEVBQUUsR0FBRyxTQUFTLENBQUMsTUFBTSxDQUFDO0lBRS9FLElBQUksVUFBVSxHQUFHLENBQUMsQ0FBQztJQUNuQixJQUFJLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNwQixJQUFJLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNuQixJQUFJLFVBQVUsR0FBRyxDQUFDLENBQUM7SUFDbkIsS0FBSyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUUsS0FBSyxHQUFHLFNBQVMsQ0FBQyxNQUFNLElBQUksVUFBVSxHQUFHLGVBQWUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ2hHLElBQUksU0FBUyxDQUFDLEtBQUssQ0FBQyxLQUFLLGVBQWUsQ0FBQyxVQUFVLENBQUM7WUFBRSxTQUFTO1FBQy9ELElBQUksVUFBVSxHQUFHLENBQUM7WUFBRSxVQUFVLEdBQUcsS0FBSyxDQUFDO1FBQ3ZDLElBQUksU0FBUyxJQUFJLENBQUM7WUFBRSxVQUFVLElBQUksS0FBSyxHQUFHLFNBQVMsR0FBRyxDQUFDLENBQUM7UUFDeEQsU0FBUyxHQUFHLEtBQUssQ0FBQztRQUNsQixVQUFVLElBQUksQ0FBQyxDQUFDO0lBQ2xCLENBQUM7SUFDRCxJQUFJLFVBQVUsS0FBSyxlQUFlLENBQUMsTUFBTTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3ZELE9BQU8sS0FBSyxHQUFHLFVBQVUsR0FBRyxFQUFFLEdBQUcsVUFBVSxHQUFHLEVBQUUsR0FBRyxTQUFTLENBQUMsTUFBTSxDQUFDO0FBQ3RFLENBQUM7QUFFRCxTQUFTLFNBQVMsQ0FBQyxLQUFhO0lBQzlCLE9BQU8sS0FBSztTQUNULFNBQVMsQ0FBQyxNQUFNLENBQUM7U0FDakIsT0FBTyxDQUFDLGtCQUFrQixFQUFFLEVBQUUsQ0FBQztTQUMvQixpQkFBaUIsRUFBRSxDQUFDO0FBQ3pCLENBQUM7QUFFRCxTQUFTLFdBQVcsQ0FBQyxDQUE0QixFQUFFLENBQTRCO0lBQzdFLE9BQU8sQ0FBQyxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUM1RSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5zcGVjdG9yQ2hlY2twb2ludFJlY29yZCB9IGZyb20gJy4vY2hlY2twb2ludHMnO1xuXG5pbnRlcmZhY2UgUmFua2VkQ2hlY2twb2ludCB7XG4gIGNoZWNrcG9pbnQ6IEluc3BlY3RvckNoZWNrcG9pbnRSZWNvcmQ7XG4gIHNjb3JlOiBudW1iZXI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmdXp6eUNoZWNrcG9pbnRzKFxuICBjaGVja3BvaW50czogSW5zcGVjdG9yQ2hlY2twb2ludFJlY29yZFtdLFxuICBxdWVyeTogc3RyaW5nLFxuKTogSW5zcGVjdG9yQ2hlY2twb2ludFJlY29yZFtdIHtcbiAgY29uc3Qgbm9ybWFsaXplZFF1ZXJ5ID0gbm9ybWFsaXplKHF1ZXJ5LnRyaW0oKSk7XG4gIGlmICghbm9ybWFsaXplZFF1ZXJ5KSByZXR1cm4gWy4uLmNoZWNrcG9pbnRzXS5zb3J0KG5ld2VzdEZpcnN0KTtcblxuICByZXR1cm4gY2hlY2twb2ludHNcbiAgICAubWFwKChjaGVja3BvaW50KTogUmFua2VkQ2hlY2twb2ludCB8IG51bGwgPT4ge1xuICAgICAgY29uc3Qgc2NvcmUgPSBmdXp6eVNjb3JlKGNoZWNrcG9pbnQubmFtZSwgbm9ybWFsaXplZFF1ZXJ5KTtcbiAgICAgIHJldHVybiBzY29yZSA9PT0gbnVsbCA/IG51bGwgOiB7IGNoZWNrcG9pbnQsIHNjb3JlIH07XG4gICAgfSlcbiAgICAuZmlsdGVyKChpdGVtKTogaXRlbSBpcyBSYW5rZWRDaGVja3BvaW50ID0+IGl0ZW0gIT09IG51bGwpXG4gICAgLnNvcnQoKGEsIGIpID0+IGIuc2NvcmUgLSBhLnNjb3JlIHx8IG5ld2VzdEZpcnN0KGEuY2hlY2twb2ludCwgYi5jaGVja3BvaW50KSlcbiAgICAubWFwKCh7IGNoZWNrcG9pbnQgfSkgPT4gY2hlY2twb2ludCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmdXp6eVNjb3JlKHZhbHVlOiBzdHJpbmcsIG5vcm1hbGl6ZWRRdWVyeTogc3RyaW5nKTogbnVtYmVyIHwgbnVsbCB7XG4gIGNvbnN0IGNhbmRpZGF0ZSA9IG5vcm1hbGl6ZSh2YWx1ZSk7XG4gIGlmIChjYW5kaWRhdGUgPT09IG5vcm1hbGl6ZWRRdWVyeSkgcmV0dXJuIDEwXzAwMDtcbiAgaWYgKGNhbmRpZGF0ZS5zdGFydHNXaXRoKG5vcm1hbGl6ZWRRdWVyeSkpIHJldHVybiA4XzAwMCAtIGNhbmRpZGF0ZS5sZW5ndGg7XG5cbiAgY29uc3Qgc3Vic3RyaW5nSW5kZXggPSBjYW5kaWRhdGUuaW5kZXhPZihub3JtYWxpemVkUXVlcnkpO1xuICBpZiAoc3Vic3RyaW5nSW5kZXggPj0gMCkgcmV0dXJuIDZfMDAwIC0gc3Vic3RyaW5nSW5kZXggKiAxMCAtIGNhbmRpZGF0ZS5sZW5ndGg7XG5cbiAgbGV0IHF1ZXJ5SW5kZXggPSAwO1xuICBsZXQgZmlyc3RJbmRleCA9IC0xO1xuICBsZXQgbGFzdEluZGV4ID0gLTE7XG4gIGxldCBnYXBQZW5hbHR5ID0gMDtcbiAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IGNhbmRpZGF0ZS5sZW5ndGggJiYgcXVlcnlJbmRleCA8IG5vcm1hbGl6ZWRRdWVyeS5sZW5ndGg7IGluZGV4ICs9IDEpIHtcbiAgICBpZiAoY2FuZGlkYXRlW2luZGV4XSAhPT0gbm9ybWFsaXplZFF1ZXJ5W3F1ZXJ5SW5kZXhdKSBjb250aW51ZTtcbiAgICBpZiAoZmlyc3RJbmRleCA8IDApIGZpcnN0SW5kZXggPSBpbmRleDtcbiAgICBpZiAobGFzdEluZGV4ID49IDApIGdhcFBlbmFsdHkgKz0gaW5kZXggLSBsYXN0SW5kZXggLSAxO1xuICAgIGxhc3RJbmRleCA9IGluZGV4O1xuICAgIHF1ZXJ5SW5kZXggKz0gMTtcbiAgfVxuICBpZiAocXVlcnlJbmRleCAhPT0gbm9ybWFsaXplZFF1ZXJ5Lmxlbmd0aCkgcmV0dXJuIG51bGw7XG4gIHJldHVybiA0XzAwMCAtIGZpcnN0SW5kZXggKiAxMCAtIGdhcFBlbmFsdHkgKiAyMCAtIGNhbmRpZGF0ZS5sZW5ndGg7XG59XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZSh2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIHZhbHVlXG4gICAgLm5vcm1hbGl6ZSgnTkZLRCcpXG4gICAgLnJlcGxhY2UoL1tcXHUwMzAwLVxcdTAzNmZdL2csICcnKVxuICAgIC50b0xvY2FsZUxvd2VyQ2FzZSgpO1xufVxuXG5mdW5jdGlvbiBuZXdlc3RGaXJzdChhOiBJbnNwZWN0b3JDaGVja3BvaW50UmVjb3JkLCBiOiBJbnNwZWN0b3JDaGVja3BvaW50UmVjb3JkKTogbnVtYmVyIHtcbiAgcmV0dXJuIGIuY3JlYXRlZEF0LmxvY2FsZUNvbXBhcmUoYS5jcmVhdGVkQXQpIHx8IGIuaWQubG9jYWxlQ29tcGFyZShhLmlkKTtcbn1cbiJdfQ==