{"id":17051838,"url":"https://github.com/therolffr/firestorm-db","last_synced_at":"2025-10-29T07:48:41.019Z","repository":{"id":43126267,"uuid":"365211081","full_name":"TheRolfFR/firestorm-db","owner":"TheRolfFR","description":"Self hosted Firestore-like database with API endpoints based on micro bulk operations","archived":false,"fork":false,"pushed_at":"2025-08-23T14:38:42.000Z","size":2234,"stargazers_count":3,"open_issues_count":4,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-10-06T12:40:45.010Z","etag":null,"topics":["api","javascript","js","nodejs","npm","php"],"latest_commit_sha":null,"homepage":"https://therolffr.github.io/firestorm-db/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TheRolfFR.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-05-07T11:26:05.000Z","updated_at":"2025-08-23T14:38:25.000Z","dependencies_parsed_at":"2022-08-26T15:11:29.562Z","dependency_job_id":"21dab2bf-7013-483f-af8c-070b7e9fb10e","html_url":"https://github.com/TheRolfFR/firestorm-db","commit_stats":{"total_commits":139,"total_committers":5,"mean_commits":27.8,"dds":"0.16546762589928055","last_synced_commit":"ceacbad527745aa4a40e6b0ac019d79c263e9168"},"previous_names":["therolffr/firestorm"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/TheRolfFR/firestorm-db","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheRolfFR%2Ffirestorm-db","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheRolfFR%2Ffirestorm-db/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheRolfFR%2Ffirestorm-db/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheRolfFR%2Ffirestorm-db/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheRolfFR","download_url":"https://codeload.github.com/TheRolfFR/firestorm-db/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheRolfFR%2Ffirestorm-db/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281584986,"owners_count":26526171,"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","status":"online","status_checked_at":"2025-10-29T02:00:06.901Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["api","javascript","js","nodejs","npm","php"],"created_at":"2024-10-14T10:07:39.610Z","updated_at":"2025-10-29T07:48:41.002Z","avatar_url":"https://github.com/TheRolfFR.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\r\n\u003cimg src=\"img/firestorm-128.png\"\u003e\r\n\r\n\u003ch1\u003efirestorm-db\u003c/h1\u003e\r\n\r\n\u003ca href=\"https://www.npmjs.com/package/firestorm-db\" target=\"_blank\"\u003e\r\n    \u003cimg alt=\"npm\" src=\"https://img.shields.io/npm/v/firestorm-db?color=cb0000\u0026logo=npm\u0026style=flat-square\"\u003e\r\n\u003c/a\u003e\r\n\u003cimg alt=\"GitHub file size in bytes\" src=\"https://img.shields.io/github/size/TheRolfFR/firestorm-db/src%2Findex.js?color=43A047\u0026label=Script%20size\u0026logoColor=green\u0026style=flat-square\"\u003e\r\n\u003ca href=\"https://github.com/TheRolfFR/firestorm-db/blob/main/CHANGELOG.md\"\u003e\r\n    \u003cimg alt=\"Changelog\" src=\"https://img.shields.io/badge/Changelog-Read_here-blue?style=flat-square\"\u003e\r\n\u003c/a\u003e\r\n\u003ca href=\"https://github.com/TheRolfFR/firestorm-db/actions/workflows/tests-js.yml\"\u003e\r\n    \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/TheRolfFR/firestorm-db/tests-js.yml?style=flat-square\" alt=\"Tests\" /\u003e\r\n\u003c/a\u003e\r\n\u003c/div\u003e\r\n\r\n*Self hosted Firestore-like database with API endpoints based on micro bulk operations.*\r\n\r\n# Installation\r\n\r\nInstalling the JavaScript client is as simple as running:\r\n\r\n```sh\r\nnpm install firestorm-db\r\n```\r\n\r\nInformation about installing Firestorm server-side is given in the [PHP](#php-backend) section.\r\n\r\n# JavaScript Client\r\n\r\nThe JavaScript [index.js](./src/index.js) file is simply an [Axios](https://www.npmjs.com/package/axios) wrapper of the PHP backend.\r\n\r\n## JavaScript setup\r\n\r\nFirst, set your API address (and your writing token if needed) using the `address()` and `token()` functions:\r\n\r\n```js\r\n// only needed in Node.js; including the script tag in a browser is enough otherwise.\r\nconst firestorm = require(\"firestorm-db\");\r\n\r\nfirestorm.address(\"http://example.com/path/to/firestorm/root/\");\r\n\r\n// only necessary if you want to write or access private collections\r\n// must match token stored in tokens.php file\r\nfirestorm.token(\"my_secret_token_probably_from_an_env_file\");\r\n```\r\n\r\nNow you can use Firestorm to its full potential.\r\n\r\n## Create your first collection\r\n\r\nFirestorm is based around the concept of a `Collection`, which is akin to an SQL table or Firestore document. The Firestorm collection constructor takes one required argument and one optional argument:\r\n\r\n- The name of the collection as a `string`.\r\n- A method adder, which lets you inject methods to query results. It's implemented similarly to [`Array.prototype.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map), taking a queried element as an argument, modifying the element with methods and data inside a callback, and returning the modified element at the end.\r\n\r\n```js\r\nconst firestorm = require(\"firestorm-db\");\r\n\r\nconst userCollection = firestorm.collection(\"users\", (el) =\u003e {\r\n    // assumes you have a 'users' table with a printable field called 'name'\r\n    el.hello = () =\u003e `${el.name} says hello!`;\r\n    // return the modified element back with the injected method\r\n    return el;\r\n});\r\n\r\n// all methods return promises\r\nconst johnDoe = await userCollection.get(123456789);\r\n// gives { name: \"John Doe\", hello: Function }\r\n\r\njohnDoe.hello(); // \"John Doe says hello!\"\r\n```\r\n\r\n## Read operations\r\n\r\n| Name                      | Parameters                                                  | Description                                                                                            |\r\n| ------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |\r\n| sha1()                    | none                                                        | Get the SHA-1 hash of the file. Can be used to compare file content without downloading the JSON.      |\r\n| readRaw(original)         | original?: `boolean`                                        | Read the entire collection. `original` disables ID field injection, for non-relational collections.    |\r\n| get(key)                  | key: `string \\| number`                                     | Get an element from the collection by its key.                                                         |\r\n| searchKeys(keys)          | keys: `(string \\| number)[]`                                | Get multiple elements from the collection by their keys.                                               |\r\n| search(options, random)   | options: `SearchOption[]` random?:`boolean \\| number`       | Search through the collection. You can randomize the output order with random as true or a given seed. |\r\n| select(option)            | option: `SelectOption`                                      | Get only selected fields from the collection. Essentially an upgraded version of readRaw.              |\r\n| values(option)            | option: `ValueOption`                                       | Get all distinct non-null values for a given key across a collection.                                  |\r\n| random(max, seed, offset) | max?: `number \u003e= -1` seed?: `number` offset?: `number \u003e= 0` | Read random collection elements.                                                                |\r\n\r\n## Write operations\r\n\r\n| Name                    | Parameters                                       | Description                                                                               |\r\n| ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------- |\r\n| writeRaw(value)         | value: `Object`                                  | Set the entire content of the collection. **⚠️ Very dangerous! ⚠️**                         |\r\n| add(value)              | value: `Object`                                  | Append a value to the collection. Only works if `autoKey` is enabled server-side.         |\r\n| addBulk(values)         | values: `Object[]`                               | Append multiple values to the collection. Only works if `autoKey` is enabled server-side. |\r\n| remove(key)             | key: `string \\| number`                          | Remove an element from the collection by its key.                                         |\r\n| removeBulk(keys)        | keys: `(string \\| number)[]`                     | Remove multiple elements from the collection by their keys.                               |\r\n| set(key, value)         | key: `string \\| number`, value: `Object`         | Set a value in the collection by its key.                                                 |\r\n| setBulk(keys, values)   | keys: `(string \\| number)[]`, values: `Object[]` | Set multiple values in the collection by their keys.                                      |\r\n| editField(obj)          | option: `EditFieldOption`                        | Edit an element's field in the collection.                                                |\r\n| editFieldBulk(objArray) | options: `EditFieldOption[]`                     | Edit multiple elements' fields in the collection.                                         |\r\n\r\n## Search options\r\n\r\nThere are more options available than the Firestore `where` command, allowing you to get better and faster search results.\r\n\r\nThe search method can take one or more options to filter entries in a collection. A search option takes a `field` with a `criteria` and compares it to a `value`. You can also use the boolean `ignoreCase` option for string values. Available criteria depends on the field type.\r\n\r\n| Criteria                | Types allowed                 | Description                                                     |\r\n| ----------------------- | ----------------------------- | --------------------------------------------------------------- |\r\n| `'!='`                  | `boolean`, `number`, `string` | Entry field's value is different from yours                     |\r\n| `'=='`                  | `boolean`, `number`, `string` | Entry field's value is equal to yours                           |\r\n| `'\u003e='`                  | `number`, `string`            | Entry field's value is greater or equal than yours              |\r\n| `'\u003c='`                  | `number`, `string`            | Entry field's value is equal to than yours                      |\r\n| `'\u003e'`                   | `number`, `string`            | Entry field's value is greater than yours                       |\r\n| `'\u003c'`                   | `number`, `string`            | Entry field's value is lower than yours                         |\r\n| `'in'`                  | `number`, `string`            | Entry field's value is in the array of values you gave          |\r\n| `'includes'`            | `string`                      | Entry field's value includes your substring                     |\r\n| `'startsWith'`          | `string`                      | Entry field's value starts with your substring                  |\r\n| `'endsWith'`            | `string`                      | Entry field's value ends with your substring                    |\r\n| `'array-contains'`      | `Array`                       | Entry field's array contains your value                         |\r\n| `'array-contains-none'` | `Array`                       | Entry field's array contains no values from your array          |\r\n| `'array-contains-any'`  | `Array`                       | Entry field's array contains at least one value from your array |\r\n| `'array-contains-all'`  | `Array`                       | Entry field's array contains every value from your array        |\r\n| `'array-length-eq'`     | `number`                      | Entry field's array size is equal to your value                 |\r\n| `'array-length-df'`     | `number`                      | Entry field's array size is different from your value           |\r\n| `'array-length-lt'`     | `number`                      | Entry field's array size is lower than your value               |\r\n| `'array-length-gt'`     | `number`                      | Entry field's array size is greater than your value             |\r\n| `'array-length-le'`     | `number`                      | Entry field's array size is lower or equal to your value        |\r\n| `'array-length-ge'`     | `number`                      | Entry field's array size is greater or equal to your value      |\r\n\r\n## Edit field options\r\n\r\nEdit objects have an element `id`, a `field` to edit, an `operation` specifying what to do to this field, and optionally a `value`.\r\n\r\n| Operation      | Needs value | Allowed value types      | Description                                                                                                                            |\r\n| -------------- | ----------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------|\r\n| `set`          | Yes         | `any`                    | Sets a value to a given field.                                                                                                         |\r\n| `remove`       | No          | *N/A*                    | Removes a field from the element.                                                                                                      |\r\n| `append`       | Yes         | `string`                 | Appends a string to the end of a string field.                                                                                         |\r\n| `invert`       | No          | *N/A*                    | Inverts the state of a boolean field.                                                                                                  |\r\n| `increment`    | No          | `number`                 | Adds a number to the field (default: 1).                                                                                               |\r\n| `decrement`    | No          | `number`                 | Removes a number from the field (default: 1).                                                                                          |\r\n| `array-push `  | Yes         | `any`                    | Pushes an element to the end of an array field.                                                                                        |\r\n| `array-delete` | Yes         | `number`                 | Removes an array element by index.                                                                                                     |\r\n| `array-splice` | Yes         | `[number, number, any?]` | Last argument is optional. Check the PHP [array_splice](https://www.php.net/manual/function.array-splice) documentation for more info. |\r\n\r\nVarious other methods and constants exist in the JavaScript client, which will make more sense once you learn what's actually happening behind the scenes.\r\n\r\n# PHP Backend\r\n\r\nFirestorm's PHP files handle files, read, and writes, through `GET` and `POST` requests sent by the JavaScript client. All JavaScript methods correspond to an equivalent Axios request to the relevant PHP file.\r\n\r\n## PHP setup\r\n\r\nThe server-side files to handle requests can be found and copied to your hosting platform [here](./php/). The two files that need editing are `tokens.php` and `config.php`.\r\n\r\n- `tokens.php` contains writing tokens declared in a `$db_tokens` array. These correspond to the tokens used with `firestorm.token()` in the JavaScript client.\r\n- `config.php` stores all of your collections. This file needs to declare a `$database_list` associative array of `JSONDatabase` instances.\r\n\r\n```php\r\n\u003c?php\r\n// config.php\r\nrequire_once './classes/JSONDatabase.php';\r\n\r\n$database_list = [];\r\n\r\n// without constructor\r\n$tmp = new JSONDatabase;\r\n$tmp-\u003efolderPath = './files/';\r\n$tmp-\u003efileName = 'orders';\r\n$tmp-\u003eautoKey = true;\r\n$tmp-\u003eautoIncrement = false;\r\n\r\n$database_list[$tmp-\u003efileName] = $tmp;\r\n\r\n// with constructor ($fileName, $autoKey = true, $autoIncrement = true)\r\n$tmp = new JSONDatabase('users', false);\r\n$tmp-\u003efolderPath = './files/';\r\n\r\n$database_list[$tmp-\u003efileName] = $tmp;\r\n```\r\n\r\n- The database will be stored in `\u003cfolderPath\u003e/\u003cfileName\u003e.json` (default folder: `./files/`).\r\n- `autoKey` controls whether to automatically generate the key name or to have explicit key names (default: `true`).\r\n- `autoIncrement` controls whether to simply start generating key names from zero or to use a [random ID](https://www.php.net/manual/en/function.uniqid.php) each time (default: `true`).\r\n- The key in the `$database_list` array is what the collection should be referred to in the JavaScript collection constructor. This can be different from the JSON filename if needed.\r\n\r\nIf you're working with multiple collections, it can be easier to initialize them all in the array constructor directly:\r\n\r\n```php\r\n// config.php\r\n\u003c?php\r\nrequire_once './classes/JSONDatabase.php';\r\n$database_list = [\r\n    'orders' =\u003e new JSONDatabase('orders', true),\r\n    'users' =\u003e new JSONDatabase('users', false),\r\n];\r\n```\r\n\r\n## Permissions\r\n\r\nThe PHP scripts used to write and read files need permissions to edit the JSON files. You can give Firestorm rights to a folder with the following command:\r\n\r\n```sh\r\nsudo chown -R www-data \"/path/to/firestorm/root/\"\r\n```\r\n\r\n# Firestorm Files\r\n\r\nFirestorm's file APIs are implemented in `files.php`. If you don't need file-related features, then simply delete this file.\r\n\r\nTo work with files server-side, you need to add two new configuration variables in `config.php`:\r\n\r\n```php\r\n// Extension whitelist\r\n$authorized_file_extension = ['.txt', '.png', '.jpg', '.jpeg'];\r\n\r\n// Root directory for where files should be uploaded\r\n// ($_SERVER['SCRIPT_FILENAME']) is a shortcut to the root Firestorm directory.\r\n$STORAGE_LOCATION = dirname($_SERVER['SCRIPT_FILENAME']) . '/uploads/';\r\n```\r\n\r\nFrom there, you can use the functions in `firestorm.files` (detailed below) from the JavaScript client.\r\n\r\n## Upload a file\r\n\r\n`firestorm.files.upload` uses a `FormData` object to represent an uploaded file. This class is generated from forms and is [native in modern browsers](https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData), and with Node.js can be installed with the [form-data](https://www.npmjs.com/package/form-data) package.\r\n\r\nThe uploaded file content can be a [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), a [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob), a [Buffer](https://nodejs.org/api/buffer.html), or an [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer).\r\n\r\nThere is additionally an overwrite option in order to avoid mistakes.\r\n\r\n```js\r\nconst FormData = require(\"form-data\");\r\nconst firestorm = require(\"firestorm-db\");\r\nfirestorm.address(\"ADDRESS_VALUE\");\r\nfirestorm.token(\"TOKEN_VALUE\");\r\n\r\nconst form = new FormData();\r\nform.append(\"path\", \"/quote.txt\");\r\n// make sure to set a temporary file name\r\nform.append(\"file\", \"but your kids are gonna love it.\", \"quote.txt\");\r\n// override is false by default; don't append it if you don't need to\r\nform.append(\"overwrite\", \"true\");\r\n\r\nconst uploadPromise = firestorm.files.upload(form);\r\n\r\nuploadPromise\r\n    .then(() =\u003e console.log(\"Upload successful\"))\r\n    .catch((err) =\u003e console.error(err));\r\n```\r\n\r\n## Get a file\r\n\r\n`firestorm.files.get` takes a file's direct URL location or its content as its parameter. If your upload folder is accessible from a server URL, you can directly use its address to retrieve the file without this method.\r\n\r\n```js\r\nconst firestorm = require(\"firestorm-db\");\r\nfirestorm.address(\"ADDRESS_VALUE\");\r\n\r\nconst getPromise = firestorm.files.get(\"/quote.txt\");\r\n\r\ngetPromise\r\n    .then((fileContent) =\u003e console.log(fileContent)) // but your kids are gonna love it.\r\n    .catch((err) =\u003e console.error(err));\r\n```\r\n\r\n## Delete a file\r\n\r\n`firestorm.files.delete` has the same interface as `firestorm.files.get`, but as the name suggests, it deletes the file.\r\n\r\n```js\r\nconst firestorm = require(\"firestorm-db\");\r\nfirestorm.address(\"ADDRESS_VALUE\");\r\nfirestorm.token(\"TOKEN_VALUE\");\r\n\r\nconst deletePromise = firestorm.files.delete(\"/quote.txt\");\r\n\r\ndeletePromise\r\n    .then(() =\u003e console.log(\"File successfully deleted\"))\r\n    .catch((err) =\u003e console.error(err));\r\n```\r\n\r\n# Advanced Features\r\n\r\n## `ID_FIELD` and its meaning\r\n\r\nThere's a constant in Firestorm called `ID_FIELD`, which is a JavaScript-side property added afterwards to each query element.\r\n\r\nIts value will always be the key of the element its in, which allows you to use `Object.values` on results without worrying about losing the elements' key names. Additionally, it can be used in the method adder in the constructor, and is convenient for collections where the key name is significant.\r\n\r\n```js\r\nconst userCollection = firestorm.collection(\"users\", (el) =\u003e {\r\n    el.basicInfo = () =\u003e `${el.name} (${el[firestorm.ID_FIELD]})`;\r\n    return el;\r\n});\r\n\r\nconst returnedID = await userCollection.add({ name: \"Bob\", age: 30 });\r\nconst returnedUser = await userCollection.get(returnedID);\r\n\r\nconsole.log(returnedID === returnedUser[firestorm.ID_FIELD]); // true\r\n\r\nreturnedUser.basicInfo(); // Bob (123456789)\r\n```\r\n\r\nAs it's entirely a JavaScript construct, `ID_FIELD` values will actually never be in the server-side collection JSONs.\r\n\r\n## Add and set operations\r\n\r\nYou may have noticed two different methods that seem to do the same thing: `add` and `set` (and their corresponding bulk variants). The key difference is that `add` automatically generates a key for the given value, and hence can only be used on collections where `autoKey` is enabled, but `set` can be used on any collection type. `autoIncrement` doesn't affect this behavior.\r\n\r\nFor instance, the following PHP configuration will disable add operations:\r\n\r\n```php\r\n$database_list['users'] = new JSONDatabase('users', false);\r\n```\r\n\r\n```js\r\nconst userCollection = firestorm.collection(\"users\");\r\n// Error: Automatic key generation is disabled\r\nawait userCollection.add({ name: \"John Doe\", age: 30 });\r\n```\r\n\r\nAdd operations return the generated ID of the added element, since it isn't known at add time, but set operations simply return a confirmation. If you want to get an element after it's been set, use the ID passed into the method.\r\n\r\n```js\r\n// Works, ID is returned\r\nuserCollection.add({ name: \"John Doe\", age: 30 })\r\n    .then((id) =\u003e userCollection.get(id));\r\n\r\n// Works, using already-known ID to retrieve results\r\nuserCollection.set(123, { name: \"John Doe\", age: 30 })\r\n    .then(() =\u003e userCollection.get(123));\r\n\r\n// Fails, confirmation is returned rather than ID\r\nuserCollection.set(123, { name: \"John Doe\", age: 30 })\r\n    .then((conf) =\u003e userCollection.get(conf));\r\n```\r\n\r\n## Combining collections\r\n\r\nUsing add methods in the constructor, you can link multiple collections together.\r\n\r\n```js\r\nconst orders = firestorm.collection(\"orders\");\r\n\r\n// using the example of a customer having orders\r\nconst customers = firestorm.collection(\"customers\", (el) =\u003e {\r\n    el.getOrders = () =\u003e orders.search([\r\n        {\r\n            field: \"customer\",\r\n            criteria: \"==\",\r\n            // assuming the customers field in the orders collection is a user ID\r\n            value: el[firestorm.ID_FIELD]\r\n        }\r\n    ])\r\n    return el;\r\n})\r\n\r\nconst johnDoe = await customers.get(123456789);\r\n\r\n// returns orders where the customer field is John Doe's ID\r\nawait johnDoe.getOrders();\r\n```\r\n\r\nThis functionality is particularly useful for complex data hierarchies with foreign keys spanning multiple collections, and is the main reason why add methods exist in the first place. It can also be used to split deeply nested data structures to increase server-side performance by only loading relevant data.\r\n\r\n## Manually sending data\r\n\r\nEach operation type requests a different file. In the JavaScript client, the corresponding file gets appended onto your base Firestorm address.\r\n\r\n- Read requests are `GET` requests sent to `\u003cyour_address_here\u003e/get.php`.\r\n- Write requests are `POST` requests sent to `\u003cyour_address_here\u003e/post.php` with JSON data.\r\n- File requests are sent to `\u003cyour_address_here\u003e/files.php` with form data.\r\n\r\nThe first keys in a Firestorm request will always be the same regardless of its type, and further keys will depend on the specific method:\r\n\r\n```json\r\n{\r\n    \"collection\": \"\u003ccollectionName\u003e\",\r\n    \"token\": \"\u003cwriteTokenIfNecessary\u003e\",\r\n    \"command\": \"\u003cmethodName\u003e\",\r\n    ...\r\n}\r\n```\r\n\r\nThe requested PHP file then grabs the `JSONDatabase` instance created in `config.php` using the `collection` key in the request as the `$database_list` key name. From there, the `token` is used to validate the request if needed and the `command` is found and executed.\r\n\r\n## Memory management\r\n\r\nHandling very large collections can cause memory allocation issues:\r\n\r\n```\r\nFatal error:\r\nAllowed memory size of 134217728 bytes exhausted (tried to allocate 32360168 bytes)\r\n```\r\n\r\nIf you encounter a memory allocation issue, simply change the memory limit in `/etc/php/7.4/apache2/php.ini` to be bigger:\r\n\r\n```ini\r\nmemory_limit = 256M\r\n```\r\n\r\nIf this doesn't help, considering splitting your collection into multiple smaller collections and linking them together with methods.\r\n\r\n# TypeScript Support\r\n\r\nFirestorm ships with TypeScript support out of the box.\r\n\r\n## Collection types\r\n\r\nCollections in TypeScript take a generic parameter `T`, which is the type of each element in the collection. If you aren't using a relational collection, this can simply be set to `any`.\r\n\r\nThe generic parameter must contain an `ID_FIELD` imported from Firestorm (unless you're using a non-relational collection).\r\n\r\n```ts\r\nimport firestorm from \"firestorm-db\";\r\nfirestorm.address(\"ADDRESS_VALUE\");\r\n\r\ninterface User {\r\n    // An ID field is required by a generic constraint\r\n    // unless the collection is non-relational\r\n    [firestorm.ID_FIELD]: string;\r\n    name: string;\r\n    password: string;\r\n    pets: string[];\r\n}\r\n\r\nconst userCollection = firestorm.collection\u003cUser\u003e(\"users\");\r\n\r\nconst johnDoe = await userCollection.get(123456789);\r\n// type: { [ID_FIELD]: string, name: string, password: string, pets: string[] }\r\n```\r\n\r\nInjected methods should also be stored in this interface. They'll get filtered out from write operations to prevent false positives:\r\n\r\n```ts\r\nimport firestorm from \"firestorm-db\";\r\nfirestorm.address(\"ADDRESS_VALUE\");\r\n\r\ninterface User {\r\n    [firestorm.ID_FIELD]: string;\r\n    name: string;\r\n    hello(): string;\r\n}\r\n\r\nconst userCollection = firestorm.collection(\"users\", (el) =\u003e {\r\n    // interface types should agree with injected methods\r\n    el.hello = () =\u003e `${el.name} says hello!`;\r\n    return el;\r\n});\r\n\r\nconst johnDoe = await userCollection.get(123456789);\r\nconst hello = johnDoe.hello(); // type: string\r\n\r\nawait userCollection.add({\r\n    name: \"Mary Doe\",\r\n    // Error: 'hello' does not exist in type 'Addable\u003cUser\u003e'.\r\n    hello() {\r\n        return \"Mary Doe says hello!\"\r\n    }\r\n})\r\n```\r\n\r\n## Additional types\r\n\r\nAdditional types exist for search criteria options, write method return types, configuration methods, the file handler, etc.\r\n\r\n```ts\r\nimport firestorm from \"firestorm-db\";\r\nconst address = firestorm.address(\"ADDRESS_VALUE\");\r\n// type: string\r\n\r\nconst deleteConfirmation = await firestorm.files.delete(\"/quote.txt\");\r\n// type: firestorm.WriteConfirmation\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftherolffr%2Ffirestorm-db","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftherolffr%2Ffirestorm-db","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftherolffr%2Ffirestorm-db/lists"}