Skip to content

Commit

Permalink
Prevent page unload while mutating operations are in progress (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
robknight authored Oct 22, 2024
1 parent 73b6fbd commit 52b25c0
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 6 deletions.
7 changes: 7 additions & 0 deletions examples/test-app/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# test-app

## 1.0.14

### Patch Changes

- Updated dependencies
- @parcnet-js/app-connector@1.1.2

## 1.0.13

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion examples/test-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "test-app",
"version": "1.0.13",
"version": "1.0.14",
"private": true,
"type": "module",
"scripts": {
Expand Down
6 changes: 6 additions & 0 deletions packages/app-connector/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @parcnet-js/app-connector

## 1.1.2

### Patch Changes

- Allow user to cancel page unload while mutating operation in progress

## 1.1.1

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/app-connector/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@parcnet-js/app-connector",
"version": "1.1.1",
"version": "1.1.2",
"license": "GPL-3.0-or-later",
"type": "module",
"main": "dist/index.cjs",
Expand Down
48 changes: 44 additions & 4 deletions packages/app-connector/src/api_wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,17 @@ export class ParcnetPODCollectionWrapper {
#api: ParcnetRPCConnector;
#collectionId: string;
#subscriptionEmitters: Map<string, Emitter<SubscriptionEvents>>;
#unloadProtector: MutationUnloadProtector;

constructor(api: ParcnetRPCConnector, collectionId: string) {
constructor(
api: ParcnetRPCConnector,
collectionId: string,
unloadProtector: MutationUnloadProtector
) {
this.#api = api;
this.#collectionId = collectionId;
this.#subscriptionEmitters = new Map();
this.#unloadProtector = unloadProtector;
this.#api.on("subscription-update", (update) => {
this.#subscriptionEmitters
.get(update.subscriptionId)
Expand Down Expand Up @@ -84,24 +90,58 @@ export class ParcnetPODCollectionWrapper {
}

async insert(podData: PODData): Promise<void> {
return this.#api.pod.insert(this.#collectionId, podData);
return this.#unloadProtector.add(
this.#api.pod.insert(this.#collectionId, podData)
);
}

async delete(signature: string): Promise<void> {
return this.#api.pod.delete(this.#collectionId, signature);
return this.#unloadProtector.add(
this.#api.pod.delete(this.#collectionId, signature)
);
}
}

/**
* This class is used to prevent the page from being unloaded while there are
* pending mutations.
*/
class MutationUnloadProtector {
#mutations = new Set<Promise<unknown>>();

public constructor() {
window.addEventListener("beforeunload", (event: BeforeUnloadEvent) => {
if (this.#mutations.size > 0) {
event.preventDefault();
}
});
}

public add<T>(mutation: Promise<T>): Promise<T> {
this.#mutations.add(mutation);
void mutation.finally(() => {
this.#mutations.delete(mutation);
});
return mutation;
}
}

export class ParcnetPODWrapper {
#api: ParcnetRPCConnector;
#modalEmitter: ModalEmitter;
#unloadProtector: MutationUnloadProtector = new MutationUnloadProtector();

constructor(api: ParcnetRPCConnector, modalEmitter: ModalEmitter) {
this.#api = api;
this.#modalEmitter = modalEmitter;
}

collection(collectionId: string): ParcnetPODCollectionWrapper {
return new ParcnetPODCollectionWrapper(this.#api, collectionId);
return new ParcnetPODCollectionWrapper(
this.#api,
collectionId,
this.#unloadProtector
);
}

async sign(entries: PODEntries): Promise<PODData> {
Expand Down

0 comments on commit 52b25c0

Please sign in to comment.