@arsenstorm/olos
v0.6.0
Published
Open Live Object Streaming protocol primitives.
Readme
OLOS
Open Live Object Streaming protocol primitives. A generic live object streaming protocol: a low-latency append-only stream log over plain object storage (S3, R2, GCS), with CMAF/LL-HLS as its first profile.
Install
npm install @arsenstorm/olosImports
import { OLOS_PROTOCOL_NAME, OLOS_WIRE_VERSION } from "@arsenstorm/olos";
import type { Session } from "@arsenstorm/olos/types";| Subpath | Use for |
| --- | --- |
| @arsenstorm/olos/runtime | Session routes, publisher loops, HLS serving. |
| @arsenstorm/olos/s3 | S3 upload grants, observation, events, recovery, retention. Needs @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner installed by the consumer (optional peer dependencies). |
| @arsenstorm/olos/media | CMAF/LL-HLS profile: media session/track/object profiles, validators, schemas, publisher pacing. |
| @arsenstorm/olos/hls | HLS rendering and blocking-reload helpers. |
| @arsenstorm/olos/protocol | Coordinator stores and adapter conformance. |
| @arsenstorm/olos/state | Lower-level state transitions and policies. |
| @arsenstorm/olos/schema | JSON Schemas for wire objects. |
| @arsenstorm/olos/validation | Runtime payload validators. |
| @arsenstorm/olos/types | Public protocol data types. |
| @arsenstorm/olos/config | Protocol constants and policy defaults. |
| @arsenstorm/olos/conformance | Assertion metadata and store checks. |
Quick start
A complete OLOS endpoint with S3-backed live media (the CMAF/LL-HLS profile):
import {
createMemorySerializedCoordinatorStoreBackend,
createSerializedCoordinatorStore,
} from "@arsenstorm/olos/protocol";
import { createStoredS3CoordinatorRuntimeHandler } from "@arsenstorm/olos/s3";
import { S3Client } from "@aws-sdk/client-s3";
const store = createSerializedCoordinatorStore(
createMemorySerializedCoordinatorStoreBackend()
);
const s3 = new S3Client({ region: "us-east-1" });
const handleOlos = createStoredS3CoordinatorRuntimeHandler({
allowedDeliveryOrigins: ["https://media.example.com"],
bucket: "olos-media",
client: s3,
expiresInSeconds: 5,
providerId: "s3_primary",
store,
});
export default { fetch: (req: Request) => handleOlos(req) };Publishers create a session, then loop: get a presigned slot, PUT media bytes to S3, post a commit. Viewers GET HLS manifests. The handler covers it.
A session declares the profile it runs under and a profile per track. Core
treats profile objects as opaque; @arsenstorm/olos/media defines and
validates the CMAF/LL-HLS ones:
import { CMAF_LLHLS_PROFILE_ID } from "@arsenstorm/olos/media";
await fetch("https://olos.example.com/sessions", {
body: JSON.stringify({
deliveryBaseUrl: "https://media.example.com",
session: {
createdAt: new Date().toISOString(),
epoch: 1,
olos: "1.0",
profile: { id: CMAF_LLHLS_PROFILE_ID, partTarget: 0.5, segmentTarget: 2 },
sessionId: "session_1",
state: "live",
tracks: [
{
profile: { bitrate: 5_000_000, codec: "avc1.640028", kind: "video" },
trackId: "v1080",
},
],
},
}),
headers: { "content-type": "application/json" },
method: "POST",
});Slot requests and commits carry the same kind of opaque profile object
(for LL-HLS: { duration, independent, programDateTime }).
Working setups:
- examples/api — Cloudflare Worker + Durable Object + R2.
- examples/streamer — OBS-to-OLOS bridge using ffmpeg micro-segments.
- examples/player — LL-HLS player at the PART-HOLD-BACK spec floor.
Routes
The handler mounts:
| Method | Path | Purpose |
| --- | --- | --- |
| POST | /sessions | Create a session. |
| POST | /sessions/:id/s3/slots | Issue a presigned upload slot. |
| POST | /sessions/:id/s3/commits | Observe and commit an upload. |
| POST | /sessions/:id/s3/events | Accept S3 object-created events. |
| POST | /sessions/:id/s3/reconcile-plan | List in-flight slots for recovery. |
| POST | /sessions/:id/s3/reconcile | Recover slots after missed events. |
| POST | /sessions/:id/s3/retention | Prune retired state and delete retired media. |
| POST | /sessions/:id/upload-slots/:slotId/complete | Publisher completion hint (alternative to waiting for events). |
| POST | /sessions/:id/transition | Advance session state. |
| POST | /sessions/:id/heartbeat | Publisher liveness ping. |
| GET | /sessions/:id/health | Live / starting / stale summary. |
| GET | /v1/live/:id/master.m3u8 | Master playlist (variants, audio groups). |
| GET | /v1/live/:id/.../media.m3u8 | LL-HLS playlist with _HLS_msn blocking reload. |
The /sessions and /v1/live prefixes are the defaults. The handler's
sessionPath and livePath options configure them. Error responses always
carry error.code from the registered OLOS_ERROR_CODES set, next to
error.message.
Layers
OLOS is layered. Core defines the commit semantics. Above it are a profile
(the CMAF/LL-HLS profile ships in @arsenstorm/olos/media and
@arsenstorm/olos/hls), a storage binding (@arsenstorm/olos/s3), a
delivery mapping, the direct-public deployment profile, and runtime
guidance. Spec Section
2
defines the layers and the split between what OLOS owns and what your app
owns.
Further reading
- Production pipeline — wiring a real deployment.
- Store adapters — coordinator store on SQL, KV, or Durable Objects.
- Direct-public deployment — when uploaded media is readable before the manifest gates it.
- Conformance — assertion catalogue covering the protocol surface.
Release check
bun --filter '@arsenstorm/olos' publish:check