@applicaster/zapp-react-native-utils 13.0.0-alpha.1711912250 → 13.0.0-alpha.1731130113
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.
- package/actionsExecutor/ActionExecutorContext.tsx +34 -7
- package/appUtils/accessibilityManager/const.ts +18 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +1 -1
- package/package.json +2 -2
- package/playerUtils/index.ts +23 -0
- package/reactHooks/app/useAppState.ts +2 -2
- package/reactHooks/state/README.md +79 -0
- package/reactHooks/state/ZStoreProvider.tsx +71 -0
- package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +66 -0
- package/reactHooks/state/index.ts +2 -0
- package/typeGuards/index.ts +3 -0
- package/zappFrameworkUtils/localStorageHelper.ts +32 -10
|
@@ -5,9 +5,14 @@ import {
|
|
|
5
5
|
actionExecutor as _actionExecutor,
|
|
6
6
|
ActionResult,
|
|
7
7
|
} from "./ActionExecutor";
|
|
8
|
-
import {
|
|
9
|
-
|
|
8
|
+
import {
|
|
9
|
+
batchRemoveAllFromNamespaceForStorage,
|
|
10
|
+
batchSave,
|
|
11
|
+
} from "../zappFrameworkUtils/localStorageHelper";
|
|
12
|
+
import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
|
|
13
|
+
|
|
10
14
|
import * as QuickBrickManager from "@applicaster/zapp-react-native-bridge/QuickBrick";
|
|
15
|
+
import { QUICK_BRICK_EVENTS } from "@applicaster/zapp-react-native-bridge/QuickBrick";
|
|
11
16
|
import { showConfirmationDialog } from "../alertUtils";
|
|
12
17
|
import { createCloudEvent, sendCloudEvent } from "../cloudEventsUtils";
|
|
13
18
|
import { createLogger } from "../logger";
|
|
@@ -27,7 +32,8 @@ import {
|
|
|
27
32
|
usePickFromState,
|
|
28
33
|
} from "@applicaster/zapp-react-native-redux/hooks";
|
|
29
34
|
import { TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT } from "./consts";
|
|
30
|
-
import { postEvent } from "../reactHooks/useSubscriberFor";
|
|
35
|
+
import { postEvent, useSubscriberFor } from "../reactHooks/useSubscriberFor";
|
|
36
|
+
import { APP_EVENTS } from "../appUtils/events";
|
|
31
37
|
|
|
32
38
|
export const { log_error, log_info, log_debug } = createLogger({
|
|
33
39
|
subsystem: "ActionExecutorContext",
|
|
@@ -92,7 +98,15 @@ async function onMaxTagsReached(data: MaxTagsReachedEvent) {
|
|
|
92
98
|
const prepareDefaultActions = (actionExecutor) => {
|
|
93
99
|
actionExecutor.registerAction("localStorageSet", async (action) => {
|
|
94
100
|
const namespaces = action.options.content;
|
|
95
|
-
await
|
|
101
|
+
await batchSave(namespaces, localStorage);
|
|
102
|
+
// TODO: Add support for ownershipKey and ownershipNamespace
|
|
103
|
+
|
|
104
|
+
return ActionResult.Success;
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
actionExecutor.registerAction("sessionStorageSet", async (action) => {
|
|
108
|
+
const namespaces = action.options.content;
|
|
109
|
+
await batchSave(namespaces, sessionStorage);
|
|
96
110
|
// TODO: Add support for ownershipKey and ownershipNamespace
|
|
97
111
|
|
|
98
112
|
return ActionResult.Success;
|
|
@@ -149,15 +163,13 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
149
163
|
actionExecutor.registerAction("confirmDialog", async (action) => {
|
|
150
164
|
log_info("handleAction: confirmDialog event");
|
|
151
165
|
|
|
152
|
-
|
|
166
|
+
return new Promise<ActionResult>((resolve) => {
|
|
153
167
|
showConfirmationDialog({
|
|
154
168
|
...action.options,
|
|
155
169
|
confirmCompletion: () => resolve(ActionResult.Success),
|
|
156
170
|
cancelCompletion: () => resolve(ActionResult.Cancel),
|
|
157
171
|
});
|
|
158
172
|
});
|
|
159
|
-
|
|
160
|
-
return confirmationPromise;
|
|
161
173
|
});
|
|
162
174
|
|
|
163
175
|
actionExecutor.registerAction("sendCloudEvent", async (action, context) => {
|
|
@@ -303,9 +315,24 @@ export function withActionExecutor(Component) {
|
|
|
303
315
|
};
|
|
304
316
|
}, []);
|
|
305
317
|
|
|
318
|
+
useSubscriberFor(APP_EVENTS.onLogout, () => {
|
|
319
|
+
log_debug(
|
|
320
|
+
"User profile: onLogout event received, clearing user profile data"
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
const userAccountKey = "user_account";
|
|
324
|
+
void batchRemoveAllFromNamespaceForStorage(userAccountKey, localStorage);
|
|
325
|
+
|
|
326
|
+
void batchRemoveAllFromNamespaceForStorage(
|
|
327
|
+
userAccountKey,
|
|
328
|
+
sessionStorage
|
|
329
|
+
);
|
|
330
|
+
});
|
|
331
|
+
|
|
306
332
|
useEffect(() => {
|
|
307
333
|
return _actionExecutor.registerAction(
|
|
308
334
|
"navigateToScreen",
|
|
335
|
+
|
|
309
336
|
async (action: ActionType, context?: Record<string, any>) => {
|
|
310
337
|
const screenType = action.options?.typeMapping;
|
|
311
338
|
|
|
@@ -47,4 +47,22 @@ export const BUTTON_ACCESSIBILITY_KEYS = {
|
|
|
47
47
|
label: "accessibility_fullscreen_label",
|
|
48
48
|
hint: "accessibility_fullscreen_hint",
|
|
49
49
|
},
|
|
50
|
+
// EPG-specific buttons
|
|
51
|
+
now: {
|
|
52
|
+
label: "accessibility_now_label",
|
|
53
|
+
hint: "accessibility_now_hint",
|
|
54
|
+
},
|
|
55
|
+
day: {
|
|
56
|
+
label: "accessibility_day_label",
|
|
57
|
+
hint: "accessibility_day_hint",
|
|
58
|
+
},
|
|
59
|
+
program: {
|
|
60
|
+
label: "accessibility_program_label",
|
|
61
|
+
hint: "accessibility_program_hint",
|
|
62
|
+
},
|
|
63
|
+
// Menu-specific buttons
|
|
64
|
+
menu_item: {
|
|
65
|
+
label: "accessibility_menu_item_label",
|
|
66
|
+
hint: "accessibility_menu_item_hint",
|
|
67
|
+
},
|
|
50
68
|
} as const;
|
|
@@ -2513,7 +2513,7 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2513
2513
|
styles.fields.push(
|
|
2514
2514
|
fieldsGroup(
|
|
2515
2515
|
"Audio Player",
|
|
2516
|
-
"This section allows you to configure the audio player layout
|
|
2516
|
+
"This section allows you to configure the audio player layout",
|
|
2517
2517
|
[
|
|
2518
2518
|
{
|
|
2519
2519
|
key: "audio_player_background_color",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "13.0.0-alpha.
|
|
3
|
+
"version": "13.0.0-alpha.1731130113",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@applicaster/applicaster-types": "13.0.0-alpha.
|
|
30
|
+
"@applicaster/applicaster-types": "13.0.0-alpha.1731130113",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|
package/playerUtils/index.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
2
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
3
|
+
import { isString } from "@applicaster/zapp-react-native-utils/typeGuards";
|
|
4
|
+
import { isFilledArray } from "@applicaster/zapp-react-native-utils/arrayUtils";
|
|
5
|
+
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
6
|
+
|
|
3
7
|
import { getBoolFromConfigValue } from "../configurationUtils";
|
|
4
8
|
|
|
5
9
|
/**
|
|
@@ -72,3 +76,22 @@ function isLiveByManager(): boolean {
|
|
|
72
76
|
export function isLive(entry: ZappEntry): boolean {
|
|
73
77
|
return isEntryLive(entry) || isLiveByManager();
|
|
74
78
|
}
|
|
79
|
+
|
|
80
|
+
export const isAudioItem = (item: Option<ZappEntry>) => {
|
|
81
|
+
if (
|
|
82
|
+
isString(item?.content?.type) &&
|
|
83
|
+
item?.content?.type?.includes?.("audio")
|
|
84
|
+
) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (isString(item?.type?.value) && item?.type?.value?.includes?.("audio")) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return false;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const isInlineTV = (screenData) => {
|
|
96
|
+
return isTV() && isFilledArray(screenData?.ui_components);
|
|
97
|
+
};
|
|
@@ -14,10 +14,10 @@ export function useAppState(returnIsActive) {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
React.useEffect(() => {
|
|
17
|
-
AppState.addEventListener("change", setAppState);
|
|
17
|
+
const subscription = AppState.addEventListener("change", setAppState);
|
|
18
18
|
|
|
19
19
|
return () => {
|
|
20
|
-
|
|
20
|
+
subscription.remove();
|
|
21
21
|
};
|
|
22
22
|
}, []);
|
|
23
23
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# ZStoreProvider and useZStore
|
|
2
|
+
|
|
3
|
+
This module provides a React context-based solution for managing Zustand stores with named access.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
### ZStoreProvider
|
|
8
|
+
|
|
9
|
+
The `ZStoreProvider` component creates a Zustand store from the provided value and makes it available to child components.
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { ZStoreProvider } from "@applicaster/zapp-react-native-utils/reactHooks/state";
|
|
13
|
+
|
|
14
|
+
// In your component
|
|
15
|
+
<ZStoreProvider name="playerConfiguration" value={controller?.config}>
|
|
16
|
+
<YourComponent />
|
|
17
|
+
</ZStoreProvider>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### useZStore
|
|
21
|
+
|
|
22
|
+
The `useZStore` hook allows you to access a Zustand store by name from within a `ZStoreProvider`.
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { useZStore } from "@applicaster/zapp-react-native-utils/reactHooks/state";
|
|
26
|
+
import { useStore } from "zustand";
|
|
27
|
+
|
|
28
|
+
// In your component
|
|
29
|
+
const MyComponent = () => {
|
|
30
|
+
const store = useZStore("playerConfiguration");
|
|
31
|
+
const config = useStore(store, (state) => state.someProperty);
|
|
32
|
+
|
|
33
|
+
return <Text>{config}</Text>;
|
|
34
|
+
};
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Example
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import React from "react";
|
|
41
|
+
import { ZStoreProvider, useZStore } from "@applicaster/zapp-react-native-utils/reactHooks/state";
|
|
42
|
+
import { useStore } from "zustand";
|
|
43
|
+
|
|
44
|
+
// Component that uses the store
|
|
45
|
+
const PlayerConfigDisplay = () => {
|
|
46
|
+
const store = useZStore("playerConfiguration");
|
|
47
|
+
const config = useStore(store, (state) => state);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<View>
|
|
51
|
+
<Text>Player Config: {JSON.stringify(config)}</Text>
|
|
52
|
+
</View>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Main component that provides the store
|
|
57
|
+
const PlayerComponent = ({ controller }) => {
|
|
58
|
+
return (
|
|
59
|
+
<ZStoreProvider name="playerConfiguration" value={controller?.config}>
|
|
60
|
+
<PlayerConfigDisplay />
|
|
61
|
+
</ZStoreProvider>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Features
|
|
67
|
+
|
|
68
|
+
- **Named Stores**: Access stores by name instead of importing them directly
|
|
69
|
+
- **Context-based**: Uses React Context for store management
|
|
70
|
+
- **Zustand Integration**: Seamlessly works with existing Zustand stores
|
|
71
|
+
- **Type Safety**: Full TypeScript support
|
|
72
|
+
- **Error Handling**: Clear error messages when stores are not found or used outside providers
|
|
73
|
+
|
|
74
|
+
## Error Handling
|
|
75
|
+
|
|
76
|
+
The `useZStore` hook will throw errors in the following cases:
|
|
77
|
+
|
|
78
|
+
1. **Used outside provider**: "useZStore must be used within a ZStoreProvider"
|
|
79
|
+
2. **Store not found**: "Store with name 'storeName' not found. Make sure it's provided by a ZStoreProvider"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React, { createContext, useContext, ReactNode, useMemo } from "react";
|
|
2
|
+
import { create, UseBoundStore } from "zustand";
|
|
3
|
+
|
|
4
|
+
interface ZStoreContextType {
|
|
5
|
+
stores: Map<string, UseBoundStore<any>>;
|
|
6
|
+
registerStore: (name: string, store: UseBoundStore<any>) => void;
|
|
7
|
+
getStore: (name: string) => UseBoundStore<any> | undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const ZStoreContext = createContext<ZStoreContextType | null>(null);
|
|
11
|
+
|
|
12
|
+
interface ZStoreProviderProps {
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
name: string;
|
|
15
|
+
value: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const ZStoreProvider: React.FC<ZStoreProviderProps> = ({
|
|
19
|
+
children,
|
|
20
|
+
name,
|
|
21
|
+
value,
|
|
22
|
+
}) => {
|
|
23
|
+
const parentContext = useContext(ZStoreContext);
|
|
24
|
+
|
|
25
|
+
const context = useMemo(() => {
|
|
26
|
+
if (parentContext) {
|
|
27
|
+
// If parent context exists, create a new store and register it
|
|
28
|
+
const store = create(() => value);
|
|
29
|
+
parentContext.registerStore(name, store);
|
|
30
|
+
|
|
31
|
+
return parentContext;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Create a new context if none exists
|
|
35
|
+
const stores = new Map<string, UseBoundStore<any>>();
|
|
36
|
+
|
|
37
|
+
// Create a store from the provided value
|
|
38
|
+
const store = create(() => value);
|
|
39
|
+
stores.set(name, store);
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
stores,
|
|
43
|
+
registerStore: (storeName: string, storeInstance: UseBoundStore<any>) => {
|
|
44
|
+
stores.set(storeName, storeInstance);
|
|
45
|
+
},
|
|
46
|
+
getStore: (storeName: string) => stores.get(storeName),
|
|
47
|
+
};
|
|
48
|
+
}, [parentContext, name, value]);
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<ZStoreContext.Provider value={context}>{children}</ZStoreContext.Provider>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const useZStore = (name: string): UseBoundStore<any> => {
|
|
56
|
+
const context = useContext(ZStoreContext);
|
|
57
|
+
|
|
58
|
+
if (!context) {
|
|
59
|
+
throw new Error("useZStore must be used within a ZStoreProvider");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const store = context.getStore(name);
|
|
63
|
+
|
|
64
|
+
if (!store) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Store with name "${name}" not found. Make sure it's provided by a ZStoreProvider.`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return store;
|
|
71
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react-native";
|
|
3
|
+
import { Text } from "react-native";
|
|
4
|
+
import { ZStoreProvider, useZStore } from "../ZStoreProvider";
|
|
5
|
+
import { useStore } from "zustand";
|
|
6
|
+
|
|
7
|
+
interface TestState {
|
|
8
|
+
value: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Test component that uses the store
|
|
12
|
+
const TestComponent = ({ storeName }: { storeName: string }) => {
|
|
13
|
+
const store = useZStore(storeName);
|
|
14
|
+
const value = useStore(store, (state: any) => (state as TestState).value);
|
|
15
|
+
|
|
16
|
+
return <Text testID="test-value">{value}</Text>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Test component that provides a store
|
|
20
|
+
const TestProvider = ({ children }: { children: React.ReactNode }) => {
|
|
21
|
+
return (
|
|
22
|
+
<ZStoreProvider name="testStore" value={{ value: "test-value" }}>
|
|
23
|
+
{children}
|
|
24
|
+
</ZStoreProvider>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
describe("ZStoreProvider and useZStore", () => {
|
|
29
|
+
it("should provide a store and allow access via useZStore", () => {
|
|
30
|
+
render(
|
|
31
|
+
<TestProvider>
|
|
32
|
+
<TestComponent storeName="testStore" />
|
|
33
|
+
</TestProvider>
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
expect(screen.getByTestId("test-value").props.children).toBe("test-value");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should throw error when useZStore is used outside provider", () => {
|
|
40
|
+
// Suppress console.error for this test
|
|
41
|
+
const originalError = console.error;
|
|
42
|
+
console.error = jest.fn();
|
|
43
|
+
|
|
44
|
+
expect(() => {
|
|
45
|
+
render(<TestComponent storeName="testStore" />);
|
|
46
|
+
}).toThrow("useZStore must be used within a ZStoreProvider");
|
|
47
|
+
|
|
48
|
+
console.error = originalError;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should throw error when store name is not found", () => {
|
|
52
|
+
// Suppress console.error for this test
|
|
53
|
+
const originalError = console.error;
|
|
54
|
+
console.error = jest.fn();
|
|
55
|
+
|
|
56
|
+
expect(() => {
|
|
57
|
+
render(
|
|
58
|
+
<TestProvider>
|
|
59
|
+
<TestComponent storeName="nonExistentStore" />
|
|
60
|
+
</TestProvider>
|
|
61
|
+
);
|
|
62
|
+
}).toThrow('Store with name "nonExistentStore" not found');
|
|
63
|
+
|
|
64
|
+
console.error = originalError;
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
StorageValuesToRemove,
|
|
8
8
|
StorageValuesToAdd,
|
|
9
9
|
} from "./types";
|
|
10
|
+
import { Storage } from "@applicaster/zapp-react-native-bridge/ZappStorage/Storage";
|
|
10
11
|
|
|
11
12
|
const defaultOwnedKey = "owned_keys";
|
|
12
13
|
const DEFAULT_NAMESPACE = "applicaster.v2";
|
|
@@ -50,8 +51,9 @@ function mapOwnedKeysToAdd(
|
|
|
50
51
|
return mappedData;
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
export async function
|
|
54
|
-
storageValues: StorageValuesToAdd
|
|
54
|
+
export async function batchSave(
|
|
55
|
+
storageValues: StorageValuesToAdd,
|
|
56
|
+
storage: Storage
|
|
55
57
|
) {
|
|
56
58
|
if (isNilOrEmpty(storageValues)) {
|
|
57
59
|
return false;
|
|
@@ -64,24 +66,37 @@ export async function batchSaveToLocalStorage(
|
|
|
64
66
|
const value = namespaceData[key];
|
|
65
67
|
|
|
66
68
|
if (!isNilOrEmpty(value)) {
|
|
67
|
-
await
|
|
69
|
+
await storage.setItem(key, value, namespace);
|
|
68
70
|
}
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
export async function
|
|
74
|
-
storageValues:
|
|
75
|
+
export async function batchSaveToLocalStorage(
|
|
76
|
+
storageValues: StorageValuesToAdd
|
|
77
|
+
) {
|
|
78
|
+
return await batchSave(storageValues, localStorage);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function batchRemoveFromStorage(
|
|
82
|
+
storageValues: StorageValuesToRemove,
|
|
83
|
+
storage: Storage = localStorage
|
|
75
84
|
) {
|
|
76
85
|
for (const namespace of Object.keys(storageValues)) {
|
|
77
86
|
const namespaceData = storageValues[namespace];
|
|
78
87
|
|
|
79
88
|
for (const key of namespaceData) {
|
|
80
|
-
await
|
|
89
|
+
await storage.removeItem(key, namespace);
|
|
81
90
|
}
|
|
82
91
|
}
|
|
83
92
|
}
|
|
84
93
|
|
|
94
|
+
export async function batchRemoveFromLocalStorage(
|
|
95
|
+
storageValues: StorageValuesToRemove
|
|
96
|
+
) {
|
|
97
|
+
await batchRemoveFromStorage(storageValues, localStorage);
|
|
98
|
+
}
|
|
99
|
+
|
|
85
100
|
async function addOwnedKeys({
|
|
86
101
|
newKeys,
|
|
87
102
|
ownershipKey,
|
|
@@ -224,13 +239,20 @@ export async function batchRemoveOwnedNamespaceKeys({
|
|
|
224
239
|
});
|
|
225
240
|
}
|
|
226
241
|
|
|
227
|
-
export async function
|
|
228
|
-
|
|
242
|
+
export async function batchRemoveAllFromNamespaceForStorage(
|
|
243
|
+
namespace: string,
|
|
244
|
+
storage: Storage
|
|
245
|
+
) {
|
|
246
|
+
const allDataInNamespace = await storage.getAllItems(namespace);
|
|
229
247
|
const keysToRemove = Object.keys(allDataInNamespace);
|
|
230
248
|
|
|
231
|
-
const dataToRemove = {
|
|
249
|
+
const dataToRemove: StorageValuesToRemove = {
|
|
232
250
|
[namespace]: keysToRemove,
|
|
233
251
|
};
|
|
234
252
|
|
|
235
|
-
await
|
|
253
|
+
await batchRemoveFromStorage(dataToRemove, storage);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export async function batchRemoveAllFromNamespace(namespace: string) {
|
|
257
|
+
await batchRemoveAllFromNamespaceForStorage(namespace, localStorage);
|
|
236
258
|
}
|