@graffiti-garden/implementation-decentralized 0.1.5 → 0.1.7

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.
@@ -41,6 +41,7 @@ export const DID_SERVICE_ID_GRAFFITI_SHARED_INBOX_PREFIX =
41
41
 
42
42
  export class Sessions {
43
43
  sessionEvents: Graffiti["sessionEvents"] = new EventTarget();
44
+ initialAuthorizationNavigation: "assign" | "replace" = "assign";
44
45
 
45
46
  constructor(
46
47
  protected readonly services: {
@@ -87,8 +88,9 @@ export class Sessions {
87
88
  const url = new URL(window.location.toString());
88
89
  url.searchParams.delete("actor");
89
90
  window.history.replaceState({}, "", url.toString());
90
- // Complete the login
91
- loginPromise = this.login(actor);
91
+ // The original app entry was kept when opening account creation or
92
+ // recovery, so OAuth reuses this callback entry.
93
+ loginPromise = this.login(actor, "replace");
92
94
  } catch (error) {
93
95
  console.error("Error decoding actor:", error);
94
96
  }
@@ -124,9 +126,13 @@ export class Sessions {
124
126
  protected inProgressLogout: infer_<typeof InProgressSchema> | undefined =
125
127
  undefined;
126
128
 
127
- async login(actor: string) {
129
+ async login(
130
+ actor: string,
131
+ initialAuthorizationNavigation: "assign" | "replace" =
132
+ this.initialAuthorizationNavigation,
133
+ ) {
128
134
  try {
129
- await this.login_(actor);
135
+ await this.login_(actor, initialAuthorizationNavigation);
130
136
  } catch (e) {
131
137
  const loginEvent: GraffitiLoginEvent = new CustomEvent("login", {
132
138
  detail: {
@@ -137,7 +143,10 @@ export class Sessions {
137
143
  this.sessionEvents.dispatchEvent(loginEvent);
138
144
  }
139
145
  }
140
- protected async login_(actor: string) {
146
+ protected async login_(
147
+ actor: string,
148
+ initialAuthorizationNavigation: "assign" | "replace",
149
+ ) {
141
150
  // First look to see if we're already logged in
142
151
  const existingSession = this.loggedInSessions.find(
143
152
  (session) => session.actor === actor,
@@ -257,6 +266,7 @@ export class Sessions {
257
266
  firstAuthorizationEndpoint,
258
267
  actor,
259
268
  firstServices.map((s) => s.endpoint),
269
+ initialAuthorizationNavigation,
260
270
  );
261
271
  }
262
272
 
@@ -367,6 +377,7 @@ export class Sessions {
367
377
  authorizationEndpoint,
368
378
  actor,
369
379
  services.map((s) => s.endpoint),
380
+ "replace",
370
381
  );
371
382
  }
372
383
  }
@@ -131,6 +131,8 @@ const MESSAGE_LABEL_INVALID = 3;
131
131
  export interface GraffitiDecentralizedOptions {
132
132
  identityCreatorEndpoint?: string;
133
133
  defaultInboxEndpoints?: string[];
134
+ /** For login hosts that already have the application in the preceding history entry. */
135
+ replaceInitialLoginHistoryEntry?: boolean;
134
136
  }
135
137
 
136
138
  const CONCURRENCY = 128;
@@ -180,7 +182,13 @@ export class GraffitiDecentralized implements Graffiti {
180
182
 
181
183
  protected readonly defaultInboxEndpoints: string[];
182
184
  protected readonly identityCreatorEndpoint: string;
185
+ protected readonly replaceInitialLoginHistoryEntry: boolean;
183
186
  constructor(options?: GraffitiDecentralizedOptions) {
187
+ this.replaceInitialLoginHistoryEntry =
188
+ options?.replaceInitialLoginHistoryEntry ?? false;
189
+ if (this.replaceInitialLoginHistoryEntry) {
190
+ this.sessions.initialAuthorizationNavigation = "replace";
191
+ }
184
192
  this.defaultInboxEndpoints = options?.defaultInboxEndpoints ?? [
185
193
  "https://graffiti.actor/i/shared",
186
194
  ];
@@ -358,9 +366,24 @@ export class GraffitiDecentralized implements Graffiti {
358
366
  "redirect_uri",
359
367
  encodeURIComponent(window.location.toString()),
360
368
  );
361
- template
362
- ?.querySelector("#graffiti-login-new")
363
- ?.setAttribute("href", createUrl.toString());
369
+ const createLink = template?.querySelector<HTMLAnchorElement>(
370
+ "#graffiti-login-new",
371
+ );
372
+ createLink?.setAttribute("href", createUrl.toString());
373
+ if (this.replaceInitialLoginHistoryEntry) {
374
+ createLink?.addEventListener("click", (event) => {
375
+ if (
376
+ event.defaultPrevented ||
377
+ event.button !== 0 ||
378
+ event.metaKey ||
379
+ event.ctrlKey ||
380
+ event.shiftKey ||
381
+ event.altKey
382
+ ) return;
383
+ event.preventDefault();
384
+ window.location.replace(createUrl.toString());
385
+ });
386
+ }
364
387
 
365
388
  await this.modal?.open();
366
389
  } else {
@@ -425,7 +448,11 @@ export class GraffitiDecentralized implements Graffiti {
425
448
 
426
449
  const url = new URL("/forgot-handle", origin);
427
450
  url.searchParams.set("redirect_uri", window.location.toString());
428
- window.location.assign(url.toString());
451
+ if (this.replaceInitialLoginHistoryEntry) {
452
+ window.location.replace(url.toString());
453
+ } else {
454
+ window.location.assign(url.toString());
455
+ }
429
456
  } catch {
430
457
  alert("Enter a valid provider domain.");
431
458
  }