This is the server files for the item delivery system built in docker and lsl code.
  • JavaScript 50.7%
  • LSL 48.4%
  • Dockerfile 0.9%
Find a file
2026-01-20 19:21:44 -05:00
docker-compose.yml Initial upload of the project files 2026-01-20 19:21:44 -05:00
Dockerfile Initial upload of the project files 2026-01-20 19:21:44 -05:00
Item Delevery Server.lsl Initial upload of the project files 2026-01-20 19:21:44 -05:00
LICENSE Initial commit 2026-01-20 19:15:28 -05:00
package.json Initial upload of the project files 2026-01-20 19:21:44 -05:00
README.md Initial upload of the project files 2026-01-20 19:21:44 -05:00
server.js Initial upload of the project files 2026-01-20 19:21:44 -05:00

Item-Delevery-Server

Second Life Item Delivery System

A Docker-based Node.js backend service that handles item delivery requests for Second Life objects, featuring harvest management, idempotency controls, and secure URL registration. Overview

This system bridges Second Life (SL) objects with an external HTTP backend to handle item deliveries, crop harvesting, and inventory management. The backend maintains persistent state across region restarts and prevents duplicate deliveries through idempotency tracking. Architecture

Backend Service (Node.js/Express)

Registers and stores HTTP-in URLs from SL objects

Manages crop reward tables (server-authoritative)

Enforces harvest idempotency with configurable TTL

Forwards delivery requests back to SL ItemServer objects

SL ItemServer Script (LSL)

Requests HTTP-in URL and registers with backend

Handles region restarts gracefully

Delivers inventory items to avatars

Supports multiple delivery formats (single item, multi-item, legacy crop types)

Features

Harvest Idempotency: Prevents duplicate item deliveries using unique harvest IDs with automatic pruning

Server-Authoritative Rewards: Modify crop rewards without updating in-world scripts

URL Registration: Automatic HTTP-in URL lifecycle management with retry logic

Security: Optional shared secret authentication between services

Object Allowlist: Restrict which SL objects can register URLs

Persistent Storage: JSON file-backed data persistence across container restarts

Multi-Item Delivery: Support for delivering multiple items in a single transaction

Quick Start Prerequisites

Docker and Docker Compose

Nginx Proxy Manager (or modify networking configuration)

Second Life object with appropriate permissions

Deployment

Clone the repository and navigate to the project directory

Configure environment variables in docker-compose.yml:

text environment:

  • SHARED_SECRET=YourSecretHere # Match this in LSL script

  • ALLOWLIST= # Optional: comma-separated object UUIDs

  • TZ=Etc/GMT+5 # Your timezone

    Build and start the container:

bash docker-compose up -d

The service will be available on port 3000 and connected to the nginx network at 172.29.0.35

Configure the LSL script:

    Update API_URL and SERVER_URL to your domain

    Set SHARED_SECRET to match your backend configuration

    Add the script to your SL object's inventory

API Endpoints GET /

Health check endpoint returning service status and statistics.

Response:

json { "ok": true, "service": "sl-item-backend", "time": "2026-01-20T19:00:00.000Z", "knownObjects": 1, "harvestIdsCached": 42 }

POST /update-sl-url

Register an SL object's HTTP-in URL.

Request:

json { "sl_url": "https://sim1234.agni.lindenlab.com:12345/...", "object_uuid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" }

Response:

json { "ok": true, "key": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "sl_url": "https://..." }

POST /deliver

Legacy delivery endpoint supporting single or multiple items.

Single Item Request:

json { "object_uuid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "user_id": "ffffffff-eeee-dddd-cccc-bbbbbbbbbbbb", "item": "Corn", "qty": 2, "harvestId": "optional-unique-id" }

Multi-Item Request:

json { "object_uuid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "user_id": "ffffffff-eeee-dddd-cccc-bbbbbbbbbbbb", "items": [ {"name": "Corn", "qty": 2}, {"name": "Hay Bundle", "qty": 1} ] }

POST /harvest

Server-authoritative harvest endpoint with idempotency.

Request:

json { "object_uuid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "user_id": "ffffffff-eeee-dddd-cccc-bbbbbbbbbbbb", "cropId": "HAY", "harvestId": "unique-harvest-identifier" }

Response (first harvest):

json { "ok": true, "duplicate": false, "cropId": "HAY", "delivered": { "items": [{"name": "Hay Bundle", "qty": 1}] }, "deliveredText": "1x Hay Bundle", "harvestId": "unique-harvest-identifier" }

Response (duplicate harvest):

json { "ok": true, "duplicate": true, "cropId": "HAY", "delivered": { "items": [{"name": "Hay Bundle", "qty": 1}] }, "deliveredText": "1x Hay Bundle" }

Configuration Environment Variables Variable Default Description PORT 3000 HTTP server port SHARED_SECRET "" Optional authentication secret ALLOWLIST "" Comma-separated object UUIDs DATA_DIR /data Persistent storage directory HARVEST_TTL_MS 604800000 Harvest ID cache duration (7 days) HARVEST_MAX_RECORDS 5000 Maximum cached harvest records TZ Etc/GMT+5 Container timezone Crop Rewards

Edit the CROPS object in server.js to modify rewards:

javascript const CROPS = { HAY: { items: [{ name: "Hay Bundle", qty: 1 }], }, CORN: { items: [{ name: "Corn", qty: 1 }], }, WHEAT: { items: [ { name: "Wheat Bundle", qty: 2 }, { name: "Wheat Seed", qty: 1 } ] }, };

Changes take effect immediately without restarting SL objects. LSL Script Configuration

Update these variables in Item-Delevery-Server.lsl:

text string API_URL = "http://items.hijinkshaven.com/update-sl-url"; string SERVER_URL = "http://items.hijinkshaven.com/"; string SHARED_SECRET = "Hijinx"; // Must match backend float URL_RETRY_SECONDS = 30.0;

Data Persistence

The system persists data in two JSON files under /data (mapped to ./data on host):

urls.json: Registered SL object HTTP-in URLs

harvests.json: Harvest idempotency cache with timestamps

Data survives container restarts and is automatically pruned based on TTL and max record limits. LSL Script Features

The ItemServer script supports three delivery formats:

Single Item:

json { "secret": "Hijinx", "user_id": "<avatar_uuid>", "item": "Corn", "qty": 2, "harvestId": "optional" }

Multiple Items:

json { "secret": "Hijinx", "user_id": "<avatar_uuid>", "items": [ {"name": "Corn", "qty": 2}, {"name": "Hay Bundle", "qty": 1} ], "harvestId": "optional" }

Legacy Crop Type:

json { "secret": "Hijinx", "user_id": "<avatar_uuid>", "crop_type": "Corn" }

Region Restart Handling

The script automatically detects region restarts via CHANGED_REGION_START and requests a new HTTP-in URL, then re-registers with the backend. Networking

The default configuration uses an external Docker network named nginx with a static IP assignment. Modify the docker-compose.yml network settings if using a different proxy setup:

text networks: nginx: external: true

Dependencies

Node.js Runtime:

express ^4.19.2 - HTTP server framework

axios ^1.7.9 - HTTP client for SL requests

Docker Base Image:

node:20-alpine - Lightweight Node.js 20 environment

Security Considerations

Set a strong SHARED_SECRET for production deployments

Use the ALLOWLIST to restrict which objects can register URLs

Consider using llRequestSecureURL() in LSL for HTTPS endpoints

The backend validates all incoming requests and returns appropriate error codes

15-second timeout on SL HTTP requests prevents hanging connections

Troubleshooting

Container won't start:

Verify the nginx network exists: docker network ls

Check if port 3000 is available

Review logs: docker logs sl-item-server

SL object not registering URL:

Confirm API_URL in LSL matches your backend

Check SHARED_SECRET matches between LSL and backend

Verify object UUID is in ALLOWLIST if configured

Look for error messages in SL object's owner chat

Duplicate deliveries:

Ensure unique harvestId values are generated per harvest

Check harvest cache isn't being cleared prematurely

Verify HARVEST_TTL_MS is appropriate for your use case

Items not delivered:

Confirm item names in CROPS match exact inventory names

Check SL object has items in inventory

Review backend logs for forwarding errors

License

This project is provided as-is for use with Second Life item delivery systems.