@ofidj/generator-fidj 1.7.2 → 1.8.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.
@@ -15,7 +15,7 @@
15
15
  "privacy:rehearse": "npm run build && node --test test/server.test.mjs"
16
16
  },
17
17
  "dependencies": {
18
- "@ofidj/node": "^3.6.26"
18
+ "@ofidj/node": "^3.6.30"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/node": "^22.0.0",
@@ -437,7 +437,14 @@ function render() {
437
437
  askedProvider = true;
438
438
  void (async () => {
439
439
  if (!(await providerRendersHere())) return;
440
- window.location.assign(await oidc.beginLogin());
440
+ // Being recognised again is the one thing somebody who just signed out did
441
+ // not ask for, and this shortcut is what made a sign-out undoable by a page
442
+ // reload. Ending the provider session is what should make that impossible,
443
+ // and that call can be refused — so here the screen asks rather than
444
+ // assumes, until somebody signs in again.
445
+ window.location.assign(
446
+ await oidc.beginLogin(oidc.signedOutHere() ? { prompt: "login" } : {}),
447
+ );
441
448
  })();
442
449
  }
443
450
 
@@ -467,17 +474,21 @@ function render() {
467
474
  signInPassword = password;
468
475
  signInAgreementAccepted = agreement?.checked === true;
469
476
  const acceptance = acceptedAgreement(event.currentTarget as HTMLFormElement);
470
- if (!acceptance) {
471
- failed = true;
472
- message = "Please accept the service agreement before continuing.";
473
- render();
474
- return;
475
- }
476
477
  const submitter = event.submitter as HTMLButtonElement | null;
477
478
  const signup = submitter?.name === "signup";
478
479
  // Which door was used. The Fidj one leaves for the provider; the credential
479
480
  // one signs in here, which is why it is the app's own form and not Fidj's.
480
481
  const throughFidj = submitter?.name === "entry" && submitter.value === "fidj";
482
+ // Only the credential door is gated here. The Fidj one is about to be asked
483
+ // the same question on the screen that names this app, where the answer is
484
+ // recorded with its version — so asking first cost a second click and kept
485
+ // nothing.
486
+ if (!throughFidj && !acceptance) {
487
+ failed = true;
488
+ message = "Please accept the service agreement before continuing.";
489
+ render();
490
+ return;
491
+ }
481
492
  void action(async () => {
482
493
  if (oidc && throughFidj) {window.location.assign(await oidc.beginLogin()); return;}
483
494
  if (oidc && (!email || !password)) {
@@ -137,9 +137,14 @@ function render() {
137
137
  const password = el<HTMLInputElement>("password")?.value || "";
138
138
  signInEmail = email;
139
139
  signInPassword = password;
140
- signInAgreementAccepted = el<HTMLInputElement>("service-agreement").checked;
140
+ signInAgreementAccepted =
141
+ el<HTMLInputElement>("service-agreement")?.checked === true;
141
142
  const acceptance = acceptedAgreement(event.currentTarget as HTMLFormElement);
142
- if (!acceptance) {
143
+ // Only a credential entry is gated here. When Fidj is the door, it asks for
144
+ // this app's agreement a moment later, on the screen that names the app,
145
+ // and records the acceptance with its version — so asking first cost a
146
+ // second click and kept nothing.
147
+ if (!oidc && !acceptance) {
143
148
  error = "Please accept the service agreement before continuing.";
144
149
  render();
145
150
  return;
@@ -20,7 +20,10 @@ export function signInErrorMessage(error: unknown) {
20
20
 
21
21
  export async function bindAgreement(form: HTMLFormElement | null, title: string, endpoint: string, appId: string, checked = false) {
22
22
  if (!form) return;
23
- const checkbox = form.querySelector<HTMLInputElement>("#service-agreement")!;
23
+ // An app whose only door is Fidj carries no agreement block: Fidj asks for
24
+ // this app's agreement on the screen that names it, and records the version.
25
+ const checkbox = form.querySelector<HTMLInputElement>("#service-agreement");
26
+ if (!checkbox) return;
24
27
  const read = form.querySelector<HTMLButtonElement>("#read-agreement")!;
25
28
  const dialog = form.querySelector<HTMLDialogElement>("#agreement-dialog")!;
26
29
  const status = form.querySelector<HTMLElement>("#agreement-status")!;
@@ -130,7 +133,10 @@ export function providerEntry(
130
133
  const fidj = hint
131
134
  ? `<button class="primary" type="submit" name="entry" value="fidj">Continue as ${escapeText(hint)}</button><button type="button" id="forget-hint" class="quiet">Use a different account</button>`
132
135
  : `<button class="${both ? "secondary" : "primary"}" type="submit" name="entry" value="fidj">${isFidjItself ? "Sign in" : "Sign in with Fidj"}</button>`;
133
- if (!both) return lead + agreementMarkup() + fidj;
136
+ // Fidj is the only door: it collects the agreement itself, a moment later, on
137
+ // the screen that names the app — and records it with its version. Collecting
138
+ // it here first recorded nothing and asked the same question twice.
139
+ if (!both) return lead + fidj;
134
140
  // Both doors. A remembered address puts Fidj first because it is one tap; no
135
141
  // memory puts the form first, because that is what the person came to do.
136
142
  const divider = `<div class="signin-divider"><span>or</span></div>`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ofidj/generator-fidj",
3
- "version": "1.7.2",
3
+ "version": "1.8.0",
4
4
  "description": "Generate a TypeScript app with Fidj sign-in, live server-side roles and per-app privacy.",
5
5
  "homepage": "https://fidj.ovh",
6
6
  "bugs": {