# spearmint
A CLI tool that syncs Roblox developer products and game passes from a local TOML config to the [Roblox Open Cloud API](https://create.roblox.com/docs/cloud).
Define your products in `spearmint.toml`, run `spearmint sync`, and spearmint handles creating/updating them on Roblox while generating Lua and TypeScript files for your game.
## Install
```bash
cargo install --path .
```
## Setup
1. Create a Roblox Open Cloud API key at [create.roblox.com/dashboard/credentials](https://create.roblox.com/dashboard/credentials) with **Developer Product** and **Game Pass** write permissions for your experience.
2. In your project directory, create a `.env` file:
```
ROBLOX_PRODUCTS_API_KEY=your_api_key_here
```
3. Initialize the config:
```bash
spearmint init
```
4. Edit the generated `spearmint.toml` with your universe ID and products.
## Config
```toml
universe_id = 123456789
[output]
path = "src/shared/modules/Products.luau"
typescript = true
[products.coins_100]
type = "dev_product"
name = "100 Coins"
price = 99
description = "Get 100 coins"
image = "assets/products/coins.png"
[products.vip]
type = "gamepass"
name = "VIP"
price = 499
description = "VIP access"
image = "assets/products/vip.png"
```
Each product entry supports:
| `type` | Yes | `dev_product` or `gamepass` |
| `name` | Yes | Display name on Roblox |
| `price` | Yes | Price in Robux |
| `description` | No | Product description |
| `image` | No | Path to thumbnail image |
| `product_id` | No | Existing Roblox ID (skips creation, used for updates) |
## Commands
### `spearmint sync`
Syncs all products to Roblox. Creates new products and updates existing ones when the config has changed. Generates Lua/TypeScript output after syncing.
```bash
spearmint sync
spearmint sync --no-generate # skip code generation
spearmint sync -c custom.toml # custom config path
```
### `spearmint generate`
Generates Lua and TypeScript output files from the current mapping without making any API calls.
```bash
spearmint generate
```
### `spearmint list`
Lists all products and their sync status.
```bash
spearmint list
```
### `spearmint init`
Creates a default `spearmint.toml` template.
```bash
spearmint init
spearmint init --force # overwrite existing config
```
## How It Works
spearmint uses a lock file (`spearmint.lock.toml`) to track the mapping between local product keys and Roblox IDs, along with cached metadata. On each sync, it compares the current config against the lock file to determine what's changed:
- **New products** (no lock file entry) are created via the API
- **Changed products** (name, price, description, or image contents differ) are updated
- **Unchanged products** are skipped
Image changes are detected by SHA-256 hashing the file contents, so replacing an image file without renaming it will trigger an update.
## Generated Output
After syncing, spearmint generates a Lua module and optionally a TypeScript declaration file:
**Products.luau**
```lua
-- This file is auto-generated by spearmint. Do not edit manually.
local Products = {
DevProducts = {
["coins_100"] = 123456,
},
Gamepasses = {
["vip"] = 789012,
},
}
return Products
```
**Products.d.ts**
```typescript
// This file is auto-generated by spearmint. Do not edit manually.
interface Products {
DevProducts: {
readonly "coins_100": 123456;
};
Gamepasses: {
readonly "vip": 789012;
};
}
declare const Products: Products;
export = Products;
```
## License
MIT