{"id":24507418,"url":"https://github.com/mstephen19/apify-global-store","last_synced_at":"2025-03-15T09:14:06.043Z","repository":{"id":57182093,"uuid":"464260333","full_name":"mstephen19/apify-global-store","owner":"mstephen19","description":"Easily access, manage, and manipulate a global state/multiple global states for an Apify actor's run","archived":false,"fork":false,"pushed_at":"2023-01-23T14:35:06.000Z","size":372,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-21T23:48:47.273Z","etag":null,"topics":["apify","apify-sdk","state","state-management","typescript","web-crawling","web-scraping"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/apify-global-store","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mstephen19.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-27T21:41:26.000Z","updated_at":"2023-03-17T12:54:30.000Z","dependencies_parsed_at":"2023-02-13T00:01:30.685Z","dependency_job_id":null,"html_url":"https://github.com/mstephen19/apify-global-store","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstephen19%2Fapify-global-store","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstephen19%2Fapify-global-store/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstephen19%2Fapify-global-store/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mstephen19%2Fapify-global-store/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mstephen19","download_url":"https://codeload.github.com/mstephen19/apify-global-store/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243707382,"owners_count":20334619,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apify","apify-sdk","state","state-management","typescript","web-crawling","web-scraping"],"created_at":"2025-01-21T23:48:54.186Z","updated_at":"2025-03-15T09:14:06.022Z","avatar_url":"https://github.com/mstephen19.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Apify Global Store\n\n\u003e **THIS PACKAGE IS DEPRECATED!** It was build for old versions of Crawlee and the Apify SDK.\n\n[![TypeScript](https://badges.frapsoft.com/typescript/code/typescript.svg?v=101)](https://github.com/ellerbrock/typescript-badges/)\n\n![npm](https://img.shields.io/npm/v/apify-global-store)\n\n![npm](https://img.shields.io/npm/dw/apify-global-store)\n\n## What's new in `1.1.3`?\n\n-   Addition of `addMethod` and `useMethod` (experimental)\n-   `pushPathToDataset` method name shortened to `pushPath`\n-   Support for array formatted paths in `setPath`, `deletePath`, and `pushPath`\n-   Bug fixes for `pushPath`, `summon`, and `summonAll`\n-   Improve debug logs\n-   Improve JSDoc\n\n## Installation\n\n```\nnpm install apify-global-store\n```\n\n## About\n\nThis is a simple and lightweight API which allows you to easily create and manage multiple global stores local to an actor's run. By using `apify-global-store`, you completely remove the need to pass large and complex data through requests. Simplify the process of storing incomplete data that isn't yet ready to be pushed to the dataset with `GlobalStore`!\n\nState persistence, actor migrations, and race conditions are automatically handled under the hood, so the global state will not be lost on migrations or graceful aborts.\n\n## Table of Contents:\n\n-   [Importing](#importing)\n-   [Example](#example)\n-   [General Usage](#general-usage)\n    -   [`await GlobalStore.init()`](#await-globalstoreinit)\n    -   [`store.state`](#storestate)\n    -   [`store.info`](#storeinfo)\n-   [Mutating State](#mutating-state)\n    -   [`store.set()`](#storeset)\n    -   [`store.setPath()`](#storesetpath)\n    -   [`store.deletePath()`](#storedeletepath)\n    -   [`store.addReducer()`](#storeaddreducer)\n    -   [`store.setWithReducer()`](#storesetwithreducer)\n-   [Data Management](#data-management)\n    -   [`await store.pushPath()`](#await-storepushpath)\n    -   [`store.dump()`](#storedump)\n    -   [`await store.backup()`](#await-storebackup)\n    -   [`await store.forceSave()`](#await-storeforcesave)\n-   [Static Methods](#static-methods)\n    -   [`GlobalStore.summon()`](#globalstoresummon)\n    -   [`GlobalStore.summonAll()`](#globalstoresummonall)\n    -   [`GlobalStore.dumpAll()`](#globalstoredumpall)\n-   [Experimental Methods](#experimental-methods)\n    -   [`GlobalStore.addMethod()`](#globalstoreaddmethod)\n    -   [`GlobalStore.useMethod()`](#globalstoreusemethod)\n-   [Best Practices](#best-practices)\n    -   [Best practices with store management](#best-practices-with-store-management)\n    -   [Best practices when using a reducer](#best-practices-when-using-a-reducer)\n-   [Storage](#storage)\n-   [Available Types](#available-types)\n-   [License](#license)\n\n## Importing\n\nES6+\n\n```TypeScript\nimport { GlobalStore } from 'apify-global-store'\n```\n\nES5-\n\n```JavaScript\nconst { GlobalStore } = require('apify-global-store')\n```\n\n## Example\n\n```JavaScript\nconst Apify = require('apify');\nconst { GlobalStore } = require('apify-global-store');\n\nApify.main(async () =\u003e {\n    const store = await GlobalStore.init();\n\n    console.log(store.state); // -\u003e {}\n\n    store.set((prev) =\u003e {\n        return {\n            ...prev,\n            message: 'hello'\n        }\n    })\n\n    console.log(store.state); // -\u003e { message: 'hello' }\n\n    store.set((prev) =\u003e {\n        return {\n            ...prev,\n            message2: 'world'\n        }\n    })\n\n    console.log(store.state); // -\u003e { message: 'hello', message2: 'world' }\n\n    await store.pushPath('message')\n});\n```\n\n## General Usage\n\n### `await GlobalStore.init()`\n\n(**initializeOptions?**: _[InitializeOptions](#available-types)_ =\u003e `Promise\u003cGlobalStore\u003e`\n\n| Argument          | Type              | Required  | Description                                                             |\n| ----------------- | ----------------- | --------- | ----------------------------------------------------------------------- |\n| initializeOptions | InitializeOptions | **false** | Configure the store's name, its initial state, and where it is located. |\n\n```TypeScript\ninterface InitializeOptions {\n    name?: string; // The name of the store to use\n    initialState?: Record\u003cstring, unknown\u003e; // The initial state to start with\n    cloud?: boolean; // Whether or not to keep the store on the cloud, or locally to the actor's run\n    debug?: boolean; // Whether or not to display helpful debug messages\n}\n```\n\n`GlobalStore` doesn't have a public constructor. Its `init()` method runs necessary asynchronous tasks prior to calling on its private constructor.\n\n**Usage:**\n\n```JavaScript\nconst store = await GlobalStore.init({\n    name: 'clothing-store',\n    initialState: {\n        websites: [],\n        errors: [],\n    },\n    cloud: true,\n    debug: true\n});\n```\n\nIf the store already has a previous state stored within the Key-Value store (in the situation that a migration/abort occurred), then the `initialState` option will have no effect.\n\nYou can only pass letters and \"-\" within the string, otherwise an error will be thrown (to follow naming conventions). The provided store name will _always_ be forced into uppercase.\n\n\u003e **Note:** A name for a store can only be used once. That includes the default name of `GLOBAL-STORE`. If the `cloud` option is set to true, then the global store will be stored in the cloud on your Apify account under \"Storages\" within a named Key-Value store called `CLOUD-GLOBAL-STORES`.\n\n### `store.state`\n\n**Usage:**\n\n```JavaScript\nconst { myValue } = store.state;\n```\n\nA getter method that returns the current state object of the store.\n\n### `store.info`\n\n```JavaScript\nconst { sizeInBytes, lastModified } = store.info;\n```\n\nAn object containing information about the contents of the store. Example:\n\n```JavaScript\n{\n    sizeInBytes: 17,\n    lastModified: '2022-03-18T15:39:45.041Z',\n    globalStoreVersion: '1.0.9',\n    type: 'LOCAL'\n}\n```\n\n## Mutating State\n\n### `store.set()`\n\n(**setStateParam**: _[SetStateFunctionCallBack](#available-types)_) =\u003e `void`\n\n| Argument      | Type                     | Required | Description                                                                                                                                      |\n| ------------- | ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |\n| setStateParam | SetStateFunctionCallBack | **true** | A callback function in which the current state is passed and can be modified. Return value must be an object which will be set as the new state. |\n\nA synchronous function which sets the current state. The previous state is passed into the callback function as a parameter. It is recommended to refer to the previous state through this parameter instead of using `store.state` within the callback.\n\n**Usage:**\n\n```JavaScript\nstore.set((prev) =\u003e {\n    return {\n        ...prev, // spread out the previous state\n        newValue: 'hello world'\n    }\n});\n```\n\n\u003e **Note:** It is always best practice to spread out the previous state at the top level of the returned object, then to add/override any values below.\n\n### `store.setPath()`\n\n(**path**: _string | string[]_, **value**: _unknown_) =\u003e `void`\n\n| Argument | Type    | Required | Description                                                              |\n| -------- | ------- | -------- | ------------------------------------------------------------------------ |\n| path     | string  | **true** | A string version of the path within the state you'd like to set/replace. |\n| value    | unknown | **true** | The value you'd like to add for the specified path.                      |\n\n**Usage:**\n\n```JavaScript\nstore.setPath(`products.${productId}.reviews`, reviewsData);\n```\n\nIf the key you are using has dots in it (eg. \"https://google.com\"), you should use bracket notation instead of dot notation.\n\n```JavaScript\nconst link = 'https://google.com';\nconst data = { hello: 'world' }\n\n// Will throw an error saying the path \"websites -\u003e https://google -\u003e com\" doesn't exist, which is true.\nstore.setPath(`websites.${link}`, data);\n\n// Using bracket notation instead; therefore, the \".com\" is not evaluated as dot notation.\nstore.setPath(`websites[${link}]`, data);\n\n// Array format can also be used\nstore.setPath(['websites', link], data);\n```\n\n### `store.deletePath()`\n\n(**path**: _string | string[]_) =\u003e `void`\n\n| Argument | Type   | Required | Description                                                         |\n| -------- | ------ | -------- | ------------------------------------------------------------------- |\n| path     | string | **true** | A string version of the path within the state you'd like to delete. |\n\n**Usage:**\n\n```JavaScript\nstore.setPath(`products.${productId}.reviews`);\n```\n\n\u003e **Note:** This method works similar to `store.pushPath()`, except it does not push the data to the dataset prior to deleting it from the state.\n\n### `store.addReducer()`\n\n(**reducerFn**: _[ReducerFunction](#available-types)_) =\u003e `void`\n\n| Argument  | Type            | Required | Description                                                             |\n| --------- | --------------- | -------- | ----------------------------------------------------------------------- |\n| reducerFn | ReducerFunction | **true** | A custom reducer function which takes (state, action) as its arguments. |\n\nWhen you find yourself writing the same code over and over again using the `store.set()` method, or you are dealing with modifying deeply nested values, it is best practice to migrate to using a reducer function.\n\n**Usage:**\n\n```JavaScript\n// the \"action\" parameter is expected to have a \"type\" property\nconst reducer = (state, action) =\u003e {\n    switch (action.type) {\n        default:\n            return state;\n        case 'ADD-PRODUCT-REVIEW':\n            return {\n                ...state,\n                products: {\n                    ...state.products,\n                    [action.productId]: { ...state[action.productId], reviews: [...state[action.productId.reviews], ...action.payload] },\n                },\n            };\n    }\n};\n\n\nstore.addReducer(reducer);\n```\n\n\u003e **Note:** Only _one_ reducer can be added to a store instance. Trying to add a second one will result in an error.\n\n### `store.setWithReducer()`\n\n(**action**: _[ReducerAction](#available-types)_) =\u003e `void`\n\n| Argument | Type          | Required | Description                                    |\n| -------- | ------------- | -------- | ---------------------------------------------- |\n| action   | ReducerAction | **true** | Use your reducer function to modify the state. |\n\n**Usage:**\n\n```JavaScript\nconst action = { type: 'ADD-PRODUCT-REVIEW', productId: 1234, payload: { title: 'review 1', author: 'super cool product!', stars: 4 } };\n\nstore.setWithReducer(action);\n```\n\n## Data Management\n\n### `await store.pushPath()`\n\n(**path**: _string_, **dataset?**: _[Dataset](https://sdk.apify.com/docs/api/dataset)_ =\u003e `Promise\u003cvoid\u003e`\n\n| Argument | Type    | Required  | Description                                                                      |\n| -------- | ------- | --------- | -------------------------------------------------------------------------------- |\n| path     | string  | **true**  | A string version of the path within the state you'd like to push to the dataset. |\n| dataset  | Dataset | **false** | The dataset to push to. If not provided a dataset, the default one will be used. |\n\nPush some data from the store into the specified dataset (or into the default one), then automatically delete it from the store after it's been pushed.\n\n**Usage:**\n\n```JavaScript\nawait store.pushPath(`products.${productId}.reviews.${reviewId}`);\n```\n\n\u003e **Note:** When using this method to push to a dataset, the path is deleted within the state. If you don't want the data to be deleted from the global store after being pushed to the dataset, use regular `Apify.pushData()` instead.\n\n### `store.dump()`\n\n() =\u003e `void`\n\nCompletely empty the entire contents of the store.\n\n### `await store.backup()`\n\n() =\u003e `Promise\u003cvoid\u003e`\n\nBack the store up to the cloud. The backup will be stored in the \"Storages\" section of your Apify account under a Key-Value store named `CLOUD-GLOBAL-STORES`. If you'd prefer to exclusively keep the store on the cloud, set the `cloud` option to `true` in `InitializeOptions`.\n\n\u003e **Note:** If you're using `cloud: true` in `InitializeOptions`, you don't need to use this method. Just use `store.forceSave()` instead\n\n### `await store.forceSave()`\n\n() =\u003e `Promise\u003cvoid\u003e`\n\nThe store's data is saved to the Key-Value Store every single time the \"persistState\" event is fired. It can also be forced to be saved instantly with this method.\n\n## Static Methods\n\n### `GlobalStore.summon()`\n\n(**storeName**: _string_) =\u003e `GlobalStore`\n\n| Argument  | Type   | Required  | Description                      |\n| --------- | ------ | --------- | -------------------------------- |\n| storeName | string | **false** | The name of the store to summon. |\n\nA static method which returns the instance of the store attached to the name provided. A useful and simple aternative to passing a store instance around a parameter.\n\nYou are **_not_** required to provide the uppercase version of the store name in the `storeName` parameter. It is automatically done for you.\n\nIf you do not provide a store name, then the default store `GLOBAL-STORE` will be summoned.\n\n**Usage:**\n\n```JavaScript\nconst store = await GlobalStore.init();\n\nconst summoned = GlobalStore.summon('GLOBAL-STORE');\n\nconsole.log(summoned.state); // =\u003e {}\n```\n\n### `GlobalStore.summonAll()`\n\n() =\u003e `StoreInstances`\n\nSimilar to `summon`, but returns the entire `storeInstances` object, which is a map of all created instances of GlobalStore.\n\n### `GlobalStore.dumpAll()`\n\n() =\u003e `void`\n\nDump all instances of GlobalStore at once.\n\n## Experimental Methods\n\n### `GlobalStore.addMethod()`\n\n(**addMethodOptions**: _[AddMethodOptions](#available-types)_) =\u003e `void`\n\n| Argument         | Type             | Required | Description                                                                                                                                                     |\n| ---------------- | ---------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| addMethodOptions | AddMethodOptions | **true** | An object containing the name and method to add. Within this method, the return value of `GlobalStore.summonAll()` is already passed in as the first parameter. |\n\nAdd a custom method to the entire GlobalStore class, which is accessible through `GlobalStore.useMethod()`. This method can be used to modify any store instance.\n\nThis is valuable for convenience sake, or when you are making complex modifications to multiple stores.\n\n**Usage:**\n\nHere is an example of using addMethod to add a complex method to GlobalStore, which modifies the state of three different instances.\n\n```TypeScript\n// Import GlobalStore and the CustomMethod type\nimport { GlobalStore, CustomMethod } from 'apify-global-store';\n\nimport { methodNames, storeNames } from './consts';\n\n// Destructure our constants\nconst { ADD_PRODUCT_AND_REVIEWS } = methodNames;\nconst { PRODUCTS, REVIEWS, RUN_DATA } = storeNames;\n\n// Create a function which ALWAYS takes StoreInstances as the first argument\n// Our custom arguments come after the first one\nconst method: CustomMethod = async (instances, product, website) =\u003e {\n    // Grab the instances of each store we need\n    const productStore = instances[PRODUCTS];\n    const reviewsStore = instances[REVIEWS];\n    const runDataStore = instances[RUN_DATA]\n\n    // First, add our product to the PRODUCTS GlobalStore instance\n    productStore.set((prev) =\u003e {\n        // Grab the product's data without its reviews\n        const { reviews, ...productData } = product;\n\n        return {\n            // Spread the previous state\n            ...prev,\n            [website]: {\n                products: {\n                    // Spread the previous data for [website].products\n                    ...prev[website].products,\n                    // Add our new product\n                    [productData.id]: productData\n                }\n            }\n        }\n    })\n\n    // Add our product's reviews to the REVIEWS GlobalStore instance\n    reviewsStore.setPath([website, product.id, 'latestReviews'], product.reviews)\n\n    // If the products for this specific website has reached our threshold,\n    // push the data to the dataset and delete it from the REVIEWS store\n    if (reviewsStore.state[website].length \u003e= 100) {\n        await reviewsStore.pushPath(website);\n    };\n\n    // Update our RUN-DATA store\n    runDataStore.set((prev) =\u003e {\n        return {\n            ...prev,\n            [website]: {\n                ...prev[website],\n                runs: prev[website].runs + 1\n            }\n        }\n    })\n};\n\nGlobalStore.addMethod({ name: ADD_PRODUCT_AND_REVIEWS, method });\n```\n\n\u003e **Note:** It's not recommended to use reducers inside of these custom methods. That can make things complicated very quickly. `addMethod` can serve as an alternative to `addReducer`.\n\n### `GlobalStore.useMethod()`\n\n(**name**: _string_, **...rest**) =\u003e `void` | `Promise\u003cvoid\u003e`\n\n| Argument | Type   | Required  | Description                                                |\n| -------- | ------ | --------- | ---------------------------------------------------------- |\n| name     | string | **true**  | The name of the method used when adding it to GlobalStore. |\n| ...rest  | any[]  | **false** | Any custom parameters the method needs to run properly     |\n\n**Usage:**\n\n```TypeScript\nimport { methodNames } from './consts';\n\nconst { ADD_PRODUCT_AND_REVIEWS } = methodNames;\n\nconst product = parseProduct($);\n\nawait GlobalStore.useMethod(ADD_PRODUCT_AND_REVIEWS, product, new URL(request.url).hostname);\n```\n\n## Best Practices\n\nThese are not necessarily gospel, but they can help you modularize and scale your project while also making it more readable.\n\n### Store Management\n\nWhen using more than one instance of GlobalStore, it is best to use custom store names, and to put them into a constant:\n\n`consts.ts`:\n\n```TypeScript\nexport enum storeNames { PRODUCTS = 'PRODUCTS', HOTELS = 'HOTELS' };\n```\n\n`main.ts`:\n\n```TypeScript\nimport { storeNames } from './consts';\n\nconst productStore = await GlobalStore.init({ name: storeNames.PRODUCTS });\n\nconst hotelStore = await GlobalStore.init({name: storeNames.HOTELS});\n\nconst summoned = GlobalStore.summon(storeNames.HOTELS);\n```\n\n### Using a reducer\n\n1. It is always best practice to define your action types as constants, then to import them when defining your reducer.\n2. Always define your reducer outside of the `store.addReducer()` method. Ideally, this should be done in a separate file, then imported.\n\n**Example:**\n\n`consts.ts`:\n\n```TypeScript\nexport enum actions {\n    GENERAL = 'GENERAL',\n    ADD_PRODUCT = 'ADD_PRODUCT',\n}\n```\n\n`reducer.ts`:\n\n```TypeScript\nimport { ReducerFunction } from 'apify-global-store';\nimport { actions } from './consts';\n\nconst reducer: ReducerFunction = (state, action) =\u003e {\n    switch (action.type) {\n        default:\n            return state;\n        case actions.GENERAL:\n            return {\n                ...state,\n                ...action.payload,\n            };\n        case actions.ADD_PRODUCT:\n            return {\n                ...state,\n                products: { ...state.products, ...action.payload }\n            }\n    }\n};\n\nexport default reducer;\n```\n\n`main.ts`:\n\n```TypeScript\nimport { GlobalStore } from 'apify-global-store';\nimport { actions } from './consts'\nimport reducer from './reducer'\n\nconst store = await GlobalStore.init();\nstore.addReducer(reducer);\n\nstore.setWithReducer({\n        type: actions.GENERAL,\n        payload: { hello: 'world' },\n    });\n```\n\n## Storage\n\nIn the Key-Value store, each store will be represented by an object looking like this:\n\n```JSON\n{\n    \"store\": {\n        \"hello\": \"world\"\n    },\n    \"data\": {\n        \"sizeInBytes\": 17,\n        \"lastModified\": \"2022-03-18T15:39:45.041Z\",\n        \"globalStoreVersion\": \"1.0.9\",\n        \"type\": \"LOCAL\"\n    }\n}\n```\n\nIf the `cloud` option was not set to `true` upon the store's initialization, the store will be local to the actor's run under a key in the default Key-Value store.\n\nIf `cloud` was set to `true`, the global store will be stored in the cloud on your Apify account, under a named Key-Value store called `CLOUD-GLOBAL-STORES`.\n\n\u003e **Please:** DO NOT manually modify these objects using `Apify.setValue()`. GlobalStore uses the actor's default Key-Value store under the hood.\n\n## Available Types\n\n-   **_GlobalStore_**\n\nThe GlobalStore class.\n\n-   **_InitializeOptions_**\n\nThe options to initialize an instance of GlobalStore.\n\n```TypeScript\ninterface InitializeOptions {\n    name?: string;\n    initialState?: Record\u003cstring, unknown\u003e;\n    cloud?: boolean;\n    debug?: boolean;\n}\n```\n\n-   **_StoreState_**\n\nAn object representing the state returned from `store.state`.\n\n```TypeScript\ntype StoreState = Record\u003cstring, unknown\u003e;\n```\n\n-   **_SetStateFunctionCallback_**\n\nThe callback function to be passed into `store.set()`\n\n```TypeScript\ntype SetStateFunctionCallBack = (previous: StoreState) =\u003e StoreState;\n```\n\n-   **_ReducerParam_**\n\nThe `action` object of your reducer function. Must include a `type` key.\n\n```TypeScript\ninterface ReducerType {\n    type: string;\n}\n\ntype ReducerParam\u003cT\u003e = ReducerType \u0026 Record\u003cstring, T\u003e;\n```\n\n-   **_ReducerFunction_**\n\nA function which should be passed into `store.addReducer()`\n\n```TypeScript\ntype ReducerFunction = \u003cT\u003e(state: StoreState, action: ReducerParam\u003cT\u003e) =\u003e StoreState;\n```\n\n-   **_StoreData_**\n\nAn object representing the data which is returned from `store.info`\n\n```TypeScript\ninterface StoreData {\n    sizeInBytes: number;\n    lastModified: string;\n    globalStoreVersion: string;\n    type: 'LOCAL' | 'CLOUD';\n}\n```\n\n-   **_StoreInstances_**\n\nAn object which hold all instances of GlobalStore, accessible through `GlobalStore.summonAll()`\n\n```TypeScript\ntype StoreInstances = Record\u003cDefaultStoreName | string, GlobalStore\u003e;\n```\n\n-   **_AddMethodOptions_**\n\n```TypeScript\nexport type CustomMethod = (storeInstances: StoreInstances, ...rest: any[]) =\u003e unknown | Promise\u003cunknown\u003e;\n\ninterface AddMethodOptions {\n    name: string;\n    method: CustomMethod;\n}\n```\n\n## Credits\n\n### Matt Stephens\n\n-   [LinkedIn](https://www.linkedin.com/in/mstephen19/)\n-   [Github](https://github.com/mstephen19)\n\n### Kristýna Lhoťanová\n\n-   [Github](https://github.com/lhotanok)\n\n## License\n\nCopyright (c) 2022-present Matt Stephens\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmstephen19%2Fapify-global-store","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmstephen19%2Fapify-global-store","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmstephen19%2Fapify-global-store/lists"}