{"id":"lucasx150/checkout","name":"checkout","scope":"lucasx150","platform":"roblox","description":"DevProduct and Gamepass grant handling","version":"0.1.1","latest":"0.1.1","versions":["0.1.0","0.1.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":{},"integrity":"196aaa9a7b03c56de7bfd48379e830b91e66e3270babc4ec4f3b722aac482e47","likes":0,"downloads":0,"install":"forest install lucasx150/checkout","url":"https://forest.dev/p/roblox/lucasx150/checkout","files":"https://api.forest.dev/ai/package/roblox/lucasx150/checkout/files","readme":"# Checkout\r\n\r\nCheckout is a DevProduct and Gamepass handler for Roblox. It lets you define grant logic as individual ModuleScripts, automatically handles `ProcessReceipt`, checks gamepass ownership on player join, supports client side handlers, and lets you grant DevProducts or Gamepasses directly without a real purchase.\r\n\r\n## Setup\r\n\r\n**Server**:\r\n```lua\r\nlocal Checkout = require(path.to.Checkout)\r\n\r\n-- Register all DevProducts and Gamepasses from a container\r\nCheckout.RegisterDevProductsIn(path.to.DevProducts)\r\nCheckout.RegisterGamepassesIn(path.to.Gamepasses)\r\n\r\n-- Register client-side handlers (replicated to the client automatically)\r\nCheckout.RegisterClientDevProductsIn(path.to.ClientDevProducts)\r\nCheckout.RegisterClientGamepassesIn(path.to.ClientGamepasses)\r\n```\r\n\r\n**Client**:\r\n```lua\r\n-- The server moves CheckoutClient into ReplicatedStorage on startup\r\nrequire(game:GetService(\"ReplicatedStorage\"):WaitForChild(\"CheckoutClient\"))\r\n```\r\n\r\n## Structure\r\n\r\nCheckout is driven by ModuleScripts organised into folders. Each folder is passed to a `Register...In` call, and Checkout will pick up every ModuleScript inside it.\r\n\r\n```\r\nServerScriptService\r\n├── ServerSetup.server.luau  -- the Register...In calls above\r\n├── DevProducts\r\n│   ├── Coins.luau\r\n│   └── Revive.luau\r\n├── Gamepasses\r\n│   └── VIP.luau\r\n├── ClientDevProducts       -- optional, for client-side effects\r\n│   └── Coins.luau\r\n└── ClientGamepasses        -- optional\r\n    └── VIP.luau\r\n```\r\n\r\nA runnable version of this layout, with both entry point scripts, is in [`Example/`](Example).\r\n\r\nA server and client module for the same item can exist independently - you don't need both. A DevProduct with only a client module and no server module is valid (e.g. cosmetic effects that don't need server state).\r\n\r\n## Server modules\r\n\r\nServer modules run on the server when a matching DevProduct is purchased or when a player owns a matching Gamepass.\r\n\r\n* **`Ids`** - array of DevProduct or Gamepass ids this module handles.\r\n* **`Grant`** - called from the server for matching ids.\r\n\r\nFor DevProducts, return `true` or `Enum.ProductPurchaseDecision.PurchaseGranted` on success. Return `false` or `Enum.ProductPurchaseDecision.NotProcessedYet` to signal failure.\r\n\r\nReturn `false` or `Enum.ProductPurchaseDecision.NotProcessedYet` to signal failure.\r\nIf no server module exists, the product is treated as client-only.\r\n\r\n```lua\r\n-- DevProduct\r\nlocal DevProduct = {}\r\n\r\nDevProduct.Ids = {01234, 56789}\r\nDevProduct.Grant = function(player: Player, productId: number, receiptInfo): Enum.ProductPurchaseDecision | boolean\r\n    -- grant the product to the player\r\n    return Enum.ProductPurchaseDecision.PurchaseGranted\r\nend\r\n\r\nreturn DevProduct\r\n```\r\n\r\n## Gamepass module\r\n\r\nEach Gamepass module handles one or more gamepass Ids.\r\n\r\n- **`Ids`** - array of Gamepass ids this module handles.\r\n- **`Grant`** - called from the server when a player owns a gamepass with an id that is in Ids.\r\n\r\nIf no server module exists, the product is treated as client-only.\r\n\r\n```lua\r\n-- Gamepass\r\nlocal Gamepass = {}\r\n\r\nGamepass.Ids = {2345, 6789}\r\nGamepass.Grant = function(player: Player, gamepassId: number)\r\n    -- grant the gamepass to the player\r\nend\r\n\r\nreturn Gamepass\r\n```\r\n\r\n## Client modules\r\n\r\nClient modules run on the purchasing player's client after the (if existing) server handler succeeds. \r\n\r\n- **`Ids`** - array of ids this module handles, matching the server-side module.\r\n- **`Grant`** - called on the client after a successful server grant.\r\n\r\n```lua\r\n-- ClientDevProduct\r\nlocal DevProduct = {}\r\n\r\nDevProduct.Ids = {01234}\r\nDevProduct.Grant = function(productId: number)\r\n    -- e.g. play a sound or show an effect\r\nend\r\n\r\nreturn DevProduct\r\n```\r\n\r\n```lua\r\n-- ClientGamepass\r\nlocal Gamepass = {}\r\n\r\nGamepass.Ids = {2345}\r\nGamepass.Grant = function(gamepassId: number)\r\n    -- e.g. update the local UI\r\nend\r\n\r\nreturn Gamepass\r\n```\r\n\r\n## Signals\r\n\r\nCheckout fires signals after a successful purchase grant. This could, for example, be used for logging.\r\n\r\n```lua\r\nCheckout.DevProductPurchased:Connect(function(player: Player, productId: number, receiptInfo)\r\n    print(player, \"bought DevProduct\", productId)\r\nend)\r\n\r\nCheckout.GamepassPurchased:Connect(function(player: Player, gamepassId: number)\r\n    print(player, \"bought Gamepass\", gamepassId)\r\nend)\r\n```\r\n\r\nThese fire only for real purchases, not for `Checkout.GrantDevProduct` / `Checkout.GrantGamepass` or for gamepasses the player already owned on join.\r\n\r\n## Manual granting\r\nCheckout also lets you give DevProduct or Gamepass perks to players from other sources. This can be used for admin commands.\r\n\r\n```lua\r\nCheckout.GrantDevProduct(player, productId)\r\nCheckout.GrantGamepass(player, gamepassId)\r\n```\r\n\r\n## Legacy ProcessReceipt\r\n\r\nIf you have existing ProcessReceipt logic for DevProducts not managed by Checkout:\r\n\r\n```lua\r\nCheckout.AddToProcessReceipt(function(receiptInfo)\r\n    -- your other ProcessReceipt callback\r\nend)\r\n```\r\n","readmeTruncated":false}