{"id":19419626,"url":"https://github.com/intellectualsites/arkitektonika","last_synced_at":"2025-04-24T14:31:53.540Z","repository":{"id":38021321,"uuid":"273154089","full_name":"IntellectualSites/Arkitektonika","owner":"IntellectualSites","description":"a REST repository for NBT data","archived":false,"fork":false,"pushed_at":"2025-04-03T16:14:40.000Z","size":872,"stargazers_count":9,"open_issues_count":2,"forks_count":8,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-21T16:21:46.950Z","etag":null,"topics":["file-upload","json","minecraft","nbt","plotsquared","rest-api"],"latest_commit_sha":null,"homepage":"https://api.schematic.cloud/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IntellectualSites.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":["IntellectualSites"]}},"created_at":"2020-06-18T05:57:46.000Z","updated_at":"2025-04-01T19:51:25.000Z","dependencies_parsed_at":"2023-09-25T23:33:55.389Z","dependency_job_id":"5f315fe2-a6bf-42b7-a8a8-1391f8fa72ff","html_url":"https://github.com/IntellectualSites/Arkitektonika","commit_stats":{"total_commits":139,"total_committers":8,"mean_commits":17.375,"dds":0.4244604316546763,"last_synced_commit":"78b1cbb78dcde6799ac485cacb9bde2a66689b1b"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IntellectualSites%2FArkitektonika","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IntellectualSites%2FArkitektonika/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IntellectualSites%2FArkitektonika/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IntellectualSites%2FArkitektonika/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IntellectualSites","download_url":"https://codeload.github.com/IntellectualSites/Arkitektonika/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250643456,"owners_count":21464178,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["file-upload","json","minecraft","nbt","plotsquared","rest-api"],"created_at":"2024-11-10T13:18:27.508Z","updated_at":"2025-04-24T14:31:53.516Z","avatar_url":"https://github.com/IntellectualSites.png","language":"TypeScript","funding_links":["https://github.com/sponsors/IntellectualSites"],"categories":[],"sub_categories":[],"readme":"# Arkitektonika\n\n\u003cp\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/IntellectualSites/Assets/main/standalone/Arkitektonika/Arkitektonika.png\" width=\"150\"\u003e\n\u003c/p\u003e\n\n---\n\nArkitektonika is a REST repository for NBT data. It accepts uploads of valid NBT data and stores them in a local folder\nwhile accounting for its metadata in a local sqlite database. Optionally, uploaded files can be expired based on the\nconfigurable age by running the prune script. Files can always be deleted via their deletion key.\n\nExample Instances:\n\n| Address                           | Expiry     |\n|-----------------------------------|------------|\n| https://api.schematic.cloud/      | 30 days    |\n\n## To Run\n\n### With Docker\n\n```sh\ndocker pull intellectualsites/arkitektonika\n```\n\nAvailable on https://hub.docker.com/r/intellectualsites/arkitektonika\n\n### From scratch\n\n```sh\ngit clone https://github.com/IntellectualSites/Arkitektonika.git \u0026\u0026\ncd Arkitektonika \u0026\u0026\nyarn install\n```\n\n#### With Typescript transpiling (recommended)\n\n```sh\nyarn start:prod\n```\n\n#### Without Typescript transpiling\n\n```sh\nyarn start\n```\n\n### Build image locally\n\nClone the entire repository and run the following commands:\n\n```sh\ndocker build -t intellectualsites/arkitektonika:\u003cTAG\u003e .\n```\n\n---\n\nExample docker compose:\n\n```yaml\nversion: '3.8'\n\nservices:\n  arkitektonika:\n    container_name: Arkitektonika\n    image: intellectualsites/arkitektonika:dev\n    restart: unless-stopped\n    volumes:\n      - /home/ark/data:/data # Mount the data folder (containing config file, database and schematic storage)\n    environment:\n      - LOG_LEVEL=DEBUG   # if debug logs should be printed to the console\n```\n\n`/data` is mounted to the host at `/home/ark/data` as that folder contains persistent data.\n\n## Prune data\n\nExecute the start command with the prune flag to execute the prune routine:\n```sh\nyarn start:prod --prune\n```\n\n## Set up Expiration\n\nCreate a cron job that runs at whatever frequency you desire. As an example, this will run the pruning script every 12\nhours:\n\n```sh\n0 */12 * * * cd /srv/arkitektonika \u0026\u0026 /usr/bin/yarn start:prod --prune\n```\n\nOr with a docker-compose configuration:\n\n```sh\n0 */12 * * * cd /srv/arkitektonika \u0026\u0026 docker-compose run --rm arkitektonika node app/launch.js --prune\n```\n\n## Configuration\n\n```json\n{\n  \"port\": 3000,\n  \"prune\": 1800000,\n  \"maxIterations\": 20,\n  \"maxSchematicSize\": 1000000,\n  \"limiter\": {\n    \"windowMs\": 60000,\n    \"delayAfter\": 30,\n    \"delayMs\": 500\n  }\n}\n```\n\n| Config Key         | Description                                                                                                                |\n|--------------------|----------------------------------------------------------------------------------------------------------------------------|\n| port               | on which port should the application bind                                                                                  |\n| prune              | defines how old records must be to be deleted by the prune script (in ms)                                                  |\n| maxIterations      | maximum amount of iterations to obtain a unique download and deletion token                                                |\n| maxSchematicSize   | maximum size of schematic files to be accepted (in bytes)                                                                  |\n| limiter.windowMs   | the frame of the limiter (after what duration should the limit gets reset)                                                 |\n| limiter.delayAfter | After how many requests during windowMs should delayMs be applied                                                          |\n| limiter.delayMs    | How many ms should the request take longer. Formula: `currentRequestDelay = (currentRequestAmount - delayAfter) * delayMs` |\n\n## File structure:\n\n```\ndata\n├── config.json\n├── database.db\n└── schemata\n    ├── fe65d7edc37149c47171962dc26a039b\n    └── a98f299c5cf294e6555617e83226bcdd\n```\n\n`config.json` holds the user configuration data \u003cbr\u003e\n`database.db` holds the required data for each schematic \u003cbr\u003e\n`schemata`    holds all schematic file data\n\n### Routes\n\nAll routes will be available at the exposed port (e.g. `localhost:3000`).\n\n### Upload a file\n\n**POST `INSTANCE_URL/upload`**: send your file as multipart/form-data; example:\n\n```sh\ncurl --location --request POST 'http://localhost:3000/upload' \\\n--form 'schematic=@/path/to/plot.schem'\n```\n\nresponse:\n\n| code | meaning                                                              |\n|------|----------------------------------------------------------------------|\n| 200  | file was of valid NBT format and was accepted                        |\n| 400  | file was not of valid NBT format                                     |\n| 413  | file payload was too large and rejected                              |\n| 500  | file could not be found on disk after being uploaded (upload failed) |\n\nsuccess body:\n\n```json\n{\n  \"download_key\": \"db6186c8795740379d26fc61ecba1a24\",\n  \"delete_key\": \"11561161dffe4a1298992ce063be5ff9\"\n}\n```\n\nThe download key allows you to download the file, and the delete key lets you delete it. Share the `download_key`, but\nnot the `delete_key`.\n\n### Check download headers\n\n**HEAD `INSTANCE_URL/download/:download_key`**: check what headers you'd get if you sent a POST request for a file with\nthe given download_key; example:\n\n```sh\ncurl --location --head 'http://localhost:3000/download/db6186c8795740379d26fc61ecba1a24'\n```\n\nThe response for this is in the form of status codes only.\n\n| Status-Code | Meaning                                                                                |\n|-------------|----------------------------------------------------------------------------------------|\n| 200         | File was found, prospective download would succeed                                     |\n| 404         | File was not found in the database                                                     |\n| 410         | File metadata is in accounting table, but file is not on disk or already expired       |\n| 500         | An internal server error occurred due to corrupted metadata (missing data in database) |\n\n### Download a file\n\n**GET `INSTANCE_URL/download/:download_key`**: download a file with the given `download_key`; example:\n\n```sh\ncurl --location --request GET 'http://localhost:3000/download/db6186c8795740379d26fc61ecba1a24'\n```\n\nresponse:\nsee **Check download headers** above.\n\nOn success, the file is sent as an attachment for download to the browser / requester.\n\n### Check deletion headers\n\n**HEAD `INSTANCE_URL/delete/:delete_key`**: check what headers you'd get if you sent a DELETE request for a file with\nthe given delete_key; example:\n\n```sh\ncurl --location --head 'http://localhost:3000/delete/11561161dffe4a1298992ce063be5ff9'\n```\n\nThe response for this is in the form of status codes only.\n\n| Status-Code | Meaning                                                                                |\n|-------------|----------------------------------------------------------------------------------------|\n| 200         | File was found, prospective deletion would succeed                                     |\n| 404         | File was not found in the database                                                     |\n| 410         | File metadata is in accounting table, but file is not on disk or already expired       |\n| 500         | An internal server error occurred due to corrupted metadata (missing data in database) |\n\n### Delete a file\n\n**DELETE `PUBLIC_URL/delete/:delete_key`**: delete a file with the given `delete_key`; example:\n\n```sh\ncurl --location --request DELETE 'http://localhost:3000/delete/11561161dffe4a1298992ce063be5ff9'\n```\n\nresponse:\nsee **Check deletion headers** above.\n\nOn success, the file is deleted and the record is marked as expired in the database. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintellectualsites%2Farkitektonika","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fintellectualsites%2Farkitektonika","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintellectualsites%2Farkitektonika/lists"}