@verdant-web/store 3.6.0 → 3.6.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.
@@ -1,10 +1,26 @@
1
1
  import { Client } from './client/Client.js';
2
2
  import { ExportData } from './metadata/Metadata.js';
3
3
  import { ReturnedFileData } from './files/FileStorage.js';
4
- export declare function createClientBackup(client: Client): Promise<Blob>;
4
+ type BackupClient = Pick<Client, 'export' | 'import'>;
5
+ export declare function createClientBackup(client: BackupClient): Promise<Blob>;
5
6
  export declare function readBackupFile(file: Blob): Promise<{
6
7
  data: ExportData;
7
8
  fileData: Omit<ReturnedFileData, "file">[];
8
9
  files: File[];
9
10
  }>;
10
- export declare function importClientBackup(client: Client, file: Blob): Promise<void>;
11
+ export declare function importClientBackup(client: BackupClient, file: Blob): Promise<void>;
12
+ /**
13
+ * Call this function in the app codebase which allows transfer to another origin
14
+ * to advertise the transfer.
15
+ */
16
+ export declare function advertiseTransferTo(client: BackupClient, destination: string): void;
17
+ /**
18
+ * Call this function in the app codebase which allows transfer from another origin
19
+ * to accept the transfer.
20
+ */
21
+ export declare function acceptTransferFrom(client: BackupClient, origin: string, onComplete?: () => void): void;
22
+ export declare function transferOrigins(client: BackupClient, from: string, to: string, handlers?: {
23
+ onStart?: () => void;
24
+ onComplete?: () => void;
25
+ }): Promise<void>;
26
+ export {};
@@ -46,4 +46,95 @@ export async function importClientBackup(client, file) {
46
46
  const importData = await readBackupFile(file);
47
47
  await client.import(importData);
48
48
  }
49
+ /**
50
+ * Call this function in the app codebase which allows transfer to another origin
51
+ * to advertise the transfer.
52
+ */
53
+ export function advertiseTransferTo(client, destination) {
54
+ // listen for 'transfer-accepted' and send transfer
55
+ window.addEventListener('message', (event) => {
56
+ if (event.data.type === 'transfer-accepted') {
57
+ if (event.origin != destination) {
58
+ console.error(`Received transfer message from unexpected origin: ${event.origin}`);
59
+ return;
60
+ }
61
+ console.info('Transfer accepted by', event.origin);
62
+ createClientBackup(client).then((file) => {
63
+ var _a;
64
+ const message = {
65
+ type: 'transfer',
66
+ file,
67
+ };
68
+ (_a = event.source) === null || _a === void 0 ? void 0 : _a.postMessage(message, {
69
+ targetOrigin: event.origin,
70
+ });
71
+ console.info('Transfer sent');
72
+ });
73
+ }
74
+ });
75
+ console.log('Advertising transfer to', destination);
76
+ const message = {
77
+ type: 'transfer-available',
78
+ };
79
+ window.parent.postMessage(message, {
80
+ targetOrigin: destination,
81
+ });
82
+ }
83
+ /**
84
+ * Call this function in the app codebase which allows transfer from another origin
85
+ * to accept the transfer.
86
+ */
87
+ export function acceptTransferFrom(client, origin, onComplete) {
88
+ console.log('Open to accepting transfer from', origin);
89
+ const frame = document.createElement('iframe');
90
+ frame.src = `${origin}`;
91
+ frame.style.display = 'none';
92
+ // listen for 'transfer-available' and begin transfer
93
+ window.addEventListener('message', async (event) => {
94
+ var _a;
95
+ if (event.data.type === 'transfer-available') {
96
+ if (event.origin !== origin) {
97
+ console.error(`Received transfer message from unexpected origin: ${event.origin}`);
98
+ return;
99
+ }
100
+ console.log('Transfer available');
101
+ const message = {
102
+ type: 'transfer-accepted',
103
+ };
104
+ (_a = frame.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(message, origin);
105
+ }
106
+ else if (event.data.type === 'transfer') {
107
+ console.info('Received transfer file');
108
+ const file = event.data.file;
109
+ await importClientBackup(client, file);
110
+ frame.remove();
111
+ console.info('Transfer complete');
112
+ onComplete === null || onComplete === void 0 ? void 0 : onComplete();
113
+ }
114
+ });
115
+ document.body.appendChild(frame);
116
+ }
117
+ export async function transferOrigins(client, from, to, handlers = {}) {
118
+ var _a;
119
+ if (window.localStorage.getItem('already-transferred')) {
120
+ return;
121
+ }
122
+ function handleComplete() {
123
+ var _a;
124
+ // remove query param
125
+ const url = new URL(window.location.href);
126
+ url.searchParams.delete('transfer');
127
+ window.history.replaceState({}, '', url.toString());
128
+ window.localStorage.setItem('already-transferred', 'true');
129
+ (_a = handlers.onComplete) === null || _a === void 0 ? void 0 : _a.call(handlers);
130
+ }
131
+ if (window.location.origin === to &&
132
+ new URLSearchParams(window.location.search).get('transfer')) {
133
+ (_a = handlers.onStart) === null || _a === void 0 ? void 0 : _a.call(handlers);
134
+ acceptTransferFrom(client, from, handleComplete);
135
+ }
136
+ else if (window.location.origin === from) {
137
+ advertiseTransferTo(client, to);
138
+ }
139
+ }
49
140
  //# sourceMappingURL=backup.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"backup.js","sourceRoot":"","sources":["../../src/backup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"backup.js","sourceRoot":"","sources":["../../src/backup.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdant-web/store",
3
- "version": "3.6.0",
3
+ "version": "3.6.1",
4
4
  "access": "public",
5
5
  "type": "module",
6
6
  "exports": {
package/src/backup.ts CHANGED
@@ -3,7 +3,10 @@ import Zip from 'jszip';
3
3
  import { ExportData } from './metadata/Metadata.js';
4
4
  import { ReturnedFileData } from './files/FileStorage.js';
5
5
 
6
- export async function createClientBackup(client: Client) {
6
+ // narrow type to just what's needed
7
+ type BackupClient = Pick<Client, 'export' | 'import'>;
8
+
9
+ export async function createClientBackup(client: BackupClient) {
7
10
  const exportData = await client.export();
8
11
  const zipFile = new Zip();
9
12
  zipFile.file('data.json', JSON.stringify(exportData.data));
@@ -54,7 +57,119 @@ export async function readBackupFile(file: Blob) {
54
57
  return importData;
55
58
  }
56
59
 
57
- export async function importClientBackup(client: Client, file: Blob) {
60
+ export async function importClientBackup(client: BackupClient, file: Blob) {
58
61
  const importData = await readBackupFile(file);
59
62
  await client.import(importData);
60
63
  }
64
+
65
+ /**
66
+ * Call this function in the app codebase which allows transfer to another origin
67
+ * to advertise the transfer.
68
+ */
69
+ export function advertiseTransferTo(client: BackupClient, destination: string) {
70
+ // listen for 'transfer-accepted' and send transfer
71
+ window.addEventListener('message', (event) => {
72
+ if (event.data.type === 'transfer-accepted') {
73
+ if (event.origin != destination) {
74
+ console.error(
75
+ `Received transfer message from unexpected origin: ${event.origin}`,
76
+ );
77
+ return;
78
+ }
79
+ console.info('Transfer accepted by', event.origin);
80
+
81
+ createClientBackup(client).then((file) => {
82
+ const message = {
83
+ type: 'transfer',
84
+ file,
85
+ };
86
+ event.source?.postMessage(message, {
87
+ targetOrigin: event.origin,
88
+ });
89
+ console.info('Transfer sent');
90
+ });
91
+ }
92
+ });
93
+
94
+ console.log('Advertising transfer to', destination);
95
+ const message = {
96
+ type: 'transfer-available',
97
+ };
98
+ window.parent.postMessage(message, {
99
+ targetOrigin: destination,
100
+ });
101
+ }
102
+
103
+ /**
104
+ * Call this function in the app codebase which allows transfer from another origin
105
+ * to accept the transfer.
106
+ */
107
+ export function acceptTransferFrom(
108
+ client: BackupClient,
109
+ origin: string,
110
+ onComplete?: () => void,
111
+ ) {
112
+ console.log('Open to accepting transfer from', origin);
113
+ const frame = document.createElement('iframe');
114
+ frame.src = `${origin}`;
115
+ frame.style.display = 'none';
116
+
117
+ // listen for 'transfer-available' and begin transfer
118
+ window.addEventListener('message', async (event) => {
119
+ if (event.data.type === 'transfer-available') {
120
+ if (event.origin !== origin) {
121
+ console.error(
122
+ `Received transfer message from unexpected origin: ${event.origin}`,
123
+ );
124
+ return;
125
+ }
126
+ console.log('Transfer available');
127
+ const message = {
128
+ type: 'transfer-accepted',
129
+ };
130
+ frame.contentWindow?.postMessage(message, origin);
131
+ } else if (event.data.type === 'transfer') {
132
+ console.info('Received transfer file');
133
+ const file = event.data.file;
134
+ await importClientBackup(client, file);
135
+ frame.remove();
136
+ console.info('Transfer complete');
137
+ onComplete?.();
138
+ }
139
+ });
140
+
141
+ document.body.appendChild(frame);
142
+ }
143
+
144
+ export async function transferOrigins(
145
+ client: BackupClient,
146
+ from: string,
147
+ to: string,
148
+ handlers: {
149
+ onStart?: () => void;
150
+ onComplete?: () => void;
151
+ } = {},
152
+ ) {
153
+ if (window.localStorage.getItem('already-transferred')) {
154
+ return;
155
+ }
156
+
157
+ function handleComplete() {
158
+ // remove query param
159
+ const url = new URL(window.location.href);
160
+ url.searchParams.delete('transfer');
161
+ window.history.replaceState({}, '', url.toString());
162
+ window.localStorage.setItem('already-transferred', 'true');
163
+ handlers.onComplete?.();
164
+ }
165
+
166
+ if (
167
+ window.location.origin === to &&
168
+ new URLSearchParams(window.location.search).get('transfer')
169
+ ) {
170
+ handlers.onStart?.();
171
+ acceptTransferFrom(client, from, handleComplete);
172
+ } else if (window.location.origin === from) {
173
+ advertiseTransferTo(client, to);
174
+ }
175
+ }