Phase 0: in-place decoupling before WarpEngine extraction
- FileService/DownloadService: lazy container-path resolution instead of class-load-time realpath (boot no longer requires /softwares to exist) - downloadCount/totalDownloads: single grouped query passed as Blueprinter option instead of per-release association counts (fixes N+1) - admin Images: Member coupling replaced with ImageUsage owner registry (precursor of the WarpEngine.config.image_owners hook) - Image: UPLOAD_PATH constant replaced with call-time upload_path accessor - proper test environment (config/environments/test.rb, softwares_test DB, hosts.clear) — suite previously ran against the development DB - spec fixes: case-insensitive uniqueness matchers (MySQL ai_ci collation), DB-cascade has_many expectations, PlatformLink::SUPPORTED_PLATFORMS - JSON baselines of /api/software and /api/builds for post-extraction diffing Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,23 @@ RSpec.describe Api::SoftwareController, type: :request do
|
||||
expect(json["softwares"].length).to eq(1)
|
||||
end
|
||||
|
||||
it "returns per-release and total download counts" do
|
||||
software = create(:software)
|
||||
release = create(:release, software: software)
|
||||
other = create(:release, software: software)
|
||||
create_list(:download, 3, release: release)
|
||||
create(:download, release: other)
|
||||
|
||||
get "/api/software"
|
||||
|
||||
json = JSON.parse(response.body)
|
||||
sw = json["softwares"].first
|
||||
expect(sw["totalDownloads"]).to eq(4)
|
||||
counts = sw["releases"].to_h { |r| [ r["id"], r["downloadCount"] ] }
|
||||
expect(counts[release.id]).to eq(3)
|
||||
expect(counts[other.id]).to eq(1)
|
||||
end
|
||||
|
||||
it "excludes soft-deleted software" do
|
||||
create(:software, deleted_at: Time.current)
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Member, type: :model do
|
||||
subject { build(:member) }
|
||||
|
||||
it { should validate_presence_of(:nick) }
|
||||
it { should validate_uniqueness_of(:nick) }
|
||||
# MySQL utf8mb4_0900_ai_ci collation: az egyediség DB-szinten case-insensitive
|
||||
it { should validate_uniqueness_of(:nick).case_insensitive }
|
||||
end
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Software, type: :model do
|
||||
subject { build(:software) }
|
||||
|
||||
it { should validate_presence_of(:name) }
|
||||
it { should validate_presence_of(:title) }
|
||||
it { should validate_presence_of(:platform) }
|
||||
it { should validate_uniqueness_of(:name) }
|
||||
# MySQL utf8mb4_0900_ai_ci collation: az egyediség DB-szinten case-insensitive
|
||||
it { should validate_uniqueness_of(:name).case_insensitive }
|
||||
|
||||
it { should have_many(:releases).dependent(:destroy) }
|
||||
it { should have_many(:external_links).dependent(:destroy) }
|
||||
# a törlést a DB-szintű ON DELETE CASCADE végzi, a modellen nincs dependent opció
|
||||
it { should have_many(:releases) }
|
||||
it { should have_many(:external_links) }
|
||||
it { should have_many(:software_images).dependent(:destroy) }
|
||||
|
||||
describe "default scope" do
|
||||
|
||||
@@ -19,7 +19,7 @@ RSpec.describe BuildsService do
|
||||
end
|
||||
|
||||
it "includes all supported platforms" do
|
||||
UpdateService::SUPPORTED_PLATFORMS.each do |platform|
|
||||
PlatformLink::SUPPORTED_PLATFORMS.each do |platform|
|
||||
expect(result[:platforms]).to have_key(platform)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"platforms": {
|
||||
"tic80": {
|
||||
"label": "TIC-80",
|
||||
"kinds": [
|
||||
"cartridge",
|
||||
"source",
|
||||
"html",
|
||||
"docs",
|
||||
"win_x64",
|
||||
"linux_x64",
|
||||
"mac_x64"
|
||||
]
|
||||
},
|
||||
"ebitengine": {
|
||||
"label": "Ebitengine",
|
||||
"kinds": [
|
||||
"html",
|
||||
"win_x86",
|
||||
"win_x64",
|
||||
"linux_x64",
|
||||
"mac_x64",
|
||||
"mac_arm64"
|
||||
]
|
||||
},
|
||||
"love": {
|
||||
"label": "L\u00d6VE",
|
||||
"kinds": [
|
||||
"html",
|
||||
"win_x64",
|
||||
"linux_x64",
|
||||
"mac_universal"
|
||||
]
|
||||
},
|
||||
"c64": {
|
||||
"label": "C64",
|
||||
"kinds": [
|
||||
"cartridge"
|
||||
]
|
||||
},
|
||||
"godot": {
|
||||
"label": "Godot",
|
||||
"kinds": [
|
||||
"html",
|
||||
"win_x86",
|
||||
"win_x64",
|
||||
"linux_x64",
|
||||
"mac_universal"
|
||||
]
|
||||
},
|
||||
"bevy": {
|
||||
"label": "Bevy",
|
||||
"kinds": [
|
||||
"html",
|
||||
"win_x64",
|
||||
"linux_x64"
|
||||
]
|
||||
},
|
||||
"phaser": {
|
||||
"label": "Phaser",
|
||||
"kinds": [
|
||||
"html"
|
||||
]
|
||||
}
|
||||
},
|
||||
"allKinds": [
|
||||
"cartridge",
|
||||
"source",
|
||||
"html",
|
||||
"docs",
|
||||
"win_x86",
|
||||
"win_x64",
|
||||
"linux_x86",
|
||||
"linux_x64",
|
||||
"mac_x64",
|
||||
"mac_arm64",
|
||||
"mac_universal"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,629 @@
|
||||
{
|
||||
"softwares": [
|
||||
{
|
||||
"latestRelease": {
|
||||
"assets": [
|
||||
{
|
||||
"kind": "cartridge",
|
||||
"path": "/file/impostor-1.0.tic"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"path": "/file/impostor-1.0.lua"
|
||||
},
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/impostor-1.0"
|
||||
},
|
||||
{
|
||||
"kind": "docs",
|
||||
"path": "/file/impostor-1.0-docs"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "/file/impostor-1.0.tic",
|
||||
"createdAt": "2026-04-30T15:56:12.781Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "/file/impostor-1.0-docs",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/impostor-1.0",
|
||||
"id": 96,
|
||||
"softwareId": 19,
|
||||
"sourcePath": "/file/impostor-1.0.lua",
|
||||
"updatedAt": "2026-04-30T15:56:12.781Z",
|
||||
"version": "1.0"
|
||||
},
|
||||
"releases": [
|
||||
{
|
||||
"assets": [
|
||||
{
|
||||
"kind": "cartridge",
|
||||
"path": "/file/impostor-1.0.tic"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"path": "/file/impostor-1.0.lua"
|
||||
},
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/impostor-1.0"
|
||||
},
|
||||
{
|
||||
"kind": "docs",
|
||||
"path": "/file/impostor-1.0-docs"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "/file/impostor-1.0.tic",
|
||||
"createdAt": "2026-04-30T15:56:12.781Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "/file/impostor-1.0-docs",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/impostor-1.0",
|
||||
"id": 96,
|
||||
"softwareId": 19,
|
||||
"sourcePath": "/file/impostor-1.0.lua",
|
||||
"updatedAt": "2026-04-30T15:56:12.781Z",
|
||||
"version": "1.0"
|
||||
},
|
||||
{
|
||||
"assets": [
|
||||
{
|
||||
"kind": "cartridge",
|
||||
"path": "/file/impostor-1.0-beta2.tic"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"path": "/file/impostor-1.0-beta2.lua"
|
||||
},
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/impostor-1.0-beta2"
|
||||
},
|
||||
{
|
||||
"kind": "docs",
|
||||
"path": "/file/impostor-1.0-beta2-docs"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "/file/impostor-1.0-beta2.tic",
|
||||
"createdAt": "2026-04-09T19:55:42.764Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "/file/impostor-1.0-beta2-docs",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/impostor-1.0-beta2",
|
||||
"id": 85,
|
||||
"softwareId": 19,
|
||||
"sourcePath": "/file/impostor-1.0-beta2.lua",
|
||||
"updatedAt": "2026-04-09T19:55:42.764Z",
|
||||
"version": "1.0-beta2"
|
||||
},
|
||||
{
|
||||
"assets": [
|
||||
{
|
||||
"kind": "cartridge",
|
||||
"path": "/file/impostor-1.0-beta1.tic"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"path": "/file/impostor-1.0-beta1.lua"
|
||||
},
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/impostor-1.0-beta1"
|
||||
},
|
||||
{
|
||||
"kind": "docs",
|
||||
"path": "/file/impostor-1.0-beta1-docs"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "/file/impostor-1.0-beta1.tic",
|
||||
"createdAt": "2026-03-22T22:49:54.926Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "/file/impostor-1.0-beta1-docs",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/impostor-1.0-beta1",
|
||||
"id": 77,
|
||||
"softwareId": 19,
|
||||
"sourcePath": "/file/impostor-1.0-beta1.lua",
|
||||
"updatedAt": "2026-03-22T22:49:54.926Z",
|
||||
"version": "1.0-beta1"
|
||||
},
|
||||
{
|
||||
"assets": [
|
||||
{
|
||||
"kind": "cartridge",
|
||||
"path": "/file/impostor-1.0-alpha.tic"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"path": "/file/impostor-1.0-alpha.lua"
|
||||
},
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/impostor-1.0-alpha"
|
||||
},
|
||||
{
|
||||
"kind": "docs",
|
||||
"path": "/file/impostor-1.0-alpha-docs"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "/file/impostor-1.0-alpha.tic",
|
||||
"createdAt": "2026-03-20T14:31:12.319Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "/file/impostor-1.0-alpha-docs",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/impostor-1.0-alpha",
|
||||
"id": 71,
|
||||
"softwareId": 19,
|
||||
"sourcePath": "/file/impostor-1.0-alpha.lua",
|
||||
"updatedAt": "2026-03-20T14:31:12.319Z",
|
||||
"version": "1.0-alpha"
|
||||
}
|
||||
],
|
||||
"software": {
|
||||
"author": "Teletype Games",
|
||||
"createdAt": "2026-03-04T14:04:42.676Z",
|
||||
"deletedAt": null,
|
||||
"desc": "Life of a programmer",
|
||||
"externalLinks": [
|
||||
{
|
||||
"createdAt": "0001-01-01T00:00:00Z",
|
||||
"deletedAt": null,
|
||||
"id": 1,
|
||||
"label": "Source Code",
|
||||
"softwareId": 19,
|
||||
"updatedAt": "0001-01-01T00:00:00Z",
|
||||
"url": "https://git.teletype.hu/games/impostor/"
|
||||
},
|
||||
{
|
||||
"createdAt": "0001-01-01T00:00:00Z",
|
||||
"deletedAt": null,
|
||||
"id": 2,
|
||||
"label": "Itch.io page",
|
||||
"softwareId": 19,
|
||||
"updatedAt": "0001-01-01T00:00:00Z",
|
||||
"url": "https://teletypegames.itch.io/definitely-not-an-impostor"
|
||||
}
|
||||
],
|
||||
"highlighted": true,
|
||||
"id": 19,
|
||||
"imageUrl": null,
|
||||
"images": [],
|
||||
"license": "MIT License",
|
||||
"name": "impostor",
|
||||
"platform": "tic80",
|
||||
"platformLinks": [],
|
||||
"status": "released",
|
||||
"story": "Norman is an average simulation engineer living a dull but stable life. Hes exactly where he belongsthough he doesnt always feel that way. Follow his mostly work-driven life and discover the excitement within it. Just dont be surprised if you find more than expected.",
|
||||
"title": "Definitely not an Impostor",
|
||||
"updatedAt": "2026-04-30T21:15:03.809Z"
|
||||
},
|
||||
"totalDownloads": 0,
|
||||
"webPlayableRelease": {
|
||||
"assets": [
|
||||
{
|
||||
"kind": "cartridge",
|
||||
"path": "/file/impostor-1.0.tic"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"path": "/file/impostor-1.0.lua"
|
||||
},
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/impostor-1.0"
|
||||
},
|
||||
{
|
||||
"kind": "docs",
|
||||
"path": "/file/impostor-1.0-docs"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "/file/impostor-1.0.tic",
|
||||
"createdAt": "2026-04-30T15:56:12.781Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "/file/impostor-1.0-docs",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/impostor-1.0",
|
||||
"id": 96,
|
||||
"softwareId": 19,
|
||||
"sourcePath": "/file/impostor-1.0.lua",
|
||||
"updatedAt": "2026-04-30T15:56:12.781Z",
|
||||
"version": "1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"latestRelease": {
|
||||
"assets": [
|
||||
{
|
||||
"kind": "cartridge",
|
||||
"path": "/file/bombexpert-0.2.tic"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"path": "/file/bombexpert-0.2.lua"
|
||||
},
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/bombexpert-0.2"
|
||||
},
|
||||
{
|
||||
"kind": "docs",
|
||||
"path": "/file/bombexpert-0.2-docs"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "/file/bombexpert-0.2.tic",
|
||||
"createdAt": "2026-03-04T14:05:54.728Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "/file/bombexpert-0.2-docs",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/bombexpert-0.2",
|
||||
"id": 52,
|
||||
"softwareId": 20,
|
||||
"sourcePath": "/file/bombexpert-0.2.lua",
|
||||
"updatedAt": "2026-03-04T14:05:54.728Z",
|
||||
"version": "0.2"
|
||||
},
|
||||
"releases": [
|
||||
{
|
||||
"assets": [
|
||||
{
|
||||
"kind": "cartridge",
|
||||
"path": "/file/bombexpert-0.2.tic"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"path": "/file/bombexpert-0.2.lua"
|
||||
},
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/bombexpert-0.2"
|
||||
},
|
||||
{
|
||||
"kind": "docs",
|
||||
"path": "/file/bombexpert-0.2-docs"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "/file/bombexpert-0.2.tic",
|
||||
"createdAt": "2026-03-04T14:05:54.728Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "/file/bombexpert-0.2-docs",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/bombexpert-0.2",
|
||||
"id": 52,
|
||||
"softwareId": 20,
|
||||
"sourcePath": "/file/bombexpert-0.2.lua",
|
||||
"updatedAt": "2026-03-04T14:05:54.728Z",
|
||||
"version": "0.2"
|
||||
}
|
||||
],
|
||||
"software": {
|
||||
"author": "Zsolt Tasnadi",
|
||||
"createdAt": "2026-03-04T14:05:54.725Z",
|
||||
"deletedAt": null,
|
||||
"desc": "Simple BombExpert for TIC-80",
|
||||
"externalLinks": [],
|
||||
"highlighted": false,
|
||||
"id": 20,
|
||||
"imageUrl": null,
|
||||
"images": [],
|
||||
"license": "MIT License",
|
||||
"name": "bombexpert",
|
||||
"platform": "tic80",
|
||||
"platformLinks": [],
|
||||
"status": "archived",
|
||||
"story": "",
|
||||
"title": "BombExpert",
|
||||
"updatedAt": "2026-03-04T14:05:54.725Z"
|
||||
},
|
||||
"totalDownloads": 0,
|
||||
"webPlayableRelease": {
|
||||
"assets": [
|
||||
{
|
||||
"kind": "cartridge",
|
||||
"path": "/file/bombexpert-0.2.tic"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"path": "/file/bombexpert-0.2.lua"
|
||||
},
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/bombexpert-0.2"
|
||||
},
|
||||
{
|
||||
"kind": "docs",
|
||||
"path": "/file/bombexpert-0.2-docs"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "/file/bombexpert-0.2.tic",
|
||||
"createdAt": "2026-03-04T14:05:54.728Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "/file/bombexpert-0.2-docs",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/bombexpert-0.2",
|
||||
"id": 52,
|
||||
"softwareId": 20,
|
||||
"sourcePath": "/file/bombexpert-0.2.lua",
|
||||
"updatedAt": "2026-03-04T14:05:54.728Z",
|
||||
"version": "0.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"latestRelease": {
|
||||
"assets": [
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/ebitenginedemo-1.0.0"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "",
|
||||
"createdAt": "2026-03-04T14:06:36.626Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/ebitenginedemo-1.0.0",
|
||||
"id": 53,
|
||||
"softwareId": 21,
|
||||
"sourcePath": "",
|
||||
"updatedAt": "2026-03-04T14:06:36.626Z",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"releases": [
|
||||
{
|
||||
"assets": [
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/ebitenginedemo-1.0.0"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "",
|
||||
"createdAt": "2026-03-04T14:06:36.626Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/ebitenginedemo-1.0.0",
|
||||
"id": 53,
|
||||
"softwareId": 21,
|
||||
"sourcePath": "",
|
||||
"updatedAt": "2026-03-04T14:06:36.626Z",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"software": {
|
||||
"author": "Teletype Games",
|
||||
"createdAt": "2026-03-04T14:06:36.623Z",
|
||||
"deletedAt": null,
|
||||
"desc": "It's a simple demo program in Ebitengine",
|
||||
"externalLinks": [],
|
||||
"highlighted": false,
|
||||
"id": 21,
|
||||
"imageUrl": null,
|
||||
"images": [],
|
||||
"license": "MIT License",
|
||||
"name": "ebitenginedemo",
|
||||
"platform": "ebitengine",
|
||||
"platformLinks": [],
|
||||
"status": "demo",
|
||||
"story": "",
|
||||
"title": "Ebitengine Demo",
|
||||
"updatedAt": "2026-03-04T14:06:36.623Z"
|
||||
},
|
||||
"totalDownloads": 0,
|
||||
"webPlayableRelease": {
|
||||
"assets": [
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/ebitenginedemo-1.0.0"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "",
|
||||
"createdAt": "2026-03-04T14:06:36.626Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/ebitenginedemo-1.0.0",
|
||||
"id": 53,
|
||||
"softwareId": 21,
|
||||
"sourcePath": "",
|
||||
"updatedAt": "2026-03-04T14:06:36.626Z",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"latestRelease": {
|
||||
"assets": [
|
||||
{
|
||||
"kind": "cartridge",
|
||||
"path": "/file/mranderson-0.1.tic"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"path": "/file/mranderson-0.1.lua"
|
||||
},
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/mranderson-0.1"
|
||||
},
|
||||
{
|
||||
"kind": "docs",
|
||||
"path": "/file/mranderson-0.1-docs"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "/file/mranderson-0.1.tic",
|
||||
"createdAt": "2026-03-04T14:06:58.912Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "/file/mranderson-0.1-docs",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/mranderson-0.1",
|
||||
"id": 54,
|
||||
"softwareId": 22,
|
||||
"sourcePath": "/file/mranderson-0.1.lua",
|
||||
"updatedAt": "2026-03-04T14:06:58.912Z",
|
||||
"version": "0.1"
|
||||
},
|
||||
"releases": [
|
||||
{
|
||||
"assets": [
|
||||
{
|
||||
"kind": "cartridge",
|
||||
"path": "/file/mranderson-0.1.tic"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"path": "/file/mranderson-0.1.lua"
|
||||
},
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/mranderson-0.1"
|
||||
},
|
||||
{
|
||||
"kind": "docs",
|
||||
"path": "/file/mranderson-0.1-docs"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "/file/mranderson-0.1.tic",
|
||||
"createdAt": "2026-03-04T14:06:58.912Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "/file/mranderson-0.1-docs",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/mranderson-0.1",
|
||||
"id": 54,
|
||||
"softwareId": 22,
|
||||
"sourcePath": "/file/mranderson-0.1.lua",
|
||||
"updatedAt": "2026-03-04T14:06:58.912Z",
|
||||
"version": "0.1"
|
||||
}
|
||||
],
|
||||
"software": {
|
||||
"author": "Zsolt Tasnadi",
|
||||
"createdAt": "2026-03-04T14:06:58.907Z",
|
||||
"deletedAt": null,
|
||||
"desc": "Life of a programmer in the Vector",
|
||||
"externalLinks": [],
|
||||
"highlighted": false,
|
||||
"id": 22,
|
||||
"imageUrl": null,
|
||||
"images": [],
|
||||
"license": "MIT License",
|
||||
"name": "mranderson",
|
||||
"platform": "tic80",
|
||||
"platformLinks": [],
|
||||
"status": "development",
|
||||
"story": "",
|
||||
"title": "Mr Anderson's Adventure",
|
||||
"updatedAt": "2026-03-04T14:06:58.907Z"
|
||||
},
|
||||
"totalDownloads": 0,
|
||||
"webPlayableRelease": {
|
||||
"assets": [
|
||||
{
|
||||
"kind": "cartridge",
|
||||
"path": "/file/mranderson-0.1.tic"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"path": "/file/mranderson-0.1.lua"
|
||||
},
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/mranderson-0.1"
|
||||
},
|
||||
{
|
||||
"kind": "docs",
|
||||
"path": "/file/mranderson-0.1-docs"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "/file/mranderson-0.1.tic",
|
||||
"createdAt": "2026-03-04T14:06:58.912Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "/file/mranderson-0.1-docs",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/mranderson-0.1",
|
||||
"id": 54,
|
||||
"softwareId": 22,
|
||||
"sourcePath": "/file/mranderson-0.1.lua",
|
||||
"updatedAt": "2026-03-04T14:06:58.912Z",
|
||||
"version": "0.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"latestRelease": {
|
||||
"assets": [
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/love2ddemo-1.0.0"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "",
|
||||
"createdAt": "2026-03-04T14:09:14.425Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/love2ddemo-1.0.0",
|
||||
"id": 55,
|
||||
"softwareId": 23,
|
||||
"sourcePath": "",
|
||||
"updatedAt": "2026-03-04T14:09:14.425Z",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"releases": [
|
||||
{
|
||||
"assets": [
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/love2ddemo-1.0.0"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "",
|
||||
"createdAt": "2026-03-04T14:09:14.425Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/love2ddemo-1.0.0",
|
||||
"id": 55,
|
||||
"softwareId": 23,
|
||||
"sourcePath": "",
|
||||
"updatedAt": "2026-03-04T14:09:14.425Z",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"software": {
|
||||
"author": "Teletype Games",
|
||||
"createdAt": "2026-03-04T14:09:14.421Z",
|
||||
"deletedAt": null,
|
||||
"desc": "It's a simple demo program in Love2D",
|
||||
"externalLinks": [],
|
||||
"highlighted": false,
|
||||
"id": 23,
|
||||
"imageUrl": null,
|
||||
"images": [],
|
||||
"license": "MIT License",
|
||||
"name": "love2ddemo",
|
||||
"platform": "love",
|
||||
"platformLinks": [],
|
||||
"status": "demo",
|
||||
"story": "",
|
||||
"title": "Love2D Demo",
|
||||
"updatedAt": "2026-03-04T14:11:51.053Z"
|
||||
},
|
||||
"totalDownloads": 0,
|
||||
"webPlayableRelease": {
|
||||
"assets": [
|
||||
{
|
||||
"kind": "html",
|
||||
"path": "/file/love2ddemo-1.0.0"
|
||||
}
|
||||
],
|
||||
"cartridgePath": "",
|
||||
"createdAt": "2026-03-04T14:09:14.425Z",
|
||||
"deletedAt": null,
|
||||
"docsFolderPath": "",
|
||||
"downloadCount": 0,
|
||||
"htmlFolderPath": "/file/love2ddemo-1.0.0",
|
||||
"id": 55,
|
||||
"softwareId": 23,
|
||||
"sourcePath": "",
|
||||
"updatedAt": "2026-03-04T14:09:14.425Z",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user