@openmrs/esm-offline 3.4.1-pre.96 → 4.0.0-pre.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,17 +1,17 @@
1
- @openmrs/esm-offline:build: cache hit, replaying output 44e1f49aa8c09bf2
1
+ @openmrs/esm-offline:build: cache hit, replaying output 1364214084b08f2a
2
2
  @openmrs/esm-offline:build: $ webpack --mode=production
3
- @openmrs/esm-offline:build: asset openmrs-esm-offline.js 112 KiB [emitted] [minimized] (name: main) 1 related asset
4
- @openmrs/esm-offline:build: orphan modules 164 KiB [orphan] 26 modules
3
+ @openmrs/esm-offline:build: asset openmrs-esm-offline.js 112 KiB [emitted] [minimized] (name: main) 1 related asset
4
+ @openmrs/esm-offline:build: orphan modules 164 KiB [orphan] 26 modules
5
5
  @openmrs/esm-offline:build: runtime modules 2.02 KiB 7 modules
6
- @openmrs/esm-offline:build: built modules 177 KiB [built]
6
+ @openmrs/esm-offline:build: built modules 177 KiB [built]
7
7
  @openmrs/esm-offline:build:  cacheable modules 176 KiB
8
- @openmrs/esm-offline:build:  modules by path ../../../node_modules/systemjs-webpack-interop/ 3.27 KiB
9
- @openmrs/esm-offline:build:  ../../../node_modules/systemjs-webpack-interop/auto-public-path/1.js 89 bytes [built] [code generated]
10
- @openmrs/esm-offline:build:  ../../../node_modules/systemjs-webpack-interop/auto-public-path/auto-public-path.js 846 bytes [built] [code generated]
11
- @openmrs/esm-offline:build:  ../../../node_modules/systemjs-webpack-interop/public-path.js 2.36 KiB [built] [code generated]
12
- @openmrs/esm-offline:build:  ./src/index.ts + 16 modules 149 KiB [built] [code generated]
13
- @openmrs/esm-offline:build:  ../../../node_modules/regenerator-runtime/runtime.js 24.3 KiB [built] [code generated]
14
- @openmrs/esm-offline:build:  modules by path external "@openmrs/ 84 bytes
15
- @openmrs/esm-offline:build:  external "@openmrs/esm-api" 42 bytes [built] [code generated]
16
- @openmrs/esm-offline:build:  external "@openmrs/esm-state" 42 bytes [built] [code generated]
17
- @openmrs/esm-offline:build: webpack 5.70.0 compiled successfully in 8264 ms
8
+ @openmrs/esm-offline:build:  modules by path ../../../node_modules/systemjs-webpack-interop/ 3.27 KiB
9
+ @openmrs/esm-offline:build:  ../../../node_modules/systemjs-webpack-interop/auto-public-path/1.js 89 bytes [built] [code generated]
10
+ @openmrs/esm-offline:build:  ../../../node_modules/systemjs-webpack-interop/auto-public-path/auto-public-path.js 846 bytes [built] [code generated]
11
+ @openmrs/esm-offline:build:  ../../../node_modules/systemjs-webpack-interop/public-path.js 2.36 KiB [built] [code generated]
12
+ @openmrs/esm-offline:build:  ./src/index.ts + 16 modules 149 KiB [built] [code generated]
13
+ @openmrs/esm-offline:build:  ../../../node_modules/regenerator-runtime/runtime.js 24.3 KiB [built] [code generated]
14
+ @openmrs/esm-offline:build:  modules by path external "@openmrs/ 84 bytes
15
+ @openmrs/esm-offline:build:  external "@openmrs/esm-api" 42 bytes [built] [code generated]
16
+ @openmrs/esm-offline:build:  external "@openmrs/esm-state" 42 bytes [built] [code generated]
17
+ @openmrs/esm-offline:build: webpack 5.70.0 compiled successfully in 10780 ms
@@ -0,0 +1,2 @@
1
+ @openmrs/esm-offline:lint: cache hit, replaying output ea6024db99e36a2e
2
+ @openmrs/esm-offline:lint: $ eslint src --ext ts,tsx
@@ -0,0 +1,123 @@
1
+ @openmrs/esm-offline:test: cache hit, replaying output 1a48812f0c130a46
2
+ @openmrs/esm-offline:test: $ jest --config jest.config.js --passWithNoTests
3
+ @openmrs/esm-offline:test: PASS src/sync.test.ts (14.915 s)
4
+ @openmrs/esm-offline:test: PASS src/dynamic-offline-data.test.ts (16.473 s)
5
+ @openmrs/esm-offline:test:  ● Console
6
+ @openmrs/esm-offline:test: 
7
+ @openmrs/esm-offline:test:  console.warn
8
+ @openmrs/esm-offline:test:  The query {"type":"test","users":"00000000-0000-0000-0000-000000000000"} on dynamicOfflineData would benefit of a compound index [type+users]
9
+ @openmrs/esm-offline:test: 
10
+ @openmrs/esm-offline:test:  149 | const db = new OfflineDb();
11
+ @openmrs/esm-offline:test:  150 | return await db.dynamicOfflineData
12
+ @openmrs/esm-offline:test:  > 151 | .where(filter)
13
+ @openmrs/esm-offline:test:  | ^
14
+ @openmrs/esm-offline:test:  152 | .toArray()
15
+ @openmrs/esm-offline:test:  153 | .catch(Dexie.errnames.DatabaseClosed, () => []);
16
+ @openmrs/esm-offline:test:  154 | }
17
+ @openmrs/esm-offline:test: 
18
+ @openmrs/esm-offline:test:  at Table.Object.<anonymous>.Table.where (../../../node_modules/dexie/src/classes/table/table.ts:118:42)
19
+ @openmrs/esm-offline:test:  at where (src/dynamic-offline-data.ts:151:6)
20
+ @openmrs/esm-offline:test:  at Object.getDynamicOfflineDataEntriesFor [as getDynamicOfflineDataEntries] (src/dynamic-offline-data.ts:135:16)
21
+ @openmrs/esm-offline:test:  at Object.<anonymous> (src/dynamic-offline-data.test.ts:28:21)
22
+ @openmrs/esm-offline:test: 
23
+ @openmrs/esm-offline:test:  console.warn
24
+ @openmrs/esm-offline:test:  The query {"type":"test","users":"00000000-0000-0000-0000-000000000000"} on dynamicOfflineData would benefit of a compound index [type+users]
25
+ @openmrs/esm-offline:test: 
26
+ @openmrs/esm-offline:test:  149 | const db = new OfflineDb();
27
+ @openmrs/esm-offline:test:  150 | return await db.dynamicOfflineData
28
+ @openmrs/esm-offline:test:  > 151 | .where(filter)
29
+ @openmrs/esm-offline:test:  | ^
30
+ @openmrs/esm-offline:test:  152 | .toArray()
31
+ @openmrs/esm-offline:test:  153 | .catch(Dexie.errnames.DatabaseClosed, () => []);
32
+ @openmrs/esm-offline:test:  154 | }
33
+ @openmrs/esm-offline:test: 
34
+ @openmrs/esm-offline:test:  at Table.Object.<anonymous>.Table.where (../../../node_modules/dexie/src/classes/table/table.ts:118:42)
35
+ @openmrs/esm-offline:test:  at where (src/dynamic-offline-data.ts:151:6)
36
+ @openmrs/esm-offline:test:  at Object.getDynamicOfflineDataEntriesFor [as getDynamicOfflineDataEntries] (src/dynamic-offline-data.ts:135:16)
37
+ @openmrs/esm-offline:test:  at Object.<anonymous> (src/dynamic-offline-data.test.ts:39:21)
38
+ @openmrs/esm-offline:test: 
39
+ @openmrs/esm-offline:test:  console.warn
40
+ @openmrs/esm-offline:test:  The query {"type":"test","users":"user-id-1"} on dynamicOfflineData would benefit of a compound index [type+users]
41
+ @openmrs/esm-offline:test: 
42
+ @openmrs/esm-offline:test:  149 | const db = new OfflineDb();
43
+ @openmrs/esm-offline:test:  150 | return await db.dynamicOfflineData
44
+ @openmrs/esm-offline:test:  > 151 | .where(filter)
45
+ @openmrs/esm-offline:test:  | ^
46
+ @openmrs/esm-offline:test:  152 | .toArray()
47
+ @openmrs/esm-offline:test:  153 | .catch(Dexie.errnames.DatabaseClosed, () => []);
48
+ @openmrs/esm-offline:test:  154 | }
49
+ @openmrs/esm-offline:test: 
50
+ @openmrs/esm-offline:test:  at Table.Object.<anonymous>.Table.where (../../../node_modules/dexie/src/classes/table/table.ts:118:42)
51
+ @openmrs/esm-offline:test:  at Object.where [as getDynamicOfflineDataEntriesFor] (src/dynamic-offline-data.ts:151:6)
52
+ @openmrs/esm-offline:test:  at Object.<anonymous> (src/dynamic-offline-data.test.ts:47:79)
53
+ @openmrs/esm-offline:test: 
54
+ @openmrs/esm-offline:test:  console.warn
55
+ @openmrs/esm-offline:test:  The query {"type":"test","identifier":"123","users":"00000000-0000-0000-0000-000000000000"} on dynamicOfflineData would benefit of a compound index [type+identifier+users]
56
+ @openmrs/esm-offline:test: 
57
+ @openmrs/esm-offline:test:  233 | const db = new OfflineDb();
58
+ @openmrs/esm-offline:test:  234 | const existingEntry = await db.dynamicOfflineData
59
+ @openmrs/esm-offline:test:  > 235 | .get({
60
+ @openmrs/esm-offline:test:  | ^
61
+ @openmrs/esm-offline:test:  236 | type,
62
+ @openmrs/esm-offline:test:  237 | identifier,
63
+ @openmrs/esm-offline:test:  238 | users: userId,
64
+ @openmrs/esm-offline:test: 
65
+ @openmrs/esm-offline:test:  at Table.Object.<anonymous>.Table.where (../../../node_modules/dexie/src/classes/table/table.ts:118:42)
66
+ @openmrs/esm-offline:test:  at Table.Object.<anonymous>.Table.get (../../../node_modules/dexie/src/classes/table/table.ts:77:19)
67
+ @openmrs/esm-offline:test:  at get (src/dynamic-offline-data.ts:235:6)
68
+ @openmrs/esm-offline:test:  at Object.removeDynamicOfflineDataFor [as removeDynamicOfflineData] (src/dynamic-offline-data.ts:218:16)
69
+ @openmrs/esm-offline:test:  at Object.<anonymous> (src/dynamic-offline-data.test.ts:56:5)
70
+ @openmrs/esm-offline:test: 
71
+ @openmrs/esm-offline:test:  console.warn
72
+ @openmrs/esm-offline:test:  The query {"type":"test","users":"00000000-0000-0000-0000-000000000000"} on dynamicOfflineData would benefit of a compound index [type+users]
73
+ @openmrs/esm-offline:test: 
74
+ @openmrs/esm-offline:test:  149 | const db = new OfflineDb();
75
+ @openmrs/esm-offline:test:  150 | return await db.dynamicOfflineData
76
+ @openmrs/esm-offline:test:  > 151 | .where(filter)
77
+ @openmrs/esm-offline:test:  | ^
78
+ @openmrs/esm-offline:test:  152 | .toArray()
79
+ @openmrs/esm-offline:test:  153 | .catch(Dexie.errnames.DatabaseClosed, () => []);
80
+ @openmrs/esm-offline:test:  154 | }
81
+ @openmrs/esm-offline:test: 
82
+ @openmrs/esm-offline:test:  at Table.Object.<anonymous>.Table.where (../../../node_modules/dexie/src/classes/table/table.ts:118:42)
83
+ @openmrs/esm-offline:test:  at where (src/dynamic-offline-data.ts:151:6)
84
+ @openmrs/esm-offline:test:  at Object.getDynamicOfflineDataEntriesFor [as getDynamicOfflineDataEntries] (src/dynamic-offline-data.ts:135:16)
85
+ @openmrs/esm-offline:test:  at Object.<anonymous> (src/dynamic-offline-data.test.ts:57:21)
86
+ @openmrs/esm-offline:test: 
87
+ @openmrs/esm-offline:test:  console.warn
88
+ @openmrs/esm-offline:test:  The query {"type":"test","identifier":"123","users":"user-id-1"} on dynamicOfflineData would benefit of a compound index [type+identifier+users]
89
+ @openmrs/esm-offline:test: 
90
+ @openmrs/esm-offline:test:  233 | const db = new OfflineDb();
91
+ @openmrs/esm-offline:test:  234 | const existingEntry = await db.dynamicOfflineData
92
+ @openmrs/esm-offline:test:  > 235 | .get({
93
+ @openmrs/esm-offline:test:  | ^
94
+ @openmrs/esm-offline:test:  236 | type,
95
+ @openmrs/esm-offline:test:  237 | identifier,
96
+ @openmrs/esm-offline:test:  238 | users: userId,
97
+ @openmrs/esm-offline:test: 
98
+ @openmrs/esm-offline:test:  at Table.Object.<anonymous>.Table.where (../../../node_modules/dexie/src/classes/table/table.ts:118:42)
99
+ @openmrs/esm-offline:test:  at Table.Object.<anonymous>.Table.get (../../../node_modules/dexie/src/classes/table/table.ts:77:19)
100
+ @openmrs/esm-offline:test:  at Object.get [as removeDynamicOfflineDataFor] (src/dynamic-offline-data.ts:235:6)
101
+ @openmrs/esm-offline:test:  at Object.<anonymous> (src/dynamic-offline-data.test.ts:64:66)
102
+ @openmrs/esm-offline:test: 
103
+ @openmrs/esm-offline:test:  console.warn
104
+ @openmrs/esm-offline:test:  The query {"type":"test","users":"user-id-2"} on dynamicOfflineData would benefit of a compound index [type+users]
105
+ @openmrs/esm-offline:test: 
106
+ @openmrs/esm-offline:test:  149 | const db = new OfflineDb();
107
+ @openmrs/esm-offline:test:  150 | return await db.dynamicOfflineData
108
+ @openmrs/esm-offline:test:  > 151 | .where(filter)
109
+ @openmrs/esm-offline:test:  | ^
110
+ @openmrs/esm-offline:test:  152 | .toArray()
111
+ @openmrs/esm-offline:test:  153 | .catch(Dexie.errnames.DatabaseClosed, () => []);
112
+ @openmrs/esm-offline:test:  154 | }
113
+ @openmrs/esm-offline:test: 
114
+ @openmrs/esm-offline:test:  at Table.Object.<anonymous>.Table.where (../../../node_modules/dexie/src/classes/table/table.ts:118:42)
115
+ @openmrs/esm-offline:test:  at Object.where [as getDynamicOfflineDataEntriesFor] (src/dynamic-offline-data.ts:151:6)
116
+ @openmrs/esm-offline:test:  at Object.<anonymous> (src/dynamic-offline-data.test.ts:66:79)
117
+ @openmrs/esm-offline:test: 
118
+ @openmrs/esm-offline:test: 
119
+ @openmrs/esm-offline:test: Test Suites: 2 passed, 2 total
120
+ @openmrs/esm-offline:test: Tests: 14 passed, 14 total
121
+ @openmrs/esm-offline:test: Snapshots: 0 total
122
+ @openmrs/esm-offline:test: Time: 20.647 s
123
+ @openmrs/esm-offline:test: Ran all test suites.
@@ -0,0 +1,2 @@
1
+ @openmrs/esm-offline:typescript: cache hit, replaying output 7455ab648603336c
2
+ @openmrs/esm-offline:typescript: $ tsc
@@ -0,0 +1,156 @@
1
+ /**
2
+ * A handler for synchronizing dynamically declared offline data.
3
+ * Can be setup using the {@link setupDynamicOfflineDataHandler} function.
4
+ */
5
+ export interface DynamicOfflineDataHandler {
6
+ /**
7
+ * A string uniquely identifying the handler.
8
+ */
9
+ id: string;
10
+ /**
11
+ * The type of offline data handled by this handler.
12
+ * See {@link DynamicOfflineData.type} for details.
13
+ */
14
+ type: string;
15
+ /**
16
+ * A human-readable string representing the handler.
17
+ * If provided, the handler can be rendered in the UI using that string.
18
+ */
19
+ displayName?: string;
20
+ /**
21
+ * Evaluates whether the given offline data is correctly synced at this point in time from the perspective
22
+ * of this single handler.
23
+ * If `false`, the handler would have to (re-)sync the data in order for offline mode to properly work.
24
+ * @param identifier The identifier of the offline data. See {@link DynamicOfflineData} for details.
25
+ * @param abortSignal An {@link AbortSignal} which can be used to cancel the operation.
26
+ */
27
+ isSynced(identifier: string, abortSignal?: AbortSignal): Promise<boolean>;
28
+ /**
29
+ * Synchronizes the given offline data.
30
+ * @param identifier The identifier of the offline data. See {@link DynamicOfflineData} for details.
31
+ * @param abortSignal An {@link AbortSignal} which can be used to cancel the operation.
32
+ */
33
+ sync(identifier: string, abortSignal?: AbortSignal): Promise<void>;
34
+ }
35
+ /**
36
+ * Represents the registration of a single dynamic offline data entry.
37
+ */
38
+ export interface DynamicOfflineData {
39
+ /**
40
+ * The internal ID of the data entry, as assigned by the IndexedDB where it is stored.
41
+ */
42
+ id?: number;
43
+ /**
44
+ * The underlying type used for categorizing the data entry.
45
+ * Examples could be `"patient"` or `"form"`.
46
+ */
47
+ type: string;
48
+ /**
49
+ * The externally provided identifier of the data entry.
50
+ * This is typically the ID of the resource as assigned by a remote API.
51
+ */
52
+ identifier: string;
53
+ /**
54
+ * The UUIDs of the users who need this data entry available offline.
55
+ */
56
+ users: Array<string>;
57
+ /**
58
+ * If this entry has already been synced, returns the result of that last sync attempt.
59
+ * Otherwise this is `undefined`.
60
+ */
61
+ syncState?: DynamicOfflineDataSyncState;
62
+ }
63
+ /**
64
+ * Represents the result of syncing a given {@link DynamicOfflineData} entry.
65
+ */
66
+ export interface DynamicOfflineDataSyncState {
67
+ /**
68
+ * The time when the entry has been synced the last time.
69
+ */
70
+ syncedOn: Date;
71
+ /**
72
+ * The ID of the user who has triggered the data synchronization.
73
+ */
74
+ syncedBy: string;
75
+ /**
76
+ * The IDs of the handlers which successfully synchronized their data.
77
+ */
78
+ succeededHandlers: Array<string>;
79
+ /**
80
+ * The IDs of the handlers which failed to synchronize their data.
81
+ */
82
+ erroredHandlers: Array<string>;
83
+ /**
84
+ * A collection of the errors caught while synchronizing, per handler.
85
+ */
86
+ errors: Array<{
87
+ handlerId: string;
88
+ message: string;
89
+ }>;
90
+ }
91
+ /**
92
+ * Returns all handlers which have been setup using the {@link setupDynamicOfflineDataHandler} function.
93
+ */
94
+ export declare function getDynamicOfflineDataHandlers(): DynamicOfflineDataHandler[];
95
+ /**
96
+ * Sets up a handler for synchronizing dynamic offline data.
97
+ * See {@link DynamicOfflineDataHandler} for details.
98
+ * @param handler The handler to be setup.
99
+ */
100
+ export declare function setupDynamicOfflineDataHandler(handler: DynamicOfflineDataHandler): void;
101
+ /**
102
+ * Returns all {@link DynamicOfflineData} entries which registered for the currently logged in user.
103
+ * Optionally returns only entries of a given type.
104
+ * @param type The type of the entries to be returned. If `undefined`, returns all types.
105
+ */
106
+ export declare function getDynamicOfflineDataEntries(type?: string): Promise<Array<DynamicOfflineData>>;
107
+ /**
108
+ * Returns all {@link DynamicOfflineData} entries which registered for the given user.
109
+ * Optionally returns only entries of a given type.
110
+ * @param userId The ID of the user whose entries are to be retrieved.
111
+ * @param type The type of the entries to be returned. If `undefined`, returns all types.
112
+ */
113
+ export declare function getDynamicOfflineDataEntriesFor(userId: string, type?: string): Promise<Array<DynamicOfflineData>>;
114
+ /**
115
+ * Declares that dynamic offline data of the given {@link type} with the given {@link identifier}
116
+ * should be made available offline for the currently logged in user.
117
+ * @param type The type of the offline data. See {@link DynamicOfflineData} for details.
118
+ * @param identifier The identifier of the offline data. See {@link DynamicOfflineData} for details.
119
+ */
120
+ export declare function putDynamicOfflineData(type: string, identifier: string): Promise<void>;
121
+ /**
122
+ * Declares that dynamic offline data of the given {@link type} with the given {@link identifier}
123
+ * should be made available offline for the user with the given ID.
124
+ * @param userId The ID of the user for whom the dynamic offline data should be made available.
125
+ * @param type The type of the offline data. See {@link DynamicOfflineData} for details.
126
+ * @param identifier The identifier of the offline data. See {@link DynamicOfflineData} for details.
127
+ */
128
+ export declare function putDynamicOfflineDataFor(userId: string, type: string, identifier: string): Promise<void>;
129
+ /**
130
+ * Declares that dynamic offline data of the given {@link type} with the given {@link identifier}
131
+ * no longer needs to be available offline for the currently logged in user.
132
+ * @param type The type of the offline data. See {@link DynamicOfflineData} for details.
133
+ * @param identifier The identifier of the offline data. See {@link DynamicOfflineData} for details.
134
+ */
135
+ export declare function removeDynamicOfflineData(type: string, identifier: string): Promise<void>;
136
+ /**
137
+ * Declares that dynamic offline data of the given {@link type} with the given {@link identifier}
138
+ * no longer needs to be available offline for the user with the given ID.
139
+ * @param userId The ID of the user who doesn't require the specified offline data.
140
+ * @param type The type of the offline data. See {@link DynamicOfflineData} for details.
141
+ * @param identifier The identifier of the offline data. See {@link DynamicOfflineData} for details.
142
+ */
143
+ export declare function removeDynamicOfflineDataFor(userId: string, type: string, identifier: string): Promise<void>;
144
+ /**
145
+ * Synchronizes all offline data entries of the given {@link type} for the currently logged in user.
146
+ * @param type The type of the offline data. See {@link DynamicOfflineData} for details.
147
+ * @param abortSignal An {@link AbortSignal} which can be used to cancel the operation.
148
+ */
149
+ export declare function syncAllDynamicOfflineData(type: string, abortSignal?: AbortSignal): Promise<void>;
150
+ /**
151
+ * Synchronizes a single offline data entry of the given {@link type} for the currently logged in user.
152
+ * @param type The type of the offline data. See {@link DynamicOfflineData} for details.
153
+ * @param identifier The identifier of the offline data. See {@link DynamicOfflineData} for details.
154
+ * @param abortSignal An {@link AbortSignal} which can be used to cancel the operation.
155
+ */
156
+ export declare function syncDynamicOfflineData(type: string, identifier: string, abortSignal?: AbortSignal): Promise<void>;
@@ -0,0 +1 @@
1
+ import "fake-indexeddb/auto";
@@ -0,0 +1,9 @@
1
+ export * from "./service-worker";
2
+ export * from "./service-worker-http-headers";
3
+ export * from "./service-worker-messaging";
4
+ export * from "./mode";
5
+ export * from "./sync";
6
+ export * from "./uuid";
7
+ export * from "./offline-patient-data";
8
+ export * from "./dynamic-offline-data";
9
+ export { getOfflineDb } from "./offline-db";
package/dist/mode.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ /** @module @category Offline */
2
+ export declare type OfflineMode = "on" | "off" | "unavailable";
3
+ export interface OfflineModeResult {
4
+ current: OfflineMode;
5
+ notAvailable: boolean;
6
+ active: boolean;
7
+ }
8
+ export declare function getCurrentOfflineMode(): OfflineModeResult;
9
+ export declare function setCurrentOfflineMode(mode: OfflineMode): void;
10
+ export declare function activateOfflineCapability(): Promise<void>;
@@ -0,0 +1,20 @@
1
+ import Dexie, { Table } from "dexie";
2
+ import { DynamicOfflineData } from "./dynamic-offline-data";
3
+ import { SyncItem } from "./sync";
4
+ /**
5
+ * Accesses the central IndexedDB used by the `esm-offline` module to persist offline related state.
6
+ * Leverages the `dexie` library for IndexedDB management.
7
+ */
8
+ export declare class OfflineDb extends Dexie {
9
+ /**
10
+ * The table used to store the data of the offline synchronization queue (aka "sync queue" / "offline actions").
11
+ */
12
+ syncQueue: Table<SyncItem, number>;
13
+ dynamicOfflineData: Table<DynamicOfflineData, number>;
14
+ constructor();
15
+ }
16
+ /**
17
+ * @internal Temporarily added for esm-offline-tools-app and workarounds. Please don't use elsewhere.
18
+ * @deprecated Should/Will be removed in the future per the above reason.
19
+ */
20
+ export declare function getOfflineDb(): OfflineDb;
@@ -0,0 +1,30 @@
1
+ /** @deprecated Will be removed once all modules have been migrated to the new dynamic offline data API. */
2
+ export interface OfflinePatientDataSyncStore {
3
+ offlinePatientDataSyncState: Record<string, OfflinePatientDataSyncState>;
4
+ handlers: Record<string, OfflinePatientDataSyncHandler>;
5
+ }
6
+ /** @deprecated Will be removed once all modules have been migrated to the new dynamic offline data API. */
7
+ export interface OfflinePatientDataSyncState {
8
+ readonly timestamp: Date;
9
+ readonly syncingHandlers: Array<string>;
10
+ readonly syncedHandlers: Array<string>;
11
+ readonly failedHandlers: Array<string>;
12
+ readonly errors: Record<string, string>;
13
+ abort(): boolean;
14
+ }
15
+ /** @deprecated Will be removed once all modules have been migrated to the new dynamic offline data API. */
16
+ export interface OfflinePatientDataSyncHandler {
17
+ readonly displayName: string;
18
+ onOfflinePatientAdded(args: OfflinePatientArgs): Promise<void>;
19
+ }
20
+ /** @deprecated Will be removed once all modules have been migrated to the new dynamic offline data API. */
21
+ export interface OfflinePatientArgs {
22
+ patientUuid: string;
23
+ signal: AbortSignal;
24
+ }
25
+ /** @deprecated Will be removed once all modules have been migrated to the new dynamic offline data API. */
26
+ export declare function getOfflinePatientDataStore(): import("unistore").Store<OfflinePatientDataSyncStore>;
27
+ /** @deprecated Will be removed once all modules have been migrated to the new dynamic offline data API. */
28
+ export declare function registerOfflinePatientHandler(identifier: string, handler: OfflinePatientDataSyncHandler): void;
29
+ /** @deprecated Will be removed once all modules have been migrated to the new dynamic offline data API. */
30
+ export declare function syncOfflinePatientData(patientUuid: string): Promise<void>;
@@ -0,0 +1,8 @@
1
+ export { OfflineMode, OfflineModeResult, getCurrentOfflineMode } from "./mode";
2
+ export * from "./offline-patient-data";
3
+ export * from "./service-worker-messaging";
4
+ export * from "./service-worker-http-headers";
5
+ export * from "./uuid";
6
+ export { QueueItemDescriptor, SyncItem, SyncProcessOptions, queueSynchronizationItem, getSynchronizationItem, getSynchronizationItems, getFullSynchronizationItems, getFullSynchronizationItemsFor, canBeginEditSynchronizationItemsOfType, beginEditSynchronizationItem, deleteSynchronizationItem, setupOfflineSync, } from "./sync";
7
+ export * from "./dynamic-offline-data";
8
+ export { getOfflineDb } from "./offline-db";
@@ -0,0 +1,36 @@
1
+ /** @module @category Offline */
2
+ export declare const omrsOfflineResponseBodyHttpHeaderName = "x-omrs-offline-response-body";
3
+ export declare const omrsOfflineResponseStatusHttpHeaderName = "x-omrs-offline-response-status";
4
+ export declare const omrsOfflineCachingStrategyHttpHeaderName = "x-omrs-offline-caching-strategy";
5
+ /**
6
+ *
7
+ *
8
+ * * `cache-or-network`: The default strategy, equal to the absence of this header.
9
+ * The SW attempts to resolve the request via the network, but falls back to the cache if required.
10
+ * The service worker decides the strategy to be used.
11
+ * * `network-first`: See https://developers.google.com/web/tools/workbox/modules/workbox-strategies#network_first_network_falling_back_to_cache.
12
+ */
13
+ export declare type OmrsOfflineCachingStrategy = "network-only-or-cache-only" | "network-first";
14
+ /**
15
+ * Defines the keys of the custom headers which can be appended to an HTTP request.
16
+ * HTTP requests with these headers are handled in a special way by the SPA's service worker.
17
+ */
18
+ export declare type OmrsOfflineHttpHeaders = {
19
+ /**
20
+ * If the client is offline and the request cannot be read from the cache (i.e. if there is no way
21
+ * to receive any kind of data for this request), the service worker will return a response with
22
+ * the body in this header.
23
+ */
24
+ [omrsOfflineResponseBodyHttpHeaderName]?: string;
25
+ /**
26
+ * If the client is offline and the request cannot be read from the cache (i.e. if there is no way
27
+ * to receive any kind of data for this request), the service worker will return a response with
28
+ * the status code defined in this header.
29
+ */
30
+ [omrsOfflineResponseStatusHttpHeaderName]?: `${number}`;
31
+ /**
32
+ * Instructs the service worker to use a specific caching strategy for this request.
33
+ */
34
+ [omrsOfflineCachingStrategyHttpHeaderName]?: OmrsOfflineCachingStrategy;
35
+ };
36
+ export declare type OmrsOfflineHttpHeaderNames = keyof OmrsOfflineHttpHeaders;
@@ -0,0 +1,28 @@
1
+ /** @module @category Offline */
2
+ import type { ImportMap } from "@openmrs/esm-globals";
3
+ import { OmrsOfflineCachingStrategy } from "./service-worker-http-headers";
4
+ /**
5
+ * Sends the specified message to the application's service worker.
6
+ * @param message The message to be sent.
7
+ * @returns A promise which completes when the message has been successfully processed by the Service Worker.
8
+ */
9
+ export declare function messageOmrsServiceWorker(message: KnownOmrsServiceWorkerMessages): Promise<MessageServiceWorkerResult<any>>;
10
+ export interface OmrsServiceWorkerMessage<MessageTypeTypeIdentifier extends string> {
11
+ type: MessageTypeTypeIdentifier;
12
+ }
13
+ export interface OnImportMapChangedMessage extends OmrsServiceWorkerMessage<"onImportMapChanged"> {
14
+ importMap: ImportMap;
15
+ }
16
+ export interface ClearDynamicRoutesMessage extends OmrsServiceWorkerMessage<"clearDynamicRoutes"> {
17
+ }
18
+ export interface RegisterDynamicRouteMessage extends OmrsServiceWorkerMessage<"registerDynamicRoute"> {
19
+ pattern?: string;
20
+ url?: string;
21
+ strategy?: OmrsOfflineCachingStrategy;
22
+ }
23
+ export declare type KnownOmrsServiceWorkerMessages = OnImportMapChangedMessage | ClearDynamicRoutesMessage | RegisterDynamicRouteMessage;
24
+ export interface MessageServiceWorkerResult<T> {
25
+ success: boolean;
26
+ result?: T;
27
+ error?: string;
28
+ }
@@ -0,0 +1,18 @@
1
+ import { Workbox } from "workbox-window";
2
+ /**
3
+ * If not yet registered, registers the application's global Service Worker.
4
+ * Throws if registration is not possible.
5
+ * @param scriptURL The service worker script associated with this instance.
6
+ * @param [registerOptions] The service worker options associated with this instance.
7
+ * @returns A promise which resolves to the registered {@link Workbox} instance which manages the SW.
8
+ */
9
+ export declare function registerOmrsServiceWorker(scriptUrl: string, registerOptions?: object): Promise<Workbox>;
10
+ /**
11
+ * If a service worker has been registered, returns a promise that resolves to a {@link Workbox}
12
+ * instance which is used by the application to manage that service worker.
13
+ *
14
+ * If no service worker has been registered (e.g. when the application is built without offline specific features),
15
+ * returns a promise which immediately resolves to `undefined`.
16
+ * @returns A promise which either resolves to `undefined` or to the app's {@link Workbox} instance.
17
+ */
18
+ export declare function getOmrsServiceWorker(): Promise<Workbox | undefined>;
package/dist/sync.d.ts ADDED
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Defines an item queued up in the offline synchronization queue.
3
+ * A `SyncItem` contains both meta information about the item in the sync queue, as well as the
4
+ * actual data to be synchronized (i.e. the item's `content`).
5
+ */
6
+ export interface SyncItem<T = any> {
7
+ id?: number;
8
+ userId: string;
9
+ type: string;
10
+ content: T;
11
+ createdOn: Date;
12
+ descriptor: QueueItemDescriptor;
13
+ lastError?: {
14
+ name?: string;
15
+ message?: string;
16
+ };
17
+ }
18
+ /**
19
+ * Contains information about the sync item which has been provided externally by the caller
20
+ * who added the item to the queue.
21
+ * This information is all optional, but, when provided while enqueuing the item, can be used in other
22
+ * locations to better represent the sync item, e.g. in the UI.
23
+ */
24
+ export interface QueueItemDescriptor {
25
+ id?: string;
26
+ dependencies?: Array<{
27
+ id: string;
28
+ type: string;
29
+ }>;
30
+ patientUuid?: string;
31
+ displayName?: string;
32
+ }
33
+ /**
34
+ * A function which, when invoked, performs the actual client-server synchronization of the given
35
+ * `item` (which is the actual data to be synchronized).
36
+ * The function receives additional `options` which provide additional data that can be used
37
+ * for synchronizing.
38
+ */
39
+ export declare type ProcessSyncItem<T> = (item: T, options: SyncProcessOptions<T>) => Promise<any>;
40
+ /**
41
+ * Additional data which can be used for synchronizing data in a {@link ProcessSyncItem} function.
42
+ */
43
+ export interface SyncProcessOptions<T> {
44
+ abort: AbortController;
45
+ userId: string;
46
+ index: number;
47
+ items: Array<T>;
48
+ dependencies: Array<any>;
49
+ }
50
+ /**
51
+ * Defines additional options which can optionally be provided when setting up a synchronization callback
52
+ * for a specific synchronization item type.
53
+ * These are not required, but, when set, allow further
54
+ */
55
+ interface SetupOfflineSyncOptions<T> {
56
+ /**
57
+ * Invoked when the user requests to edit a sync item.
58
+ * The typical behavior for such a callback is to launch a UI which allows editing the content
59
+ * encapsulated by the sync item.
60
+ * @param syncItem The sync item to be edited.
61
+ */
62
+ onBeginEditSyncItem?(syncItem: SyncItem<T>): void;
63
+ }
64
+ /**
65
+ * Represents the data inside the global offline synchronization store.
66
+ * Provides information about a currently ongoing synchronization.
67
+ */
68
+ export interface OfflineSynchronizationStore {
69
+ synchronization?: {
70
+ totalCount: number;
71
+ pendingCount: number;
72
+ abortController: AbortController;
73
+ };
74
+ }
75
+ export declare function getOfflineSynchronizationStore(): import("unistore").Store<OfflineSynchronizationStore>;
76
+ /**
77
+ * Runs a full synchronization of **all** queued synchronization items.
78
+ */
79
+ export declare function runSynchronization(): Promise<void>;
80
+ /**
81
+ * Enqueues a new item in the sync queue for a specific user.
82
+ * @param userId The user with whom the sync item should be associated with.
83
+ * @param type The identifying type of the synchronization item.
84
+ * @param content The actual data to be synchronized.
85
+ * @param descriptor An optional descriptor providing additional metadata about the sync item.
86
+ */
87
+ export declare function queueSynchronizationItemFor<T>(userId: string, type: string, content: T, descriptor?: QueueItemDescriptor): Promise<number>;
88
+ /**
89
+ * Enqueues a new item in the sync queue and associates the item with the currently signed in user.
90
+ * @param type The identifying type of the synchronization item.
91
+ * @param content The actual data to be synchronized.
92
+ * @param descriptor An optional descriptor providing additional metadata about the sync item.
93
+ */
94
+ export declare function queueSynchronizationItem<T>(type: string, content: T, descriptor?: QueueItemDescriptor): Promise<number>;
95
+ /**
96
+ * Returns the content of all currently queued up sync items of a given user.
97
+ * @param userId The ID of the user whose synchronization items should be returned.
98
+ * @param type The identifying type of the synchronization items to be returned..
99
+ */
100
+ export declare function getSynchronizationItemsFor<T>(userId: string, type?: string): Promise<T[]>;
101
+ /**
102
+ * Returns all currently queued up sync items of a given user.
103
+ * @param userId The ID of the user whose synchronization items should be returned.
104
+ * @param type The identifying type of the synchronization items to be returned..
105
+ */
106
+ export declare function getFullSynchronizationItemsFor<T>(userId: string, type?: string): Promise<Array<SyncItem<T>>>;
107
+ /**
108
+ * Returns the content of all currently queued up sync items of the currently signed in user.
109
+ * @param type The identifying type of the synchronization items to be returned.
110
+ */
111
+ export declare function getSynchronizationItems<T>(type?: string): Promise<T[]>;
112
+ /**
113
+ * Returns all currently queued up sync items of the currently signed in user.
114
+ * @param type The identifying type of the synchronization items to be returned.
115
+ */
116
+ export declare function getFullSynchronizationItems<T>(type?: string): Promise<SyncItem<T>[]>;
117
+ /**
118
+ * Returns a queued sync item with the given ID or `undefined` if no such item exists.
119
+ * @param id The ID of the requested sync item.
120
+ */
121
+ export declare function getSynchronizationItem<T = any>(id: number): Promise<SyncItem<T> | undefined>;
122
+ /**
123
+ * Returns whether editing synchronization items of the given type is supported by the currently
124
+ * registered synchronization handlers.
125
+ * @param type The identifying type of the synchronization item which should be edited.
126
+ */
127
+ export declare function canBeginEditSynchronizationItemsOfType(type: string): boolean;
128
+ /**
129
+ * Triggers an edit flow for the given synchronization item.
130
+ * If this is not possible, throws an error.
131
+ * @param id The ID of the synchronization item to be edited.
132
+ */
133
+ export declare function beginEditSynchronizationItem(id: number): Promise<void>;
134
+ /**
135
+ * Deletes a queued up sync item with the given ID.
136
+ * @param id The ID of the synchronization item to be deleted.
137
+ */
138
+ export declare function deleteSynchronizationItem(id: number): Promise<void>;
139
+ /**
140
+ * Registers a new synchronization handler which is able to synchronize data of a specific type.
141
+ * @param type The identifying type of the synchronization items which can be handled by this handler.
142
+ * @param dependsOn An array of other sync item types which must be synchronized before this handler
143
+ * can synchronize its own data. Items of these types are effectively dependencies of the data
144
+ * synchronized by this handler.
145
+ * @param process A function which, when invoked, performs the actual client-server synchronization of the given
146
+ * `item` (which is the actual data to be synchronized).
147
+ * @param options Additional options which can optionally be provided when setting up a synchronization callback
148
+ * for a specific synchronization item type.
149
+ */
150
+ export declare function setupOfflineSync<T>(type: string, dependsOn: Array<string>, process: ProcessSyncItem<T>, options?: SetupOfflineSyncOptions<T>): void;
151
+ export {};
@@ -0,0 +1 @@
1
+ import "fake-indexeddb/auto";
package/dist/uuid.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export declare const offlineUuidPrefix = "OFFLINE+";
2
+ /** Generates a UUID-like string which is used for uniquely identifying objects while offline. */
3
+ export declare function generateOfflineUuid(): string;
4
+ /** Checks whether the given string has the format of an offline UUID generated by {@link generateOfflineUuid} */
5
+ export declare function isOfflineUuid(uuid: string): boolean;
package/jest.config.js CHANGED
@@ -4,5 +4,9 @@ module.exports = {
4
4
  },
5
5
  moduleNameMapper: {
6
6
  "lodash-es": "lodash",
7
+ // See https://jestjs.io/docs/upgrading-to-jest28#packagejson-exports
8
+ // which links to https://github.com/microsoft/accessibility-insights-web/pull/5421#issuecomment-1109168149
9
+ "^dexie$": require.resolve("dexie"),
7
10
  },
11
+ testEnvironment: "jsdom",
8
12
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-offline",
3
- "version": "3.4.1-pre.96",
3
+ "version": "4.0.0-pre.1",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Helper utilities for OpenMRS",
6
6
  "browser": "dist/openmrs-esm-offline.js",
@@ -36,18 +36,18 @@
36
36
  "access": "public"
37
37
  },
38
38
  "devDependencies": {
39
- "@openmrs/esm-api": "^3.4.1-pre.96",
40
- "@openmrs/esm-globals": "^3.4.1-pre.96",
41
- "@openmrs/esm-state": "^3.4.1-pre.96",
42
- "@openmrs/esm-styleguide": "^3.4.1-pre.96",
39
+ "@openmrs/esm-api": "^4.0.0-pre.1",
40
+ "@openmrs/esm-globals": "^4.0.0-pre.1",
41
+ "@openmrs/esm-state": "^4.0.0-pre.1",
42
+ "@openmrs/esm-styleguide": "^4.0.0-pre.1",
43
43
  "@types/uuid": "^8.3.0",
44
44
  "rxjs": "^6.5.3"
45
45
  },
46
46
  "peerDependencies": {
47
- "@openmrs/esm-api": "3.x",
48
- "@openmrs/esm-globals": "3.x",
49
- "@openmrs/esm-state": "3.x",
50
- "@openmrs/esm-styleguide": "3.x",
47
+ "@openmrs/esm-api": "4.x",
48
+ "@openmrs/esm-globals": "4.x",
49
+ "@openmrs/esm-state": "4.x",
50
+ "@openmrs/esm-styleguide": "4.x",
51
51
  "rxjs": "6.x"
52
52
  },
53
53
  "dependencies": {
@@ -56,5 +56,5 @@
56
56
  "uuid": "^8.3.2",
57
57
  "workbox-window": "^6.1.5"
58
58
  },
59
- "gitHead": "593214cd88408e07e9c18eab4c204be4a3722c73"
59
+ "gitHead": "9f58b801f07526083a9edc1cc5a1e58660d71eb0"
60
60
  }
package/src/sync.test.ts CHANGED
@@ -43,7 +43,7 @@ describe("Sync Queue", () => {
43
43
  beforeAll(() => {
44
44
  // We want to control the timers to ensure that we can test the `createdOn` attribute
45
45
  // of the sync item (which is created using `new Date()`).
46
- jest.useFakeTimers("modern");
46
+ jest.useFakeTimers();
47
47
  jest.setSystemTime(systemTime);
48
48
  });
49
49