{"id":"grunionnn/dataservice","name":"dataservice","scope":"grunionnn","platform":"roblox","description":"Type-safe Roblox data-store wrapper with automatic client replication, nested value wrappers, signals, arrays, and mock-store support","version":"1.0.1","latest":"1.0.1","versions":["0.0.8","0.0.9","0.0.10","1.0.0","1.0.1"],"license":"MIT","licenseRating":"safe","licenseCaveats":["The package archive does not include its license text; the license is declared in its manifest metadata."],"licenseVerified":false,"dependencies":{"stravant/goodsignal":{"version":"^0.3.1","alias":"goodsignal"},"grunionnn/networker":{"version":"^0.3.1","alias":"networker"},"lm-loleris/profilestore":{"version":"^1.0.3","alias":"profilestore"}},"integrity":"64b519fed0b25e7781e1559cb711c055fe8eca3724eb6bef7707616712bafff9","likes":0,"downloads":0,"install":"forest install grunionnn/dataservice","url":"https://forest.dev/p/roblox/grunionnn/dataservice","files":"https://api.forest.dev/ai/package/roblox/grunionnn/dataservice/files","readme":"# DataService\n\nDataService is a type-safe Roblox data-store wrapper with automatic client replication, nested value wrappers, signals, arrays, and mock-store support.\n\n## Features\n\n- Strongly typed server and client APIs using Luau's new type solver\n- ProfileStore-backed player data with optional mock stores\n- Automatic snapshots and mutation replication\n- Callable values for reading, setting, and updating data\n- Typed nested tables, dictionaries, and arrays\n- Typed `Changed`, `OnInsert`, and `OnRemove` signals\n- Array `Insert` and `RemoveAt` operations\n- Per-mutation replication suppression on writable values\n- Runtime protection against direct field assignment\n\n## Installation\n\nAdd DataService to your `wally.toml` dependencies:\n\n```toml\n[dependencies]\nDataService = \"grunionnn/dataservice@version\"\n```\n\nThen install the package:\n\n```sh\nwally install\n```\n\nDataService expects its server dependencies to be available through the Rojo project. Its current Wally dependencies are Networker, GoodSignal, and ProfileStore.\n\n## Quick Example\n\nCreate and return one configured DataService module shared by the server and client:\n\n```luau\nlocal ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\n\nlocal DataService = require(ReplicatedStorage.Packages.DataService)\n\nlocal template = {\n\tCoins = 0,\n\tInventory = {} :: { [string]: number },\n\tItems = {} :: { number },\n\tSettings = {\n\t\tMusicVolume = 0.5,\n\t},\n}\n\nreturn DataService({\n\ttemplate = template,\n\tuseMock = false,\n\tprofileStoreIndex = \"PlayerData\",\n})\n```\n\nUse the configured service on the server:\n\n```luau\nlocal Players = game:GetService(\"Players\")\nlocal ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\n\nlocal Data = require(ReplicatedStorage.Data).server\n\nData.PlayerInitialized:Connect(function(player)\n\tlocal coins = Data[player].Coins()\n\tData[player].Coins(coins + 10)\n\n\tData[player].Coins(function(current)\n\t\treturn current + 1\n\tend)\n\n\tData[player].Inventory[\"Sword\"](1)\n\tData[player].Items.Insert(25)\n\n\tData[player].Coins.Changed:Connect(function(newCoins, oldCoins)\n\t\tprint(player, oldCoins, newCoins)\n\tend)\nend)\n\nPlayers.PlayerAdded:Connect(function(player)\n\tlocal snapshot = Data:WaitForData(player)\n\tif snapshot then\n\t\tprint(`Loaded {snapshot.Coins} coins for {player.Name}`)\n\tend\nend)\n```\n\nPass `true` as the second argument to suppress replication for one set or update:\n\n```luau\nData[player].Coins(200, true)\n\nData[player].Coins(function(current)\n\treturn current + 1\nend, true)\n```\n\nThe mutation is still saved and server-side signals still fire. Pass `false` or omit the second argument to replicate normally.\n\nRead replicated data on the client:\n\n```luau\nlocal ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\n\nlocal Data = require(ReplicatedStorage.Data).client\n\nlocal snapshot = Data:WaitForData()\nassert(snapshot, \"Unable to load data\")\n\nlocal coins: number = snapshot.Coins\n\nData.Coins.Changed:Connect(function(newCoins, oldCoins)\n\tprint(oldCoins, newCoins)\nend)\n\nlocal index, item = Data.Items.OnInsert:Wait()\nprint(index, item)\n```\n\nPublic value signals expose `Connect`, `Once`, and `Wait`. Signal dispatch remains internal to DataService.\n\n## Links\n\n- [Getting Started](docs/GETTINGSTARTED.md)\n- [API Reference](docs/API.md)\n- [Wally package registry](https://wally.run/)\n- [Wally index](https://github.com/UpliftGames/wally-index)\n- [ProfileStore](https://github.com/MadStudioRoblox/ProfileStore)\n- [Rojo](https://rojo.space/)\n\n## Current Version\n\nThe current package version is `1.0.1`.\n\n## Limitations\n\n- DataService requires Luau's new type solver and user-defined type-function support.\n- Only one configured DataService instance may be created in a game runtime.\n- Data is currently scoped around player profiles.\n- Client value wrappers are read-only.\n- Luau does not currently support separate read/write indexer types for generated tables. Dictionary and array indexers therefore use a read/write type-system indexer, while direct assignment is rejected at runtime by the value wrapper.\n- `dontReplicate` suppresses only the selected live mutation. A later full snapshot contains the server's current stored data, so it is not a permanent privacy filter.\n- Skipping an array or structural mutation can leave the current client state unsuitable for later dependent mutations until a fresh snapshot is received.\n\n## License\n\nDataService is available under the MIT License.\n","readmeTruncated":false}