{"id":"hollower233/group-join-reward-service","name":"group-join-reward-service","scope":"hollower233","platform":"roblox","description":"Secure, one-time group-join rewards for Roblox experiences.","version":"0.1.2","latest":"0.1.2","versions":["0.1.0","0.1.1","0.1.2"],"license":"MIT","licenseRating":"safe","licenseCaveats":[],"licenseVerified":true,"dependencies":{"sleitnick/net":{"version":"^0.2.0","alias":"Net"}},"integrity":"2c4c00da75e5ae494f6905609860d1b49c95e4e772915d3bff5b8626aaf6b3e4","likes":0,"downloads":0,"install":"forest install hollower233/group-join-reward-service","url":"https://forest.dev/p/roblox/hollower233/group-join-reward-service","files":"https://api.forest.dev/ai/package/roblox/hollower233/group-join-reward-service/files","readme":"# Group Join Reward Service\r\n\r\nA shared Wally package for a one-time reward after a player joins the Roblox group that owns the experience. The package prompts from the client, but independently verifies membership on the server before awarding anything.\r\n\r\n## Installation\r\n\r\n```toml\r\n[dependencies]\r\nGroupJoinRewardService = \"hollower233/group-join-reward-service@0.1.0\"\r\n```\r\n\r\nRun `wally install`, then require the package from your generated `Packages` folder.\r\n\r\n## Server setup\r\n\r\nCall `server.init` exactly once during server startup. The three callbacks connect the package to your persistence and reward systems.\r\n\r\n```lua\r\nlocal ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\r\nlocal Packages = ReplicatedStorage:WaitForChild(\"Packages\")\r\nlocal GroupJoinRewardService = require(Packages:WaitForChild(\"GroupJoinRewardService\"))\r\n\r\nGroupJoinRewardService.server.init({\r\n\thasClaimed = function(player)\r\n\t\treturn false -- Read your saved one-time-reward flag.\r\n\tend,\r\n\tmarkClaimed = function(player)\r\n\t\t-- Persist the one-time-reward flag.\r\n\tend,\r\n\tgrantReward = function(player)\r\n\t\t-- Grant your currency, item, or cosmetic here.\r\n\t\treturn {\r\n\t\t\tok = true,\r\n\t\t\tresults = { rewardType = \"coins\", amount = 500 },\r\n\t\t}\r\n\tend,\r\n})\r\n```\r\n\r\n`grantReward` must return `{ ok = true, results = ... }` after successfully granting the reward. Return `{ ok = false, reason = \"...\" }` when it cannot award the reward; the package will not mark the player as claimed.\r\n\r\n## Client usage\r\n\r\n```lua\r\nif not GroupJoinRewardService.client.hasClaimed() then\r\n\tlocal result = GroupJoinRewardService.client.request()\r\n\tif result.ok then\r\n\t\tprint(\"Reward granted\", result.results)\r\n\tend\r\nend\r\n```\r\n\r\n`client.request()` uses `GroupService:PromptJoinAsync(game.CreatorId)`. Therefore, publish the experience under the Roblox group whose membership should be rewarded.\r\n\r\n## Result reasons\r\n\r\n- `not_initialized`: The server did not call `server.init`.\r\n- `pending`: Another claim request for this player is being processed.\r\n- `already_claimed`: The persistence callback reports that the player already claimed the reward.\r\n- `not_joined`: The player closed, declined, or could not complete the group prompt.\r\n- `not_in_group`: The server could not verify group membership.\r\n- `prompt_failed` or `request_failed`: Roblox prompt or remote communication failed.\r\n- `error`: A callback raised an error or returned an invalid result.\r\n\r\n## License\r\n\r\nMIT. See [LICENSE](LICENSE).\r\n","readmeTruncated":false}