{"id":"sonoranbrian/sonoran-lua","name":"sonoran-lua","scope":"sonoranbrian","platform":"roblox","description":"Sonoran CAD v2 client for Roblox","version":"0.1.15","latest":"0.1.15","versions":["0.1.15"],"license":"MIT","licenseRating":"safe","licenseCaveats":["License identified from the packaged LICENSE file; the manifest's declared license (\"PolyForm-Noncommercial-1.0.0\") is not a recognized identifier."],"licenseVerified":true,"dependencies":{},"integrity":"4abe2500620daf4c62b045976535a2838f52461d045954f58a8bfb33a09941a2","likes":0,"downloads":0,"install":"forest install sonoranbrian/sonoran-lua","url":"https://forest.dev/p/roblox/sonoranbrian/sonoran-lua","files":"https://api.forest.dev/ai/package/roblox/sonoranbrian/sonoran-lua/files","readme":"# Sonoran.lua\n\n`Sonoran.lua` is a Lua SDK for Sonoran CAD v2 endpoints with shared client code for FiveM and Roblox runtimes.\n\n## Installation\n\n### FiveM\n\nInstall from LuaRocks:\n\n```sh\nluarocks install sonoran.lua\n```\n\nLuaRocks package:\n[sonoran.lua on LuaRocks](https://luarocks.org/modules/sonoransoftware/sonoran.lua)\n\nOr use the generated FiveM resource release asset and start it before resources that consume it.\n\n```cfg\nensure Sonoran.lua\n```\n\nIn your consuming resource:\n\n```lua\nfx_version 'cerulean'\ngame 'gta5'\nlua54 'yes'\n\nserver_scripts {\n  'server.lua'\n}\n\ndependency 'Sonoran.lua'\n```\n\n### Roblox\n\nInstall from Wally:\n\n```toml\n[dependencies]\nSonoran = \"sonoranbrian/sonoran-lua@^0.1.0\"\n```\n\nThen require the package module:\n\n```lua\nlocal Sonoran = require(ReplicatedStorage.Packages.Sonoran)\n```\n\n## Usage\n\nFiveM resource usage:\n\n```lua\nlocal sonoran = exports[\"Sonoran.lua\"]:createClient({\n  apiKey = \"your-cad-api-key\",\n  communityId = \"your-community-id\",\n  apiUrl = \"https://api.sonorancad.com\",\n  defaultServerId = 1,\n  timeoutMs = 30000\n})\n```\n\nRoblox usage:\n\n```lua\nlocal sonoran = Sonoran.createClient({\n  apiKey = \"your-cad-api-key\",\n  communityId = \"your-community-id\",\n  apiUrl = \"https://api.sonorancad.com\",\n  defaultServerId = 1,\n  timeoutMs = 30000\n})\n```\n\n### Config\n\n- `apiKey`: required for authenticated endpoints.\n- `communityId`: optional; used by `getLoginPageV2()` when no explicit `communityId` is supplied.\n- `apiUrl`: optional; defaults to `https://api.sonorancad.com`.\n- `defaultServerId`: optional; defaults to `1`.\n- `headers`: optional extra headers merged into every request.\n- `timeoutMs`: optional timeout for the FiveM adapter; defaults to `30000`.\n\n### Response Shape\n\nAll public methods return:\n\n```lua\n{ success = true, data = ... }\n```\n\nor:\n\n```lua\n{ success = false, reason = ... }\n```\n\nSuccessful JSON responses are decoded automatically. Plain-text error responses are returned as strings. `204 No Content` responses return `data = nil`.\n\n## Examples\n\nGeneral endpoint:\n\n```lua\nlocal version = sonoran:getVersionV2()\nif version.success then\n  print(version.data)\nend\n```\n\nCivilian endpoint:\n\n```lua\nlocal characters = sonoran:getCharactersV2({\n  apiId = \"1234567890\"\n})\n\nif characters.success then\n  print((\"Found %s character(s)\"):format(#characters.data))\nend\n```\n\nEmergency endpoint:\n\n```lua\nlocal created = sonoran:createDispatchCallV2({\n  serverId = 1,\n  origin = 1,\n  status = 1,\n  priority = 1,\n  block = \"123\",\n  address = \"Main St\",\n  postal = \"100\",\n  title = \"Traffic Stop\",\n  code = \"TS\",\n  description = \"Blue sedan heading north\",\n  notes = {},\n  apiIds = { \"1234567890\" }\n})\n\nif not created.success then\n  print(json.encode(created.reason))\nend\n```\n\n## Public API\n\n### General\n\n- `getLoginPageV2(params?)`\n- `checkApiIdV2(apiId)`\n- `applyPermissionKeyV2(data)`\n- `banUserV2(data)`\n- `setPenalCodesV2(codes)`\n- `setApiIdsV2(data)`\n- `getTemplatesV2(recordTypeId?)`\n- `createRecordV2(data)`\n- `updateRecordV2(recordId, data)`\n- `removeRecordV2(recordId)`\n- `sendRecordDraftV2(data)`\n- `lookupV2(data)`\n- `lookupByValueV2(data)`\n- `lookupCustomV2(data)`\n- `getAccountV2(query?)`\n- `getAccountsV2(query?)`\n- `createCommunityLinkV2(data)`\n- `checkCommunityLinkV2(data)`\n- `setAccountPermissionsV2(data)`\n- `heartbeatV2(serverId, playerCount)`\n- `getVersionV2()`\n- `getServersV2()`\n- `setServersV2(servers, deployMap?)`\n- `verifySecretV2(secret)`\n- `authorizeStreetSignsV2(serverId?)`\n- `setPostalsV2(postals)`\n- `sendPhotoV2(data)`\n- `getInfoV2()`\n\n### Civilian\n\n- `getCharactersV2(query?)`\n- `removeCharacterV2(characterId)`\n- `setSelectedCharacterV2(data)`\n- `getCharacterLinksV2(query?)`\n- `addCharacterLinkV2(syncId, data)`\n- `removeCharacterLinkV2(syncId, data)`\n\n### Emergency\n\n- `getUnitsV2(query?)`\n- `getCallsV2(query?)`\n- `getCurrentCallV2(accountUuid)`\n- `updateUnitLocationsV2(data)`\n- `setUnitPanicV2(data)`\n- `setUnitStatusV2(data)`\n- `kickUnitV2(data)`\n- `getIdentifiersV2(accountUuid)`\n- `getAccountUnitsV2(data)`\n- `selectIdentifierV2(accountUuid, identId)`\n- `createIdentifierV2(accountUuid, data)`\n- `updateIdentifierV2(accountUuid, identId, data)`\n- `deleteIdentifierV2(accountUuid, identId)`\n- `addIdentifiersToGroupV2(data)`\n- `createEmergencyCallV2(data)`\n- `deleteEmergencyCallV2(callId, serverId?)`\n- `createDispatchCallV2(data)`\n- `updateDispatchCallV2(callId, data)`\n- `attachUnitsToDispatchCallV2(callId, data)`\n- `detachUnitsFromDispatchCallV2(data)`\n- `setDispatchPostalV2(callId, postal, serverId?)`\n- `setDispatchPrimaryV2(callId, identId, trackPrimary?, serverId?)`\n- `addDispatchNoteV2(callId, data)`\n- `closeDispatchCallsV2(callIds, serverId?)`\n- `updateStreetSignsV2(data)`\n- `setStreetSignConfigV2(signs, serverId?)`\n- `setAvailableCalloutsV2(callouts, serverId?)`\n- `getPagerConfigV2(serverId?)`\n- `setPagerConfigV2(data)`\n- `setStationsV2(config, serverId?)`\n- `getBlipsV2(serverId?)`\n- `createBlipV2(data)`\n- `updateBlipV2(blipId, data)`\n- `deleteBlipsV2(ids, serverId?)`\n\n## Notes\n\n- FiveM uses `PerformHttpRequest`, `promise.new()`, and `Citizen.Await`.\n- Roblox uses `HttpService:RequestAsync()`.\n- Radio, CMS, and legacy CAD endpoints are intentionally out of scope for this initial port.\n","readmeTruncated":false}