@stopnetic/js 0.0.4-pilot → 0.0.5-pilot
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 +34 -22
- package/dist/client-guide.md +149 -35
- package/dist/setup.js +2 -1
- package/examples/frontend/angular/app/app.ts +1 -3
- package/examples/frontend/react/App.tsx +1 -1
- package/examples/frontend/solid/App.tsx +2 -2
- package/examples/frontend/svelte/App.svelte +1 -3
- package/examples/frontend/vanilla/main.js +1 -1
- package/examples/frontend/vue/App.vue +1 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,18 +6,20 @@ frontend build. No React/Vue/Angular dependency or version upgrade is required.
|
|
|
6
6
|
The hosting server must run Node.js 22 or newer. This is an MIT-licensed pilot SDK;
|
|
7
7
|
hosted production/provider validation is still required before paid rollout.
|
|
8
8
|
|
|
9
|
-
Version **0.0.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
Version **0.0.5-pilot is prepared locally; it is not published yet**. The guide
|
|
10
|
+
offers two explicit rendering paths: preserve SSR or retain a static/CSR app.
|
|
11
|
+
Server document navigation is the default; leave startup/layout unchanged with
|
|
12
|
+
no global checking screen. Optional SPA demos for all six frontends explain
|
|
13
|
+
their asynchronous checks and use empty pending content. Unchanged
|
|
14
|
+
0.0.2/0.0.3/0.0.4 guides migrate safely; custom edits require merging.
|
|
13
15
|
Angular, React, Vue, Svelte, Solid and plain JavaScript share the browser/server
|
|
14
16
|
contracts; no React dependency is required. See the
|
|
15
17
|
[complete generated guide](dist/client-guide.md) for SSR, static builds, frameworks,
|
|
16
18
|
client navigation, API protection and runtime restrictions.
|
|
17
19
|
|
|
18
|
-
The currently published **0.0.
|
|
19
|
-
server/browser setup, complete Node application wrapper
|
|
20
|
-
migration. Version 0.0.2 added the reusable browser/server setup for Netlify, Vercel
|
|
20
|
+
The currently published **0.0.4-pilot** includes full frontend examples and the
|
|
21
|
+
framework-independent server/browser setup, complete Node application wrapper
|
|
22
|
+
and older-guide migration. Version 0.0.2 added the reusable browser/server setup for Netlify, Vercel
|
|
21
23
|
and Node/Express, a browser access check and optional React boundary. It also
|
|
22
24
|
normalizes public PEM formatting and rejects placeholder or reused installation
|
|
23
25
|
keys as cookie secrets. Install the published pilot with:
|
|
@@ -28,7 +30,14 @@ npm install @stopnetic/js@pilot
|
|
|
28
30
|
|
|
29
31
|
## Framework implementation examples
|
|
30
32
|
|
|
31
|
-
The guide and `examples/frontend` contain complete, locally tested
|
|
33
|
+
The guide and `examples/frontend` contain complete, locally tested OPTIONAL
|
|
34
|
+
browser-only SPA examples. The default document-navigation integration needs
|
|
35
|
+
the server guard and normal links, not these full-layout browser gates. Keep SSR
|
|
36
|
+
and hydration; do not apply the browser demos to an existing SSR root. A runtime
|
|
37
|
+
incompatibility needs a deployment decision, not an automatic conversion to CSR.
|
|
38
|
+
Dashboard policies decide which paths require verification; demo paths are not
|
|
39
|
+
instructions to protect every page. SPA checks still evaluate public targets
|
|
40
|
+
asynchronously and can show a brief empty pending state. The examples are:
|
|
32
41
|
|
|
33
42
|
| Frontend | Example |
|
|
34
43
|
| --- | --- |
|
|
@@ -40,7 +49,7 @@ The guide and `examples/frontend` contain complete, locally tested examples:
|
|
|
40
49
|
| Plain JavaScript | DOM rendering, checked navigation and API loading |
|
|
41
50
|
|
|
42
51
|
Each example includes initial access, later navigation, verification redirect,
|
|
43
|
-
pending
|
|
52
|
+
empty pending content, denied UI and cancellation. Backend page/API guards remain necessary.
|
|
44
53
|
No framework library is added as a required SDK dependency. The generated guide
|
|
45
54
|
embeds the source; use its file paths and helper instructions when copying it.
|
|
46
55
|
The dashboard's frontend selector shows the same files. For maintenance, run
|
|
@@ -62,7 +71,7 @@ npm run build
|
|
|
62
71
|
npm pack
|
|
63
72
|
```
|
|
64
73
|
|
|
65
|
-
Install the resulting `stopnetic-js-0.0.
|
|
74
|
+
Install the resulting `stopnetic-js-0.0.5-pilot.tgz` into the website project using
|
|
66
75
|
`npm install <absolute-path-to-tarball>`. The installed package has no Next.js or
|
|
67
76
|
other runtime dependency. The build packages the same signed decision implementation
|
|
68
77
|
as the Next.js adapter. Keep `@stopnetic/next` for its Next.js 16 guided installer.
|
|
@@ -98,7 +107,8 @@ preserved. Vercel configuration is preserved. Put runtime settings in the hostin
|
|
|
98
107
|
provider's server/Functions environment; plain `netlify.toml` build env is not a
|
|
99
108
|
Functions secret store. Copy the generated cookie secret without committing it.
|
|
100
109
|
|
|
101
|
-
Wire
|
|
110
|
+
Wire the server page guard and EACH protected API following the generated guide.
|
|
111
|
+
Browser route checks are optional for retained SPA navigation.
|
|
102
112
|
Run `npm exec --no -- stopnetic-js check` after setting credentials (`--local-http`
|
|
103
113
|
for a loopback pilot). This check validates configuration and generated files
|
|
104
114
|
offline; it cannot prove deployment routing, API coverage or browser integration.
|
|
@@ -111,12 +121,11 @@ server environment loader. Production credentials belong in runtime settings.
|
|
|
111
121
|
|
|
112
122
|
### Shared browser startup and Node SSR
|
|
113
123
|
|
|
114
|
-
The generated [framework-independent guide](
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
or recheck target access in the client router. A browser-only check is UI behavior.
|
|
124
|
+
The generated [framework-independent guide](dist/client-guide.md) defaults to
|
|
125
|
+
server document navigation: leave browser startup/layout intact, use normal
|
|
126
|
+
links, and let the server apply dashboard policies. It also gives an OPTIONAL
|
|
127
|
+
browser startup gate and separate OPTIONAL SPA router demos. Do not combine
|
|
128
|
+
the alternatives or apply browser-only gates to an SSR hydration root.
|
|
120
129
|
|
|
121
130
|
For Node SSR use the generated Express helper before static files/rendering,
|
|
122
131
|
or `createStopneticAppHandler` around a Fetch-style application entry (0.0.3).
|
|
@@ -128,15 +137,17 @@ adapted; accepting Request/Response does not make an Edge runtime supported.
|
|
|
128
137
|
The guide includes Angular SSR/rendering and client router examples. Angular
|
|
129
138
|
SSR compiled with the installed Angular 22 dependencies and served real HTML
|
|
130
139
|
after verification in an isolated local fixture. That does not validate a live
|
|
131
|
-
provider deployment. Netlify's automatic Angular SSR uses Edge;
|
|
132
|
-
|
|
140
|
+
provider deployment. Netlify's automatic Angular SSR uses Edge; the Node SDK
|
|
141
|
+
has no drop-in integration for that runtime. Preserve SSR and obtain a supported
|
|
142
|
+
Node deployment/gateway decision instead of silently converting the app. Do not publish protected prerendered
|
|
133
143
|
HTML. For other frameworks use the same Node server entry and verify their
|
|
134
144
|
actual deployed runtime. React's boundary remains an optional convenience.
|
|
135
145
|
|
|
136
146
|
### Optional React Router boundary
|
|
137
147
|
|
|
138
148
|
The optional React entry uses Hooks. The core/browser modules need no React.
|
|
139
|
-
|
|
149
|
+
Use this only for explicitly retained browser SPA navigation, inside BrowserRouter,
|
|
150
|
+
around the full target layout. Server document navigation does not require it:
|
|
140
151
|
|
|
141
152
|
```jsx
|
|
142
153
|
import { useLocation } from 'react-router-dom';
|
|
@@ -144,11 +155,12 @@ import { StopneticBoundary } from '@stopnetic/js/react';
|
|
|
144
155
|
|
|
145
156
|
function RouteGuard({ children }) {
|
|
146
157
|
const location = useLocation();
|
|
147
|
-
return <StopneticBoundary path={location.pathname + location.search}>
|
|
158
|
+
return <StopneticBoundary path={location.pathname + location.search} pending={null}>
|
|
148
159
|
{children}
|
|
149
160
|
</StopneticBoundary>;
|
|
150
161
|
}
|
|
151
|
-
// <BrowserRouter><RouteGuard><
|
|
162
|
+
// <BrowserRouter><RouteGuard><Layout/></RouteGuard></BrowserRouter>
|
|
163
|
+
// Layout includes the target header, routes and footer.
|
|
152
164
|
```
|
|
153
165
|
|
|
154
166
|
The boundary hides children while checking, ignores canceled/stale checks and
|
package/dist/client-guide.md
CHANGED
|
@@ -13,8 +13,61 @@ layout, navigation and protected API example, not just the startup function.
|
|
|
13
13
|
The generated control endpoint is only part of installation. It does not
|
|
14
14
|
automatically intercept pages, edit your router or protect existing APIs.
|
|
15
15
|
|
|
16
|
+
## Integration contract — read before editing an existing app
|
|
17
|
+
|
|
18
|
+
1. Inspect the existing server entry, rendering modes, hosting adapter and router.
|
|
19
|
+
Preserve SSR, hydration, public pages, routes and application features.
|
|
20
|
+
Installing Stopnetic is not authorization to convert SSR to CSR, delete server
|
|
21
|
+
files, replace the application's router or copy the demo over an existing app.
|
|
22
|
+
2. Choose ONE of the two rendering paths below. Keep the app's current rendering
|
|
23
|
+
by default. A hosting/runtime incompatibility must be explained to the owner;
|
|
24
|
+
do not resolve it by silently removing SSR or changing hosting.
|
|
25
|
+
3. Install the guard before the existing server renders or serves HTML. Keep the
|
|
26
|
+
existing browser bootstrap unchanged for the default document-navigation mode.
|
|
27
|
+
Do not add a global `Checking access...` screen or a browser startup gate.
|
|
28
|
+
4. Save protected paths in Stopnetic Policies. Do not add the demo paths, protect
|
|
29
|
+
every page, copy dashboard rules into a frontend path list, or change defaults
|
|
30
|
+
without the owner's instruction. Guards evaluate requests; they do not make
|
|
31
|
+
every evaluated request require verification.
|
|
32
|
+
5. Use normal document navigation for the simplest server-enforced integration.
|
|
33
|
+
If retaining client-side SPA navigation is required, use the OPTIONAL router
|
|
34
|
+
examples and explain their asynchronous checks before adding them.
|
|
35
|
+
6. Independently guard private API handlers. Validate public, protected and denied
|
|
36
|
+
pages plus SSR output before declaring integration complete.
|
|
37
|
+
|
|
38
|
+
## What visitors should see
|
|
39
|
+
|
|
40
|
+
For example, suppose only `/members` is Page / Automatic browser flow:
|
|
41
|
+
|
|
42
|
+
| Request | Normal behavior |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| `/`, `/about`, `/contact` with no matching rule | Public page; normal layout, no Stopnetic checking screen or verification |
|
|
45
|
+
| `/members` without a valid session | Server verification flow before returning the page |
|
|
46
|
+
| `/members` with a valid session | Normal page content |
|
|
47
|
+
| A Page / Block route | Empty HTTP 404 before any site layout renders |
|
|
48
|
+
| A protected API without a valid session | HTTP 404; no JSON data and no browser challenge |
|
|
49
|
+
|
|
50
|
+
Generated site mode leaves unmatched paths public; explicit broader rules can
|
|
51
|
+
change that. Public requests still need a valid signed policy response. A service
|
|
52
|
+
failure returns 503 rather than bypassing policy. Rules belong in the dashboard;
|
|
53
|
+
the browser cannot know whether a target is public until the server checks it.
|
|
54
|
+
|
|
16
55
|
## 1. Choose the actual rendering and server runtime
|
|
17
56
|
|
|
57
|
+
**Option A — preserve SSR.** Keep the existing renderer, server entry and
|
|
58
|
+
hydration. Add the Node guard before the renderer (section 3). Use server
|
|
59
|
+
document navigation (section 4). Public pages render normally; protected pages
|
|
60
|
+
render only after the dashboard decision permits them.
|
|
61
|
+
|
|
62
|
+
**Option B — retain a static/CSR frontend.** Keep the existing browser bootstrap
|
|
63
|
+
and build. Add a Node hosting page guard before HTML (section 3), then use server
|
|
64
|
+
document navigation (section 4). A Node function serving built `index.html` is
|
|
65
|
+
static page handling, not SSR. Choose this option for an existing static app or
|
|
66
|
+
only after an explicit decision to convert rendering.
|
|
67
|
+
|
|
68
|
+
Neither option requires a global browser boundary. Optional SPA navigation is
|
|
69
|
+
a separate choice, not a third rendering mode.
|
|
70
|
+
|
|
18
71
|
| Application | Where the shared guard belongs |
|
|
19
72
|
| --- | --- |
|
|
20
73
|
| Node/Express SSR or static-file server | Before body parsers, static files, API handlers and rendering |
|
|
@@ -128,11 +181,21 @@ export const serverRoutes: ServerRoute[] = [
|
|
|
128
181
|
];
|
|
129
182
|
```
|
|
130
183
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
184
|
+
This is an all-request-time demonstration, not an instruction to replace an
|
|
185
|
+
existing hybrid route configuration. Preserve public rendering modes where
|
|
186
|
+
appropriate. Any path the dashboard may protect must reach the guard before
|
|
187
|
+
HTML is served; publicly cached/prerendered HTML bypassing it cannot be protected
|
|
188
|
+
by adding a dashboard rule alone. Plan server coverage for those paths first.
|
|
189
|
+
|
|
190
|
+
Netlify's automatic Angular SSR adapter currently uses Edge Functions. This
|
|
191
|
+
combination does not have a drop-in integration with the current Node SDK.
|
|
192
|
+
Do not import the SDK into that Edge entry or assume a Node function intercepts
|
|
193
|
+
the Edge renderer. If SSR must stay, keep the SSR files and explain that a
|
|
194
|
+
supported Node SSR deployment or a Node gateway that cannot be bypassed is
|
|
195
|
+
needed. A custom Node SSR adapter requires separate deployment/routing work;
|
|
196
|
+
the static page-function example is not that adapter. Stop and obtain a rendering
|
|
197
|
+
or deployment decision if the current runtime is incompatible. Do not delete
|
|
198
|
+
`server.ts`, `main.server.ts`, SSR providers or hydration as a workaround.
|
|
136
199
|
|
|
137
200
|
### Static apps on Netlify / Vercel
|
|
138
201
|
|
|
@@ -148,7 +211,55 @@ root rather than `/assets`. Bundle the correct HTML and assets, preserve their
|
|
|
148
211
|
MIME types, and do not use the Vite-only file paths unchanged for Angular.
|
|
149
212
|
Reject direct entry-HTML and function aliases that would bypass protected paths.
|
|
150
213
|
|
|
151
|
-
## 4.
|
|
214
|
+
## 4. Navigation — server enforcement by default
|
|
215
|
+
|
|
216
|
+
For BOTH rendering options, leave the existing browser entry and app layout
|
|
217
|
+
alone. Use document links for page navigation so every target reaches the
|
|
218
|
+
guarded server before rendering. No global `checkAccess`, `StopneticBoundary`,
|
|
219
|
+
startup import gate, root access service or loading message is required.
|
|
220
|
+
|
|
221
|
+
| Frontend | Document navigation |
|
|
222
|
+
| --- | --- |
|
|
223
|
+
| Angular | `<a href="/members">Members</a>` instead of `routerLink` for this navigation |
|
|
224
|
+
| React | `<a href="/members">Members</a>` instead of router `<Link>` |
|
|
225
|
+
| Vue | `<a href="/members">Members</a>` instead of `<RouterLink>` |
|
|
226
|
+
| Svelte / SvelteKit | `<a href="/members" data-sveltekit-reload>Members</a>`; disable any custom interception |
|
|
227
|
+
| Solid | `<a href="/members" target="_self">Members</a>` instead of router `<A>` |
|
|
228
|
+
| Plain JavaScript | `<a href="/members">Members</a>`; do not intercept it with `pushState` |
|
|
229
|
+
|
|
230
|
+
Replace programmatic SPA transitions with `location.assign('/members')` when
|
|
231
|
+
using this mode. Turn off router prefetch/preload of protected page data that
|
|
232
|
+
would bypass the guarded document request. Existing routers may still resolve
|
|
233
|
+
the current URL after loading. Normal pages keep their usual loading behavior;
|
|
234
|
+
Stopnetic's verification HTML is sent only when the server decision requires it.
|
|
235
|
+
|
|
236
|
+
For SSR, hydrate the HTML already authorized by the server. Do not replace it
|
|
237
|
+
with a browser-only loading screen or run a redundant startup check. Private API
|
|
238
|
+
requests remain independently checked by their server handler.
|
|
239
|
+
|
|
240
|
+
### Optional SPA navigation — explicit asynchronous tradeoff
|
|
241
|
+
|
|
242
|
+
Retain SPA navigation only when needed. SPA transitions do not make a new
|
|
243
|
+
document request, so check each target in the router before showing its content.
|
|
244
|
+
The current browser API returns access after a server request; it does not
|
|
245
|
+
provide a synchronous dashboard route manifest. Public transitions also need
|
|
246
|
+
that check to discover the current policy. A brief empty pending state is
|
|
247
|
+
possible; it is not a challenge and is not advertised as instant public rendering.
|
|
248
|
+
Use document navigation above if this delay is unacceptable. Do not bypass
|
|
249
|
+
checks with a hardcoded public/protected list, cached `allowed` flag, or client
|
|
250
|
+
user-agent detection. Keep full target content hidden until the check succeeds.
|
|
251
|
+
|
|
252
|
+
The six optional demos below intentionally check their sample router targets.
|
|
253
|
+
They are not instructions to protect all those paths in Policies. Their pending
|
|
254
|
+
state contains no `Checking access...` text. They do not provide server SSR
|
|
255
|
+
integration or HTTP status changes. Do not install both a startup check and a
|
|
256
|
+
router gate; do not apply these browser demos to an existing hydrated SSR root.
|
|
257
|
+
|
|
258
|
+
### Optional browser startup gate for a browser-only app
|
|
259
|
+
|
|
260
|
+
This alternative is useful only if browser mounting must wait for an access
|
|
261
|
+
check. Skip it when the server already guards HTML and document navigation is
|
|
262
|
+
used. It is not required by either rendering option above.
|
|
152
263
|
|
|
153
264
|
For a browser-only/static app, move the existing startup code from `src/main.ts`
|
|
154
265
|
or `src/main.js` into `src/bootstrap.ts` or `src/bootstrap.js`. Keep its original
|
|
@@ -186,26 +297,26 @@ This is browser code, not a server hook. The startup file can use any framework:
|
|
|
186
297
|
| Solid | Your existing `render(...)` |
|
|
187
298
|
| Plain JavaScript | Your existing DOM rendering code |
|
|
188
299
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
does not rerun the startup file. If keeping SPA navigation, call `checkAccess`
|
|
192
|
-
in that router's before-navigation guard for every target and handle denial,
|
|
193
|
-
verification redirects, outages and stale/cancelled requests. A UI check cannot
|
|
194
|
-
set the original HTTP status or make public bundles private.
|
|
300
|
+
Client router navigation does not rerun this optional startup file. A UI check
|
|
301
|
+
cannot set the original HTTP status or make public bundles private.
|
|
195
302
|
|
|
196
303
|
<!-- BEGIN FRONTEND EXAMPLES -->
|
|
197
304
|
|
|
198
|
-
###
|
|
305
|
+
### Optional SPA demos — choose your frontend implementation
|
|
199
306
|
|
|
200
307
|
The package includes copyable source files in `examples/frontend`. The same
|
|
201
|
-
examples appear below and in the dashboard frontend selector.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
308
|
+
examples appear below and in the dashboard frontend selector. Skip this
|
|
309
|
+
section for the default server/document-navigation integration. These are
|
|
310
|
+
optional browser-only demos, not replacements for an existing app or SSR
|
|
311
|
+
entry. Retaining SPA navigation requires asynchronous target checks, even
|
|
312
|
+
for public targets. Pending content is empty; no global checking text is
|
|
313
|
+
required. Keep the target layout hidden until allowed to avoid exposing it
|
|
314
|
+
on denial. Only dashboard rules decide which paths require verification.
|
|
315
|
+
|
|
316
|
+
If explicitly choosing this mode, merge the relevant hooks into your own
|
|
317
|
+
browser router and adapt the sample paths. Do not add every demo path to
|
|
318
|
+
Policies. Do not combine these gates with the optional startup gate or
|
|
319
|
+
apply them to a hydrated SSR root. SSR uses section 3 and document navigation.
|
|
209
320
|
|
|
210
321
|
Copy the selected folder under `src/<frontend>/` and the shared data helper
|
|
211
322
|
to `src/load-private-data.js` (plus its `.d.ts` file for TypeScript). This keeps
|
|
@@ -261,7 +372,7 @@ import { loadPrivateData } from '../load-private-data.js';
|
|
|
261
372
|
function RouteGuard({ children }: { children: ReactNode }) {
|
|
262
373
|
const location = useLocation();
|
|
263
374
|
return <StopneticBoundary path={location.pathname + location.search}
|
|
264
|
-
pending={
|
|
375
|
+
pending={null}
|
|
265
376
|
blocked={<p>Access unavailable.</p>}>
|
|
266
377
|
{children}
|
|
267
378
|
</StopneticBoundary>;
|
|
@@ -314,7 +425,7 @@ createRoot(document.getElementById('app')!).render(<App/>);
|
|
|
314
425
|
|
|
315
426
|
### Angular Router
|
|
316
427
|
|
|
317
|
-
|
|
428
|
+
Optional browser-only SPA demo: the service records checking/allowed/denied state. Checks evaluate policy; only dashboard rules require verification. Members uses HttpClient after route access succeeds. Merge providers into your existing browser appConfig. Preserve SSR/hydration with the server/document-navigation option instead of applying this demo to a hydrated root. Modern standalone Angular syntax.
|
|
318
429
|
|
|
319
430
|
#### src/angular/app/app.config.ts
|
|
320
431
|
|
|
@@ -375,9 +486,7 @@ import { StopneticAccess } from './stopnetic-access.service';
|
|
|
375
486
|
</nav></header>
|
|
376
487
|
<router-outlet/>
|
|
377
488
|
<footer>Example site</footer>
|
|
378
|
-
} @else if (access.state() === '
|
|
379
|
-
<p role="status">Checking access...</p>
|
|
380
|
-
} @else {
|
|
489
|
+
} @else if (access.state() === 'denied') {
|
|
381
490
|
<p role="alert">Access unavailable.</p>
|
|
382
491
|
}
|
|
383
492
|
`,
|
|
@@ -478,8 +587,7 @@ import { accessState } from './router.js';
|
|
|
478
587
|
<RouterView/>
|
|
479
588
|
<footer>Example site</footer>
|
|
480
589
|
</template>
|
|
481
|
-
<p v-else-if="accessState === '
|
|
482
|
-
<p v-else role="alert">Access unavailable.</p>
|
|
590
|
+
<p v-else-if="accessState === 'denied'" role="alert">Access unavailable.</p>
|
|
483
591
|
</template>
|
|
484
592
|
```
|
|
485
593
|
|
|
@@ -620,9 +728,7 @@ Svelte 5 example with onMount, History API navigation, popstate and abort cleanu
|
|
|
620
728
|
</nav></header>
|
|
621
729
|
<main><h1>{path === '/members' ? 'Members' : path === '/' ? 'Home' : path === '/slow' ? 'Slow' : 'Not found'}</h1><p>{data}</p></main>
|
|
622
730
|
<footer>Example site</footer>
|
|
623
|
-
{:else if state === '
|
|
624
|
-
<p role="status">Checking access...</p>
|
|
625
|
-
{:else}
|
|
731
|
+
{:else if state === 'denied'}
|
|
626
732
|
<p role="alert">Access unavailable.</p>
|
|
627
733
|
{/if}
|
|
628
734
|
```
|
|
@@ -668,8 +774,8 @@ const GuardedLayout: ParentComponent = props => {
|
|
|
668
774
|
onCleanup(() => controller.abort());
|
|
669
775
|
});
|
|
670
776
|
return <Show when={result().allowed && result().path === path() ? result() : undefined}
|
|
671
|
-
fallback={<Show when={result().pending
|
|
672
|
-
|
|
777
|
+
fallback={<Show when={!result().pending && result().path === path()}>
|
|
778
|
+
<p role="alert">Access unavailable.</p></Show>}>
|
|
673
779
|
{_checked => <>
|
|
674
780
|
<header><nav><A href="/">Home</A>{' '}<A href="/members">Members</A>{' '}
|
|
675
781
|
<A href="/slow">Slow</A>{' '}<A href="/blocked">Blocked</A>{' '}<A href="/offline">Offline</A>
|
|
@@ -725,7 +831,7 @@ let current;
|
|
|
725
831
|
async function showPage() {
|
|
726
832
|
current?.abort();
|
|
727
833
|
const controller = new AbortController(); current = controller;
|
|
728
|
-
root.replaceChildren(
|
|
834
|
+
root.replaceChildren();
|
|
729
835
|
try {
|
|
730
836
|
const path = location.pathname;
|
|
731
837
|
const result = await checkAccess(path + location.search, { signal: controller.signal });
|
|
@@ -810,6 +916,14 @@ client navigation, entry HTML, aliases, prerender outputs and caches. A denied
|
|
|
810
916
|
request must not execute the renderer or data handler. The offline CLI check
|
|
811
917
|
validates configuration and generated files, not deployed coverage.
|
|
812
918
|
|
|
919
|
+
With only `/members` protected, confirm `/about` and `/contact` render without
|
|
920
|
+
a Stopnetic checking screen. Change a dashboard rule and make a new document
|
|
921
|
+
request: the change must apply without editing a client route list. For SSR,
|
|
922
|
+
confirm permitted HTML contains server-rendered page content before JavaScript
|
|
923
|
+
runs, hydration still works, and the renderer is never called on denial. Verify
|
|
924
|
+
the deployed request actually reaches Node; an SSR build alone proves nothing
|
|
925
|
+
about a provider's deployed runtime. Optional SPA checks may have a pending delay.
|
|
926
|
+
|
|
813
927
|
Ordinary policy changes apply on subsequent guarded requests without reinstalling
|
|
814
928
|
or redeploying. Already loaded content is not recalled. Public HTML/JS/assets and
|
|
815
929
|
content bundled into frontend code remain public; keep private data in guarded
|
|
@@ -818,7 +932,7 @@ server endpoints.
|
|
|
818
932
|
## Updating an existing generated guide
|
|
819
933
|
|
|
820
934
|
After installing the new SDK, rerun `stopnetic-js init --platform <same-platform>`
|
|
821
|
-
(preview with `--dry-run`). An unchanged 0.0.2/0.0.3 generated guide is upgraded
|
|
935
|
+
(preview with `--dry-run`). An unchanged 0.0.2/0.0.3/0.0.4 generated guide is upgraded
|
|
822
936
|
with its setup manifest. Your key, cookie secret and server files are preserved.
|
|
823
937
|
Customized guides or handlers require manual merging; switching platforms also
|
|
824
938
|
requires review. This command does not publish, deploy or contact Stopnetic.
|
package/dist/setup.js
CHANGED
|
@@ -38,6 +38,7 @@ function platformFor(root, supplied) {
|
|
|
38
38
|
const legacyGuideDigests = new Set([
|
|
39
39
|
'b1f149af44f9ceb08fb80c18cb5d4b521620196f536d8ad422ab94d15d1d125d', // 0.0.2
|
|
40
40
|
'55e36295b6aa87ad9558cde29786998483095adeae74e149ff5c7fe78507fad7', // published 0.0.3
|
|
41
|
+
'08f919257d8c85af4e56e842705825832ae2810ed68d5c1dfc8405c8f7be7610', // published 0.0.4
|
|
41
42
|
]);
|
|
42
43
|
const clientGuide = readFileSync(new URL('./client-guide.md', import.meta.url), 'utf8');
|
|
43
44
|
|
|
@@ -119,5 +120,5 @@ export function checkSetup(input, { localHttp = false } = {}) {
|
|
|
119
120
|
if (!localHttp && !options.apiUrl?.startsWith('https:')) throw new Error();
|
|
120
121
|
createStopneticAccessHandler(options);
|
|
121
122
|
} catch { throw new SetupError('Check server settings, HTTPS URLs, installation/signing keys and the separate cookie secret. No secret values are displayed.'); }
|
|
122
|
-
return `Checked ${manifest.platform} generated files and server configuration offline. Confirm
|
|
123
|
+
return `Checked ${manifest.platform} generated files and server configuration offline. Confirm server page enforcement, your chosen navigation mode, API wrappers and hosting routing with a deployed test. Preserve existing SSR; browser gates are optional. This does not prove coverage or start a trial.`;
|
|
123
124
|
}
|
|
@@ -13,9 +13,7 @@ import { StopneticAccess } from './stopnetic-access.service';
|
|
|
13
13
|
</nav></header>
|
|
14
14
|
<router-outlet/>
|
|
15
15
|
<footer>Example site</footer>
|
|
16
|
-
} @else if (access.state() === '
|
|
17
|
-
<p role="status">Checking access...</p>
|
|
18
|
-
} @else {
|
|
16
|
+
} @else if (access.state() === 'denied') {
|
|
19
17
|
<p role="alert">Access unavailable.</p>
|
|
20
18
|
}
|
|
21
19
|
`,
|
|
@@ -6,7 +6,7 @@ import { loadPrivateData } from '../load-private-data.js';
|
|
|
6
6
|
function RouteGuard({ children }: { children: ReactNode }) {
|
|
7
7
|
const location = useLocation();
|
|
8
8
|
return <StopneticBoundary path={location.pathname + location.search}
|
|
9
|
-
pending={
|
|
9
|
+
pending={null}
|
|
10
10
|
blocked={<p>Access unavailable.</p>}>
|
|
11
11
|
{children}
|
|
12
12
|
</StopneticBoundary>;
|
|
@@ -21,8 +21,8 @@ const GuardedLayout: ParentComponent = props => {
|
|
|
21
21
|
onCleanup(() => controller.abort());
|
|
22
22
|
});
|
|
23
23
|
return <Show when={result().allowed && result().path === path() ? result() : undefined}
|
|
24
|
-
fallback={<Show when={result().pending
|
|
25
|
-
|
|
24
|
+
fallback={<Show when={!result().pending && result().path === path()}>
|
|
25
|
+
<p role="alert">Access unavailable.</p></Show>}>
|
|
26
26
|
{_checked => <>
|
|
27
27
|
<header><nav><A href="/">Home</A>{' '}<A href="/members">Members</A>{' '}
|
|
28
28
|
<A href="/slow">Slow</A>{' '}<A href="/blocked">Blocked</A>{' '}<A href="/offline">Offline</A>
|
|
@@ -51,8 +51,6 @@
|
|
|
51
51
|
</nav></header>
|
|
52
52
|
<main><h1>{path === '/members' ? 'Members' : path === '/' ? 'Home' : path === '/slow' ? 'Slow' : 'Not found'}</h1><p>{data}</p></main>
|
|
53
53
|
<footer>Example site</footer>
|
|
54
|
-
{:else if state === '
|
|
55
|
-
<p role="status">Checking access...</p>
|
|
56
|
-
{:else}
|
|
54
|
+
{:else if state === 'denied'}
|
|
57
55
|
<p role="alert">Access unavailable.</p>
|
|
58
56
|
{/if}
|
|
@@ -5,7 +5,7 @@ let current;
|
|
|
5
5
|
async function showPage() {
|
|
6
6
|
current?.abort();
|
|
7
7
|
const controller = new AbortController(); current = controller;
|
|
8
|
-
root.replaceChildren(
|
|
8
|
+
root.replaceChildren();
|
|
9
9
|
try {
|
|
10
10
|
const path = location.pathname;
|
|
11
11
|
const result = await checkAccess(path + location.search, { signal: controller.signal });
|
|
@@ -13,6 +13,5 @@ import { accessState } from './router.js';
|
|
|
13
13
|
<RouterView/>
|
|
14
14
|
<footer>Example site</footer>
|
|
15
15
|
</template>
|
|
16
|
-
<p v-else-if="accessState === '
|
|
17
|
-
<p v-else role="alert">Access unavailable.</p>
|
|
16
|
+
<p v-else-if="accessState === 'denied'" role="alert">Access unavailable.</p>
|
|
18
17
|
</template>
|