@invisibleloop/pulse 0.1.39 → 0.2.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.
@@ -25,11 +25,12 @@ jobs:
25
25
 
26
26
  - run: npm test
27
27
 
28
- - name: Bump patch version if already published, then publish
28
+ - name: Bump version from conventional commits, then publish
29
29
  env:
30
30
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
31
31
  run: |
32
- VERSION=$(node -p "require('./package.json').version")
32
+ VERSION=$(node scripts/release-version.js)
33
+ # Fallback: if this exact version is somehow already on npm, bump patch
33
34
  while npm view @invisibleloop/pulse@$VERSION version 2>/dev/null | grep -q .; do
34
35
  VERSION=$(node -e "const [a,b,c]='$VERSION'.split('.').map(Number);console.log(a+'.'+b+'.'+(c+1))")
35
36
  done
package/CLAUDE.md CHANGED
@@ -114,7 +114,17 @@ export const mySpec = {
114
114
  // Streaming SSR — split view into shell (instant) + deferred segments
115
115
  stream: {
116
116
  shell: ['header', 'nav'],
117
- deferred: ['feed']
117
+ deferred: ['feed'],
118
+
119
+ // Optional: scope each segment to only the server fetchers it needs.
120
+ // Shell sends as soon as its own fetchers resolve — deferred-only fetchers
121
+ // never block the shell. Each deferred segment streams independently.
122
+ // Omit scope (or omit a segment from scope) to give it all server state.
123
+ scope: {
124
+ header: ['user'], // 'user' fetcher resolves → shell writes
125
+ nav: ['user'],
126
+ feed: ['posts', 'ads'], // 'posts' + 'ads' fetchers resolve → feed writes
127
+ }
118
128
  }
119
129
  }
120
130
 
@@ -138,6 +148,16 @@ Pulse binds to DOM attributes — no JSX, no templates.
138
148
  <button data-dialog-close>Cancel</button> <!-- closes nearest ancestor <dialog> -->
139
149
  ```
140
150
 
151
+ **List keys — use `data-key` on repeated elements** to enable key-based DOM reconciliation. When all element children of a container carry `data-key`, the runtime matches nodes by key instead of position — inserts, removals, and reorders become O(1) rather than O(n) patches, and existing DOM nodes (inputs, images) are preserved correctly:
152
+
153
+ ```html
154
+ <ul>
155
+ ${items.map(item => `<li data-key="${item.id}">${item.name}</li>`).join('')}
156
+ </ul>
157
+ ```
158
+
159
+ All sibling elements in the container must have `data-key` to activate key mode — mixed keyed/unkeyed siblings fall back to position-based matching.
160
+
141
161
  **Modal pattern — never use `state.modalOpen`.** Always render the `<dialog>` in the DOM unconditionally and use `data-dialog-open` to show it. ESC key, backdrop click, and `<form method="dialog">` all close it natively with no spec state.
142
162
 
143
163
  **Important:** Do not use `data-event` on text inputs to mirror their value into state. The `innerHTML` replacement on every keystroke destroys focus. Instead, use uncontrolled inputs and capture `FormData` in `action.onStart` before `validate` runs.
@@ -0,0 +1,188 @@
1
+ {
2
+ "timestamp": "2026-03-27T09:20:25.195Z",
3
+ "node": "v22.19.0",
4
+ "suites": [
5
+ {
6
+ "label": "simple",
7
+ "path": "/bench/simple",
8
+ "iterations": 100,
9
+ "ttfb": {
10
+ "mean": 0.18965339000000087,
11
+ "p50": 0.17383399999999938,
12
+ "p95": 0.29887500000000955,
13
+ "p99": 0.3626250000000084,
14
+ "min": 0.14820799999998258,
15
+ "max": 0.3626250000000084
16
+ },
17
+ "total": {
18
+ "mean": 0.21540463999999956,
19
+ "p50": 0.19762500000001637,
20
+ "p95": 0.32587499999999636,
21
+ "p99": 0.40537499999999227,
22
+ "min": 0.16808299999999576,
23
+ "max": 0.40537499999999227
24
+ },
25
+ "bodyBytes": 1054,
26
+ "serverData": null,
27
+ "serverRender": null
28
+ },
29
+ {
30
+ "label": "data-1",
31
+ "path": "/bench/data-1",
32
+ "iterations": 100,
33
+ "ttfb": {
34
+ "mean": 0.7174741700000027,
35
+ "p50": 0.6867910000000848,
36
+ "p95": 1.1546250000001237,
37
+ "p99": 1.5141250000001492,
38
+ "min": 0.26679200000012315,
39
+ "max": 1.5141250000001492
40
+ },
41
+ "total": {
42
+ "mean": 22.057245399999985,
43
+ "p50": 22.128749999999854,
44
+ "p95": 22.988791999999876,
45
+ "p99": 23.292291999999975,
46
+ "min": 20.543083000000024,
47
+ "max": 23.292291999999975
48
+ },
49
+ "bodyBytes": 4384,
50
+ "serverData": null,
51
+ "serverRender": null
52
+ },
53
+ {
54
+ "label": "data-3",
55
+ "path": "/bench/data-3",
56
+ "iterations": 100,
57
+ "ttfb": {
58
+ "mean": 0.7575587300000006,
59
+ "p50": 0.7104169999997794,
60
+ "p95": 1.4852919999998448,
61
+ "p99": 1.7593329999999696,
62
+ "min": 0.2626669999999649,
63
+ "max": 1.7593329999999696
64
+ },
65
+ "total": {
66
+ "mean": 31.95738079999998,
67
+ "p50": 32.02441699999963,
68
+ "p95": 32.793916999999965,
69
+ "p99": 33.06345800000008,
70
+ "min": 30.259124999999585,
71
+ "max": 33.06345800000008
72
+ },
73
+ "bodyBytes": 1246,
74
+ "serverData": null,
75
+ "serverRender": null
76
+ },
77
+ {
78
+ "label": "cached",
79
+ "path": "/bench/cached",
80
+ "iterations": 100,
81
+ "ttfb": {
82
+ "mean": 0.1528695300000345,
83
+ "p50": 0.13799999999991996,
84
+ "p95": 0.2255829999994603,
85
+ "p99": 0.48387499999989814,
86
+ "min": 0.09737500000028376,
87
+ "max": 0.48387499999989814
88
+ },
89
+ "total": {
90
+ "mean": 0.16491832000000614,
91
+ "p50": 0.14895900000010442,
92
+ "p95": 0.2435829999994894,
93
+ "p99": 0.49779099999977916,
94
+ "min": 0.10537500000009459,
95
+ "max": 0.49779099999977916
96
+ },
97
+ "bodyBytes": 988,
98
+ "serverData": null,
99
+ "serverRender": null
100
+ },
101
+ {
102
+ "label": "nav/simple",
103
+ "path": "/bench/simple",
104
+ "iterations": 100,
105
+ "ttfb": {
106
+ "mean": 0.13343495999998595,
107
+ "p50": 0.1262909999995827,
108
+ "p95": 0.19287500000064028,
109
+ "p99": 0.423333000000639,
110
+ "min": 0.08924999999999272,
111
+ "max": 0.423333000000639
112
+ },
113
+ "total": {
114
+ "mean": 0.14239336000002367,
115
+ "p50": 0.13475000000016735,
116
+ "p95": 0.20391700000072888,
117
+ "p99": 0.4311250000000655,
118
+ "min": 0.09600000000045839,
119
+ "max": 0.4311250000000655
120
+ },
121
+ "bodyBytes": 244,
122
+ "serverData": null,
123
+ "serverRender": null
124
+ },
125
+ {
126
+ "label": "nav/data-1",
127
+ "path": "/bench/data-1",
128
+ "iterations": 100,
129
+ "ttfb": {
130
+ "mean": 21.82076291000002,
131
+ "p50": 21.85304200000064,
132
+ "p95": 22.433207999999468,
133
+ "p99": 23.03662499999973,
134
+ "min": 20.698709000000235,
135
+ "max": 23.03662499999973
136
+ },
137
+ "total": {
138
+ "mean": 21.865540849999878,
139
+ "p50": 21.896166999998968,
140
+ "p95": 22.511749999999665,
141
+ "p99": 23.08691699999963,
142
+ "min": 20.723042000000532,
143
+ "max": 23.08691699999963
144
+ },
145
+ "bodyBytes": 3513,
146
+ "serverData": null,
147
+ "serverRender": null
148
+ },
149
+ {
150
+ "label": "nav/data-3",
151
+ "path": "/bench/data-3",
152
+ "iterations": 100,
153
+ "ttfb": {
154
+ "mean": 31.878054999999968,
155
+ "p50": 31.92083300000013,
156
+ "p95": 32.69962499999929,
157
+ "p99": 33.174958999999944,
158
+ "min": 30.299708999998984,
159
+ "max": 33.174958999999944
160
+ },
161
+ "total": {
162
+ "mean": 31.93094377999998,
163
+ "p50": 31.96887500000048,
164
+ "p95": 32.76958299999933,
165
+ "p99": 33.27116700000079,
166
+ "min": 30.37066699999923,
167
+ "max": 33.27116700000079
168
+ },
169
+ "bodyBytes": 375,
170
+ "serverData": null,
171
+ "serverRender": null
172
+ }
173
+ ],
174
+ "bundles": {
175
+ "contact.boot": {
176
+ "file": "contact.boot-IBC3WEQQ.js",
177
+ "bytes": 2506
178
+ },
179
+ "counter.boot": {
180
+ "file": "counter.boot-VUWQFE5L.js",
181
+ "bytes": 1229
182
+ },
183
+ "runtime": {
184
+ "file": "runtime-YLZ4ZGK4.js",
185
+ "bytes": 7017
186
+ }
187
+ }
188
+ }
@@ -0,0 +1,188 @@
1
+ {
2
+ "timestamp": "2026-03-27T09:21:12.621Z",
3
+ "node": "v22.19.0",
4
+ "suites": [
5
+ {
6
+ "label": "simple",
7
+ "path": "/bench/simple",
8
+ "iterations": 100,
9
+ "ttfb": {
10
+ "mean": 0.18461582000000049,
11
+ "p50": 0.1646250000000009,
12
+ "p95": 0.2852500000000191,
13
+ "p99": 0.42183299999999235,
14
+ "min": 0.1447080000000085,
15
+ "max": 0.42183299999999235
16
+ },
17
+ "total": {
18
+ "mean": 0.21154751000000033,
19
+ "p50": 0.18912499999999,
20
+ "p95": 0.31433400000000233,
21
+ "p99": 0.4727500000000191,
22
+ "min": 0.1662499999999909,
23
+ "max": 0.4727500000000191
24
+ },
25
+ "bodyBytes": 1107,
26
+ "serverData": null,
27
+ "serverRender": null
28
+ },
29
+ {
30
+ "label": "data-1",
31
+ "path": "/bench/data-1",
32
+ "iterations": 100,
33
+ "ttfb": {
34
+ "mean": 0.6358262399999944,
35
+ "p50": 0.5394169999999576,
36
+ "p95": 1.2368329999999332,
37
+ "p99": 2.6608750000000327,
38
+ "min": 0.22608299999990322,
39
+ "max": 2.6608750000000327
40
+ },
41
+ "total": {
42
+ "mean": 22.039515369999986,
43
+ "p50": 22.052624999999807,
44
+ "p95": 23.031082999999853,
45
+ "p99": 23.720332999999982,
46
+ "min": 20.468165999999655,
47
+ "max": 23.720332999999982
48
+ },
49
+ "bodyBytes": 4437,
50
+ "serverData": null,
51
+ "serverRender": null
52
+ },
53
+ {
54
+ "label": "data-3",
55
+ "path": "/bench/data-3",
56
+ "iterations": 100,
57
+ "ttfb": {
58
+ "mean": 0.5651482699999678,
59
+ "p50": 0.49766700000009223,
60
+ "p95": 1.3021660000003976,
61
+ "p99": 1.4529170000000704,
62
+ "min": 0.23220799999944575,
63
+ "max": 1.4529170000000704
64
+ },
65
+ "total": {
66
+ "mean": 31.685546209999952,
67
+ "p50": 31.745542000000114,
68
+ "p95": 32.82679100000041,
69
+ "p99": 33.18908300000021,
70
+ "min": 29.795499999999265,
71
+ "max": 33.18908300000021
72
+ },
73
+ "bodyBytes": 1299,
74
+ "serverData": null,
75
+ "serverRender": null
76
+ },
77
+ {
78
+ "label": "cached",
79
+ "path": "/bench/cached",
80
+ "iterations": 100,
81
+ "ttfb": {
82
+ "mean": 0.1482587500000227,
83
+ "p50": 0.13324999999986176,
84
+ "p95": 0.2303750000000946,
85
+ "p99": 0.3728339999997843,
86
+ "min": 0.10658300000068266,
87
+ "max": 0.3728339999997843
88
+ },
89
+ "total": {
90
+ "mean": 0.16088121999998292,
91
+ "p50": 0.145542000000205,
92
+ "p95": 0.24883299999964947,
93
+ "p99": 0.3845839999994496,
94
+ "min": 0.11658299999999144,
95
+ "max": 0.3845839999994496
96
+ },
97
+ "bodyBytes": 1041,
98
+ "serverData": null,
99
+ "serverRender": null
100
+ },
101
+ {
102
+ "label": "nav/simple",
103
+ "path": "/bench/simple",
104
+ "iterations": 100,
105
+ "ttfb": {
106
+ "mean": 0.11078830999994352,
107
+ "p50": 0.10883399999966059,
108
+ "p95": 0.12508299999990413,
109
+ "p99": 0.37304199999925913,
110
+ "min": 0.09274999999979627,
111
+ "max": 0.37304199999925913
112
+ },
113
+ "total": {
114
+ "mean": 0.1193449899999905,
115
+ "p50": 0.11745799999971496,
116
+ "p95": 0.13524999999935972,
117
+ "p99": 0.38433399999939866,
118
+ "min": 0.09883399999944231,
119
+ "max": 0.38433399999939866
120
+ },
121
+ "bodyBytes": 244,
122
+ "serverData": null,
123
+ "serverRender": null
124
+ },
125
+ {
126
+ "label": "nav/data-1",
127
+ "path": "/bench/data-1",
128
+ "iterations": 100,
129
+ "ttfb": {
130
+ "mean": 21.61796121999997,
131
+ "p50": 21.62274999999954,
132
+ "p95": 22.23725000000013,
133
+ "p99": 22.784042000000227,
134
+ "min": 20.593541999999616,
135
+ "max": 22.784042000000227
136
+ },
137
+ "total": {
138
+ "mean": 21.65816495000001,
139
+ "p50": 21.65904099999989,
140
+ "p95": 22.343792000000576,
141
+ "p99": 22.863250000000335,
142
+ "min": 20.61554199999955,
143
+ "max": 22.863250000000335
144
+ },
145
+ "bodyBytes": 3513,
146
+ "serverData": null,
147
+ "serverRender": null
148
+ },
149
+ {
150
+ "label": "nav/data-3",
151
+ "path": "/bench/data-3",
152
+ "iterations": 100,
153
+ "ttfb": {
154
+ "mean": 31.698053359999975,
155
+ "p50": 31.66662499999984,
156
+ "p95": 32.492291999999,
157
+ "p99": 32.72829199999978,
158
+ "min": 30.043375000001106,
159
+ "max": 32.72829199999978
160
+ },
161
+ "total": {
162
+ "mean": 31.743360929999927,
163
+ "p50": 31.71479199999885,
164
+ "p95": 32.56791599999997,
165
+ "p99": 32.881624999999985,
166
+ "min": 30.08008300000074,
167
+ "max": 32.881624999999985
168
+ },
169
+ "bodyBytes": 375,
170
+ "serverData": null,
171
+ "serverRender": null
172
+ }
173
+ ],
174
+ "bundles": {
175
+ "contact.boot": {
176
+ "file": "contact.boot-IBC3WEQQ.js",
177
+ "bytes": 2506
178
+ },
179
+ "counter.boot": {
180
+ "file": "counter.boot-VUWQFE5L.js",
181
+ "bytes": 1229
182
+ },
183
+ "runtime": {
184
+ "file": "runtime-YLZ4ZGK4.js",
185
+ "bytes": 7017
186
+ }
187
+ }
188
+ }
@@ -0,0 +1,188 @@
1
+ {
2
+ "timestamp": "2026-03-27T09:29:14.607Z",
3
+ "node": "v22.19.0",
4
+ "suites": [
5
+ {
6
+ "label": "simple",
7
+ "path": "/bench/simple",
8
+ "iterations": 100,
9
+ "ttfb": {
10
+ "mean": 0.18297082000000045,
11
+ "p50": 0.17108400000000756,
12
+ "p95": 0.2559579999999926,
13
+ "p99": 0.4467909999999904,
14
+ "min": 0.15024999999999977,
15
+ "max": 0.4467909999999904
16
+ },
17
+ "total": {
18
+ "mean": 0.20846497000000028,
19
+ "p50": 0.19445799999999736,
20
+ "p95": 0.30350000000001387,
21
+ "p99": 0.48399999999998045,
22
+ "min": 0.17208299999998644,
23
+ "max": 0.48399999999998045
24
+ },
25
+ "bodyBytes": 1107,
26
+ "serverData": null,
27
+ "serverRender": null
28
+ },
29
+ {
30
+ "label": "data-1",
31
+ "path": "/bench/data-1",
32
+ "iterations": 100,
33
+ "ttfb": {
34
+ "mean": 0.6133241500000065,
35
+ "p50": 0.4627920000002632,
36
+ "p95": 1.2224160000000666,
37
+ "p99": 2.668916000000081,
38
+ "min": 0.29625000000010004,
39
+ "max": 2.668916000000081
40
+ },
41
+ "total": {
42
+ "mean": 21.990226709999998,
43
+ "p50": 21.921583999999996,
44
+ "p95": 22.944167000000107,
45
+ "p99": 23.517833999999993,
46
+ "min": 20.591375000000085,
47
+ "max": 23.517833999999993
48
+ },
49
+ "bodyBytes": 4437,
50
+ "serverData": null,
51
+ "serverRender": null
52
+ },
53
+ {
54
+ "label": "data-3",
55
+ "path": "/bench/data-3",
56
+ "iterations": 100,
57
+ "ttfb": {
58
+ "mean": 0.5387367000000086,
59
+ "p50": 0.4626250000001164,
60
+ "p95": 1.293916999999965,
61
+ "p99": 1.4869160000007469,
62
+ "min": 0.28574999999955253,
63
+ "max": 1.4869160000007469
64
+ },
65
+ "total": {
66
+ "mean": 31.784648730000022,
67
+ "p50": 31.87787500000013,
68
+ "p95": 32.797083000000384,
69
+ "p99": 33.82358299999942,
70
+ "min": 30.11054200000035,
71
+ "max": 33.82358299999942
72
+ },
73
+ "bodyBytes": 1299,
74
+ "serverData": null,
75
+ "serverRender": null
76
+ },
77
+ {
78
+ "label": "cached",
79
+ "path": "/bench/cached",
80
+ "iterations": 100,
81
+ "ttfb": {
82
+ "mean": 0.14762670000003708,
83
+ "p50": 0.13516700000036508,
84
+ "p95": 0.23062500000014552,
85
+ "p99": 0.5274579999995694,
86
+ "min": 0.11129199999959383,
87
+ "max": 0.5274579999995694
88
+ },
89
+ "total": {
90
+ "mean": 0.16071208999996997,
91
+ "p50": 0.1472089999997479,
92
+ "p95": 0.2516670000004524,
93
+ "p99": 0.5587909999994736,
94
+ "min": 0.12033299999984592,
95
+ "max": 0.5587909999994736
96
+ },
97
+ "bodyBytes": 1041,
98
+ "serverData": null,
99
+ "serverRender": null
100
+ },
101
+ {
102
+ "label": "nav/simple",
103
+ "path": "/bench/simple",
104
+ "iterations": 100,
105
+ "ttfb": {
106
+ "mean": 0.11551874999987376,
107
+ "p50": 0.11016599999948085,
108
+ "p95": 0.13649999999961437,
109
+ "p99": 0.39541600000029575,
110
+ "min": 0.09170799999992596,
111
+ "max": 0.39541600000029575
112
+ },
113
+ "total": {
114
+ "mean": 0.12438039999991815,
115
+ "p50": 0.11924999999973807,
116
+ "p95": 0.1472909999993135,
117
+ "p99": 0.40704099999948085,
118
+ "min": 0.09787500000038563,
119
+ "max": 0.40704099999948085
120
+ },
121
+ "bodyBytes": 244,
122
+ "serverData": null,
123
+ "serverRender": null
124
+ },
125
+ {
126
+ "label": "nav/data-1",
127
+ "path": "/bench/data-1",
128
+ "iterations": 100,
129
+ "ttfb": {
130
+ "mean": 21.649980459999988,
131
+ "p50": 21.569624999999178,
132
+ "p95": 22.391042000000198,
133
+ "p99": 22.874499999999898,
134
+ "min": 20.5278330000001,
135
+ "max": 22.874499999999898
136
+ },
137
+ "total": {
138
+ "mean": 21.690494169999955,
139
+ "p50": 21.597499999999854,
140
+ "p95": 22.469167000000198,
141
+ "p99": 22.954249999998865,
142
+ "min": 20.546290999999655,
143
+ "max": 22.954249999998865
144
+ },
145
+ "bodyBytes": 3513,
146
+ "serverData": null,
147
+ "serverRender": null
148
+ },
149
+ {
150
+ "label": "nav/data-3",
151
+ "path": "/bench/data-3",
152
+ "iterations": 100,
153
+ "ttfb": {
154
+ "mean": 31.646467500000053,
155
+ "p50": 31.64995799999997,
156
+ "p95": 32.36629200000061,
157
+ "p99": 32.69512500000019,
158
+ "min": 30.283833000001323,
159
+ "max": 32.69512500000019
160
+ },
161
+ "total": {
162
+ "mean": 31.690145040000026,
163
+ "p50": 31.678874999999607,
164
+ "p95": 32.40204200000153,
165
+ "p99": 32.79820800000016,
166
+ "min": 30.3387500000008,
167
+ "max": 32.79820800000016
168
+ },
169
+ "bodyBytes": 375,
170
+ "serverData": null,
171
+ "serverRender": null
172
+ }
173
+ ],
174
+ "bundles": {
175
+ "contact.boot": {
176
+ "file": "contact.boot-IBC3WEQQ.js",
177
+ "bytes": 2506
178
+ },
179
+ "counter.boot": {
180
+ "file": "counter.boot-VUWQFE5L.js",
181
+ "bytes": 1229
182
+ },
183
+ "runtime": {
184
+ "file": "runtime-YLZ4ZGK4.js",
185
+ "bytes": 7017
186
+ }
187
+ }
188
+ }